#690 OIDC & JWT event refactoring.

This commit is contained in:
Chris R 2016-03-15 15:19:25 -07:00
parent 6a0e58e3ff
commit 3f596108aa
26 changed files with 278 additions and 490 deletions

View File

@ -12,7 +12,7 @@
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNET_ENVIRONMENT": "Development"
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"web": {

View File

@ -61,8 +61,6 @@ namespace JwtBearerSample
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
// You also need to update /wwwroot/app/scripts/app.js
Authority = Configuration["jwt:authority"],
Audience = Configuration["jwt:audience"]
@ -74,14 +72,14 @@ namespace JwtBearerSample
// Use this if options.AutomaticAuthenticate = false
// var user = await context.Authentication.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
var user = context.User; // We can do this because of options.AutomaticAuthenticate = true; above.
var user = context.User; // We can do this because of options.AutomaticAuthenticate = true;
if (user?.Identity?.IsAuthenticated ?? false)
{
await next();
}
else
{
// We can do this because of options.AutomaticChallenge = true; above
// We can do this because of options.AutomaticChallenge = true;
await context.Authentication.ChallengeAsync();
}
});

View File

@ -15,7 +15,7 @@
"web": "JwtBearerSample"
},
"frameworks": {
"dnx451": {},
"dnx451": { },
"netstandardapp1.5": {
"imports": [
"dnxcore50"
@ -30,5 +30,9 @@
"**.user",
"**.vspscc"
],
"content": [
"project.json",
"wwwroot"
],
"userSecretsId": "aspnet5-JwtBearerSample-20151210102827"
}

View File

@ -12,7 +12,7 @@
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"Hosting:Environment": "Development"
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"web": {

View File

@ -64,10 +64,7 @@ namespace OpenIdConnect.AzureAdSample
app.UseIISPlatformHandler();
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AutomaticAuthenticate = true
});
app.UseCookieAuthentication(new CookieAuthenticationOptions());
var clientId = Configuration["oidc:clientid"];
var clientSecret = Configuration["oidc:clientsecret"];

View File

@ -18,5 +18,8 @@
"commands": {
"web": "OpenIdConnect.AzureAdSample"
},
"content": [
"project.json"
],
"userSecretsId": "aspnet5-OpenIdConnectSample-20151210110318"
}

View File

@ -12,7 +12,7 @@
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNET_ENV": "Development"
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"web": {

View File

@ -59,10 +59,7 @@ namespace OpenIdConnectSample
app.UseIISPlatformHandler();
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AutomaticAuthenticate = true
});
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{

View File

@ -9,7 +9,7 @@
"Microsoft.NETCore.Platforms": "1.0.1-*"
},
"frameworks": {
"dnx451": {},
"dnx451": { },
"netstandardapp1.5": {
"imports": [
"dnxcore50"
@ -22,5 +22,8 @@
"commands": {
"web": "OpenIdConnectSample"
},
"content": [
"project.json"
],
"userSecretsId": "aspnet5-OpenIdConnectSample-20151210110318"
}

View File

@ -18,17 +18,12 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
/// <summary>
/// Invoked when a protocol message is first received.
/// </summary>
Task ReceivingToken(ReceivingTokenContext context);
/// <summary>
/// Invoked with the security token that has been extracted from the protocol message.
/// </summary>
Task ReceivedToken(ReceivedTokenContext context);
Task MessageReceived(MessageReceivedContext context);
/// <summary>
/// Invoked after the security token has passed validation and a ClaimsIdentity has been generated.
/// </summary>
Task ValidatedToken(ValidatedTokenContext context);
Task TokenValidated(TokenValidatedContext context);
/// <summary>
/// Invoked to apply a challenge sent back to the caller.

View File

@ -19,17 +19,12 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
/// <summary>
/// Invoked when a protocol message is first received.
/// </summary>
public Func<ReceivingTokenContext, Task> OnReceivingToken { get; set; } = context => Task.FromResult(0);
/// <summary>
/// Invoked with the security token that has been extracted from the protocol message.
/// </summary>
public Func<ReceivedTokenContext, Task> OnReceivedToken { get; set; } = context => Task.FromResult(0);
public Func<MessageReceivedContext, Task> OnMessageReceived { get; set; } = context => Task.FromResult(0);
/// <summary>
/// Invoked after the security token has passed validation and a ClaimsIdentity has been generated.
/// </summary>
public Func<ValidatedTokenContext, Task> OnValidatedToken { get; set; } = context => Task.FromResult(0);
public Func<TokenValidatedContext, Task> OnTokenValidated { get; set; } = context => Task.FromResult(0);
/// <summary>
/// Invoked before a challenge is sent back to the caller.
@ -38,11 +33,9 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
public virtual Task AuthenticationFailed(AuthenticationFailedContext context) => OnAuthenticationFailed(context);
public virtual Task ReceivingToken(ReceivingTokenContext context) => OnReceivingToken(context);
public virtual Task MessageReceived(MessageReceivedContext context) => OnMessageReceived(context);
public virtual Task ReceivedToken(ReceivedTokenContext context) => OnReceivedToken(context);
public virtual Task ValidatedToken(ValidatedTokenContext context) => OnValidatedToken(context);
public virtual Task TokenValidated(TokenValidatedContext context) => OnTokenValidated(context);
public virtual Task Challenge(JwtBearerChallengeContext context) => OnChallenge(context);
}

View File

@ -6,9 +6,9 @@ using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Authentication.JwtBearer
{
public class ReceivingTokenContext : BaseJwtBearerContext
public class MessageReceivedContext : BaseJwtBearerContext
{
public ReceivingTokenContext(HttpContext context, JwtBearerOptions options)
public MessageReceivedContext(HttpContext context, JwtBearerOptions options)
: base(context, options)
{
}

View File

@ -1,18 +0,0 @@
// 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 Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Authentication.JwtBearer
{
public class ReceivedTokenContext : BaseJwtBearerContext
{
public ReceivedTokenContext(HttpContext context, JwtBearerOptions options)
: base(context, options)
{
}
public string Token { get; set; }
}
}

View File

@ -3,14 +3,17 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.IdentityModel.Tokens;
namespace Microsoft.AspNetCore.Authentication.JwtBearer
{
public class ValidatedTokenContext : BaseJwtBearerContext
public class TokenValidatedContext : BaseJwtBearerContext
{
public ValidatedTokenContext(HttpContext context, JwtBearerOptions options)
public TokenValidatedContext(HttpContext context, JwtBearerOptions options)
: base(context, options)
{
}
public SecurityToken SecurityToken { get; set; }
}
}

View File

@ -28,24 +28,21 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
string token = null;
AuthenticateResult result = null;
try
{
// Give application opportunity to find from a different location, adjust, or reject token
var receivingTokenContext = new ReceivingTokenContext(Context, Options);
var messageReceivedContext = new MessageReceivedContext(Context, Options);
// event can set the token
await Options.Events.ReceivingToken(receivingTokenContext);
if (receivingTokenContext.HandledResponse)
await Options.Events.MessageReceived(messageReceivedContext);
if (messageReceivedContext.CheckEventResult(out result))
{
return AuthenticateResult.Success(receivingTokenContext.Ticket);
}
if (receivingTokenContext.Skipped)
{
return AuthenticateResult.Skip();
return result;
}
// If application retrieved token from somewhere else, use that.
token = receivingTokenContext.Token;
token = messageReceivedContext.Token;
if (string.IsNullOrEmpty(token))
{
@ -69,22 +66,6 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
}
}
// notify user token was received
var receivedTokenContext = new ReceivedTokenContext(Context, Options)
{
Token = token,
};
await Options.Events.ReceivedToken(receivedTokenContext);
if (receivedTokenContext.HandledResponse)
{
return AuthenticateResult.Success(receivedTokenContext.Ticket);
}
if (receivedTokenContext.Skipped)
{
return AuthenticateResult.Skip();
}
if (_configuration == null && Options.ConfigurationManager != null)
{
_configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.RequestAborted);
@ -138,20 +119,18 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
Logger.TokenValidationSucceeded();
var ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), Options.AuthenticationScheme);
var validatedTokenContext = new ValidatedTokenContext(Context, Options)
var tokenValidatedContext = new TokenValidatedContext(Context, Options)
{
Ticket = ticket
Ticket = ticket,
SecurityToken = validatedToken,
};
await Options.Events.ValidatedToken(validatedTokenContext);
if (validatedTokenContext.HandledResponse)
await Options.Events.TokenValidated(tokenValidatedContext);
if (tokenValidatedContext.CheckEventResult(out result))
{
return AuthenticateResult.Success(validatedTokenContext.Ticket);
}
if (validatedTokenContext.Skipped)
{
return AuthenticateResult.Skip();
return result;
}
ticket = tokenValidatedContext.Ticket;
if (Options.SaveToken)
{
@ -173,13 +152,9 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
};
await Options.Events.AuthenticationFailed(authenticationFailedContext);
if (authenticationFailedContext.HandledResponse)
if (authenticationFailedContext.CheckEventResult(out result))
{
return AuthenticateResult.Success(authenticationFailedContext.Ticket);
}
if (authenticationFailedContext.Skipped)
{
return AuthenticateResult.Skip();
return result;
}
return AuthenticateResult.Fail(authenticationFailedContext.Exception);
@ -197,13 +172,9 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
};
await Options.Events.AuthenticationFailed(authenticationFailedContext);
if (authenticationFailedContext.HandledResponse)
if (authenticationFailedContext.CheckEventResult(out result))
{
return AuthenticateResult.Success(authenticationFailedContext.Ticket);
}
if (authenticationFailedContext.Skipped)
{
return AuthenticateResult.Skip();
return result;
}
throw;

