Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,8 @@ public void Configure(string? name, JwtBearerOptions options)

var issuer = configSection[nameof(TokenValidationParameters.ValidIssuer)];
var issuers = configSection.GetSection(nameof(TokenValidationParameters.ValidIssuers)).GetChildren().Select(iss => iss.Value).ToList();
if (issuer is not null)
{
issuers.Add(issuer);
}
var audience = configSection[nameof(TokenValidationParameters.ValidAudience)];
var audiences = configSection.GetSection(nameof(TokenValidationParameters.ValidAudiences)).GetChildren().Select(aud => aud.Value).ToList();
if (audience is not null)
{
audiences.Add(audience);
}

options.Authority = configSection[nameof(options.Authority)] ?? options.Authority;
options.BackchannelTimeout = StringHelpers.ParseValueOrDefault(configSection[nameof(options.BackchannelTimeout)], _invariantTimeSpanParse, options.BackchannelTimeout);
Expand All @@ -73,8 +65,10 @@ public void Configure(string? name, JwtBearerOptions options)
{
ValidateIssuer = issuers.Count > 0,
ValidIssuers = issuers,
ValidIssuer = issuer,
ValidateAudience = audiences.Count > 0,
ValidAudiences = audiences,
ValidAudience = audience,
ValidateIssuerSigningKey = true,
IssuerSigningKeys = GetIssuerSigningKeys(configSection, issuers),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ public async Task WebApplicationBuilder_RegistersAuthenticationAndAuthorizationM
Assert.True(app.Properties.ContainsKey("__AuthorizationMiddlewareSet"));

var options = app.Services.GetService<IOptionsMonitor<JwtBearerOptions>>().Get(JwtBearerDefaults.AuthenticationScheme);
Assert.Equal(new[] { "SomeIssuer" }, options.TokenValidationParameters.ValidIssuers);
Assert.Equal("SomeIssuer", options.TokenValidationParameters.ValidIssuer);
Assert.Equal(new[] { "https://localhost:5001" }, options.TokenValidationParameters.ValidAudiences);
}

Expand Down
69 changes: 0 additions & 69 deletions src/Security/Authentication/test/JwtBearerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1010,75 +1010,6 @@ public async Task ExpirationAndIssuedWhenMinOrMaxValue()
Assert.Equal(max, elementValueUtc);
}

[Fact]
public void CanReadJwtBearerOptionsFromConfig()
{
var services = new ServiceCollection().AddLogging();
var config = new ConfigurationBuilder().AddInMemoryCollection(new[]
{
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:ValidIssuer", "dotnet-user-jwts"),
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:ValidAudiences:0", "http://localhost:5000"),
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:ValidAudiences:1", "https://localhost:5001"),
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:BackchannelTimeout", "00:01:00"),
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:RequireHttpsMetadata", "false"),
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:SaveToken", "True"),
}).Build();
services.AddSingleton<IConfiguration>(config);

// Act
var builder = services.AddAuthentication(o =>
{
o.AddScheme<TestHandler>("Bearer", "Bearer");
});
builder.AddJwtBearer("Bearer", o => o.UseSecurityTokenValidators = true);
RegisterAuth(builder, _ => { });
var sp = services.BuildServiceProvider();

// Assert
var jwtBearerOptions = sp.GetRequiredService<IOptionsMonitor<JwtBearerOptions>>().Get(JwtBearerDefaults.AuthenticationScheme);
Assert.Equal(jwtBearerOptions.TokenValidationParameters.ValidIssuers, new[] { "dotnet-user-jwts" });
Assert.Equal(jwtBearerOptions.TokenValidationParameters.ValidAudiences, new[] { "http://localhost:5000", "https://localhost:5001" });
Assert.Equal(jwtBearerOptions.BackchannelTimeout, TimeSpan.FromSeconds(60));
Assert.False(jwtBearerOptions.RequireHttpsMetadata);
Assert.True(jwtBearerOptions.SaveToken);
Assert.True(jwtBearerOptions.MapInboundClaims); // Assert default values are respected
}

