WCF has an extensibility point to set your own IPrincipal implementation on Thread.CurrentPrincipal (I wrote about that here). Geneva uses this mechanism to set its IClaimsPrincipal (wrote about that here).
Since the standard “slot” for custom principals is already used by Geneva, it was unclear to me how to set your own IPrincipal after Geneva has done its work. With a little help from the Geneva team (thanks Jan) – I found a way that works.
You can replace the principal in a service authorization manager via the Properties collection on the authorization context. Voodoo.
class AuthorizationManager : IdentityModelServiceAuthorizationManager
{
public override bool CheckAccess(OperationContext operationContext, ref Message message)
{
base.CheckAccess(operationContext, ref message);
// action header to get to the request operation
string action = operationContext.IncomingMessageHeaders.Action;
// properties collection holds the principal that goes on Thread.CurrentPrincipal
var properties = operationContext
.ServiceSecurityContext
.AuthorizationContext
.Properties;
// retrieve current principal
IClaimsPrincipal principal = properties[“Principal”] as IClaimsPrincipal;
// create custom principal
var customPrincipal = new CustomClaimsPrincipal(principal, “some value”);
// set the custom principal
properties[“Principal”] = customPrincipal;
return Authorize(action, customPrincipal);
}
private bool Authorize(string action, CustomClaimsPrincipal principal)
{
// do whatever authZ logic you have
return true;
}
}
public class CustomClaimsPrincipal : ClaimsPrincipal
{
public CustomClaimsPrincipal(IClaimsPrincipal principal, string customValue)
: base(principal)
{
CustomPropery = customValue;
}
public string CustomPropery { get; set; }
}
Afterwards register this class in the ServiceAuthorizationBehavior.
Be aware that this gets called on every request – so don’t put expensive operations in the custom principal creation code.