protected override async Task HandleSignOutAsync(SignOutContext context)
        {
            // request may be null when no logout request has been received
            // or has been already handled by InvokeLogoutEndpointAsync.
            var request = Context.GetOpenIdConnectRequest();

            if (request == null)
            {
                return;
            }

            // Stop processing the request if there's no signout context that matches
            // the authentication type associated with this middleware instance
            // or if the response status code doesn't indicate a successful response.
            if (context == null || Response.StatusCode != 200)
            {
                return;
            }

            // post_logout_redirect_uri is added to the response message since it can be
            // set or replaced from the ValidateClientLogoutRedirectUri event.
            var response = new OpenIdConnectMessage {
                PostLogoutRedirectUri = request.PostLogoutRedirectUri,
                State = request.State
            };

            var notification = new ApplyLogoutResponseContext(Context, Options, request, response);
            await Options.Provider.ApplyLogoutResponse(notification);

            if (notification.HandledResponse)
            {
                return;
            }

            else if (notification.Skipped)
            {
                return;
            }

            // Stop processing the request if no explicit
            // post_logout_redirect_uri has been provided.
            if (string.IsNullOrEmpty(response.PostLogoutRedirectUri))
            {
                return;
            }

            var location = response.PostLogoutRedirectUri;

            foreach (var parameter in response.Parameters)
            {
                // Don't include post_logout_redirect_uri in the query string.
                if (string.Equals(parameter.Key, OpenIdConnectParameterNames.PostLogoutRedirectUri, StringComparison.Ordinal))
                {
                    continue;
                }

                location = QueryHelpers.AddQueryString(location, parameter.Key, parameter.Value);
            }

            Response.Redirect(location);
        }
        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;
            }

            // Create a new parameters dictionary holding the name/value pairs.
            var parameters = new Dictionary <string, string>();

            foreach (var parameter in response.GetParameters())
            {
                // Ignore null or empty parameters, including JSON
                // objects that can't be represented as strings.
                var value = (string)parameter.Value;
                if (string.IsNullOrEmpty(value))
                {
                    continue;
                }

                parameters.Add(parameter.Key, value);
            }

            Logger.LogInformation("The logout response was successfully returned to '{PostLogoutRedirectUri}': {Response}.",
                                  notification.PostLogoutRedirectUri, response);

            var location = QueryHelpers.AddQueryString(notification.PostLogoutRedirectUri, parameters);

            Response.Redirect(location);
            return(true);
        }
Beispiel #3
0
 /// <summary>
 /// Called before the LogoutEndpoint endpoint redirects its response to the caller.
 /// If the web application wishes to produce the authorization response directly in the LogoutEndpoint call it may write to the
 /// context.Response directly and should call context.RequestCompleted to stop other handlers from executing.
 /// This call may also be used to add additional response parameters to the authorization response.
 /// </summary>
 /// <param name="context">The context of the event carries information in and results out.</param>
 /// <returns>Task to enable asynchronous execution</returns>
 public virtual Task ApplyLogoutResponse(ApplyLogoutResponseContext context) => OnApplyLogoutResponse(context);
Beispiel #4
0
        private async Task <bool> SendLogoutResponseAsync(OpenIdConnectResponse response)
        {
            var request = Context.GetOpenIdConnectRequest();

            if (request == null)
            {
                request = new OpenIdConnectRequest();
            }

            Context.SetOpenIdConnectResponse(response);

            var notification = new ApplyLogoutResponseContext(Context, Options, request, response);
            await Options.Provider.ApplyLogoutResponse(notification);

            if (notification.HandledResponse)
            {
                return(true);
            }

            else if (notification.Skipped)
            {
                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);
                }

                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(response.PostLogoutRedirectUri))
            {
                return(true);
            }

            // Create a new parameters dictionary holding the name/value pairs.
            var parameters = new Dictionary <string, string>();

            foreach (var parameter in response.GetParameters())
            {
                // Don't include post_logout_redirect_uri in the parameters dictionary.
                if (string.Equals(parameter.Key, OpenIdConnectConstants.Parameters.PostLogoutRedirectUri, StringComparison.Ordinal))
                {
                    continue;
                }

                var value = parameter.Value as JValue;
                if (value == null)
                {
                    Logger.LogWarning("A parameter whose type was incompatible was ignored and excluded " +
                                      "from the logout response: '{Parameter}'.", parameter.Key);

                    continue;
                }

                parameters.Add(parameter.Key, (string)value);
            }

            var location = QueryHelpers.AddQueryString(response.PostLogoutRedirectUri, parameters);

            Response.Redirect(location);
            return(true);
        }
