Advanced ASP.NET Programming for Windows Identity Foundation

  • 9/15/2010

Claims Processing at the RP

In this final section of the chapter, I cover some of the things you can do with claims at the last minute, when they are already in the RP pipeline and are about to hit the application code.

There is not a whole lot of coding required, especially considering that I already covered ClaimsAuthorizationManager in detail in Chapter 2. This section attempts to give you an idea of the intended usage of those extension points and inspire you to take advantage of them in your scenarios.

Authorization

Claims authorization is a fascinating subject that probably deserves an entire book of its own. One thing that puts off the various Role-Based Access Control (RBAC) aficionados is that there is so much freedom and so many ways of doing things. For example, take the coarse form of authorization that can be implemented by simply refusing to issue a token. You can set up rules at the IP that prevent from obtaining a token all the users that are already known not to be authorized to access the application they are asking for. That is feasible for all the situations in which the IP knows enough to make a decision—for example, in cases like Customer Relationship Management (CRM) online, in which users need to be explicitly invited before having access, even when there’s a federation in place.

Another obvious place for enforcing authorization is in the R-STS, which might deny tokens on the basis of some cross-organizational considerations. For example, the R-STS used by one independent software vendor (ISV) for managing access to its application portfolio might keep track of how many concurrent users are currently holding active sessions and refuse to issue a new token if that would exceed the number of licenses bought by the IP organization.

The enforcement point that is the closest to traditional authorization systems is the RP itself, which is where ClaimsAuthorizationManager is positioned. There are intrinsic advantages to enforcing authorization here. The resources are well known. For example, if the RP is a document management system, the life cycle of documents themselves is under the control of the RP, which can easily manage permissions as well; whereas others (such as the R-STS, or worse still, the IP) would need to be synchronized. Another advantage is the availability of the call itself, although that’s easier to see with Web services than with Web sites. If you want to authorize the user to make a purchase according to a spending-limit claim, you need both the claim value and the amount of the proposed purchase: one STS would only see the claim value, as the body of a call plays no part in RST/RSTR exchanges.

The absolute flexibility offered by ClaimsAuthorizationManager is both its greatest strength and biggest weakness. Claims-based authorization is really powerful, but at the time of this writing there are no out-of-the-box implementations of ClaimsAuthorizationManager or tools and official policy formats for it. You can do everything with it, but you are required to write your own code.

Authentication and Claims Processing

Sometimes it just makes sense to do some claims processing at the RP side. Perhaps you need to make available to the application code information about the user that is known to the RP but not to the R-STS, such as in the case of a user profile specific to the application. Or maybe there are claims you need to see only once, at the beginning of the session, but that you prefer not to make available to the application code.

For doing any of these things, WIF offers you a specific hook in the RP pipeline, which you can leverage by providing your own claims-manipulation logic wrapped in a custom ClaimsAuthenticationManager class. ClaimsAuthenticationManager works a lot like ClaimsAuthorizationManager: you provide your logic by overriding one method (here it’s Authenticate), and you add your class in the pipeline by adding in the WIF config the element <claimsAuthenticationManager type=“CustomClaimsAuthnMgr”/>.

In your implementation of Authenticate, you can do whatever you want with the principal, including deleting claims, adding claims, or even using a custom IClaimsPrincipal implementation. Here is a super-simple example of ClaimsAuthenticationManager:

public class CustomClaimsAuthnMgr: ClaimsAuthenticationManager
{
  public override IClaimsPrincipal Authenticate(string resourceName, IClaimsPrincipal
incomingPrincipal)
  {
 //If the identity is not authenticated yet, keep this principal and let it redirect to the
STS
    if (!incomingPrincipal.Identity.IsAuthenticated)
    {
      return incomingPrincipal;
    }
    ((IClaimsIdentity)incomingPrincipal.Identity).Claims.Add(
      new Claim(ClaimTypes.Country,"Saturn,"ClaimValueTypes.String,"LOCAL AUTHORITY"));
    return incomingPrincipal;
  }
}

In this case, the code simply adds an extra claim to the principal. Note that the issuer is assigned to “LOCAL AUTHORITY.” You can use pretty much anything you want here, but you should really avoid using an existing issuer identifier because it is equivalent to pretending to be a legitimate issuer.