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 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 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 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.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.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 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 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; }
|
||||
[System.Diagnostics.DebuggerStepThroughAttribute]
|
||||
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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
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>
|
||||
/// Invoked when a protocol message is first received.
|
||||
/// </summary>
|
||||
|
|
@ -33,6 +38,8 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
|||
|
||||
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 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)
|
||||
{
|
||||
IEnumerable<Exception> exceptions;
|
||||
|
|
|
|||
|
|
@ -679,6 +679,77 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
|||
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
|
||||
{
|
||||
public InvalidTokenValidator()
|
||||
|
|
@ -879,6 +950,11 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
|||
var result = await context.AuthenticateAsync(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"))
|
||||
{
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(JwtBearerDefaults.AuthenticationScheme, new ClaimsPrincipal()));
|
||||
|
|
@ -924,5 +1000,26 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
|||
|
||||
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