A Federation Swiss Army Knife -- OpenID, FB, & OAuth to SAML & WS-*

| | Comments (7) | TrackBacks (0)
Imagine you have a scenario where you want to authenticate end users to your Web site with a consumer-grade authentication protocol like OpenID, OAuth, Facebook Connect, etc. from many different Identity Providers (IdPs). Also, suppose you need to SSO from your site to another or you want to invoke a partner's Web service that requires calls to be secured w/ a WS-Security token. For instance, imagine you have an e-commerce Web site. To increase engagement, conversion rates, yadda yadda, you want to allow customers to login w/ their Twitter, Yahoo!, Facebook, or Google accounts. When a user posts a question in your forum, which you've outsourced to a third-party, you need to SSO to that partner's site which exposes a SAML endpoint. Imagine you also want to publish the user's activity in the forum to one or more of their social networks. Tall order! How might you accomplish this? I've been wondering this, and here's my idea.

My solution leverages PingFederate and Gigya Connect (both of which are sold by companies I'm affiliated w/). Gigya Connect is used as an abstraction that hides all the IdPs and provides a unified representation of a customer. PingFederate marshals this abstract notion of the user into a SAML, WS-Federation, or WS-Trust message for SSO purposes. From a high level, we have this:


In the sketch, I am trying to show how each of the IdPs sends their own types of tokens (TT, TY, TFB, TGOOG) to Gigya which normalizes it into a Gigya token (TG). When the Web app receives this, it can send user-related info to PingFederate, and it sends a SAML message (TSAML) to the partner (i.e., the Service Provider or SP). At the SP, it can use the Gigya API and the user's ID passed in TSAML to publish activity back to Twitter, Google Buzz, FB, etc. Sounds easy when I write it all out like this, but the devil's certainly in the details on this one.

To make this work, I started w/ the HTML doc I wrote after chatting w/ David Brisebois on Twitter the other day. Literally, all I had to change was the location the form was submitted to (nice!):
<body onload="onLoad()">
    <p>Please Sign In using one of the following providers:</p>
    <div id="loginDiv"></div>
    <form method="post" action="https://idp:9031/idp/startSSO.ping?PartnerSpId=localhost:gigya:entityId:sp">

If you look at the whole doc, you'll see in the JavaScript that I dynamically added each of the Gigya user object's properties to the form that is being submitted to the highlighted URL. That is a special PingFederate endpoint that instructs it to start an SSO transaction.

Here's the magic:
PingFederate can't make sense of the Gigya user data, so I used its SDK to create an adapter that converts it into something it can understand and will put into a SAML assertion. The code basically loops over the form parameters dynamically added to the request in the JavaScript and hands them back to PingFederate in code like this:

public class AuthenticationAdapter implements IdpAuthenticationAdapter

    public Map lookupAuthN(HttpServletRequest request, HttpServletResponse response, ...)

        Enumeration e = request.getParameterNames();
        Map result = new HashMap<String, String>();
        while (e.hasMoreElements())
            String name = (String)e.nextElement();
            String value = request.getParameter(name);
            result.put(name, value);
        return result;


(It's a good thing the Java code wasn't much harder than this. I was a Java programmer once, but I'm not anymore, and, boy, am I glad! The tools and the verbosity of the language are dreadful IMHO.)

The class also has code in it that creates a Gigya-specific configuration GUI in PingFederate that can be used to provide my adapter w/ config data (e.g., the secret key). Here's what it looks like:


After you've configured the adapter, you need to specify what attributes will be passed in from it to PingFederate. I decided to make almost all of Gigya's user attributes extended properties. In hind sight, they should have been core attributes, especially considering my while loop above.


This forms the connection between Gigya and PingFederate. After that, it can be used to create a federation connection. This is standard PingFederation stuff; no more magic at this point.

In my case, the SAML Response send from PingFederate to the partner used the Gigya user ID as the SAML subject. This would allow the SP to not only use the values in the token, but also use the Gigya API to publish events back to the user's social networks when they perform activities there.

The ability to use Gigya and PingFederate like this is very cool and gives you a federation Swiss army knife that you can use to carve up all sorts of new business opportunities. I know that this writeup leaves a lot out and that things might not be clear, so I may make a screencast showing this in a bit more detail. In the meantime, feel free to drop me a note if you have questions.