Claims-based authentication in .NET4.5 MVC4 with C#: External authentication with WS-Federation Part 2 Testing a real STS
March 11, 2013 67 Comments
In this post we’ll go into more details of WS-Federation in .NET4.5 using the MVC4 internet project we produced in the previous post. More specifically we’ll look at the changes that the Identity and Access Tool made to our project when we introduced the local STS.
We’ll introduce the following topics:
- External login specification
- Setting up trust
- Certificate validation
- Token validation
- Federation metadata
In the demo we’ll continue with the MVC4 application we started in the earlier posts. We’ll also test a real STS instead of the built-in local one.
External login
In a traditional .NET forms-based web app you would specify the login page as follows:
<authentication mode="Forms"> <forms loginUrl="~/Account/Login" timeout="2880" /> </authentication>
This login page is then an internal page of the web application.
A web app that is fully claims-based will be void of any internal Login page as we saw in the previous post. Instead we’ll specify an external Login like this:
<system.identityModel.services> <federationConfiguration> <wsFederation passiveRedirectEnabled="true" issuer="http://localhost:12808/wsFederationSTS/Issue" realm="http://localhost:2532/" requireHttps="false" /> </federationConfiguration> </system.identityModel.services>
This was added by the Identity and Access Tool to web.config. Issuer is the URL of the login service. As you see it is an external URL as opposed to the relative one of the forms-auth solution. The realm is the identifier of your application, usually its URL. It is used by the STS to know who the token is meant for so that it can build application specific security tokens.
Setting up trust
Another important section added by the Identity and Access Tool sets up the trust between the web app and the local STS:
<issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry"> <authority name="LocalSTS"> <keys> <add thumbprint="9B74CB2F320F7AAFC156E1252270B1DC01EF40D0" /> </keys> <validIssuers> <add name="LocalSTS" /> </validIssuers> </authority> </issuerNameRegistry>
This is located within the system.identityModel element. The issuerNameRegistry specifies the details of the trust relationship between the web app and the STS. You can specify a type, which will be a class that allows to set up the trust through configuration. There’s a built-in implementation called ValidatingIssuerNameRegistry which works just fine. You can provide your own solution by deriving from that class if you want to describe the trust relationship in another way, e.g. through a database.
The above configuration is telling us the following: we have one valid, i.e. trusted issuer whose X509 signature -i.e. thumbprint – is 9B74CB2F320F7AAFC156E1252270B1DC01EF40D0 and bears the name ‘LocalSTS’. Our application will accept claims from this issuer. .NET will automatically look at the thumbprint of the issuer in the token and check the value(s) against the one in web.config. If the token was signed by a different X509 certificate then the token will be rejected. If the values match then the ‘Issuer’ property of the token will be assigned the symbolic name of ‘LocalSTS’. The ‘Isser’ property of each claim will receive this value as well.
Certificate validation
There’s an optional step after the token has been accepted by the web app, i.e. after the token has passed the first level of scrutiny which is checking the thumbprint.
Normally that initial check is enough for us to say that the token is real. The keys element contains very strong statements about which certificates are the trusted ones. In addition, however, we can perform an additional check on the certificate itself as follows:
<certificateValidation certificateValidationMode="ChainTrust" revocationMode="Online" />
This will check if your certificate store includes a certificate with the same thumbprint and that it has not been revoked in the meantime. ChainTrust means that .NET will check if the specified issuer, i.e. LocalSTS is available in your trusted CA folder in your certificate store. revocationMode Online means that we want to go the CRL – Certificate Revocation List – endpoint of the CA to see if the certificate has been revoked.
This extra validation step is often not needed as stated above. It adds extra complexity to your application: the same X509 certificate that was used to sign the token must be installed on the application server and the web server must have access to the CRL endpoint. If you are satisfied with the list of thumbprints and do not want to carry out any additional checks then you can set this type of validation to none as follows:
<certificateValidation certificateValidationMode="None" />
This is inserted by the Identity and Access Tool by default within the identityConfiguration node.
Token validation
Token validation is different from certificate validation. When validating a token we want to make sure that it is really meant for our application. This is expressed by the following element added by the Identity and Access Tool to the web.config file:
<audienceUris> <add value="http://localhost:2532/" /> </audienceUris>
Imagine that there are two applications that trust the same STS and that a token meant for myniceapplication is redirected to myotherniceapplication. As they both trust the same certificate then myotherniceapplication will also accept the token meant for myniceapplication. This can lead to subtle security holes that can be difficult to discover.
The STS will embed the name of the realm in the token. Recall that the realm is also specified as the unique ID in the query string sent to the STS login page. The same value will be put back inside the token. The above audienceUri setting will check if the URI value, i.e. http://localhost:2532 is the same as the one embedded in the token. This will make sure that the token was really meant for our own web application.
Federation metadata
Federation metadata is an XML document that describes the STS: WS-Federation endpoint, which certificate is used to sign the token etc. Most STSs support this document format. The Identity and Access Tool specifies this document in the web.config as follows:
<add key="ida:FederationMetadataLocation" value="http://localhost:13866/wsFederationSTS/FederationMetadata/2007-06/FederationMetadata.xml" />
We will look at this document in more detail in the demo.
Demo
Now we’ll see how to set up and use a real STS.
For the demo we’ll use an STS built by Thinktecture. The Thinktecture IdentityServer was created using .NET4.5, it is open source and can be used as a starting point of a custom-made STS in your own project. Navigate to the following link:
Thinktecture IdentityServer 2.1
Download the zip file containing the source code from the ‘Download’ link. Make sure you select version 2.1. That is the most recent version available as of May 16 2013. The STS will need to be installed on your machine. There’s an easy step-by-step video guide available for version 2.0 under the ‘Documentation’ link. The video guide is available here. There are very little visual changes from v2.0 to 2.1 so you should be able to set up the system based on that guide. I will not recount what’s said there. So, follow the steps and come back here when you’re done. Make sure you follow each step carefully and that you’ll have 2 users ready: one admin and one ‘normal’ user who corresponds to the user we created before on the Register page of our MVC4 web app. I created a user with the same user name as the one I created on the Register page as my custom claims auth – CustomAuthorisationManager.cs – and claims transformation – CustomClaimsTransformer.cs – logic is based on that. If this is the case in your implementation then make sure that the username of the STS user matches the one you’ve been working with so far.
When you’re done your local Thinktecture STS page should look as follows when logging in as an admin:
Select the ‘home’ link and click on ‘View WS-Federation Metadata’:
You will be presented with the Federation Metadata which describes the STS. This is the document we referred to under the ‘Federation metadata’ section above. Some interesting bits and pieces:
You will find the URL of the STS sign-in page under the PassiveRequestorEndpoint element:
Locate the KeyInfo element where you will see the certificate which will sign the outgoing token:
The Identity and Access Tool will use this metadata document to set up our configuration. Take a note of the URL of this XML page, we’ll need it soon. It should look similar to the following:
https://your_local_server_name/idsrv/FederationMetadata/2007-06/FederationMetadata.xml
Before we go on let’s give a meaningful name to the Thinktecture issuer:
By default the Site ID value is some URL ending with “changethis”. Give it some meaningful name instead, I chose ThinkTectureSTS, but it’s your choice. The Site Id will be reflected in the federation metadata:
Open our MVC4 internet application in Visual Studio 2012. Right click the web project name and select ‘Identity and Access…’ from the context menu. In the previous blog post we tested the first option in the Identity and Access window, i.e. the ‘Use the Local Development STS to test your application’ one. This time select the second option, i.e. ‘Use a business identity provider’.
You’ll need to specify the path to the STS metadata document. Paste in the link to FederationMetadata.xml as noted above:
You can also specify the realm, i.e. the ID of your web application in the same window. This can be the localhost URL as given in the wizard or some symbolic name, like DonaldDuck. Normally it is the URL of the web page, so we’ll leave it as it is for the time being.
Press OK and see what happens. The web.config file has been modified to accommodate the new STS. Things to note:
The Federation Metadata XML file has been inserted in the appsettings section:
<add key="ida:FederationMetadataLocation" value="https://localhost/IdentityServer/FederationMetadata/2007-06/FederationMetadata.xml" />
We inserted the system.identityModel and system.identityModel.services config sections in previous posts. However, the wizard would have inserted them for us if they had not been there already.
Our trusted issuers list has been modified to include the new local certificate instead of the default LocalSTS:
<issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry"> <authority name="ThinkTectureSTS"> <keys> <add thumbprint="79EE2CF0CA42818DDBECA1A191480DFFEDBCF4AB" /> </keys> <validIssuers> <add name="ThinkTectureSTS" /> </validIssuers> </authority> </issuerNameRegistry>
The name of the Thinktecture STS is the default one which is provided during the STS installation process. You’ll notice that the name of the issuer is the same as the Site ID we chose when we set up the STS. It is important that the two values are the same, otherwise you will get a strange WIF exception: WIF10201: No valid key mapping found for securityToken: ‘System.IdentityModel.Tokens.X509SecurityToken’ and issuer: ‘http://identityserver.v2.thinktecture.com/trust/changethis’.
The issuer URI has also been modified accordingly:
<system.identityModel.services> <federationConfiguration> <cookieHandler requireSsl="false" /> <wsFederation passiveRedirectEnabled="true" issuer="https://localhost/IdentityServer/issue/wsfed" realm="http://localhost:2532/" requireHttps="false" /> </federationConfiguration> </system.identityModel.services>
You’ll notice that the attributes ‘requireSsl’ and ‘requireHttps’ in the above XML are set to false. This is acceptable for testing purposes but you should make sure to set have SSL ready for the production environment. ‘passiveRedirectEnabled=true’ means that upon a 401 response the user is redirected to the login page of the STS, i.e. at https://localhost/IdentityServer/issue/wsfed in this example. The realm http://localhost:2532 will be attached to the query string as the ID of our web site.
The audience URI is the URI of our test web site:
<audienceUris> <add value="http://localhost:2532/" /> </audienceUris>
This value is typically the same as the realm under the federationConfiguration element.
As we saw in the previous post the wizard will make sure that all visiting users must be authenticated:
<authorization> <deny users="?" /> </authorization>
The effect is that as soon as a user tries to view your site they will be redirected to the STS. Let’s remove this element to allow anonymous users as well. Run the application now. You may be presented with an exception saying that the element ‘certificateValidation’ occurs more than once. We added this element in the previous post and the wizard was not smart enough to detect it in web.config. If you get this exception then remove one of the elements and re-run the application.
If you remember then we made our About page protected. Click that link and… …you should be redirected to the Thinktecture login page. The URL will conform to the format we discussed before and will look similar to the following:
Log in with the user you created during the Thinktecture STS setup and you should actually receive an error message:
The reason is that the STS does not give out tokens to arbitrary applications. The application first needs to be registered with the STS. We’ll do it now:
Navigate to the STS home page and sign in as an admin. If you followed the video presentation on the Thinktecture STS installation then you’ll have an admin user ready.
Click the ‘administration’ link and select Relying Parties & Resources:
Press the ‘New’ button:
Make sure you specify the same realm as in the web.config:
Press Create.
Re-run our MVC4 demo application and click the About link… …and you’ll most likely receive one more exception: the return URL requires SSL. Didn’t we specify ‘requireSsl’ as false in the web.config file? It turns out that SSL must be disabled on the STS as well.
Go to the STS home page and log in as an admin. Select ‘administration’, protocols and WS-Federation and uncheck the Require SSL option:
Save the changes and run the MVC4 application again. As usual, you can set breakpoints within CustomClaimsTransformer.Authenticate and CustomAuthorisationManager.CheckAccess to see if our custom made claims managers still work.
Select About and you should be redirected to the STS login page. Enter the username and password of the ‘normal’ user you created during the Thinktecture Identity Server installation process and press ‘Sign In’. You should be redirected to the About page meaning that the logi nwas successful.
If you have set the breakpoints in place then you’ll see that code execution stops within our custom claims managers showing that they still work as expected. Feel free to step through the code with F11 and inspect how the Claims collection is built up.
If everything went fine then you’ll be presented with the About page. Great, we’ve just implemented a real STS solution! In addition, all our custom Claims auth managers work exactly the same as before.
In the next post we’ll discuss some more advanced topics.
You can view the list of posts on Security and Cryptography here.
Could you please update this section to handle the code that the Identity and Access dialog places in the Web.config file. The code you show:
is no longer written to the web.config file, instead the Identity and Access dialog writes the following into the web.config file and it will not work with ThinkTecture:
This new code ends up with “Server Error in ‘/’ Application.”
WIF10201: No valid key mapping found for securityToken: ‘System.IdentityModel.Tokens.X509SecurityToken’ and issurer …
Thanks for your update. Your xml code has been erased by wordpress but I will go through this process as soon as possible.
I’ve updated the post and provided a quick solution to the problem so that users can log in using Identity Server.
//Andras
ow can I put a user name in ‘appliesTo’ not a URI. Do you have code example for implementation of a SecurityTokenServicer for WIF SAML2 framework4.5? Thank You, Singed LindaDet.
Hi Andras. Thanks for the post, it was really useful. Did you find any chance to through the issue Les mentioned?
Hi Irmak,
No, not yet. I’ll try to do it before my baby is due in the coming days, otherwise I’ll need to wait a couple of weeks.
//Andras
No Prob. Congrats:)
Hi Irmak, I’ve gone through the setup of Identity Server and I’ve provided a quick solution in the post – we simply need to revert back to the issuerNameRegistry type that the Identity and Access Tool inserted before the latest update was published.
//Andras
One more update: the error that Les Ventimiglia mentioned was due to a mismatch between the Site ID in the STS and the Issuer name in web.config. I’ve updated the post to correct this mistake.
Hi,
I am pretty new in the world of Thinktecture! Till now I have configured one MVC application which uses Thinktecture ACS deployed on azure.
Now next step that I am planning for is to get the tokens.
I also want to authenticate iPad and Android application which are dependent on same identity server as my webApp!
Kindly suggest a method to authenticate and get the tokens for all the three apps…
Can you please suggest best approach for this? Please post links towards implementation.
Thanks in advance!
Hello,
I don’t develop for the iPad or Android so if you want to get tips specific to those technologies then you’ll need to search elsewhere.
You should get the token from the identity server. It’s up to the consuming application to handle the tokens. I’m quite sure that the languages behind the Android and iPad applications support the consumption of claims.
//Andras
Hello Andras,
I have been reading most of your posts regarding Claims, and would just like to express my gratitude over the job you put into writing them.
It has helped me alot to gain understanding regarding Claims.
Köszönöm szépen!
Hej Anders, tack för din kommentar och varsågod!
//Andras
Hi Andras,
First of all, thank you so much for all this series blog posts. They’re helping me a lot.
After complete the real STS test, I noted that you continued using the method “DressUpPrincipal” in the CustomClaimsTransformer.cs to simulate database lookup.
My question is, with a STS server configured we continue go to database in the application to get the user claims ?
Another question is:
How to store claims in a database ? and where we should retrieve it ?
Hi Israel,
“with a STS server configured we continue go to database in the application to get the user claims ?”
It depends on where you store the claims. If all the necessary claims that your application needs can be retrieved from the STS then there’s no need for an extra DressUpPrincipal method. However, this is usually not the case. Say you have a product suite: WebAppA, WebAppB, WebAppC with their specific purposes. You can store all the claims for all three apps in one central STS. When the user is redirected to the login page from WebAppA then the STS will provide the claims for even WebAppB and WebAppC which WebAppA does not care about. This is conceptually wrong and the authentication ticket will be unnecessarily bloated. Imagine that you work as a .NET programmer and you receive 3 computers to work with: one Windows, one Linux and one iOS. What are you going to do with Linux and iOS? They may be fun to test and play with but they will not help you do your job.
The central STS should only store those claims that are common across all applications using it. In reality this will be a very short list:
…and probably that’s it. All the application-specific claims should be stored in the storage mechanism of the application. If the applications are somehow interconnected, then you can probably provide some basic information about the rights of the user to use the other apps to enable certain features. E.g. if certain WebAppA users are allowed to use WebAppC as well then you can put a link on WebAppA like “Click here for your personal info from WebAppC” where you can base the show/hide logic of the link on some basic true/false claim type coming from the STS. But as soon as the app receives the claims from the STS it should populate the claims list with the application-specific claims from its own data store.
“How to store claims in a database ? and where we should retrieve it ?”
You have a lot of freedom here. If you work with a relational database then you can have a User table with columns for the claim types. It can be as simple as true/false columns called e.g. “View”, “Edit”, “Admin”. You can then have a claim key called “http://mycompany.com/permission-group” and the value will be “view”, “edit” or “admin” depending on the bit values in those columns.
However, claims can be dispersed across the database if you wish. Some of the claims I use in the project I’m working on are coming from 4-5 different tables. It is up to the data access logic to read all the claims.
I’m not sure what you mean by “where we should retrieve it?” exactly, but it is the data access layer with the DB code – ADO.NET, EntityFramework, Linq to SQL etc. – which ultimately reads that type of data from the data store.
//Andras
Hi Andras, great blog, I’m a fan. I know I’m kind of late to the party here but when I was reading this comment I could not help disagreeing with some of the things you are claiming here. Consider the following. In a big enterprise applications where your claims are scattered across multiple locations, AD Oracle db, MSSql db, some 3rd party apps and so on, you would have to access all of these ( or the ones where the claims that you need ) in all of your webapps ( the dress up claim function in this case ). Now if someone decides to merge the Oracle DB and the MSSQL db, you have broken all your webapps that are using claims from these DBs. And note, this is not a trivial example, my experience with big enterprise apps things usually get ugly and scattered over time. However I completely agree with you that a WebAppA should only get the claims that it needs ( not the WebAppB and WebAppC claims ) but it should not care were these claims come from, it only knows about the STS and relies on it for getting the claims it needs. Now in the thinktecture STS we setup a “Relying Parties & Resources” instance so we should be able to set what claims to return on that instance so we don’t get all the claims available from the STS back to the application. But then again I am kind of a noob to these STS so I might be way off, what do you think?
Hello Huxley, thanks for your inputs.
I think you have a lot more experience with large integration projects than I do. Do you have a blog somewhere with a post that is relevant to this topic? It could be good to add a link to it from here.
//Andras
Hi Andras, no, i have no blog about the subject and I think I don’t have the sufficient knowledge to write such a blog. I have only used existing STS in a large scale company and through some in house written libraries that go on top of a in house written STS. I have not configured them my self ( hence here I am reading your great blog! ). The only point that i was trying to come across was that you should be careful was tying all of your webapps to number of data sources in order to get your claims. Ideally in my opinion it would be best that you only have dependency on your STS. That way if you change the location where claims are kept you would only have to reconfigure your STS and all your webapps would work afterwards. I think the ideal way to implement this is to ask the STS for list of claims and the STS sends them over. That way if your webapp goes stail, no biggy, its always asking for the same claims and your STS knows how to get them. If you are developing a new webapp, you would have to configure the STS so it can provide these new claims. But as I said, i’m kind of a noob in these STS, so what do you think? See any flaws in this approach? ( you are the pro here 🙂 )
This may be a dumb question but when the user gets redirected to the STS login page, he enter his username and password (BTW, can you setup Google and / or Microsoft authentication with this open source identity server) and then the STS issues a token with the user’s claims.
What I’m missing is, where do you setup claims for specific users? If user random users registers on my website I have to store some claims about him on my data store AND the STS? How do you communicate with the STS saying things like “hey, this user has just registered with username XXX and password ZZZ”? Or does the STS and my application have to ‘share’ the user store so they have access the the same information?
Also, with MVC 5 coming out, it would be nice if you could talk about how the ASP.NET One Identity feature relates with everything you talk about in your blog series about claims. Does some things have become obsolete? (I haven’t read past this post so maybe you did talk about it)
Thank you very much for your posts they helped me understand claims a lot better!
Salut Francois,
“BTW, can you setup Google and / or Microsoft authentication with this open source identity server”
–> you mean like signing in with your Google or Microsoft Live ID? Well, it’s an open source project so you can certainly add logic to accept Google/Facebook etc. identification types. However, I think the idea with this particular STS is that that you have complete control over the user database as well. You are free to extend it and store what you want about your users at the STS side. There are OAuth templates in the standard MVC4 startup project for Facebook, Microsoft, Twitter and Google, so there’s nothing stopping you from adding that to the Thinktecture project.
“where do you setup claims for specific users?”
–> that’s entirely up to you where and how you register your users and their claims but they will likely end up in a good old relational database. Another commenter in this thread had a similar question, check out my answer, it may help you.
“If random users registers on my website I have to store some claims about him on my data store AND the STS?”
–> It’s enough to store a single identifier about the user that cannot change and is common to the STS and the application database, such as a GUID, to minimise the need for synchronisation. This GUID can be sent as a claim to the consuming application so that it can find the user based on that and retrieve the application-specific claims from its own user store. It’s again up to you as a developer to register the user and their claims. There’s no need to duplicate any data across the STS and application databases other than this GUID so that you know who you are looking for.
“How do you communicate with the STS saying things like ‘hey, this user has just registered with username XXX and password ZZZ’? Or does the STS and my application have to ‘share’ the user store so they have access the the same information?”
–> You can store global user data in the STS data store, such as username, password, the GUID that links the user to the user stores of the applications that accept the tokens from the STS. You might store a couple of other things at the STS side, such as created_utc, but not much else. You can take care of user creation either at the STS or the application side but the two are not constrained to share any data store. They can communicate through some minimalistic web service. Be sure to make the the STS and your application as loosely coupled as possible where a shared database does not sound like a good idea to me.
“Also, with MVC 5 coming out, it would be nice if you could talk about how the ASP.NET One Identity feature relates with everything you talk about in your blog series about claims. Does some things have become obsolete? (I haven’t read past this post so maybe you did talk about it)”
I haven’t got that far yet and quite frankly I don’t know. I only heard that this new Identity feature can be used with OAuth, Claims, the good old MembershipProvider etc. in any project type: mvc, web forms, wpf, you name it, and it should be nothing short of “revolutionary”. Claims can be stored in a database and entity framework will help you retrieve them more easily I guess, but I’m really not sure. I’m unfortunately not a Microsoft insider to be able to give people any hints in advance.
//Andras
Dear Andras,
Read here that you going to be a father soon, congratulate on that!!
From all the bottom of my heart, I thank you for putting up these series of articles on claims, custom STS etc.. Really it is not an easy thing for a newcomer to figure out all these things. You have put in so much efforts and have made sure that followers (like me) shouldn’t go wrong while setting up things (unlike some other posts where after whole day article reading, you will come across many errors). So again, thank you so much.
Sincerely, patiently following every byte of your article 🙂 Please keep the good work and research going!!
Cheers!!
Ashwin
Dear Ashwin,
thank you for your kind comments! I’m glad you’ve found the blog posts helpful.
//Andras
Hi Andras,
you are welcome.
I have a doubt or question: my situation is:
– I want to build a custom STS. so i am referring to ThinkTecture as it is the best available option in market as of today. (that’s what i understand from internet search)
– From high level my scenario is: user will click on websites (say site1, site2….) to SIGN-IN button for single sign ON.
– on sign in button click, request will be redirected to ACS login page.
– ACS login page will have social IDPs PLUS my own IDP (which will be a seperate web application).
– For later case, ACS will redirect me to a claims aware web application which will display a login page with username/password textbox and login/submit button. There i am planning to send these username/password to another CUSTOM STS class library sort of application to get a token based on valid authentication or not? STS app will check this against asp.net membership provider.
Now, the interesting and difficult portion begins for me: Till now i am successful in setting up claims aware app, identity server (as explained in their videos) etc etc. But i am having lot of difficulty in understanding
> how to start in ThinkTecture source code (modification)?
> where to start? Which project is actually doing the token related work?
> Whether it is possible or not? Or am i totally misunderstood?
The ThinkTecture.AuthorizationServer source code has a web application and other class libraries but I am stuck and don’t understand the modifications needed to get a token back to my application.
They have few videos however there videos display more of graphical setup process etc. I am sure in many real life scenarios, they would not like to use there login page, server setup configuration style, client configuration style etc.. instead they would like to use ThinkTecture as a custom STS which can do a token providing job. That’s it!!!
If you have any ideas on these matters, could you please help? I would really be grateful.
Thanking you in anticipation.
Regards
Ashwin
Hi Andras,
I want to add SQL as Identity Provider in Windows Azure Access Control. This IdP can authenticate users based on the credentials may be stored in SQL server or may be use the login username and password for sql as authentication.
Are there any code samples or references for the same? How exactly do i need to proceed on that?
Simer
Hi Simer,
I’m not sure I understand what you mean exactly. Would like to have Azure Access Control as your STS or as the user data store for your STS?
Please clarify.
//Andras
Hi,
I am getting error as below after using our company provided STS authentication. This STS is not giving user name. SO not sure how to fix this issue. Appreciate your help on this.
Server Error in ‘/’ Application.
——————————————————————————–
Value cannot be null.
Parameter name: username
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ArgumentNullException: Value cannot be null.
Parameter name: username
Source Error:
Line 86: //}
Line 87:
Line 88: foreach (Claim claim in currentPrincipal.Claims)
Line 89: {
Hello again,
It’s difficult to see from here what’s happening within your STS. Do you have access to the code? Can you run it in debug mode to see what’s happening?
You should check and see if the STS finds the credentials of the user who is trying to log on. The username may not be populated correctly because the STS cannot find the user in the data store.
//Andras
Great job! Helped me out a LOT!
Hi Andras,
I have a question which is think is relevant to this topic, and i wonder if you could help me.
There is an issue that i’ve come across recently which i really cannot resolve. I have a web application that uses Federated claims-based authentication using the Identity Server as the STS. I have a custom implementation of the ClaimsAuthenitcationManager where i go all the custom claims principal transformation. I’ve been testing my app on IISExpress and everything used to work fine; The authenticate methods was being invoked by FAM; However, once i deployed the application on a virtual machine using the IIS, that method is not being fired anymore. I honestly, don’t know what I’ve done wrong. I wonder if you know anything about that.
Cheers,
Pavlos
Hi Pavlos,
“Virtual machine”, do you mean Azure or some other service?
//Andras
No it’s a VM installed locally on our servers
Do you have any logging in place? Can you describe what’s happening in the code? Does the overridden CheckAccess method in CustomAuthorisationManager fire at all? Have you maybe missed some uncaught exception before?
Well it’s really strange, because it works fine when i deploy on my machine. I’m using the remote the debugger; so there is no exception being thrown. And the CheckAccess method in CustomAuthorisationManager is not called either. However, i see the FedAuth Cookies being set.
Have the ClaimsAuthenticationManager and ClaimsAuthorizationManager modules been registered in the web.config file correctly on the server? Please double-check that web.config has not been modified by some other template like web.release.config. The custom check access not being invoked sounds like a symptom of faulty module registration.
I thought that the problem was due to the migration from IISExpress to IIS, but that doesn’t seem to be the case. I deployed everything locally on my machine, and it works fine. I will try to re-deploy it just to make sure i didn’t do anything wrong.
Cheers
Hi Andras, first of all I wish to congratulate you on your blog. It’s so difficult to find any articles as well and clear explained as yours, additionally illustrated by step by step guide through the code.
I’m new to claims authentication, and all of this STS, RP, IdSrv, OAuth and others. Your posts resolved many of my doubts, but not all of them. I was trying to modify your example and added api controller instead of regular one in the relying party. When I call a method in the controller directly everything works fine, I am being redirected IdSrv where I login and gain access to the content. Now, is it possible to consume data exposed in this controller, and secured with [ClaimsAuthorize(“Show”, “Code”)] from another, external mvc application?
When I create get request in fiddler to the method in the api controller I get a redirect (302) response to identity server but OK (200) response just after that
Hi Bartek,
I’ve never tried to translate the solution into Web API, so I cannot give you a definite answer unfortunately. As far as I know the ClaimsAuthorize attribute has a Web API equivalent in a different namespace. Check the attributes available in the NuGet package where the MVC ClaimsAuthorize attribute is located, there should be a ClaimsAuthorize attribute in the ThinkTecture.IdentityModel.Authorization.WebApi namespace as well.
Also, in the MVC solution we created an authentication session. It’s normal to have sessions in an MVC app where you can log on and off but with Web API it’s different as it a restful web service. You send your request, receive some answer and then you’re forgotten. It’s hard to see how an auth session can be established with a web api application. You’ll need to send the auth token with every request in some form, normally in the header. You’ll get an auth token from the id server and you’ll send that token to the web api every time you need some protected data.
The next topic on this blog will actually discuss Web API 2 in 3 installments. The 3rd part will show an example of how to authenticate with a web api controller using tokens. The difference is that the web api example is simpler in that it won’t use an external auth provider. The web api will be responsible for handing out the tokens. However, it may be enough to get you started.
//Andras
Hi Andras
Thanks for your reply. Would like to ask you couple more precise questions if you don’t mind:
1) You are right, Thinktecture.IdentityModel.Authorization.WebApi namespace is used to authorize access to a Web API method. Whenever I call this method and am not logged into IdSrv I will be redirected to the IdSrv login page. This happens when I call the method from the web browser. Problem is, I would like to call this method from MVC controller in another application (first because it’s required for the business logic, second to avoid CORS that I would need to handle in JavaScript). Is it possible? Is there any way I could handle HTML of the IdSrv login page (http response – redirect) in the controller do display it correctly to the user?
2) How do I add token to the response? Can it be done through the Thinktecture IdSrv interface?
3) If the token would be added to the response header, would I still be able to use similar ws-federation and CustomClaimsTransformer class to dress up the user in additional claims held locally? Would the incoming principal ClaimsPrincipal object of the authorize method be replaced by the token object?
Hope those questions make any sense,
Bartosz
Hi Bartozs,
Let’s see if I got this right. You have a system with 3 components:
A customer lands on the MVC app and tries to access a protected resource. The request goes to the Web API app which sees that there’s no auth header yet and redirects the client to the auth server login page. The auth server responds with the auth token + claims that in turn can be is also used by the Web API.
Are these statements correct?
//Andras
Could not reply to your latest post for some reason.
YES!!! What you described is exactly what I’m trying to achieve! I would only add that username is the only claim I would like to keep on the IdSrv. The rest of claims should be sourced from the Web API database
Are you able to give me any advice on how to modify your MVC solution to achieve that?
Thank in advance
Bartosz
OK, I see. So the MVC app is really only a collection of views and all the logic, including the detailed user database is only available for the Web API app, right?
I don’t think there’s a straightforward solution to transform the MVC model in this blog to automatically fit a Web API app. As there are no sessions in a RESTful web service it’s not possible to set up and auth session in the web API app.
Taking these elements into consideration I can see 2 different approaches:
Approach #1: let the MVC app establish the auth session with the following flow:
Approach #2: request user token from Web API with the following flow:
This second approach is almost readily available in Web API 2, but you can achieve the same with some extra coding. The auth token should have an expiry date and should be signed to detect tampering. You’ll soon see on this blog how to get an auth token from Web API.
//Andras
That’s a great explanation! I somehow feel that approach #2 is more ‘appropriate’ and can hardly wait for your posts related to Web API 2. Meanwhile, can you please correct if I understand it correctly? According to what you say the STS would have nothing in common with the Web API itself. It would be a resource with its own database of users and user login as the only claim. This resource could be then shared between different MVC apps requiring the same set of users. It would be up to those apps to contact the appropriate API’s which would hold detailed claims characteristic for each system that particular MVC app would represent. Security between MVC apps and their Web APIs would be based on tokens generated on behalf of the user sourced from the STS. Therefore, WebAPI could stay stateless?
“STS would have nothing in common with the Web API itself. It would be a resource with its own database of users and user login as the only claim.”
That’s right. If you prefer to put all your logic in a separate web service and keep the MVC as a collection of views only then I don’t see the point of associating the Web API app with the STS. The sign in/up/out process can be handled between the MVC app and the STS.
“It would be a resource with its own database of users and user login as the only claim.”
Yes, an STS is always an independent piece of software that many applications can use for sign up/in/off purposes – those applications that have been configured for it of course. It’s your decision what types of claims you put there but normally you store those claims at the STS which are common to all consuming parties. Generally there aren’t too many: username, some user GUID, created date and possibly some more. You’ll need to assess how to distribute the claims of a user: general claims at the STS, application-specific claims at the application user store.
“This resource could be then shared between different MVC apps requiring the same set of users.”
Yes, this comes back to the point that normally an STS holds a minimal set of generic claims that all consuming parties need so that they can identify the user and fill up the STS claims with application-specific ones.
” It would be up to those apps to contact the appropriate API’s which would hold detailed claims characteristic for each system that particular MVC app would represent.”
Yes, if you hold all logic with the Web API then the MVC app must contact it for services, including services about users and customers.
“Security between MVC apps and their Web APIs would be based on tokens generated on behalf of the user sourced from the STS.”
The STS sends the initial set of claims back to the MVC app and the MVC app establishes the auth session. If you go with approach #2 then the MVC app requests an auth token from the Web API and uses that token upon all subsequent requests. The Web API can decide for each request if the user has access to the protected resource.
“Therefore, WebAPI could stay stateless?”
A Web API app is stateless regardless of what we have discussed so far. You cannot log onto a RESTful web service and expect it to remember you in the next request. That’s possible with stateful web apps where you can log in, click around and log off.
You can still however store the current ClaimsIdentity within each request. Say that you intercept all incoming calls to the Web API using a DelegatingHandler class. You can extract the incoming claims in that handler and store it like we did in the blog:
…then further down the stacktrace of the same request you can get hold of the claims identity where you need it:
However, you won’t be able to put this into a session, the “principal” object is only valid for a single request.
//Andras
Hi. As you suggested I’ve been looking into Web API 2 template, Identity, OWIN, Katana, default /token endpoint, etc. As I’ve seen however, the default security setting for Web API 2 require password for managing user, which is obvious. However, when I override Authenticate method in CustomClaimsTransformer I do not have access to password, which is right since authentication is handled by STS. Therefore, what would you suggest to do at this point? I was considering creating a simple algorithm which would autogenerate internal passwords based on the user login. This way API would have additional security mechanism, otherwise any request with a bearer token and any claims would be allowed to access secured methods? Does it make any sense?
Hello, yes, you’ll see in tomorrow’s post that the built-in /Token endpoint only works for users that have been registered with the web api, i.e. those whose login + pw data are stored in the data store of the web api. However, you don’t HAVE to use that endpoint. Your custom scenario is asking for for a custom solution. There’s nothing stopping you from setting up your own endpoint with your own OWIN and Katana elements where you inspect the customised auth token sent from the front end.
Even if you had access to the pw from the STS then you’d need to store it in the web api data store as well, meaning that you’d need to register the users in two places. This clearly beats the purpose of SSO. So if you want to make the API public then you’d have to take this into consideration. Your users should be able to call the Web API with login + pw. Alternatively you can offer a separate service within your web page: create unique user tokens for your users that will give them access to the API. You can register those access tokens in both the Web API DB and the STS and send it along with every request to the web API from your front end. That way unauthenticated users cannot just send any bearer token to the API – they must send along a valid token that they have acquired through your web site.
Hi Andras .. This is a wonderful article and it helped me a lot to come up with the POC to enable single sign on for multiple organization..It worked perfectly Thank you so much. Please help me in the follwoing questions
1. I am going to host this as a service and dont want to add IssuerNameRegistry in web.config every time whenever i am adding new organization. I Need to pull the details from DB and set it dynamically (token, url etc). I tried to do that based on the return URL . But this fails because FederationConfiguration can be only updated in Application_Start Event. I cant do that becuase i cant access my HTTPContext to know the return url in my App_Start. So i kept a separate Config file and had all my authorities configured for all Organizations in it. But our client raising a question on security and the performance. Is it advisable to keep the sensitive data in XML for all the organizations and also we are concerned about performance. if the return token go and read all the keys to validate against it’s token, will the system be Slow
Please advise me with some sample code to achieve this..
2. I tried to implement ValidatingIssuerNameRegistry but unable to success since it is talking about updating the tenent id based on the Metadata.xml. All i have is the following info for all the organizations
Hi Jeevitha,
“I am going to host this as a service”. Can you please elaborate? Host what as a service? Can you describe the flow how you’re planning to register new organisations?
“All i have is the following info for all the organizations”. The sentence is unfinished, were you planning to write more info? It may have been cut off by WordPress.
//Andras
Thanks for your reply . Yes Andras.. possibly it would have cut off. Basically i want to develop an centralized application where different organization users can log-in and perform operations in my site later i will generate report out of it and give it to each organization. I am maintaining my own SQL DB where i will save all the organization issuer , certificate details etc….I am able to dynamically send the signinRequest based on the Organization id [i will get the details from my DB for that org and process it]. However while coming back from their ADFS server with the token i need following details to be added in my web.config to validate the token. I dont want to expose these details in my web.config for 2 reasons.
– Security [i need to have all the organizations details in config which may result some fraud access]
-Performance [if i have 100 organization who is going to use my app, is it advisible to configure all the issuerauthority in my config. wont it hit the performance]
Again my sample code got cutoff . Please append this code with my new reply above
Thanks for your reply .
oops.. its not accepting tags..
Again my sample code got cutoff . removed all the tags
Thanks for your reply . Yes Andras.. possibly it would have cut off. Basically i want to develop an centralized application where different organization users can log-in and perform operations in my site later i will generate report out of it and give it to each organization. I am maintaining my own SQL DB where i will save all the organization issuer , certificate details etc….I am able to dynamically send the signinRequest based on the Organization id [i will get the details from my DB for that org and process it]. However while coming back from their ADFS server with the token i need following details to be added in my web.config to validate the token. I dont want to expose these details in my web.config for 2 reasons.
– Security [i need to have all the organizations details in config which may result some fraud access]
-Performance [if i have 100 organization who is going to use my app, is it advisible to configure all the issuerauthority in my config. wont it hit the performance]
issuerNameRegistry type=”System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry”
authority name=”name”
keys
<add thumbprint="{Org 1 thumbprint}"
<add thumbprint="{Org 2 thumbprint}"
<add thumbprint="{Org 3 thumbprint}"
/keys
validIssuers
add name="http://test.login.edu/adfs/service/trust"
add name="Org 3 url"
add name="Org 4 url"
add name="Org 5 url"
validIssuers
authority
issuerNameRegistry
i hope my question is clear now please help me to get a solution
It’s Easter holidays in Europe, so I have no time to look into this issue. It sounds quite involved so I would need to do some proper research myself before I give you any advise. If you need an urgent answer then you’re better off asking on StackOverflow or on the ThinkTecture STS project page.
//Andras
I think i got a solution please let me know me if this works ?
I have configured all organization federation details in DB as a separate row [trustedissuer, security thumbprint, metadataxml, claimxml etc]
in my webonfig referred a class where i have added the IssuerRegitry as a Base class
issuerNameRegistry type=”MVC_Test.AccessControlServiceIssuerNameRegistry, MVC_Test”>
issuerNameRegistry>
In my class, i have overridden GetissuerName maethod, after getting token and issuername i m connecting to the DB to validate whether that particular org detail is available or not…
public override string GetIssuerName(SecurityToken securityToken, string requestedIssuerName)
{
var issuerToken = securityToken as X509SecurityToken;
DataAccess da = new DataAccess();
Organization org = da.IsValidToken(issuerToken.Certificate.Thumbprint, requestedIssuerName);
if (org != null)
{
Will this solution works ?
Hi Jeevitha,
It sounds promising. Does your application pick up the custom registry type correctly as defined in web.config?
//Andras
Hi Andras, did you get a chance to look into this solution… please let me know your thoughts
Yes.. it works perfectly. Now i have come up with 2 questions. Please guide me
1. I have another application which uses MVC Form authentication (using simple Membership provider). Can i use this ADFS SSO along with my existing Form authentication. Basically, i would like to switch the authentication type based on my URL [I will pass the orgid in my url].
I hope we cannot use that since i have removed ‘Form Authentication’ from my Web.config file. please let me know if there is a simple workaround to switch between both dynamically
2. I Have created sample MVC app for this SSO [multiple issuers]. I want to make this as a separate Class library or a service and plugin to the existing app. Can we do that. Will it work if i move all Federation settings to the App.config from the Web.config ?
Thanks
Jeevitha
1. As far as I know it’s not possible to mix authentication types within the same MVC application. Once you declare in the web.config that you want to with Forms auth, then you can’t have forms auth AND something else, e.g. Windows auth based on some interception.
2. Not sure I follow. You have an MVC application that you’d like to package as a dll and use in other projects? Please clarify.
//Andras
Thanks for your replay Andras
1. I will not use windows authentication. I am going to handle ADFS return token from IDP. Since Membership also working in claim based, i hope we can customize the code to have both authentication types. Currently, i have added both form and federation related settings in my web config. I have set Authentication mode as ‘Forms’. If the Orgid in the url is of ADFS type, i am dynamically passing the signin message from my .cs file. otherwise i am opening my regular Simplemembership form page. It si working for me without any issue now. But not sure about the issues we may face once after deploying the application
2. I dont want to package my MVC app. I want to create a class library with all the federation settings defined in the app.config. I would like to pass my signin message and return token validation everything in my class libraty instead of MVC app.. Basically i dont want to have any federation settings in my MVC webconfig. I will only refer my class library dll to my app and remining will be taken care by MVC application
1. I have no direct experience with what you’re working on, but you seem to be going in the right direction then. Why are you worried about the deployment? Which part of the architecture is that you’re worried about?
2. OK, then the dll will need access to some appSettings values, right? is the library going to access the appSettings directly with ConfigurationManager.AppSettings[“blah”] or are you planning to supply the values as parameter arguments into the library?
1.I have deployed in our dev server and able to access both SimpleMembership and ADFS for different Organization.
2.Basically i would like to configure FederatedAuthentication and SessionManagement and placeholder for issues in App.config of my class library and will supply the values from my MVC application… because my MVC app going to have basic Form Authentication. But in this way it doesn’t work on the return token validation. It expects all federated related configuration in my web.config because Mywebapp url is the realm and it checks for the issuer token details in my webconfig instead of my class library app.config. So I moved the following settings to my web.config and it works for both Form and ADFS without any issue
issuerNameRegistry>
add name=”WSFederationAuthenticationModule” type=”System.IdentityModel.Services.WSFederationAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089″ preCondition=”managedHandler” >
add name=”SessionAuthenticationModule” type=”System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089″ preCondition=”managedHandler” >
ssuerNameRegistry type=”MVC_Test.AccessControlServiceIssuerNameRegistry, MVC_Test”>
issuerNameRegistry>
</audienceUris
Hi Andras,
I have implemented Identity access in MVC project that is hosted on Azure cloud.
Issue I am facing is that though I am getting Claim object and able to loop through the assertions but on an average, after short time of being idle, the application redirects to Identity login page and then come back to requested url.
Say even after 3 minutes, it goes back to Identity site and then redirects to application page?
What may be the issue of such a short time span?
Varun
Hi Varun,
It sounds like your session times out. Have you checked the amount of idle time set in IIS for the application pool?
//Andras
Pingback: VS2013 & MVC 4 -How to setup thinktecture Embedded STS | Zapatero Answers
Pingback: Simple authentication using Json Web Tokens in Asp.Net Web Api 2.2 | Stewart Blog
How would I bypass ws federation for specific controller/action. [AllowAnonymous] and user=”?” did not work?