Browse Source

Replace the internal error handling logic by the status code pages stack

pull/157/head
Kévin Chalet 10 years ago
parent
commit
696b883d4d
  1. 16
      samples/Mvc.Server/Controllers/AuthorizationController.cs
  2. 28
      samples/Mvc.Server/Controllers/ErrorController.cs
  3. 3
      samples/Mvc.Server/Startup.cs
  4. 2
      samples/Mvc.Server/ViewModels/Shared/ErrorViewModel.cs
  5. 12
      samples/Mvc.Server/Views/Authorization/Error.cshtml
  6. 18
      samples/Mvc.Server/Views/Shared/Error.cshtml
  7. 1
      samples/Mvc.Server/Views/_ViewImports.cshtml
  8. 32
      src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Authentication.cs
  9. 34
      src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Session.cs
  10. 10
      src/OpenIddict.Core/OpenIddictBuilder.cs
  11. 6
      src/OpenIddict.Core/OpenIddictOptions.cs
  12. 3
      src/OpenIddict.Core/project.json

16
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
});
}
}
}

28
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
});
}
}
}

3
samples/Mvc.Server/Startup.cs

@ -33,7 +33,6 @@ namespace Mvc.Server {
services.AddOpenIddict<ApplicationUser, IdentityRole<Guid>, 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();

2
samples/Mvc.Server/ViewModels/Authorization/ErrorViewModel.cs → 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; }

12
samples/Mvc.Server/Views/Authorization/Error.cshtml

@ -1,12 +0,0 @@
@model ErrorViewModel
<div class="jumbotron">
<h2>Ooooops, something went really bad with your OpenID Connect request! :(</h2>
<p class="lead text-left">
<strong>@Model.Error</strong>
@if (!string.IsNullOrEmpty(Model.ErrorDescription)) {
<small>@Model.ErrorDescription</small>
}
</p>
</div>

18
samples/Mvc.Server/Views/Shared/Error.cshtml

@ -1,6 +1,14 @@
@{
ViewData["Title"] = "Error";
}
@model ErrorViewModel
<div class="jumbotron">
<h2>Ooooops, something went really bad! :(</h2>
<p class="lead text-left">
@if (!string.IsNullOrEmpty(Model.Error)) {
<strong>@Model.Error</strong>
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
@if (!string.IsNullOrEmpty(Model.ErrorDescription)) {
<small>@Model.ErrorDescription</small>
}
</p>
</div>

1
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

32
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<IStatusCodePagesFeature>();
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();
}
}
}
}

34
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<OpenIddictServices<TUser, TApplication, TAuthorization, TScope, TToken>>();
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<IStatusCodePagesFeature>();
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);

10
src/OpenIddict.Core/OpenIddictBuilder.cs

@ -385,16 +385,6 @@ namespace Microsoft.AspNetCore.Builder {
return Configure(options => options.AuthorizationEndpointPath = path);
}
/// <summary>
/// Sets the relative path corresponding to the middleware or controller action responsible
/// of rendering the OpenID Connect errors occurred during interactive workflows.
/// </summary>
/// <param name="path">The relative path of the error handler.</param>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public virtual OpenIddictBuilder SetErrorHandlingPath(PathString path) {
return Configure(options => options.ErrorHandlingPath = path);
}
/// <summary>
/// Sets the relative path corresponding to the logout endpoint.
/// </summary>

6
src/OpenIddict.Core/OpenIddictOptions.cs

@ -30,12 +30,6 @@ namespace OpenIddict {
/// </summary>
public IDistributedCache Cache { get; set; }
/// <summary>
/// Gets or sets the path of the middleware responsible of rendering
/// the OpenID Connect errors occurred during interactive workflows.
/// </summary>
public PathString ErrorHandlingPath { get; set; }
/// <summary>
/// Gets the list of the OpenIddict modules registered in the application.
/// </summary>

3
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"
},

Loading…
Cancel
Save