views:

787

answers:

4

I have a per-call WCF service that's being hosted in IIS (.svc). In the service's constructor, I set Thread.CurrentPrincipal = HttpContext.Current.User as per this article. In this case HttpContext.Current.User is of type Microsoft.IdentityModel.Claims.ClaimsPrincipal and has the claims that were sent back from my custom passive STS.

However, as soon as I step into my service operation and examine Thread.CurrentPrincipal, while this object is still of type Microsoft.IdentityModel.Claims.ClaimsIdentity, the object itself is no longer the same as HttpContext.Current.User (IsAuthenticated = false, AuthenticationType = "" and Name is null on Thread.CurrentPrincipal.Identity), whereas these values are all still filled in correctly on HttpContext.Current.User. This tells me that something is intercepting the call to the operation and incorrectly changing the current principal to some generic, empty, unauthenticated claims principal.

I checked the thread ID in the constructor as well as in the operation and it's the same in both places, and evaluating Thread.CurrentPrincipal in the immediate window after assigning from HttpContext.Current.User shows that the thread identity is being set correctly in the constructor, so something is definitely executing in between the constructor and the method, and that something is changing my Thread.CurrentPrincipal.

Does anybody have any idea what is doing this, and how I can go about preventing / fixing this behaviour?

A: 

My guess is that nothing is intercepting the call. Either the CurrentPrincipal is reset by the time you're examining it or you're in a different thread.

Check the CurrentPrincipal immediately after assigning to it and you should see the correct value.

Amnon
+1  A: 

When configuring a service for WIF federation, you call

FederatedServiceCredentials.ConfigureServiceHost(this);

Part of what this call does is to set up a custom ServiceAuthorizationManager of type IdentityModelServiceAuthorizationManager on the service host. This authorization manager appears to get called in between activation (construction) of the instance and execution of the operation, and it overwrites Thread.CurrentPrincipal with an instance of IClaimsPrincipal, but it doesn't seem to realize that it's running in ASP.NET Compatibility mode, so it doesn't pull the principal from HttpContext.Current.User.

I was able to bypass this behaviour by deriving from IdentityModelServiceAuthorizationManager and overriding the CheckAccess method as follows:

public class CustomAuthorizationManager : IdentityModelServiceAuthorizationManager
{
    public override bool CheckAccess(System.ServiceModel.OperationContext operationContext, ref System.ServiceModel.Channels.Message message)
    {
        var result = base.CheckAccess(operationContext, ref message);

        var properties = operationContext.ServiceSecurityContext.AuthorizationContext.Properties;
        properties["Principal"] = System.Web.HttpContext.Current.User;

        return result;
    }
}

This then gets applied to the service host as follows:

protected override void InitializeRuntime()
{
    FederatedServiceCredentials.ConfigureServiceHost(this);
    this.Authorization.ServiceAuthorizationManager = new CustomAuthorizationManager();
    base.InitializeRuntime();
}

And now when I enter my service operation, I have the correct IClaimsPrincipal on Thread.CurrentPrincipal, so declarative PrincipalPermission now works as expected.

Terence Lewis
This solution works, however I'm not sure whether there is a bug in the existing IdentityModelServiceAuthorizationManager - my feeling is that it should be able to tell that it's running in ASP.NET Compatibility mode and therefore should be able to pull the principal from HttpContext.Current.User automatically. Should I report this to Microsoft as a bug before they ship Microsoft.IdentityModel 1.0.0.0?
Terence Lewis
A: 

confguration settings for call FederatedServiceCredentials.ConfigureServiceHost(this);

is as below in system.serviceModel add following

<extensions>
      <behaviorExtensions>
        <add name="federatedServiceHostConfiguration" type="Microsoft.IdentityModel.Configuration.ConfigureServiceHostBehaviorExtensionElement, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
      </behaviorExtensions>
    </extensions>

under inside add folowing line

<behavior name="serviceBehavior">
          <federatedServiceHostConfiguration name="MyService" />
Ranjeet
A: 

Hi, I just ran into a similar problem. I set my custom principal in the constructor of my WCF service. When I left the constructor, and entered the method I called, the thread.currentprincipal was overridden by an empty one. I solved this by adding the following behavior:

<serviceAuthorization principalPermissionMode="None"></serviceAuthorization>

This worked fine for me.

pabes