private async Task CreateAuthorizationAsync( [NotNull] AuthenticationTicket ticket, [NotNull] OpenIddictOptions options, [NotNull] HttpContext context, [NotNull] OpenIdConnectRequest request) { var descriptor = new OpenIddictAuthorizationDescriptor { Principal = ticket.Principal, Status = OpenIddictConstants.Statuses.Valid, Subject = ticket.Principal.GetClaim(OpenIdConnectConstants.Claims.Subject), Type = OpenIddictConstants.AuthorizationTypes.AdHoc }; foreach (var property in ticket.Properties.Items) { descriptor.Properties.Add(property); } foreach (var scope in ticket.GetScopes()) { descriptor.Scopes.Add(scope); } // If the client application is known, bind it to the authorization. if (!string.IsNullOrEmpty(request.ClientId)) { var application = await Applications.FindByClientIdAsync(request.ClientId, context.RequestAborted); if (application == null) { throw new InvalidOperationException("The client application cannot be retrieved from the database."); } descriptor.ApplicationId = await Applications.GetIdAsync(application, context.RequestAborted); } var authorization = await Authorizations.CreateAsync(descriptor, context.RequestAborted); if (authorization != null) { var identifier = await Authorizations.GetIdAsync(authorization, context.RequestAborted); if (string.IsNullOrEmpty(request.ClientId)) { Logger.LogInformation("An ad hoc authorization was automatically created and " + "associated with an unknown application: {Identifier}.", identifier); } else { Logger.LogInformation("An ad hoc authorization was automatically created and " + "associated with the '{ClientId}' application: {Identifier}.", request.ClientId, identifier); } // Attach the unique identifier of the ad hoc authorization to the authentication ticket // so that it is attached to all the derived tokens, allowing batched revocations support. ticket.SetProperty(OpenIddictConstants.Properties.AuthorizationId, identifier); } }
public override async Task SerializeRefreshToken([NotNull] SerializeRefreshTokenContext context) { var options = (OpenIddictOptions)context.Options; if (!options.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); 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.SetProperty(OpenIdConnectConstants.Properties.TokenId, 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); } } }
private async Task <string> CreateTokenAsync( [NotNull] string type, [NotNull] AuthenticationTicket ticket, [NotNull] OpenIddictOptions options, [NotNull] HttpContext context, [NotNull] OpenIdConnectRequest request, [NotNull] ISecureDataFormat <AuthenticationTicket> format) { Debug.Assert(!(options.DisableTokenRevocation && options.UseReferenceTokens), "Token revocation cannot be disabled when using reference tokens."); Debug.Assert(type == OpenIdConnectConstants.TokenUsages.AccessToken || type == OpenIdConnectConstants.TokenUsages.AuthorizationCode || type == OpenIdConnectConstants.TokenUsages.RefreshToken, "Only authorization codes, access and refresh tokens should be created using this method."); // When sliding expiration is disabled, the expiration date of generated refresh tokens is fixed // and must exactly match the expiration date of the refresh token used in the token request. if (request.IsTokenRequest() && request.IsRefreshTokenGrantType() && !options.UseSlidingExpiration && type == OpenIdConnectConstants.TokenUsages.RefreshToken) { var properties = request.GetProperty <AuthenticationTicket>( OpenIddictConstants.Properties.AuthenticationTicket)?.Properties; Debug.Assert(properties != null, "The authentication properties shouldn't be null."); ticket.Properties.ExpiresUtc = properties.ExpiresUtc; } if (options.DisableTokenRevocation) { return(null); } var descriptor = new OpenIddictTokenDescriptor { AuthorizationId = ticket.GetProperty(OpenIddictConstants.Properties.AuthorizationId), CreationDate = ticket.Properties.IssuedUtc, ExpirationDate = ticket.Properties.ExpiresUtc, Principal = ticket.Principal, Status = OpenIddictConstants.Statuses.Valid, Subject = ticket.Principal.GetClaim(OpenIdConnectConstants.Claims.Subject), Type = type }; foreach (var property in ticket.Properties.Items) { descriptor.Properties.Add(property); } string result = null; // When reference tokens are enabled or when the token is an authorization code or a // refresh token, remove the unnecessary properties from the authentication ticket. if (options.UseReferenceTokens || (type == OpenIdConnectConstants.TokenUsages.AuthorizationCode || type == OpenIdConnectConstants.TokenUsages.RefreshToken)) { ticket.Properties.IssuedUtc = ticket.Properties.ExpiresUtc = null; ticket.RemoveProperty(OpenIddictConstants.Properties.AuthorizationId) .RemoveProperty(OpenIdConnectConstants.Properties.TokenId); } // If reference tokens are enabled, create a new entry for // authorization codes, refresh tokens and access tokens. if (options.UseReferenceTokens) { // Note: the data format is automatically replaced at startup time to ensure // that encrypted tokens stored in the database cannot be considered as // valid tokens if the developer decides to disable reference tokens support. descriptor.Ciphertext = format.Protect(ticket); // Generate a new crypto-secure random identifier that will be // substituted to the ciphertext returned by the data format. var bytes = new byte[256 / 8]; options.RandomNumberGenerator.GetBytes(bytes); result = Base64UrlEncoder.Encode(bytes); // Compute the digest of the generated identifier and use // it as the hashed identifier of the reference token. // Doing that prevents token identifiers stolen from // the database from being used as valid reference tokens. using (var algorithm = SHA256.Create()) { descriptor.Hash = Convert.ToBase64String(algorithm.ComputeHash(bytes)); } } // Otherwise, only create a token metadata entry for authorization codes and refresh tokens. else if (type != OpenIdConnectConstants.TokenUsages.AuthorizationCode && type != OpenIdConnectConstants.TokenUsages.RefreshToken) { return(null); } // If the client application is known, associate it with the token. if (!string.IsNullOrEmpty(request.ClientId)) { var application = await Applications.FindByClientIdAsync(request.ClientId, context.RequestAborted); if (application == null) { throw new InvalidOperationException("The client application cannot be retrieved from the database."); } descriptor.ApplicationId = await Applications.GetIdAsync(application, context.RequestAborted); } // If a null value was returned by CreateAsync(), return immediately. var token = await Tokens.CreateAsync(descriptor, context.RequestAborted); if (token == null) { return(null); } // Throw an exception if the token identifier can't be resolved. var identifier = await Tokens.GetIdAsync(token, context.RequestAborted); if (string.IsNullOrEmpty(identifier)) { throw new InvalidOperationException("The unique key associated with a refresh token cannot be null or empty."); } // Restore the token identifier using the unique // identifier attached with the database entry. ticket.SetTokenId(identifier); // Dynamically set the creation and expiration dates. ticket.Properties.IssuedUtc = descriptor.CreationDate; ticket.Properties.ExpiresUtc = descriptor.ExpirationDate; // Restore the authorization identifier using the identifier attached with the database entry. ticket.SetProperty(OpenIddictConstants.Properties.AuthorizationId, descriptor.AuthorizationId); if (!string.IsNullOrEmpty(result)) { Logger.LogTrace("A new reference token was successfully generated and persisted " + "in the database: {Token} ; {Claims} ; {Properties}.", result, ticket.Principal.Claims, ticket.Properties.Items); } return(result); }