Browse Source

Backport the token revocation changes to OpenIddict 1.x

pull/570/head
Kévin Chalet 8 years ago
parent
commit
edc75dcd8e
  1. 1
      src/OpenIddict/OpenIddictProvider.Exchange.cs
  2. 47
      src/OpenIddict/OpenIddictProvider.Helpers.cs
  3. 2
      test/OpenIddict.Tests/OpenIddictProviderTests.cs

1
src/OpenIddict/OpenIddictProvider.Exchange.cs

@ -277,6 +277,7 @@ namespace OpenIddict
// response will be returned to the client application.
await TryRevokeAuthorizationAsync(context.Ticket, context.HttpContext);
await TryRevokeTokensAsync(context.Ticket, context.HttpContext);
await TryRevokeTokenAsync(token, context.HttpContext);
logger.LogError("The token request was rejected because the authorization code " +
"or refresh token '{Identifier}' has already been redeemed.", identifier);

47
src/OpenIddict/OpenIddictProvider.Helpers.cs

@ -417,11 +417,38 @@ namespace OpenIddict
}
}
private async Task<bool> TryRevokeTokensAsync([NotNull] AuthenticationTicket ticket, [NotNull] HttpContext context)
private async Task<bool> TryRevokeTokenAsync([NotNull] TToken token, [NotNull] HttpContext context)
{
var logger = context.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var tokens = context.RequestServices.GetRequiredService<OpenIddictTokenManager<TToken>>();
var identifier = await tokens.GetIdAsync(token);
Debug.Assert(!string.IsNullOrEmpty(identifier), "The token identifier shouldn't be null or empty.");
try
{
// Note: the request cancellation token is deliberately not used here to ensure the caller
// cannot prevent this operation from being executed by resetting the TCP connection.
await tokens.RevokeAsync(token);
logger.LogInformation("The token '{Identifier}' was automatically revoked.", identifier);
return true;
}
catch (Exception exception)
{
logger.LogWarning(0, exception, "An exception occurred while trying to revoke " +
"the token '{Identifier}'.", identifier);
return false;
}
}
private async Task<bool> TryRevokeTokensAsync([NotNull] AuthenticationTicket ticket, [NotNull] HttpContext context)
{
var tokens = context.RequestServices.GetRequiredService<OpenIddictTokenManager<TToken>>();
// Note: if the authorization identifier is null, return true as no tokens need to be revoked.
var identifier = ticket.GetProperty(OpenIddictConstants.Properties.AuthorizationId);
if (string.IsNullOrEmpty(identifier))
@ -431,23 +458,13 @@ namespace OpenIddict
foreach (var token in await tokens.FindByAuthorizationIdAsync(identifier))
{
try
// Don't change the status of the token used in the token request.
if (string.Equals(ticket.GetTokenId(), await tokens.GetIdAsync(token), StringComparison.Ordinal))
{
// Note: the request cancellation token is deliberately not used here to ensure the caller
// cannot prevent this operation from being executed by resetting the TCP connection.
await tokens.RevokeAsync(token);
logger.LogInformation("The token '{Identifier}' was automatically revoked.",
await tokens.GetIdAsync(token));
continue;
}
catch (Exception exception)
{
logger.LogWarning(0, exception, "An exception occurred while trying to revoke the tokens " +
"associated with the token '{Identifier}'.",
await tokens.GetIdAsync(token));
return false;
}
await TryRevokeTokenAsync(token, context);
}
return true;

2
test/OpenIddict.Tests/OpenIddictProviderTests.cs

@ -825,6 +825,7 @@ namespace OpenIddict.Tests
Assert.NotNull(response.RefreshToken);
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[0], It.IsAny<CancellationToken>()), Times.Never());
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());
}
@ -894,6 +895,7 @@ namespace OpenIddict.Tests
Assert.Null(response.RefreshToken);
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[0], 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());
}

Loading…
Cancel
Save