OwinMiddleware implementation in Resource Server s

2019-08-24 02:13发布

问题:

I have set up my Resource Server (Web Api 2) to validate JWT token for incoming requests. The JWT token is issued by Auth0 and my client pass it to my web api. This all works fine and raises 401 response if Issuer, Audience or Expiry date is not valid. When I add my custom middleware derived from OwinMiddleware it suppresses token validation logic and I get 200 response for invalid requests.

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
         var issuer = "my issuer";
         var audience= "my audience";
         var clientId= "my client id";
         app.UseActiveDirectoryFederationServicesBearerAuthentication(
            new ActiveDirectoryFederationServicesBearerAuthenticationOptions
            {
                TokenValidationParameters = new TokenValidationParameters
                {
                    ValidAudience = audience,
                    ValidIssuer = issuer,
                    IssuerSigningKeyResolver = (token, securityToken, identifier, parameters) => parameters.IssuerSigningTokens.FirstOrDefault()?.SecurityKeys?.FirstOrDefault()
                },
                // Setting the MetadataEndpoint so the middleware can download the RS256 certificate
                MetadataEndpoint = $"{issuer.TrimEnd('/')}/wsfed/{clientId}/FederationMetadata/2007-06/FederationMetadata.xml"
            });



        HttpConfiguration config = new HttpConfiguration();

        app.Use<HttpUsernameInjector>();

        // Web API routes
        config.MapHttpAttributeRoutes();
        app.UseWebApi(config);
    }
}

and my custom OwinMiddleWare:

public class HttpUsernameInjector : OwinMiddleware
{
    public HttpUsernameInjector(OwinMiddleware next)
        : base(next)
    {
    }

    public override async Task Invoke(IOwinContext context)
    {
        const string usernameClaimKey = "my username claim key";

        var bearerString = context.Request.Headers["Authorization"];
        if (bearerString != null && bearerString.StartsWith("Bearer ", StringComparison.InvariantCultureIgnoreCase))
        {
            var tokenString = bearerString.Substring(7);

            var token = new JwtSecurityToken(tokenString);
            var claims = token.Claims.ToList();
            var username = claims.FirstOrDefault(x => x.Type == usernameClaimKey);

            if (username == null) throw new Exception("Token should have username");

            // Add to HttpContext
            var genericPrincipal = new GenericPrincipal(new GenericIdentity(username.Value), new string[] { });

            IPrincipal principal = genericPrincipal;

            context.Request.User = principal;
        }

        await Next.Invoke(context);
    }
}

How should I configure my custom middleware to avoid conflict/suppressing OWIN token authentication logic?

回答1:

Nothing's wrong with OWINMiddleware but assigning context.Request.User causes problem. GenericIdentity created here has a Readonly IsAuthenticated equal to true and not possible to set to false. When assigning context.Request.User = genericPrincipal; it overrides IsAuthenticated inside context.Request.User with IsAuthenticated from genericPrincipal. Need to check for Authentication result at the beginning of Invoke method and skip the logic if user is not authenticated. So it wouldn't change IsAuthenticated in context.Request.User.

public override async Task Invoke(IOwinContext context)
    {
        if (context.Authentication.User.Identity.IsAuthenticated)
        {
            //my username injection logic
        }
        await Next.Invoke(context);
    }