AuthUserSaml

Summary: SAML authentication extension for AuthUser
Version: 2022-11-08
Prerequisites: authuser, pmwiki 2.3.7+ (not tested on older versions, but may work)
Status: In active use
Maintainer: Harco Kuppens
License: BSD-3-clause
Users: (View? / Edit?)

Questions answered by this recipe

How can I add "login with SAML" option to my PMWiki?

Description

SAML authentication extension for AuthUser.

This recipe adds the directive:

  • (:saml_loginbox:)

Notes

Security Assertion Markup Language(SAML) is an open standard for exchanging authentication and authorization data between parties, in particular, between an identity provider and a service provider. See https://en.wikipedia.org/wiki/Security_Assertion_Markup_Language for a more extensive explanation.

This extension uses the SAML implementation library from SimpleSAMLphp (https://simplesamlphp.org) for integrating SAML authentication into AuthUser. Look at the documentation about SimpleSAMLphp at https://simplesamlphp.org/docs and in particularly the SimpleSAMLphp Service Provider QuickStart page.

In the AuthUserSaml GitHub repository is a docker-examples/ directory which contains 3 examples of an identity provider and a service provider setup using SimpleSAMLphp. Each example is run with docker compose to start both the identity provider and a service provider at once. One example demonstrates SAML with a simple php script, and the other two examples with pmwiki as service provider; once for a basic config, and the other with a more advanced config. The advanced PmWiki example is also used to show Single SignOn and Single Logout feature of SAML by using docker compose to start one instance of IDP and two separate instances of the PmWiki website:

  • Single SignOn(SSO): if you login to one PmWiki website with your credentials, you can directly login to the other PmWiki website without needing to supply your credentials again.
  • Single Logout(SSL): if you logout from one PmWiki website you are directly logged out from the other PmWiki website.

Take a look at these examples to better understand how it all works. The docker-examples/ directory is also in the AuthUserSaml release.

Installation Process

install cookbook script

1. Create a subdirectory named AuthUserSaml in the cookbook directory. Then copy the file AuthUserSaml.php from the release zip into this directory.

2. edit your local/farmconfig.php or local/config.php file just before line including authuser.php to add the following line

 include_once("$FarmD/cookbook/AuthUserSaml/AuthUserSaml.php"); // Must be included before authuser

4. Modify your wiki's Site.AuthForm Page to include (suit to your needs):

  (:saml_loginbox:)

You can change the text in the login button by setting the $AuthUserSaml_ButtonText variable in your local/farmconfig.php or local/config.php file.

5. Modify you wiki's Site.PageActions (and other similar locations) by replacing

 (:if enabled AuthPw:)
 * %item rel=nofollow class=logout    accesskey="$[ak_logout]"%''  [-[[{*$FullName}?action=logout | $[Logout] ]]-]''
 (:ifend:)

with

 (:if authid:)
 * %item rel=nofollow class=logout    accesskey="$[ak_logout]"%''  [-[[{*$FullName}?action=logout | $[Logout] {$AuthId} ]]-]''
 (:else:)
 * %item rel=nofollow class=login    accesskey="$[ak_login]"%''  [-[[{*$FullName}?action=login | $[Login] ]]-]''
 (:ifend:)

6. Set your AuthUser permissions as you wish.
A good basic example is provided in the config.php file in the pmwiki.basic docker example which sets authorisation rules such that:

  • everone : read permission
  • authenticated users: read+write permission
  • people in admin group : all permissions

install SimpleSAMLphp

1. Install SimpleSAMLphp in the cookbook/AuthUserSaml/ directory

 # some settings  (suit to your needs)
 export SIMPLESAMLPHP_VERSION='1.19.5'
 export WEBSERVER_ROOT_DIR='/var/www/html'
 export PMWIKI_DIR="${WEBSERVER_ROOT_DIR}" 

 # install simplesamlphp
 export SIMPLESAMLPHP_DIR="${PMWIKI_DIR}/cookbook/AuthUserSaml/simplesamlphp"
 mkdir -p ${SIMPLESAMLPHP_DIR}
 curl  -LO  "https://github.com/simplesamlphp/simplesamlphp/releases/download/v${SIMPLESAMLPHP_VERSION}/simplesamlphp-${SIMPLESAMLPHP_VERSION}.tar.gz" 
 tar  -xz --strip-components 1  -C ${SIMPLESAMLPHP_DIR}  -f simplesamlphp-${SIMPLESAMLPHP_VERSION}.tar.gz
 chmod -R +rX  ${SIMPLESAMLPHP_DIR}  # fix permissions so your web server can read the files  (suit to your needs)

2. make a softlink named simplesaml from the root of your webserver to the www directory in the ${SIMPLESAMLPHP_DIR} directory

 ln -s ${SIMPLESAMLPHP_DIR}/www ${WEBSERVER_ROOT_DIR}/simplesaml 

configure SimpleSAMLphp

1. change contact email, adminpassword and secretsalt in ${SIMPLESAMLPHP_DIR}/config/config.php

2. place the certificate from your identity provider in the file ${SIMPLESAMLPHP_DIR}/cert/idp.crt

3. set variables for configuring identity provider (suit to your needs):

 export IDP_HOST='your specific IDP host'
 export SIMPLESAMLPHP_IDP_ENTITY_ID="https://${IDP_HOST}/simplesaml/saml2/idp/metadata.php"
 export SIMPLESAMLPHP_IDP_SINGLE_SIGNON_SERVICE="https://${IDP_HOST}/simplesaml/saml2/idp/SSOService.php"
 export SIMPLESAMLPHP_IDP_SINGLE_LOGOUT_SERVICE="https://${IDP_HOST}/simplesaml/saml2/idp/SingleLogoutService.php"

Set in the variable IDP_HOST the DNS hostname value of your specific IDP host. The variable SIMPLESAMLPHP_IDP_ENTITY_ID is used for writing config/authsources.php and metadata/saml20-idp-remote.php, and the variables SIMPLESAMLPHP_IDP_SINGLE_SIGNON_SERVICE and SIMPLESAMLPHP_IDP_SINGLE_LOGOUT_SERVICE are used for writing metadata/saml20-idp-remote.php.

4. configure the remote idp within SP (Adding IdP to the SP). We do this by creating the file ${SIMPLESAMLPHP_DIR}/metadata/saml20-idp-remote.php with the following content:

 cat > ${SIMPLESAMLPHP_DIR}/metadata/saml20-idp-remote.php <<EOF
<?php
 \$metadata['${SIMPLESAMLPHP_IDP_ENTITY_ID}'] = [
      'SingleSignOnService'  =>'${SIMPLESAMLPHP_IDP_SINGLE_SIGNON_SERVICE}',
      'SingleLogoutService'  => '${SIMPLESAMLPHP_IDP_SINGLE_LOGOUT_SERVICE}',
      'certificate'          => 'idp.crt',
 ]; 
EOF

We are using bash heredoc syntax to write content to file where the SIMPLESAMLPHP variables are expanded during the write. Note that the '$' sign for the php metadata variable is escaped to prevent expanding!

NOTE: From the SimpleSAMLphp documentation we read
  SimpleSAMLphp only signs authentication responses by default.

The IDP always signs the authentication responses sent to the SP. The SP always does validate the authentication responses of the IDP. If it would not do so anyone could send an authentication response causing that person to login without being authenticated. That's why we always have to set an idp.crt in ${SIMPLESAMLPHP_DIR}/metadata/saml20-idp-remote.php on the SP, because the SP needs the certificate from the IDP to validate the IPD's signature on the authentication responses.

5. configuring auth source in SP. We do this by creating the file ${SIMPLESAMLPHP_DIR}/config/authsources.php with the following content:

 cat > ${SIMPLESAMLPHP_DIR}/config/authsources.php <<EOF
<?php
\$config = [

     // This is a authentication source which handles admin authentication.
     'admin' => [
         // The default is to use core:AdminPassword, but it can be replaced with
         // any authentication source.
         'core:AdminPassword',
     ],

     /* This is the name of this authentication source, and will be used to access it later. */
     'default-sp' => [
         'saml:SP',
         # 'privatekey' => 'sp.pem',       // Enabling a certificate for your Service Provider (optional,see 6)
         # 'certificate' => 'sp.crt',      //  => allows you to receive encrypted assertions from IdP (not enforced).

         # 'assertion.encryption' => TRUE, // '''Enforce''' encryption on assertions received (optional, see 7)
         # 'redirect.sign' => TRUE,        // Sign the authentication request, logout requests and logout responses sent to the IdP. (optional, see 8)
         # 'redirect.validate' => TRUE,    // Validate the signatures on logout requests and logout responses received from IdP (optional, see 9)

         /*
          * The entity ID of the IdP this should SP should contact.
          * Can be NULL/unset, in which case the user will be shown a list of available IdPs.
          */
         'idp' => '${SIMPLESAMLPHP_IDP_ENTITY_ID}',
     ],
];
EOF

We are using bash heredoc syntax to write content to file where the SIMPLESAMLPHP variables are expanded during the write. Note that the '$' sign for the php config variable is escaped to prevent expanding!

We are done, this setup should work. However there are some security options you also add to make it more secure in the step 6, 7, 8, and 9 below.

OPTIONAL security options which can be configured in SimpleSAMLphp

6. OPTIONAL: Enabling a certificate for your Service Provider

Some Identity Providers/Federations may require that your Service Providers holds a certificate. If you enable a certificate for your Service Provider, it may be able to sign requests and responses sent to the Identity Provider(step 8), as well as receiving encrypted responses from the IdP. (enforced in step 7).

Create a self-signed certificate in the cert/ directory:

 cd  ${SIMPLESAMLPHP_DIR}/cert
 openssl req -newkey rsa:3072 -new -x509 -days 3652 -nodes -out sp.crt -keyout sp.pem

Then edit your ${SIMPLESAMLPHP_DIR}/authsources.php entry, and uncomment the references to the SP's certificate and private key:

  ...
 'default-sp' => [
        'saml:SP',
        'privatekey' => 'sp.pem',       // Enabling a certificate for your Service Provider 
        'certificate' => 'sp.crt',      // allows you to receive encrypted assertions from IdP (not enforced).   
        ...

7. OPTIONAL: Enforce encryption on assertions received

Edit your ${SIMPLESAMLPHP_DIR}/authsources.php entry, and add the assertion.encryption option:

  ...
 'default-sp' => [
        'saml:SP',
        'privatekey' => 'sp.pem',    // REQUIRED for receiving encrypted messages from IdP
        'certificate' => 'sp.crt',   // The IdP must have 'sp.crt' to encrypt.    

        ...
        'assertion.encryption' => TRUE, 
        ...

From From the SimpleSAMLphp documentation we read

  assertion.encryption
    Whether assertions received by this SP must be encrypted. The default value is FALSE . 
    If this option is set to TRUE , unencrypted assertions will be rejected.

Thus if assertion.encryption is set to TRUE incoming assertions MUST be encrypted and unencrypted assertions will be rejected. This requires that the assertion.encryption option is enabled on the IdP which causes assertions send from the IdP to this SP to be encrypted.

If 'assertion.encryption' is set to FALSE it will handle unencrypted assertions, but it will also handle encrypted assertions ONLY IF certificate of the IDP (idp.crt) is configured in ${SIMPLESAMLPHP_DIR}/config/authsources.php which is by default REQUIRED!!! (see explanation in step 4 why)

You must supply the sp.crt to the IdP, otherwise it cannot send encrypted messages to the SP which the SP can decrypt which its own private key sp.pem.

8. OPTIONAL: Sign the authentication request, logout requests and logout responses sent to the IdP.

Edit your ${SIMPLESAMLPHP_DIR}/authsources.php entry, and add the redirect.sign option:

  ...
 'default-sp' => [
        'saml:SP',
        'privatekey' => 'sp.pem',  // use to sign by SP
        'certificate' => 'sp.crt', // used to validate signature by IdP       

        ...
        'redirect.sign' => TRUE, 
        ...

From From the SimpleSAMLphp documentation we read

  redirect.sign
    Whether authentication requests, logout requests and logout responses sent from this SP should be signed. The default is FALSE .

By enabling the 'redirect.sign' option on the SP, the SP does sign authentication requests, logout requests and logout responses sent from this SP to the IdP. Signatures are only validated by the IdP if on the IdP site the 'redirect.sign' option is enabled otherwise the signatures will just be ignored by the IdP.

You must supply the sp.crt to the IdP, otherwise it cannot validate the signature from the SP.

9. OPTIONAL: Validate the signatures on logout requests and logout responses received from IdP

Edit your ${SIMPLESAMLPHP_DIR}/authsources.php entry, and add the redirect.sign and redirect.validate options:

  ...
 'default-sp' => [
        'saml:SP',
         #'privatekey' => 'sp.pem',   // sp keys are not needed for validating signatures from IdP, 
         #'certificate' => 'sp.crt',  // we only need the 'idp.crt' certificate for validating     

         ...
        'redirect.validate' => TRUE, 
         ...

From From the SimpleSAMLphp documentation we read

  redirect.validate
    Whether logout requests and logout responses received by this SP should be validated. The default is FALSE .

By enabling the 'redirect.sign' option on the SP, the SP does validate signatures on logout requests and logout responses received by this SP from the IdP. This requires that the signature is added on IdP site by enabling the 'redirect.sign' option on the IdP, because otherwise you get error on SP: Validation of received messages enabled, but no signature found on message.

Release notes

If the recipe has multiple releases, then release notes can be placed here. Note that it's often easier for people to work with "release dates" instead of "version numbers".

User notes? : If you use, used or reviewed this recipe, you can add your name. These statistics appear in the Cookbook listings and will help newcomers browsing through the wiki.