…and fire in the sky ♫
Don’t you hate it when a technical blog devolves in what is for the most part a series of announcements? That’s kind of what happened to mine. The reality is that making the things which get announced here take an inordinate amount of time, and that every remaining moment (usually none) should be spent writing the WIF book *gasps*.
Well, this time i am making an exception and spending some of this Seattle-Paris flight discussing a topic which came up very often in the last few months: how to obtain, and how to use, claims on a client. I had various discussions about it both internally and more recently during the workshops, and given the originality of my positions I think it’s high time I actually write it down and point people to it instead of restarting every time the conversation from the beginning.
Remember this blog’s disclaimer, those are MY thoughts (as opposed to the official IDA blog, please always refer to it first).
Let’s say that you learned how to use WIF for driving the behavior of your web application (or web service). IClaimsPrincipal is your friend: You use claims for authorizing access to certain pages/services, you customize the appearance of the pages according to what the claims tell you abut the user, and so on: all without the need of actually knowing what goes on under the hood. Life is good.
Let’s say that now you are asked to create a Silverlight application, let’s say in-browser for the sake of simplicity. You run the federation wizard on the hosting website, like you are used to for the web application case, and you obtain the usual redirect behavior to the identity provider. So far so good. However, when you go in the Silverlight code and you search for the claims, perhaps for deciding if a certain portion of the UI should enabled or disabled according to the user’s role, but they are nowhere to be found. What’s going on?
Identity-wise, a classic Silverlight application is kind of a strange animal. The application has its home on a web site, the one on which the XAP resides, but the UI is in fact executed within the browser process, back on the client machine. It’s like a cat sleeping on the web server, which unfolds a very long neck and pops up its cute face in the client’s browser when you navigate there.
In the case above, when you ask a token to the Identity Provider you are in fact asking it for the body of the cat, the web site. The code which drives the redirects, understand the token format, performs the various validations and so on all reside on the web server. In this case, the SilverLight code (the cat’s head) does not even see the token; and no token, no claims [noisily uncork a bottle of sparkly wine for reinforcing the point].
Let’s look at another example: you are writing a SL application for Windows Phone 7. In that case, the XAP file lives directly on the phone; there is no website to go to, no browser sandbox, no ws-federation redirect to ride. If you want a token, you have to get it via ws-trust. The entire cat is cuddled in the palm of your hand (real or virtual, if you are using the excellent emulator). In fact, this case is architecturally equivalent to ANY rich client case regardless of the technology used. The rich client application MAY have a set of associated web services, designed to work in synergy with the client (think Seesmic and the twitter backend); but in the generic case a rich client may have no concept of a single backend, performing something useful per se and occasionally integrating its functionalities with calls to external services from different owners (think Excel, which you can use for working with local files but that can occasionally reach out for external data sources, or even translation and thesaurus services).
In the full rich client case, if the services require authentication you may reach out to one or more IPs for obtaining suitable tokens. This time the application will contain (explicitly, via trustchannel, or implicitly, via bindings) the code for obtaining and using the token, but that won’t be of much help for gaining access to its claims. And even if you’d concoct some trick for chiming in the process, the IP may have encrypted the token using the certificate of the service, whose corresponding private key is available only on the web service machine. The identity-driven customizations you wanted to do in the UI still elude you.
One last example, perhaps not as intuitive as the two above. Let’s say that you run a web site, secured via WIF. In this case you do have access to the claims in the token used for authenticating & starting the session (the famous bootstrap token) hence you can use for customizing the UI at will. Let’s say that your application relies on a services backend, and that you did your due diligence and avoided a trusted subsystem: your frontend calls the backend by using an ActAs token, obtained by the frontend by sending the bootstrap token to an ActAs STS. Also, the bootstrap token may come from an external IP which knows nothing about your backed and the roles it needs/understands. Therefore the knowledge about if the current user can or cannot call a certain service is NOT available in the bootstrap token, which the frontend understands: it is hidden inside that ActAs token, which has been issued for the backend and that the frontend may be unable to read (see above). Did you want to hide or show the button on your page that triggers the call of the service, according to if the current user can or cannot call the service? That’s a valid concern, it steers the use toward the choices actually available, reduces UI clutter, prevents frustrating error messages which could be avoided, eliminates one of the use cases you’d instead need to add in the script of your call center people, and so on. Unfortunately, the content of the actas token is in general inaccessible to your frontend; and if it is, that means that you are relying on assumptions that could be broken in the future (ie if the service changes policy and seals the token, functionalities relying on the token being open will break with no obvious workarounds available) which is exactly the opposite of what you want to achieve using standards. Being able to hack something together once by working around the object model is not the strategic way of handling the issue.
In summary. There are good architectural reasons for which claims are currently not easily accessible from a client; at the same time, there are good reasons for which developers would like to have that access when developing rich clients, Silverlight apps, or even just handling a backend. This is something which clearly deserves attention.
Before we start musing about a solution, there are various issues with the idea of claims on a client which must be accounted for.
The first one is, the current flow is architecturally sound. The semantic of the RTS/RSTR is obtaining a token for the RP, for the purpose of complying with it policies and gaining access, and that’s precisely what happens. Following strictly the building blocks we use today, if the client wants a token, it should be an RP in its own right and ask a token for itself; of course this is all kind of circular, because in the cases above what you need is knowing what’s inside the token for the RP rather than getting a token for accessing itself; which in turn would change the semantic of the RST/RSTR, would require the IP to have an entry for the “client RP” and somehow tie it to the associated RP(s), and so on… all very messy. One could argue that a very common case would be for the client to need a “profile”, containing things about the user and the app itself rather than the user and the services the app calls, in which case a moral equivalent of the bootstrap token for the rich client app may be justified. I agree, but this would solve only part of the problem and just defer the solution for “can the user call this RP service?” issue. Hence, while acknowledging that this would be a sound path, i’ll pursue different angles.
The second one, but it should have been the first one, is that even if you have claims on the client you are NOT doing authorization. Thinking that hiding a button which would call a service is authorization is fooling oneself, as much as thinking that making the new of a web service proxy is actually newing one instance of the service somewhere.
What you can do at the UI level is customization, if you will: but it is NOT, and it cannot substitute, authorization at the resource (or token issuance) level. Think about it! Let’s say that own both the services and the frontend, and that you hide the buttons corresponding to the service methods your current user should not be able to call but you neglect to actually add suitable claimsauthorizationmanager policies on the services themselves. How long do you think it would take somebody to read the info that the services metadata so handsomely reveal about the service, build another client without silly restrictions and call methods as she/he please? Go ahead, hide the metadata after design time svcutil did its job; how long do you think it would take to open up the rich client code (which, once it lands on the client machine, has to be assumed disassemblable at will) and retrieve the info from there? Do yourself a favor and don’t call what you do (or will do) with claims on the client “authorization”; you have no control on the resource itself, and even if “you know what you mean” by saying that other people in the team may not and it’s easy to slip.
Third one. There is no guarantee that the client will understand the semantic of claims meant for the RP, or that the semantic is even stable in the first place. Unless you own both the rich client and the services it invokes (and you are willing to keep the two synchronized by hand over things that are not specified in a contract), or there are business agreements which strictly define how things will be used (ie “gold” access means access to certain services and since you are billed for it, you expect this to be as stable as the biz agreement it backs the terms or service), just knowing the claim values does not guarantee that the client will be able to predict the behavior of the RP. The beauty of claims is also that you can run sophisticated logic on them to drive the application behavior, but in the general case the RP has no obligation to share that logic with the client. Note, don’t confuse this with user control and consent: as I user I may have a right to know which claims I am sending and to whom, but how the RP will react to the claims is its decision. The rich client is very much in the same position.
I am sure that there are other caveats, but hopefully the ones above are enough to suggest caution as we proceed; this is not something that should be hacked together, and even once we obtained it it is not something to be used mindlessly.
OK, at his point it is probably clear that I think we need to be able to use claims on the client, albeit carefully. How to make that happen? Skipping the “client as an RP in its own right” solution, as mentioned above, I see two possible solutions: asking them to the RP and asking them to the IP. Let’s briefly explore both.
If you observe the RIA services templates, you’ll see that they do something for connecting the cat’s body to its head; their authorization services expose to the silverlight code information about the user known by the hosting web site. That’s an approach that the Silverlight labs in the training kit took as well; basically the RP exposes a method which tells to some infrastructure object on the client the list of claims, which are then packed in one IClaimsPrincipal.
This is a method which works very well in the classic silverlight case, where there is a “home” web site to refer to which is owned by the same owner of the UI code. This helps you to do a number of interesting things, for example embedding the service which reveals the claim values in the template of the application itself.
In the general case, however, I believe that this approach has a number of drawbacks. If the rich client app does not have its own “home” site, like in the SL on the phone and general rich client case, relying on the RP to tell you about the claims can be impractical and maybe even a bit dangerous.
Note, the above objections may be trumped by the convenience of the approach in the classic silverlight case; approach that could be generalized if one would assume the presence of a “profile” RP even if no "proper “home” site is available; however, my current preference goes toward the next approach.
If you followed the user centric identity movement in the last years, reading this post probably gave you some deja-vu moments. This is not the first time we encounter the issue of making claims available on the client: remember the much-debated Display Token? That was the artifact which allows CardSpace to inform the user about the claims values that are about to be sent to the RP, while keeping the actual token absolutely opaque (both in term of the format used and, optionally, cryptographically) to direct inquiries on the client side. In practice it is one extra “token” that the IP includes in the RSTR, readable by the client and containing the list of claims (or kind-of, see below).
The purposes for which the claim values are required differ in the two cases, for CardSpace it’s a matter of showing them to the user before actually sending them while in our case we want them for driving the UI of the application. However there is no technical reason for which the machinery in place for one case could not be used to tackle the other. In fact, I believe it would introduce various key advantages:
I understand why the RIA services would not have introduced such a model, for them the IP is implicit, but now that we are in the token trade I think that this should be the way to go.
Regardless of the method used for getting the claim values to the client, you’ll need to expose that information to the programmer (hopefully without leaking which method has been selected :-)). Here the issue is less obvious that it would appear at first glance.
IMO there’s no doubt that the claim values so obtained should be accessible via the IClaimsIdentity API: those are the API that developers are learning to use for obtaining info about the user, and breaking the consistency just because this is will often contain “a profile” does not seem very wise. It should be super-clear that those claims came from a displaytoken, though; probably picking a specific issuer (or modifying one issuer name accordingly) would do the trick.
I am much less clear about where that IClaimsPrincipal should live; putting it in the current thread, as in the web application & services case, does not sound very promising. On a rich client it kind of violates the semantic of Thread.CurrentPrincipal; in the case of a frontent calling a backend, it would have to coexist with the one extracted from the bootstrap token; finally, in all cases it should account for the possibilities of the application talking to multiple RPs all requiring different tokens.
At the same time, I think it is really important not to burden those developers who do not care about identity/security by exposing details which get in the way of the desired effect (customizing the UI with identity information). Hey, nobody said it would be easy! Simple for the developer rarely means simple for the object model designer as well… ;-)
They just announced we begun the descent to Paris: good, because I am running out of battery juice… once on the ground, while waiting for the Munich layover I’ll add few sketches and will post.
Again, don’t forget, those are just my ramblings. From the above you can probably tell that this problem has been bugging me for quite some time: thanks to the fact that WIF is now in the hands of the community, making the idea of claims no longer an abstract possibility but as concrete as it can get, I can finally expand on similar stuff without sounding too arcane :-)
I know that the engineering team is looking at the problem very thoroughly: if you want to share your thoughts on the above, I am sure they’ll be very happy of the feedback.