Saturday, July 17, 2010

Windows Indentity Foundation – Custom Security Token Service and the relying party configuration

The last couple of days I’ve been coding with the Windows Identity Foundation (WIF) in order to create a WS Federation Security Token Service (STS) that provides the user authentication for multiple relying parties (RPs). I decided to write a small tutorial and a sample (full commented) project that describes the basic steps that are required in order to setup the authentication via passive federation.

First of all you should start by downloading the Windows Identity Foundation (aka WIF) from Microsoft. This download provides all the necessary dlls (including System.IdentityModel and Microsoft.IdentityModel) to build a WIF claim based application.

The second thing you have to do is download the Windows Identity Foundation SDK that integrates into visual studio and provides many helpful examples. This download provides the FedUtil.exe also known as Federation Utility that automatically configures the trust between an RP and an STS and also auto generates a custom STS based on your RP configuration file.

Having installed the two prerequisites, you may download the sample project I have created, from the following link, and look for the comments that start with “WIF Comment:” in order to locate the code that is WIF specific.


Project description

As I mentioned earlier I wanted to create a simple claim based web site application (see a couple of reasons on why you may need to create one on my previous post). In fact the downloaded solution contains two relying parties. One (RelyingParty) that was manually created from start to end (ok I admit that the design is created by vs) and another one (AutoconfiguredRelayingParty) that was configured almost entirely by the Federation Utility that comes with the WIF SDK. Let’s see the RelyingParty project first.

The RelyingParty (RP) web application

This is the default asp.net application that was created from the visual studio templates. I have stripped off the entire FormsAuthentication mechanism that comes with the original template (deleted the appropriate folder) and modified the web.config to enable the WS Federation Authentication.

One thing you should note is that we have completely disabled the asp.net’s build in authentication by setting the mode to None and on the other hand we have denied unauthenticated users by setting «deny users="?"». The next thing we did was to add the WS Federation httpmodules in the asp.net’s modules stack (under the httpModules for IIS6 and the webdev server visual studio runs and under system.webServer.Modules for IIS 7+). These modules will be handling the authentication requests of our application. In order to configure them we will have to introduce a new configuration section in our web.config file by adding the corresponding section declaration in the configSections region on the top of our configuration file. We added the microsoft.identityModel section which is heavily commented in the downloaded source code. The most important parts of this section are:
  • The applicationService\claimTypeRequired part where you specify the claims your application requests from the STS.
  • The passiveRedirectEnabled="true" set in the wsFederation section that enable the passive redirect to the STS whenever authentication is required
One more thing to note is that I have disabled all the certificate checks that are made by WIF in order to simplify the demo. Normally, the RP receives and installs in the computer it runs the STS’s certificate in order to verify each message it receives by checking the signature and STS installs the public key of RP in order to encrypt the authentication messages so as to ensure the trust between both parties. WIF supports a lot of certificate lookup mechanisms but it also requires valid certificates which are not easy to get your hands on. If on the other hand you want to play around with the certificates functionality, you may use the custom WIFCommonLibrary.Certificate.CustomX509CertificateValidator x509 certificate validator which reads the certificate from the embedded resources (thus you’ll not have to install your certificate in the machines certificate store). See the web.config comments on how to enable this functionality.

