Browse Source

Backport the token revocation changes to OpenIddict 1.x

pull/570/head
Kévin Chalet 9 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. // response will be returned to the client application.
await TryRevokeAuthorizationAsync(context.Ticket, context.HttpContext); await TryRevokeAuthorizationAsync(context.Ticket, context.HttpContext);
await TryRevokeTokensAsync(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 " + logger.LogError("The token request was rejected because the authorization code " +
"or refresh token '{Identifier}' has already been redeemed.", identifier); "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 logger = context.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var tokens = context.RequestServices.GetRequiredService<OpenIddictTokenManager<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. // Note: if the authorization identifier is null, return true as no tokens need to be revoked.
var identifier = ticket.GetProperty(OpenIddictConstants.Properties.AuthorizationId); var identifier = ticket.GetProperty(OpenIddictConstants.Properties.AuthorizationId);
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
@ -431,23 +458,13 @@ namespace OpenIddict
foreach (var token in await tokens.FindByAuthorizationIdAsync(identifier)) 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 continue;
// 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));
} }
catch (Exception exception) await TryRevokeTokenAsync(token, context);
{
logger.LogWarning(0, exception, "An exception occurred while trying to revoke the tokens " +
"associated with the token '{Identifier}'.",
await tokens.GetIdAsync(token));
return false;
}
} }
return true; return true;

2
test/OpenIddict.Tests/OpenIddictProviderTests.cs

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