Saturday, 31 October 2015

Claims-based authentication in .NET4.5 MVC4 with C#: External authentication with WS-Federation Part 3 Various advanced topics

In the previous post we looked at some basic features of WS-Federation in a .NET4.5 MVC4 web app. In this post we’ll dive into some advanced features around WS-Federation.
Topics we’ll discuss include:
  • Dynamic WS-Federation configuration at runtime
  • WS-Federation authentication events
  • Logging off
The features will be presented in a demo at the end as usual.
Dynamic configuration
We saw in Part 2 how WS-Federation can be configured in web.config. Those settings are of course static. However, occasionally you may need to set some properties dynamically. You might have these values stored in a database or you need to query a web service for the right configuration.
You can achieve this using Global.asax in the Application_Start() method. First wire up the FederationConfigurationCreated event as follows:
1
FederatedAuthentication.FederationConfigurationCreated += FederatedAuthentication_FederationConfigurationCreated;
…where FederatedAuthentication_FederationConfigurationCreated will initially look like the following:
1
2
3
4
void FederatedAuthentication_FederationConfigurationCreated(object sender, FederationConfigurationCreatedEventArgs e)
        {
            throw new NotImplementedException();
        }
The incoming FederationConfigurationCreatedEventArgs has a property called FederationConfiguration. This property in turn has other properties, such as Name, ServiceCertificate, IdentityConfiguration, etc. that allow you to dynamically set the WS-Federation properties at runtime. Thus you get programmatic access to all WS-related configuration elements in web.config. Feel free to inspect what’s available using IntelliSense.
WS-Federation authentication events
The WSFederationAuthenticationModule, which is available as a property of FederationAuthentication has events similar to those of the SessionAuthenticationModule which we discussed before.
Type FederatedAuthentication.WSFederationAuthenticationModule. in the editor and inspect the available events using IntelliSense. The names of the events are pretty self-explanatory. We will look at the event called RedirectingToIdentityProvider in the demo. This event is fired when the HTTP request is redirected to the STS. Here you have the chance to modify the data that’s sent to the STS at runtime. You would hook up the event in Global.asax in the Application_Start() method:
1
FederatedAuthentication.WSFederationAuthenticationModule.RedirectingToIdentityProvider += WSFederationAuthenticationModule_RedirectingToIdentityProvider;
…which looks initially like this:
1
2
3
4
void WSFederationAuthenticationModule_RedirectingToIdentityProvider(object sender, RedirectingToIdentityProviderEventArgs e)
        {
            throw new NotImplementedException();
        }
The RedirectingToIdentityProviderEventArgs parameter has a property called SignInRequestMessage which allows you to modify the outgoing message properties, such as Realm, BaseUri etc. You can create a new SignInRequestMessage as follows:
1
2
SignInRequestMessage signInRequestMessage = new SignInRequestMessage(new Uri("https://stsuri"), "the realm identifier");
String completeQueryString = signInRequestMessage.WriteQueryString();
You can then send the query string to the STS. This is the technique to be used with the Login link on your web page. As the web app does not have its own Login page any more the Login link needs to lead to the external STS using the query string constructed from the SignInRequestMessage object. We’ll see in the demo how this works.
Logging off
Locate the LogOff action in AccountController.cs. If you followed the posts in the series then you may have the following calls in there at present:
1
2
WebSecurity.Logout();
FederatedAuthentication.SessionAuthenticationModule.SignOut();
You can delete them and add the following call instead:
1
FederatedAuthentication.WSFederationAuthenticationModule.SignOut();
This will clear out the FedAuth session cookie. However, this will not sign you out of the STS. There’s a technique called Single SignOut which will do that for you. We won’t look at that in this blog post but in the next one.
Sliding expiration
Sliding session token expiration was explained here. You use the same techniques in the case of WS-Federation.
Server-side security token caching
This is very similar to FederatedAuthentication.SessionAuthenticationModule.SessionSecurityTokenReceived we saw here:
1
FederatedAuthentication.WSFederationAuthenticationModule.SessionSecurityTokenCreated += WSFederationAuthenticationModule_SessionSecurityTokenCreated;
In WSFederationAuthenticationModule_SessionSecurityTokenCreated you would then set the reference mode to true:
1
e.SessionToken.IsReferenceMode = true;
The effect is the same as before: not the entire Claims collection is serialised into FedAuth but only an identifier and the server will locate the serialised Claims collection using that token identifier.
Demo
Open the MVC4 internet application we’ve been working on in this series. Let’s see how dynamic configuration works first. Go to Global.asax and locate the Application_Start() method. Wire up the RedirectingToIdentityProvider event as follows:
1
FederatedAuthentication.WSFederationAuthenticationModule.RedirectingToIdentityProvider += WSFederationAuthenticationModule_RedirectingToIdentityProvider;
The skeleton of WSFederationAuthenticationModule_RedirectingToIdentityProvider will look like this:
1
2
3
4
void WSFederationAuthenticationModule_RedirectingToIdentityProvider(object sender, RedirectingToIdentityProviderEventArgs e)
        {
            SignInRequestMessage signInRequestMessage = e.SignInRequestMessage;
        }
