Skip to content

Commit d5914f4

Browse files
author
Steve Riesenberg
committed
Fix token expired and not before use check
Closes gh-290
1 parent 2712a7b commit d5914f4

File tree

2 files changed

+75
-47
lines changed

2 files changed

+75
-47
lines changed

oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeAuthenticationProvider.java

+9-19
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,11 @@
1515
*/
1616
package org.springframework.security.oauth2.server.authorization.authentication;
1717

18-
import java.security.Principal;
19-
import java.util.Collections;
20-
import java.util.HashMap;
21-
import java.util.Map;
22-
import java.util.Set;
23-
2418
import org.springframework.beans.factory.annotation.Autowired;
2519
import org.springframework.security.authentication.AuthenticationProvider;
2620
import org.springframework.security.core.Authentication;
2721
import org.springframework.security.core.AuthenticationException;
28-
import org.springframework.security.oauth2.core.AuthorizationGrantType;
29-
import org.springframework.security.oauth2.core.OAuth2AccessToken;
30-
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
31-
import org.springframework.security.oauth2.core.OAuth2Error;
32-
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
33-
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
34-
import org.springframework.security.oauth2.core.OAuth2TokenType;
22+
import org.springframework.security.oauth2.core.*;
3523
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
3624
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
3725
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
@@ -41,16 +29,18 @@
4129
import org.springframework.security.oauth2.jwt.Jwt;
4230
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
4331
import org.springframework.security.oauth2.jwt.JwtEncoder;
44-
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
45-
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
32+
import org.springframework.security.oauth2.server.authorization.*;
4633
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
4734
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
48-
import org.springframework.security.oauth2.server.authorization.JwtEncodingContext;
49-
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationCode;
50-
import org.springframework.security.oauth2.server.authorization.OAuth2TokenCustomizer;
5135
import org.springframework.util.Assert;
5236
import org.springframework.util.StringUtils;
5337

38+
import java.security.Principal;
39+
import java.util.Collections;
40+
import java.util.HashMap;
41+
import java.util.Map;
42+
import java.util.Set;
43+
5444
import static org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthenticationProviderUtils.getAuthenticatedClientElseThrowInvalidClient;
5545

5646
/**
@@ -135,7 +125,7 @@ public Authentication authenticate(Authentication authentication) throws Authent
135125
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT));
136126
}
137127

138-
if (authorizationCode.isInvalidated()) {
128+
if (!authorizationCode.isActive()) {
139129
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT));
140130
}
141131

oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeAuthenticationProviderTests.java

+66-28
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,12 @@
1515
*/
1616
package org.springframework.security.oauth2.server.authorization.authentication;
1717

18-
import java.security.Principal;
19-
import java.time.Duration;
20-
import java.time.Instant;
21-
import java.time.temporal.ChronoUnit;
22-
import java.util.HashMap;
23-
import java.util.HashSet;
24-
import java.util.Map;
25-
import java.util.Set;
26-
2718
import org.junit.Before;
2819
import org.junit.Test;
2920
import org.mockito.ArgumentCaptor;
30-
3121
import org.springframework.security.authentication.TestingAuthenticationToken;
3222
import org.springframework.security.core.Authentication;
33-
import org.springframework.security.oauth2.core.AuthorizationGrantType;
34-
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
35-
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
36-
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
37-
import org.springframework.security.oauth2.core.OAuth2TokenType;
23+
import org.springframework.security.oauth2.core.*;
3824
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
3925
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
4026
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
@@ -45,24 +31,20 @@
4531
import org.springframework.security.oauth2.jwt.Jwt;
4632
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
4733
import org.springframework.security.oauth2.jwt.JwtEncoder;
48-
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
49-
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
50-
import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations;
34+
import org.springframework.security.oauth2.server.authorization.*;
5135
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
5236
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;
5637

57-
import static org.assertj.core.api.Assertions.assertThat;
58-
import static org.assertj.core.api.Assertions.assertThatThrownBy;
59-
import static org.assertj.core.api.Assertions.entry;
38+
import java.security.Principal;
39+
import java.time.Duration;
40+
import java.time.Instant;
41+
import java.time.temporal.ChronoUnit;
42+
import java.util.*;
43+
44+
import static org.assertj.core.api.Assertions.*;
6045
import static org.mockito.ArgumentMatchers.any;
6146
import static org.mockito.ArgumentMatchers.eq;
62-
import static org.mockito.Mockito.mock;
63-
import static org.mockito.Mockito.times;
64-
import static org.mockito.Mockito.verify;
65-
import static org.mockito.Mockito.when;
47+
import static org.mockito.Mockito.*;
6648

6749
/**
6850
* Tests for {@link OAuth2AuthorizationCodeAuthenticationProvider}.
@@ -222,6 +204,62 @@ public void authenticateWhenInvalidatedCodeThenThrowOAuth2AuthenticationExceptio
222204
.isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
223205
}
224206

207+
// gh-290
208+
@Test
209+
public void authenticateWhenExpiredCodeThenThrowOAuth2AuthenticationException() throws InterruptedException {
210+
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
211+
Instant now = Instant.now();
212+
OAuth2AuthorizationCode authorizationCode = new OAuth2AuthorizationCode(
213+
AUTHORIZATION_CODE, now, now.plusNanos(1));
214+
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient)
215+
.token(authorizationCode)
216+
.build();
217+
when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(AUTHORIZATION_CODE_TOKEN_TYPE)))
218+
.thenReturn(authorization);
219+
220+
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(registeredClient);
221+
OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute(
222+
OAuth2AuthorizationRequest.class.getName());
223+
OAuth2AuthorizationCodeAuthenticationToken authentication =
224+
new OAuth2AuthorizationCodeAuthenticationToken(AUTHORIZATION_CODE, clientPrincipal, authorizationRequest.getRedirectUri(), null);
225+
226+
// Busy wait a brief moment for token to expire. TODO: Add a way to mock the underlying java.time.Clock?
227+
while (!Instant.now().isAfter(authorizationCode.getExpiresAt())) {
228+
Thread.sleep(0, 1);
229+
}
230+
231+
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
232+
.isInstanceOf(OAuth2AuthenticationException.class)
233+
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
234+
.extracting("errorCode")
235+
.isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
236+
}
237+
238+
// gh-290
239+
@Test
240+
public void authenticateWhenCodeIsBeforeUseThenThrowOAuth2AuthenticationException() throws InterruptedException {
241+
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
242+
OAuth2AuthorizationCode authorizationCode = new OAuth2AuthorizationCode(
243+
AUTHORIZATION_CODE, Instant.now(), Instant.now().plusSeconds(240));
244+
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient)
245+
.token(authorizationCode, (metadata) -> metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME, Collections.singletonMap("nbf", Instant.now().plusSeconds(120))))
246+
.build();
247+
when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(AUTHORIZATION_CODE_TOKEN_TYPE)))
248+
.thenReturn(authorization);
249+
250+
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(registeredClient);
251+
OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute(
252+
OAuth2AuthorizationRequest.class.getName());
253+
OAuth2AuthorizationCodeAuthenticationToken authentication =
254+
new OAuth2AuthorizationCodeAuthenticationToken(AUTHORIZATION_CODE, clientPrincipal, authorizationRequest.getRedirectUri(), null);
255+
256+
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
257+
.isInstanceOf(OAuth2AuthenticationException.class)
258+
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
259+
.extracting("errorCode")
260+
.isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
261+
}
262+
225263
@Test
226264
public void authenticateWhenValidCodeThenReturnAccessToken() {
227265
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();

0 commit comments

Comments
 (0)