<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<article>
  <title>simpleSAMLphp advanced features</title>

  <articleinfo>
    <date>...</date>

    <pubdate>Tue Nov  4 06:50:31 2008</pubdate>

    <author>
      <firstname>Andreas Åkre</firstname>

      <surname>Solberg</surname>

      <email>andreas.solberg@uninett.no</email>
    </author>
  </articleinfo>

  <section>
    <title>simpleSAMLphp documentation</title>

    <para>This document is part of the simpleSAMLphp documentation
    suite.</para>

    <itemizedlist>
      <listitem>
        <para><ulink url="http://rnd.feide.no/view/simplesamlphpdocs">List of
        all simpleSAMLphp documentation</ulink></para>
      </listitem>
    </itemizedlist>

    <para>This document assumes that you already have a installation of
    simpleSAMLphp running, configured and working. This is the next step
    :)</para>
  </section>

  <section>
    <title>Bridging between protocols</title>

    <para>A bridge between two protocols is built using both an IdP and an SP,
    connected together. To let a SAML 2.0 SP talk to a Shibboleth IdP, you
    build a simpleSAMLphp bridge from a SAML 2.0 IdP and a Shibboleth SP.The
    SAML 2.0 SP talks to the SAML 2.0 IdP, which hands the request over to the
    Shibboleth 1.3 SP, which forwards it to the Shibboleth IdP. This is
    configured in the IdP hosted metadata, and is controlled by the
    <code>auth</code> and <code>authority</code> parameters.</para>

    <example>
      <title>Example of bridge configuration</title>

      <para>A bridge configured with a SAML 2.0 IdP and a Shibboleth 1.3 SP:
      In the <filename>saml20-idp-hosted.php</filename> metadata you configure
      the authentication to use Shibboleth 1.3 SP like this:</para>

      <programlisting>'auth' =&gt; 'shib13/sp/initSSO.php',
'authority' =&gt; 'shib13'
</programlisting>

      <para>As no specific Shibboleth IdP is specified as parameter to the
      <filename>initSSO.php</filename> script, the discovery service page will
      be shown. If you want to connect the SAML 2.0 IdP to a specific
      Shibboleth 1.3 IdP, give the entity id as a parameter to the
      <filename>initSSO.php</filename> script:</para>

      <programlisting>'auth' =&gt; 'shib13/sp/initSSO.php?idpentityid=shib13idp.example.org',
'authority' =&gt; 'shib13'
</programlisting>
    </example>
  </section>

  <section>
    <title>Attribute control</title>

    <para>You have several options for controlling which attributes are sent
    to services.This chapter discusses functionality for filtering and
    modification of attributes.</para>

    <section>
      <title>Attribute filtering</title>

      <para>Attribute filtering restricts the selection of attributes sent to
      each service. This option is placed in the service provider metadata
      files.</para>

      <para>In the <filename>shib13-sp-remote.php</filename> or
      <filename>saml20-sp-remote.php</filename> metadata file, you may add a
      parameter <code>attributes</code>, limiting theattributes to be sent to
      the SP to those named in this list. If you omit this parameter, all
      available attributes are sent.</para>

      <example>
        <title>Example of attribute filtering</title>

        <para>Here is a metadata entry for a remote SP that will only receive
        the two attributes <code>eduPersonPrincipalName</code> and
        <code>mail</code>:</para>

        <programlisting>'dev.andreas.feide.no' =&gt; array(
  'AssertionConsumerService' =&gt; 'http://dev.andreas.feide.no/simplesaml/saml2/sp/AssertionConsumerService.php', 
  'SingleLogoutService'      =&gt; 'http://dev.andreas.feide.no/simplesaml/saml2/sp/SingleLogoutService.php',
  'attributes'               =&gt; array('eduPersonPrincipalName', 'mail'),
),</programlisting>
      </example>
    </section>

    <section>
      <title>Attribute name mapping</title>

      <para>When bridging between federations, attribute names may differ for
      a given property. To handle this, you may configure an attribute name
      mapping table.</para>

      <para>The mapping table is defined as a PHP array in a file in the
      <filename>attributemap</filename> directory. E.g. you may define a
      mapping table from Feide to EduGAIN in
      <filename>attributemap/feide2edugain.php</filename> that might look like
      this:</para>

      <programlisting>&lt;?php