View File

@ -25,6 +25,8 @@ namespace Microsoft.AspNetCore.Builder
public JwtBearerOptions() : base()
{
AuthenticationScheme = JwtBearerDefaults.AuthenticationScheme;
AutomaticAuthenticate = true;
AutomaticChallenge = true;
}
/// <summary>

View File

@ -1,20 +0,0 @@
// 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 Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
{
public class AuthorizationResponseReceivedContext : BaseOpenIdConnectContext
{
public AuthorizationResponseReceivedContext(HttpContext context, OpenIdConnectOptions options, AuthenticationProperties properties)
: base(context, options)
{
Properties = properties;
}
public AuthenticationProperties Properties { get; }
}
}

View File

@ -15,21 +15,11 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
/// </summary>
Task AuthenticationFailed(AuthenticationFailedContext context);
/// <summary>
/// Invoked after the id token has passed validation and a ClaimsIdentity has been generated.
/// </summary>
Task AuthenticationValidated(AuthenticationValidatedContext context);
/// <summary>
/// Invoked after security token validation if an authorization code is present in the protocol message.
/// </summary>
Task AuthorizationCodeReceived(AuthorizationCodeReceivedContext context);
/// <summary>
/// Invoked when an authorization response is received.
/// </summary>
Task AuthorizationResponseReceived(AuthorizationResponseReceivedContext context);
/// <summary>
/// Invoked when a protocol message is first received.
/// </summary>
@ -38,18 +28,23 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
/// <summary>
/// Invoked before redirecting to the identity provider to authenticate.
/// </summary>
Task RedirectToAuthenticationEndpoint(RedirectContext context);
Task RedirectToIdentityProvider(RedirectContext context);
/// <summary>
/// Invoked before redirecting to the identity provider to sign out.
/// </summary>
Task RedirectToEndSessionEndpoint(RedirectContext context);
Task RedirectToIdentityProviderForSignOut(RedirectContext context);
/// <summary>
/// Invoked after "authorization code" is redeemed for tokens at the token endpoint.
/// </summary>
Task TokenResponseReceived(TokenResponseReceivedContext context);
/// <summary>
/// Invoked when an IdToken has been validated and produced an AuthenticationTicket.
/// </summary>
Task TokenValidated(TokenValidatedContext context);
/// <summary>
/// Invoked when user information is retrieved from the UserInfoEndpoint.
/// </summary>

View File

@ -3,6 +3,7 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
{
@ -17,5 +18,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
/// Bearer Token. This will give application an opportunity to retrieve token from an alternation location.
/// </summary>
public string Token { get; set; }
public AuthenticationProperties Properties { get; set; }
}
}

View File

