HttpContext in .NET Core Custom AuthProvider

A while back, we wrote a custom AuthProvider in ServiceStack against our custom implementation of IdentityServer 2. It’s been working well for us. I am now porting our code to .NET Core and in the process ran into an issue that HttpContext seems to no longer be available to us. As we rely on this heavily in our custom AuthProvider
e.g.:

public override object Authenticate(IServiceBase authService, IAuthSession session, Authenticate request)
...
if (HttpContext.Current != null)
                {
                    // set the current request's user the the decoded principal
                    HttpContext.Current.User = currentPrincipal;
                }

we have a bit of an issue. The workarounds online suggesting using DI with IHttpContextAccessor, but since we don’t control the signature of the Authenticate method, that doesn’t seem to be viable. Help?

.NET Core disables singleton access to the Request Context by default, have a look at this existing StackOverflow https://stackoverflow.com/a/49019952/85785 answer for how to access the underlying User attached to the .NET Core request. You can access the IRequest with authService.Request.

“authService.Request.HttpContext.Current” is not valid. HttpContext doesn’t exist on the IRequest.

Did you use the code from the StackOverflow answer? You need to cast OriginalRequest:

var user = (authService.Request.OriginalRequest as HttpRequest).HttpContext.user;

That did it - thanks. With the IsAuthorized method, I don’t have access to the authService. I need the Principal there as well - can I get it from the session?

Here is current code:

public override bool IsAuthorized(IAuthSession session, IAuthTokens tokens, Authenticate request = null)
    {
        return HttpContext.Current.User.Identity.IsAuthenticated && session.IsAuthenticated && string.Equals(session.UserName, HttpContext.Current.User.Identity.Name, StringComparison.OrdinalIgnoreCase);
    }

The IsAuthorized() is used to validate whether the IAuthSession is an authenticated UserSession. You’d need to populate it with whatever info you want to be available on it, which is typically done by the AuthProvider during authentication.

But to make this easier I’ve added a IRequest param to OnSessionFilter() which you can override in your AppHost to customize the Session before it’s resolved.

If it’s easier you can also choose to override OnLoad(IRequest) in a Custom AuthUserSession instead of the AppHost.

This change is available from v5.03 that’s now available on MyGet.

The IsAuthorized() is used to validate whether the IAuthSession is an authenticated UserSession. You’d need to populate it with whatever info you want to be available on it, which is typically done by the AuthProvider during authentication.

this is precisly what we were doing previously. As mentioned above, we were doing this

HttpContext.Current.User = currentPrincipal;

in the Authenticate method and then checking it later in IsAuthorized. Because HttpContext is not longer available, we now have

((HttpRequest)(authService.Request.OriginalRequest)).HttpContext.User = currentPrincipal;

in the Authenticate method, however, in the IsAuthorized method, we don’t have access to the Request on the authService and therefore don’t have a way to retrieve that value that we set in the Authenticate method as we were previously doing:

string.Equals(session.UserName, HttpContext.Current.User.Identity.Name, StringComparison.OrdinalIgnoreCase

That’s what I’m looking to understand how to do now.

thanks!

Override AppHost.OnSessionFilter() or AuthUserSession.OnLoad(IRequest) and populate your UserSession object with everything you need from the IRequest.

The session object already has the username - I’d be comparing it with itself, no? I think the idea of checking the value in the HttpConetxt.Request is to validate the request wasn’t hijacked.

If you’re storing the session then that should ideally be the source of truth, I’m not sure what anti hijacking features you’re looking to protect against where it’s only the ServiceStack Session being hijacked. But sure you can use the Session Filters to validate that the user names match per request.

Although if you’re able to recreate what you need in the Session from the IRequest context you wouldn’t need to persist the session and can have your Custom AuthProvider implement IAuthWithRequest and have the PreAuthenticate method validate the IRequest and populate IRequest.Items[Keywords.Session] with the AuthUserSession to be used for that request so the Session wouldn’t need to be persisted in between requests. The ApiKeyAuthProvider.cs and JwtAuthProviderReader.cs are examples of IAuthWithRequest Auth Providers which re-create sessions per request.