$attributemap = array(
  'mobile' =&gt; 'urn:mace:dir:attribute-def:mobile'
);

?&gt;
</programlisting>

      <para>IdP hosted metadata or SP remote metadata may identify an
      attribute name mapping table in the parameter
      <literal>attributemap</literal>.</para>

      <example>
        <title>Example of attribute mapping</title>

        <para>Here is an example of
        <filename>saml20-idp-hosted.php</filename>, configuring the mapping
        table defined above:</para>

        <programlisting>'test.andreas.feide.no' =&gt; array(
 'host'         =&gt; 'dev2.andreas.feide.no',
 'privatekey'   =&gt; 'googleappsidp.pem',
 'certificate'  =&gt; 'googleappsidp.crt',
 'auth'         =&gt; 'auth/login.php',

 'attributemap' =&gt; 'feide2edugain'
),</programlisting>

        <para>This will process the attributemap
        <literal>feide2edugain</literal> for all SPs that connects to the SAML
        2.0 IdP <literal>test.andreas.feide.no</literal>. Alternatively the
        parameter can be configured to the SP remote metadata, where it will
        be processed for that specific SP only.</para>
      </example>
    </section>

    <section>
      <title>Attribute alter functions</title>

      <para>You can implement attribute alter functions that filters, injects,
      modifies or removes attributes. E.g. you may create a function
      extracting the part following the '@' of the eduPersonPrincipalName
      attribute (e.g. <literal>uninett.no</literal> in
      <literal>andreas@uninett.no</literal>), and define this a new attribute
      with the name <literal>realm</literal>.</para>

      <para>Attribute alter functions are named by the attribute name prefixed
      with <code>attributealter_</code>, and are stored in a file in the
      <filename>attributealter/</filename> directory. The filename for a given
      attribute alter functions must be named with the function name. The
      attribute alter function should have the name of the attribute, but
      prefixed with <literal>attributealter_</literal>, e.g.
      <literal>attributealter_realm for the <code>realm</code>
      attribute</literal> this function should then be placed in
      <filename>attributealter/realm.php</filename>. The function signature
      should be:</para>

      <programlisting>function attributealter_realm(&amp;$attributes, $spentityid = null, $idpentityid = null) {</programlisting>

      <para>The function receives a reference to the <code>attributes</code>
      array, containing the attributes that will be sent to the service. h,
      and may add new attributes into this array. The function also receives
      the entity IDs of the SP and the IdP.</para>

      <para>When doing bridging installation the IdP entity ID given to
      attribute alter functions is the ID of the hosted IdP (the bridge) and
      not remote IdP where the user actually came from. The correct IdP
      (remote one) is found in the session object. e.g. in an alter
      function:</para>

      <para><programlisting>...
$session = SimpleSAML_Session::getInstance();
$remoteidp = $session-&gt;getIdp();
...</programlisting></para>

      <para>The attribute alter function must be declared in the metadata for
      the IdP or SP metadata, similar to the 'attributemap' parameter
      discussed above: The <code>'attributealter'</code> parameter names the
      attributes defined by attribute alter functions:</para>

      <para><programlisting>'test.andreas.feide.no' =&gt; array(
 'host'           =&gt; 'dev2.andreas.feide.no',
 'privatekey'     =&gt; 'googleappsidp.pem',
 'certificate'    =&gt; 'googleappsidp.crt',
 'auth'           =&gt; 'auth/login.php',

 'attributealter' =&gt; 'realm'
),</programlisting></para>

      <para>If more than one function is defined, the parameter should be an
      array of names.</para>

      <para>Here is the complete example function which must be placed in the
      file <filename>attributealter/realm.php</filename>:</para>

      <programlisting>function attributealter_realm(&amp;$attributes, $spentityid = null, $idpentityid = null) {

  $attributename = 'eduPersonPrincipalName';
  if (array_key_exists($attributename, $attributes)) {
    $eduppn = $attributes[$attributename][0];
    $split = explode('@', $eduppn);
    if (count($split) &gt; 1) {
      $attributes['realm'] = array($split[1]);
    } else {
      SimpleSAML_Logger::debug('attributealter_realm: Wrong format of ' . $attributename . ' (missing @)');
    }
  } else {
    SimpleSAML_Logger::debug('attributealter_realm: Could not find ' . $attributename);
  }

}</programlisting>

      <itemizedlist>
        <listitem>
          <para><ulink
          url="https://ow.feide.no/simplesamlphp:alterfunctions">This wiki
          page on the simpleSAMLphp wiki page is supposed to hold several
          example attribute alter functions as inspiration for others</ulink>.
          Please contribute with your attribute alter functions to this page.
          Contact Andreas, if you have not access to the wiki and want to add
          some examples.</para>
        </listitem>
      </itemizedlist>
    </section>

    <section>
      <title>In which order are the attribute tweaking functions
      executed?</title>

      <para>The order is:</para>

      <orderedlist>
        <listitem>
          <para>IdP specific attributemap</para>
        </listitem>

        <listitem>
          <para>SP specific attributemap</para>
        </listitem>

        <listitem>
          <para>IdP specific attributealter</para>
        </listitem>

        <listitem>
          <para>SP specific attributealter</para>
        </listitem>

        <listitem>
          <para>SP specific attribute filter</para>
        </listitem>
      </orderedlist>
    </section>
  </section>

  <section>
    <title>Automatic update of SAML 2.0 Metadata XML from HTTPS</title>

    <para>simpleSAMLphp supports the SAML 2.0 Metadata XML format. There are
    mulitple ways of using simpleSAMLphp with SAML 2.0 Metadata XML documents,
    but the reccomended approach is to use the command line utility
    <filename>bin/parseMetadata.php</filename> to download and parse metadata
    from a HTTPS location. This script will grab the XML document from a URL
    and parse the content and output simpleSAMLphp flat files in a directory.
    In the <filename>config.php</filename> configuration you should configure
    simpleSAMLphp to read these files generated by
    <filename>parseMetadata.php</filename>.</para>
  </section>

  <section>
    <title>Automated testing</title>

    <para>simpleSAMLphp includes a test script that can connect to a
    simpleSAMLphp SP, initiate login, enter some credentials. It then picks up
    the response to the SP and validates it, checking the output for expected
    attributes.</para>

    <para>The intention of this script is to be run in system monitoring
    systems, like nagios or hobbit, to generate alerts when something breaks
    (e.g. a server is down or metadata misconfigured).</para>

    <para>The test script is located in <filename>bin/test.php</filename>. The
    configuration file is located in
    <filename>config/test.php</filename>.</para>

    <para>Documentation about configuration file format and more details about
    this test script will be added later. If you e.g. write a nagios plugin
    for this test script, let us know :) We will add a hobbit plugin and
    publish it somewhere pretty soon. Stay tuned!</para>
  </section>

  <section>
    <title>Auth MemCookie</title>

    <para>It is possible to integrate simpleSAMLphp with <ulink
    url="http://authmemcookie.sourceforge.net/">Auth MemCookie</ulink>. This
    allows you to integrate simpleSAMLphp with web applications written in
    another language than PHP.</para>

    <para>Auth MemCookie works by reading authentication data from a memcache
    server and setting environment variables based on attributes in this data.
    It also allows you to use the default Apache access control features to
    restrict access to your site.</para>

    <para>The simpleSAMLphp Auth MemCookie module can be found in
    <filename>www/authmemcookie.php</filename> and the configuration should be
    stored in <filename>config/authmemcookie.php</filename>. You may have to
    copy this file from
    <filename>config-template/authmemcookie.php</filename>.</para>

    <para>To use Auth MemCookie, you need to do the following steps:</para>

    <orderedlist>
      <listitem>
        <para>Install and configure simpleSAMLphp for running as an SP.</para>
      </listitem>

      <listitem>
        <para>Install and configure a memcache server.</para>
      </listitem>

      <listitem>
        <para>Install and configure Auth MemCookie. Go to the <ulink
        url="http://authmemcookie.sourceforge.net/">Auth MemCookie
        homepage</ulink> for downloads and installation instructions. The
        following example (from
        <filename>extra/auth_memcookie.conf</filename>) may be useful when
        configuring Auth MemCookie:</para>

        <para><programlisting>&lt;Location /&gt;
        # This is a list of memcache servers which Auth MemCookie
        # should use. It is a ','-separated list of
        # host:port-pairs.
        # Note that this list must list the same servers as the
        # 'authmemcookie.servers'-option in config.php in the
        # configuration for simpleSAMLphp.
        Auth_memCookie_Memcached_AddrPort "127.0.0.1:11211"

        # This must be set to 'on' to enable Auth MemCookie for
        # this directory.
        Auth_memCookie_Authoritative on

        # This adjusts the maximum number of data elements in the
        # session data. The default is 10, which can be to low.
        Auth_memCookie_SessionTableSize "40"

        # These two commands are required to enable access control
        # in Apache.
        AuthType Cookie
        AuthName "My Login"

        # This command causes apache to redirect to the given
        # URL when we receive a '401 Authorization Required'
        # error. We redirect to "/simplesaml/authmemcookie.php",
        # which initializes a login to the IdP.
        ErrorDocument 401 "/simplesaml/authmemcookie.php"

