Single Sign-on to Azure AD using SimpleSAMLphp
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.
Import federation data from Azure application to SimpleSAMLphp
- 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.
Configure SimpleSAMLphp as a service provider
- 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.
PHP12'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.
Custom PHP application code
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.
require_once (dirname(__FILE__) . '/../simplesamlphp/lib/_autoload.php');
$as = new SimpleSAML_Auth_Simple('default-sp');
$attributes = $as->getAttributes();
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<h3>Welcome <strong>Authenticated User</strong>!</h3>
// Get a logout URL
$url = $as->getLogoutURL();
echo '<a href="' . htmlspecialchars($url) . '">Logout</a>';
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.
A little something extra?
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.
- 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.
Until next time – probably tomorrow.
First of all, thank you for sharing your know-How on SSO to Azure with SAML+PHP.
I’ve tried following your directions, but unfortunately I’ve had no success.
I keep geting the error ‘State information lost’ and Iget the folowing debug information:
2 /var/www/html/simplesamlphp/lib/SimpleSAML/Auth/State.php:225 (SimpleSAML_Auth_State::loadState)
1 /var/www/html/simplesamlphp/modules/saml/www/sp/saml2-acs.php:63 (require)
0 /var/www/html/simplesamlphp/www/module.php:134 (N/A)
I’m really looking forward to surpass this obstacle as I’m sure I will find it again and again in future projects
Hi Sebastio, it reads to me as a potential issue with session state. Assuming you’ve configured on Windows, it’s worth testing if the normal PHP session state is working as you expect on your installation. It’s difficult to suggest how you might achieve this yourself but there’s plenty of guidance on the PHP.net site.
Also, PHP as installed on Windows will place entries in your Application event log when it fails to load and it could lead you to the answer.
Lastly, don’t ignore the PHP logs as they can also help identify the issue.
As mentioned though, I would be looking very closely at PHP session storage.
Hope this helps.
We’ve changed the ‘ Session.use_cookies’ on our php.ini from Off to On (0 to 1) and restarted our apache server.
Afterwards it worked properly 🙂
Thanks a lot
We’ve changed the ‘ Session.use_cookies’ on our php.ini from Off to On (0 to 1) and restarted our apache server.
Afterwards it worked properly 🙂
Yet, only users with ‘Sourced From’ = ‘Microsoft Azure Active Directory’ can login trough this App and the majority of users in my WAAD have ‘Sourced From’ = ‘Local Active Directory’
Does this ring a bell to you?
Hi Sebastião, I’m glad we’ve got you past that point. 🙂
How have you configured your Azure AD Connect synchronisation server? Are you using ADFS?
If you’re not using ADFS (federation), you would need to make sure that “password sync” is enabled on your Azure AD Connect synchronisation server (and that a sync has performed successfully!) so that the users’ on-premises passwords are synchronised in to the Azure AD directory. The best thing to do is simply test if they can log on using the https://portal.office.com/ site. It doesn’t matter if they have a licence or not but it proves your Azure AD users can log-on.
Those criteria were all matched.
After speaking with the AD’s SysAdmin we’ve discovered the «new» issue was related to an unproper assignment of an E1 licence.
After the licencing of the E1 account was done, the SignOn was successfull.
Once again thank you so much for your know-how, sharing spirit and availability.
Thanks for your post.
I’m looking for the same things but with a php web app hosting directly on Azure.
Did you know how to do that ?
Thanks in advance,
First of all, thank you very much for sharing your know-How on SSO to Azure with SAML+PHP.
I’m looking for doing the same thing but with an azure website, did you know how to install simplesaml on an Azure website ?
Forget my last question, I’ve found the answer 🙂
Just extract simplesamlphp at the same level than wwwroot and create a virtual application in the webapp configuration like you do in IIS.
Good to know Vincent, that is what I would have guessed so thank you for confirming!
Thanks for the article. I follow all the steps, but the problem now Login “AADSTS75005: The request is not a valid Saml2 protocol message.” The link https://login.microsoftonline.com/c1542126-0b6c-4c45-980c-b7c98b2afee3/saml2.
I’d better check the error are.
Very clear and neat explaination. Thank You.
I was fighting with htis SSO very badly.
Your article saved me.
Thank You once again!!
Hello Lewis, very nice document. i have used this for configuration.
do you have similar document for configuring SAML using IBM TIVOLI? i could not find any post on this.
You’re a lifesaver. I’m having to support a legacy application with this set up and no documentation to support what was done to get it up and running. It made for a pretty decent needle in a haystack to try to figure out what needed fixing, but your guide filled in a lot of blanks for me.
Very clear and concise, especially for someone who has never worked with Azure or SSO before. Couldn’t ask for more.
Many thanks for posting this its great for everyone:-).
Thanks Lewis for the guide. Very helpful.
I’ve written a follow up that tends to a few different needs:
1. Hosting on Apache / Ubuntu instead of IIS
2. Setting up metadata refresh (so it doesn’t suddenly stop working a few months later).
3. Configuring a free certificate with letsencrypt.org
Hopefully this helps someone!
Great Guideline, it was really helpfull.
Now what can I do if I want my website authorize multiple SP ?
For now I have a Login page where I ask users to enter mail address then I calculate the good SP to redirect to.
But users need to enter their mail address again.
I need a solution to save users mail address then put-it in the login form of azure.
I didn’t find any solution maybe you can help.
I am trying to configure Azure AD as an IDP to SimpleSAMLPHP (SP), I have created an APP in Azure and configured all the URLs
Sign-On URL to Assertion Consumer Service URL
APP ID to MetaData EntityID
Reply URL to Assertion Consumer Service URL
When I click on the APP I created it redirects to my AssertionService URL after authenticating with https://login.microsoftonline.com/common/oauth2/authorize but on the return I do not see SAMLRESPONSE without it SIMPLESAMLPHP will not proceed further and it stops there.
Could you please let me know what I could be missing here.
I get error from Azure login that https://my.sso.domain.com/simplesamlphp/module.php/saml/sp/saml2-acs.php/default-sp does not match the reply addresses configured for the application.
Your tutorial did not mention saml2-acs.php ? Should I add it, so should it be there with the metadata.php?
And if so, what is rationale here?
First, thank you very much for your manual.
I was able to adapt nerly every thing to my Office 365 Tenant and the new Azure Interface. Had to do some stuff a little bit different.
I did not found the Link in the Azure Interface, Google helped me to find out: To get the Metadata XML i had to open the following adress:
As “entityID” in the “authsources.php” i hat to enter my ApplicationID (for example: 1a234b56-7ab8-901a-bb12-345a6789b10c), not the Entered adress (for example: https://sso.mydomain.com)
Now I am able to do the authentification in Office 365, but then (back in SimpleSAMLphp) i get the following Error-Message:
0 D:\WWW\domain-ch\sso\saml\www\module.php:180 (N/A)
Caused by: SimpleSAML_Error_Exception: This SP [1a234b56-7ab8-901a-bb12-345a6789b10c] is not a valid audience for the assertion. Candidates were: [spn:1a234b56-7ab8-901a-bb12-345a6789b10c]
3 D:\WWW\domain-ch\sso\saml\modules\saml\lib\Message.php:584 (sspmod_saml_Message::processAssertion)
2 D:\WWW\domain-ch\sso\saml\modules\saml\lib\Message.php:524 (sspmod_saml_Message::processResponse)
1 D:\WWW\domain-ch\sso\saml\modules\saml\www\sp\saml2-acs.php:120 (require)
0 D:\WWW\domain-ch\sso\saml\www\module.php:137 (N/A)
@Christian: I ran into the same issue with the invalid audience. Changing the entityID to “spn:” instead of only “” seems to have solved the problem.
My apologies. “less than” and “greater than” characters were stripped from my previous comment. It was supposed to be “spn:” followed by the App ID GUID instead of only the App ID GUID.
Just wanted to thank you for this, and your previous post on Azure AD 🙂
It’s been a terrific help, and your instructions were very clear, and easy to follow!
Good luck on your other posts! 🙂
Thanks for this tried-and-true recipe, Lewis. It works!
I wonder if you have any advice on how to get additional AD attributes from the SAML response from Azure.
@Robert Fridén you might have saved my job!!! lol i saw the spn: thing and didnt think it would make a difference. Been struggling with this for weeks
Thanks for a great article, it was really helpful.
When I got to the point where the reply url was misconfigured I found that the error message did not include what it should be.
I had to use an online SAML decoder (google and you shall find) and paste in the GET parameter. That spat out the xml where the reply url was clearly visible. Note that this is not the “relay” parameter which is urlencoded in the url.
Has anyone been able to do multiple SPs with Azure? I believe I’m missing something. I have one server with SimpleSamlPHP but I want to have different pages to authenticate based off different SP or Azure groups. I’m getting an error on the second SP I have setup but the first one it working fine.
I figured out my issue. I thought the XML convert was identical but it was a little different.
Thanks for the document, I struggled a lot to get a simple and useful documentation and finally find yours!!!
I have followed the steps, but stuck somewhere. I have added parsed metadata to saml20-idp-remote.php and also configured SimpleSAML php as service provider. Unfortunately while doing test authentication I am getting Unhanded exception error as:
1 www/_include.php:17 (SimpleSAML_exception_handler)
0 [builtin] (N/A)
Caused by: SimpleSAML\Error\Exception: Could not find the metadata of an IdP with entity ID ‘https://ietdssodb2c.b2clogin.com/ietdssodb2c.onmicrosoft.com/B2C_1A_RPSignI…’
7 modules/saml/lib/Auth/Source/SP.php:315 (SimpleSAML\Module\saml\Auth\Source\SP::getIdPMetadata)
6 modules/saml/lib/Auth/Source/SP.php:720 (SimpleSAML\Module\saml\Auth\Source\SP::startSSO)
5 modules/saml/lib/Auth/Source/SP.php:826 (SimpleSAML\Module\saml\Auth\Source\SP::authenticate)
4 lib/SimpleSAML/Auth/Source.php:208 (SimpleSAML\Auth\Source::initLogin)
3 lib/SimpleSAML/Auth/Simple.php:167 (SimpleSAML\Auth\Simple::login)
2 modules/core/www/authenticate.php:38 (require)
1 lib/SimpleSAML/Module.php:254 (SimpleSAML\Module::process)
0 www/module.php:10 (N/A)
Could you please help me to figure this out!!!
I am trying to configure Azure AD using SimpleSAML for my PHP application. I have successfully installed SimpleSAML to my applicaiton. The next stage is to configure AD, and I stuck somewhere. The error response I am getting is :
The specified assertion consumer service URL https://SIMPLE_SAML_APP_URL/module.php/saml/sp/saml2-acs.php/default-sp is invalid.
The steps I followed so far are:
1. Imported federation data from Azure application to SimpleSAMLphp
2. Added metadata to SimpleSAML
3. Configured SimpleSAMLphp as a service provider
Did I missed anything, why I am getting error while doing test Authentication…!!!
Thanks in advance.
Hi, there is multiple references to your previous post but no link on it, so where is your previous post exactly ?
I think I did used to have a literal arrow to allow navigation back then so it’s less obvious now. Here it is:
I implemented my first SSO with Azure-AD following your precious guide, and I want to thank you a lot. Your guide il well done, and explains everything in a clear and effective way!
thank you again!