Description
When implementing a ClaimsTransformation that attempts to access HttpContext.Session, an error "Session has not been configured for this application or request." is raised by Kestrel. This is related to #3805 and this code appears to be the culprit as it invokes authentication middleware before UseSession is called in the Startup.Configure method. I can find no way to check if Session has been been configured without a try/catch block.
To Reproduce
- Using IIS 10 and ASP.Net Core 2.2. App must be configured to run Out-of-process for this issue to occur.
- I have created a repo @ https://github.com/fractionalJoe/TestIisIntegration that has a skeleton project that can be deployed to IIS to demonstrate the issue. It seemed like too much code to paste inline since it was multiple files.
- I enable stdout to get the following message.
Hosting environment: Production
Content root path: C:\Users\*****\source\TestIisIntegration\bin\Release\netcoreapp2.2\win-x64\publish
Now listening on: http://127.0.0.1:5781
Application started. Press Ctrl+C to shut down.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost/
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Route matched with {action = "Index", controller = "Home"}. Executing action TestIisIntegration.Controllers.HomeController.Index (TestIisIntegration)
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
Authorization failed.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
info: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
Executing ChallengeResult with authentication schemes ().
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action TestIisIntegration.Controllers.HomeController.Index (TestIisIntegration) in 43.0389ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 401.6257ms 401
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost/
fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "*************", Request id "*************:00000002": An unhandled exception was thrown by the application.
System.InvalidOperationException: Session has not been configured for this application or request.
at Microsoft.AspNetCore.Http.DefaultHttpContext.get_Session()
at TestIisIntegration.ClaimsTransformation.TransformAsync(ClaimsPrincipal principal) in C:\Users\erhma5\source\TestIisIntegration\ClaimsTransformation.cs:line 25
at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
at Microsoft.AspNetCore.Server.IISIntegration.IISMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 35.5237ms 500
Expected behavior
Expected behavior is that HttpContext.Session
should return null
if Session is not available. Or at least there should be a HttpContext.SessionConfigured
bool that can safely check. This ClaimsTransformation will be hit constantly and an exception being thrown, caught, and ignored is unnecessary overhead, not to mention messy.
.Net Info
.NET Core SDK (reflecting any global.json):
Version: 2.2.101
Commit: 236713b0b7
Runtime Environment:
OS Name: Windows
OS Version: 10.0.16299
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\2.2.101\
Host (useful for support):
Version: 2.2.2
Commit: a4fd7b2c84
.NET Core SDKs installed:
1.0.4 [C:\Program Files\dotnet\sdk]
2.0.2 [C:\Program Files\dotnet\sdk]
2.0.3 [C:\Program Files\dotnet\sdk]
2.1.2 [C:\Program Files\dotnet\sdk]
2.1.4 [C:\Program Files\dotnet\sdk]
2.1.100 [C:\Program Files\dotnet\sdk]
2.1.101 [C:\Program Files\dotnet\sdk]
2.1.102 [C:\Program Files\dotnet\sdk]
2.1.103 [C:\Program Files\dotnet\sdk]
2.1.104 [C:\Program Files\dotnet\sdk]
2.1.200 [C:\Program Files\dotnet\sdk]
2.1.201 [C:\Program Files\dotnet\sdk]
2.1.202 [C:\Program Files\dotnet\sdk]
2.1.302 [C:\Program Files\dotnet\sdk]
2.1.403 [C:\Program Files\dotnet\sdk]
2.1.500 [C:\Program Files\dotnet\sdk]
2.1.502 [C:\Program Files\dotnet\sdk]
2.1.503 [C:\Program Files\dotnet\sdk]
2.2.101 [C:\Program Files\dotnet\sdk]
.NET Core runtimes installed:
Microsoft.AspNetCore.All 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.1.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.1.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.2.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.2.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.App 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.1.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.1.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.2.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.2.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 1.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 1.1.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.0.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.0.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.0.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.2.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.2.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Possible Fixes
- This line could be changed to the below code, but I would assume this would be breaking change and may have negative downstream impact.
var feature = SessionFeatureOrNull;
if (feature == null)
{
return null;
}
return feature.Session;
- Add
SessionConfigured
property to DefaultHttpContext. With this, I could wrap myHttpContext.Session
calls in any Auth Handler inside of aif (HttpContext.SessionConfigured) {}
block.
public bool SessionConfigured
{
get
{
return SessionFeatureOrNull != null;
}
}
- Add
GetSession()
method to DefaultHttpContext.
public ISession GetSession()
{
get
{
if (SessionFeatureOrNull == null)
{
return null;
}
return Session;
}
}
Let me know if any of these solutions sound good and I'll create a pull request.