Set a breakpoint at ‘SignInRequestMessage signInRequestMessage = e.SignInRequestMessage’ and run the application. Click the About link and you’ll see that code execution stopped at the break point. Inspect the SignInRequestMessage property in the Locals window and you’ll see it holds the values of the Request Url and the Realm:
SignInRequestMessage in locals window
Here we have the chance to dynamically set these properties based on a DB lookup or a web service call or a similar mechanism.
The SignInRequestMessage object can be used to redirect the user to the external Login page if the user clicks the Login link on the main screen. In a traditional forms-based app the user would then see the internal Login page but that is not an option any more.
Locate the Index action within HomeController.cs. There are two ways to construct the SignIn message. One is using a constructor:
1
SignInRequestMessage signInRequestMessage = new SignInRequestMessage(new Uri("https://andras1/idsrv/issue/wsfed"), "http://localhost:2533/");
You pass in the STS login URI and the realm. I simply copied the values from web.config.
Another way to set these properties is the following:
1
2
FederatedAuthentication.FederationConfiguration.WsFederationConfiguration.Realm = "http://localhost:2533/";
            FederatedAuthentication.FederationConfiguration.WsFederationConfiguration.Issuer = "https://andras1/idsrv/issue/wsfed";
We’ll go with the constructor type of solution. Add the following just before the return statement in the Index action:
1
2
SignInRequestMessage signInRequestMessage = new SignInRequestMessage(new Uri("https://andras1/idsrv/issue/wsfed"), "http://localhost:2533/");
            ViewBag.StsSignInUrl = signInRequestMessage.WriteQueryString();
For simplicity we add the query string to the ViewBag. Ideally it would be part of a ViewModel, but that’s beside the point in this discussion. Open Index.cshtml in the Views/Home folder. Add the following markup somewhere in the View:
1
2
3
<p>
    <a href="@ViewBag.StsSignInUrl">Log in here!</a>
</p>
Run the application now and click the generated Login link on the home page. If you set up the STS login URL correctly then you’ll be redirected to the STS where you can sign in. Upon successful login you’ll be redirected to the MVC4 web app with Hello, [username] in the top right hand corner meaning that you successfully logged in to you site.
We modified the LogOut action before to make sure that the FedAuth cookie is removed. Press the ‘Log off’ link and you should then be logged out of the web site. Great! However, keep in mind what we said about the logoff method before: the session ended as far as the MVC application is concerned but is still alive on the STS side. Press the About link again and you should be automatically logged in without having to provide the username and password.
You can end the STS session by a technique called Single SignOut which is one of the things we’ll look at in the next blog post among other features such as Single SignOn.
You can view the list of posts on Security and Cryptography here.

No comments:

Post a Comment

Angular Tutorial (Update to Angular 7)

As Angular 7 has just been released a few days ago. This tutorial is updated to show you how to create an Angular 7 project and the new fe...