Versatile OpenID Connect stack for ASP.NET Core and Microsoft.Owin (compatible with ASP.NET 4.6.1)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

138 lines
7.3 KiB

/*
* 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 System;
using System.Diagnostics;
using System.Security.Claims;
using System.Threading.Tasks;
using AspNet.Security.OpenIdConnect.Extensions;
using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OpenIddict.Core;
namespace OpenIddict
{
public partial class OpenIddictProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
{
public override async Task SerializeAuthorizationCode([NotNull] SerializeAuthorizationCodeContext context)
{
var applications = context.HttpContext.RequestServices.GetRequiredService<OpenIddictApplicationManager<TApplication>>();
var options = context.HttpContext.RequestServices.GetRequiredService<IOptions<OpenIddictOptions>>();
var tokens = context.HttpContext.RequestServices.GetRequiredService<OpenIddictTokenManager<TToken>>();
Debug.Assert(!string.IsNullOrEmpty(context.Request.ClientId), "The client identifier shouldn't be null or empty.");
if (!options.Value.DisableTokenRevocation)
{
// Resolve the subject from the authentication ticket. If it cannot be found, throw an exception.
var subject = context.Ticket.Principal.GetClaim(OpenIdConnectConstants.Claims.Subject) ??
context.Ticket.Principal.GetClaim(ClaimTypes.NameIdentifier) ??
context.Ticket.Principal.GetClaim(ClaimTypes.Upn);
if (string.IsNullOrEmpty(subject))
{
throw new InvalidOperationException("The subject associated with the authentication ticket cannot be retrieved.");
}
// If a null value was returned by CreateAsync, return immediately.
var token = await tokens.CreateAsync(OpenIdConnectConstants.TokenTypeHints.AuthorizationCode, subject, context.HttpContext.RequestAborted);
if (token == null)
{
return;
}
// Throw an exception if the token identifier can't be resolved.
var identifier = await tokens.GetIdAsync(token, context.HttpContext.RequestAborted);
if (string.IsNullOrEmpty(identifier))
{
throw new InvalidOperationException("The unique key associated with an authorization code cannot be null or empty.");
}
// Attach the key returned by the underlying store
// to the authorization code to override the default GUID
// generated by the OpenID Connect server middleware.
context.Ticket.SetTicketId(identifier);
var application = await applications.FindByClientIdAsync(context.Request.ClientId, context.HttpContext.RequestAborted);
if (application == null)
{
throw new InvalidOperationException("The client application cannot be retrieved from the database.");
}
await tokens.SetClientAsync(token, await applications.GetIdAsync(application, context.HttpContext.RequestAborted), context.HttpContext.RequestAborted);
// If an authorization identifier was specified, bind it to the token.
var authorization = context.Ticket.GetProperty(OpenIddictConstants.Properties.AuthorizationId);
if (!string.IsNullOrEmpty(authorization))
{
await tokens.SetAuthorizationAsync(token, authorization, context.HttpContext.RequestAborted);
}
}
}
public override async Task SerializeRefreshToken([NotNull] SerializeRefreshTokenContext context)
{
var applications = context.HttpContext.RequestServices.GetRequiredService<OpenIddictApplicationManager<TApplication>>();
var options = context.HttpContext.RequestServices.GetRequiredService<IOptions<OpenIddictOptions>>();
var tokens = context.HttpContext.RequestServices.GetRequiredService<OpenIddictTokenManager<TToken>>();
if (!options.Value.DisableTokenRevocation)
{
// Resolve the subject from the authentication ticket. If it cannot be found, throw an exception.
var subject = context.Ticket.Principal.GetClaim(OpenIdConnectConstants.Claims.Subject) ??
context.Ticket.Principal.GetClaim(ClaimTypes.NameIdentifier) ??
context.Ticket.Principal.GetClaim(ClaimTypes.Upn);
if (string.IsNullOrEmpty(subject))
{
throw new InvalidOperationException("The subject associated with the authentication ticket cannot be retrieved.");
}
// If a null value was returned by CreateAsync, return immediately.
var token = await tokens.CreateAsync(OpenIdConnectConstants.TokenTypeHints.RefreshToken, subject, context.HttpContext.RequestAborted);
if (token == null)
{
return;
}
// Throw an exception if the token identifier can't be resolved.
var identifier = await tokens.GetIdAsync(token, context.HttpContext.RequestAborted);
if (string.IsNullOrEmpty(identifier))
{
throw new InvalidOperationException("The unique key associated with a refresh token cannot be null or empty.");
}
// Attach the key returned by the underlying store
// to the refresh token to override the default GUID
// generated by the OpenID Connect server middleware.
context.Ticket.SetTicketId(identifier);
// If the client application is known, associate it with the token.
if (!string.IsNullOrEmpty(context.Request.ClientId))
{
var application = await applications.FindByClientIdAsync(context.Request.ClientId, context.HttpContext.RequestAborted);
if (application == null)
{
throw new InvalidOperationException("The client application cannot be retrieved from the database.");
}
await tokens.SetClientAsync(token, await applications.GetIdAsync(application, context.HttpContext.RequestAborted), context.HttpContext.RequestAborted);
}
// If an authorization identifier was specified, bind it to the token.
var authorization = context.Ticket.GetProperty(OpenIddictConstants.Properties.AuthorizationId);
if (!string.IsNullOrEmpty(authorization))
{
await tokens.SetAuthorizationAsync(token, authorization, context.HttpContext.RequestAborted);
}
}
}
}
}