Bug 17965 - Calling Thread.CurrentPrincipal blindly with the User from an HttpListenerContext can throw a NullReferenceException
Summary: Calling Thread.CurrentPrincipal blindly with the User from an HttpListenerCon...
Status: NEW
Alias: None
Product: Class Libraries
Classification: Mono
Component: System.Web (show other bugs)
Version: 3.2.x
Hardware: PC Windows
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2014-02-24 09:35 UTC by Arne Ruhnau
Modified: 2014-02-27 12:07 UTC (History)
1 user (show)

See Also:
Tags:
Is this bug a regression?: ---
Last known good build:


Attachments

Description Arne Ruhnau 2014-02-24 09:35:39 UTC
I'm currently looking into using OWIN to host a WebAPI based on the HttpListener.
I've installed various Nuget packages from the Microsoft.Owin - family:
<packages>
  <package id="Microsoft.AspNet.WebApi.Client" version="5.1.1" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.Core" version="5.1.1" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.Owin" version="5.1.1" targetFramework="net45" />
  <package id="Microsoft.Owin" version="3.0.0-alpha1" targetFramework="net45" />
  <package id="Microsoft.Owin.Host.HttpListener" version="3.0.0-alpha1" targetFramework="net45" />
  <package id="Microsoft.Owin.Hosting" version="3.0.0-alpha1" targetFramework="net45" />
  <package id="Microsoft.Owin.Security" version="3.0.0-alpha1" targetFramework="net45" />
  <package id="Owin" version="1.0" targetFramework="net45" />
</packages>
(other packages omitted)

When I register my webapi controller, the first request to it returns a 500, and all subsequent requests show

{"Message":"An error has occurred.","ExceptionMessage":"Object reference not set to an instance of an object","ExceptionType":"System.NullReferenceException","StackTrace":"  at System.Net.Http.DelegatingHandler.SendAsync (System.Net.Http.HttpRequestMessage request, CancellationToken cancellationToken) [0x00000] in C:\\cygwin\\sources\\mono\\mcs\\class\\System.Net.Http\\System.Net.Http\\DelegatingHandler.cs:64 \r\n  at System.Web.Http.HttpServer.<>n__FabricatedMethod9 (System.Net.Http.HttpRequestMessage , CancellationToken ) [0x00000] in <filename unknown>:0 \r\n  at System.Web.Http.HttpServer+<SendAsync>d__0.MoveNext () [0x00000] in <filename unknown>:0 "}

I tried to track the root cause down using mono --debug --trace=E:System.NullReferenceException

This shows, upon issueing the request targeting my controller class,

----- 8< ---------------
[00001138:] EXCEPTION handling: System.NullReferenceException: Object reference not set to an instance of an object

"Threadpool worker"  at System.Threading.Thread.SerializePrincipal (System.Threading.Thread,System.Security.Principal.IPrincipal) [0x00008] in C:\cygwin\sources\mono\mcs\class\corlib\System.Threading\
Thread.cs:223
  at System.Threading.Thread.set_CurrentPrincipal (System.Security.Principal.IPrincipal) [0x00029] in C:\cygwin\sources\mono\mcs\class\corlib\System.Threading\Thread.cs:292
  at Microsoft.Owin.Host.HttpListener.RequestProcessing.OwinHttpListenerContext.SetServerUser (System.Security.Principal.IPrincipal) <IL 0x0000d, 0x0003b>
  at Microsoft.Owin.Host.HttpListener.RequestProcessing.OwinHttpListenerContext..ctor (System.Net.HttpListenerContext,string,string,string,Microsoft.Owin.Host.HttpListener.DisconnectHandler) <IL 0x000
