Skip to content

Commit 9109d37

Browse files
uc4w6cjgrandja
authored andcommitted
Fix to return hashed client_secret when registering with client_secret_jwt
Closes gh-1344
1 parent 647e873 commit 9109d37

File tree

2 files changed

+65
-8
lines changed

2 files changed

+65
-8
lines changed

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

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -196,22 +196,28 @@ private OidcClientRegistrationAuthenticationToken registerClient(OidcClientRegis
196196
}
197197

198198
RegisteredClient registeredClient = this.registeredClientConverter.convert(clientRegistrationAuthentication.getClientRegistration());
199+
RegisteredClient.Builder registeredClientForDBBuilder = RegisteredClient.from(registeredClient);
200+
RegisteredClient.Builder registeredClientForResponseBuilder = RegisteredClient.from(registeredClient);
199201

200202
if (StringUtils.hasText(registeredClient.getClientSecret())) {
201203
// Encode the client secret
202-
RegisteredClient updatedRegisteredClient = RegisteredClient.from(registeredClient)
203-
.clientSecret(this.passwordEncoder.encode(registeredClient.getClientSecret()))
204-
.build();
205-
this.registeredClientRepository.save(updatedRegisteredClient);
206-
} else {
207-
this.registeredClientRepository.save(registeredClient);
204+
String encodedClientSecret = this.passwordEncoder.encode(registeredClient.getClientSecret());
205+
registeredClientForDBBuilder = registeredClientForDBBuilder
206+
.clientSecret(encodedClientSecret);
207+
if (ClientAuthenticationMethod.CLIENT_SECRET_JWT.getValue().equals(clientRegistrationAuthentication.getClientRegistration().getTokenEndpointAuthenticationMethod())) {
208+
registeredClientForResponseBuilder.clientSecret(encodedClientSecret);
209+
}
208210
}
209211

212+
this.registeredClientRepository.save(registeredClientForDBBuilder.build());
213+
214+
RegisteredClient registeredClientForResponse = registeredClientForResponseBuilder.build();
215+
210216
if (this.logger.isTraceEnabled()) {
211217
this.logger.trace("Saved registered client");
212218
}
213219

214-
OAuth2Authorization registeredClientAuthorization = registerAccessToken(registeredClient);
220+
OAuth2Authorization registeredClientAuthorization = registerAccessToken(registeredClientForResponse);
215221

216222
// Invalidate the "initial" access token as it can only be used once
217223
authorization = OidcAuthenticationProviderUtils.invalidate(authorization, authorization.getAccessToken().getToken());
@@ -224,7 +230,7 @@ private OidcClientRegistrationAuthenticationToken registerClient(OidcClientRegis
224230
this.logger.trace("Saved authorization with invalidated initial access token");
225231
}
226232

227-
Map<String, Object> clientRegistrationClaims = this.clientRegistrationConverter.convert(registeredClient).getClaims();
233+
Map<String, Object> clientRegistrationClaims = this.clientRegistrationConverter.convert(registeredClientForResponse).getClaims();
228234
OidcClientRegistration clientRegistration = OidcClientRegistration.withClaims(clientRegistrationClaims)
229235
.registrationAccessToken(registeredClientAuthorization.getAccessToken().getToken().getTokenValue())
230236
.build();

oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OidcClientRegistrationTests.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
6868
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
6969
import org.springframework.security.oauth2.jose.TestJwks;
70+
import org.springframework.security.oauth2.jose.jws.MacAlgorithm;
7071
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
7172
import org.springframework.security.oauth2.jwt.JwsHeader;
7273
import org.springframework.security.oauth2.jwt.Jwt;
@@ -102,6 +103,8 @@
102103
import org.springframework.test.web.servlet.MvcResult;
103104
import org.springframework.web.util.UriComponentsBuilder;
104105

106+
import javax.crypto.spec.SecretKeySpec;
107+
105108
import static org.assertj.core.api.Assertions.assertThat;
106109
import static org.hamcrest.CoreMatchers.containsString;
107110
import static org.mockito.ArgumentMatchers.any;
@@ -399,6 +402,54 @@ public void requestWhenClientRegistersWithSecretThenClientAuthenticationSuccess(
399402
.andReturn();
400403
}
401404

405+
@Test
406+
public void requestWhenClientRegistersWithClientSecretJwtThenClientAuthenticationSuccess() throws Exception {
407+
this.spring.register(AuthorizationServerConfiguration.class).autowire();
408+
409+
// @formatter:off
410+
OidcClientRegistration clientRegistration = OidcClientRegistration.builder()
411+
.clientName("client-name")
412+
.redirectUri("https://client.example.com")
413+
.grantType(AuthorizationGrantType.AUTHORIZATION_CODE.getValue())
414+
.grantType(AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
415+
.tokenEndpointAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_JWT.getValue())
416+
.scope("scope1")
417+
.scope("scope2")
418+
.build();
419+
// @formatter:on
420+
421+
OidcClientRegistration clientRegistrationResponse = registerClient(clientRegistration);
422+
423+
JwsHeader jwsHeader = JwsHeader.with(MacAlgorithm.HS256)
424+
.build();
425+
426+
Instant issuedAt = Instant.now();
427+
Instant expiresAt = issuedAt.plus(1, ChronoUnit.HOURS);
428+
JwtClaimsSet jwtClaimsSet = JwtClaimsSet.builder()
429+
.issuer(clientRegistrationResponse.getClientId())
430+
.subject(clientRegistrationResponse.getClientId())
431+
.audience(Collections.singletonList(asUrl(this.authorizationServerSettings.getIssuer(), this.authorizationServerSettings.getTokenEndpoint())))
432+
.issuedAt(issuedAt)
433+
.expiresAt(expiresAt)
434+
.build();
435+
436+
JWKSet jwkSet = new JWKSet(TestJwks.jwk(
437+
new SecretKeySpec(clientRegistrationResponse.getClientSecret().getBytes(), "HS256")).build());
438+
JwtEncoder jwtClientAssertionEncoder = new NimbusJwtEncoder((jwkSelector, securityContext) -> jwkSelector.select(jwkSet));
439+
440+
Jwt jwtAssertion = jwtClientAssertionEncoder.encode(JwtEncoderParameters.from(jwsHeader, jwtClaimsSet));
441+
442+
this.mvc.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
443+
.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
444+
.param(OAuth2ParameterNames.SCOPE, "scope1")
445+
.param(OAuth2ParameterNames.CLIENT_ASSERTION_TYPE, "urn:ietf:params:oauth:client-assertion-type:jwt-bearer")
446+
.param(OAuth2ParameterNames.CLIENT_ASSERTION, jwtAssertion.getTokenValue())
447+
.param(OAuth2ParameterNames.CLIENT_ID, clientRegistrationResponse.getClientId()))
448+
.andExpect(status().isOk())
449+
.andExpect(jsonPath("$.access_token").isNotEmpty())
450+
.andExpect(jsonPath("$.scope").value("scope1"));
451+
}
452+
402453
private OidcClientRegistration registerClient(OidcClientRegistration clientRegistration) throws Exception {
403454
// ***** (1) Obtain the "initial" access token used for registering the client
404455

0 commit comments

Comments
 (0)