@ -16,21 +16,11 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
/// </summary>
public Func<AuthenticationFailedContext, Task> OnAuthenticationFailed { get; set; } = context => Task.FromResult(0);
/// <summary>
/// Invoked after the id token has passed validation and a ClaimsIdentity has been generated.
/// </summary>
public Func<AuthenticationValidatedContext, Task> OnAuthenticationValidated { get; set; } = context => Task.FromResult(0);
/// <summary>
/// Invoked after security token validation if an authorization code is present in the protocol message.
/// </summary>
public Func<AuthorizationCodeReceivedContext, Task> OnAuthorizationCodeReceived { get; set; } = context => Task.FromResult(0);
/// <summary>
/// Invoked when an authorization response is received.
/// </summary>
public Func<AuthorizationResponseReceivedContext, Task> OnAuthorizationResponseReceived { get; set; } = context => Task.FromResult(0);
/// <summary>
/// Invoked when a protocol message is first received.
/// </summary>
@ -39,18 +29,23 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
/// <summary>
/// Invoked before redirecting to the identity provider to authenticate.
/// </summary>
public Func<RedirectContext, Task> OnRedirectToAuthenticationEndpoint { get; set; } = context => Task.FromResult(0);
public Func<RedirectContext, Task> OnRedirectToIdentityProvider { get; set; } = context => Task.FromResult(0);
/// <summary>
/// Invoked before redirecting to the identity provider to sign out.
/// </summary>
public Func<RedirectContext, Task> OnRedirectToEndSessionEndpoint { get; set; } = context => Task.FromResult(0);
public Func<RedirectContext, Task> OnRedirectToIdentityProviderForSignOut { get; set; } = context => Task.FromResult(0);
/// <summary>
/// Invoked after "authorization code" is redeemed for tokens at the token endpoint.
/// </summary>
public Func<TokenResponseReceivedContext, Task> OnTokenResponseReceived { get; set; } = context => Task.FromResult(0);
/// <summary>
/// Invoked when an IdToken has been validated and produced an AuthenticationTicket.
/// </summary>
public Func<TokenValidatedContext, Task> OnTokenValidated { get; set; } = context => Task.FromResult(0);
/// <summary>
/// Invoked when user information is retrieved from the UserInfoEndpoint.
/// </summary>
@ -58,20 +53,18 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
public virtual Task AuthenticationFailed(AuthenticationFailedContext context) => OnAuthenticationFailed(context);
public virtual Task AuthenticationValidated(AuthenticationValidatedContext context) => OnAuthenticationValidated(context);
public virtual Task AuthorizationCodeReceived(AuthorizationCodeReceivedContext context) => OnAuthorizationCodeReceived(context);
public virtual Task AuthorizationResponseReceived(AuthorizationResponseReceivedContext context) => OnAuthorizationResponseReceived(context);
public virtual Task MessageReceived(MessageReceivedContext context) => OnMessageReceived(context);
public virtual Task RedirectToAuthenticationEndpoint(RedirectContext context) => OnRedirectToAuthenticationEndpoint(context);
public virtual Task RedirectToIdentityProvider(RedirectContext context) => OnRedirectToIdentityProvider(context);
public virtual Task RedirectToEndSessionEndpoint(RedirectContext context) => OnRedirectToEndSessionEndpoint(context);
public virtual Task RedirectToIdentityProviderForSignOut(RedirectContext context) => OnRedirectToIdentityProviderForSignOut(context);
public virtual Task TokenResponseReceived(TokenResponseReceivedContext context) => OnTokenResponseReceived(context);
public virtual Task TokenValidated(TokenValidatedContext context) => OnTokenValidated(context);
public virtual Task UserInformationReceived(UserInformationReceivedContext context) => OnUserInformationReceived(context);
}
}

View File

@ -1,6 +1,8 @@
// 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.IdentityModel.Tokens.Jwt;
using System.Net.Http;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
@ -8,16 +10,22 @@ using Microsoft.IdentityModel.Protocols.OpenIdConnect;
namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
{
public class AuthenticationValidatedContext : BaseOpenIdConnectContext
public class TokenValidatedContext : BaseOpenIdConnectContext
{
public AuthenticationValidatedContext(HttpContext context, OpenIdConnectOptions options, AuthenticationProperties properties)
/// <summary>
/// Creates a <see cref="TokenValidatedContext"/>
/// </summary>
public TokenValidatedContext(HttpContext context, OpenIdConnectOptions options)
: base(context, options)
{
Properties = properties;
}
public AuthenticationProperties Properties { get; }
public AuthenticationProperties Properties { get; set; }
public JwtSecurityToken SecurityToken { get; set; }
public OpenIdConnectMessage TokenEndpointResponse { get; set; }
public string Nonce { get; set; }
}
}
}

View File

