Driving the WS-Federation Handshake from ASP.NET Web API

In general I think the API design of the WS-Federation support in WIF / .NET 4.5 is a bit unfortunate.

It was a strange decision to combine the HTTP module (aka the FAM) and the more generic protocol helpers into a single class. And the fact the system.identityModel configuration sections are not declared by default, makes the FAM hard to use as a “standalone” library (for the search engines: “ID7027: Could not load the identity configuration because no <system.identityModel> configuration section was found.”). Microsoft?! Please fix this.

That all in combination makes it non-obvious how to “manually” process WS-Federation messages and since the question came up recently – here’s how to do it with ASP.NET Web API:

To create the WS-Federation request you can use this code:

public HttpResponseMessage Get()

{

    var signInRequest = new SignInRequestMessage(

        new Uri(https://idsrv.local/issue/wsfed),

        “urn:realm”);

 

    var response = Request.CreateResponse(
     
HttpStatusCode
.Found);

    response.Headers.Location =
     
new Uri(signInRequest.WriteQueryString());

 

    return response;

}

The interesting bit is processing the response. As long as you can turn the post data into a NameValueCollection, it’s quite easy:

public HttpResponseMessage Post(HttpRequestMessage request)
{
    var form = request.Content.ReadAsFormDataAsync().Result;
    var signInResponse = WSFederationMessage.CreateFromNameValueCollection(
        FederationMessage.GetBaseUrl(request.RequestUri),
        form) as SignInResponseMessage;
 
    var fam = new WSFederationAuthenticationModule();
 
    // set all the necessary configuration
    // don't forget to declare the system.identityModel config sections
    fam.FederationConfiguration = new FederationConfiguration();
 
    var token = fam.GetSecurityToken(signInResponse);
            
    // validate token etc.
}

 

HTH

This entry was posted in ASP.NET, IdentityModel, WebAPI. Bookmark the permalink.

7 Responses to Driving the WS-Federation Handshake from ASP.NET Web API

  1. RonyK says:

    Can this technique be used to “manually” get a SessionSecurityToken from the ThinkTecture IdentityServer? How? I don’t exactly understand where should this code be placed, and how is it that no credentials are passed to authenticate with the Issuer/IDP ?

  2. Not sure what you mean – IdentityServer does not issue session tokens to RPs.

    This was mainly for educational purposes to show it is possible to handle the WS-Fed response in an environment “outside” of ASP.NET, e.g. (self hosted) Web API.

  3. RonyK says:

    I’ll explain: I have an MVC web application configured to passively authenticate using IdentityServer, then using an HttpClient to call a WEB API application sending the SAML token from the bootstrap context in the security header, of course the WEB Api is configured to handle the SAML token. This works great!
    What I was now trying to do, was to allow an invited guest to view parts of the site. By custom validating it’s invitation token, then “progmatically” authenticate with Identity server, get a security token, put it in a session cookie using the SAM, and in the bootstrap context to allow the same code that handles a registered user to work untouched (getting the SAML from the bootstrap context and using it to authenticate with the WEB API. Transforming the claims on the way would also be useful, and maybe even using some kind of delegation/ActAs, to allow the Guest to act as the user who invited him.
    So, am I’m trying to do something very awkward? What is the way I’m supposed to use WIF/Thinktecture infrastructure to achieve my goal? I still couldn’t find all the puzzle pieces to make this fit together…

    • Well – OK. Why not.

      You can programmatically request tokens using WS-Trust. Manually creating the session token with the bootstrap token should work as well – though I never tried it.

      • RonyK says:

        I tried, but couldn’t find a way to convert the GenericXMLSecurityToken received from the wstrust endpoint to a SessionSecurityToken, required by the sam.WriteSessionTokenToCookie(token), is there a way for doing that?

  4. Well – OK. Why not.

    You can programmatically request tokens using WS-Trust. Manually creating the session token with the bootstrap token should work as well – though I never tried it.

  5. You first need to turn it into a SAML token – i think tt.idm has a ToSecurityToken() extension method. Then validate it to get the ClaimsPrincipal.
    Then turn into a SessionSecurityToken.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s