none
Principal Mysteriously Swapped After CheckAccessCore RRS feed

  • Question

  • I have a ServiceAuthorizationManager.   If it sees an Authorization header it installs a custom principal onto the thread / operation context.  It mostly works.  See code below
        protected override bool CheckAccessCore(OperationContext operationContext)
        {
          var headers = WebOperationContext.Current.IncomingRequest.Headers;
          var properties = operationContext.ServiceSecurityContext.AuthorizationContext.Properties;
    
          if (! string.IsNullOrWhiteSpace(headers["Authorization"])) {
            Thread.CurrentPrincipal = new MyPrincipal(Thread.CurrentPrincipal, headers["Authorization"]);
          }
    
          properties["Principal"] = Thread.CurrentPrincipal;
          return true;
        }
    
    


    The principal simply wraps the existing principal and keeps a reference to the authorization string.   Note my real authorization manager does other "stuff",  but I dumbed it down to the smallest reproducible test case.   In any case,  once I get to my service code I check the Thread.CurrentPrincipal looking for MyPrincipal and compare the referenced authorization string against a parameter that is passed in on the request.   They should match.   If I have a single client, life is good.

    If I start a second client,  then things start to go wrong.  Occasionally, the authorization data (from the principal) doesn't match the parameter passed in on the same request.  When I say sometimes I mean maybe one in 10,0000.   But it gets better.  If I stand up the same API in the same server process on two different endpoints (I just replicated the service interface (and point at the same implementation)),   Then all hell breaks loose,  I get the wrong principal about 1 in every 20.

    When I get to my service,  I can break on the mismatch,  I can check the request and the principal on the operation context and it's just wrong.   The principal,  on both the Thread.CurrentPrincipal, and the AuhorizationContext.Properties["Principal"] are from some other request.

    I have done network traces to make sure it isn't the client.  I have seen the requests in the debugger.  they are correct.  I have add tracing to the authorization manager and have proved that the request and header match at that point,  and verified that the Thread.CurrentPrincipal and AuthorizationContext.Properties["Principal"] are set correctly at that point.   Everything matches when it leaves the authorization manager.   But somewhere between there and the method invocation,  the streams get crossed.   I really have almost no code,  and I want to say it is a bug in .NET/WCF.   Hopefully,  someone will come back and say "do you have <blah> turned on?" or set. or something. 

    It happens using the Visual Studio Development Server.  It happens using IIS Express.  I have not tried it with plain old IIS.   I have two VS 2010 .NET 4.0 projects for interested parties.   Any help is greatly appreciated.


    sjz
    Sunday, August 7, 2011 2:27 AM

All replies

  • I have gone a littler deeper into the rabbit hole.  I have come to the conclusion that

    operationContext.ServiceSecurityContext.AuthorizationContext.Properties

    is not specific to my thread/request.   That means one of two things.  A) I am putting my custom principal in the wrong place?,  or B) I am running in the wrong mode,  like I shoulud be running such that there is a new service instance for every request?  I am sure one of you has the answer.   Hopefully it is some form of A).

    _sjz.


    sjz

    Sunday, August 7, 2011 3:06 AM
  • Hello, it is recommended to use WIF to perform authorization. You can refer to http://msdn.microsoft.com/en-us/identitytrainingcourse_webservicesandidentitylab2010_topic2 for a tutorial.
    Lante, shanaolanxing This posting is provided "AS IS" with no warranties, and confers no rights.
    Windows Azure Technical Forum Support Team Blog
    Monday, August 8, 2011 3:46 AM
  • We are using WIF.   However, not everything WIF does is WSTrust.  It supports various token handlers,  authorization managers, protocol handlers, etc all of which we use.   Because that is more complicated I removed all the WIF and all the authorization to come up with the smallest piece of code that will reproduct the problem.   So let's forget about the the whole Thread.CurrentPrincipal thing.

    The root of the problem has nothing to do with WIF,  our use of WIF, or authorization at all.   The core of the matter is that when I am in my ServiceAuthorizationManager I have a request and a matching set of Properties in the operation context.   But then later when I land in my application code,  they no longer match.   More specifically,  the same AuthorizationContext is being shared across all threads.

    For instance,  I have request that has a single value in a header.  In the authorization manager I add a property with that value.   Then when I get to the web method,  I check the header against the value in the Properties.   Sometimes it doesn't match.

    More exciting is this.   The value I am sending is a monotonically increasing integer.   If in my authorization manager I add something like Properties["a"+myValue] = myValue,  the value is added and I always see it in my web method.  That is because it is unique, and there not overwritten by another thread.   Curiously,  from my webMethod I see every value ever placed in there across all threads across the life of the service.   That is I don't receive a new AuthorizationContext with my operation context on each call.   It is shared across all threads for all time.

    No amount of per call, per session, instancing seems to make a difference.


    sjz
    Monday, August 8, 2011 6:51 PM
  • I am also facing the same issue. do you have a solution for this.
    Monday, May 11, 2015 9:16 AM
  • Authorization is not the same as authentication. Authorization should just return true or false whether a principal should be used or not. The code you are mentioning should be implemented in ServiceAuthenticationManager.Authenticate method. This is a good example of this scenario:

    http://stackoverflow.com/questions/3715778/custom-wcf-authentication-with-system-servicemodel-serviceauthenticationmanager


    Monday, June 1, 2015 8:06 PM
  • >>> Thread.CurrentPrincipal = new MyPrincipal(Thread.CurrentPrincipal, headers["Authorization"]);

    Don't do this, let WCF set the principal for you. 

    Make sure principalPermissionMode == PrincipalPermissionMode.Custom. This instructs WCF to get the principal from SC.AuthorizationContext.Properties.


    Brent Schmaltz - MSFT

    Friday, July 17, 2015 7:37 PM