Mixing SSO with existing technologies (Part 3)

Ready to continue the arduous journey of realizing the perfect blend of old and new? To implement a blended Single Sign On architecture that easily allows you to mix legacy applications and new, cloud capable SSO enabled applications?

Last time we successfully authenticated to our Identity Provider (Microsoft ADFS) using active flow. (Utilizing the WSTrust protocol to request a SAML token) This is great, The hardest part is done! But there is still work to be done before we can realize the full architecture that we originally envisioned.

This time we will continue with the detailed look, this time focusing on the second hop of the process, authenticating with the Federation Provider utilizing the hard-earned token we obtained in part one.

Note: This is a continuation in a series of blog posts. If you haven't read the previous posts, I would highly recommend doing so to get up to speed.
I will be diving right back into solutions which will make much more sense with the right groundwork. Orient yourself with an overview of the problem and the approach we took to solving it in the first post: Part 1, or start with some terms in the introductory post here.

Ok, so now that we have the token from ADFS (Our IdP STS), we can now perform the federation step of the process. We have to perform this step because our cloud application only trusts tokens that are obtained from its one registered partner, the Federation Server (In our case ACS). In order to authenticate to this application we need a token from that STS. Thankfully, we now have the means to authenticate to that server, using the token we obtained.

Quick confession, I forgot to include some important information about where to get the correct versions of some classes we used last time. It may have worked, but it likely left you with a mess of conflicting namespaces. Please see my ninja-updated post here, and be confused about how oblivious you must have been when first reading the post to miss that detail.

The Federation STS, unlike an IdP STS, is not backed by an identity store and thus has no use for usernames/passwords (Ignoring some special cases with service accounts not for identifying users). Instead, its only purpose is to be trusted by reliant party applications, and to trust other STS's such as our IdP STS. This provides a flexibility point in our architecture, allowing new Identity Providers to be added and removed at will, all without requiring code changes to the application itself. This is key in a multi-tenant environment such as our planned architecture.

Ok, enough overview, let's dig in.

The code for this should look familiar, as it uses many of the same classes and namespaces as step 1. We simply configure the bindings a bit differently.

First, we need to make a binding to use for the communication. Last time, if you remember we utilized a port by Dominick Baier of the UserNameWSTrustBinding to authenticate using user credentials. This time we want to use the token we have, so we will need an IssuedBeareTokenWsTrustBinding for it.

Thankfully, as before, Dominick has done the heavy lifting, and all it needs is a little focusing to our use case. Dom's class is available here, or you can check out the slimmed down version we ended up making available on Github here IssuedBearerTokenWSTrustBinding.

var issuedTokenBinding = new IssuedTokenWSTrustBinding();

Once you have the binding we can use it to create a channel factory to create a communication channel. As before, it is pretty simple.

using (var channelFactory = new WSTrustChannelFactory(
            issuedTokenBinding,
            fedEndpointAddress))
{
    .... 
}

As before, you will need the correct endpoint address to connect to, this one will be something like this:

var fedEndpointAddress = @"https://SERVER/v2/wstrust/13/issuedtoken-bearer";

Like before we need to set a property on the factory to make sure it uses the correct version of WSTrust (1.3 ). We will also need to make sure that it does not try to prompt the user for alternate authentication sources, just to be safe.

channelFactory.TrustVersion = TrustVersion.WSTrust13;
channelFactory.Credentials.SupportInteractive = false;

Finally, we can use the channel factory to actually create the communication channel.

       var channel = factory.CreateChannelWithIssuedToken(StsToken);

What is StsToken? Why, that is the token you fought for last time to obtain! This sets up the channel to utilize that as the authentication token for the next calls.

Now that we have a channel all ready for communication, we need to build something to actually say. We want to request a token, so let's make a request.

var request = new RequestSecurityToken
        {
            RequestType = RequestTypes.Issue,
            AppliesTo = new EndpointReference(REALM),
            KeyType = KeyTypes.Bearer,
            TokenType = Constants.TokenTypes.SAML2
        };

This builds a request for the server to issue a SAML 2.0 Bearer token for the given Realm. Once we have built the request, we need to actually send it.

RequestSecurityTokenResponse response;
var FederationToken = channel.Issue(request, out response);

We will see how the full response will come in handy later, but for now we simply save it off. The token returned will be, assuming all your steps were successful, a SecurityToken containing the token obtained from the Federation STS. Congrats! You have successfully performed active federation using WSFederation and WSTrust!

Next time we will dive into how to use the obtained token to authenticate with the cloud application both for API use, as well as for transitioning over to the web application.

Have you found this series useful? Confusing? Inspiring?
I would love to hear any feedback that anybody might have!
Sound off in the comments below!

Tim Ritzer's Image
Tim Ritzer
Missouri, USA

I am a Software Architect who loves to code, trying to practice what he preaches.
Follow me on Twitter @TimRitzer

Share this post