Few weeks ago I had the pleasure of presenting, together with Planky, a TechEd EMEA interactive session on the subject of equipping your Identity Provider with an STS. The session was pretty popular, I got a lot of people telling me that they searched for that exact content without finding it anywhere else, and the topic of custom STSes keeps coming out: hence I decided to capture some of the key points in a couple of posts before the Thanksgiving laziness takes over. The first one, that you are reading right now, will be about demystifying the topic a bit; the second installment will be about a simple example of custom STS written with the Geneva Framework.
You want to be an IP... and you think you need an STS
Many businesses are natural identity providers. Countries, banks, airlines, clubs, credit reporting agencies, social networks... those are all examples of entities involved in a 1:many relationship with subjects & knowing a great deal of interesting facts about them. Those would probably be the IPs you'd think of if you'd come from the information card camp. However, as anybody from the "traditional" federation camp would tell you, there are many more candidates to the IP role: any business entity wishing to federate with another may, depending on which side of the relationship it sits, be an identity provider. We can get even more granular: if inside your enterprise you have a product or an island of some sort which maintains a users/attributes store and does not integrate with your directory, here there's another construct that may benefit from being modeled as an IP. I could go on, but I guess you get the point by now: the IP role is ubiquitous and can be successfully applied in a wide range of scenarios.
Once you realize that yes, you want to be an IP, you've got to make that happen. That basically means that you need the capability of minting portable identities for your users whenever you are asked to and you deem appropriate: and yes, in the current backbone architecture of the metasystem that means that you need an STS.
A security token service, or STS if you are in a hurry, is the tool that the IP uses for fulfilling its role: the security tokens are in a sense the reification (sort of) of identities, hence being able of processing requests for issuing tokens does the trick (at least formally: for being an effective IP you need to worry about many other things).
For its very nature, the STS plays an absolutely pivotal role for the IP: no STS, no party. A couple of examples:
- It is a key asset to secure. It's really handy to have a single place where you can concentrate your access control logic, but it goes without saying that it becomes an absolutely critical element. If somebody compromises the STS, he/she can easily do horrible damage to all the systems that trust it. And even if for some strange miracle not a lot of damage is made, the sheer fact of having been breached can destroy reputation and user acceptance
- High availability is of essence. If your STS is unavailable when a user or an app demand a token from it, there's simply nothing that can be done. The more popular your STS is, that is to say the more apps/federated partners rely on it, the higher the cost of downtime. Simple.
Let's say that you are now aware of the importance of getting the STS right: from where you should start? The problem can be very complicated, however I suggest that the rough steps you may follow are:
- Derive requirements from what you have. Chances are that you are not starting from scratch, but you already have a solution in place that you want to enhance with IP capabilities; and/or you may have an idea of who will be using your services and their requirements. Below I'll give a more comprehensive list of relevant factors, but you get the point: you'll rarely deal with a pure green field scenario, and if you do there's probably something wrong
- Pick an off-the-shelf product that satisfies your requirements. Until some time ago the only route to having an STS was writing one, now there are finished products that do a great job and pack the expertise of specialized teams who thought long & hard about solving problems such as the security & availability mentioned above. The Not Invented Here (NIH) syndrome is always bad, but in case of cornerstone components like STSes can be fatal: the first option to consider should always be a shrink wrap product.
- If there is no perfect fit, consider how to leverage product's extensibility points. There's always the possibility that a product just out of the box is not a perfect fit for your scenario. Before giving it up, it is worth exploring what can be done for customizing the product: maybe a thin integration layer here or there is all is needed for reaping the advantages of a finished solution.
- If extensibility can't solve your problem, consider writing your own STS. Products can give a very good coverage of many scenarios, and the extensibility points can extend that by many times: however you can never rule out the possibility that certain scenarios will end up not being addressable. In those cases writing your own custom STS is a possibility: what is absolutely key is realizing that obtaining the same quality & dependability of an STS provided by a product may require a lot of effort. Of course there may be times in which you don't care, for example if you are setting up an STS for development purposes (ie your actual product is a RP, and you are developing a dummy STS just for testing it); as long as you are aware of what you are doing, you should be fine
Too generic? Well, let's dig in some more details.
Factors driving STS implementation decisions
At the end of the day, an STS can be just a web service that is able to issue security tokens. Or is it? Perhaps your scenario is a federation in which only passive clients are allowed: in that case, the STS is actually a web page rather than a WS-* service. And what "able to issue security tokens" means? Using which protocols? Authenticating against which kind of credentials? And which token format should be produced, by the way?
All those decisions can shape up the STS that you need to deploy in order to meet your needs: ignoring security/availability/manageability, which are orthogonal to everything else, let's take a brief look to some of the most important influencing factors.
- Attributes Stores. You want to be an IP, you've got to have some identities in your stash. The attributes of your users may currently be in a single database, or scattered across different stores & components; you may be able to consolidate them in a new store specifically for the new IP function, or you may be forced to keep everything as it is for many different reasons; ad so on. In any case, your STS will need to be able to tap from your attributes store(s) in order to assign the requested claims values.
Small SOA note: this is a "detail" that lives within the boundaries of the service itself, hence it should not have consequences on what is exchanged on the wire; but it remains a key architectural aspect.
- Authentication Factors. You may already have an authentication mechanism in place, or you may just have an attribute store without direct interaction with the users whose identities are kept in your system. In the former case, you may want/need to reuse the current authentication mechanism as a way of securing token issuing requests; in the latter, you may need to create such a mechanism in order to enable users to authenticate themselves when requesting tokens. Some examples: username/password, x509 (soft, smartcard), Kerberos, other issued tokens, and so on. The authentication factor of choice will influence the protocols that your STS can use, and impose further requirements in the context of the protocol of choice (ie, a specific token type)
- Authentication Stores. Strange as it may seem, authentication factors and authentication stores represent quite different requirements. My factor may be a super common username/password pair, but if the authentication store is a custom db that cannot be moved I have to take that into account in my design. Another thing to notice about this factor is that, similarly to the attributes store, it should have no direct influence on the wire.
- Requestors. How do we envision our users to access the STS? Though browser only? Via rich client, perhaps via identity selector? Any specific constraints on the client devices capabilities? This will have an impact on the protocol hosting and the protocol itself that we'll use. There are dependencies on the authentication factors and the next point, the intended relying parties: what constraints what will depend on the relative weights on the specific scenario.
- Intended RPs. The relying party applications we foresee will require our tokens can influence, again, the protocol hosting and the supported protocol through which we'll expose our STS. If one of the apps we want to serve is a web service, we better be prepared to expose a WS-Trust STS which issues holder-of-key token types; if another is a web app which supports SAML-P, let's get ready to support browser redirects and to process SAML-P compliant requests. Another way in which the list of intended RPs can influence the behavior of the STS, though not the wire, is the fact that such list can (and should) be consulted for making decisions about if a token should or should not be released for a specific RP. This is of fundamental importance in federation relationships, where you always want to verify that you are dealing with your actual federated partner as opposed to some random imposter; and it serves an important role for providing the crypto material to be used for encrypting the token for a specific RP (the list will likely contain RP endpoint URIs, certificates and other info).
- Other Authorities. It is pretty common to expect token issuance requests secured with tokens obtained by other STSes: in that case, obviously the protocol of choice will limit the set of STSes from where ours can receive requests. Technically there's no big difference with the requestor constraint above, the key differentiation point here is the expected use of issued tokens. This is not strictly about the IP role, and is in fact a function of the FP one; however it is very common for an entity to play both roles, hence this is a requirement that should be considered even if for the time being you are planning to play just the IP.
This is just a short list, definitely incomplete. Furthermore, it lists just the external elements that may already be part of your scenario even before making the move toward being an IP: there is a much longer list of things you should think about once you get the ball rolling. Card issuance policies & stores, revocation handling, claim filtering criteria, factors influencing issuance rules... let's keep those out for simplicity.
Geneva Server as a balm against the NIH Syndrome
In my little recipe above the step 2 says "Pick an off-the-shelf product that satisfies your requirements" (yes I know, step 3 should be "Profit!"). Now, that's a pretty young market and there's not a lot out there: but there is a product I feel I can suggest to you, and that's Geneva Server. Geneva Server
- Is part of Windows Server
- Offers an STS that can fullfill both IP and FP roles
- Is an information cards issuer
- Supports WS-Trust 2005, WS-Trust 1.3, WS-Federation, SAML-P (IdP Lite, SP Lite)
- Generates WMI events, MMC managed
- Features claim generation and transformation built in
- Uses Active Directory as Authentication store
- Uses Active Directory or other (directory) stores for Attributes
- Offers an STS Proxy service to expose STSes in DMZ
- Point&click Federation and Trust Management support
- Shrink-wrapped, production software
- Takes advantage of the Windows Server eco-system
If you compare this description with the list of relevant factors I gave earlier, you'll see how Geneva Server as is can address a wiiide range of cases. If you want to set up an STS for your IP and you are working on Windows, you should really think long & hard before deciding NOT to use it. The Not Invented Here syndrome has a strong allure to every developer and architect, we all like to fiddle with things and leave our fingerprints everywhere: but remember, the day in which your baby goes in production it ceases to be your play buddy and can become an endless nuisance. Given the fact that the merry time spent designing and developing the system is usually a fraction of the time it is expected to function, make sure you take the right decision there 🙂
If everything else fails: contemplating writing a custom STS
There will always be situations that the product won't be able to address. Maybe you want to use an exotic token format, corresponding to an exotic authentication factor; or more simply, you don't have AD and this beta requires it as the authentication store. Besides the fact that this is the first beta of the product, hence I expect that your feedback can still go a long way for influencing the feature set at release time: if everything else fails, you still have the chance of writing your own custom STS. You have to be prepared to give up a number of the good properties that a shrink wrap product such as geneva server gives you, or be prepared to work hard to reproduce those in your custom code, but writing your custom STS is definitely a possibility. In fact, it has never been easier: the geneva framework, which BTW has been used for writing the geneva server, offers suitable classes and a programming model that helps you as much as humanly possible to streamline the development of an STS. The fact is that while there are things that we can manage for you, such as sheer handling of the protocol and crypto management, there are others that are intrinsically up to you: how you want to retrieve claim values from custom stores, for example, or how you want to perform user credential/RP/claim types validation. We can give you good hooks in the programming model for injecting your login in the right place, but we can't help you to make that logic secure or performing. And of course you are in control of all other vertical aspects, such as hosting/availability/manageability/health monitoring/auditing and everything else. You may simply not care about many of those factors, like in the previous example in which your real product is an RP and the STS is just an artifact used for testing; or perhaps the intended use of your STS is for some reason not as demanding as I am implying above; or again, perhaps you are a pro ISV with the necessary know-how and you do intend to have fine control on everything hence you are willing to invest what it takes for getting all those aspects right. You may have your own reason, and I don't want to discourage you from writing your own STS: I just want to make sure that you are aware of the implications of doing so and that you are OK with it. In fact, in the next post I will show you how you can structure a simple custom STS with the October beta of the Geneva Framework