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.
Hello I'been reading your post, and is fantastic. But I have some problems.
I have configured everything using:
- linking drupal root with ln -s ../vendor/simplesamlphp/simplesamlphp/www idp
- 'baseurlpath' => '/idp',
- my local server for the idp is www.idp.local,
When I try to access www.idp.local/idp I get this error:
SimpleSAML\Error\CriticalConfigurationError: The configuration is invalid: The configuration (config/config.php) is invalid: Missing configuration file
But my conf.php file is there.
However, if in apache I do the following:
Alias /simplesaml /var/www/html/idp/vendor/simplesamlphp/simplesamlphp/www
Require all granted
And in the config.php I put:
'baseurlpath' => 'simplesaml',
And I execute in the browser localhost/simplesaml, everything comes out correctly.
Do you have any idea how to do it like you did? what am I doing wrong?
Thanks for commenting. I'm so pleased you took the time to read and feedback :)
With regards to your problem, it sounds like there is something about symlinks that your apache/SimpleSAMLphp configuration doesn't like? I'm not sure if you have removed the full path or not, but your error contains a relative reference to the config.php file. I found more success with an absolute path on my configuration setting.
Normally, when I see that error it is because I have forgotten this line, which sets the configuration directory as an absolute path.
SetEnv SIMPLESAMLPHP_CONFIG_DIR /var/www/sso/simplesamlphp/dev/config
Please let me know how you get on.
Hello Philip!, thanks for your reply.
I have tried to change everything to absolute paths. I have made the symbolic link from the root of my drupal:
- ln -s /var/www/html/idp/vendor/simplesamlphp/simplesamlphp/www idp
I have also set the environment variable SIMPLESAMLPHP_CONFIG_DIR. With the only difference that I am in Ubuntu and I have to use the export command because my system does not use csh.
- export SIMPLESAMLPHP_CONFIG_DIR=/var/www/html/idp/simplesamlphp/dev/config
But I still get the same error. I really have no idea what the problem is...
Strange isn't it?
I found getting these systems setup took me some time. In fact the posts you see on this site took me many, many hours of research and straight up just reading code to make sure I understand what configuration was needed and how to configure Drupal correctly. In other words, this was difficult and I hope that my articles have gone some way towards properly explaining this.
That said, one thing that stood out from your previous comment was that you talked about using export to set the configuration setting for SimpleSAMLphp. I should have been clearer in my explanation as the SIMPLESAMLPHP_CONFIG_DIR configuration directive is intended to be held within your Apache configuration, not exported on the command line. I can only guess, but maybe that is what the issue is here?
I have some news.
After many configurations and operating system changes (ubuntu to centos), I was able to configure almost everything correctly. I can successfully login from the service provider.
But I have a little error that is driving me crazy. Every time I try to logout from the service provider I get the following error:
Error message: Error encountered while processing SAML single-logout response; details have been logged.
Note: The system logout correctly both in the service provider and in the identity provider. However, once the logout is done, this message appears in the service provider.
I was able to see the log of the service provider and I find the following. The error is the following:
Error(s) encountered during processing of SLS response. Type(s): invalid_logout_response; reason given for last error: The Message of the Logout Response is not signed and the SP requires it in Drupal\samlauth\SamlService->sls()
Did it happen to you? Did I forget any settings?
Good news that you've been able to log into everything. I went through the same pain, believe me.
I have seen that error before. Although I wasn't able to solve it.
If you look right down the bottom of the SAML Authentication module settings page there are a number of options that turn on and off the requirement of signed responses. I was able to suppress that error message by turning off some of those options.
Sorry I can't be of more help here.