private async Task <bool> SendLogoutResponseAsync(OpenIdConnectResponse response) { var request = Context.GetOpenIdConnectRequest(); Context.SetOpenIdConnectResponse(response); response.SetProperty(OpenIdConnectConstants.Properties.MessageType, OpenIdConnectConstants.MessageTypes.LogoutResponse); // Note: as this stage, the request may be null (e.g if it couldn't be extracted from the HTTP request). var notification = new ApplyLogoutResponseContext(Context, Scheme, Options, request, response) { PostLogoutRedirectUri = request?.GetProperty <string>(OpenIdConnectConstants.Properties.PostLogoutRedirectUri) }; await Provider.ApplyLogoutResponse(notification); if (notification.Result != null) { if (notification.Result.Handled) { Logger.LogDebug("The logout request was handled in user code."); return(true); } else if (notification.Result.Skipped) { Logger.LogDebug("The default logout request handling was skipped from user code."); return(false); } } if (!string.IsNullOrEmpty(response.Error)) { // Apply a 400 status code by default. Response.StatusCode = 400; if (Options.ApplicationCanDisplayErrors) { // Return false to allow the rest of // the pipeline to handle the request. return(false); } Logger.LogInformation("The logout response was successfully returned " + "as a plain-text document: {Response}.", response); return(await SendNativePageAsync(response)); } // Don't redirect the user agent if no explicit post_logout_redirect_uri was // provided or if the URI was not fully validated by the application code. if (string.IsNullOrEmpty(notification.PostLogoutRedirectUri)) { Logger.LogInformation("The logout response was successfully returned: {Response}.", response); return(true); } // At this stage, throw an exception if the request was not properly extracted, if (request == null) { throw new InvalidOperationException("The logout response cannot be returned."); } // Attach the request state to the end session response. if (string.IsNullOrEmpty(response.State)) { response.State = request.State; } // Note: a dictionary is deliberately not used here to allow multiple parameters with the // same name to be specified. While initially not allowed by the core OAuth2 specification, // this is now accepted by derived drafts like the OAuth2 token exchange specification. // For consistency, multiple parameters with the same name are also supported by this endpoint. var parameters = new List <KeyValuePair <string, string> >(); foreach (var parameter in response.GetParameters()) { var values = (string[])parameter.Value; if (values == null) { continue; } foreach (var value in values) { parameters.Add(new KeyValuePair <string, string>(parameter.Key, value)); } } Logger.LogInformation("The logout response was successfully returned to '{PostLogoutRedirectUri}': {Response}.", notification.PostLogoutRedirectUri, response); var location = notification.PostLogoutRedirectUri; foreach (var parameter in parameters) { location = QueryHelpers.AddQueryString(location, parameter.Key, parameter.Value); } Response.Redirect(location); return(true); }
/// <summary> /// Represents an event called before the logout response is returned to the caller. /// </summary> /// <param name="context">The context instance associated with this event.</param> /// <returns>A <see cref="Task"/> that can be used to monitor the asynchronous operation.</returns> public virtual Task ApplyLogoutResponse(ApplyLogoutResponseContext context) => OnApplyLogoutResponse(context);