06 October 2011
In this post I provided a description of the active federation authentication pattern and shared how to implement it with RIA Services. In this post I will show how to do the same but use a regular WCF service instead of a RIA Services DomainService. I am including the diagram from my last post, with some minimal modifications here.
I should clarify why I am putting the word active in quotation marks. The following will only make sense if you understand the difference between passive and active federation, which is outlined in the post linked above. In the passive federation case, the user never enters their credentials in the client app; they are redirected to the STS of the identity provider organization. This way the user is providing their credentials directly to the party they trust, and not to the app, which they may not trust. In the active federation case, they actually provide their credentials to the client app, and trust that the app will not be malicious, and will simply forward those credentials to the STS of the identity provider. The client app is responsible for creating a secure login UI, and also for securely transmitting the credentials to the STS. That is a lot of responsibility, and in traditional active federation scenarios, the client app uses strong encryption to guarantee the secure transfer of credentials. Still, lots of users may be reluctant to type in their credentials into a client app they don’t trust.
In this example I show how to do the active federation flow, and my client app does collect the credentials. I have hand-rolled my login UI, and cannot make any guarantees as to how secure it actually is. For the communication with the server, I simply use HTTPS, instead of more comprehensive message-level security. So my example reaps the convenience of the active flow (no need to redirect the user to a different page, login happens in-app), however may not provide the traditional security guarantees associated with it. Hence “active”.
What I provide here may be perfectly secure for many scenarios but is up to you, the developer, to assess if this particular setup satisfies the requirements of your users and your organization.
Now some specifics of the sample. It’s a simple app that can draw squares on the screen according to a Fibonacci tiling. There are two registered users: fabrikam\yavor and fabrikam\test and the password for both of them is 12345. Both can log into the app, however only the fabrikam\yavor user is in the role Calculators, meaning people who can carry out calculations on the service. This is enforced by the following attribute on the service’s GetSequence method.
[PrincipalPermission(SecurityAction.Demand, Authenticated = true, Role = "Calculators")] public int GetSequence(int max)
The bottom line here is that even though we have a STS with external user authentication, we kept authorization local to our app (we use ASP.NET roles). That’s a choice you can make as a developer - you can also externalize the user roles (or claims) as part of the STS, or keep them local.
There are lots of extra details in the app, which you’ll see by exploring the source.
The code is available here. The solution should be fairly self-contained, so all you need to run it is Visual Studio 2010 and the Windows Identity Foundation Runtime. Here are some additional notes on the structure of the sample:
I want to credit the folks behind the Identity Developer Training Kit, from where I shamelessly stole some code.