|
19 | 19 | import java.time.Duration; |
20 | 20 | import java.time.Instant; |
21 | 21 | import java.time.temporal.ChronoUnit; |
| 22 | +import java.util.Collections; |
22 | 23 | import java.util.HashMap; |
23 | 24 | import java.util.HashSet; |
24 | 25 | import java.util.Map; |
|
45 | 46 | import org.springframework.security.oauth2.jwt.Jwt; |
46 | 47 | import org.springframework.security.oauth2.jwt.JwtClaimsSet; |
47 | 48 | import org.springframework.security.oauth2.jwt.JwtEncoder; |
| 49 | +import org.springframework.security.oauth2.server.authorization.JwtEncodingContext; |
48 | 50 | import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; |
| 51 | +import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationCode; |
49 | 52 | import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; |
| 53 | +import org.springframework.security.oauth2.server.authorization.OAuth2TokenCustomizer; |
50 | 54 | import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations; |
51 | 55 | import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; |
52 | 56 | import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients; |
53 | | -import org.springframework.security.oauth2.server.authorization.JwtEncodingContext; |
54 | | -import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationCode; |
55 | | -import org.springframework.security.oauth2.server.authorization.OAuth2TokenCustomizer; |
56 | 57 |
|
57 | 58 | import static org.assertj.core.api.Assertions.assertThat; |
58 | 59 | import static org.assertj.core.api.Assertions.assertThatThrownBy; |
@@ -222,6 +223,62 @@ public void authenticateWhenInvalidatedCodeThenThrowOAuth2AuthenticationExceptio |
222 | 223 | .isEqualTo(OAuth2ErrorCodes.INVALID_GRANT); |
223 | 224 | } |
224 | 225 |
|
| 226 | +// gh-290 |
| 227 | +@Test |
| 228 | +public void authenticateWhenExpiredCodeThenThrowOAuth2AuthenticationException() throws InterruptedException { |
| 229 | +RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); |
| 230 | +Instant now = Instant.now(); |
| 231 | +OAuth2AuthorizationCode authorizationCode = new OAuth2AuthorizationCode( |
| 232 | +AUTHORIZATION_CODE, now, now.plusNanos(1)); |
| 233 | +OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient) |
| 234 | +.token(authorizationCode) |
| 235 | +.build(); |
| 236 | +when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(AUTHORIZATION_CODE_TOKEN_TYPE))) |
| 237 | +.thenReturn(authorization); |
| 238 | + |
| 239 | +OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(registeredClient); |
| 240 | +OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute( |
| 241 | +OAuth2AuthorizationRequest.class.getName()); |
| 242 | +OAuth2AuthorizationCodeAuthenticationToken authentication = |
| 243 | +new OAuth2AuthorizationCodeAuthenticationToken(AUTHORIZATION_CODE, clientPrincipal, authorizationRequest.getRedirectUri(), null); |
| 244 | + |
| 245 | +// Busy wait a brief moment for token to expire. TODO: Add a way to mock the underlying java.time.Clock? |
| 246 | +while (!Instant.now().isAfter(authorizationCode.getExpiresAt())) { |
| 247 | +Thread.sleep(0, 1); |
| 248 | +} |
| 249 | + |
| 250 | +assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication)) |
| 251 | +.isInstanceOf(OAuth2AuthenticationException.class) |
| 252 | +.extracting(ex -> ((OAuth2AuthenticationException) ex).getError()) |
| 253 | +.extracting("errorCode") |
| 254 | +.isEqualTo(OAuth2ErrorCodes.INVALID_GRANT); |
| 255 | +} |
| 256 | + |
| 257 | +// gh-290 |
| 258 | +@Test |
| 259 | +public void authenticateWhenCodeIsBeforeUseThenThrowOAuth2AuthenticationException() throws InterruptedException { |
| 260 | +RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); |
| 261 | +OAuth2AuthorizationCode authorizationCode = new OAuth2AuthorizationCode( |
| 262 | +AUTHORIZATION_CODE, Instant.now(), Instant.now().plusSeconds(240)); |
| 263 | +OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient) |
| 264 | +.token(authorizationCode, (metadata) -> metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME, Collections.singletonMap("nbf", Instant.now().plusSeconds(120)))) |
| 265 | +.build(); |
| 266 | +when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(AUTHORIZATION_CODE_TOKEN_TYPE))) |
| 267 | +.thenReturn(authorization); |
| 268 | + |
| 269 | +OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(registeredClient); |
| 270 | +OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute( |
| 271 | +OAuth2AuthorizationRequest.class.getName()); |
| 272 | +OAuth2AuthorizationCodeAuthenticationToken authentication = |
| 273 | +new OAuth2AuthorizationCodeAuthenticationToken(AUTHORIZATION_CODE, clientPrincipal, authorizationRequest.getRedirectUri(), null); |
| 274 | + |
| 275 | +assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication)) |
| 276 | +.isInstanceOf(OAuth2AuthenticationException.class) |
| 277 | +.extracting(ex -> ((OAuth2AuthenticationException) ex).getError()) |
| 278 | +.extracting("errorCode") |
| 279 | +.isEqualTo(OAuth2ErrorCodes.INVALID_GRANT); |
| 280 | +} |
| 281 | + |
225 | 282 | @Test |
226 | 283 | public void authenticateWhenValidCodeThenReturnAccessToken() { |
227 | 284 | RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); |
|
0 commit comments