Child pages
  • Configuring a simpleSAMLphp SP for step-up authentication
Skip to end of metadata
Go to start of metadata

The example script below demonstrates how you can use SimpleSAMLphp to:

  • Request a specific minimum level op assurance (LoA) from the step-up gateway
  • Verify the LoA at which the step-up gateway authenticated a user

To use this example:

  1. Configure a SimpleSAMLphp SAML 2.0 hosted SP named "default-sp" by following the instructions on
  2. Add the step-up gateway as SAML 2.0 identity provider to <simplesaml>/metadata/saml20-idp-remote.php. See below for configuration example.
  3. Put the sp.php example script below in the <simplesaml>/www directory

Note: depending on what environment you are using (Production, Pilot) you need to adapt the example code with the correct LoA identifiers (e.g. in $gLOAmap below). Different environments use different identifiers!

// Include SimpleSAMLphp. Assume this script is placed in the <simplesaml>/www dir.

// Name of session variable for storing the min required LOA for a login
define( 'SSP_SESSION_MIN_LOA', 'RequestedMinLOA' );

// Build return URL. This is where ask simplesamlPHP to direct the browser to after login or logout
// Point to this script, but without any request parameters so we won't trigger an login again (and again, and again, and ...)
$returnURL = ($_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://';
$returnURL .= $_SERVER['HTTP_HOST'];
$returnURL .= $_SERVER['SCRIPT_NAME'];

// Map integer level of assurance level to identifier used by the gateway
// Note: these identifiers differ between environments!
$gLOAmap = array(
    1 => '',
    2 => '',
    3 => '',

try {
    // Init SP instance
    // Assumes you have setup a SP named "default-sp" in <simplesaml>/config/authsources.php
    // See:
    $as = new SimpleSAML_Auth_Simple('default-sp');    // Init SP instance

    /** @var $session SimpleSAML_Session */
    $session = SimpleSAML_Session::getInstance();

    // Process login action. Assumes the login function of your SP uses ...?action=login
    if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'login' ) {

        // We use the SSP session to keep track of the LOA we want.
        // Unset any existing RequiredAuthnContextClassRef
        $session->deleteData('string', SSP_SESSION_MIN_LOA);

        // login
        $requiredLOA = 2; // The LOA we want.

        // Store the requested LOA in the session so we can verify it later
        $session->setData('string', SSP_SESSION_MIN_LOA, $requiredLOA);

        $as->login( array(
            'ReturnTo' => $returnURL,
            'ForceAuthn' => false,
            'saml:AuthnContextClassRef' => $gLOAmap[$requiredLOA]  // Specify LOA
        ) );

        exit;   // Never reached. Added for clarity

    // Process logout action
    if( isset($_REQUEST['action']) && $_REQUEST['action'] == 'logout' ) {
        $as->logout( array (
            'ReturnTo' => $returnURL,
        ) );  // Process logout

        exit;   // Never reached. Added for clarity

    // Display HTML page

    echo <<<head
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "">
    <html xmlns="" xml:lang="en" lang="en">
            <meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
            <style type="text/css">
                table,th,td {border: 1px solid black;}
                th,td {padding 1px}
            <title>simpleSAMLphp Demo</title>
            <h1>SimpleSAMLphp LOA Demo</h1>

    // Show some info when authenticated
    if ( $as->isAuthenticated() ) {
        $attributes = $as->getAttributes();

        $requestedLoA = $session->getData('string', SSP_SESSION_MIN_LOA);    // What we requested during login
        $authState = $session->getAuthState();
        $authnConext = $authState['saml:sp:AuthnContext'];
        $nameID = $session->getNameID();
        $authnInstant = gmdate('r', $authState['AuthnInstant'] );
        $expire = gmdate('r', $authState['Expire'] );

        echo "<h2>You are logged in</h2>";

        echo "<h3>SimpleSAMLphp Session</h3>";
        echo "<p>SimpleSAMLphp session start: <b>{$authnInstant}</b></br />";
        echo "SimpleSAMLphp session expire: <b>{$expire}</b></p>";

        echo "<h3>LOA</h3>";
        echo "<p>Received authnConext: <b>{$authnConext}</b></p>";

        // Map LoA identifier back to integer LoA level
        $actualLoA = array_search($authnConext, $gLOAmap);
        if (false ==! $actualLoA)
            echo "<p>Actual LoA is: <b>{$actualLoA}</b></p>";
            $actualLoA = -1;

        if (NULL !== $requestedLoA) {
            echo "<p>Requested LoA was: <b>{$requestedLoA}</b></p>";
            if ($actualLoA >= $requestedLoA)
                echo '<p><b>You were authenticated at or above the minimally required LoA</b></p>';
                echo '<p><b>You were NOT authenticated at the required LoA</b></p>';

        echo <<<html

        echo <<<html
        <h3>SAML Attributes</h3>
        foreach ($attributes as $attrName => $attrVal) {
            echo "<tr><td>{$attrName}</td><td>";
            if (is_array($attrVal))
                echo implode('<br />', $attrVal);
                echo $attrVal;
            echo "</td>";
        echo <<<html

            <form name="logout" action="{$returnURL}" method="get">
               <input type="hidden" name="action" value="logout"/>
               <input type="submit" value="Logout" />
    } else {
        echo <<<html
            <h2>Your are not logged in</h2>

    echo <<<html
            <h3>Login (again)</h3>
                <form name="login" action="{$returnURL}" method="get">
                   <input type="hidden" name="action" value="login"/>
                   <input type="submit" value="Login" />

    echo <<<html
catch (Exception $e)
    echo $e->getFile().':'.$e->getLine().' : '.$e->getMessage();
$metadata[''] = array (
    'entityid' => '',
    'metadata-set' => 'saml20-idp-remote',
    'SingleSignOnService' =>
        array (
            0 =>
                array (
                    'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
                    'Location' => '',
    'keys' =>
        array (
            0 =>
                array (
                    'encryption' => false,
                    'signing' => true,
                    'type' => 'X509Certificate',
                    'X509Certificate' => 'MIIDGTCCAgGgAwIBAgIJAKkrrAirCzVBMA0GCSqGSIb3DQEBBQUAMCMxITAfBgNVBAMMGFNBTUwgR2F0ZXdheSBTaWduaW5nIEtleTAeFw0xMzEwMjMxMjMyMDlaFw0xMzExMjIxMjMyMDlaMCMxITAfBgNVBAMMGFNBTUwgR2F0ZXdheSBTaWduaW5nIEtleTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANw/+yw5EUmJRMA83oRy6mNgh46KYKZzDgH4yHi51RxvSHfbrewfN6e4nUCr+Jid3jH01Ga/tbOQ4t/uMyybwQ/+0sv8PAhsfEy7I/fKXVG8e93fAKg+6TeRfwntFtmd3EhUrZzldYCo3d8LOnrhhmPbh3Y1DwR3ozkyZzL9BHC+0JfKqdLUvo8OI08jjc7Vn/EM7MXmf3p7Ojx6mDqfuwgjBGDDnwpqox9i4TcCkoJB32XdGrmxlK+/yUDxfjF5pMFGKTNKhVZ2Ozdx8e52E6+L8g7ohBxHNxeYBNNWcklPb5AJSM95keb67vtLSe9bHP43GsyeMuurunEziAvWzvcCAwEAAaNQME4wHQYDVR0OBBYEFIj2o9DBY3s2vHLJUZVjz6sXicb1MB8GA1UdIwQYMBaAFIj2o9DBY3s2vHLJUZVjz6sXicb1MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAF995US913G8e9dmu1ygQoDGVPGO0xE2k9vKkMrX6ioxRBPU77dhlVez4krF6t5g1UCBK/RlrBfAmNtBwFjYX16ThQPZWtwcu9Pibta5GtsZPZWEWyfEZWj6QIsmK8YTSryq7UC2NjnOCl1rQTY0MUkiU6a0/KZUqLzrQUhdatrV2LwN28x66G+kH59XY0DQhXwh5NnZ7T5jqSJ4j7xfevvVJbN6q/IXpzgoMjzMiMfog8BN/TjQbzUhrokTi+KB4OilPT6et1D1K0PU84I8ZoNd12sq2UXYa5Q4CL3mxHQz4p9jlDbe0EvpyTKbxt2p3HrodDhqpkfOjCObMLdl8Io=',
  • No labels