I have previously talked about configuring a Drupal site to authenticate against a remote SimpleSAMLphp install, but as Drupal is an excellent user management system I wanted to turn it around and use Drupal as the identity provider. This means that Drupal would allow users to log into other systems using their Drupal username and password by leveraging the power of SimpleSAMLphp.
This can be accomplished by wrapping the Drupal site and SimpleSAMLphp together along with a couple of modules to power the communication between the two systems.
The same terms apply as I described in the previous post, but to reiterate their meaning in this context I will go over them again.
SP - Service Provider - This is the system that users are trying to log into, which in this setup is some other site or service. Service providers will generally create a local user to track the user within the site and in this setup the user will be a Drupal user.
IdP - Identity Provider - The Drupal system holds information about the users and is therefore called an identity provider as it provides the identity of the user. This is used by the Service Provider (SP) to authenticate the user.
I'm going to assume that you have a Drupal site already installed via composer, preferably using the Drupal recommended composer file. This will be basis of the rest of the article.
To get this working we need to require SimpleSAMLphp in the same project as you Drupal site. The first step, therefore, is to require SimpleSAMLphp as a project dependency, which will install SimpleSAMLphp alongside Drupal.
composer require simplesamlphp/simplesamlphp
In order to allow SimpleSAMLphp to communicate with Drupal we need to install a SimpleSAMLphp module called drupalauth. This is required as another composer dependency.
composer require drupalauth/simplesamlphp-module-drupalauth
This should install the module in your SimpleSAMLphp module directory inside your vendor directory (i.e. in the directory vendor/simplesamlphp/simplesamlphp/modules/drupalauth).
The SimpleSAMlphp application needs to be served as a stand alone application. This means that Drupal will be the main application (served from the root directory) and SimpleSAMLphp will be served from a sub directory. I chose to serve it from the path /idp.
The www directory in the SimpleSAMLphp vendor directory needs to be exposed as the /idp path. I have tried a few methods of doing this, but I have found the best and most reliable approach is just to create symlink between the www directory and your chosen path in your web root.
Navigate to your Drupal web directory and run the following to create that symlink.
ln -s ../vendor/simplesamlphp/simplesamlphp/www idp
The last thing to do is follow through the rest of the instructions on configuring the application. I have detailed these instructions in a separate post that deals with installing SimpleSAMLphp as a composer project. This project structure should the same once you have completed setting things up.
The slight difference to those instructions is that you need to configure SimpleSAMLphp to understand that it lives in a separate directory. As this is different from the default path we need to alter the baseurlpath setting to point to the correct place
'baseurlpath' => '/idp',
Your project should have the following structure, with 'web' being used as the Drupal directory.
simplesamlphp/ - dev/ - - certs/ - - config/ - - metadata/ - prod/ - - certs/ - - config/ - - metadata/ vendor/ - simplesamlphp/ - - simplesamlphp/ - - - modules/ - - - - drupalauth/ web/ - autoload.php - core/ - .htaccess - idp -> ../vendor/simplesamlphp/simplesamlphp/www - index.php - modules/ - profiles/ - sites/ - themes/ - update.php composer.json composer.lock
Note that I have removed some of the items above to keep things brief.
Now that SimpleSAMLphp is installed we need to configure it to work with the drupalauth module. This follows on from the instructions in my previous article on getting SimpleSAMLphp installed using composer.
A requirement of the drupalauth module is a database connection, this doesn't need to be the same database as Drupal is installed in, but it requires changing some settings in the config.php file.
'store.type' => 'sql', 'store.sql.dsn' => 'mysql:host=localhost;dbname=drupal', 'store.sql.username' => 'drupal', 'store.sql.password' => 'drupal',
If you have the database details correct then you will see the tables SimpleSAMLphp_kvstore and SimpleSAMLphp_tableVersion created in your database. This is assuming that your 'store.sql.prefix' setting is set to the default of 'SimpleSAMLphp'.
You now need to enable the drupalauth module in SimpleSAMLphp. This is done by editing the config.php file and adding the drupalauth entry to the 'module.enable' option.
'module.enable' => [ 'core' => true, 'saml' => true, 'drupalauth' => true, ],
With that in place we can add our Drupal site authentication details to the authsources.php file. This needs to reference the Drupal web root, the login and logout links as well as any attributes you want to pass between Drupal and the service providers when the user authenticates. In the example below we are returning the Drupal user ID, name and email address in the authentication package. The site www.ssotest.local is just a locally created domain for this example.
'drupal-userpass' => [ 'drupalauth:External', // The filesystem path of the Drupal directory. 'drupalroot' => '/var/www/drupaltest/web', // Whether to turn on debug 'debug' => true, // Cookie name. Set this to use a cache-busting cookie pattern // (e.g. 'SESSdrupalauth4ssp') if hosted on Pantheon so that the cookie // is is not stripped away by Varnish. See https://pantheon.io/docs/cookies#cache-busting-cookies . 'cookie_name' => 'SESSdrupalauth4ssp', // the URL of the Drupal logout page 'drupal_logout_url' => 'https://www.ssotest.local/user/logout', // the URL of the Drupal login page 'drupal_login_url' => 'https://www.ssotest.local/user/login', // Which attributes should be retrieved from the Drupal site. 'attributes' => [ ['field_name' => 'uid', 'attribute_name' => 'uid'], ['field_name' => 'name', 'attribute_name' => 'cn'], ['field_name' => 'mail', 'attribute_name' => 'mail'], ], ],
We now need to inform SimpleSAMLphp of our intent to use it as an IdP. This is done by editing the metadata file saml20-idp-hosted.php and adding an array that details what the name, certificates and authentication system for the IdP. The certificates in this array are the same certificates created for SimpleSAMLphp in the previous article on setting up Drupal as an SP. The authentication name of 'drupal-userpass' must match the authentication source added in the previous step.
$metadata['ssotestdrupal'] = [ 'host' => '__DEFAULT__', 'privatekey' => 'simplesaml.pem', 'certificate' => 'simplesaml.crt', 'auth' => 'drupal-userpass', ];
With this configuration array in place, head over to the "Federation" tab in your SimpleSAMLphp setup, which is at the path /idp on your site. You should now see your IdP in the list. This is viewable even without being logged in as the administrator of the application. Click "Show metadata", you'll see a bunch of output. This consists of your metadata URL, the SAML 2.0 metadata XML, a PHP representation of the same and the public x509 certificate we created above that is used to encrypt/decrypt the data.
Copy the PHP output and paste it into saml20-ipd-remote.php in your metadata directory. It should contain something like the following output.
$metadata['ssotestdrupal'] = [ 'metadata-set' => 'saml20-idp-remote', 'entityid' => 'ssotestdrupal', 'SingleSignOnService' => [ [ 'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect', 'Location' => 'https://www.ssotest.local/idp/saml2/idp/SSOService.php', ], ], 'SingleLogoutService' => [ [ 'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect', 'Location' => 'https://www.ssotest.local/idp/saml2/idp/SingleLogoutService.php', ], ], 'certData' => '[REMOVED]', 'NameIDFormat' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient', 'contacts' => [ [ 'emailAddress' => '[email protected]', 'contactType' => 'technical', 'givenName' => 'Administrator', ], ], ];
I have removed the certificate here as it is of no use really.
That is SimpleSAMLphp configured, so let's move onto configuring Drupal.
Configure Drupal As An IdP
A requirement of getting this all working in Drupal is the use of the drupalauth4ssp module. This is installed via composer.
composer require drupal/drupalauth4ssp
Once the module is installed you can head over to the configuration page for the module at the path /admin/config/people/drupalauth4ssp. There isn't much to configure here, you just need to make sure that the Authsource field matches the authentication source you set up in the authsources.php file. By default this is drupal-userpass.
You can optionally add URLs to the list of allowed ReturnTo parameters. This is used by the authentication system to push users back to their originating sites (i.e. the SP they are trying to log into) and so can be an added security measure to prevent unwanted sites from using your site as an IdP.
That's pretty much it in terms of setting up Drupal as an IdP. The drupalauth4ssp Drupal module is pretty much plug and play.
Of course, this setup does absolutely nothing on its own, you need a system to be a service provider so that you can log into it. Let's do that.
Configuring A Drupal SP To Log Into The Drupal IdP
What we want to do is setup another Drupal site as an SP so that users from the Drupal IdP can login to the SP using credentials created in the IdP. Essentially, if users want to log into site 2 (i.e. the SP), they must authenticate against site 1 (i.e. the IdP).
The instructions here are very similar to the instructions in the previous article in setting up Drupal to be an SP so you should install and configure the module in a similar way. In this instance, however, we have a much better IdP than a standard SimpleSAMLphp install (ie, Drupal + SimpleSAMLphp) and so we just need to repoint the Drupal SP site to point at out IdP. This requires us to just alter the SAML Authentication modules settings to change the Identity Provider settings and the user info and syncing settings.
The settings for the identity provider in the SAML authentication module are pretty straight forward (even though they don't look like it). You need to copy the values from the IdP settings we created in the saml20-idp-remote.php file. The fields are labelled well so that it's possible to match up what item goes where.
The following is a screenshot of the settings from the array in saml20-ipd-remote.php added to the form.
Next is the user information and syncing section. Here, we just need to enter the user name and user email attributes to match the fields we set up in the authsources.php file. In this case the username is 'cn' and the user email address is 'mail'. The other options here are up to you to enable or disable. The settings in the screenshot below are pretty open and allow more control over user field matching than should be enabled in a production environment. That said, it's up to you how open you make the settings for your install.
Finally, we need to copy the configuration from the Drupal SP into the Drupal IdP. This is detailed in the previous article under the section "Adding Drupal Configuration To SimpleSAMLphp". You should go to the path /saml/metadata in the SP site and copy the XML from that page, convert it to a PHP array in SimpleSAMLphp. The key difference is that you need to add the PHP array to the saml20-sp-remote.php file in your IdP SimpleSAMLphp instance.
Now, when users want to log into the Drupal SP site they will log into the Drupal IdP site and be redirected back to the SP site and authenticated there too. If the user isn't known to the SP site then the attributes sent over by the IdP are used to create the user and fill in their details (assuming they also exist on the IdP site).
Following these instructions, there is nothing to stop us from setting up multiple SP instances of Drupal and allow them all to authenticate against the central Drupal IdP install.