Browse Source

Replace ISession by IDistributedCache and extend request_id handling to GET requests

pull/152/head
Kévin Chalet 10 years ago
parent
commit
289b18045b
  1. 4
      samples/Mvc.Server/Startup.cs
  2. 1
      samples/Mvc.Server/project.json
  3. 70
      src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Authentication.cs
  4. 5
      src/OpenIddict.Core/OpenIddictExtensions.cs
  5. 7
      src/OpenIddict.Core/OpenIddictOptions.cs

4
samples/Mvc.Server/Startup.cs

@ -21,8 +21,6 @@ namespace Mvc.Server {
services.AddMvc();
services.AddSession();
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(configuration["Data:DefaultConnection:ConnectionString"]));
@ -117,8 +115,6 @@ namespace Mvc.Server {
ConsumerSecret = "Il2eFzGIrYhz6BWjYhVXBPQSfZuS4xoHpSSyD9PI"
});
app.UseSession();
app.UseOpenIddict();
app.UseMvcWithDefaultRoute();

1
samples/Mvc.Server/project.json

@ -27,7 +27,6 @@
"Microsoft.AspNetCore.Mvc": "1.0.0",
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
"Microsoft.AspNetCore.Session": "1.0.0",
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.EntityFrameworkCore.SqlServer": "1.0.0",
"Microsoft.Extensions.Configuration.CommandLine": "1.0.0",

70
src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Authentication.cs

@ -14,11 +14,9 @@ using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@ -53,25 +51,9 @@ namespace OpenIddict.Infrastructure {
}
// If a request_id parameter can be found in the authorization request,
// restore the complete authorization request stored in the user session.
// restore the complete authorization request stored in the distributed cache.
if (!string.IsNullOrEmpty(context.Request.GetRequestId())) {
// Ensure session support has been enabled for this request.
if (context.HttpContext.Features.Get<ISessionFeature>() == null) {
services.Logger.LogError("The authorization request was rejected because the session middleware " +
"was not correctly registered. Session support must be enabled to allow " +
"processing authorization requests specifying a request_id parameter.");
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
description: "The request_id parameter is not allowed by this authorization server.");
return;
}
// Load the session from the session store.
await context.HttpContext.Session.LoadAsync();
var payload = context.HttpContext.Session.Get(OpenIddictConstants.Environment.Request + context.Request.GetRequestId());
var payload = await services.Options.Cache.GetAsync(OpenIddictConstants.Environment.Request + context.Request.GetRequestId());
if (payload == null) {
services.Logger.LogError("The authorization request was rejected because an unknown " +
"or invalid request_id parameter was specified.");
@ -317,37 +299,31 @@ namespace OpenIddict.Infrastructure {
return;
}
if (context.HttpContext.Request.Path == context.Options.AuthorizationEndpointPath &&
string.Equals(context.HttpContext.Request.Method, "POST", StringComparison.OrdinalIgnoreCase)) {
// Ensure session support has been enabled for this request.
if (context.HttpContext.Features.Get<ISessionFeature>() == null) {
services.Logger.LogError("The authorization request was rejected because the session middleware " +
"was not correctly registered. Session support must be enabled to allow " +
"processing POST authorization requests.");
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
description: "POST authorization requests are not allowed by this authorization server.");
return;
}
// If no request_id parameter can be found in the current request, assume the OpenID Connect request
// was not serialized yet and store the entire payload in the distributed cache to make it easier
// to flow across requests and internal/external authentication/registration workflows.
if (string.IsNullOrEmpty(context.Request.GetRequestId())) {
// Generate a request identifier. Note: using a crypto-secure
// random number generator is not necessary in this case.
var identifier = Guid.NewGuid().ToString();
// Load the session from the session store.
await context.HttpContext.Session.LoadAsync();
var options = new DistributedCacheEntryOptions {
AbsoluteExpiration = context.Options.SystemClock.UtcNow + TimeSpan.FromMinutes(30),
SlidingExpiration = TimeSpan.FromMinutes(10)
};
// Store the serialized authorization request parameters in the user session.
context.HttpContext.Session.Set(OpenIddictConstants.Environment.Request + identifier, context.Request.Export());
// Store the serialized authorization request parameters in the distributed cache.
await services.Options.Cache.SetAsync(OpenIddictConstants.Environment.Request + identifier, context.Request.Export(), options);
// Add the request_id to the current URL.
// Create a new authorization request containing only the request_id parameter.
var address = QueryHelpers.AddQueryString(
uri: context.HttpContext.Request.GetEncodedUrl(),
uri: context.Options.AuthorizationEndpointPath,
name: OpenIdConnectConstants.Parameters.RequestId, value: identifier);
context.HttpContext.Response.Redirect(address);
// Mark the response as handled
// to skip the rest of the pipeline.
context.HandleResponse();
return;
@ -356,15 +332,15 @@ namespace OpenIddict.Infrastructure {
context.SkipToNextMiddleware();
}
public override Task ApplyAuthorizationResponse([NotNull] ApplyAuthorizationResponseContext context) {
public override async Task ApplyAuthorizationResponse([NotNull] ApplyAuthorizationResponseContext context) {
var services = context.HttpContext.RequestServices.GetRequiredService<OpenIddictServices<TUser, TApplication, TAuthorization, TScope, TToken>>();
// Remove the authorization request from the user session.
// Remove the authorization request from the distributed cache.
if (!string.IsNullOrEmpty(context.Request.GetRequestId())) {
// Note: the ApplyAuthorizationResponse event is called for both successful
// and errored authorization responses but discrimination is not necessary here,
// as the authorization request must be removed from the user session in both cases.
context.HttpContext.Session.Remove(OpenIddictConstants.Environment.Request + context.Request.GetRequestId());
// as the authorization request must be removed from the distributed cache in both cases.
await services.Options.Cache.RemoveAsync(OpenIddictConstants.Environment.Request + context.Request.GetRequestId());
}
if (!string.IsNullOrEmpty(context.Response.Error) && services.Options.ErrorHandlingPath.HasValue) {
@ -380,8 +356,6 @@ namespace OpenIddict.Infrastructure {
context.SkipToNextMiddleware();
}
return Task.FromResult(0);
}
}
}

5
src/OpenIddict.Core/OpenIddictExtensions.cs

@ -7,6 +7,7 @@
using System;
using System.Linq;
using JetBrains.Annotations;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
@ -87,6 +88,10 @@ namespace Microsoft.AspNetCore.Builder {
// Resolve the OpenIddict options from the DI container.
var options = app.ApplicationServices.GetRequiredService<IOptions<OpenIddictOptions>>().Value;
if (options.Cache == null) {
options.Cache = app.ApplicationServices.GetRequiredService<IDistributedCache>();
}
// Get the modules registered by the application
// and add the OpenID Connect server middleware.
var modules = options.Modules.ToList();

7
src/OpenIddict.Core/OpenIddictOptions.cs

@ -8,6 +8,7 @@ using System;
using System.Collections.Generic;
using AspNet.Security.OpenIdConnect.Server;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Distributed;
namespace OpenIddict {
/// <summary>
@ -23,6 +24,12 @@ namespace OpenIddict {
AccessTokenLifetime = TimeSpan.FromMinutes(30);
}
/// <summary>
/// Gets or sets the distributed cache used by OpenIddict. If no cache is explicitly
/// provided, the cache registered in the dependency injection container is used.
/// </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.

Loading…
Cancel
Save