none
When and where to set custom IIdentity when implementing custom authentication

    Question

  • Hi -

    If custom user name/password authentication is being implemented, where is it possible/recommended to set the "PrincipalIdentity" to a custom IIdentity object?

    So far I have custom implementations of ServiceCredentials, UserNameSecurityTokenAuthenticator, UserNameSecurityToken and IAuthorizationPolicy all hooked in and working nicely to verify user credentials against a custom store. I am looking to attach a custom principal object following the example in this thread. However, the object obtained from EvaluationContext.Properties["PrimaryIdentity"] when IAuthorizationPolicy.Evaluate gets called is a GenericIdentity. Where should I (can I?) set this to a custom identity.

    Thanks,

    Frank

    Friday, December 02, 2005 5:07 PM

Answers

  •  Frank Buckley wrote:
    Inheriting directly from SecurityToken and overriding AuthorizationPolicies { get; } looks like it would give me the opportunity to create a custom ClaimSet that could hold on to the extra information.


    Actually, I was trying to suggest that you just stick the data into a private member variable... Something like this;

    class MyToken: SecurityToken
    {
       private MyData d;

       ... ValidateCore ( ... )
       { 
          ...
          d = new MyData ( ... )
          ...
       }

       ... AuthorizationPolicies
       {
          ap = new MyAuthPolicy ( d );
        }
    }

    Does that make sense?

    Gudge
    Monday, December 05, 2005 5:29 PM