One final thing you should note in the web.config file is the requestValidationType="WIFCommonLibrary.Web.AllowWFClaimsRequestValidator" set in the httpRuntime. By overriding the request validation, we will be allowing the federation form requests that will be coming into our application. If you don’t do so, you will get a «A potentially dangerous Request.Form value was detected from the client (wresult="trust:RequestSecuri..."» error due to the default asp.net’s request validation that prevents suspicious requests.

On the Default page I have added the code to display the claims that are associated with the authenticated user. On the Site.Master page I have modified the logout functionality by tampering the asp:LoginStatus to redirect to the SignOut page and finally in the the SignOut page I have a simple call to Microsoft.IdentityModel.Web.FederatedAuthentication.WSFederationAuthenticationModule.SignOut which ensures that you log out the user. Note that you’ll have to redirect the user because the request is authenticated and the user will end up seeing the page. If you allow the user to see the page, on the next request, he will not pass the authentication stage and thus he will end up with the STS’s login screen (automatically driven there because we have enabled the passiveRedirectEnabled).

The SecurityTokenService (STS) web application

The STS consists of two web pages:
  • The default.aspx which will be creating the federating identity and
  • The login.aspx which will be authenticating the incoming users.
The STS is a simple web application (in a manner of speech). If you take a look in the web.config, perhaps you will be surprised to see that there is no identity configuration. It only contains a simple FormsAuthentication declaration. In order to keep the demo simple, I have decided to use asp.net’s default forms authentication in order to verify my users. This means that you can simply add your own membership provider and verify the users on any source you like. One more thing you have to note is that I don’t allow any unauthenticated user to see the default page (the one responsible for creating the federation token). This means that when the RP calls the STS for a security token, the request is automatically redirected to the STS’s login screen where the user has to present his credentials, and then he is redirected to the default page which redirects the user back to the RP passing the security token. This is depicted in the following sequence diagram:

 
The nice thing about WIF is that this is totally transparent to the end user. The regular end user will not even notice that he is redirected to another place (the STS).

The default page contains the code that handles the federation requests (signin and signout) and there are not many things you should modify in this page. The hard work of the STS is located in the folder SecurityTokenService where the customsecuritytokenservice is defined.

CustomSecurityTokenServiceConfiguration refers to the configuration of the STS and provides a single instance access of this configuration (thus you’ll not have to set the security token service’s configuration over and over again). Note that we initialize the STS’s certificate calling the CertificateUtil.GetCertificate() method which retrieves the certificate from the embedded resources. In the actual production STS you should retrieve the certificate from the computer’s certificate store!

CustomSecurityTokenService is the actual STS. It inherits Microsoft.IdentityModel.SecurityTokenService.SecurityTokenService, it handles the requests and provides the requested ClaimsIdentity based on the authenticated user’s properties. To keep this demo simple, I have hard coded the output claims, but you should probably add some database lookup mechanism in order to retrieve each user’s claims. The place to add this kind of mechanism is the overridden GetOutputClaimsIdentity method.

The last file you should probably see is \FederationMetadata\2007-06\FederationMetadata.xml which is a descriptive metadata file of the STS’s capabilities. It describes in the oasis standards what are the available claims, who is responsible for this STS, how can you access this STS and staff like that. In order to create these files please refer to the WIF Custom STS metadata file editor I have created in a previous post.

The AutoconfiguredRelayingParty (RP) web application

Having created the STS you may now have the Federation Utility (found in the WIF SDK) to automatically configure your RP. To demonstrate this functionality I have created another empty asp.net web application and used the tool to pair it with my new STS. To see how this is done, please refer to my older post found here.
The only thing you should note is that you’ll have to manually set the requestValidationType to allow the federation token form posts, as mentioned in the previous relying party (or you can see the web.config comments).
The WIFCommonLibrary library

This library contains some useful classes that I have gathered together in order to facilitate the development of custom STSs and RPs. They are only for developing and testing purposes and should never be used in the actual production applications. Both available classes are discussed in the previous sections of this article.

Hope this article and the source code will help you get started with the windows identity foundation!

3 comments:

Anonymous said...

Thanks!

Sam said...

Would you need ADFS 2.0 to create the relying party?

Andreas Botsikas said...

@Sam, ADFS is an implementation of an STS and it's a great product. Thanks to the new WIF implementation in .Net 4.0, I have been implementing my own STS during the last couple of years in order to support weird user stores like mainframes etc. Unfortunately the article is a bit outdated (Owin has simplified the process a lot), but the main principal remains the same.