In a previous post, I talked about candidate architectures for federated identity systems. My current favorite includes a single IP-STS that issues identity-only claims that are globally unique across all security realms. Because most applications will require more than just identity claims to make an access control decision, the architecture includes an RP-STS per realm. These token services translate globally unique user attributes into ones that are specific to him/her in each of these fiefdoms. The additional claims allow the applications in these realms to determine if the subject should be allowed access to their resources. A diagram of this arrangement doesn't have many boxes or arrows (as you can see in the first figure); however, it gets more complicated when you think about what it would require to solve some fairly common use cases. For instance, how does a Web application in one realm call a Web service in another? This need may arise when one BU owns the Web front-end and another owns the back-end service. Each application in these two BUs (i.e., security realms) would trust different RP-STSs. So, how (on paper) can this use case be solved with the previously described candidate architecture?
In order for this to work, the Web front-end RP 1 needs to trust RP-STS 1; RP-STS 1 must trust the IP-STS. Also, the Web service RP 2 trusts RP-STS 2. The RP-STSs must trust each other. These relationships can be seen in the second figure.
That's a few more lines, and we still haven't shown the information flows ;-)
Given these trusts, the chain of events that result is as follows: When an unauthenticated user accesses RP 1, he is redirected to RP-STS 1 (via WS-Federation). From there, he is redirected again to the IP-STS (also on the front-channel). The user authenticates, and the IP-STS issues him a security token ST0 containing identity-only claims. It redirects him back to RP-STS 1. That STS accepts ST0 as proof of the callers identification (because it trusts the IP-STS), and issues him a new token ST1 which contains application-specific claims that RP 1 will need authorize his access. It is very important to note that at this point ST0 is gone. RP-STS 1 may have copied the identity claims into ST1, but for all practical purposes ST0 with its signature, claims, and whatnot is completely gone. ST1 is returned to the user, and relayed to RP 1.
Now, our Web front-end RP 1 wants to call the back-end Web service RP 2 to get some additional resource. To do so, RP 1 needs a token for the user that is specific to RP 2. This RP only trusts RP-STS 2, so RP 1 must request an ActAs token from RP-STS 2 (using WS-Trust). To get this, RP 1 must be able to authenticate (e.g., using an X.509 cert) and send it ST1 that it got from an issuer that RP-STS 2 trusts, namely, RP-STS 1. RP-STS 2 does some verification of the token and authorization to ensure that RP 1 and ST1 can be used to get an ActAs token for RP 2. If so, RP-STS 2 transforms ST1 into an ActAs token ST2 that contains application-specific claims for the user accessing RP 2 (via RP 1). ST2 is returned to RP 1 who includes it with the request sent to RP 2. RP 2 trusts the issuer, so it accepts the claims in it and uses them to determine if the user is allowed access.
This sequence of events is shown in the final figure:
I know what you're thinking: This is maddening. Anyone that does this is psycho. You're right that this is complicated stuff. (Anyone who tells you differently is trying to sell you something.) If you're dealing with financial data, healthcare records, government secrets, or other sensitive information, however, what alternatives do you have? Let me know if you can think of a better way.