2
votes

I have web api which uses jwt bearer authentication. The implementation (openiddict) which creates the jwt uses the the current url as issuer.

services
    .AddOpenIddict()
    .UseJsonWebTokens();

I configured the jwt authentication handler to use a valid issuer.

services
    .AddAuthentication()
    .AddJwtBearer(options =>
    {
        options.Authority = "http://test/";
        ...
    });

When I reach the site under http://test/ I get an access token with the issuer set to http://test/. As the Authority matches the issuer the requests will be authenticated.

When I reach the site under http://125.124.35.21/ I get an access token with the issuer set to http://125.124.35.21/. As the Authority doesn't match the issuer the request won't be authenticated.

I want in both cases to be able to authenticate the request.

Now I saw that according to the jwt rfc the iss claim is optional.

My question is if I can set ValidateIssuer to false for this purpose, if I open a security hole when I do that and if there is an more recommended alternative?

services
    .AddAuthentication()
    .AddJwtBearer(options =>
    {
        options.Authority = "http://test/";
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = false,
            ...
        }
    });

Which configuration is used to resolve the .well-known/openid-configuration?The Authority? Hopefully not the issuer because that would mean that everybody can issue a token and use it with my api.

3

3 Answers

2
votes

I've looked into the code which generates my access token and found out that it only takes the current uri when no configuration value was set.

https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/blob/120a7ea9a14a33fad292cf4a11b4077118fab21f/src/AspNet.Security.OpenIdConnect.Server/OpenIdConnectServerHelpers.cs#L198

public static string GetIssuer(this HttpContext context, OpenIdConnectServerOptions options)
{
    var issuer = options.Issuer;
    if (issuer == null)
    {
        if (!Uri.TryCreate(context.Request.Scheme + "://" + context.Request.Host +
                               context.Request.PathBase, UriKind.Absolute, out issuer))
        {
            throw new InvalidOperationException("The issuer address cannot be inferred from the current request");
        }
    }

    return issuer.AbsoluteUri;
}

So when I configure openiddict I can just set the Issuer property.

services.AddOpenIddict()
    ...
    .Configure(options =>
    {
        options.Issuer = "http://test/";
        ...
    });

And when I add the authentication services I can also just set the Authority property.

services
    .AddAuthentication()
    .AddJwtBearer(options =>
    {
        options.Authority = "http://test/";
        ...
    });

It seems like that when no valid issuer is configured the Authority is taken to validate the issuer. But I've found no code to support that claim.

Maybe its hidden in Microsoft.IdentityModel.Protocols.OpenIdConnect.dll

1
votes

Another alternative would be to set ValidateIssuer to false.


As the JWT RFC says that the iss (Issuer) claim is optional.

The "iss" (issuer) claim identifies the principal that issued the JWT. The processing of this claim is generally application specific. The "iss" value is a case-sensitive string containing a StringOrURI value. Use of this claim is OPTIONAL.


The OAuth 2.0 RFC doesn't mention an issuer or in what format tokens are at all.


The uri to resolve the .well-known/openid-configuration is configured by the MetadataAddress property. If this property is not set it seems like the Authority property is used to build the uri.

https://github.com/aspnet/Security/blob/b3e4bf382c9676e2d912636b7ee0255cad244e11/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerPostConfigureOptions.cs#L37

if (string.IsNullOrEmpty(options.MetadataAddress) && !string.IsNullOrEmpty(options.Authority))
{
    options.MetadataAddress = options.Authority;
    if (!options.MetadataAddress.EndsWith("/", StringComparison.Ordinal))
    {
        options.MetadataAddress += "/";
    }

    options.MetadataAddress += ".well-known/openid-configuration";
}

And as the public key to verify the token is stored in the .well-known/jwks file which is prefixed by the MetadataAddress, it should be save to ignore this claim, if you don't wan't to excluce certain issuers where all share the same configuration file. But I can't think of such a case.

0
votes

Yet another solution would be to include all known aliases in the ValidIssuers property of the TokenValidationParameters. But I don't think this is a good idea as you would probably forget some aliases.

For example in different subnets you might can reach the service under different ips or different dns aliases.