Browse Source

Backport the caching logic to OpenIddict 1.x

pull/553/head
Kévin Chalet 8 years ago
parent
commit
df3aee64f1
  1. 3
      src/OpenIddict.Core/OpenIddictConstants.cs
  2. 4
      src/OpenIddict/OpenIddictProvider.Authentication.cs
  3. 25
      src/OpenIddict/OpenIddictProvider.Exchange.cs
  4. 106
      src/OpenIddict/OpenIddictProvider.Helpers.cs
  5. 17
      src/OpenIddict/OpenIddictProvider.Introspection.cs
  6. 17
      src/OpenIddict/OpenIddictProvider.Revocation.cs
  7. 7
      src/OpenIddict/OpenIddictProvider.cs
  8. 12
      test/OpenIddict.Tests/OpenIddictProviderTests.Exchange.cs
  9. 7
      test/OpenIddict.Tests/OpenIddictProviderTests.Introspection.cs
  10. 2
      test/OpenIddict.Tests/OpenIddictProviderTests.Revocation.cs
  11. 24
      test/OpenIddict.Tests/OpenIddictProviderTests.Serialization.cs
  12. 14
      test/OpenIddict.Tests/OpenIddictProviderTests.cs

3
src/OpenIddict.Core/OpenIddictConstants.cs

@ -39,8 +39,11 @@ namespace OpenIddict.Core
public static class Properties
{
public const string Application = ".application";
public const string AuthenticationTicket = ".authentication_ticket";
public const string AuthorizationId = ".authorization_id";
public const string ReferenceToken = ".reference_token";
public const string Token = ".token";
}
public static class PropertyTypes

4
src/OpenIddict/OpenIddictProvider.Authentication.cs

@ -273,6 +273,10 @@ namespace OpenIddict
return;
}
// Store the application entity as a request property to make it accessible
// from the other provider methods without having to call the store twice.
context.Request.SetProperty($"{OpenIddictConstants.Properties.Application}:{context.ClientId}", application);
// Ensure that the specified redirect_uri is valid and is associated with the client application.
if (!await applications.ValidateRedirectUriAsync(application, context.RedirectUri, context.HttpContext.RequestAborted))
{

25
src/OpenIddict/OpenIddictProvider.Exchange.cs

@ -135,6 +135,10 @@ namespace OpenIddict
return;
}
// Store the application entity as a request property to make it accessible
// from the other provider methods without having to call the store twice.
context.Request.SetProperty($"{OpenIddictConstants.Properties.Application}:{context.ClientId}", application);
if (await applications.IsPublicAsync(application, context.HttpContext.RequestAborted))
{
// Note: public applications are not allowed to use the client credentials grant.
@ -229,24 +233,11 @@ namespace OpenIddict
// Extract the token identifier from the authentication ticket.
var identifier = context.Ticket.GetTokenId();
Debug.Assert(!string.IsNullOrEmpty(identifier),
"The authentication ticket should contain a ticket identifier.");
// Retrieve the authorization code/refresh token from the database and ensure it is still valid.
var token = await tokens.FindByIdAsync(identifier, context.HttpContext.RequestAborted);
if (token == null)
{
logger.LogError("The token request was rejected because the authorization code " +
"or refresh token '{Identifier}' was not found in the database.", identifier);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidGrant,
description: context.Request.IsAuthorizationCodeGrantType() ?
"The specified authorization code is no longer valid." :
"The specified refresh token is no longer valid.");
Debug.Assert(!string.IsNullOrEmpty(identifier), "The authentication ticket should contain a token identifier.");
return;
}
// Retrieve the authorization code/refresh token from the request properties.
var token = context.Request.GetProperty<TToken>($"{OpenIddictConstants.Properties.Token}:{identifier}");
Debug.Assert(token != null, "The token shouldn't be null.");
// If the authorization code/refresh token is already marked as redeemed, this may indicate that
// it was compromised. In this case, revoke the authorization and all the associated tokens.

106
src/OpenIddict/OpenIddictProvider.Helpers.cs

@ -8,7 +8,6 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Security.Cryptography;
using System.Threading.Tasks;
using AspNet.Security.OpenIdConnect.Extensions;
using AspNet.Security.OpenIdConnect.Primitives;
@ -57,11 +56,8 @@ namespace OpenIddict
// 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.");
}
var application = request.GetProperty<TApplication>($"{OpenIddictConstants.Properties.Application}:{request.ClientId}");
Debug.Assert(application != null, "The client application shouldn't be null.");
descriptor.ApplicationId = await applications.GetIdAsync(application, context.RequestAborted);
}
@ -183,11 +179,8 @@ namespace OpenIddict
// 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.");
}
var application = request.GetProperty<TApplication>($"{OpenIddictConstants.Properties.Application}:{request.ClientId}");
Debug.Assert(application != null, "The client application shouldn't be null.");
descriptor.ApplicationId = await applications.GetIdAsync(application, context.RequestAborted);
}
@ -247,18 +240,24 @@ namespace OpenIddict
if (options.UseReferenceTokens)
{
// Retrieve the token entry from the database.
// If it cannot be found, assume the token is not valid.
try
// For introspection or revocation requests, this method may be called more than once.
// For reference tokens, this may result in multiple database calls being made.
// To optimize that, the token is added to the request properties to indicate that
// a database lookup was already made with the same identifier. If the marker exists,
// the property value (that may be null) is used instead of making a database call.
if (request.HasProperty($"{OpenIddictConstants.Properties.ReferenceToken}:{value}"))
{
token = await tokens.FindByReferenceIdAsync(value, context.RequestAborted);
token = request.GetProperty<TToken>($"{OpenIddictConstants.Properties.ReferenceToken}:{value}");
}
// Swallow format-related exceptions to ensure badly formed
// or tampered tokens don't cause an exception at this stage.
catch
else
{
return null;
// Retrieve the token entry from the database. If it
// cannot be found, assume the token is not valid.
token = await tokens.FindByReferenceIdAsync(value, context.RequestAborted);
// Store the token as a request property so it can be retrieved if this method is called another time.
request.AddProperty($"{OpenIddictConstants.Properties.ReferenceToken}:{value}", token);
}
if (token == null)
@ -299,6 +298,8 @@ namespace OpenIddict
return null;
}
request.SetProperty($"{OpenIddictConstants.Properties.Token}:{identifier}", token);
}
else if (type == OpenIdConnectConstants.TokenUsages.AuthorizationCode ||
@ -312,21 +313,38 @@ namespace OpenIddict
return null;
}
// Retrieve the authorization code/refresh token entry from the database.
// If it cannot be found, assume the authorization code/refresh token is not valid.
token = await tokens.FindByIdAsync(ticket.GetTokenId(), context.RequestAborted);
if (token == null)
identifier = ticket.GetTokenId();
if (string.IsNullOrEmpty(identifier))
{
logger.LogInformation("The token '{Identifier}' cannot be found in the database.", ticket.GetTokenId());
logger.LogWarning("The identifier associated with the received token cannot be retrieved. " +
"This may indicate that the token entry is corrupted.");
return null;
}
identifier = await tokens.GetIdAsync(token, context.RequestAborted);
if (string.IsNullOrEmpty(identifier))
// For introspection or revocation requests, this method may be called more than once.
// For codes/refresh tokens, this may result in multiple database calls being made.
// To optimize that, the token is added to the request properties to indicate that
// a database lookup was already made with the same identifier. If the marker exists,
// the property value (that may be null) is used instead of making a database call.
if (request.HasProperty($"{OpenIddictConstants.Properties.Token}:{identifier}"))
{
logger.LogWarning("The identifier associated with the received token cannot be retrieved. " +
"This may indicate that the token entry is corrupted.");
token = request.GetProperty<TToken>($"{OpenIddictConstants.Properties.Token}:{identifier}");
}
// Otherwise, retrieve the authorization code/refresh token entry from the database.
// If it cannot be found, assume the authorization code/refresh token is not valid.
else
{
token = await tokens.FindByIdAsync(identifier, context.RequestAborted);
// Store the token as a request property so it can be retrieved if this method is called another time.
request.AddProperty($"{OpenIddictConstants.Properties.Token}:{identifier}", token);
}
if (token == null)
{
logger.LogInformation("The token '{Identifier}' cannot be found in the database.", ticket.GetTokenId());
return null;
}
@ -429,25 +447,13 @@ namespace OpenIddict
return true;
}
private async Task<bool> TryRedeemTokenAsync([NotNull] AuthenticationTicket ticket, [NotNull] HttpContext context)
private async Task<bool> TryRedeemTokenAsync([NotNull] TToken token, [NotNull] HttpContext context)
{
var logger = context.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var tokens = context.RequestServices.GetRequiredService<OpenIddictTokenManager<TToken>>();
// Note: if the token identifier or the token itself
// cannot be found, return true as the token doesn't need
// to be revoked if it doesn't exist or is already invalid.
var identifier = ticket.GetTokenId();
if (string.IsNullOrEmpty(identifier))
{
return true;
}
var token = await tokens.FindByIdAsync(identifier, context.RequestAborted);
if (token == null)
{
return true;
}
var identifier = await tokens.GetIdAsync(token, context.RequestAborted);
Debug.Assert(!string.IsNullOrEmpty(identifier), "The token identifier shouldn't be null or empty.");
try
{
@ -468,22 +474,14 @@ namespace OpenIddict
}
private async Task<bool> TryExtendTokenAsync(
[NotNull] AuthenticationTicket ticket, [NotNull] HttpContext context, [NotNull] OpenIddictOptions options)
[NotNull] TToken token, [NotNull] AuthenticationTicket ticket,
[NotNull] HttpContext context, [NotNull] OpenIddictOptions options)
{
var logger = context.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var tokens = context.RequestServices.GetRequiredService<OpenIddictTokenManager<TToken>>();
var identifier = ticket.GetTokenId();
if (string.IsNullOrEmpty(identifier))
{
return false;
}
var token = await tokens.FindByIdAsync(identifier, context.RequestAborted);
if (token == null)
{
return false;
}
Debug.Assert(!string.IsNullOrEmpty(identifier), "The token identifier shouldn't be null or empty.");
try
{

17
src/OpenIddict/OpenIddictProvider.Introspection.cs

@ -68,6 +68,10 @@ namespace OpenIddict
return;
}
// Store the application entity as a request property to make it accessible
// from the other provider methods without having to call the store twice.
context.Request.SetProperty($"{OpenIddictConstants.Properties.Application}:{context.ClientId}", application);
// Reject introspection requests sent by public applications.
if (await applications.IsPublicAsync(application, context.HttpContext.RequestAborted))
{
@ -107,8 +111,8 @@ namespace OpenIddict
Debug.Assert(context.Ticket != null, "The authentication ticket shouldn't be null.");
Debug.Assert(!string.IsNullOrEmpty(context.Request.ClientId), "The client_id parameter shouldn't be null.");
var identifier = context.Ticket.GetProperty(OpenIdConnectConstants.Properties.TokenId);
Debug.Assert(!string.IsNullOrEmpty(identifier), "The token identifier shouldn't be null or empty.");
var identifier = context.Ticket.GetTokenId();
Debug.Assert(!string.IsNullOrEmpty(identifier), "The authentication ticket should contain a token identifier.");
// Note: the OpenID Connect server middleware allows authorized presenters (e.g relying parties) to introspect access tokens
// but OpenIddict uses a stricter policy that only allows resource servers to use the introspection endpoint, unless the ticket
@ -132,10 +136,11 @@ namespace OpenIddict
// When the received ticket is revocable, ensure it is still valid.
if (options.UseReferenceTokens || context.Ticket.IsAuthorizationCode() || context.Ticket.IsRefreshToken())
{
// Retrieve the token from the database using the unique identifier stored in the authentication ticket:
// if the corresponding entry cannot be found, return Active = false to indicate that is is no longer valid.
var token = await tokens.FindByIdAsync(identifier, context.HttpContext.RequestAborted);
if (token == null || !await tokens.IsValidAsync(token, context.HttpContext.RequestAborted))
// Retrieve the token from the request properties. If it's marked as invalid, return active = false.
var token = context.Request.GetProperty<TToken>($"{OpenIddictConstants.Properties.Token}:{identifier}");
Debug.Assert(token != null, "The token shouldn't be null.");
if (!await tokens.IsValidAsync(token, context.HttpContext.RequestAborted))
{
logger.LogInformation("The token '{Identifier}' was declared as inactive because it was revoked.", identifier);

17
src/OpenIddict/OpenIddictProvider.Revocation.cs

@ -94,6 +94,10 @@ namespace OpenIddict
return;
}
// Store the application entity as a request property to make it accessible
// from the other provider methods without having to call the store twice.
context.Request.SetProperty($"{OpenIddictConstants.Properties.Application}:{context.ClientId}", application);
// Reject revocation requests containing a client_secret if the application is a public client.
if (await applications.IsPublicAsync(application, context.HttpContext.RequestAborted))
{
@ -183,13 +187,14 @@ namespace OpenIddict
}
// Extract the token identifier from the authentication ticket.
var identifier = context.Ticket.GetProperty(OpenIdConnectConstants.Properties.TokenId);
Debug.Assert(!string.IsNullOrEmpty(identifier), "The token should contain a ticket identifier.");
var identifier = context.Ticket.GetTokenId();
Debug.Assert(!string.IsNullOrEmpty(identifier), "The authentication ticket should contain a token identifier.");
// Retrieve the token from the request properties. If it's already marked as revoked, directly return a 200 response.
var token = context.Request.GetProperty<TToken>($"{OpenIddictConstants.Properties.Token}:{identifier}");
Debug.Assert(token != null, "The token shouldn't be null.");
// Retrieve the token from the database. If the token cannot be found,
// assume it is invalid and consider the revocation as successful.
var token = await tokens.FindByIdAsync(identifier, context.HttpContext.RequestAborted);
if (token == null || await tokens.IsRevokedAsync(token, context.HttpContext.RequestAborted))
if (await tokens.IsRevokedAsync(token, context.HttpContext.RequestAborted))
{
logger.LogInformation("The token '{Identifier}' was not revoked because " +
"it was already marked as invalid.", identifier);

7
src/OpenIddict/OpenIddictProvider.cs

@ -101,12 +101,15 @@ namespace OpenIddict
return;
}
var token = context.Request.GetProperty<TToken>($"{OpenIddictConstants.Properties.Token}:{context.Ticket.GetTokenId()}");
Debug.Assert(token != null, "The token shouldn't be null.");
// If rolling tokens are enabled or if the request is a grant_type=authorization_code request,
// mark the authorization code or the refresh token as redeemed to prevent future reuses.
// See https://tools.ietf.org/html/rfc6749#section-6 for more information.
if (options.UseRollingTokens || context.Request.IsAuthorizationCodeGrantType())
{
if (!await TryRedeemTokenAsync(context.Ticket, context.HttpContext))
if (!await TryRedeemTokenAsync(token, context.HttpContext))
{
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidGrant,
@ -137,7 +140,7 @@ namespace OpenIddict
// with a new expiration date if sliding expiration was not disabled.
else if (options.UseSlidingExpiration && context.Request.IsRefreshTokenGrantType())
{
if (!await TryExtendTokenAsync(context.Ticket, context.HttpContext, options))
if (!await TryExtendTokenAsync(token, context.Ticket, context.HttpContext, options))
{
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidGrant,

12
test/OpenIddict.Tests/OpenIddictProviderTests.Exchange.cs

@ -689,7 +689,7 @@ namespace OpenIddict.Tests
Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error);
Assert.Equal("The specified authorization code has already been redeemed.", response.ErrorDescription);
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.IsRedeemedAsync(token, It.IsAny<CancellationToken>()), Times.Once());
}
@ -755,7 +755,7 @@ namespace OpenIddict.Tests
Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error);
Assert.Equal("The specified refresh token has already been redeemed.", response.ErrorDescription);
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("60FFF7EA-F98E-437B-937E-5073CC313103", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("60FFF7EA-F98E-437B-937E-5073CC313103", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.IsRedeemedAsync(token, It.IsAny<CancellationToken>()), Times.Once());
}
@ -1007,7 +1007,7 @@ namespace OpenIddict.Tests
Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error);
Assert.Equal("The specified authorization code has already been redeemed.", response.ErrorDescription);
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.IsRedeemedAsync(tokens[0], It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.RevokeAsync(tokens[0], It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.RevokeAsync(tokens[1], It.IsAny<CancellationToken>()), Times.Once());
@ -1094,7 +1094,7 @@ namespace OpenIddict.Tests
Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error);
Assert.Equal("The specified refresh token has already been redeemed.", response.ErrorDescription);
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.IsRedeemedAsync(tokens[0], It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.RevokeAsync(tokens[0], It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.RevokeAsync(tokens[1], It.IsAny<CancellationToken>()), Times.Once());
@ -1169,7 +1169,7 @@ namespace OpenIddict.Tests
Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error);
Assert.Equal("The specified authorization code is no longer valid.", response.ErrorDescription);
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.IsRedeemedAsync(token, It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.IsValidAsync(token, It.IsAny<CancellationToken>()), Times.Once());
}
@ -1239,7 +1239,7 @@ namespace OpenIddict.Tests
Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error);
Assert.Equal("The specified refresh token is no longer valid.", response.ErrorDescription);
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("60FFF7EA-F98E-437B-937E-5073CC313103", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("60FFF7EA-F98E-437B-937E-5073CC313103", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.IsValidAsync(token, It.IsAny<CancellationToken>()), Times.Once());
}

7
test/OpenIddict.Tests/OpenIddictProviderTests.Introspection.cs

@ -397,7 +397,7 @@ namespace OpenIddict.Tests
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]);
Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("QaTk2f6UPe9trKismGBJr0OIs0KqpvNrqRsJqGuJAAI", It.IsAny<CancellationToken>()), Times.Exactly(3));
Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("QaTk2f6UPe9trKismGBJr0OIs0KqpvNrqRsJqGuJAAI", It.IsAny<CancellationToken>()), Times.Once());
}
[Fact]
@ -478,7 +478,6 @@ namespace OpenIddict.Tests
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]);
Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("QaTk2f6UPe9trKismGBJr0OIs0KqpvNrqRsJqGuJAAI", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.IsValidAsync(token, It.IsAny<CancellationToken>()), Times.Once());
}
@ -615,7 +614,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]);
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.IsValidAsync(token, It.IsAny<CancellationToken>()), Times.Once());
}
@ -755,7 +754,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]);
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.IsValidAsync(token, It.IsAny<CancellationToken>()), Times.Once());
}
}

2
test/OpenIddict.Tests/OpenIddictProviderTests.Revocation.cs

@ -480,7 +480,7 @@ namespace OpenIddict.Tests
// Assert
Assert.Empty(response.GetParameters());
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.RevokeAsync(token, It.IsAny<CancellationToken>()), Times.Once());
}
}

24
test/OpenIddict.Tests/OpenIddictProviderTests.Serialization.cs

@ -196,7 +196,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]);
Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
}
@ -254,7 +254,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]);
Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
}
@ -319,7 +319,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]);
Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Once());
}
@ -592,7 +592,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]);
Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
}
@ -650,7 +650,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]);
Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
}
@ -715,7 +715,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]);
Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Once());
}
@ -995,8 +995,7 @@ namespace OpenIddict.Tests
Assert.Equal(1483228800, (long) response[OpenIdConnectConstants.Claims.IssuedAt]);
Assert.Equal(1484006400, (long) response[OpenIdConnectConstants.Claims.ExpiresAt]);
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.Once());
format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Once());
}
@ -1172,7 +1171,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]);
Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
}
@ -1230,7 +1229,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]);
Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
}
@ -1295,7 +1294,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]);
Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Once());
}
@ -1575,8 +1574,7 @@ namespace OpenIddict.Tests
Assert.Equal(1483228800, (long) response[OpenIdConnectConstants.Claims.IssuedAt]);
Assert.Equal(1484006400, (long) response[OpenIdConnectConstants.Claims.ExpiresAt]);
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.Once());
format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Once());
}

14
test/OpenIddict.Tests/OpenIddictProviderTests.cs

@ -447,7 +447,7 @@ namespace OpenIddict.Tests
});
// Assert
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.RedeemAsync(token, It.IsAny<CancellationToken>()), Times.Once());
}
@ -522,7 +522,7 @@ namespace OpenIddict.Tests
Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error);
Assert.Equal("The specified authorization code is no longer valid.", response.ErrorDescription);
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.RedeemAsync(token, It.IsAny<CancellationToken>()), Times.Once());
}
@ -588,7 +588,7 @@ namespace OpenIddict.Tests
// Assert
Assert.NotNull(response.RefreshToken);
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("60FFF7EA-F98E-437B-937E-5073CC313103", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("60FFF7EA-F98E-437B-937E-5073CC313103", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.RedeemAsync(token, It.IsAny<CancellationToken>()), Times.Once());
}
@ -658,7 +658,7 @@ namespace OpenIddict.Tests
Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error);
Assert.Equal("The specified refresh token is no longer valid.", response.ErrorDescription);
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("60FFF7EA-F98E-437B-937E-5073CC313103", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("60FFF7EA-F98E-437B-937E-5073CC313103", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.RedeemAsync(token, It.IsAny<CancellationToken>()), Times.Once());
}
@ -716,7 +716,7 @@ namespace OpenIddict.Tests
// Assert
Assert.Null(response.RefreshToken);
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("60FFF7EA-F98E-437B-937E-5073CC313103", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("60FFF7EA-F98E-437B-937E-5073CC313103", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.RedeemAsync(token, It.IsAny<CancellationToken>()), Times.Never());
}
@ -792,7 +792,7 @@ namespace OpenIddict.Tests
// Assert
Assert.NotNull(response.RefreshToken);
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("60FFF7EA-F98E-437B-937E-5073CC313103", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("60FFF7EA-F98E-437B-937E-5073CC313103", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.RevokeAsync(tokens[1], It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.RevokeAsync(tokens[2], It.IsAny<CancellationToken>()), Times.Once());
}
@ -861,7 +861,7 @@ namespace OpenIddict.Tests
// Assert
Assert.Null(response.RefreshToken);
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("60FFF7EA-F98E-437B-937E-5073CC313103", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(mock => mock.FindByIdAsync("60FFF7EA-F98E-437B-937E-5073CC313103", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.RevokeAsync(tokens[1], It.IsAny<CancellationToken>()), Times.Never());
Mock.Get(manager).Verify(mock => mock.RevokeAsync(tokens[2], It.IsAny<CancellationToken>()), Times.Never());
}

Loading…
Cancel
Save