Fix device access token response error codes
Closes gh-1885 Signed-off-by: Nick Holloway <nick.holloway@pyrites.org.uk>
This commit is contained in:
committed by
Joe Grandja
parent
fae09f66ac
commit
8d4da24892
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2023 the original author or authors.
|
||||
* Copyright 2020-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -134,9 +134,30 @@ public final class OAuth2DeviceCodeAuthenticationProvider implements Authenticat
|
||||
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_GRANT);
|
||||
}
|
||||
|
||||
if (deviceCode.isInvalidated() && !userCode.isInvalidated()) {
|
||||
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_GRANT);
|
||||
}
|
||||
|
||||
// In https://www.rfc-editor.org/rfc/rfc8628.html#section-3.5,
|
||||
// the following error codes are defined:
|
||||
|
||||
// expired_token
|
||||
// The "device_code" has expired, and the device authorization
|
||||
// session has concluded. The client MAY commence a new device
|
||||
// authorization request but SHOULD wait for user interaction before
|
||||
// restarting to avoid unnecessary polling.
|
||||
if (deviceCode.isExpired()) {
|
||||
// Invalidate the device code
|
||||
authorization = OAuth2AuthenticationProviderUtils.invalidate(authorization, deviceCode.getToken());
|
||||
this.authorizationService.save(authorization);
|
||||
if (this.logger.isWarnEnabled()) {
|
||||
this.logger.warn(LogMessage.format("Invalidated device code used by registered client '%s'",
|
||||
authorization.getRegisteredClientId()));
|
||||
}
|
||||
OAuth2Error error = new OAuth2Error(EXPIRED_TOKEN, null, DEVICE_ERROR_URI);
|
||||
throw new OAuth2AuthenticationException(error);
|
||||
}
|
||||
|
||||
// authorization_pending
|
||||
// The authorization request is still pending as the end user hasn't
|
||||
// yet completed the user-interaction steps (Section 3.3). The
|
||||
@@ -165,23 +186,6 @@ public final class OAuth2DeviceCodeAuthenticationProvider implements Authenticat
|
||||
throw new OAuth2AuthenticationException(error);
|
||||
}
|
||||
|
||||
// expired_token
|
||||
// The "device_code" has expired, and the device authorization
|
||||
// session has concluded. The client MAY commence a new device
|
||||
// authorization request but SHOULD wait for user interaction before
|
||||
// restarting to avoid unnecessary polling.
|
||||
if (deviceCode.isExpired()) {
|
||||
// Invalidate the device code
|
||||
authorization = OAuth2AuthenticationProviderUtils.invalidate(authorization, deviceCode.getToken());
|
||||
this.authorizationService.save(authorization);
|
||||
if (this.logger.isWarnEnabled()) {
|
||||
this.logger.warn(LogMessage.format("Invalidated device code used by registered client '%s'",
|
||||
authorization.getRegisteredClientId()));
|
||||
}
|
||||
OAuth2Error error = new OAuth2Error(EXPIRED_TOKEN, null, DEVICE_ERROR_URI);
|
||||
throw new OAuth2AuthenticationException(error);
|
||||
}
|
||||
|
||||
if (this.logger.isTraceEnabled()) {
|
||||
this.logger.trace("Validated device token request parameters");
|
||||
}
|
||||
|
||||
@@ -191,6 +191,7 @@ public class OAuth2DeviceCodeAuthenticationProviderTests {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
Authentication authentication = createAuthentication(registeredClient);
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.token(createDeviceCode())
|
||||
.token(createUserCode())
|
||||
.build();
|
||||
given(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class))).willReturn(authorization);
|
||||
@@ -209,7 +210,7 @@ public class OAuth2DeviceCodeAuthenticationProviderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenDeviceCodeIsInvalidatedThenThrowOAuth2AuthenticationException() {
|
||||
public void authenticateWhenDeviceCodeAndUserCodeAreInvalidatedThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
Authentication authentication = createAuthentication(registeredClient);
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
@@ -231,13 +232,36 @@ public class OAuth2DeviceCodeAuthenticationProviderTests {
|
||||
verifyNoInteractions(this.tokenGenerator);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenDeviceCodeIsInvalidatedThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
Authentication authentication = createAuthentication(registeredClient);
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.token(createDeviceCode(), withInvalidated())
|
||||
.token(createUserCode())
|
||||
.build();
|
||||
given(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class))).willReturn(authorization);
|
||||
// @formatter:off
|
||||
assertThatExceptionOfType(OAuth2AuthenticationException.class)
|
||||
.isThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.extracting(OAuth2AuthenticationException::getError)
|
||||
.extracting(OAuth2Error::getErrorCode)
|
||||
.isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
|
||||
// @formatter:on
|
||||
|
||||
verify(this.authorizationService).findByToken(DEVICE_CODE,
|
||||
OAuth2DeviceCodeAuthenticationProvider.DEVICE_CODE_TOKEN_TYPE);
|
||||
verifyNoMoreInteractions(this.authorizationService);
|
||||
verifyNoInteractions(this.tokenGenerator);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenDeviceCodeIsExpiredThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
Authentication authentication = createAuthentication(registeredClient);
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.token(createExpiredDeviceCode())
|
||||
.token(createUserCode(), withInvalidated())
|
||||
.token(createUserCode())
|
||||
.build();
|
||||
given(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class))).willReturn(authorization);
|
||||
// @formatter:off
|
||||
|
||||
Reference in New Issue
Block a user