4. Active Directory Singel Sign-On extended to SimpleSAMLphp

TODO

The goal of this guide is to be able to authenticate users by Active Directory (AD) credentials using Kerberos SPNEGO mechanism. If a SPNEGO token is not available, offer a secondary two factor (2FA) authentication mechanism. The SimpleSAMLphp module Negotiate offer the Simple And Protected Negotiate (SPNEGO) mechanism. The SPNEGO token is a Kerberos service ticket encoded in a platform independent manner ASN.1 DER format.


From the Negotiate module documentation:

“In effect this module aims to extend the Microsoft AD SSO session to the SAML IdP. (Or any other Kerberos domain) It doesn't work like this of course but for the user the client is automatically authenticated when an SP sends the client to the IdP. In reality Negotiate authenticates the user via SPNEGO and issues a separate SAML session. The Kerberos session against the Authentication Server is completely separate from the SAML session with the IdP”

 

The module will be used to authenticate a user by the HTTP-Based Cross-Platform Negotiate Protocol. When the browser is redirected from the SP to the IdP single sign on end point the IdP responds with a HTTP 401 challenge header. The users AD credentials is used to request a valid Kerberos service ticket from the KDC. The ticket is encoded into a SPNEGO token and transferd to the IdP.

 

If the browser aren't configured correctly or the Kerberos ticket is missing. It is up to the browser to solve this. Some browser will prompt the user for a user-name and a password (NTLM) and not proceed until the users have entered the credentials. This is not what we want. If the browser are unable to supply a valid kerberos ticket the IdP should display the 2FA page.

 

The SimpleSAMLphp Radius module are used as the secondary authentication mechanism for 2FA. How to setup the radius server is out of scope and will not be explained in this guide.

The Negocheck Module

The SimpleSAMLphp default login page must be extended with the JavaScript and AJAX code. By defining a theme in a module the module can override the default login page. The default loginuserpass.php is included in the theme but are altered to run the negocheck code.

Login Flow

The login flow must be able to check if the browser is able to respond to a 401 challenge header. AJAX send requests asynchronously in the background. Utilizing AJAX to separate the process of checking for a SPNEGO token from the presentation layer, it is possible to load the 2FA page but hiddend and with JavaScript execute the AJAX request. If the AJAX request do not return or return SPNEGO not available the 2FA page are already loaded and will be displayed.



  1. The flow begins when the user agent (browser) access a secured resource at the SP

  2. The user agent is redirected to the IdP SSO endpoint. The negochek theme is loaded and the login page are sent to the user agent

  3. On load of the login page the <div> elements are hidden until the configured time limit. By doing it this way the page are loaded and if the check for a valid SPNEGO token halts the login page are displayed

  4. Execute the check for the SPNEGO token. Send an AJAX GET request to the IDP. The IDP will respond by issuing a 401 Unauthorized. If the user agent returns a valid SPNEGO token the AJAX request will return SPNEGOAvailable. In case the user agent doesn't provide a valitd SPNEGO token the returned value will be SPNEGONotAvailable

  5. If the AJAX request returns SPNEGOAvailable the SimpleSAMLphp module Negotiate will be used to authenticate the user. For any client/user that fails authentication the Negotiate module are configured to fall back to the initial authentication module. If the returned value is SPNEGONotAvailable the login page is already loaded and will be displayed.

  6. The user is authenticated and the user agent will proceed to the SP and consume the target resource.

Install PHP extensions

Install PHP extensions to be able to supprt Radius and Kerberos Negotiate authentication

sudo apt-get install php5-dev libkrb5-dev php-pear
sudo pecl install krb5
sudo pecl install radius
echo "extension=krb5.so" | tee /etc/php5/mods-available/krb5.ini
echo "extension=radius.so" | tee /etc/php5/mods-available/radius.ini
cd /etc/php5/apache2/conf.d/
ln -s ../../mods-available/krb5.ini 20-krb5.ini
ln -s ../../mods-available/radius.ini 20-radius.ini

Configure Apache

Add the rewrite rules to the Apache simpleSAMLphp configuration.

  Alias /simplesaml "/var/simplesamlphp/www"
   <Directory "/var/simplesamlphp/www">
      RewriteEngine on
      RewriteCond %{HTTP:Authorization}  !^$
      RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
      Require all granted
   </Directory>

 

Enable the rewrite module and restart Apache.

sudo a2enmod rewrite
sudo service apache2 restart

Generate the keytab file

This task is performed on the AD domain controller.

 

Create a user account in the Active Directory

Use ADSI Edit to locate the user account

Right-click the user account object, and then click Properties

