External authentication with Claims and WS-Federation in MVC4 .NET4.5 Part 5: configuring multiple identity providers for federated log-in
March 21, 2013 3 Comments
Normally a web application is configured to use a single STS for authentication. Using the Identity and Access Tool also pushes you into that direction; there’s no option to set up 2 or more different federated STSs.
However, there may be cases where you would like to allow external users to access your application. Who are these external users? A typical example is the users of a business partner; those users will use a different STS to access their own web app. What if you wish to give those users access to your web app without them having to sign up with your app first? After all you don’t want to manage those accounts, right? They are not really your users, you don’t want to be responsible for their sensitive data in your database.
You could instead somehow configure your application to accept tokens from 2 STSs: your own and that of the partner company. You can designate the STS of the partner as a trusted identity provider. If the external user can come with a token from that other trusted STS then they will be allowed to view your application.
The recommended way to implement this is to follow a pattern called ‘Resource-STS’ or ‘Federation Gateway’.
The idea of this pattern is the following:
- Your application should only trust one single token service. Always.
- This “master” STS is called the Resource-STS
- The Resource-STS can be configured to broker trust with other token services
- The external users contact your STS and carry with them the token from their STS
- Your STS will understand the external token because the Issuer figures on its trusted issuers’ list
- Your STS will issue a new token that your application trusts and understands
This method simplifies the configuration of your web application because it still only needs to be concerned with your single trusted STS. The external relying parties will not need any reconfiguration either. The only application that will need to be adjusted is your STS because it must understand tokens that do not originate from your application.
The trust relationships are set up as follows:
- Your web app trusts your STS
- Your STS trusts the STS of the business partner
- The application of the business partner trusts the external STS
So indirectly your web app will trust the external users.
The logical steps to log on to your web application “from the outside” will look like this:
- An external user logs in to their own STS which lies within their domain
- The external STS will issue a security token to that external user
- The external token will be sent to your STS
- Your STS will validate the external token
- If necessary your STS will even transform the external claims into claims that your application needs
- The external user will be given a new token by your STS, a token which comes from your side of the authentication chain: it is signed by your STS
- In the last step the external user sends the transformed token to your we app
- From here onwards we have “business as usual”: the claim is inspected, transformed, saved in the auth session etc.
However, there seems to be something missing. The external user will need to navigate to your application first, right? They do not contact the STS login page first and somehow try to modify the URL, that would be impractical. It is your application that should redirect the user to your STS. The additional difficulty is the following: how does your application know where the visiting user is coming from? Which STS should it redirect the user to? The complexity increases if there are more than one external STSs. Even if we establish that the user is an “external” one, then which external STS is theirs?
The process of finding out who is trying to log in and where to redirect this user is called Home Realm Discovery. There’s of course no magic way to answer all those questions in the previous paragraph, we simply need to ask the visitor. Are you a partner? Which partner? Are you an “internal” user? There will be a special GUI within your application to ask these questions and redirect the user to the correct STS.
This GUI may actually not be necessary. There is another way to discover where the external user is coming from. If you have 5 partners then you will probably have links on their web sites that lead to your web application. You can build special landing pages for each of those partners. You can then see based on the opening URL where the user is coming from. Once you know that then you can add a special flag to the STS Url. The flag takes the form of ‘&whr=[id_of_external_identityprovider]’ where ‘hr’ means home realm. The URL may look like the following:
Demo
A pre-warning: this demo is far from complete as I don’t have access to a second STS.
Navigate to the Thinktecture Identity Server we installed before and log into the identity provider. Select the [administration] link and then choose the Identity Providers menu item:
Click “New” and you will be presented with the necessary fields to enter a trusted federation endpoint:
This is where you can add the details of an external STS. I don’t have any such STS unfortunately but the textboxes are pretty self-explanatory. Typical values might look like this:
The thumbprint is the certificate signature of the external STS which helps us decide whether the token is coming from a trusted source. The WS-Federation endpoint is the value of the login page of the external STS, like https://localhost/idsrv/issue/wsfed in the case of the demo project.
As we want to run the auth process through Home Realm Discovery we have to update the issuer from ‘wsfed’ to ‘hrd’:
<system.identityModel.services> <federationConfiguration> <cookieHandler requireSsl="false" /> <wsFederation passiveRedirectEnabled="true" issuer="https://andras1/idsrv/issue/hrd" realm="http://localhost:2533/" requireHttps="false" /> </federationConfiguration> </system.identityModel.services>
Other commercially available STSs will also have similar URLs for home realm discovery. As we don’t have any other STSs there’s no point in testing the application really. However, using the hrd link we would land on an interim page where the user can select among the available STSs and pick the one that’s relevant to them. They will then be redirected to the login page of their STS. After a successful login the user will see the protected page of your web application.
In case you would like to go directly to an external STS after identifying where the external user is coming from you have two choices:
Add the homeRealm attribute to the web.config:
<wsFederation passiveRedirectEnabled="true" issuer="https://andras1/idsrv/issue/hrd" realm="http://localhost:2533/" requireHttps="false" homeRealm="BusinessPartner" />
The homeRealm value will be the ‘Identifier’ field in the Identity Providers setup window we saw above. It adds the ‘&whr=BusinessPartner’ parameter to the STS query string. It tells our STS to go directly to the external STS called ‘BusinessPartner’ and do not show the interim page where the user can pick one of the available trusted STSs.
This is of course a very static way of specifying an external STS. Fortunately we can assign this value dynamically as well. You’ll need to override the following method in Global.asax:
public void WSFederationAuthenticationModule_RedirectingToIdentityProvider(object sender, RedirectingToIdentityProviderEventArgs e) { }
You can set the Home Realm parameter using the RedirectingToIdentityProviderEventArgs parameter as follows:
SignInRequestMessage signInRequestMessage = e.SignInRequestMessage; signInRequestMessage.HomeRealm = "BusinessPartner";
You obviously need to somehow decide beforehand where the user is coming from. If you use different landing pages for each partner, such as:
- partnerone.mycompany.com
- partnertwo.mycompany.com
…or
…then this should be a straighforward task.
This finishes the entire series of posts dedicated to Claims in .NET4.5. I hope it is enough to get you started with your own Claims-aware web or desktop projects. Happy programming!
The next post will be the starting point for an entirely different topic: Test Driven Development in .NET.
You can view the list of posts on Security and Cryptography here.
Interesting..
Very Well written tutorial. I had been thinking of learning claims based authentication for long time but never found anything ins such a simple way as you did. I followed all the tutorials from beginning to end without any issues until this last post. I do not see “Identity Providers” menu item in my Thinktecture Identity server. Have I missed some configuration?
Thanks again for the tutorials.
I have found the solution. I had to check “Enable Federation” checkbox under Protocols – WS-Federation