diff --git a/samples/Mvc.Server/Controllers/AuthorizationController.cs b/samples/Mvc.Server/Controllers/AuthorizationController.cs index f86e4c7b..3290abce 100644 --- a/samples/Mvc.Server/Controllers/AuthorizationController.cs +++ b/samples/Mvc.Server/Controllers/AuthorizationController.cs @@ -18,6 +18,7 @@ using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Mvc.Server.Models; using Mvc.Server.ViewModels.Authorization; +using Mvc.Server.ViewModels.Shared; using OpenIddict; namespace Mvc.Server { @@ -115,20 +116,5 @@ namespace Mvc.Server { // to the post_logout_redirect_uri specified by the client application. return SignOut(OpenIdConnectServerDefaults.AuthenticationScheme); } - - [HttpGet, HttpPost, Route("~/connect/error")] - public IActionResult Error() { - var response = HttpContext.GetOpenIdConnectResponse(); - if (response == null) { - return View(new ErrorViewModel { - Error = OpenIdConnectConstants.Errors.InvalidRequest - }); - } - - return View(new ErrorViewModel { - Error = response.Error, - ErrorDescription = response.ErrorDescription - }); - } } } \ No newline at end of file diff --git a/samples/Mvc.Server/Controllers/ErrorController.cs b/samples/Mvc.Server/Controllers/ErrorController.cs new file mode 100644 index 00000000..eefffc58 --- /dev/null +++ b/samples/Mvc.Server/Controllers/ErrorController.cs @@ -0,0 +1,28 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Mvc; +using Mvc.Server.ViewModels.Shared; + +namespace Mvc.Server { + public class ErrorController : Controller { + [HttpGet, HttpPost, Route("~/error")] + public IActionResult Error() { + // If the error was not caused by an invalid + // OIDC request, display a generic error page. + var response = HttpContext.GetOpenIdConnectResponse(); + if (response == null) { + return View(); + } + + return View(new ErrorViewModel { + Error = response.Error, + ErrorDescription = response.ErrorDescription + }); + } + } +} \ No newline at end of file diff --git a/samples/Mvc.Server/Startup.cs b/samples/Mvc.Server/Startup.cs index 7388fb78..d994292e 100644 --- a/samples/Mvc.Server/Startup.cs +++ b/samples/Mvc.Server/Startup.cs @@ -33,7 +33,6 @@ namespace Mvc.Server { services.AddOpenIddict, ApplicationDbContext, Guid>() .SetAuthorizationEndpointPath("/connect/authorize") .SetLogoutEndpointPath("/connect/logout") - .SetErrorHandlingPath("/connect/error") // During development, you can disable the HTTPS requirement. .DisableHttpsRequirement(); @@ -115,6 +114,8 @@ namespace Mvc.Server { ConsumerSecret = "Il2eFzGIrYhz6BWjYhVXBPQSfZuS4xoHpSSyD9PI" }); + app.UseStatusCodePagesWithReExecute("/error"); + app.UseOpenIddict(); app.UseMvcWithDefaultRoute(); diff --git a/samples/Mvc.Server/ViewModels/Authorization/ErrorViewModel.cs b/samples/Mvc.Server/ViewModels/Shared/ErrorViewModel.cs similarity index 84% rename from samples/Mvc.Server/ViewModels/Authorization/ErrorViewModel.cs rename to samples/Mvc.Server/ViewModels/Shared/ErrorViewModel.cs index 631083d4..aebc2452 100644 --- a/samples/Mvc.Server/ViewModels/Authorization/ErrorViewModel.cs +++ b/samples/Mvc.Server/ViewModels/Shared/ErrorViewModel.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Mvc.Server.ViewModels.Authorization { +namespace Mvc.Server.ViewModels.Shared { public class ErrorViewModel { [Display(Name = "Error")] public string Error { get; set; } diff --git a/samples/Mvc.Server/Views/Authorization/Error.cshtml b/samples/Mvc.Server/Views/Authorization/Error.cshtml deleted file mode 100644 index efe5e0a2..00000000 --- a/samples/Mvc.Server/Views/Authorization/Error.cshtml +++ /dev/null @@ -1,12 +0,0 @@ -@model ErrorViewModel - -
-

Ooooops, something went really bad with your OpenID Connect request! :(

-

- @Model.Error - - @if (!string.IsNullOrEmpty(Model.ErrorDescription)) { - @Model.ErrorDescription - } -

-
\ No newline at end of file diff --git a/samples/Mvc.Server/Views/Shared/Error.cshtml b/samples/Mvc.Server/Views/Shared/Error.cshtml index 48524426..1b5c5de8 100644 --- a/samples/Mvc.Server/Views/Shared/Error.cshtml +++ b/samples/Mvc.Server/Views/Shared/Error.cshtml @@ -1,6 +1,14 @@ -@{ - ViewData["Title"] = "Error"; -} +@model ErrorViewModel + +
+

Ooooops, something went really bad! :(

+

+ @if (!string.IsNullOrEmpty(Model.Error)) { + @Model.Error + } -

Error.

-

An error occurred while processing your request.

+ @if (!string.IsNullOrEmpty(Model.ErrorDescription)) { + @Model.ErrorDescription + } +

+
\ No newline at end of file diff --git a/samples/Mvc.Server/Views/_ViewImports.cshtml b/samples/Mvc.Server/Views/_ViewImports.cshtml index c2721a8f..e8080468 100644 --- a/samples/Mvc.Server/Views/_ViewImports.cshtml +++ b/samples/Mvc.Server/Views/_ViewImports.cshtml @@ -3,5 +3,6 @@ @using Mvc.Server.ViewModels.Account @using Mvc.Server.ViewModels.Authorization @using Mvc.Server.ViewModels.Manage +@using Mvc.Server.ViewModels.Shared @using Microsoft.AspNetCore.Identity @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Authentication.cs b/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Authentication.cs index 61a60180..d5836218 100644 --- a/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Authentication.cs +++ b/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Authentication.cs @@ -14,6 +14,7 @@ using AspNet.Security.OpenIdConnect.Server; using JetBrains.Annotations; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Http.Authentication; using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.Caching.Distributed; @@ -343,18 +344,25 @@ namespace OpenIddict.Infrastructure { await services.Options.Cache.RemoveAsync(OpenIddictConstants.Environment.Request + context.Request.GetRequestId()); } - if (!string.IsNullOrEmpty(context.Response.Error) && services.Options.ErrorHandlingPath.HasValue) { - // Rewrite the request path to point to the error handler path. - context.HttpContext.Request.Path = services.Options.ErrorHandlingPath; - - // Replace the default status code to return a 400 response. - context.HttpContext.Response.StatusCode = 400; - - // Store the OpenID Connect response in the HTTP context to allow retrieving it - // from user code (e.g from an ASP.NET Core MVC controller or a Nancy module). - context.HttpContext.SetOpenIdConnectResponse(context.Response); - - context.SkipToNextMiddleware(); + if (!context.Options.ApplicationCanDisplayErrors && !string.IsNullOrEmpty(context.Response.Error) && + string.IsNullOrEmpty(context.Response.RedirectUri)) { + // Determine if the status code pages middleware has been enabled for this request. + // If it was not registered or disabled, let the OpenID Connect server middleware render + // a default error page instead of delegating the rendering to the status code middleware. + var feature = context.HttpContext.Features.Get(); + if (feature != null && feature.Enabled) { + // Replace the default status code to return a 400 response. + context.HttpContext.Response.StatusCode = 400; + + // Store the OpenID Connect response in the HTTP context to allow retrieving it + // from user code (e.g from an ASP.NET Core MVC controller or a Nancy module). + context.HttpContext.SetOpenIdConnectResponse(context.Response); + + // Mark the request as fully handled to prevent the OpenID Connect server middleware + // from displaying the default error page and to allow the status code pages middleware + // to rewrite the response using the logic defined by the developer when registering it. + context.HandleResponse(); + } } } } diff --git a/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Session.cs b/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Session.cs index a91c8b0d..2d10d04d 100644 --- a/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Session.cs +++ b/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Session.cs @@ -11,6 +11,7 @@ using AspNet.Security.OpenIdConnect.Extensions; using AspNet.Security.OpenIdConnect.Server; using JetBrains.Annotations; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -108,20 +109,25 @@ namespace OpenIddict.Infrastructure { } public override Task ApplyLogoutResponse([NotNull] ApplyLogoutResponseContext context) { - var services = context.HttpContext.RequestServices.GetRequiredService>(); - - if (!string.IsNullOrEmpty(context.Response.Error) && services.Options.ErrorHandlingPath.HasValue) { - // Rewrite the request path to point to the error handler path. - context.HttpContext.Request.Path = services.Options.ErrorHandlingPath; - - // Replace the default status code to return a 400 response. - context.HttpContext.Response.StatusCode = 400; - - // Store the OpenID Connect response in the HTTP context to allow retrieving it - // from user code (e.g from an ASP.NET Core MVC controller or a Nancy module). - context.HttpContext.SetOpenIdConnectResponse(context.Response); - - context.SkipToNextMiddleware(); + if (!context.Options.ApplicationCanDisplayErrors && !string.IsNullOrEmpty(context.Response.Error) && + string.IsNullOrEmpty(context.Response.PostLogoutRedirectUri)) { + // Determine if the status code pages middleware has been enabled for this request. + // If it was not registered or disabled, let the OpenID Connect server middleware render + // a default error page instead of delegating the rendering to the status code middleware. + var feature = context.HttpContext.Features.Get(); + if (feature != null && feature.Enabled) { + // Replace the default status code to return a 400 response. + context.HttpContext.Response.StatusCode = 400; + + // Store the OpenID Connect response in the HTTP context to allow retrieving it + // from user code (e.g from an ASP.NET Core MVC controller or a Nancy module). + context.HttpContext.SetOpenIdConnectResponse(context.Response); + + // Mark the request as fully handled to prevent the OpenID Connect server middleware + // from displaying the default error page and to allow the status code pages middleware + // to rewrite the response using the logic defined by the developer when registering it. + context.HandleResponse(); + } } return Task.FromResult(0); diff --git a/src/OpenIddict.Core/OpenIddictBuilder.cs b/src/OpenIddict.Core/OpenIddictBuilder.cs index 239763cf..c33517a1 100644 --- a/src/OpenIddict.Core/OpenIddictBuilder.cs +++ b/src/OpenIddict.Core/OpenIddictBuilder.cs @@ -385,16 +385,6 @@ namespace Microsoft.AspNetCore.Builder { return Configure(options => options.AuthorizationEndpointPath = path); } - /// - /// Sets the relative path corresponding to the middleware or controller action responsible - /// of rendering the OpenID Connect errors occurred during interactive workflows. - /// - /// The relative path of the error handler. - /// The . - public virtual OpenIddictBuilder SetErrorHandlingPath(PathString path) { - return Configure(options => options.ErrorHandlingPath = path); - } - /// /// Sets the relative path corresponding to the logout endpoint. /// diff --git a/src/OpenIddict.Core/OpenIddictOptions.cs b/src/OpenIddict.Core/OpenIddictOptions.cs index eafc073f..cfaf25ec 100644 --- a/src/OpenIddict.Core/OpenIddictOptions.cs +++ b/src/OpenIddict.Core/OpenIddictOptions.cs @@ -30,12 +30,6 @@ namespace OpenIddict { /// public IDistributedCache Cache { get; set; } - /// - /// Gets or sets the path of the middleware responsible of rendering - /// the OpenID Connect errors occurred during interactive workflows. - /// - public PathString ErrorHandlingPath { get; set; } - /// /// Gets the list of the OpenIddict modules registered in the application. /// diff --git a/src/OpenIddict.Core/project.json b/src/OpenIddict.Core/project.json index a63a4d88..f1d8c6f5 100644 --- a/src/OpenIddict.Core/project.json +++ b/src/OpenIddict.Core/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.0.0-alpha2-*", "description": "Core components of OpenIddict.", @@ -36,6 +36,7 @@ "AspNet.Security.OpenIdConnect.Server": "1.0.0-beta6-final", "CryptoHelper": "2.0.0", "JetBrains.Annotations": { "type": "build", "version": "10.1.4" }, + "Microsoft.AspNetCore.Diagnostics.Abstractions": "1.0.0", "Microsoft.AspNetCore.Identity": "1.0.0", "Microsoft.Extensions.Caching.Memory": "1.0.0" },