From e4019e8a1d4454a9919453b14237dbc4457f2dc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Thu, 9 Jun 2016 18:47:51 +0200 Subject: [PATCH] Implement ValidateUserinfoRequest and GrantAuthorizationCode to reject invalid tokens more gracefully --- .../OpenIddictProvider.Exchange.cs | 19 ++++++++++++++ .../OpenIddictProvider.Userinfo.cs | 25 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Exchange.cs b/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Exchange.cs index 573e1e34..de4920f4 100644 --- a/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Exchange.cs +++ b/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Exchange.cs @@ -161,6 +161,25 @@ namespace OpenIddict.Infrastructure { context.Validate(ticket); } + public override async Task GrantAuthorizationCode([NotNull] GrantAuthorizationCodeContext context) { + var services = context.HttpContext.RequestServices.GetRequiredService>(); + + var user = await services.Users.GetUserAsync(context.Ticket.Principal); + if (user == null) { + services.Logger.LogError("The token request was rejected because the user profile associated " + + "with the authorization code was not found in the database: '{Identifier}'.", + context.Ticket.Principal.GetClaim(ClaimTypes.NameIdentifier)); + + context.Reject( + error: OpenIdConnectConstants.Errors.InvalidGrant, + description: "The authorization code is no longer valid."); + + return; + } + + context.Validate(context.Ticket); + } + public override async Task GrantRefreshToken([NotNull] GrantRefreshTokenContext context) { var services = context.HttpContext.RequestServices.GetRequiredService>(); diff --git a/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Userinfo.cs b/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Userinfo.cs index 72929f43..57d991b3 100644 --- a/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Userinfo.cs +++ b/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Userinfo.cs @@ -12,11 +12,36 @@ using AspNet.Security.OpenIdConnect.Extensions; using AspNet.Security.OpenIdConnect.Server; using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Newtonsoft.Json.Linq; namespace OpenIddict.Infrastructure { public partial class OpenIddictProvider : OpenIdConnectServerProvider where TUser : class where TApplication : class where TAuthorization : class where TScope : class where TToken : class { + public override async Task ValidateUserinfoRequest([NotNull] ValidateUserinfoRequestContext context) { + var services = context.HttpContext.RequestServices.GetRequiredService>(); + + // Note: the principal returned by AuthenticateAsync cannot be null as the OpenID Connect server + // middleware always ensures the ticket is valid before invoking the ValidateUserinfoRequest event. + var principal = await context.HttpContext.Authentication.AuthenticateAsync(context.Options.AuthenticationScheme); + Debug.Assert(principal != null, "The principal extracted from the access token shouldn't be null."); + + // Ensure the user was not removed from the database. + var user = await services.Users.GetUserAsync(principal); + if (user == null) { + services.Logger.LogError("The userinfo request was rejected because the user profile " + + "corresponding to the access token was not found in the database."); + + context.Reject( + error: OpenIdConnectConstants.Errors.InvalidGrant, + description: "The access token is no longer valid."); + + return; + } + + context.Validate(); + } + public override async Task HandleUserinfoRequest([NotNull] HandleUserinfoRequestContext context) { var services = context.HttpContext.RequestServices.GetRequiredService>();