@ -7,10 +7,10 @@ namespace Microsoft.Extensions.Logging
{
internal static class LoggingExtensions
{
private static Action<ILogger, Exception> _redirectToEndSessionEndpointHandledResponse;
private static Action<ILogger, Exception> _redirectToEndSessionEndpointSkipped;
private static Action<ILogger, Exception> _redirectToAuthenticationEndpointHandledResponse;
private static Action<ILogger, Exception> _redirectToAuthenticationEndpointSkipped;
private static Action<ILogger, Exception> _redirectToIdentityProviderForSignOutHandledResponse;
private static Action<ILogger, Exception> _redirectToIdentityProviderForSignOutSkipped;
private static Action<ILogger, Exception> _redirectToIdentityProviderHandledResponse;
private static Action<ILogger, Exception> _redirectToIdentityProviderSkipped;
private static Action<ILogger, Exception> _updatingConfiguration;
private static Action<ILogger, Exception> _receivedIdToken;
private static Action<ILogger, Exception> _redeemingCodeForTokens;
@ -19,20 +19,17 @@ namespace Microsoft.Extensions.Logging
private static Action<ILogger, string, Exception> _messageReceived;
private static Action<ILogger, Exception> _messageReceivedContextHandledResponse;
private static Action<ILogger, Exception> _messageReceivedContextSkipped;
private static Action<ILogger, Exception> _authorizationResponseReceived;
private static Action<ILogger, Exception> _authorizationCodeReceived;
private static Action<ILogger, Exception> _configurationManagerRequestRefreshCalled;
private static Action<ILogger, Exception> _tokenResponseReceived;
private static Action<ILogger, Exception> _authorizationResponseReceivedHandledResponse;
private static Action<ILogger, Exception> _authorizationResponseReceivedSkipped;
private static Action<ILogger, Exception> _tokenValidatedHandledResponse;
private static Action<ILogger, Exception> _tokenValidatedSkipped;
private static Action<ILogger, Exception> _authenticationFailedContextHandledResponse;
private static Action<ILogger, Exception> _authenticationFailedContextSkipped;
private static Action<ILogger, Exception> _authorizationCodeReceivedContextHandledResponse;
private static Action<ILogger, Exception> _authorizationCodeReceivedContextSkipped;
private static Action<ILogger, Exception> _authorizationCodeRedeemedContextHandledResponse;
private static Action<ILogger, Exception> _authorizationCodeRedeemedContextSkipped;
private static Action<ILogger, Exception> _authenticationValidatedHandledResponse;
private static Action<ILogger, Exception> _authenticationValidatedtSkipped;
private static Action<ILogger, Exception> _tokenResponseReceivedHandledResponse;
private static Action<ILogger, Exception> _tokenResponseReceivedSkipped;
private static Action<ILogger, string, Exception> _userInformationReceived;
private static Action<ILogger, Exception> _userInformationReceivedHandledResponse;
private static Action<ILogger, Exception> _userInformationReceivedSkipped;
@ -54,14 +51,14 @@ namespace Microsoft.Extensions.Logging
static LoggingExtensions()
{
// Final
_redirectToEndSessionEndpointHandledResponse = LoggerMessage.Define(
_redirectToIdentityProviderForSignOutHandledResponse = LoggerMessage.Define(
eventId: 1,
logLevel: LogLevel.Debug,
formatString: "RedirectToEndSessionEndpoint.HandledResponse");
_redirectToEndSessionEndpointSkipped = LoggerMessage.Define(
formatString: "RedirectToIdentityProviderForSignOut.HandledResponse");
_redirectToIdentityProviderForSignOutSkipped = LoggerMessage.Define(
eventId: 2,
logLevel: LogLevel.Debug,
formatString: "RedirectToEndSessionEndpoint.Skipped");
formatString: "RedirectToIdentityProviderForSignOut.Skipped");
_invalidLogoutQueryStringRedirectUrl = LoggerMessage.Define<string>(
eventId: 3,
logLevel: LogLevel.Warning,
@ -74,14 +71,14 @@ namespace Microsoft.Extensions.Logging
eventId: 5,
logLevel: LogLevel.Trace,
formatString: "Using properties.RedirectUri for 'local redirect' post authentication: '{RedirectUri}'.");
_redirectToAuthenticationEndpointHandledResponse = LoggerMessage.Define(
_redirectToIdentityProviderHandledResponse = LoggerMessage.Define(
eventId: 6,
logLevel: LogLevel.Debug,
formatString: "RedirectToAuthenticationEndpoint.HandledResponse");
_redirectToAuthenticationEndpointSkipped = LoggerMessage.Define(
formatString: "RedirectToIdentityProvider.HandledResponse");
_redirectToIdentityProviderSkipped = LoggerMessage.Define(
eventId: 7,
logLevel: LogLevel.Debug,
formatString: "RedirectToAuthenticationEndpoint.Skipped");
formatString: "RedirectToIdentityProvider.Skipped");
_invalidAuthenticationRequestUrl = LoggerMessage.Define<string>(
eventId: 8,
logLevel: LogLevel.Warning,
@ -106,18 +103,14 @@ namespace Microsoft.Extensions.Logging
eventId: 13,
logLevel: LogLevel.Debug,
formatString: "Updating configuration");
_authorizationResponseReceived = LoggerMessage.Define(
eventId: 14,
logLevel: LogLevel.Trace,
formatString: "Authorization response received.");
_authorizationResponseReceivedHandledResponse = LoggerMessage.Define(
_tokenValidatedHandledResponse = LoggerMessage.Define(
eventId: 15,
logLevel: LogLevel.Debug,
formatString: "AuthorizationResponseReceived.HandledResponse");
_authorizationResponseReceivedSkipped = LoggerMessage.Define(
formatString: "TokenValidated.HandledResponse");
_tokenValidatedSkipped = LoggerMessage.Define(
eventId: 16,
logLevel: LogLevel.Debug,
formatString: "AuthorizationResponseReceived.Skipped");
formatString: "TokenValidated.Skipped");
_exceptionProcessingMessage = LoggerMessage.Define(
eventId: 17,
logLevel: LogLevel.Error,
@ -174,22 +167,14 @@ namespace Microsoft.Extensions.Logging
eventId: 30,
logLevel: LogLevel.Trace,
formatString: "Token response received.");
_authorizationCodeRedeemedContextHandledResponse = LoggerMessage.Define(
_tokenResponseReceivedHandledResponse = LoggerMessage.Define(
eventId: 31,
logLevel: LogLevel.Debug,
formatString: "AuthorizationCodeRedeemedContext.HandledResponse");
_authorizationCodeRedeemedContextSkipped = LoggerMessage.Define(
formatString: "TokenResponseReceived.HandledResponse");
_tokenResponseReceivedSkipped = LoggerMessage.Define(
eventId: 32,
logLevel: LogLevel.Debug,
formatString: "AuthorizationCodeRedeemedContext.Skipped");
_authenticationValidatedHandledResponse = LoggerMessage.Define(
eventId: 33,
logLevel: LogLevel.Debug,
formatString: "AuthenticationFailedContext.HandledResponse");
_authenticationValidatedtSkipped = LoggerMessage.Define(
eventId: 34,
logLevel: LogLevel.Debug,
formatString: "AuthenticationFailedContext.Skipped");
formatString: "TokenResponseReceived.Skipped");
_userInformationReceived = LoggerMessage.Define<string>(
eventId: 35,
logLevel: LogLevel.Trace,
@ -258,19 +243,14 @@ namespace Microsoft.Extensions.Logging
_redeemingCodeForTokens(logger, null);
}
public static void AuthorizationResponseReceived(this ILogger logger)
public static void TokenValidatedHandledResponse(this ILogger logger)
{
_authorizationResponseReceived(logger, null);
_tokenValidatedHandledResponse(logger, null);
}
public static void AuthorizationResponseReceivedHandledResponse(this ILogger logger)
public static void TokenValidatedSkipped(this ILogger logger)
{
_authorizationResponseReceivedHandledResponse(logger, null);
}
public static void AuthorizationResponseReceivedSkipped(this ILogger logger)
{
_authorizationResponseReceivedSkipped(logger, null);
_tokenValidatedSkipped(logger, null);
}
public static void AuthorizationCodeReceivedContextHandledResponse(this ILogger logger)
@ -283,24 +263,14 @@ namespace Microsoft.Extensions.Logging
_authorizationCodeReceivedContextSkipped(logger, null);
}
public static void AuthorizationCodeRedeemedContextHandledResponse(this ILogger logger)
public static void TokenResponseReceivedHandledResponse(this ILogger logger)
{
_authorizationCodeRedeemedContextHandledResponse(logger, null);
_tokenResponseReceivedHandledResponse(logger, null);
}
public static void AuthorizationCodeRedeemedContextSkipped(this ILogger logger)
public static void TokenResponseReceivedSkipped(this ILogger logger)
{
_authorizationCodeRedeemedContextSkipped(logger, null);
}
public static void AuthenticationValidatedHandledResponse(this ILogger logger)
{
_authenticationValidatedHandledResponse(logger, null);
}
public static void AuthenticationValidatedSkipped(this ILogger logger)
{
_authenticationValidatedtSkipped(logger, null);
_tokenResponseReceivedSkipped(logger, null);
}
public static void AuthenticationFailedContextHandledResponse(this ILogger logger)
@ -328,24 +298,24 @@ namespace Microsoft.Extensions.Logging
_messageReceivedContextSkipped(logger, null);
}
public static void RedirectToEndSessionEndpointHandledResponse(this ILogger logger)
public static void RedirectToIdentityProviderForSignOutHandledResponse(this ILogger logger)
{
_redirectToEndSessionEndpointHandledResponse(logger, null);
_redirectToIdentityProviderForSignOutHandledResponse(logger, null);
}
public static void RedirectToEndSessionEndpointSkipped(this ILogger logger)
public static void RedirectToIdentityProviderForSignOutSkipped(this ILogger logger)
{
_redirectToEndSessionEndpointSkipped(logger, null);
_redirectToIdentityProviderForSignOutSkipped(logger, null);
}
public static void RedirectToAuthenticationEndpointHandledResponse(this ILogger logger)
public static void RedirectToIdentityProviderHandledResponse(this ILogger logger)
{
_redirectToAuthenticationEndpointHandledResponse(logger, null);
_redirectToIdentityProviderHandledResponse(logger, null);
}
public static void RedirectToAuthenticationEndpointSkipped(this ILogger logger)
public static void RedirectToIdentityProviderSkipped(this ILogger logger)
{
_redirectToAuthenticationEndpointSkipped(logger, null);
_redirectToIdentityProviderSkipped(logger, null);
}
public static void UserInformationReceivedHandledResponse(this ILogger logger)

View File

@ -111,15 +111,15 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
ProtocolMessage = message
};
await Options.Events.RedirectToEndSessionEndpoint(redirectContext);
await Options.Events.RedirectToIdentityProviderForSignOut(redirectContext);
if (redirectContext.HandledResponse)
{
Logger.RedirectToEndSessionEndpointHandledResponse();
Logger.RedirectToIdentityProviderForSignOutHandledResponse();
return;
}
else if (redirectContext.Skipped)
{
Logger.RedirectToEndSessionEndpointSkipped();
Logger.RedirectToIdentityProviderForSignOutSkipped();
return;
}
@ -169,7 +169,6 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
/// Responds to a 401 Challenge. Sends an OpenIdConnect message to the 'identity authority' to obtain an identity.
/// </summary>
/// <returns></returns>
/// <remarks>Uses log id's OIDCH-0026 - OIDCH-0050, next num: 37</remarks>
protected override async Task<bool> HandleUnauthorizedAsync(ChallengeContext context)
{
if (context == null)
@ -230,15 +229,15 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
ProtocolMessage = message
};
await Options.Events.RedirectToAuthenticationEndpoint(redirectContext);
await Options.Events.RedirectToIdentityProvider(redirectContext);
if (redirectContext.HandledResponse)
{
Logger.RedirectToAuthenticationEndpointHandledResponse();
Logger.RedirectToIdentityProviderHandledResponse();
return true;
}
else if (redirectContext.Skipped)
{
Logger.RedirectToAuthenticationEndpointSkipped();
Logger.RedirectToIdentityProviderSkipped();
return false;
}
@ -350,27 +349,38 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
try
{
var messageReceivedContext = await RunMessageReceivedEventAsync(authorizationResponse);
if (CheckEventResult(messageReceivedContext, out result))
AuthenticationProperties properties = null;
if (!string.IsNullOrEmpty(authorizationResponse.State))
{
properties = Options.StateDataFormat.Unprotect(authorizationResponse.State);
}
var messageReceivedContext = await RunMessageReceivedEventAsync(authorizationResponse, properties);
if (messageReceivedContext.CheckEventResult(out result))
{
return result;
}
authorizationResponse = messageReceivedContext.ProtocolMessage;
properties = messageReceivedContext.Properties;
// Fail if state is missing, it's required for the correlation id.
if (string.IsNullOrEmpty(authorizationResponse.State))
if (properties == null)
{
// This wasn't a valid OIDC message, it may not have been intended for us.
Logger.NullOrEmptyAuthorizationResponseState();
if (Options.SkipUnrecognizedRequests)
// Fail if state is missing, it's required for the correlation id.
if (string.IsNullOrEmpty(authorizationResponse.State))
{
return AuthenticateResult.Skip();
// This wasn't a valid OIDC message, it may not have been intended for us.
Logger.NullOrEmptyAuthorizationResponseState();
if (Options.SkipUnrecognizedRequests)
{
return AuthenticateResult.Skip();
}
return AuthenticateResult.Fail(Resources.MessageStateIsNullOrEmpty);
}
return AuthenticateResult.Fail(Resources.MessageStateIsNullOrEmpty);
// if state exists and we failed to 'unprotect' this is not a message we should process.
properties = Options.StateDataFormat.Unprotect(authorizationResponse.State);
}
// if state exists and we failed to 'unprotect' this is not a message we should process.
var properties = Options.StateDataFormat.Unprotect(Uri.UnescapeDataString(authorizationResponse.State));
if (properties == null)
{
Logger.UnableToReadAuthorizationResponseState();
@ -382,17 +392,6 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
return AuthenticateResult.Fail(Resources.MessageStateIsInvalid);
}
// if any of the error fields are set, throw error null
if (!string.IsNullOrEmpty(authorizationResponse.Error))
{
Logger.AuthorizationResponseError(
authorizationResponse.Error,
authorizationResponse.ErrorDescription ?? "ErrorDecription null",
authorizationResponse.ErrorUri ?? "ErrorUri null");
return AuthenticateResult.Fail(new OpenIdConnectProtocolException(string.Format(CultureInfo.InvariantCulture, Resources.MessageContainsError, authorizationResponse.Error, authorizationResponse.ErrorDescription ?? "ErrorDecription null", authorizationResponse.ErrorUri ?? "ErrorUri null")));
}
string userstate = null;
properties.Items.TryGetValue(OpenIdConnectDefaults.UserstatePropertiesKey, out userstate);
authorizationResponse.State = userstate;
@ -402,20 +401,25 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
return AuthenticateResult.Fail("Correlation failed.");
}
// if any of the error fields are set, throw error null
if (!string.IsNullOrEmpty(authorizationResponse.Error))
{
Logger.AuthorizationResponseError(
authorizationResponse.Error,
authorizationResponse.ErrorDescription ?? "ErrorDecription null",
authorizationResponse.ErrorUri ?? "ErrorUri null");
return AuthenticateResult.Fail(new OpenIdConnectProtocolException(
string.Format(CultureInfo.InvariantCulture, Resources.MessageContainsError, authorizationResponse.Error,
authorizationResponse.ErrorDescription ?? "ErrorDecription null", authorizationResponse.ErrorUri ?? "ErrorUri null")));
}
if (_configuration == null && Options.ConfigurationManager != null)
{
Logger.UpdatingConfiguration();
_configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.RequestAborted);
}
var authorizationResponseReceivedContext = await RunAuthorizationResponseReceivedEventAsync(authorizationResponse, properties);
if (CheckEventResult(authorizationResponseReceivedContext, out result))
{
return result;
}
authorizationResponse = authorizationResponseReceivedContext.ProtocolMessage;
properties = authorizationResponseReceivedContext.Properties;
PopulateSessionProperties(authorizationResponse, properties);
AuthenticationTicket ticket = null;
@ -434,6 +438,17 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
{
nonce = ReadNonceCookie(nonce);
}
var tokenValidatedContext = await RunTokenValidatedEventAsync(authorizationResponse, null, properties, ticket, jwt, nonce);
if (tokenValidatedContext.CheckEventResult(out result))
{
return result;
}
authorizationResponse = tokenValidatedContext.ProtocolMessage;
properties = tokenValidatedContext.Properties;
ticket = tokenValidatedContext.Ticket;
jwt = tokenValidatedContext.SecurityToken;
nonce = tokenValidatedContext.Nonce;
}
Options.ProtocolValidator.ValidateAuthenticationResponse(new OpenIdConnectProtocolValidationContext()
@ -444,15 +459,13 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
Nonce = nonce
});
// TODO: AuthorizationResponseValidated event?
OpenIdConnectMessage tokenEndpointResponse = null;
// Authorization Code or Hybrid flow
if (!string.IsNullOrEmpty(authorizationResponse.Code))
{
var authorizationCodeReceivedContext = await RunAuthorizationCodeReceivedEventAsync(authorizationResponse, properties, ticket, jwt);
if (CheckEventResult(authorizationCodeReceivedContext, out result))
if (authorizationCodeReceivedContext.CheckEventResult(out result))
{
return result;
}
@ -469,13 +482,13 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
tokenEndpointResponse = await RedeemAuthorizationCodeAsync(tokenEndpointRequest);
}
var authorizationCodeRedeemedContext = await RunTokenResponseReceivedEventAsync(authorizationResponse, tokenEndpointResponse, properties);
if (CheckEventResult(authorizationCodeRedeemedContext, out result))
var tokenResponseReceivedContext = await RunTokenResponseReceivedEventAsync(authorizationResponse, tokenEndpointResponse, properties);
if (tokenResponseReceivedContext.CheckEventResult(out result))
{
return result;
}
authorizationResponse = authorizationCodeRedeemedContext.ProtocolMessage;
tokenEndpointResponse = authorizationCodeRedeemedContext.TokenEndpointResponse;
authorizationResponse = tokenResponseReceivedContext.ProtocolMessage;
tokenEndpointResponse = tokenResponseReceivedContext.TokenEndpointResponse;
// We only have to process the IdToken if we didn't already get one in the AuthorizationResponse
if (ticket == null)
@ -491,6 +504,18 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
{
nonce = ReadNonceCookie(nonce);
}
var tokenValidatedContext = await RunTokenValidatedEventAsync(authorizationResponse, tokenEndpointResponse, properties, ticket, jwt, nonce);
if (tokenValidatedContext.CheckEventResult(out result))
{
return result;
}
authorizationResponse = tokenValidatedContext.ProtocolMessage;
tokenEndpointResponse = tokenValidatedContext.TokenEndpointResponse;
properties = tokenValidatedContext.Properties;
ticket = tokenValidatedContext.Ticket;
jwt = tokenValidatedContext.SecurityToken;
nonce = tokenValidatedContext.Nonce;
}
// Validate the token response if it wasn't provided manually
@ -506,15 +531,6 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
}
}
var authenticationValidatedContext = await RunAuthenticationValidatedEventAsync(authorizationResponse, ticket, properties, tokenEndpointResponse);
if (CheckEventResult(authenticationValidatedContext, out result))
{
return result;
}
authorizationResponse = authenticationValidatedContext.ProtocolMessage;
tokenEndpointResponse = authenticationValidatedContext.TokenEndpointResponse;
ticket = authenticationValidatedContext.Ticket;
if (Options.SaveTokens)
{
SaveTokens(ticket.Properties, tokenEndpointResponse ?? authorizationResponse);
@ -542,7 +558,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
}
var authenticationFailedContext = await RunAuthenticationFailedEventAsync(authorizationResponse, exception);
if (CheckEventResult(authenticationFailedContext, out result))
if (authenticationFailedContext.CheckEventResult(out result))
{
return result;
}
@ -551,22 +567,6 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
}
}
private bool CheckEventResult(BaseControlContext context, out AuthenticateResult result)
{
if (context.HandledResponse)
{
result = AuthenticateResult.Success(context.Ticket);
return true;
}
else if (context.Skipped)
{
result = AuthenticateResult.Skip();
return true;
}
result = null;
return false;
}
private void PopulateSessionProperties(OpenIdConnectMessage message, AuthenticationProperties properties)
{
if (!string.IsNullOrEmpty(message.SessionState))
@ -643,7 +643,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
var userInformationReceivedContext = await RunUserInformationReceivedEventAsync(ticket, message, user);
AuthenticateResult result;
if (CheckEventResult(userInformationReceivedContext, out result))
if (userInformationReceivedContext.CheckEventResult(out result))
{
return result;
}
@ -830,12 +830,13 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
}
}
private async Task<MessageReceivedContext> RunMessageReceivedEventAsync(OpenIdConnectMessage message)
private async Task<MessageReceivedContext> RunMessageReceivedEventAsync(OpenIdConnectMessage message, AuthenticationProperties properties)
{
Logger.MessageReceived(message.BuildRedirectUrl());
var messageReceivedContext = new MessageReceivedContext(Context, Options)
{
ProtocolMessage = message
ProtocolMessage = message,
Properties = properties,
};
await Options.Events.MessageReceived(messageReceivedContext);
@ -851,23 +852,29 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
return messageReceivedContext;
}
private async Task<AuthorizationResponseReceivedContext> RunAuthorizationResponseReceivedEventAsync(OpenIdConnectMessage message, AuthenticationProperties properties)
private async Task<TokenValidatedContext> RunTokenValidatedEventAsync(OpenIdConnectMessage authorizationResponse, OpenIdConnectMessage tokenEndpointResponse, AuthenticationProperties properties, AuthenticationTicket ticket, JwtSecurityToken jwt, string nonce)
{
Logger.AuthorizationResponseReceived();
var authorizationResponseReceivedContext = new AuthorizationResponseReceivedContext(Context, Options, properties)
var tokenValidatedContext = new TokenValidatedContext(Context, Options)
{
ProtocolMessage = message
ProtocolMessage = authorizationResponse,
TokenEndpointResponse = tokenEndpointResponse,
Properties = properties,
Ticket = ticket,
SecurityToken = jwt,
Nonce = nonce,
};
await Options.Events.AuthorizationResponseReceived(authorizationResponseReceivedContext);
if (authorizationResponseReceivedContext.HandledResponse)
await Options.Events.TokenValidated(tokenValidatedContext);
if (tokenValidatedContext.HandledResponse)
{
Logger.AuthorizationResponseReceivedHandledResponse();
Logger.TokenValidatedHandledResponse();
}
else if (authorizationResponseReceivedContext.Skipped)
else if (tokenValidatedContext.Skipped)
{
Logger.AuthorizationResponseReceivedSkipped();
Logger.TokenValidatedSkipped();
}
return authorizationResponseReceivedContext;
return tokenValidatedContext;
}
private async Task<AuthorizationCodeReceivedContext> RunAuthorizationCodeReceivedEventAsync(OpenIdConnectMessage authorizationResponse, AuthenticationProperties properties, AuthenticationTicket ticket, JwtSecurityToken jwt)
@ -909,46 +916,23 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
private async Task<TokenResponseReceivedContext> RunTokenResponseReceivedEventAsync(OpenIdConnectMessage message, OpenIdConnectMessage tokenEndpointResponse, AuthenticationProperties properties)
{
Logger.TokenResponseReceived();
var tokenResponseReceivedContext = new TokenResponseReceivedContext(Context, Options, properties)
var eventContext = new TokenResponseReceivedContext(Context, Options, properties)
{
ProtocolMessage = message,
TokenEndpointResponse = tokenEndpointResponse
};
await Options.Events.TokenResponseReceived(tokenResponseReceivedContext);
if (tokenResponseReceivedContext.HandledResponse)
await Options.Events.TokenResponseReceived(eventContext);
if (eventContext.HandledResponse)
{
Logger.AuthorizationCodeRedeemedContextHandledResponse();
Logger.TokenResponseReceivedHandledResponse();
}
else if (tokenResponseReceivedContext.Skipped)
else if (eventContext.Skipped)
{
Logger.AuthorizationCodeRedeemedContextSkipped();
Logger.TokenResponseReceivedSkipped();
}
return tokenResponseReceivedContext;
}
private async Task<AuthenticationValidatedContext> RunAuthenticationValidatedEventAsync(OpenIdConnectMessage message, AuthenticationTicket ticket, AuthenticationProperties properties, OpenIdConnectMessage tokenResponse)
{
var authenticationValidatedContext = new AuthenticationValidatedContext(Context, Options, properties)
{
Ticket = ticket,
ProtocolMessage = message,
TokenEndpointResponse = tokenResponse,
};
await Options.Events.AuthenticationValidated(authenticationValidatedContext);
if (authenticationValidatedContext.HandledResponse)
{
Logger.AuthenticationValidatedHandledResponse();
}
else if (authenticationValidatedContext.Skipped)
{
Logger.AuthenticationValidatedSkipped();
}
return authenticationValidatedContext;
return eventContext;
}
private async Task<UserInformationReceivedContext> RunUserInformationReceivedEventAsync(AuthenticationTicket ticket, OpenIdConnectMessage message, JObject user)

