开发者

Where is the best place to have custom Principal/Identity set?

I have been working on a web site (using ASP.NET C#) that uses both forms based and claims based authentication. I wanted to override the ClaimsIdentity class so I could implement a custom IsAuthenticated method and add more properties for the identity specific for the claims authentication.

I'm implementing a custom WSFederationAuthentionModule currently, but I was trying to figure out what module I should override (specifically what method) so I can set my custom identity/principa开发者_JS百科l rather than the default ClaimsPrincipal?

So far I have looked at both the SessionAuthenticationModule and ClaimsPrincipalHTTPModule, but I could not figure out at what step the principal is set/the best way to override it.

Thanks

Addition: Since I'm kind of new at this let me be sure this is correct: The way to set an identity is to set a custom principal which is set to use that identity:

System.Threading.Thread.CurrentPrincipal = customClaimsPrincipal;

Alternatively if a custom principal was not needed then the ClaimPrincipal class could be constructed with a ClaimsIdentityCollection.


There are several places you can do this, but if you are using the SessionAuthenticationModule, some of the process is not documented well which can make using a custom principal tricky. The rest of this answer explains one possible way to handle this when using the SessionAuthenticationModule.

Override the SessionAuthenticationModule.SetPrincipalFromSessionToken method.

The SessionAuthenticationModule stores the security token, principal, identities, and claims in a cookie and an in-memory cache to avoid having to make round-trips to the identity provider/token service on every request. What's not documented well is the existence of the cache and that it is the first place checked, then the cookie, and the limits on serializing the ClaimsPrincipal.

If you already set a custom principal in ClaimsAuthenticationManager.Authenticate and the cache is intact, your custom principal will most likely be there already since the cache stores native .NET objects. If you haven't yet set a custom principal, or the cache is not populated, then the security token will be retrieved from the FedAuth session cookie.

When the token is serialized/deserialized to/from the cookie, the process uses custom serialization that is only capable of reading and writing attributes of the IClaimsPrincipal and IClaimsIdentity interfaces (or the ClaimsPrinicpal and ClaimsIdentity classes - I can't remember which). Any custom principal and identity object attributes will not be included. It may be possible to override the serialization, but that requires several (3 IIRC) more layers of class overrides.

You'll also need to be aware of the fact that the base SetPrincipalFromSessionToken method creates a new ClaimsPrincipal object and sets it on the thread and context, so even if the sessionSecurityToken parameter contains a custom principal object, it will get translated back into a ClaimsPrincipal object.

Here's an example override method:

protected override void SetPrincipalFromSessionToken(SessionSecurityToken sessionSecurityToken)
{
    SessionSecurityToken newToken = MyClaimsPrincipalUtility.CreateCustomClaimsPrincipalToken(sessionSecurityToken);

    base.SetPrincipalFromSessionToken(newToken);

    //the following lines need to be set after the base method call, because the base method overwrites the Principal object
    HttpContext.Current.User = newToken.ClaimsPrincipal;
    Thread.CurrentPrincipal = newToken.ClaimsPrincipal;
}

The base class (SessionAuthenticationModule) implementation looks like the following. So there are a couple different ways you can achieve the overriding and getting the custom claims principal.

protected virtual void SetPrincipalFromSessionToken(SessionSecurityToken sessionSecurityToken)
{
    IClaimsPrincipal fromIdentities = ClaimsPrincipal.CreateFromIdentities(this.ValidateSessionToken(sessionSecurityToken));

    HttpContext.Current.User = (IPrincipal) fromIdentities;
    Thread.CurrentPrincipal = (IPrincipal) fromIdentities;

    //tracing code removed

    this.ContextSessionSecurityToken = sessionSecurityToken;
}

And just in case you're wondering, here's the base class implementation for SessionAuthenticationModule.ContextSessionSecurityToken.

public virtual SessionSecurityToken ContextSessionSecurityToken
{
    get
    {
        return (SessionSecurityToken) HttpContext.Current.Items[(object) typeof (SessionSecurityToken).AssemblyQualifiedName];
    }
    internal set
    {
        HttpContext.Current.Items[(object) typeof (SessionSecurityToken).AssemblyQualifiedName] = (object) value;
    }
}


You're correct in that HttpModules are the way to go in terms of extensibility, but make sure that whatever logic you implement doesn't inhibit the performance of your application. I've had websites go thoroughly berserk performance-wise after adding too many HttpModules to the application. It might be worth caching results of your queries, depending on what auth model you're using.

You need to figure out under what conditions you need to use your custom ClaimsPrincipal. Until you do this you're stabbing in the dark. Are there specific URLs for which you need claims authentication?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