68, 0x00187>
  at Microsoft.Owin.Host.HttpListener.OwinHttpListener/<ProcessRequestAsync>d__5.MoveNext () <IL 0x00081, 0x0014b>
  at System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start<Microsoft.Owin.Host.HttpListener.OwinHttpListener/<ProcessRequestAsync>d__5> (Microsoft.Owin.Host.HttpListener.OwinHttpListener/<Proce
ssRequestAsync>d__5&) [0x0001b] in C:\cygwin\sources\mono\mcs\class\corlib\System.Runtime.CompilerServices\AsyncTaskMethodBuilder.cs:112
  at Microsoft.Owin.Host.HttpListener.OwinHttpListener.ProcessRequestAsync (System.Net.HttpListenerContext) <IL 0x00030, 0x00107>
  at Microsoft.Owin.Host.HttpListener.OwinHttpListener/<ProcessRequestsAsync>d__0.MoveNext () <IL 0x0017d, 0x003bb>
  at (wrapper unbox) Microsoft.Owin.Host.HttpListener.OwinHttpListener/<ProcessRequestsAsync>d__0.MoveNext () <IL 0x0000a, 0xffffffff>
  at System.Threading.Tasks.ActionContinuation.Execute () [0x00000] in C:\cygwin\sources\mono\mcs\class\corlib\System.Threading.Tasks\TaskContinuation.cs:124
  at System.Threading.Tasks.Task.ProcessCompleteDelegates () [0x00015] in C:\cygwin\sources\mono\mcs\class\corlib\System.Threading.Tasks\Task.cs:556
  at System.Threading.Tasks.Task.Finish () [0x000ce] in C:\cygwin\sources\mono\mcs\class\corlib\System.Threading.Tasks\Task.cs:539
  at System.Threading.Tasks.Task`1.TrySetResult (TResult) [0x00051] in C:\cygwin\sources\mono\mcs\class\corlib\System.Threading.Tasks\Task_T.cs:228
  at System.Threading.Tasks.TaskCompletionSource`1.TrySetResult (TResult) [0x00000] in C:\cygwin\sources\mono\mcs\class\corlib\System.Threading.Tasks\TaskCompletionSource.cs:121
  at System.Threading.Tasks.TaskCompletionSource`1.SetResult (TResult) [0x00000] in C:\cygwin\sources\mono\mcs\class\corlib\System.Threading.Tasks\TaskCompletionSource.cs:85
  at System.Threading.Tasks.TaskFactory`1.InnerInvoke (System.Threading.Tasks.TaskCompletionSource`1<TResult>,System.Func`2<System.IAsyncResult, TResult>,System.IAsyncResult) [0x00000] in C:\cygwin\so
urces\mono\mcs\class\corlib\System.Threading.Tasks\TaskFactory_T.cs:473
  at System.Threading.Tasks.TaskFactory`1/<FromAsyncBeginEnd>c__AnonStorey3E.<>m__32 (System.IAsyncResult) [0x00010] in C:\cygwin\sources\mono\mcs\class\corlib\System.Threading.Tasks\TaskFactory_T.cs:
345
  at System.Net.ListenerAsyncResult.InvokeCallback (object) [0x0001e] in C:\cygwin\sources\mono\mcs\class\System\System.Net\ListenerAsyncResult.cs:82
  at (wrapper runtime-invoke) <Module>.runtime_invoke_void__this___object (object,intptr,intptr,intptr) <IL 0x00052, 0xffffffff>
----- >8 ---------------

I looked through the source code of the packages involved in this call stack to find that:
- HttpListenerContext.User can be null, which is what's documented on MSDN as well, in case of authentication-less requests
- The OwinHttpListenerContext passes the HttpListenerContext.User to become the principal of the current thread
(https://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Host.HttpListener/RequestProcessing/OwinHttpListenerContext.cs)
- The System.Threading.Thread.CurrentPrincipal property passes this null into the SerializePrincipal function, where the .GetType() method invocation throws.
(https://github.com/mono/mono/blob/master/mcs/class/corlib/System.Threading/Thread.cs#L294 ff)

I let the same program run on the Microsoft CLR and it works correctly, so I assume this is bug of the Mono part of the equation.
Comment 1 Arne Ruhnau 2014-02-27 04:03:42 UTC
I can work around this specific issue by using a custom build of the Microsoft.Owin.Host.HttpListener project, using a 

new GenericPrincipal(new GenericIdentity(String.Empty), new string[0])

as the anonymous identity instead of null. I "stole" this from the System.Web.Http.HttpServer class in the aspnetwebstack.

Using WebAPI in the OWIN pipeline still throws a NullReferenceException in the SendAsync of the System.Net.Http.DelegatingHandler - for every request - , but this is another problem.

Note You need to log in before you can comment on or make changes to this bug.