Claims in Thread.CurrentPrincipal are getting lost which are set in AfterReceiveRequest in WCF

1.8k Views Asked by At

I am using Microsoft.IdentityModel.dll for Set & Get the claims in WCF. I have implemented MessageInspectors also for setting up the claims. So, I am adding ClaimsIdentity for request headers like below from client side.

public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
    var claims = new List<Claim> { new Claim(UserIdClaim, "12345"), };
    ClaimsIdentity claimsIdentity = new ClaimsIdentity(claims);
    MessageHeader<ClaimsIdentity> header = new MessageHeader<ClaimsIdentity>(claimsIdentity);
    var untypedHeader = header.GetUntypedHeader(ClaimsName, ClaimsNameSpace);
    request.Headers.Add(untypedHeader);

    return null;
}

And service side,

public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
    ClaimsIdentity claimsIdentity = request.Headers.GetHeader<ClaimsIdentity>(ClaimsName, ClaimsNameSpace);
    var claimsIdentitylst = new ClaimsIdentityCollection(new List<IClaimsIdentity> { claimsIdentity });
    IClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(claimsIdentitylst);
    Thread.CurrentPrincipal = claimsPrincipal;

    return null;
}

I am trying to access the claim values in method implementation(OperationContract) which are set in AfterReceiveRequest like below. But the claims are not available in Thread.CurrentPrincipal.

var userIdClaim = ((IClaimsIdentity)Thread.CurrentPrincipal.Identity).Claims.First(c => c.ClaimType == UserIdClaim);

userIdClaim is null here.

Any ideas?

3

There are 3 best solutions below

0
On

You might have good reasons to do this by hand, but passing of identity in wcf is handled out of the box with a wsFederationHttpBinding. You can find examples in the WIF SDK or online at http://msdn.microsoft.com/nl-be/library/aa355045.aspx .

1
On

Well - besides what you are doing is very uncommon practice - there is only one place in the WCF pipeline where you can safely set Thread.CurrentPrincipal. That's in a service authorization manager when PrincipalPermissionMode is set to Custom.

Typically you would rather pass the claims as part of a security token (like SAML) and let WCF do the server side plumbing for you.

0
On

Ran into this issue on a legacy WCF service when switching to https (oddly enough it didn't happen under http). Quick and dirty fix is to set the principalPermissionMode to None.

<system.serviceModel>
    <behaviors>
        <serviceBehaviors>
            <behavior>
                <serviceAuthorization principalPermissionMode="None" />
            </behavior>
        </serviceBehaviors>
    </behaviors>
</system.serviceModel>