Search code examples
asp.netowinidentityserver3owin-middleware

How to read ASP.NET Session on IdentityServer3? OWIN Pipeline Order is broken


Problem: I'm trying to use ASP.NET Session on IdentityServer3 Controllers, but I just can't make it work.

I found this similar question that explains how to enable session on OWIN middleware, and it worked perfectly: I created some controllers outside of IdentityServer (that is, outside of the pipeline Mapped in "/core") and it worked perfectly. I also added Autofac to my controllers to make sure that Autofac (used extensivly in IdentityServer) was not the problem, and it works fine.

This is working code - Startup.cs:

// register middleware that enables session using SetSessionStateBehavior(SessionStateBehavior.Required)
app.RequireAspNetSession(); 

var config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseWebApi(config);

var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<DummyClassCreatedByAutofac>();;
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

//app.UseIdentityServer(); // if I add IdentityServer, context.Session is always null

This works fine. The middleware (SetSessionStateBehavior) runs on every requisition, and the session is available on the constructor. However, as soon as I add app.UseIdentityServer() to my Startup.cs, IdentityServer starts working perfectly (and all requisitions pass through the session middleware) but now Session is null for all controllers - not only for IdentityServer controllers but also for my other controllers (which are outside of IdentityServer pipeline) - they stop working.

If I completely remove all my code and just stick with regular IdentityServer pipeline, I just can't find the correct place to add RequireAspNetSession() in the pipeline. I tried adding in many different places, but couldn't make it work.

After some trial-and-error, I realized that the session middleware RequireAspNetSession() was being broken by the following two calls: app.UseEmbeddedFileServer() and app.ConfigureCookieAuthentication. When both calls were removed, Session was available to IdentityServer controllers (and also were available again to my other controllers). Probably the problem is because some of those OWIN middlewares run on specific stages (using UseStageMarker and defining a PipelineStage), and probably I'm breaking the priority order of the middlewares. UseEmbeddedFileServer for example runs on stage PipelineStage.MapHandler, as well as RequireAspNetSession.

I tried adding app.RequireAspNetSession() both before and after those middlewares, but it didn't work either. In fact, app.RequireAspNetSession() never works when it is used inside Map() method, which is where those middlewares are configured (inside UseIdentityServer()):

app.Map("/core", coreApp =>
{
  // this DOESN'T work, even if I remove
  // UseEmbeddedFileServer() or ConfigureCookieAuthentication()
  coreApp.RequireAspNetSession(); 
  //...
  coreApp.UseIdentityServer(idsrvOptions); 
}

_

// this WORKS as long as inside the Map() I don't call 
// UseEmbeddedFileServer() or ConfigureCookieAuthentication() 
app.RequireAspNetSession(); 
app.Map("/core", coreApp =>
{
  //...
  coreApp.UseIdentityServer(idsrvOptions);
}

Last, if I don't use the Map method (and setup the IdentityServer API directly on root folder), it works fine (session is available to all controllers, even if I keep the UseEmbeddedFileServer() and ConfigureCookieAuthentication() middlewares). But it's not acceptable because I need to run APIs on a mapped folder.

In summary: If I use RequireAspNetSession() inside Map(), it doesn't work (session is always null). If I use RequireAspNetSession() outside Map() but keep the UseEmbeddedFileServer() or ConfigureCookieAuthentication() inside the Map(), it also doesn't work.

How to make the RequireAspNetSession() work in IdentityServer3 pipeline?

Also, how could Map("/core") affect (and broke) the pipeline for my DefaultController that is hosted outside of that pipeline?


Solution

  • It is not broken. It is by design. IdentityServer clears session on purpose.

    You have a couple alternatives.

    1) you can create a cookie helper
    2) the SignInMessage holds most of what you need -> Don't forget about LoginViewModel

    Once your user or application is signed in, session is under your control again.