JwtBearer Token: Catch exception during unauthorized flow
This commit is contained in:
parent
5231c5a853
commit
0314632696
|
|
@ -323,7 +323,6 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
|
|||
await Options.Events.RedirectToReturnUrl(redirectContext);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static bool IsHostRelative(string path)
|
||||
|
|
|
|||
|
|
@ -185,11 +185,11 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
|||
|
||||
protected override async Task<bool> HandleUnauthorizedAsync(ChallengeContext context)
|
||||
{
|
||||
var authResult = await HandleAuthenticateOnceAsync();
|
||||
var authResult = await HandleAuthenticateOnceSafeAsync();
|
||||
|
||||
var eventContext = new JwtBearerChallengeContext(Context, Options, new AuthenticationProperties(context.Properties))
|
||||
{
|
||||
AuthenticateFailure = authResult?.Failure,
|
||||
AuthenticateFailure = authResult?.Failure
|
||||
};
|
||||
|
||||
// Avoid returning error=invalid_token if the error is not caused by an authentication failure (e.g missing token).
|
||||
|
|
|
|||
|
|
@ -233,15 +233,43 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle the authentication for once.
|
||||
///
|
||||
/// If the authentication has been done before returns the last authentication result.
|
||||
/// </summary>
|
||||
protected Task<AuthenticateResult> HandleAuthenticateOnceAsync()
|
||||
{
|
||||
if (_authenticateTask == null)
|
||||
{
|
||||
_authenticateTask = HandleAuthenticateAsync();
|
||||
}
|
||||
|
||||
return _authenticateTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle the authentication for once.
|
||||
///
|
||||
/// If the authentication has been done before returns the last authentication result.
|
||||
/// This method won't throw exception. Any exception thrown during the authentication will be convert
|
||||
/// to a AuthenticateResult.
|
||||
/// </summary>
|
||||
protected Task<AuthenticateResult> HandleAuthenticateOnceSafeAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
return HandleAuthenticateOnceAsync().ContinueWith<AuthenticateResult>(
|
||||
task => task.IsFaulted ? AuthenticateResult.Fail(task.Exception) : task.Result
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// capture exception which is thrown before the task is actually started
|
||||
return Task.FromResult(AuthenticateResult.Fail(ex));
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Task<AuthenticateResult> HandleAuthenticateAsync();
|
||||
|
||||
public async Task SignInAsync(SignInContext context)
|
||||
|
|
@ -313,7 +341,7 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
{
|
||||
case ChallengeBehavior.Automatic:
|
||||
// If there is a principal already, invoke the forbidden code path
|
||||
var result = await HandleAuthenticateOnceAsync();
|
||||
var result = await HandleAuthenticateOnceSafeAsync();
|
||||
if (result?.Ticket?.Principal != null)
|
||||
{
|
||||
goto case ChallengeBehavior.Forbidden;
|
||||
|
|
@ -350,4 +378,4 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
auth.Handler = PriorHandler;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,46 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
|||
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ThrowAtAuthenticationFailedEvent()
|
||||
{
|
||||
var options = new JwtBearerOptions
|
||||
{
|
||||
Events = new JwtBearerEvents
|
||||
{
|
||||
OnAuthenticationFailed = context =>
|
||||
{
|
||||
context.Response.StatusCode = 401;
|
||||
throw new Exception();
|
||||
},
|
||||
OnMessageReceived = context =>
|
||||
{
|
||||
context.Token = "something";
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
options.SecurityTokenValidators.Clear();
|
||||
options.SecurityTokenValidators.Insert(0, new InvalidTokenValidator());
|
||||
|
||||
var server = CreateServer(options, async (context, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await next();
|
||||
Assert.False(true, "Expected exception is not thrown");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
context.Response.StatusCode = 401;
|
||||
await context.Response.WriteAsync("i got this");
|
||||
}
|
||||
});
|
||||
|
||||
var transaction = await server.SendAsync("https://example.com/signIn");
|
||||
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, transaction.Response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CustomHeaderReceived()
|
||||
|
|
@ -104,7 +144,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
|||
public async Task HeaderWithoutBearerReceived()
|
||||
{
|
||||
var server = CreateServer(new JwtBearerOptions());
|
||||
var response = await SendAsync(server, "http://example.com/oauth","Token");
|
||||
var response = await SendAsync(server, "http://example.com/oauth", "Token");
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
|
||||
}
|
||||
|
||||
|
|
@ -347,7 +387,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
|||
var response = await SendAsync(server, "http://example.com/unauthorized", "Bearer Token");
|
||||
Assert.Equal(HttpStatusCode.Forbidden, response.Response.StatusCode);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task BearerDoesNothingTo401IfNotAuthenticated()
|
||||
{
|
||||
|
|
@ -522,7 +562,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
|||
public string AuthenticationScheme { get; }
|
||||
|
||||
public bool CanValidateToken => true;
|
||||
|
||||
|
||||
public int MaximumTokenSizeInBytes
|
||||
{
|
||||
get
|
||||
|
|
@ -558,11 +598,21 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
|||
}
|
||||
}
|
||||
|
||||
private static TestServer CreateServer(JwtBearerOptions options, Func<HttpContext, bool> handler = null)
|
||||
private static TestServer CreateServer(JwtBearerOptions options)
|
||||
{
|
||||
return CreateServer(options, handlerBeforeAuth: null);
|
||||
}
|
||||
|
||||
private static TestServer CreateServer(JwtBearerOptions options, Func<HttpContext, Func<Task>, Task> handlerBeforeAuth)
|
||||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.Configure(app =>
|
||||
{
|
||||
if (handlerBeforeAuth != null)
|
||||
{
|
||||
app.Use(handlerBeforeAuth);
|
||||
}
|
||||
|
||||
if (options != null)
|
||||
{
|
||||
app.UseJwtBearerAuthentication(options);
|
||||
|
|
@ -622,6 +672,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
|||
});
|
||||
})
|
||||
.ConfigureServices(services => services.AddAuthentication());
|
||||
|
||||
return new TestServer(builder);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue