Browse Source

Cache the TApplication/TToken entities in the request properties to avoid multiple stores calls

pull/539/head
Kévin Chalet 9 years ago
parent
commit
9bae6740db
  1. 3
      src/OpenIddict.Core/OpenIddictConstants.cs
  2. 4
      src/OpenIddict/OpenIddictProvider.Authentication.cs
  3. 25
      src/OpenIddict/OpenIddictProvider.Exchange.cs
  4. 107
      src/OpenIddict/OpenIddictProvider.Helpers.cs
  5. 18
      src/OpenIddict/OpenIddictProvider.Introspection.cs
  6. 18
      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 static class Properties
{ {
public const string Application = ".application";
public const string AuthenticationTicket = ".authentication_ticket"; public const string AuthenticationTicket = ".authentication_ticket";
public const string AuthorizationId = ".authorization_id"; public const string AuthorizationId = ".authorization_id";
public const string ReferenceToken = ".reference_token";
public const string Token = ".token";
} }
public static class PropertyTypes public static class PropertyTypes

4
src/OpenIddict/OpenIddictProvider.Authentication.cs

@ -267,6 +267,10 @@ namespace OpenIddict
return; 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. // 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)) if (!await Applications.ValidateRedirectUriAsync(application, context.RedirectUri, context.HttpContext.RequestAborted))
{ {

25
src/OpenIddict/OpenIddictProvider.Exchange.cs

@ -131,6 +131,10 @@ namespace OpenIddict
return; 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)) if (await Applications.IsPublicAsync(application, context.HttpContext.RequestAborted))
{ {
// Note: public applications are not allowed to use the client credentials grant. // Note: public applications are not allowed to use the client credentials grant.
@ -222,24 +226,11 @@ namespace OpenIddict
// Extract the token identifier from the authentication ticket. // Extract the token identifier from the authentication ticket.
var identifier = context.Ticket.GetTokenId(); var identifier = context.Ticket.GetTokenId();
Debug.Assert(!string.IsNullOrEmpty(identifier), Debug.Assert(!string.IsNullOrEmpty(identifier), "The authentication ticket should contain a token 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.");
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 // 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. // it was compromised. In this case, revoke the authorization and all the associated tokens.

107
src/OpenIddict/OpenIddictProvider.Helpers.cs

@ -5,11 +5,9 @@
*/ */
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.Security.Cryptography;
using System.Threading.Tasks; using System.Threading.Tasks;
using AspNet.Security.OpenIdConnect.Extensions; using AspNet.Security.OpenIdConnect.Extensions;
using AspNet.Security.OpenIdConnect.Primitives; using AspNet.Security.OpenIdConnect.Primitives;
@ -52,11 +50,8 @@ namespace OpenIddict
// If the client application is known, bind it to the authorization. // If the client application is known, bind it to the authorization.
if (!string.IsNullOrEmpty(request.ClientId)) if (!string.IsNullOrEmpty(request.ClientId))
{ {
var application = await Applications.FindByClientIdAsync(request.ClientId, context.RequestAborted); var application = request.GetProperty<TApplication>($"{OpenIddictConstants.Properties.Application}:{request.ClientId}");
if (application == null) Debug.Assert(application != null, "The client application shouldn't be null.");
{
throw new InvalidOperationException("The client application cannot be retrieved from the database.");
}
descriptor.ApplicationId = await Applications.GetIdAsync(application, context.RequestAborted); descriptor.ApplicationId = await Applications.GetIdAsync(application, context.RequestAborted);
} }
@ -174,11 +169,8 @@ namespace OpenIddict
// If the client application is known, associate it with the token. // If the client application is known, associate it with the token.
if (!string.IsNullOrEmpty(request.ClientId)) if (!string.IsNullOrEmpty(request.ClientId))
{ {
var application = await Applications.FindByClientIdAsync(request.ClientId, context.RequestAborted); var application = request.GetProperty<TApplication>($"{OpenIddictConstants.Properties.Application}:{request.ClientId}");
if (application == null) Debug.Assert(application != null, "The client application shouldn't be null.");
{
throw new InvalidOperationException("The client application cannot be retrieved from the database.");
}
descriptor.ApplicationId = await Applications.GetIdAsync(application, context.RequestAborted); descriptor.ApplicationId = await Applications.GetIdAsync(application, context.RequestAborted);
} }
@ -238,18 +230,24 @@ namespace OpenIddict
if (options.UseReferenceTokens) if (options.UseReferenceTokens)
{ {
// Retrieve the token entry from the database. // For introspection or revocation requests, this method may be called more than once.
// If it cannot be found, assume the token is not valid. // For reference tokens, this may result in multiple database calls being made.
try // 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 else
// or tampered tokens don't cause an exception at this stage.
catch
{ {
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) if (token == null)
@ -289,6 +287,8 @@ namespace OpenIddict
return null; return null;
} }
request.SetProperty($"{OpenIddictConstants.Properties.Token}:{identifier}", token);
} }
else if (type == OpenIdConnectConstants.TokenUsages.AuthorizationCode || else if (type == OpenIdConnectConstants.TokenUsages.AuthorizationCode ||
@ -302,21 +302,38 @@ namespace OpenIddict
return null; return null;
} }
// Retrieve the authorization code/refresh token entry from the database. identifier = ticket.GetTokenId();
// If it cannot be found, assume the authorization code/refresh token is not valid. if (string.IsNullOrEmpty(identifier))
token = await Tokens.FindByIdAsync(ticket.GetTokenId(), context.RequestAborted);
if (token == null)
{ {
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; return null;
} }
identifier = await Tokens.GetIdAsync(token, context.RequestAborted); // For introspection or revocation requests, this method may be called more than once.
if (string.IsNullOrEmpty(identifier)) // 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. " + token = request.GetProperty<TToken>($"{OpenIddictConstants.Properties.Token}:{identifier}");
"This may indicate that the token entry is corrupted."); }
// 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; return null;
} }
@ -413,22 +430,10 @@ namespace OpenIddict
return true; return true;
} }
private async Task<bool> TryRedeemTokenAsync([NotNull] AuthenticationTicket ticket, [NotNull] HttpContext context) private async Task<bool> TryRedeemTokenAsync([NotNull] TToken token, [NotNull] HttpContext context)
{ {
// Note: if the token identifier or the token itself var identifier = await Tokens.GetIdAsync(token, context.RequestAborted);
// cannot be found, return true as the token doesn't need Debug.Assert(!string.IsNullOrEmpty(identifier), "The token identifier shouldn't be null or empty.");
// 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;
}
try try
{ {
@ -449,19 +454,11 @@ namespace OpenIddict
} }
private async Task<bool> TryExtendTokenAsync( 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 identifier = ticket.GetTokenId(); var identifier = ticket.GetTokenId();
if (string.IsNullOrEmpty(identifier)) Debug.Assert(!string.IsNullOrEmpty(identifier), "The token identifier shouldn't be null or empty.");
{
return false;
}
var token = await Tokens.FindByIdAsync(identifier, context.RequestAborted);
if (token == null)
{
return false;
}
try try
{ {

18
src/OpenIddict/OpenIddictProvider.Introspection.cs

@ -12,6 +12,7 @@ using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server; using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using OpenIddict.Core;
namespace OpenIddict namespace OpenIddict
{ {
@ -63,6 +64,10 @@ namespace OpenIddict
return; 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. // Reject introspection requests sent by public applications.
if (await Applications.IsPublicAsync(application, context.HttpContext.RequestAborted)) if (await Applications.IsPublicAsync(application, context.HttpContext.RequestAborted))
{ {
@ -99,8 +104,8 @@ namespace OpenIddict
Debug.Assert(context.Ticket != null, "The authentication ticket shouldn't be null."); 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."); Debug.Assert(!string.IsNullOrEmpty(context.Request.ClientId), "The client_id parameter shouldn't be null.");
var identifier = context.Ticket.GetProperty(OpenIdConnectConstants.Properties.TokenId); var identifier = context.Ticket.GetTokenId();
Debug.Assert(!string.IsNullOrEmpty(identifier), "The token identifier shouldn't be null or empty."); 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 // 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 // but OpenIddict uses a stricter policy that only allows resource servers to use the introspection endpoint, unless the ticket
@ -124,10 +129,11 @@ namespace OpenIddict
// When the received ticket is revocable, ensure it is still valid. // When the received ticket is revocable, ensure it is still valid.
if (options.UseReferenceTokens || context.Ticket.IsAuthorizationCode() || context.Ticket.IsRefreshToken()) if (options.UseReferenceTokens || context.Ticket.IsAuthorizationCode() || context.Ticket.IsRefreshToken())
{ {
// Retrieve the token from the database using the unique identifier stored in the authentication ticket: // Retrieve the token from the request properties. If it's marked as invalid, return active = false.
// if the corresponding entry cannot be found, return Active = false to indicate that is is no longer valid. var token = context.Request.GetProperty<TToken>($"{OpenIddictConstants.Properties.Token}:{identifier}");
var token = await Tokens.FindByIdAsync(identifier, context.HttpContext.RequestAborted); Debug.Assert(token != null, "The token shouldn't be null.");
if (token == null || !await Tokens.IsValidAsync(token, context.HttpContext.RequestAborted))
if (!await Tokens.IsValidAsync(token, context.HttpContext.RequestAborted))
{ {
Logger.LogInformation("The token '{Identifier}' was declared as inactive because it was revoked.", identifier); Logger.LogInformation("The token '{Identifier}' was declared as inactive because it was revoked.", identifier);

18
src/OpenIddict/OpenIddictProvider.Revocation.cs

@ -12,6 +12,7 @@ using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server; using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using OpenIddict.Core;
namespace OpenIddict namespace OpenIddict
{ {
@ -89,6 +90,10 @@ namespace OpenIddict
return; 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. // Reject revocation requests containing a client_secret if the application is a public client.
if (await Applications.IsPublicAsync(application, context.HttpContext.RequestAborted)) if (await Applications.IsPublicAsync(application, context.HttpContext.RequestAborted))
{ {
@ -175,13 +180,14 @@ namespace OpenIddict
} }
// Extract the token identifier from the authentication ticket. // Extract the token identifier from the authentication ticket.
var identifier = context.Ticket.GetProperty(OpenIdConnectConstants.Properties.TokenId); var identifier = context.Ticket.GetTokenId();
Debug.Assert(!string.IsNullOrEmpty(identifier), "The token should contain a ticket identifier."); 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, if (await Tokens.IsRevokedAsync(token, context.HttpContext.RequestAborted))
// 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))
{ {
Logger.LogInformation("The token '{Identifier}' was not revoked because " + Logger.LogInformation("The token '{Identifier}' was not revoked because " +
"it was already marked as invalid.", identifier); "it was already marked as invalid.", identifier);

7
src/OpenIddict/OpenIddictProvider.cs

@ -147,12 +147,15 @@ namespace OpenIddict
return; 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, // 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. // 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. // See https://tools.ietf.org/html/rfc6749#section-6 for more information.
if (options.UseRollingTokens || context.Request.IsAuthorizationCodeGrantType()) if (options.UseRollingTokens || context.Request.IsAuthorizationCodeGrantType())
{ {
if (!await TryRedeemTokenAsync(context.Ticket, context.HttpContext)) if (!await TryRedeemTokenAsync(token, context.HttpContext))
{ {
context.Reject( context.Reject(
error: OpenIdConnectConstants.Errors.InvalidGrant, error: OpenIdConnectConstants.Errors.InvalidGrant,
@ -183,7 +186,7 @@ namespace OpenIddict
// with a new expiration date if sliding expiration was not disabled. // with a new expiration date if sliding expiration was not disabled.
else if (options.UseSlidingExpiration && context.Request.IsRefreshTokenGrantType()) 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( context.Reject(
error: OpenIdConnectConstants.Errors.InvalidGrant, error: OpenIdConnectConstants.Errors.InvalidGrant,

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

@ -687,7 +687,7 @@ namespace OpenIddict.Tests
Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error); Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error);
Assert.Equal("The specified authorization code has already been redeemed.", response.ErrorDescription); 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()); Mock.Get(manager).Verify(mock => mock.IsRedeemedAsync(token, It.IsAny<CancellationToken>()), Times.Once());
} }
@ -753,7 +753,7 @@ namespace OpenIddict.Tests
Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error); Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error);
Assert.Equal("The specified refresh token has already been redeemed.", response.ErrorDescription); 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()); Mock.Get(manager).Verify(mock => mock.IsRedeemedAsync(token, It.IsAny<CancellationToken>()), Times.Once());
} }
@ -1005,7 +1005,7 @@ namespace OpenIddict.Tests
Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error); Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error);
Assert.Equal("The specified authorization code has already been redeemed.", response.ErrorDescription); 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.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[0], 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[1], It.IsAny<CancellationToken>()), Times.Once());
@ -1092,7 +1092,7 @@ namespace OpenIddict.Tests
Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error); Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error);
Assert.Equal("The specified refresh token has already been redeemed.", response.ErrorDescription); 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.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[0], 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[1], It.IsAny<CancellationToken>()), Times.Once());
@ -1167,7 +1167,7 @@ namespace OpenIddict.Tests
Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error); Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error);
Assert.Equal("The specified authorization code is no longer valid.", response.ErrorDescription); 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.IsRedeemedAsync(token, It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.IsValidAsync(token, It.IsAny<CancellationToken>()), Times.Once()); Mock.Get(manager).Verify(mock => mock.IsValidAsync(token, It.IsAny<CancellationToken>()), Times.Once());
} }
@ -1237,7 +1237,7 @@ namespace OpenIddict.Tests
Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error); Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error);
Assert.Equal("The specified refresh token is no longer valid.", response.ErrorDescription); 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()); Mock.Get(manager).Verify(mock => mock.IsValidAsync(token, It.IsAny<CancellationToken>()), Times.Once());
} }

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

@ -395,7 +395,7 @@ namespace OpenIddict.Tests
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); 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] [Fact]
@ -476,7 +476,6 @@ namespace OpenIddict.Tests
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); 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.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()); Mock.Get(manager).Verify(mock => mock.IsValidAsync(token, It.IsAny<CancellationToken>()), Times.Once());
} }
@ -613,7 +612,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters()); Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); 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()); Mock.Get(manager).Verify(mock => mock.IsValidAsync(token, It.IsAny<CancellationToken>()), Times.Once());
} }
@ -753,7 +752,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters()); Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); 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()); Mock.Get(manager).Verify(mock => mock.IsValidAsync(token, It.IsAny<CancellationToken>()), Times.Once());
} }
} }

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

@ -478,7 +478,7 @@ namespace OpenIddict.Tests
// Assert // Assert
Assert.Empty(response.GetParameters()); 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()); Mock.Get(manager).Verify(mock => mock.RevokeAsync(token, It.IsAny<CancellationToken>()), Times.Once());
} }
} }

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

@ -194,7 +194,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters()); Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); 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()); Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
} }
@ -252,7 +252,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters()); Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); 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()); Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
} }
@ -317,7 +317,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters()); Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); 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()); Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Once()); format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Once());
} }
@ -590,7 +590,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters()); Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); 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()); Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
} }
@ -648,7 +648,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters()); Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); 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()); Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
} }
@ -713,7 +713,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters()); Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); 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()); Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Once()); format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Once());
} }
@ -993,8 +993,7 @@ namespace OpenIddict.Tests
Assert.Equal(1483228800, (long) response[OpenIdConnectConstants.Claims.IssuedAt]); Assert.Equal(1483228800, (long) response[OpenIdConnectConstants.Claims.IssuedAt]);
Assert.Equal(1484006400, (long) response[OpenIdConnectConstants.Claims.ExpiresAt]); 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.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", 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()); format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Once());
} }
@ -1170,7 +1169,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters()); Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); 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()); Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
} }
@ -1228,7 +1227,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters()); Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); 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()); Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
} }
@ -1293,7 +1292,7 @@ namespace OpenIddict.Tests
Assert.Single(response.GetParameters()); Assert.Single(response.GetParameters());
Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); 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()); Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Once()); format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Once());
} }
@ -1573,8 +1572,7 @@ namespace OpenIddict.Tests
Assert.Equal(1483228800, (long) response[OpenIdConnectConstants.Claims.IssuedAt]); Assert.Equal(1483228800, (long) response[OpenIdConnectConstants.Claims.IssuedAt]);
Assert.Equal(1484006400, (long) response[OpenIdConnectConstants.Claims.ExpiresAt]); 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.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", 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()); format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Once());
} }

14
test/OpenIddict.Tests/OpenIddictProviderTests.cs

@ -446,7 +446,7 @@ namespace OpenIddict.Tests
}); });
// Assert // 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()); Mock.Get(manager).Verify(mock => mock.RedeemAsync(token, It.IsAny<CancellationToken>()), Times.Once());
} }
@ -521,7 +521,7 @@ namespace OpenIddict.Tests
Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error); Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error);
Assert.Equal("The specified authorization code is no longer valid.", response.ErrorDescription); 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()); Mock.Get(manager).Verify(mock => mock.RedeemAsync(token, It.IsAny<CancellationToken>()), Times.Once());
} }
@ -587,7 +587,7 @@ namespace OpenIddict.Tests
// Assert // Assert
Assert.NotNull(response.RefreshToken); 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()); Mock.Get(manager).Verify(mock => mock.RedeemAsync(token, It.IsAny<CancellationToken>()), Times.Once());
} }
@ -657,7 +657,7 @@ namespace OpenIddict.Tests
Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error); Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error);
Assert.Equal("The specified refresh token is no longer valid.", response.ErrorDescription); 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()); Mock.Get(manager).Verify(mock => mock.RedeemAsync(token, It.IsAny<CancellationToken>()), Times.Once());
} }
@ -715,7 +715,7 @@ namespace OpenIddict.Tests
// Assert // Assert
Assert.Null(response.RefreshToken); 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()); Mock.Get(manager).Verify(mock => mock.RedeemAsync(token, It.IsAny<CancellationToken>()), Times.Never());
} }
@ -791,7 +791,7 @@ namespace OpenIddict.Tests
// Assert // Assert
Assert.NotNull(response.RefreshToken); 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[1], It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.RevokeAsync(tokens[2], It.IsAny<CancellationToken>()), Times.Once()); Mock.Get(manager).Verify(mock => mock.RevokeAsync(tokens[2], It.IsAny<CancellationToken>()), Times.Once());
} }
@ -860,7 +860,7 @@ namespace OpenIddict.Tests
// Assert // Assert
Assert.Null(response.RefreshToken); 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[1], It.IsAny<CancellationToken>()), Times.Never());
Mock.Get(manager).Verify(mock => mock.RevokeAsync(tokens[2], It.IsAny<CancellationToken>()), Times.Never()); Mock.Get(manager).Verify(mock => mock.RevokeAsync(tokens[2], It.IsAny<CancellationToken>()), Times.Never());
} }

Loading…
Cancel
Save