Beispiel #5
0
        private async Task <bool> SendLogoutResponseAsync(OpenIdConnectMessage request, OpenIdConnectMessage response)
        {
            if (request == null)
            {
                request = new OpenIdConnectMessage();
            }

            var notification = new ApplyLogoutResponseContext(Context, Options, request, response);
            await Options.Provider.ApplyLogoutResponse(notification);

            if (notification.HandledResponse)
            {
                return(true);
            }

            else if (notification.Skipped)
            {
                return(false);
            }

            if (!string.IsNullOrEmpty(response.Error))
            {
                // When returning an error, remove the authorization request from the OWIN context
                // to inform TeardownCoreAsync that there's nothing more to handle.
                Context.SetOpenIdConnectRequest(request: null);

                // Apply a 400 status code by default.
                Response.StatusCode = 400;

                if (Options.ApplicationCanDisplayErrors)
                {
                    Context.SetOpenIdConnectResponse(response);

                    // Return false to allow the rest of
                    // the pipeline to handle the request.
                    return(false);
                }

                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(response.PostLogoutRedirectUri))
            {
                return(true);
            }

            var location = response.PostLogoutRedirectUri;

            foreach (var parameter in response.Parameters)
            {
                // Don't include post_logout_redirect_uri in the query string.
                if (string.Equals(parameter.Key, OpenIdConnectParameterNames.PostLogoutRedirectUri, StringComparison.Ordinal))
                {
                    continue;
                }

                location = QueryHelpers.AddQueryString(location, parameter.Key, parameter.Value);
            }

            Response.Redirect(location);

            return(true);
        }
        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);
        }
Beispiel #7
0
        private async Task <bool> SendLogoutResponseAsync(OpenIdConnectResponse response)
        {
            var request = Context.GetOpenIdConnectRequest();

            Context.SetOpenIdConnectResponse(response);

            response.SetProperty(OpenIdConnectConstants.Properties.MessageType,
                                 OpenIdConnectConstants.MessageTypes.LogoutResponse);

            var notification = new ApplyLogoutResponseContext(Context, Options, request, response);
            await Options.Provider.ApplyLogoutResponse(notification);

            if (notification.HandledResponse)
            {
                Logger.LogDebug("The logout request was handled in user code.");

                return(true);
            }

            else if (notification.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));
            }

            Logger.LogInformation("The logout response was successfully returned: {Response}", 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(response.PostLogoutRedirectUri))
            {
                return(true);
            }

            // Create a new parameters dictionary holding the name/value pairs.
            var parameters = new Dictionary <string, string>();

            foreach (var parameter in response.GetParameters())
            {
                // Don't include post_logout_redirect_uri in the parameters dictionary.
                if (string.Equals(parameter.Key, OpenIdConnectConstants.Parameters.PostLogoutRedirectUri, StringComparison.Ordinal))
                {
                    continue;
                }

                // Ignore null or empty parameters, including JSON
                // objects that can't be represented as strings.
                var value = (string)parameter.Value;
                if (string.IsNullOrEmpty(value))
                {
                    continue;
                }

                parameters.Add(parameter.Key, value);
            }

            var location = QueryHelpers.AddQueryString(response.PostLogoutRedirectUri, parameters);

            Response.Redirect(location);
            return(true);
        }