Click the Attribute Editor tab

Click filter and ensure that Constructed is selected

Locate msDS-KeyVersionNumber in the Attributes list.

ktpass -princ HTTP/mysimplesamlphpserver.example.com@MYADDOMAIN -mapuser DOMAIN_NETBIOS\username -pass mypassword -out krb5.keytab /crypto RC4-HMAC-NT /kvno msDS-KeyVersionNumber_from_previus_step -ptype KRB5_NT_SRV_HST

 

Move the ketab file krb5.keytab to the directory /var/simplesamlphp/config on the SimpleSAMLphp host.

 

Set permissions

cd /var/simplesamlphp
chown root:www-data config/krb5.keytab
chmod 440 config/krb5.keytab

Configure the Radius module (2FA).

Enable the module

cd /var/simplesamlphp
touch modules/radius/enable

 

Change the parameters to match the intended environment then add the configuration to config/authsource.php

'2FA' => array(
    'radius:Radius',
    'servers' => array(
        array(
            'hostname' => 'radius.example.com',
            'port'     => 18121,
            'secret'   => 'verysecuresecret',
        ),
    ),
    'username_attribute' => 'sAMAccountName',
),

 

Get the attributes from the AD using the LDAP module.

touch modules/ldap/enable

 

Change the parameters to match the intended environment then add the configuration to metadata/saml20-idp-hosted.php.

/* UID */
'userid.attribute' => 'uid',

/* Fix attributes */
'AttributeNameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',

/* Additional IDP-specific authentication processing filters */
'authproc' => array(
   100 => array(
        'class' => 'core:AttributeAlter',
        'subject' => 'sAMAccountName',
        'pattern' => '/([^@]+)/',
        '%replace',
        'target' => 'uid',
    ),
    110 => array(
        'class' => 'ldap:AttributeAddFromLDAP',
        'attributes' => array('mail','displayName'),
        'attribute.policy' => 'merge',
        'search.filter' => '(sAMAccountName=%uid%)',
        'ldap.basedn'   => 'ou=All Users,dc=office,dc=nic,dc=se',
        'ldap.hostname' => 'ldaps://2k8r2dc1.office.nic.se ldaps://2k8r2dc2.office.nic.se ldaps://2k8r2dc3.office.nic.se',
        'ldap.username' => 'CN=2fa,OU=Service Accounts,dc=office,dc=nic,dc=se',
        'ldap.password' => '1sNNG2Tf-elhdLW',
        'ldap.product'  => 'ActiveDirectory',
        'ldap.timeout'  => 2,
        'ldap.debug'    => FALSE,
    ),
),

/*
 * Authentication source to use. Must be one that is configured in
 * 'config/authsources.php'.
 */
'auth' => '2FA',

Configure the Negotiate module

Change the parameters then add the configuration to config/authsources.php

 'negotiate' => array(
    'negotiate:Negotiate',
    'keytab' => '/etc/krb5.keytab',
    'fallback' => '2FA',
    'attr' =>'sAMAccountName',
    'hostname' => 'ldaps://dc1.example.com ldaps://dc2.example.com',
    'base' =>'ou=Users,dc=example,dc=com',
    'adminUser' => 'CN=negotiate,OU=Users,dc=example,dc=com',
    'adminPassword' => 'verysecurepassword',
    'timeout' => 2,
    'referrals' => FALSE,
    'attributes' => array('sAMAccountName','mail','displayName'),
),


Install the Negocheck module

Download the Negocheck module #LINK# and extrackt to the SimpleSAMLphp module directory.

wget #LINK#
sudo tar xvzfC file /var/simplesamlphp/modules/
 

 

Enable the module

cd /var/simplesamlphp
sudo touch modules/negocheck/enable

 

Configure the module

cp modules/negocheck/config-template/config-negocheck.php config/
sudo vim config/config-negocheck.php


$config = array(
    /**
    * The name of the autentication source that configures the negotiate module.
    */
    'authsource' => 'negotiate',

    /**
     * Set divshow and divhide to the div tags on the fallback page to hide them
     * when checking if kerberos authentication is possible.
     * Set timeout in milliseconds to hide the tags for the specified number of milliseconds.
     */
    'divshow' => array(
                    'login' => 'block',
                    'languagebar' => 'block',
    ),
    'divhide' => array(
                    'login' => 'none',
                    'languagebar' => 'none',
    ),
    'timeout' => 3000,
);

Enable the theme

Since the Negocheck test are executed by a theme the theme must be enabled. Edit the file config/config.php and locate the parameter theme.use.

vim config/config.php
'theme.use' => 'negocheck:negocheck',