Skip to content

Commit b7ddb83

Browse files
committed
Polish gh-84
1 parent dc94e5e commit b7ddb83

File tree

18 files changed

+585
-438
lines changed

18 files changed

+585
-438
lines changed

core/src/main/java/org/springframework/security/oauth2/server/authorization/DefaultOAuth2TokenRevocationService.java

Lines changed: 0 additions & 48 deletions
This file was deleted.

core/src/main/java/org/springframework/security/oauth2/server/authorization/OAuth2TokenRevocationService.java

Lines changed: 0 additions & 34 deletions
This file was deleted.

core/src/test/java/org/springframework/security/oauth2/server/authorization/DefaultOAuth2TokenRevocationServiceTests.java

Lines changed: 0 additions & 92 deletions
This file was deleted.

oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationServerConfigurer.java

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,13 @@
3131
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeAuthenticationProvider;
3232
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationProvider;
3333
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientCredentialsAuthenticationProvider;
34+
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenRevocationAuthenticationProvider;
3435
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
3536
import org.springframework.security.oauth2.server.authorization.web.JwkSetEndpointFilter;
3637
import org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationEndpointFilter;
3738
import org.springframework.security.oauth2.server.authorization.web.OAuth2ClientAuthenticationFilter;
3839
import org.springframework.security.oauth2.server.authorization.web.OAuth2TokenEndpointFilter;
40+
import org.springframework.security.oauth2.server.authorization.web.OAuth2TokenRevocationEndpointFilter;
3941
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
4042
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
4143
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
@@ -73,6 +75,8 @@ public final class OAuth2AuthorizationServerConfigurer<B extends HttpSecurityBui
7375
HttpMethod.POST.name()));
7476
private final RequestMatcher tokenEndpointMatcher = new AntPathRequestMatcher(
7577
OAuth2TokenEndpointFilter.DEFAULT_TOKEN_ENDPOINT_URI, HttpMethod.POST.name());
78+
private final RequestMatcher tokenRevocationEndpointMatcher = new AntPathRequestMatcher(
79+
OAuth2TokenRevocationEndpointFilter.DEFAULT_TOKEN_REVOCATION_ENDPOINT_URI, HttpMethod.POST.name());
7680
private final RequestMatcher jwkSetEndpointMatcher = new AntPathRequestMatcher(
7781
JwkSetEndpointFilter.DEFAULT_JWK_SET_ENDPOINT_URI, HttpMethod.GET.name());
7882

@@ -118,8 +122,8 @@ public OAuth2AuthorizationServerConfigurer<B> keyManager(KeyManager keyManager)
118122
* @return a {@code List} of {@link RequestMatcher}'s for the authorization server endpoints
119123
*/
120124
public List<RequestMatcher> getEndpointMatchers() {
121-
return Arrays.asList(this.authorizationEndpointMatcher,
122-
this.tokenEndpointMatcher, this.jwkSetEndpointMatcher);
125+
return Arrays.asList(this.authorizationEndpointMatcher, this.tokenEndpointMatcher,
126+
this.tokenRevocationEndpointMatcher, this.jwkSetEndpointMatcher);
123127
}
124128

125129
@Override
@@ -145,11 +149,17 @@ public void init(B builder) {
145149
jwtEncoder);
146150
builder.authenticationProvider(postProcess(clientCredentialsAuthenticationProvider));
147151

152+
OAuth2TokenRevocationAuthenticationProvider tokenRevocationAuthenticationProvider =
153+
new OAuth2TokenRevocationAuthenticationProvider(
154+
getAuthorizationService(builder));
155+
builder.authenticationProvider(postProcess(tokenRevocationAuthenticationProvider));
156+
148157
ExceptionHandlingConfigurer<B> exceptionHandling = builder.getConfigurer(ExceptionHandlingConfigurer.class);
149158
if (exceptionHandling != null) {
150-
// Register the default AuthenticationEntryPoint for the token endpoint
159+
// Register the default AuthenticationEntryPoint for the token endpoint and token revocation endpoint
151160
exceptionHandling.defaultAuthenticationEntryPointFor(
152-
new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED), this.tokenEndpointMatcher);
161+
new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED),
162+
new OrRequestMatcher(this.tokenEndpointMatcher, this.tokenRevocationEndpointMatcher));
153163
}
154164
}
155165

@@ -160,8 +170,10 @@ public void configure(B builder) {
160170

161171
AuthenticationManager authenticationManager = builder.getSharedObject(AuthenticationManager.class);
162172

163-
OAuth2ClientAuthenticationFilter clientAuthenticationFilter = new OAuth2ClientAuthenticationFilter(
164-
authenticationManager, this.tokenEndpointMatcher);
173+
OAuth2ClientAuthenticationFilter clientAuthenticationFilter =
174+
new OAuth2ClientAuthenticationFilter(
175+
authenticationManager,
176+
new OrRequestMatcher(this.tokenEndpointMatcher, this.tokenRevocationEndpointMatcher));
165177
builder.addFilterAfter(postProcess(clientAuthenticationFilter), AbstractPreAuthenticatedProcessingFilter.class);
166178

167179
OAuth2AuthorizationEndpointFilter authorizationEndpointFilter =
@@ -175,6 +187,11 @@ public void configure(B builder) {
175187
authenticationManager,
176188
getAuthorizationService(builder));
177189
builder.addFilterAfter(postProcess(tokenEndpointFilter), FilterSecurityInterceptor.class);
190+
191+
OAuth2TokenRevocationEndpointFilter tokenRevocationEndpointFilter =
192+
new OAuth2TokenRevocationEndpointFilter(
193+
authenticationManager);
194+
builder.addFilterAfter(postProcess(tokenRevocationEndpointFilter), OAuth2TokenEndpointFilter.class);
178195
}
179196

