Need help debugging JwtSecurityTokenHandler (web a

2019-07-19 14:11发布

问题:

I am desperately trying to find out why I keep getting a 401 response from my resource server:

Scenario: Console program running an authorization server. Console program running a resource server. Console program using both (client).

I have no problem getting the token, and it validates with expected content at jwt.io. Further, when submitting the base64 encoded secret used to create the token, the site also validates the token string.

I have tried every possible combination of suppressing and/or adding HostAuthentication defaults/filters; I have used UseCors (AllowAll) before and after both auth and webapi use-calls; I have tried juuuuust about anything!

This is my configure auth:

private void ConfigureAuth(IAppBuilder app, HttpConfiguration config)
    {
        config.SuppressDefaultHostAuthentication();
        config.Filters.Add(new HostAuthenticationFilter("Bearer"));

        var issuer = ConfigurationManager.AppSettings["tokenIssuer"];
        var audience = "MyEnergy"; //TODO: audience should be taken from somewhere else!!
        var secret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["secret"]); //TODO: no configuration manager here!

        var jwtBearerOptions = new JwtBearerAuthenticationOptions()
        {
         TokenHandler  = new testdumbass(),
            AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
            AuthenticationType = "JWT",
            AllowedAudiences = new[] {audience},
            IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
            {new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)}
        };
        app.UseJwtBearerAuthentication(jwtBearerOptions);
    }

and here is my Configuration and ConfigureWebApi:

public void Configuration(IAppBuilder app)
    {
        var config = new HttpConfiguration();
        ConfigureAuth(app, config); //using oauth
        ConfigureWebApi(config);
        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
        app.UseWebApi(config);
    }

private void ConfigureWebApi(HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes(); 
        config.Routes.MapHttpRoute(
            "Default",
            "{controller}/{id}",
            new {id = RouteParameter.Optional});
    }

So, I tried to implement a custom JwtSecurityTokenHandler (testdumbass class) and just overrided everything I could, calling base operations. From what I can see, the default implementation has NO problem reading the token (all the expected values are there).

So how can I test the validation? The following three methods are called (in that order): ReadToken CanReadToken ValidateToken (out validatedToken) *ValidateSignature *ReadToken *CanReadToken *ValidateIssuerSecurityKey *ValidateLifetime *ValidateAudience *ValidateIssuer *CreateClaimsIdentity ValidateToken finishes

Now the out parameter looks fine. SecurityKeys however are 0 and Id is null (any relevance?) The inner JwtSecurityToken has a signing key, where the 32 byte array matches what I would expect. If I look at non-public members allthe 4 rawXXX field have values (Data, Header and Payload as expected (dunno what to make of rawSignature)) I am using "https://localhost" as issuer, which can also be read from the validated token.

After all of this, I have overriden OnAuthorizationAsync in my own custom AuthorizeAttribute. Here I call the base implementation (the one in AuthorizeAttribute) and the actionContext always fails with 401.

I must admit I really cannot figure out WHY!

回答1:

I found out what the problem was:

I took these two lines from here:

private void ConfigureAuth(IAppBuilder app, HttpConfiguration config)
{
    config.SuppressDefaultHostAuthentication();
    config.Filters.Add(new HostAuthenticationFilter("Bearer"));

and moved them here:

private void ConfigureWebApi(HttpConfiguration config)
{
    config.SuppressDefaultHostAuthentication();
    config.Filters.Add(new HostAuthenticationFilter("Bearer"));
    config.MapHttpAttributeRoutes();

This would result in the correct context with correct identity in the AuthorizeAttribute validation (in the HttpActionContext sent as parameter).

What I dont get, is why changes in the config matter before using it in the UseWebApi call?