Problem using custom principal and identity with W

2019-03-22 05:20发布

问题:

We are using a custom principal and identity type (ProdigyPrincipal/ProdigyIdentity) because we need extra information within our programs and services. In the program we set the principal and identity. When communicating with a WCF service the principal and identity are set, but after casting to our own type the principal and identity are null.

I noticed that there is a difference between running in Debug mode and Unit Test mode. In Debug mode the type of the principal and identity are of type WindowsPrincipal and WindowsIdentity. In Unit Test mode the types are GenericPrincipal and GenericIdenity. In both situations when casting to the custom type the value is null.

Setting and getting of the principal/identity is done through Thread.CurrentPrincipal. In the App.configs in the binding section the security mode is set to 'Transport‘.

Used function for settings/getting the principal and identity:

  protected static bool SetProdigyPrincipal()
  {
     #region require Thread.CurrentPrincipal should not be null

     if (Thread.CurrentPrincipal == null) // OK
     {
        throw new InvalidOperationException("SetProdigyPrincipal(): Thread.CurrentPrincipal should not be null");
     }

     #endregion require Thread.CurrentPrincipal should not be null

     var prodigyPrincipal = Thread.CurrentPrincipal as ProdigyPrincipal;

     #region require prodigyPrincipal should not be null

     if (prodigyPrincipal == null) // NOT OK
     {
        throw new InvalidOperationException("SetProdigyPrincipal(): prodigyPrincipal should not be null");
     }

     #endregion require prodigyPrincipal should not be null

     // Get the Windows identity from the current principal
     var prodigyIdentity = Thread.CurrentPrincipal.Identity as ProdigyIdentity;

     #region require windowsIdentity should not be null

     if (prodigyIdentity == null) // NOT OK
     {
        throw new InvalidOperationException("SetProdigyPrincipal(): prodigyIdentity should not be null");
     }

     #endregion require windowsIdentity should not be null

     // Create new instance of Prodigy principal
     var newProdigyPrincipal = new ProdigyPrincipal(prodigyIdentity);

     #region require prodigyPrincipal should not be null

     if (prodigyPrincipal == null)
     {
        throw new InvalidOperationException("SetProdigyPrincipal(): prodigyPrincipal should not be null");
     }

     #endregion require prodigyPrincipal should not be null

     // Set the prodigy principal
     var principalIsSet = ProdigyPrincipal.SetCurrentPrincipal(newProdigyPrincipal, ProdigyService.EnterpriseServiceBus);

     // Return principal is set status
     return principalIsSet;
  }

Does anyone know why the custom principal and identity type can not be retrieved from Thread?

Kind regard, Hans

回答1:

WCF has a more standard way of achieving the same goal, via a ServiceAuthorizationBehavior.

If you set its PrincipalPermissionMode property to "Custom", it allows you to provide a custom IAuthorizationPolicy via which you can make a custom IPrincipal available to the WCF ServiceSecurityContext. The DispatchRuntime will assign this (your custom) IPrincipal to Thread.CurrentPrincipal - which is what you're after, right?

This is a sample IAuthorizationPolicy implementation:

public class DemoAuthorizationPolicy : IAuthorizationPolicy
{
    private readonly string id = Guid.NewGuid().ToString();

    public string Id { get { return this.id; } }

    public ClaimSet Issuer { get { return ClaimSet.System; } }

    public bool Evaluate(EvaluationContext context, ref object state)
    {
        // Here, create your custom principal
        IIdentity customIdentity = new GenericIdentity("myUserName", "myCustomAuthenticationType");
        IPrincipal customPrincipal = new GenericPrincipal(customIdentity, new[] { "user", "powerUser" });

        // Set EvaluationContext properties
        context.Properties["Identities"] = new List<IIdentity> { customIdentity };
        context.Properties["Principal"] = customPrincipal;

        return true;
    }
}

And this is how you declare the ServiceAuthorizationBehavior in the Web.config:

  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceAuthorization principalPermissionMode="Custom" >
            <authorizationPolicies>
              <add policyType="PrincipalPermissionModeDemo.DemoAuthorizationPolicy, YourAssemblyName"/>
            </authorizationPolicies>
          </serviceAuthorization>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

Inside your service you can then leverage declarative security via the [PrincipalPermission] attribute, you can get the custom IPrincipal from Thread.CurrentPrincipal, and (alternatively) you can also get the custom IIdentity from ServiceSecurityContext.Current.PrimaryIdentity.

Hope that solves your issue!