#942 Add the SignedOutCallbackRedirect event for OIDC

This commit is contained in:
Chris Ross (ASP.NET) 2017-09-21 12:28:24 -07:00
parent 31dd4ebd9c
commit 13fdbac48f
5 changed files with 643 additions and 583 deletions

View File

@ -38,6 +38,11 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
/// </summary> /// </summary>
public Func<RedirectContext, Task> OnRedirectToIdentityProviderForSignOut { get; set; } = context => Task.CompletedTask; public Func<RedirectContext, Task> OnRedirectToIdentityProviderForSignOut { get; set; } = context => Task.CompletedTask;
/// <summary>
/// Invoked before redirecting to the <see cref="OpenIdConnectOptions.SignedOutRedirectUri"/> at the end of a remote sign-out flow.
/// </summary>
public Func<RemoteSignOutContext, Task> OnSignedOutCallbackRedirect { get; set; } = context => Task.CompletedTask;
/// <summary> /// <summary>
/// Invoked when a request is received on the RemoteSignOutPath. /// Invoked when a request is received on the RemoteSignOutPath.
/// </summary> /// </summary>
@ -68,6 +73,8 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
public virtual Task RedirectToIdentityProviderForSignOut(RedirectContext context) => OnRedirectToIdentityProviderForSignOut(context); public virtual Task RedirectToIdentityProviderForSignOut(RedirectContext context) => OnRedirectToIdentityProviderForSignOut(context);
public virtual Task SignedOutCallbackRedirect(RemoteSignOutContext context) => OnSignedOutCallbackRedirect(context);
public virtual Task RemoteSignOut(RemoteSignOutContext context) => OnRemoteSignOut(context); public virtual Task RemoteSignOut(RemoteSignOutContext context) => OnRemoteSignOut(context);
public virtual Task TokenResponseReceived(TokenResponseReceivedContext context) => OnTokenResponseReceived(context); public virtual Task TokenResponseReceived(TokenResponseReceivedContext context) => OnTokenResponseReceived(context);

View File

@ -9,6 +9,8 @@ namespace Microsoft.Extensions.Logging
{ {
private static Action<ILogger, Exception> _redirectToIdentityProviderForSignOutHandledResponse; private static Action<ILogger, Exception> _redirectToIdentityProviderForSignOutHandledResponse;
private static Action<ILogger, Exception> _redirectToIdentityProviderHandledResponse; private static Action<ILogger, Exception> _redirectToIdentityProviderHandledResponse;
private static Action<ILogger, Exception> _signoutCallbackRedirectHandledResponse;
private static Action<ILogger, Exception> _signoutCallbackRedirectSkipped;
private static Action<ILogger, Exception> _updatingConfiguration; private static Action<ILogger, Exception> _updatingConfiguration;
private static Action<ILogger, Exception> _receivedIdToken; private static Action<ILogger, Exception> _receivedIdToken;
private static Action<ILogger, Exception> _redeemingCodeForTokens; private static Action<ILogger, Exception> _redeemingCodeForTokens;
@ -248,6 +250,14 @@ namespace Microsoft.Extensions.Logging
eventId: 49, eventId: 49,
logLevel: LogLevel.Information, logLevel: LogLevel.Information,
formatString: "AuthenticationScheme: {AuthenticationScheme} signed out."); formatString: "AuthenticationScheme: {AuthenticationScheme} signed out.");
_signoutCallbackRedirectHandledResponse = LoggerMessage.Define(
eventId: 50,
logLevel: LogLevel.Debug,
formatString: "RedirectToSignedOutRedirectUri.HandledResponse");
_signoutCallbackRedirectSkipped = LoggerMessage.Define(
eventId: 51,
logLevel: LogLevel.Debug,
formatString: "RedirectToSignedOutRedirectUri.Skipped");
} }
public static void UpdatingConfiguration(this ILogger logger) public static void UpdatingConfiguration(this ILogger logger)
@ -345,6 +355,16 @@ namespace Microsoft.Extensions.Logging
_redirectToIdentityProviderHandledResponse(logger, null); _redirectToIdentityProviderHandledResponse(logger, null);
} }
public static void SignoutCallbackRedirectHandledResponse(this ILogger logger)
{
_signoutCallbackRedirectHandledResponse(logger, null);
}
public static void SignoutCallbackRedirectSkipped(this ILogger logger)
{
_signoutCallbackRedirectSkipped(logger, null);
}
public static void UserInformationReceivedHandledResponse(this ILogger logger) public static void UserInformationReceivedHandledResponse(this ILogger logger)
{ {
_userInformationReceivedHandledResponse(logger, null); _userInformationReceivedHandledResponse(logger, null);

View File

@ -122,6 +122,10 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
Logger.RemoteSignOutSkipped(); Logger.RemoteSignOutSkipped();
return false; return false;
} }
if (remoteSignOutContext.Result.Failure != null)
{
throw new InvalidOperationException("An error was returned from the RemoteSignOut event.", remoteSignOutContext.Result.Failure);
}
} }
if (message == null) if (message == null)
@ -273,18 +277,46 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
/// Response to the callback from OpenId provider after session ended. /// Response to the callback from OpenId provider after session ended.
/// </summary> /// </summary>
/// <returns>A task executing the callback procedure</returns> /// <returns>A task executing the callback procedure</returns>
protected virtual Task<bool> HandleSignOutCallbackAsync() protected async virtual Task<bool> HandleSignOutCallbackAsync()
{ {
if (Request.Query.TryGetValue(OpenIdConnectParameterNames.State, out StringValues protectedState)) var message = new OpenIdConnectMessage(Request.Query.Select(pair => new KeyValuePair<string, string[]>(pair.Key, pair.Value)));
AuthenticationProperties properties = null;
if (!string.IsNullOrEmpty(message.State))
{ {
var properties = Options.StateDataFormat.Unprotect(protectedState); properties = Options.StateDataFormat.Unprotect(message.State);
if (!string.IsNullOrEmpty(properties?.RedirectUri)) }
var signOut = new RemoteSignOutContext(Context, Scheme, Options, message)
{
Properties = properties,
};
await Events.SignedOutCallbackRedirect(signOut);
if (signOut.Result != null)
{
if (signOut.Result.Handled)
{ {
Response.Redirect(properties.RedirectUri); Logger.SignoutCallbackRedirectHandledResponse();
return true;
}
if (signOut.Result.Skipped)
{
Logger.SignoutCallbackRedirectSkipped();
return false;
}
if (signOut.Result.Failure != null)
{
throw new InvalidOperationException("An error was returned from the SignedOutCallbackRedirect event.", signOut.Result.Failure);
} }
} }
return Task.FromResult(true); properties = signOut.Properties;
if (!string.IsNullOrEmpty(properties?.RedirectUri))
{
Response.Redirect(properties.RedirectUri);
}
return true;
} }
/// <summary> /// <summary>

View File

@ -93,6 +93,10 @@ namespace Microsoft.AspNetCore.Authentication
{ {
return false; return false;
} }
else if (errorContext.Result.Failure != null)
{
throw new InvalidOperationException("An error was returned from the RemoteFailure event.", errorContext.Result.Failure);
}
} }
throw exception; throw exception;