All replies

  • You should set it in IAuthorizationPolicy.Evaluate. The property you need to set is "Principal", not "PrimaryIdentity". I typically create a custom IPrincipal implementation and pass the IIdentity to it in the constructor. Here is an example;

    // Extract PrimaryIdentity
    object pi = null;
    if (ec.Properties.TryGetValue("PrimaryIdentity", out pi))
    {
      // Primary identity property could be a Claim or an IIdentity, we need to figure out which
      // Try to cast pi to a Claim
      Claim c = pi as Claim;
      IIdentity i = null;

      // If pi is a Claim...
      if (c != null)
      {
        // see if Claim.Resource is an IIdentity. Could also check that ClaimType is Identity too...
        i = c.Resource as IIdentity;
      }
      else // If pi is NOT a Claim, then try to case it to an IIdentity directly
       
    i = pi as IIdentity;

      // If we either got an IIdentity out of a claim, or directly from PrimaryIdentity...
      if (i != null)
      {
       
    // Create an IPrincipal implementation, passing in the IIdentity
       
    ec.Properties["Principal"] = new ClientPrincipal(i);
       
    // Add a custom claim to the evaluation context
       
    ec.AddToTarget(this, new DefaultClaimSet(new Claim("http://schemas.microsoft.com/gudge.demos.security.accesscontrol/", "You're in!!", "http://schemas.microsoft.com/xsi/2005/05/right/possessproperty")));
        bRet = true;
      }
    }

    And here's the ClientPrincipal class:


    class
    ClientPrincipal : IPrincipal
    {
     
    // member variables
     
    IIdentity id;

     
    // Constructors
     
    public ClientPrincipal(IIdentity i)
      {
       
    id = i;
     
    }

     
    public IIdentity Identity { get { return id; }}
     
    public bool IsInRole(string role)
     
    {
        
    // Do the role check here
     
    }
    }

    Does that help at all?

    Gudge

    Sunday, December 04, 2005 7:24 PM
  • Yes, sort of. I was looking to create an AppUserIdentity instance in ValidateCore() on an AppUserNameSecurityToken implementation, expose it as a property of the token (looking at UserNameWindowsSecurityToken for inspiration) and then pick it up again from somewhere (though I could not see where).

    The issue is that the validation done in SecurityToken.ValidateCore may involve wandering off to a database. I therefore wanted to pick up some other data at this point to avoid additional trips to the DB. Is there a recommended way to flow data to IAuthorizationPolicy.Evaluate where I can attach it to the custom Principal object? (I cannot see a way to get to the EvaluationContext from SecurityToken.ValidateCore).

    Many thanks.

    Sunday, December 04, 2005 8:45 PM
  • I've not investigated this in detail but could you store the information you collect in SecurityToken.ValidateCore in the AppUserNameSecurityToken class and then pass it into the IAuthorizationPolicy implementation when you construct it inside AppUserNameSecurityToken.AuthorizationPolicies?

    Gudge

    Monday, December 05, 2005 1:51 AM
  • Trying to iterate through AuthorizationPolicies from within ValidateCore() results in an InvalidOperationException ("The security token needs to be first validated") - I'm inheriting from UserNameSecurityToken and this overrides the property getter and throws if not validated.

    Inheriting directly from SecurityToken and overriding AuthorizationPolicies { get; } looks like it would give me the opportunity to create a custom ClaimSet that could hold on to the extra information.

    Internally, it appears that System.ServiceModel.Security.Tokens.GenericClaimSet offers this by keeping a reference to the SecurityToken hanging around. If this was not internal, I could get a reference to the SecurityToken by simply looking at the ClaimSet carried in the EvaluationContext to IAuthorizationPolicy.Evaluate. Any chance of making GenericClaimSet public?
    Monday, December 05, 2005 11:38 AM
  • Inheriting directly from SecurityToken and overriding AuthorizationPolicies { get; } does appear to give some options - additional information can be pushed into a ClaimSet implementation, along with the identity claims, (and on into a (say) MyIdentityAuthorizationPolicy instance) here. That MyIdentityAuthorizationPolicy instance can then add the ClaimSet implementation to the EvaluationContext's TargetClaims so MyPrincipalAuthorizationPolicy set up by <serviceAuthorization principalPermissionMode="Custom">... gets to see the additional claim data when its Evaluate() is called.

    Seems to work OK and do end up with my custom principal in Thread.CurrentPrincipal and a custom identity in ServiceSecurityContext.PrimaryIdentity and my custom claims all ready for my OperationRequirements with only one trip to the database. It does seems like quite a lot of work (and lots of scope for things to go wrong) just to hook into a custom user data store if you won't adopt a MembershipProvider/RoleProvider implementation. I suppose it will now be quite easy to implement credentials other that username/password against the same store.

    So next question: What happens with security sessions - how do (do?) my custom principal/identity objects get reconsituted in subsequent calls during the same session?

    Thanks.

    Monday, December 05, 2005 2:28 PM
  •  Frank Buckley wrote:
    Inheriting directly from SecurityToken and overriding AuthorizationPolicies { get; } looks like it would give me the opportunity to create a custom ClaimSet that could hold on to the extra information.


    Actually, I was trying to suggest that you just stick the data into a private member variable... Something like this;

    class MyToken: SecurityToken
    {
       private MyData d;

       ... ValidateCore ( ... )
       { 
          ...
          d = new MyData ( ... )
          ...
       }

       ... AuthorizationPolicies
       {
          ap = new MyAuthPolicy ( d );
        }
    }

    Does that make sense?

    Gudge
    Monday, December 05, 2005 5:29 PM
  •  Frank Buckley wrote:
    So next question: What happens with security sessions - how do (do?) my custom principal/identity objects get reconsituted in subsequent calls during the same session?

    Are you asking because it's NOT working? Or are you just curious as to what the expected behaviour is?

    Net, we associate the SecurityContextToken with the credentials (and claims) used to set up that SecurityContextToken. So the claims/credentials should be the same for subsequent messages in the session.

    Are you seeing something different to this?

    Gudge
    Monday, December 05, 2005 5:33 PM
  •  Gudge wrote:


    Are you asking because it's NOT working? Or are you just curious as to what the expected behaviour is?



    Curious. Having tested, it seems to work fine.
    Monday, December 05, 2005 10:38 PM
  •  Gudge wrote:

    Actually, I was trying to suggest that you just stick the data into a private member variable... Something like ...

    Does that make sense?


    Yes. Thanks.
    Monday, December 05, 2005 10:40 PM