Danielmartin/update to jwt bearer events (#12133)
* Updated Jwt Bearer Events to inlcude event for if the request is unauthorized * added forbidden as exception * updated reference assemblies * Updated code based on feedback from PR. * added empty line between methods * removed exception from ForbiddenContext based on response from pr. * added unit tests * re-generated the reference sources after removal of the exception from the forbidden context * removed failing test that was used for validation on the tests * Fixed tests. This was fixed before but i think during a merge i removed the updated code for the test. This is just adding it back * updated tests based on feedback in PR. * Removed extra line from csproj file * Revert ref csproj change
This commit is contained in:
parent
fb5da88b25
commit
5458a102e6
|
|
@ -8,6 +8,10 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
||||||
public AuthenticationFailedContext(Microsoft.AspNetCore.Http.HttpContext context, Microsoft.AspNetCore.Authentication.AuthenticationScheme scheme, Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions options) : base (default(Microsoft.AspNetCore.Http.HttpContext), default(Microsoft.AspNetCore.Authentication.AuthenticationScheme), default(Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions)) { }
|
public AuthenticationFailedContext(Microsoft.AspNetCore.Http.HttpContext context, Microsoft.AspNetCore.Authentication.AuthenticationScheme scheme, Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions options) : base (default(Microsoft.AspNetCore.Http.HttpContext), default(Microsoft.AspNetCore.Authentication.AuthenticationScheme), default(Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions)) { }
|
||||||
public System.Exception Exception { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public System.Exception Exception { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
}
|
}
|
||||||
|
public partial class ForbiddenContext : Microsoft.AspNetCore.Authentication.ResultContext<Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions>
|
||||||
|
{
|
||||||
|
public ForbiddenContext(Microsoft.AspNetCore.Http.HttpContext context, Microsoft.AspNetCore.Authentication.AuthenticationScheme scheme, Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions options) : base (default(Microsoft.AspNetCore.Http.HttpContext), default(Microsoft.AspNetCore.Authentication.AuthenticationScheme), default(Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions)) { }
|
||||||
|
}
|
||||||
public partial class JwtBearerChallengeContext : Microsoft.AspNetCore.Authentication.PropertiesContext<Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions>
|
public partial class JwtBearerChallengeContext : Microsoft.AspNetCore.Authentication.PropertiesContext<Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions>
|
||||||
{
|
{
|
||||||
public JwtBearerChallengeContext(Microsoft.AspNetCore.Http.HttpContext context, Microsoft.AspNetCore.Authentication.AuthenticationScheme scheme, Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions options, Microsoft.AspNetCore.Authentication.AuthenticationProperties properties) : base (default(Microsoft.AspNetCore.Http.HttpContext), default(Microsoft.AspNetCore.Authentication.AuthenticationScheme), default(Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions), default(Microsoft.AspNetCore.Authentication.AuthenticationProperties)) { }
|
public JwtBearerChallengeContext(Microsoft.AspNetCore.Http.HttpContext context, Microsoft.AspNetCore.Authentication.AuthenticationScheme scheme, Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions options, Microsoft.AspNetCore.Authentication.AuthenticationProperties properties) : base (default(Microsoft.AspNetCore.Http.HttpContext), default(Microsoft.AspNetCore.Authentication.AuthenticationScheme), default(Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions), default(Microsoft.AspNetCore.Authentication.AuthenticationProperties)) { }
|
||||||
|
|
@ -27,10 +31,12 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
||||||
public JwtBearerEvents() { }
|
public JwtBearerEvents() { }
|
||||||
public System.Func<Microsoft.AspNetCore.Authentication.JwtBearer.AuthenticationFailedContext, System.Threading.Tasks.Task> OnAuthenticationFailed { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public System.Func<Microsoft.AspNetCore.Authentication.JwtBearer.AuthenticationFailedContext, System.Threading.Tasks.Task> OnAuthenticationFailed { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public System.Func<Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerChallengeContext, System.Threading.Tasks.Task> OnChallenge { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public System.Func<Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerChallengeContext, System.Threading.Tasks.Task> OnChallenge { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
|
public System.Func<Microsoft.AspNetCore.Authentication.JwtBearer.ForbiddenContext, System.Threading.Tasks.Task> OnForbidden { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public System.Func<Microsoft.AspNetCore.Authentication.JwtBearer.MessageReceivedContext, System.Threading.Tasks.Task> OnMessageReceived { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public System.Func<Microsoft.AspNetCore.Authentication.JwtBearer.MessageReceivedContext, System.Threading.Tasks.Task> OnMessageReceived { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public System.Func<Microsoft.AspNetCore.Authentication.JwtBearer.TokenValidatedContext, System.Threading.Tasks.Task> OnTokenValidated { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public System.Func<Microsoft.AspNetCore.Authentication.JwtBearer.TokenValidatedContext, System.Threading.Tasks.Task> OnTokenValidated { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public virtual System.Threading.Tasks.Task AuthenticationFailed(Microsoft.AspNetCore.Authentication.JwtBearer.AuthenticationFailedContext context) { throw null; }
|
public virtual System.Threading.Tasks.Task AuthenticationFailed(Microsoft.AspNetCore.Authentication.JwtBearer.AuthenticationFailedContext context) { throw null; }
|
||||||
public virtual System.Threading.Tasks.Task Challenge(Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerChallengeContext context) { throw null; }
|
public virtual System.Threading.Tasks.Task Challenge(Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerChallengeContext context) { throw null; }
|
||||||
|
public virtual System.Threading.Tasks.Task Forbidden(Microsoft.AspNetCore.Authentication.JwtBearer.ForbiddenContext context) { throw null; }
|
||||||
public virtual System.Threading.Tasks.Task MessageReceived(Microsoft.AspNetCore.Authentication.JwtBearer.MessageReceivedContext context) { throw null; }
|
public virtual System.Threading.Tasks.Task MessageReceived(Microsoft.AspNetCore.Authentication.JwtBearer.MessageReceivedContext context) { throw null; }
|
||||||
public virtual System.Threading.Tasks.Task TokenValidated(Microsoft.AspNetCore.Authentication.JwtBearer.TokenValidatedContext context) { throw null; }
|
public virtual System.Threading.Tasks.Task TokenValidated(Microsoft.AspNetCore.Authentication.JwtBearer.TokenValidatedContext context) { throw null; }
|
||||||
}
|
}
|
||||||
|
|
@ -43,6 +49,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
||||||
protected override System.Threading.Tasks.Task<Microsoft.AspNetCore.Authentication.AuthenticateResult> HandleAuthenticateAsync() { throw null; }
|
protected override System.Threading.Tasks.Task<Microsoft.AspNetCore.Authentication.AuthenticateResult> HandleAuthenticateAsync() { throw null; }
|
||||||
[System.Diagnostics.DebuggerStepThroughAttribute]
|
[System.Diagnostics.DebuggerStepThroughAttribute]
|
||||||
protected override System.Threading.Tasks.Task HandleChallengeAsync(Microsoft.AspNetCore.Authentication.AuthenticationProperties properties) { throw null; }
|
protected override System.Threading.Tasks.Task HandleChallengeAsync(Microsoft.AspNetCore.Authentication.AuthenticationProperties properties) { throw null; }
|
||||||
|
protected override System.Threading.Tasks.Task HandleForbiddenAsync(Microsoft.AspNetCore.Authentication.AuthenticationProperties properties) { throw null; }
|
||||||
}
|
}
|
||||||
public partial class JwtBearerOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions
|
public partial class JwtBearerOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
||||||
|
{
|
||||||
|
public class ForbiddenContext : ResultContext<JwtBearerOptions>
|
||||||
|
{
|
||||||
|
public ForbiddenContext(
|
||||||
|
HttpContext context,
|
||||||
|
AuthenticationScheme scheme,
|
||||||
|
JwtBearerOptions options)
|
||||||
|
: base(context, scheme, options) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,6 +16,11 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<AuthenticationFailedContext, Task> OnAuthenticationFailed { get; set; } = context => Task.CompletedTask;
|
public Func<AuthenticationFailedContext, Task> OnAuthenticationFailed { get; set; } = context => Task.CompletedTask;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked if Authorization fails and results in a Forbidden response
|
||||||
|
/// </summary>
|
||||||
|
public Func<ForbiddenContext, Task> OnForbidden { get; set; } = context => Task.CompletedTask;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked when a protocol message is first received.
|
/// Invoked when a protocol message is first received.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -33,6 +38,8 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
||||||
|
|
||||||
public virtual Task AuthenticationFailed(AuthenticationFailedContext context) => OnAuthenticationFailed(context);
|
public virtual Task AuthenticationFailed(AuthenticationFailedContext context) => OnAuthenticationFailed(context);
|
||||||
|
|
||||||
|
public virtual Task Forbidden(ForbiddenContext context) => OnForbidden(context);
|
||||||
|
|
||||||
public virtual Task MessageReceived(MessageReceivedContext context) => OnMessageReceived(context);
|
public virtual Task MessageReceived(MessageReceivedContext context) => OnMessageReceived(context);
|
||||||
|
|
||||||
public virtual Task TokenValidated(TokenValidatedContext context) => OnTokenValidated(context);
|
public virtual Task TokenValidated(TokenValidatedContext context) => OnTokenValidated(context);
|
||||||
|
|
|
||||||
|
|
@ -265,6 +265,13 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override Task HandleForbiddenAsync(AuthenticationProperties properties)
|
||||||
|
{
|
||||||
|
var forbiddenContext = new ForbiddenContext(Context, Scheme, Options);
|
||||||
|
Response.StatusCode = 403;
|
||||||
|
return Events.Forbidden(forbiddenContext);
|
||||||
|
}
|
||||||
|
|
||||||
private static string CreateErrorDescription(Exception authFailure)
|
private static string CreateErrorDescription(Exception authFailure)
|
||||||
{
|
{
|
||||||
IEnumerable<Exception> exceptions;
|
IEnumerable<Exception> exceptions;
|
||||||
|
|
|
||||||
|
|
@ -679,6 +679,77 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
||||||
Assert.Equal(string.Empty, response.ResponseText);
|
Assert.Equal(string.Empty, response.ResponseText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task EventOnForbidden_ResponseNotModified()
|
||||||
|
{
|
||||||
|
var tokenData = CreateStandardTokenAndKey();
|
||||||
|
|
||||||
|
var server = CreateServer(o =>
|
||||||
|
{
|
||||||
|
o.TokenValidationParameters = new TokenValidationParameters()
|
||||||
|
{
|
||||||
|
ValidIssuer = "issuer.contoso.com",
|
||||||
|
ValidAudience = "audience.contoso.com",
|
||||||
|
IssuerSigningKey = tokenData.key,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
var newBearerToken = "Bearer " + tokenData.tokenText;
|
||||||
|
var response = await SendAsync(server, "http://example.com/forbidden", newBearerToken);
|
||||||
|
Assert.Equal(HttpStatusCode.Forbidden, response.Response.StatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task EventOnForbiddenSkip_ResponseNotModified()
|
||||||
|
{
|
||||||
|
var tokenData = CreateStandardTokenAndKey();
|
||||||
|
var server = CreateServer(o =>
|
||||||
|
{
|
||||||
|
o.TokenValidationParameters = new TokenValidationParameters()
|
||||||
|
{
|
||||||
|
ValidIssuer = "issuer.contoso.com",
|
||||||
|
ValidAudience = "audience.contoso.com",
|
||||||
|
IssuerSigningKey = tokenData.key,
|
||||||
|
};
|
||||||
|
o.Events = new JwtBearerEvents()
|
||||||
|
{
|
||||||
|
OnForbidden = context =>
|
||||||
|
{
|
||||||
|
return Task.FromResult(0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
var newBearerToken = "Bearer " + tokenData.tokenText;
|
||||||
|
var response = await SendAsync(server, "http://example.com/forbidden", newBearerToken);
|
||||||
|
Assert.Equal(HttpStatusCode.Forbidden, response.Response.StatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task EventOnForbidden_ResponseModified()
|
||||||
|
{
|
||||||
|
var tokenData = CreateStandardTokenAndKey();
|
||||||
|
var server = CreateServer(o =>
|
||||||
|
{
|
||||||
|
o.TokenValidationParameters = new TokenValidationParameters()
|
||||||
|
{
|
||||||
|
ValidIssuer = "issuer.contoso.com",
|
||||||
|
ValidAudience = "audience.contoso.com",
|
||||||
|
IssuerSigningKey = tokenData.key,
|
||||||
|
};
|
||||||
|
o.Events = new JwtBearerEvents()
|
||||||
|
{
|
||||||
|
OnForbidden = context =>
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = 418;
|
||||||
|
return context.Response.WriteAsync("You Shall Not Pass");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
var newBearerToken = "Bearer " + tokenData.tokenText;
|
||||||
|
var response = await SendAsync(server, "http://example.com/forbidden", newBearerToken);
|
||||||
|
Assert.Equal(418, (int)response.Response.StatusCode);
|
||||||
|
Assert.Equal("You Shall Not Pass", await response.Response.Content.ReadAsStringAsync());
|
||||||
|
}
|
||||||
|
|
||||||
class InvalidTokenValidator : ISecurityTokenValidator
|
class InvalidTokenValidator : ISecurityTokenValidator
|
||||||
{
|
{
|
||||||
public InvalidTokenValidator()
|
public InvalidTokenValidator()
|
||||||
|
|
@ -879,6 +950,11 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
||||||
var result = await context.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
|
var result = await context.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
|
||||||
await context.ChallengeAsync(JwtBearerDefaults.AuthenticationScheme);
|
await context.ChallengeAsync(JwtBearerDefaults.AuthenticationScheme);
|
||||||
}
|
}
|
||||||
|
else if (context.Request.Path == new PathString("/forbidden"))
|
||||||
|
{
|
||||||
|
// Simulate Forbidden
|
||||||
|
await context.ForbidAsync(JwtBearerDefaults.AuthenticationScheme);
|
||||||
|
}
|
||||||
else if (context.Request.Path == new PathString("/signIn"))
|
else if (context.Request.Path == new PathString("/signIn"))
|
||||||
{
|
{
|
||||||
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(JwtBearerDefaults.AuthenticationScheme, new ClaimsPrincipal()));
|
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(JwtBearerDefaults.AuthenticationScheme, new ClaimsPrincipal()));
|
||||||
|
|
@ -924,5 +1000,26 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
||||||
|
|
||||||
return transaction;
|
return transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static (string tokenText, SymmetricSecurityKey key) CreateStandardTokenAndKey()
|
||||||
|
{
|
||||||
|
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(new string('a', 128)));
|
||||||
|
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
||||||
|
|
||||||
|
var claims = new[]
|
||||||
|
{
|
||||||
|
new Claim(ClaimTypes.NameIdentifier, "Bob")
|
||||||
|
};
|
||||||
|
|
||||||
|
var token = new JwtSecurityToken(
|
||||||
|
issuer: "issuer.contoso.com",
|
||||||
|
audience: "audience.contoso.com",
|
||||||
|
claims: claims,
|
||||||
|
expires: DateTime.Now.AddMinutes(30),
|
||||||
|
signingCredentials: creds);
|
||||||
|
|
||||||
|
var tokenText = new JwtSecurityTokenHandler().WriteToken(token);
|
||||||
|
return (tokenText, key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue