by Lewis · Sat 5th September, 2015
In my last mammoth post, I posted an update/re-write to an article originally written on the Azure website that used some libraries provided by Microsoft to enable custom PHP applications to sign-on to Azure AD using WS-Federation. In that post I described a method for installing and configuring SimpleSAMLphp to IIS that enables it to be used by any number of sites on the same server, all that’s required is to add a simple Virtual Directory to each site. If you want to configure SimpleSAMLphp on IIS, check that post out.
The intention with this post is to do away with Microsoft’s libraries altogether and use only SimpleSAMLphp in a more integrated way. The purpose is to avoid having to re-write a lot of functionality already provided by SimpleSAMLphp that’s likely to be missing from Microsoft’s libraries, and of course open up access to SimpleSAMLphp’s documented API.
I will assume you have configured SimpleSAMLphp already using the method documented in the last post. In order to proceed in this post, you also need to have configured an application within Azure Active Directory. Again, you can find instructions for that included in the previous post.
The largest difference with this post is, as I mentioned, better integration with SimpleSAMLphp – as such, there’s more configuration to complete within SimpleSAMLphp than there was in the previous post.
We’ll import federation data from our Azure application in to SimpleSAMLphp.
We’ll configure SimpleSAMLphp as a Service Provider.
We’ll create a little code to get us authenticating.
As mentioned, we need
SimpleSAMLphp set up on the server as per my previous post. In this
post, I’ve created a new website called sso.lewisroberts.com
and configured the Virtual Directory. It’s all documented in the
previous post so you can use that to get to this stage.
We need an application configured in Azure Active Directory
just as per my previous post. In this post, I’ve created a new
application I’ve called sso.lewisroberts.com.
There’s no special configuration required for the application.
Open the Windows Azure
Management portal and navigate to your application. Click View
Endpoints in the grey banner at the bottom.
In the App Endpoints
window. Copy the URL for the Federation Metadata Document.
Using your favourite browser,
navigate to the location and save the metadata document. How you do
this doesn’t really matter, as long as it’s just the XML you
save.
Open the federationmetadata.xml
file in a text editor, select the entire contents (Ctrl+A) and then
copy it to the clipboard.
Open a browser and navigate to
https://sso.lewisroberts.com/simplesaml
(Actually,
you’ll obviously navigate to your own PHP application’s website,
not mine.) Once there, click the Federation
tab.
On the Federation
tab, look for Tools and then click XML to
simpleSAMLphp metadata converter.
Paste the entire
federationmetadata.xml
file’s contents in to the field and click the Parse
button.
The page should return almost
immediately with some information similar to the following under the
Converted metadata section. Copy the contents of the
saml20-idp-remote field to your clipboard, or a
file, it’s your choice.
Navigate to your SimpleSAMLphp
installation folder and find the metadata
folder.
Now open the
saml20-idp-remote.php
file.
Did you notice? The converted metadata returned from
SimpleSAMLphp had the field set to saml20-idp-remote – the same
name as the file we’re editing.
Now copy the converted metadata contents in to the file.
I’ve highlighted where this was pasted in to my own version of the
file. Do note however that obviously the converted metadata extends
beyond the bottom of the visible screen I show here. It should be a
simple matter of pasting in the converted metadata. Save the file.
Navigate to your SimpleSAMLphp
installation folder and open the config
folder.
Open authsources.php
in your favourite text editor.
There are a number of
authentication sources preconfigured (but commented out) however the
one we’re interested in (or rather, its general format) is
default-sp.
I’ve shown this (actually, the interesting bits) in its default
state, below.
In order to achieve compatibility with Azure AD, we need to make some small changes to default-sp. We could just create another authsource called something else but it’s easier to show what it looks like initially and then edited if we change default-sp. The next few steps will show where we make edits.
Firstly, change the entityID
value to reflect the name or URL of your Azure application.
Next, enter the idp
value. Where did I get this from? The very first line of the
converted metadata actually gives you the IdP (Identity Provider) –
in this case, Azure AD.
discoURL
stays as null.
Next we must add some additional information that is required to communicate with Azure AD. Underneath discoURL, add the following two lines.
PHP
'NameIDFormat' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', 'simplesaml.nameidattribute' => 'eduPersonTargetedID',
1 2 |
'NameIDFormat' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', 'simplesaml.nameidattribute' => 'eduPersonTargetedID', |
We’re complete editing authsources.php so save and close the file.
Now that configuration of SimpleSAMLphp is complete, we can use SimpleSAMLphp to test authentication works as expected, without actually writing any code but we’ll get to that in a second.
Navigate to
https://sso.lewisroberts.com/simplesaml
(remember, your own app, not mine, this is an example.) and then
click the Authentication tab.
Once there, click Test
configured authentication sources
We should see only two options,
admin and default-sp.
These were the only two authentication sources defined in
authsources.php.
Click default-sp.
You will likely receive an error
that looks as follows. This means that the Reply URL
sent by SimpleSAMLphp to Azure AD as part of the authentication
attempt isn’t one that is accepted by the application. So it’s
not very happy. To fix this, we need to quickly visit the Azure
Management portal and add this Reply URL to our
application.
First, copy the URL from the
error. In this case, the URL is:
https://sso.lewisroberts.com/simplesaml/module.php/saml/sp/metadata.php/default-sp
In the Azure Management portal,
find the application, scroll to Single Sign-On and
add it to the list of Reply URLs. Save the
configuration change but leave the management portal open in case
you must make any more edits.
Close the other browser showing
the error, open another and repeat steps 1 to 3.
After clicking
on default-sp now that we have added the Reply
URL in to the Windows Azure portal, we should be shown the
Sign in page.
Notice the URL we’re sent
to. This is the actually the SAML-P Sign On
Endpoint for the Azure application.
Log in with a user account
that’s in your Azure Active Directory.
We should now be able to sign in
without error and get redirected back to SimpleSAMLphp and shown a
list of the claims that were sent along with the authentication.
To test logging out, click Logout.
So, all this configuration was just to get us to the point where we can create our own application code that allows us to authenticate with Azure AD. The reality is that our PHP “application” can be a single page.
Generally, the application will require an index.php file – the code for which is below. I’ll give a very brief breakdown of the first few lines, the rest is obvious.
PHP
<?php require_once (dirname(__FILE__) . '/../simplesamlphp/lib/_autoload.php'); $as = new SimpleSAML_Auth_Simple('default-sp'); $as->requireAuth(); $attributes = $as->getAttributes(); ?> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Index Page</title> </head> <body> <h2>Index Page</h2> <h3>Welcome <strong>Authenticated User</strong>!</h3> <h4>Claim list:</h4> <?php echo '<pre>'; print_r($attributes); echo '</pre>'; // Get a logout URL $url = $as->getLogoutURL(); echo '<a href="' . htmlspecialchars($url) . '">Logout</a>'; ?> </body> </html>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<?php require_once (dirname(__FILE__) . '/../simplesamlphp/lib/_autoload.php'); $as = new SimpleSAML_Auth_Simple('default-sp'); $as->requireAuth();
$attributes = $as->getAttributes();
?> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Index Page</title> </head> <body> <h2>Index Page</h2> <h3>Welcome <strong>Authenticated User</strong>!</h3> <h4>Claim list:</h4> <?php echo '<pre>'; print_r($attributes); echo '</pre>';
// Get a logout URL $url = $as->getLogoutURL(); echo '<a href="' . htmlspecialchars($url) . '">Logout</a>';
?> </body> </html> |
This file will require authentication so, on line 2, it calls SimpleSAMLphp’s autoloader from the main installation of SimpleSAMLphp.
On line 3, we create a new object from the SimpleSAML_Auth_Simple class but notice here we specify the authsource default-sp – that’s correct, we’re associating this application with the default-sp auth source we created.
On line 4, we use the object and tell it we require authentication. If the user is authenticated, the script will proceed to the next line, if not however, they will begin the authentication process and be redirected to Azure AD to sign in. Once signed in, they will be redirected back to this page.
On line 6, we pull the attributes from the SAML token and store them in the $attributes array. These are then used later (line 21) to show the user their claims.
On line 25 we get a logout URL from the $as object and send that back to the interface so the user can click a link to log out.
The user navigates to the web
application. Given they’re not logged in, they’re automatically
redirected to the Azure AD sign in page.
The user lands at the Azure AD
sign in page.
The user logs in with a valid
Azure AD account.
Notice as well that the page also says
sso.lewisroberts.com
– a bit of free branding.
After successfully
authenticating, the user is redirected back to the site where they
can see their claims and a logout link.
When clicking the Logout link, the user is
logged out of their account.
One thing I’ve wondered while doing all this was whether we could get additional claims through rather than just those few that are shown in the screenshots. Something like groups would be great. As it turns out, that feature was introduced at the back end of 2014. I’ll run through it very quickly in the context of our application but for more details (and how to handle users who might be members of more than 150 groups (in SAML)) you really should visit the blog of Dushyant Gill.
In the Windows Azure management
portal, navigate to your application and click Manage
Manifest then Download Manifest.
Download the manifest file and
save it to disk. Leave the portal open, you’ll need it shortly.
Open the file in any decent text
editor. I’ve chosen to do it in Visual Studio code. Locate the
groupMembershipClaims
value.
Change this to one of SecurityGroup or All.
SecurityGroup – The groups claim will contain the identifiers of all security groups that the user is a member of.
All – The groups claim will contain the identifiers of all security groups and distribution lists that the user is a member of.
I’ve chosen to just enable
SecurityGroup
option in the screenshot below. Save the file.
Back on the portal site, Manage
Manifest and then click Upload Manifest.
Browse for the saved file and
then click the tick icon to upload it.
Dushyant’s post goes on to mention that you should grant additional permissions in the application. This is only really required if you are going to be dealing with “overage” scenarios which means users who are members of more than 150 groups, since these can’t be included in the SAML token. Read his blog post for more info. For our demo app purposes, our user is a member of only one group.
So, I’ve created a group in my
Azure AD and added the user to it. Note the Object ID,
this is the value that will be shown in the claim.
Members
Now if we re-try our authentication (and without making any
code changes to our index.php
file) we see that the groups
claim is carried through in to the application. Of course this means
you can use it for security trimming etc. within your custom
app.
Note:
I noticed that there was another group id in the claim – I’m
assuming this is related to this user’s status as a Global
Administrator since if I authenticate as a user who is purely a
member of the LocalAzureAD group, the only groups claim attribute is
the Object ID of the LocalAzureAD group.
So, another not insignificant post ends and hopefully you’ve learned a little something along the way. Seeing that it’s possible to pull group claims through in to the application opens a lot of possibilities for developers of bespoke PHP applications and I’m sure it’ll be very handy to know in the future.
I think I’ve got one more post in me about SimpleSAMLphp and that is probably going to be integrating SimpleSAMLphp with ADFS 2012R2. That post will hopefully be shorter since we’ll be repeating a lot of the activities we’ve done above. For example, instead of importing the federation metadata from our Azure Application, we’ll import from the ADFS server and set that up in SimpleSAMLphp. We’ll configure our PHP “application” as a Relying Party Trust and get all the necessary information automatically from simpleSAMLphp and finally configure the ADFS server as the IdP for the application.