Mixing SSO with existing technologies (Part 4)

I know this has been a long journey on the road to an ideal SSO solution. However, take heart, victory is within sight. We will be able to close the loop in this post, finally realizing the full cycle of the Architecture. We will need one more post to fully flush it out, but in this post we will have working code for our architecture.

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 working on finishing up the solution, and you will need some orientation for maximum value. Start with an overview of the problem and the approach we took to solving it in the first post: Part 1, or go farther back and make sure you are familiar with all of the terms in the introductory post here.

Ok, so before we dive back in let's review where we are. In the First Post we designed the system. In the Second Post we authenticated against a STS (ADFS in our case) and obtained our token. In the Third Post we took that token and federated against our Federation STS (ACS in our case) and obtained our application token. What is left? Authenticating to the actual application of course!

This step has a lot going on. Because of this, I am going to focus on the web side for this post, and then quickly follow up with another post about the API side. This should keep them a manageable size to read.

If you recall, at the end of the last post we had obtained the federated token from the Federation STS. We actually saved off the full response as well as the token itself. This is actually just to make our life easier, and may or may not apply in your situation.

For our application we needed the passive WS-Federation flow, with browser redirects and users manually authenticating into the application, in addition to our active flow that we built. Because this was already set up we utilized the same middleware and configuration for the web redirect SSO as we did for normal login flow. This consolidated the interactions into web and API, and made dealing with everything much cleaner.

I am going to assume you have a vanilla passive redirect-enabled application already. I know, it is a bit of an assumption, but it is really easy to setup, and I have to draw the line somewhere. But if you don't, you are in luck! Vittorio has a great guide up on how to use the middleware and set it up. Check that out from one of the developers of the middleware! Once you have it working with the middleware you will need ACS, or another "full-featured" STS to perform the federation. ACS is really easy to insert into the chain, and works nicely. If many of you struggle with this I would be wiling to post a follow up this with a guide, but for now we will assume you are able to make this work.

Ok, so assuming you have that all working we can actually simulate what the passive flow does, and simply post the response from ACS to force the OWIN middleware to treat it just like a manual login. Convenient, right!? No special code needed. Well, ok a little code to serialize the object we have into a postable string value.

RequestSecurityTokenResponse response = DoWhatWeDidLastTime();
//This is the response from the ACS Federation calls we finished last time

StringBuilder sb = new StringBuilder();
using (XmlWriter writer = XmlWriter.Create(sb))
{
    var serializer = new WSTrust13ResponseSerializer();
    var context = new WSTrustSerializationContext();

    serializer.WriteXml(response, writer, context);
    writer.Flush();
    writer.Close();
}

var serializedResponse = sb.ToString();

That wasn't that hard, was it? It was a pain to figure out, so reap the benefits of our mistakes!

Ok, now that you have the values, let's build a page to perform the redirect. It can be a pretty simple page. It just needs to post the values for us. This page will live in your legacy application, and will be posting to the new application to login and perform SSO.

<html>
  <head>
    <script type="text/javascript">
        window.onload = function () { 
            document.redirectForm.submit(); //Redirect on load
        };
    </script>
  </head>
  <body>
    <form name="redirectForm" method="post" action="https://YOUR_APPLICATION/LOGIN_FINISH_URL">
      <input type="hidden" name="wa" value="wsignin1.0" />
      <input type="hidden" name="wresult" value="<%:serializedResponse%>" />
    </form> 
  </body>   
</html>

That is all you need. Once this page loads, and redirects you should see the full result work together to SSO from the legacy application automatically! Success! But there is still a little bit of work to be done. We still need the API to work. Let's tackle that now.

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