Making An Existing Application Claims-Aware
-
04 Juli 2012 8:19
Hi,
I'm a complete noob to Claims and have been working through various on-line resources to get my head around it but I'm still needing some (a lot of) help. I've been reading the "Microsoft Windows Identity Foundation (WIF) Whitepaper for developers" amongst others and doing examples in the "Identity Developer Training Kit".
My scenario is that I have a web application which calls a WCF authentication service which gives back a custom IPrincipal class. I am required to turn this into claims-aware web application which would be accessed by a single sign-on site. If my understanding is correct:
- The single sign-on site will request credentials, pass them to the STS.
- The STS will call my WCF authentication service to get an IClaimsIdentity
- The STS will return to the single sign-on site an IClaimsPrincipal containing my IClaimsIdentity (and maybe others)
- The single sign-on site will call my claims-aware web application, passing the IClaimsPrincipal.
- My web application will get the IClaimsPrincipal, determine which of the Identities is relevant and off we go.
Is that right so far?
The information that I get back from the authentication service contains the user's name and a list of things he can do. I can see that these map to "Claims of ClaimTypes.Name" and "ClaimTypes.Role". It also contains other attributes which I can’t see an obvious ClaimType for – for example a list of shops which the user can access.
Just to complicate matters, in my architecture a user might have access to multiple instances of my application / WCF authentication service. Therefore the IClaimsPrincipal could have two different Identities which are similarly structured but for different instances of the web application.
So some questions:
- How do I identify which of the Identities is relevant to one web application? Should I be adding a Claim identifying the authentication service - if so which ClaimType.
- What ClaimTypes should I use for my other attributes.
Thanks,
John.
p.s. Sorry for the long question!
Semua Balasan
-
04 Juli 2012 17:19
Overall I think your logic is correct for the basic flow.
More often than not working with multiple identities is a pain, so it may be wiser to simply return a single identity and when the user accesses the second shop reauth them with the new identity. In theory this shouldn't have any noticeable affect for the customer as the STS would already contain their session and it would just do the SSO thing.
Another way may be to have a known relationship between the two identities and make one into the Actor. That infers that one of the identities is impersonating the other identity though. If that doesn't work, then your way would work too.
As for the second question, you are welcome and encouraged to create your own claim types since they are application and domain-specific.
Developer Security MVP | www.syfuhs.net
- Ditandai sebagai Jawaban oleh John T. Angle 06 Juli 2012 8:32
-
05 Juli 2012 11:25
Thanks Steve.
More often than not working with multiple identities is a pain,
Yes. I have seen one example where it has caused me a problem using the PrincipalPermissionAttribute. I had two identities; one with a role = "Admin" and the other not. The latter was the relevant identity, but the IClaimsPrincipal.IsInRole("Admin") returned true.
[PrincipalPermission(SecurityAction.Demand, Authenticated = true, Role = "Admin")] public void Index() { ... }More often than not working with multiple identities is a pain, so it may be wiser to simply return a single identity and when the user accesses the second shop reauth them with the new identity. In theory this shouldn't have any noticeable affect for the customer as the STS would already contain their session and it would just do the SSO thing.
In otherwords each time I switch application I would drop the previous identity and load the new one. Yes, I could see that working and would stop each application seeing information from other identities.
It does seem to contradict the principle of ClaimsPrincipal having multiple federated identities though.
Another way may be to have a known relationship between the two identities and make one into the Actor. That infers that one of the identities is impersonating the other identity though. If that doesn't work, then your way would work too.
I'm not really sure what this means but I don't think it's viable for my scenario. I'll try to exemplify it.
We provide an application which looks at product and sales information for the retail industry.
A retail corporation has two chains of shops "Reds" and "Blues". There are two instances of the web application; one for Reds and another for Blues. When I log into one of the applications, I select a specific shop. So I might log into the Reds application and choose the Stratford shop to see its product and sales information.
In the Reds application, I am a Manager and can look at all Reds' shops.
In the Blues application, I am an Assistant but can only look at one shop.
<><><><><><><><><><><><>
From what I've understood so far my single sign-on could yield a ClaimsPrincipal like this:
ClaimsPrincipal principal = new ClaimsPrincipal(); ClaimsIdentity redsIdentity = new ClaimsIdentity(); ClaimsIdentity bluesIdentity = new ClaimsIdentity(); redsIdentity.Label = "Reds Ltd."; redsIdentity.Claims.Add( new Claim(ClaimTypes.Name, "John"); redsIdentity.Claims.Add( new Claim(ClaimTypes.Role, "Manager"); redsIdentity.Claims.Add( new Claim(CustomClaimType.Shop, "Stratford"); redsIdentity.Claims.Add( new Claim(CustomClaimType.Shop, "Santa Rosa"); redsIdentity.Claims.Add( new Claim(CustomClaimType.Shop, "Winslow"); // and all the other sites. bluesIdentity.Label = "Blues Inc."; bluesIdentity.Claims.Add( new Claim(ClaimTypes.Name, "JohnTAngle"); bluesIdentity.Claims.Add( new Claim(ClaimTypes.Role, "Assistant"); bluesIdentity.Claims.Add( new Claim(CustomClaimType.Shop, "Pittenweem"); principal.Identities.Add(redsIdentity); principal.Identities.Add(bluesIdentity);Then when I navigate to the Reds web application I can do this.
ClaimsPrincipal principal = Thread.CurrentPrincipal as ClaimsPrincipal; IClaimsIdentity relevantIdentity = principal.Identities.Single(p => p.Label == "Reds Ltd."); List<string> shops = relevantIdentity.Claims.Where(c => c.ClaimType = CustomClaimType.Shop).Select(c => c.Value).ToList();
Thanks,
John.
- Diedit oleh John T. Angle 05 Juli 2012 12:16 Clarify response.
-
05 Juli 2012 16:37
I think in this case your best option is to just reauth for each application, otherwise you will be rewriting a lot of the boilerplate code already in ASP.NET.
Developer Security MVP | www.syfuhs.net
- Ditandai sebagai Jawaban oleh John T. Angle 06 Juli 2012 8:32