&lt;/Location&gt;

&lt;Location /secret&gt;
        # This allows all authenticated users to access the
        # directory. To learn more about the 'Require' command,
        # please look at:
        # http://httpd.apache.org/docs/2.0/mod/core.html#require
        Require valid-user
&lt;/Location&gt;</programlisting></para>
      </listitem>

      <listitem>
        <para>Configure the simpleSAMLphp Auth MemCookie module by editing
        <filename>config/authmemcookie.php</filename>. You must set the
        <option>username</option> option to a valid attribute name. All other
        can most likely be left at their default values.</para>
      </listitem>

      <listitem>
        <para>Enable the simpleSAMLphp Auth MemCookie module by setting
        <option>enable.authmemcookie</option> to <parameter>true</parameter>
        in <filename>config/config.php</filename>.</para>
      </listitem>

      <listitem>
        <para>To test the installation, you can add the following script as
        your <filename>/secret/index.php</filename> directory:</para>

        <para><programlisting>&lt;html&gt;&lt;body&gt;&lt;table&gt;
&lt;?php
foreach($_SERVER as $key=&gt;$value) {
  echo('&lt;tr&gt;&lt;td&gt;' . htmlspecialchars($key) . '&lt;/td&gt;&lt;td&gt;' . htmlspecialchars($value) . '&lt;/td&gt;&lt;/tr&gt;');
}
?&gt;
&lt;/table&gt;&lt;/body&gt;&lt;/html&gt;</programlisting></para>

        <para>You should now be able to go to
        <filename>http://yourserver/secret/</filename> to test the
        configuration. You should be redirected to your IdP, and after
        entering your username and password you should be taken back to
        <filename>http://yourserver/secret/</filename>. The resulting page
        should list all environment variables set by Apache, including the
        ones set by Auth MemCookie.</para>
      </listitem>
    </orderedlist>
  </section>

  <section>
    <title>Metadata signing</title>

    <para>simpleSAMLphp supports signing of the metadata it generates.
    Metadata signing is configured by four options:</para>

    <itemizedlist>
      <listitem>
        <para><literal>metadata.sign.enable</literal>: Whether metadata
        signing should be enabled or not. Set to <literal>TRUE</literal> to
        enable metadata signing. Defaults to <literal>FALSE</literal>.</para>
      </listitem>

      <listitem>
        <para><literal>metadata.sign.privatekey</literal>: Name of the file
        with the private key which should be used to sign the metadata. This
        file must exist in in the <literal>cert</literal> directory.</para>
      </listitem>

      <listitem>
        <para><literal>metadata.sign.privatekey_pass</literal>: Passphrase
        which should be used to open the private key. This parameter is
        optional, and should be left out if the private key is
        unencrypted.</para>
      </listitem>

      <listitem>
        <para><literal>metadata.sign.certificate</literal>: Name of the file
        with the certificate which matches the private key. This file must
        exist in in the <literal>cert</literal> directory.</para>
      </listitem>
    </itemizedlist>

    <para>These options can be configured globally in the
    <literal>config/config.php</literal>-file, or per SP/IdP by adding them to
    the hosted metadata for the SP/IdP. The configuration in the metadata for
    the SP/IdP takes precedence over the global configuration.</para>

    <para>There is also an additional fallback for the private key and the
    certificate. If <literal>metadata.sign.privatekey</literal> and
    <literal>metadata.sign.certificate</literal> isn't configured,
    simpleSAMLphp will use the <literal>privatekey</literal>,
    <literal>privatekey_pass</literal> and <literal>certificate</literal>
    options in the metadata for the SP/IdP.</para>
  </section>

  <section>
    <title>Attribute release consent</title>

    <para>simpleSAMLphp can be configured to require the user to give consent
    before his or her attributes are released to the service provider. The
    users consent choices can optionally be stored to a database.</para>

    <para>Attribute release consent is enabled on a per-IdP basis by setting
    the <literal>requireconsent</literal> option in the metadata of the IdP.
    It is supported by both the SAML 2.0 and Shib 1.3 IdP. This is all you
    need to do if you don't want to allow simpleSAMLphp to remember the user's
    consent choices.</para>

    <section>
      <title>Consent storage setup</title>

      <para>Consent storage requires a database to store the consent
      information in. MySQL and PostgreSQL are tested and known to work. The
      consent will be stored in a table named <literal>consent</literal>. This
      table can be created with the following command:</para>

      <programlisting>CREATE TABLE consent (
  hashed_user_id varchar(128) NOT NULL,
  service_id varchar(128) NOT NULL,
  attribute varchar(128) NOT NULL,
  consent_date timestamp NOT NULL,
  usage_date timestamp NOT NULL,
  PRIMARY KEY (hashed_user_id, service_id)
);</programlisting>

      <para>Consent storage is controlled by the following options in
      <literal>config/config.php</literal>:</para>

      <para><glosslist>
          <glossentry>
            <glossterm>consent_usestorage</glossterm>

            <glossdef>
              <para>Whether the consent storage module should be enabled. Set
              this to <literal>TRUE</literal> to allow simpleSAMLphp to
              remember the user's consent choices.</para>
            </glossdef>
          </glossentry>

          <glossentry>
            <glossterm>consent_userid</glossterm>

            <glossdef>
              <para>This is the name of the attribute which should be used to
              uniquely identify each user. It is important that the value of
              the attribute uniquely identifies a single user - otherwise
              several users will share the same consent information. The
              default attribute is
              <literal>eduPersonPrincipalName</literal>.</para>
            </glossdef>
          </glossentry>

          <glossentry>
            <glossterm>consent_salt</glossterm>

            <glossdef>
              <para>This option should be set to a random valid PHP string.
              This option is used when hashing values which are stored in the
              database.</para>
            </glossdef>
          </glossentry>

          <glossentry>
            <glossterm>consent_pdo_connect</glossterm>

            <glossdef>
              <para>This is the DSN for the database where the consent
              information is stored. See the <ulink
              url="http://www.php.net/manual/en/pdo.drivers.php">database
              driver specific documentation</ulink> in the PHP documentation
              for information about the syntax. The DSN syntax for the MySQL
              driver can be found <ulink
              url="http://www.php.net/manual/en/ref.pdo-mysql.connection.php">
              here</ulink>.</para>
            </glossdef>
          </glossentry>

          <glossentry>
            <glossterm>consent_pdo_user</glossterm>

            <glossdef>
              <para>This is the username which should be used when
              authenticating with the database server.</para>
            </glossdef>
          </glossentry>

          <glossentry>
            <glossterm>consent_pdo_passwd</glossterm>

            <glossdef>
              <para>This is the password which should be used when
              authenticating with the database server.</para>
            </glossdef>
          </glossentry>
        </glosslist></para>
    </section>
  </section>

  <section>
    <title>Support</title>

    <para>If you need help to make this work, or want to discuss simpleSAMLphp
    with other users of the software, you are fortunate: Around simpleSAMLphp
    there is a great Open source community, and you are welcome to join! The
    forums are open for you to ask questions, contribute answers other further
    questions, request improvements or contribute with code or plugins of your
    own.</para>

    <itemizedlist>
      <listitem>
        <para><ulink url="http://rnd.feide.no/simplesamlphp">simpleSAMLphp
        homepage (at Feide RnD)</ulink></para>
      </listitem>

      <listitem>
        <para><ulink url="http://rnd.feide.no/view/simplesamlphpdocs">List of
        all available simpleSAMLphp documentation</ulink></para>
      </listitem>

      <listitem>
        <para><ulink
        url="http://rnd.feide.no/content/simplesamlphp-users-mailinglist">Join
        the simpleSAMLphp user's mailing list</ulink></para>
      </listitem>

      <listitem>
        <para><ulink url="https://ow.feide.no/simplesamlphp:start">Visit and
        contribute to the simpleSAMLphp wiki</ulink></para>
      </listitem>
    </itemizedlist>
  </section>
</article>