I have a problem with owin cokies. We have a site powered by ASP.net MVC 5. And authorization is by owin middleware. Sometimes users get a white screen with 500 error. I cant reproduce it at local but a couple of times i could reproduce this case at production. Exploring logs i discovered error "System.NullReferenceException: Object reference not set to an instance of an object." Stack:
System.NullReferenceException: Object reference not set to an instance of an object. at Microsoft.Owin.Security.DataHandler.Serializer.TicketSerializer.Write(BinaryWriter writer, AuthenticationTicket model) at Microsoft.Owin.Security.DataHandler.Serializer.TicketSerializer.Serialize(AuthenticationTicket model) at Microsoft.Owin.Security.DataHandler.SecureDataFormat
1.Protect(TData data) at Microsoft.Owin.Security.Cookies.CookieAuthenticationHandler.<ApplyResponseGrantAsync>d__f.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.Owin.Security.Infrastructure.AuthenticationHandler.<ApplyResponseCoreAsync>d__b.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.Owin.Security.Infrastructure.AuthenticationHandler.<ApplyResponseAsync>d__8.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.Owin.Security.Infrastructure.AuthenticationHandler.<TeardownAsync>d__5.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.Owin.Security.Infrastructure.AuthenticationMiddleware
1.d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNet.Identity.Owin.IdentityFactoryMiddleware2.<Invoke>d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNet.Identity.Owin.IdentityFactoryMiddleware
2.d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNet.Identity.Owin.IdentityFactoryMiddleware2.<Invoke>d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNet.Identity.Owin.IdentityFactoryMiddleware
2.d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContextStage.d__5.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContext.d__2.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContext.EndFinalWork(IAsyncResult ar) at System.Web.HttpApplication.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
A part of Startup.Auth:
app.CreatePerOwinContext(Entities.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
//owin иногда теряет куки авторизации в response, поэтому потом возникается nullreference error
//здесь вызывается специальная библиотека, которая сохраняет куки авторизации (создана для фикса бага овина)
app.UseKentorOwinCookieSaver();
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/newLogin"),
LogoutPath = new PathString("/logout"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = ctx =>
{
var ret = Task.Run(async () =>
{
Claim claim = null;
int userId = default(int);
User user = null;
try
{
claim = ctx.Identity.FindFirst("SecurityStamp");
if (claim == null) return;
var userManager = new ApplicationUserManager(DependencyResolver.Current.GetService<IUserStore<User, int>>());
userId = ctx.Identity.GetUserId<int>();
user = await userManager.FindByIdAsync(userId);
if (user != null && user.SecurityStamp != null && user.SecurityStamp != claim.Value)
{
var exc = new Exception("ConfigureAuth->OnValidateIdentity->Reject");
exc.Data.Add("claim", claim.Value);
exc.Data.Add("userId", userId);
exc.Data.Add("userStamp", user.SecurityStamp);
ErrorStore.LogException(exc, HttpContext.Current);
ctx.RejectIdentity();
}
}
catch (Exception ex)
{
var exc = new Exception("ConfigureAuth->OnValidateIdentity->catch", ex);
if (claim != null)
{
exc.Data.Add("claim", claim.Value);
}
exc.Data.Add("userId", userId);
if (user!=null)
{
exc.Data.Add("userStamp", user.SecurityStamp);
}
ErrorStore.LogException(exc, HttpContext.Current);
ctx.RejectIdentity();
return;
}
});
return ret;
},
OnApplyRedirect = ctx =>
{
if (!IsApiRequest(ctx.Request))
{
ctx.Response.Redirect(ctx.RedirectUri);
}
},
OnException = (context =>
{
ErrorStore.LogException(context.Exception, HttpContext.Current);
return;
})
}
});
When user gets white screen, he can write into url "logout" and he will be redirected to index page. (domain.me/ru/logout). Or if he clean his cookies he wiil be redirected to index page too.
I installed nuget package "Kentor.OwinCookieSaver" because of i thought owin didn't fixed the bug. But i think it was in vain because i have the latest version of OWIN:
Microsoft.AspNet.Identity.Owin: 2.2.1
Microsoft.Owin: 3.1.0
Microsoft.Owin.Security.OAuth: 3.1.0
Microsoft.Owin.Security.Cookies: 3.1.0
However Owin.Security.Providers is 1.27.0 version because of we dont need for many providers (only facebook and linkedin).
Its a legacy project, so im not deep into it.
I need some help. Thank you.