[Fact]
public void CanReadMultipleIssuersFromConfig()
{
var services = new ServiceCollection().AddLogging();
var firstKey = "qPG6tDtfxFYZifHW3sEueQ==";
var secondKey = "6JPzXj6aOPdojlZdeLshaA==";
var config = new ConfigurationBuilder().AddInMemoryCollection(new[]
{
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:ValidIssuers:0", "dotnet-user-jwts"),
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:ValidIssuers:1", "dotnet-user-jwts-2"),
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:SigningKeys:0:Issuer", "dotnet-user-jwts"),
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:SigningKeys:0:Value", firstKey),
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:SigningKeys:0:Length", "32"),
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:SigningKeys:1:Issuer", "dotnet-user-jwts-2"),
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:SigningKeys:1:Value", secondKey),
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:SigningKeys:1:Length", "32"),
}).Build();
services.AddSingleton<IConfiguration>(config);

// Act
var builder = services.AddAuthentication(o =>
{
o.AddScheme<TestHandler>("Bearer", "Bearer");
});
builder.AddJwtBearer("Bearer", o => o.UseSecurityTokenValidators = true);
RegisterAuth(builder, _ => { });
var sp = services.BuildServiceProvider();

// Assert
var jwtBearerOptions = sp.GetRequiredService<IOptionsMonitor<JwtBearerOptions>>().Get(JwtBearerDefaults.AuthenticationScheme);
Assert.Equal(2, jwtBearerOptions.TokenValidationParameters.IssuerSigningKeys.Count());
Assert.Equal(firstKey, Convert.ToBase64String(jwtBearerOptions.TokenValidationParameters.IssuerSigningKeys.OfType<SymmetricSecurityKey>().FirstOrDefault()?.Key));
Assert.Equal(secondKey, Convert.ToBase64String(jwtBearerOptions.TokenValidationParameters.IssuerSigningKeys.OfType<SymmetricSecurityKey>().LastOrDefault()?.Key));
}

class InvalidTokenValidator : ISecurityTokenValidator
{
public InvalidTokenValidator()
Expand Down
38 changes: 33 additions & 5 deletions src/Security/Authentication/test/JwtBearerTests_Handler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -968,8 +968,9 @@ public void CanReadJwtBearerOptionsFromConfig()
var config = new ConfigurationBuilder().AddInMemoryCollection(new[]
{
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:ValidIssuer", "dotnet-user-jwts"),
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:ValidAudiences:0", "http://localhost:5000"),
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:ValidAudiences:1", "https://localhost:5001"),
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:ValidIssuers:0", "dotnet-user-jwts-2"),
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:ValidAudience", "http://localhost:5000"),
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:ValidAudiences:0", "http://localhost:5001"),
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:BackchannelTimeout", "00:01:00"),
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:RequireHttpsMetadata", "false"),
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:SaveToken", "True"),
Expand All @@ -987,14 +988,41 @@ public void CanReadJwtBearerOptionsFromConfig()

// Assert
var jwtBearerOptions = sp.GetRequiredService<IOptionsMonitor<JwtBearerOptions>>().Get(JwtBearerDefaults.AuthenticationScheme);
Assert.Equal(jwtBearerOptions.TokenValidationParameters.ValidIssuers, new[] { "dotnet-user-jwts" });
Assert.Equal(jwtBearerOptions.TokenValidationParameters.ValidAudiences, new[] { "http://localhost:5000", "https://localhost:5001" });
Assert.Equal(jwtBearerOptions.BackchannelTimeout, TimeSpan.FromSeconds(60));
Assert.Equal("dotnet-user-jwts", jwtBearerOptions.TokenValidationParameters.ValidIssuer);
Assert.Equal(["dotnet-user-jwts-2"], jwtBearerOptions.TokenValidationParameters.ValidIssuers);
Assert.Equal("http://localhost:5000", jwtBearerOptions.TokenValidationParameters.ValidAudience);
Assert.Equal(["http://localhost:5001"], jwtBearerOptions.TokenValidationParameters.ValidAudiences);
Assert.Equal(TimeSpan.FromSeconds(60), jwtBearerOptions.BackchannelTimeout);
Assert.False(jwtBearerOptions.RequireHttpsMetadata);
Assert.True(jwtBearerOptions.SaveToken);
Assert.True(jwtBearerOptions.MapInboundClaims); // Assert default values are respected
}

[Fact]
public void CanReadMultipleAudiencesFromConfig()
{
var services = new ServiceCollection().AddLogging();
var config = new ConfigurationBuilder().AddInMemoryCollection(new[]
{
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:ValidAudiences:0", "http://localhost:5000"),
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:ValidAudiences:1", "https://localhost:5001")
}).Build();
services.AddSingleton<IConfiguration>(config);

// Act
var builder = services.AddAuthentication(o =>
{
o.AddScheme<TestHandler>("Bearer", "Bearer");
});
builder.AddJwtBearer("Bearer");
RegisterAuth(builder, _ => { });
var sp = services.BuildServiceProvider();

// Assert
var jwtBearerOptions = sp.GetRequiredService<IOptionsMonitor<JwtBearerOptions>>().Get(JwtBearerDefaults.AuthenticationScheme);
Assert.Equal(["http://localhost:5000", "https://localhost:5001"], jwtBearerOptions.TokenValidationParameters.ValidAudiences);
}

[Fact]
public void CanReadMultipleIssuersFromConfig()
{
Expand Down