asp.netowinthinktecture-ident-model

Missing owin context


I'm trying to use the ResourceAuthorize attribute from Thinktecture.IdentityModel, but everything stops because there is no owin context.

I have a owin startup class which setups the authorization manager

[assembly: OwinStartup(typeof(My.WebApi.Startup))]

namespace My.WebApi
{
    public class Startup
    {        
        public void Configuration(IAppBuilder app)
        {
            AuthConfig.Configure(app);
        }
    }
}

public class AuthConfig
{
    public static void Configure(IAppBuilder app)
    {         
        app.UseResourceAuthorization(new ResourceAuthorizationMiddlewareOptions
        {
            Manager = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IResourceAuthorizationManager)) as IResourceAuthorizationManager
        });
    }
}

and I know that it is detected and invoked. But later on, when hitting the following code from IdentityModel, I get a null pointer exception:

    public static Task<bool> CheckAccessAsync(this HttpRequestMessage request, IEnumerable<Claim> actions, IEnumerable<Claim> resources)
    {
        var authorizationContext = new ResourceAuthorizationContext(
            request.GetOwinContext().Authentication.User ?? Principal.Anonymous,
            actions,
            resources);

        return request.CheckAccessAsync(authorizationContext);
    }

I have stepped through and sees that it's caused by the GetOwinContext() returning null, since there is no MS_OwinContext or MS_OwinEnvironment property on the request.

What am I missing?

UPDATE:

I have found that i have an owin.environment property available, but it's part of the `HttpContextWrapper, not the request.

By searching around, I found some code inside of System.Web.Http.WebHost.HttpControllerHandler that looks like it should have converted the owin.environment to an MS_OwinEnvironment, but apparently, that code is never called in my case...

internal static readonly string OwinEnvironmentHttpContextKey = "owin.Environment";
internal static readonly string OwinEnvironmentKey = "MS_OwinEnvironment";

internal static HttpRequestMessage ConvertRequest(HttpContextBase httpContextBase, IHostBufferPolicySelector policySelector)
{
  HttpRequestBase requestBase = httpContextBase.Request;
  HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethodHelper.GetHttpMethod(requestBase.HttpMethod), requestBase.Url);
  bool bufferInput = policySelector == null || policySelector.UseBufferedInputStream((object) httpContextBase);
  httpRequestMessage.Content = HttpControllerHandler.GetStreamContent(requestBase, bufferInput);
  foreach (string str in (NameObjectCollectionBase) requestBase.Headers)
  {
    string[] values = requestBase.Headers.GetValues(str);
    HttpControllerHandler.AddHeaderToHttpRequestMessage(httpRequestMessage, str, values);
  }
  HttpRequestMessageExtensions.SetHttpContext(httpRequestMessage, httpContextBase);
  HttpRequestContext httpRequestContext = (HttpRequestContext) new WebHostHttpRequestContext(httpContextBase, requestBase, httpRequestMessage);
  System.Net.Http.HttpRequestMessageExtensions.SetRequestContext(httpRequestMessage, httpRequestContext);
  IDictionary items = httpContextBase.Items;
  if (items != null && items.Contains((object) HttpControllerHandler.OwinEnvironmentHttpContextKey))
    httpRequestMessage.Properties.Add(HttpControllerHandler.OwinEnvironmentKey, items[(object) HttpControllerHandler.OwinEnvironmentHttpContextKey]);
  httpRequestMessage.Properties.Add(HttpPropertyKeys.RetrieveClientCertificateDelegateKey, (object) HttpControllerHandler._retrieveClientCertificate);
  httpRequestMessage.Properties.Add(HttpPropertyKeys.IsLocalKey, (object) new Lazy<bool>((Func<bool>) (() => requestBase.IsLocal)));
  httpRequestMessage.Properties.Add(HttpPropertyKeys.IncludeErrorDetailKey, (object) new Lazy<bool>((Func<bool>) (() => !httpContextBase.IsCustomErrorEnabled)));
  return httpRequestMessage;
}

UPDATE 2:

Inside of mvc controllers, the context is available. But not in webapi controllers.


Solution

  • A team mate found a solution. He simply added the following line to the owin startup class:

    app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
    

    Why this solves the issue is another mystery, though. But we are using wsFederation, so I guess it's needed some how. But what if we didn't use wsFed? Would we still need it to get a context? Who knows...