Skip to content

Commit c5fcbbd

Browse files
Steve Riesenbergjgrandja
Steve Riesenberg
authored andcommitted
Do not issue refresh token to public client
Closes spring-projectsgh-296
1 parent 0ae0160 commit c5fcbbd

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.springframework.security.crypto.keygen.Base64StringKeyGenerator;
3333
import org.springframework.security.crypto.keygen.StringKeyGenerator;
3434
import org.springframework.security.oauth2.core.AuthorizationGrantType;
35+
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
3536
import org.springframework.security.oauth2.core.OAuth2AccessToken;
3637
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
3738
import org.springframework.security.oauth2.core.OAuth2Error;
@@ -191,7 +192,8 @@ public Authentication authenticate(Authentication authentication) throws Authent
191192
jwtAccessToken.getExpiresAt(), authorizedScopes);
192193

193194
OAuth2RefreshToken refreshToken = null;
194-
if (registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.REFRESH_TOKEN)) {
195+
if (registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.REFRESH_TOKEN)
196+
&& !registeredClient.getClientAuthenticationMethods().contains(ClientAuthenticationMethod.NONE)) {
195197
refreshToken = generateRefreshToken(registeredClient.getTokenSettings().getRefreshTokenTimeToLive());
196198
}
197199

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

+57
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,63 @@ public void authenticateWhenInvalidCodeThenThrowOAuth2AuthenticationException()
166166
.isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
167167
}
168168

169+
// gh-296
170+
@Test
171+
public void authenticateWhenPublicClientThenRefreshTokenIsNotIssued() {
172+
RegisteredClient registeredClient = TestRegisteredClients.registeredPublicClient()
173+
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
174+
.build();
175+
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient).build();
176+
when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(AUTHORIZATION_CODE_TOKEN_TYPE)))
177+
.thenReturn(authorization);
178+
179+
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(registeredClient);
180+
OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute(
181+
OAuth2AuthorizationRequest.class.getName());
182+
OAuth2AuthorizationCodeAuthenticationToken authentication =
183+
new OAuth2AuthorizationCodeAuthenticationToken(AUTHORIZATION_CODE, clientPrincipal, authorizationRequest.getRedirectUri(), null);
184+
185+
when(this.jwtEncoder.encode(any(), any())).thenReturn(createJwt());
186+
187+
OAuth2AccessTokenAuthenticationToken accessTokenAuthentication =
188+
(OAuth2AccessTokenAuthenticationToken) this.authenticationProvider.authenticate(authentication);
189+
190+
ArgumentCaptor<JwtEncodingContext> jwtEncodingContextCaptor = ArgumentCaptor.forClass(JwtEncodingContext.class);
191+
verify(this.jwtCustomizer).customize(jwtEncodingContextCaptor.capture());
192+
JwtEncodingContext jwtEncodingContext = jwtEncodingContextCaptor.getValue();
193+
assertThat(jwtEncodingContext.getRegisteredClient()).isEqualTo(registeredClient);
194+
assertThat(jwtEncodingContext.<Authentication>getPrincipal()).isEqualTo(authorization.getAttribute(Principal.class.getName()));
195+
assertThat(jwtEncodingContext.getAuthorization()).isEqualTo(authorization);
196+
assertThat(jwtEncodingContext.getAuthorizedScopes())
197+
.isEqualTo(authorization.getAttribute(OAuth2Authorization.AUTHORIZED_SCOPE_ATTRIBUTE_NAME));
198+
assertThat(jwtEncodingContext.getTokenType()).isEqualTo(OAuth2TokenType.ACCESS_TOKEN);
199+
assertThat(jwtEncodingContext.getAuthorizationGrantType()).isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE);
200+
assertThat(jwtEncodingContext.<OAuth2AuthorizationGrantAuthenticationToken>getAuthorizationGrant()).isEqualTo(authentication);
201+
assertThat(jwtEncodingContext.getHeaders()).isNotNull();
202+
assertThat(jwtEncodingContext.getClaims()).isNotNull();
203+
204+
ArgumentCaptor<JwtClaimsSet> jwtClaimsSetCaptor = ArgumentCaptor.forClass(JwtClaimsSet.class);
205+
verify(this.jwtEncoder).encode(any(), jwtClaimsSetCaptor.capture());
206+
JwtClaimsSet jwtClaimsSet = jwtClaimsSetCaptor.getValue();
207+
208+
Set<String> scopes = jwtClaimsSet.getClaim(OAuth2ParameterNames.SCOPE);
209+
assertThat(scopes).isEqualTo(authorization.getAttribute(OAuth2Authorization.AUTHORIZED_SCOPE_ATTRIBUTE_NAME));
210+
assertThat(jwtClaimsSet.getSubject()).isEqualTo(authorization.getPrincipalName());
211+
212+
ArgumentCaptor<OAuth2Authorization> authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class);
213+
verify(this.authorizationService).save(authorizationCaptor.capture());
214+
OAuth2Authorization updatedAuthorization = authorizationCaptor.getValue();
215+
216+
assertThat(accessTokenAuthentication.getRegisteredClient().getId()).isEqualTo(updatedAuthorization.getRegisteredClientId());
217+
assertThat(accessTokenAuthentication.getPrincipal()).isEqualTo(clientPrincipal);
218+
assertThat(accessTokenAuthentication.getAccessToken()).isEqualTo(updatedAuthorization.getAccessToken().getToken());
219+
assertThat(accessTokenAuthentication.getAccessToken().getScopes())
220+
.isEqualTo(authorization.getAttribute(OAuth2Authorization.AUTHORIZED_SCOPE_ATTRIBUTE_NAME));
221+
assertThat(accessTokenAuthentication.getRefreshToken()).isNull();
222+
OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCode = updatedAuthorization.getToken(OAuth2AuthorizationCode.class);
223+
assertThat(authorizationCode.isInvalidated()).isTrue();
224+
}
225+
169226
@Test
170227
public void authenticateWhenCodeIssuedToAnotherClientThenThrowOAuth2AuthenticationException() {
171228
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization().build();

0 commit comments

Comments
 (0)