Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom WCF authentication with System.ServiceModel.ServiceAuthenticationManager?

I'm working on custom WCF authentication and authorization and found some articles about UserNamePasswordValidator and ServiceAuthorizationManager.

I also found clues about using a custom System.ServiceModel.ServiceAuthenticationManager (dead link ), but msdn does not tell a lot about it ( http://msdn.microsoft.com/en-us/library/system.servicemodel.serviceauthenticationmanager.aspx ).

So here I am: anyone knows more about ServiceAuthenticationManager ?

In general, how would you set up custom WCF authentication ?

like image 564
fredlegrain Avatar asked Sep 15 '10 08:09

fredlegrain


1 Answers

You're right, the documentation on this is no help at all.

The way I have used this class is as follows. Override the Authenticate() method to:

  1. Pull the authentication tokens (e.g. username/password) out of the incoming message
  2. Authenticate the tokens and use them to create an IPrincipal object. This will be the principal that is used during the invocation of the service operation.
  3. Add the IPrincipal object to the message.Properties collection so it can be used later in the WCF processing pipeline

You can't just set the thread principal at this point as it is changed later on by WCF.

The code in the ServiceAuthenticationManager.Authenticate() methods would look something like this:

public override ReadOnlyCollection<IAuthorizationPolicy> Authenticate(ReadOnlyCollection<IAuthorizationPolicy> authPolicy, Uri listenUri, ref Message message)
{
   int tokenPosition = message.Headers.FindHeader("Token", "http://customnamespace.org");
   string token = message.Headers.GetHeader<string>(tokenPosition);

   IPrincipal user = new CustomPrincipal(token);

   message.Properties["Principal"] = user;

   return authPolicy;
}

Then you add a custom authorization policy that

  1. Retrieves the IPrincipal from the message (using the System.ServiceModel.EvaluationContext.Current.IncomingMessageProperties collection).
  2. Pushes the IPrincipal into the EvaluationContext.Properties collection
  3. Makes claims based on the IPrincipal.IsInRole() method

The code in the IAuthorizationPolicy() method would look like

public bool Evaluate(EvaluationContext evaluationContext, ref object state)
{
    IPrincipal user = OperationContext.Current.IncomingMessageProperties["Principal"] as IPrincipal;
    evaluationContext.Properties["Principal"] = user;
    evaluationContext.Properties["Identities"] = new List<IIdentity> { user.Identity };

    IList<Claim> roleClaims = this.GetRoleClaims(user);

    evaluationContext.AddClaimSet(this, new DefaultClaimSet(this.Issuer, roleClaims));

    return true;
}

In the service behaviour configuration, you need to set principalPermissionMode="Custom" in order for WCF to set the IPrincipal as the principal on the executing thread for the actual service operation invocation.

<serviceAuthorization principalPermissionMode="Custom"...
like image 171
Mike Goodwin Avatar answered Oct 08 '22 01:10

Mike Goodwin