180197
private static <B extends HttpSecurityBuilder<B>> RegisteredClientRepository getRegisteredClientRepository(B builder) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616
package org.springframework.security.oauth2.server.authorization;
1717

18-
import org.springframework.security.oauth2.server.authorization.Version;
1918
import org.springframework.util.Assert;
2019

2120
import java.io.Serializable;
@@ -26,6 +25,7 @@
2625
public final class TokenType implements Serializable {
2726
private static final long serialVersionUID = Version.SERIAL_VERSION_UID;
2827
public static final TokenType ACCESS_TOKEN = new TokenType("access_token");
28+
public static final TokenType REFRESH_TOKEN = new TokenType("refresh_token");
2929
public static final TokenType AUTHORIZATION_CODE = new TokenType("authorization_code");
3030
private final String value;
3131

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.security.oauth2.server.authorization.authentication;
17+
18+
import org.springframework.security.authentication.AuthenticationProvider;
19+
import org.springframework.security.oauth2.core.AbstractOAuth2Token;
20+
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
21+
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
22+
import org.springframework.security.oauth2.server.authorization.token.OAuth2AuthorizationCode;
23+
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenMetadata;
24+
import org.springframework.security.oauth2.server.authorization.token.OAuth2Tokens;
25+
26+
/**
27+
* Utility methods for the OAuth 2.0 {@link AuthenticationProvider}'s.
28+
*
29+
* @author Joe Grandja
30+
* @since 0.0.3
31+
*/
32+
final class OAuth2AuthenticationProviderUtils {
33+
34+
private OAuth2AuthenticationProviderUtils() {
35+
}
36+
37+
static <T extends AbstractOAuth2Token> OAuth2Authorization invalidate(
38+
OAuth2Authorization authorization, T token) {
39+
40+
OAuth2Tokens.Builder builder = OAuth2Tokens.from(authorization.getTokens())
41+
.token(token, OAuth2TokenMetadata.builder().invalidated().build());
42+
43+
if (OAuth2RefreshToken.class.isAssignableFrom(token.getClass())) {
44+
builder.token(
45+
authorization.getTokens().getAccessToken(),
46+
OAuth2TokenMetadata.builder().invalidated().build());
47+
OAuth2AuthorizationCode authorizationCode =
48+
authorization.getTokens().getToken(OAuth2AuthorizationCode.class);
49+
if (authorizationCode != null &&
50+
!authorization.getTokens().getTokenMetadata(authorizationCode).isInvalidated()) {
51+
builder.token(
52+
authorizationCode,
53+
OAuth2TokenMetadata.builder().invalidated().build());
54+
}
55+
}
56+
57+
return OAuth2Authorization.from(authorization)
58+
.tokens(builder.build())
59+
.build();
60+
}
61+
}

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

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,17 @@ public Authentication authenticate(Authentication authentication) throws Authent
105105
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT));
106106
}
107107
OAuth2AuthorizationCode authorizationCode = authorization.getTokens().getToken(OAuth2AuthorizationCode.class);
108+
OAuth2TokenMetadata authorizationCodeMetadata = authorization.getTokens().getTokenMetadata(authorizationCode);
108109

109110
OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute(
110111
OAuth2AuthorizationAttributeNames.AUTHORIZATION_REQUEST);
111112

112113
if (!registeredClient.getClientId().equals(authorizationRequest.getClientId())) {
113-
// Invalidate the authorization code given that a different client is attempting to use it
114-
authorization.getTokens().invalidate(authorizationCode);
115-
this.authorizationService.save(authorization);
114+
if (!authorizationCodeMetadata.isInvalidated()) {
115+
// Invalidate the authorization code given that a different client is attempting to use it
116+
authorization = OAuth2AuthenticationProviderUtils.invalidate(authorization, authorizationCode);
117+
this.authorizationService.save(authorization);
118+
}
116119
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT));
117120
}
118121

@@ -121,9 +124,7 @@ public Authentication authenticate(Authentication authentication) throws Authent
121124
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT));
122125
}
123126

124-
OAuth2TokenMetadata authorizationCodeMetadata = authorization.getTokens().getTokenMetadata(authorizationCode);
125127
if (authorizationCodeMetadata.isInvalidated()) {
126-
// Prevent the same client from using the authorization code more than once
127128
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT));
128129
}
129130

@@ -154,15 +155,16 @@ public Authentication authenticate(Authentication authentication) throws Authent
154155
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
155156
jwt.getTokenValue(), jwt.getIssuedAt(), jwt.getExpiresAt(), jwt.getClaim(OAuth2ParameterNames.SCOPE));
156157

157-
OAuth2Tokens tokens = OAuth2Tokens.from(authorization.getTokens())
158-
.accessToken(accessToken)
159-
.build();
160-
tokens.invalidate(authorizationCode); // Invalidate the authorization code as it can only be used once
161-
162158
authorization = OAuth2Authorization.from(authorization)
163-
.tokens(tokens)
159+
.tokens(OAuth2Tokens.from(authorization.getTokens())
160+
.accessToken(accessToken)
161+
.build())
164162
.attribute(OAuth2AuthorizationAttributeNames.ACCESS_TOKEN_ATTRIBUTES, jwt)
165163
.build();
164+
165+
// Invalidate the authorization code as it can only be used once
166+
authorization = OAuth2AuthenticationProviderUtils.invalidate(authorization, authorizationCode);
167+
166168
this.authorizationService.save(authorization);
167169

168170
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken);

0 commit comments

Comments
 (0)