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:
- Pull the authentication tokens (e.g. username/password) out of the incoming message
- 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.
- 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
- Retrieves the IPrincipal from the message (using the System.ServiceModel.EvaluationContext.Current.IncomingMessageProperties collection).
- Pushes the IPrincipal into the EvaluationContext.Properties collection
- 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"...
The Black Labrador
2010-10-01 13:43:37