View File

@ -46,5 +46,21 @@ namespace Microsoft.AspNetCore.Authentication
/// Gets or set the <see cref="Ticket"/> to return if this event signals it handled the event.
/// </summary>
public AuthenticationTicket Ticket { get; set; }
public bool CheckEventResult(out AuthenticateResult result)
{
if (HandledResponse)
{
result = AuthenticateResult.Success(Ticket);
return true;
}
else if (Skipped)
{
result = AuthenticateResult.Skip();
return true;
}
result = null;
return false;
}
}
}

View File

@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
AutomaticAuthenticate = true,
Events = new JwtBearerEvents()
{
OnReceivingToken = context =>
OnMessageReceived = context =>
{
var claims = new[]
{
@ -143,39 +143,6 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
Assert.Equal("", response.ResponseText);
}
[Fact]
public async Task CustomTokenReceived()
{
var server = CreateServer(new JwtBearerOptions
{
AutomaticAuthenticate = true,
Events = new JwtBearerEvents()
{
OnReceivedToken = context =>
{
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, "Bob le Magnifique"),
new Claim(ClaimTypes.Email, "bob@contoso.com"),
new Claim(ClaimsIdentity.DefaultNameClaimType, "bob")
};
context.Ticket = new AuthenticationTicket(
new ClaimsPrincipal(new ClaimsIdentity(claims, context.Options.AuthenticationScheme)),
new AuthenticationProperties(), context.Options.AuthenticationScheme);
context.HandleResponse();
return Task.FromResult<object>(null);
}
}
});
var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob");
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
Assert.Equal("Bob le Magnifique", response.ResponseText);
}
[Fact]
public async Task CustomTokenValidated()
{
@ -184,7 +151,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
AutomaticAuthenticate = true,
Events = new JwtBearerEvents()
{
OnValidatedToken = context =>
OnTokenValidated = context =>
{
// Retrieve the NameIdentifier claim from the identity
// returned by the custom security token validator.
@ -204,6 +171,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
}
}
};
options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(new BlobTokenValidator(options.AuthenticationScheme));
var server = CreateServer(options);
@ -215,67 +183,37 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
public async Task RetrievingTokenFromAlternateLocation()
{
var server = CreateServer(new JwtBearerOptions
var options = new JwtBearerOptions()
{
AutomaticAuthenticate = true,
Events = new JwtBearerEvents()
{
OnReceivingToken = context =>
OnMessageReceived = context =>
{
context.Token = "CustomToken";
return Task.FromResult<object>(null);
},
OnReceivedToken = context =>
{
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, "Bob le Magnifique"),
new Claim(ClaimTypes.Email, "bob@contoso.com"),
new Claim(ClaimsIdentity.DefaultNameClaimType, "bob")
};
context.Ticket = new AuthenticationTicket(
new ClaimsPrincipal(new ClaimsIdentity(claims, context.Options.AuthenticationScheme)),
new AuthenticationProperties(), context.Options.AuthenticationScheme);
context.HandleResponse();
return Task.FromResult<object>(null);
}
}
});
};
options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT", token =>
{
Assert.Equal("CustomToken", token);
}));
var server = CreateServer(options);
var response = await SendAsync(server, "http://example.com/oauth", "Bearer Token");
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
Assert.Equal("Bob le Magnifique", response.ResponseText);
Assert.Equal("Bob le Tout Puissant", response.ResponseText);
}
[Fact]
public async Task BearerTurns401To403IfAuthenticated()
{
var server = CreateServer(new JwtBearerOptions
{
Events = new JwtBearerEvents()
{
OnReceivedToken = context =>
{
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, "Bob le Magnifique"),
new Claim(ClaimTypes.Email, "bob@contoso.com"),
new Claim(ClaimsIdentity.DefaultNameClaimType, "bob")
};
context.Ticket = new AuthenticationTicket(
new ClaimsPrincipal(new ClaimsIdentity(claims, context.Options.AuthenticationScheme)),
new AuthenticationProperties(), context.Options.AuthenticationScheme);
context.HandleResponse();
return Task.FromResult<object>(null);
}
}
});
var options = new JwtBearerOptions();
options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT"));
var server = CreateServer(options);
var response = await SendAsync(server, "http://example.com/unauthorized", "Bearer Token");
Assert.Equal(HttpStatusCode.Forbidden, response.Response.StatusCode);
@ -284,52 +222,26 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
public async Task BearerDoesNothingTo401IfNotAuthenticated()
{
var server = CreateServer(new JwtBearerOptions
{
Events = new JwtBearerEvents()
{
OnReceivedToken = context =>
{
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, "Bob le Magnifique"),
new Claim(ClaimTypes.Email, "bob@contoso.com"),
new Claim(ClaimsIdentity.DefaultNameClaimType, "bob")
};
context.Ticket = new AuthenticationTicket(
new ClaimsPrincipal(new ClaimsIdentity(claims, context.Options.AuthenticationScheme)),
new AuthenticationProperties(), context.Options.AuthenticationScheme);
context.HandleResponse();
return Task.FromResult<object>(null);
}
}
});
var server = CreateServer(new JwtBearerOptions());
var response = await SendAsync(server, "http://example.com/unauthorized");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
}
[Fact]
public async Task EventOnReceivingTokenSkipped_NoMoreEventsExecuted()
public async Task EventOnMessageReceivedSkipped_NoMoreEventsExecuted()
{
var server = CreateServer(new JwtBearerOptions
{
AutomaticAuthenticate = true,
Events = new JwtBearerEvents()
{
OnReceivingToken = context =>
OnMessageReceived = context =>
{
context.SkipToNextMiddleware();
return Task.FromResult(0);
},
OnReceivedToken = context =>
{
throw new NotImplementedException();
},
OnValidatedToken = context =>
OnTokenValidated = context =>
{
throw new NotImplementedException();
},
@ -350,47 +262,14 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
}
[Fact]
public async Task EventOnReceivedTokenSkipped_NoMoreEventsExecuted()
{
var server = CreateServer(new JwtBearerOptions
{
AutomaticAuthenticate = true,
Events = new JwtBearerEvents()
{
OnReceivedToken = context =>
{
context.SkipToNextMiddleware();
return Task.FromResult(0);
},
OnValidatedToken = context =>
{
throw new NotImplementedException();
},
OnAuthenticationFailed = context =>
{
throw new NotImplementedException(context.Exception.ToString());
},
OnChallenge = context =>
{
throw new NotImplementedException();
},
}
});
var response = await SendAsync(server, "http://example.com/checkforerrors", "Bearer Token");
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
Assert.Equal(string.Empty, response.ResponseText);
}
[Fact]
public async Task EventOnValidatedTokenSkipped_NoMoreEventsExecuted()
public async Task EventOnTokenValidatedSkipped_NoMoreEventsExecuted()
{
var options = new JwtBearerOptions
{
AutomaticAuthenticate = true,
Events = new JwtBearerEvents()
{
OnValidatedToken = context =>
OnTokenValidated = context =>
{
context.SkipToNextMiddleware();
return Task.FromResult(0);
@ -422,7 +301,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
AutomaticAuthenticate = true,
Events = new JwtBearerEvents()
{
OnValidatedToken = context =>
OnTokenValidated = context =>
{
throw new Exception("Test Exception");
},
@ -493,9 +372,17 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
class BlobTokenValidator : ISecurityTokenValidator
{
private Action<string> _tokenValidator;
public BlobTokenValidator(string authenticationScheme)
{
AuthenticationScheme = authenticationScheme;
}
public BlobTokenValidator(string authenticationScheme, Action<string> tokenValidator)
{
AuthenticationScheme = authenticationScheme;
_tokenValidator = tokenValidator;
}
public string AuthenticationScheme { get; }
@ -519,6 +406,10 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
{
validatedToken = null;
if (_tokenValidator != null)
{
_tokenValidator(securityToken);
}
var claims = new[]
{

View File

@ -150,12 +150,12 @@ namespace Microsoft.AspNetCore.Authentication.Tests.OpenIdConnect
options.AutomaticChallenge = true;
options.Events = new OpenIdConnectEvents()
{
OnRedirectToAuthenticationEndpoint = (context) =>
OnRedirectToIdentityProvider = (context) =>
{
context.ProtocolMessage = fakeOpenIdRequestMessage;
return Task.FromResult(0);
},
OnRedirectToEndSessionEndpoint = (context) =>
OnRedirectToIdentityProviderForSignOut = (context) =>
{
context.ProtocolMessage = fakeOpenIdRequestMessage;
return Task.FromResult(0);
@ -208,7 +208,7 @@ namespace Microsoft.AspNetCore.Authentication.Tests.OpenIdConnect
options.AutomaticChallenge = challenge.Equals(ChallengeWithOutContext);
options.Events = new OpenIdConnectEvents()
{
OnRedirectToAuthenticationEndpoint = context =>
OnRedirectToIdentityProvider = context =>
{
context.ProtocolMessage.State = userState;
context.ProtocolMessage.RedirectUri = queryValues.RedirectUri;
@ -258,7 +258,7 @@ namespace Microsoft.AspNetCore.Authentication.Tests.OpenIdConnect
var options = GetOptions(DefaultParameters(), queryValues);
options.Events = new OpenIdConnectEvents()
{
OnRedirectToAuthenticationEndpoint = context =>
OnRedirectToIdentityProvider = context =>
{
context.ProtocolMessage.ClientId = queryValuesSetInEvent.ClientId;
context.ProtocolMessage.RedirectUri = queryValuesSetInEvent.RedirectUri;