|
@@ -67,6 +67,7 @@ import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResp
|
|
|
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
|
|
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
|
|
|
import org.springframework.security.oauth2.jose.TestJwks;
|
|
|
+import org.springframework.security.oauth2.jose.jws.MacAlgorithm;
|
|
|
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
|
|
|
import org.springframework.security.oauth2.jwt.JwsHeader;
|
|
|
import org.springframework.security.oauth2.jwt.Jwt;
|
|
@@ -102,6 +103,8 @@ import org.springframework.test.web.servlet.MockMvc;
|
|
|
import org.springframework.test.web.servlet.MvcResult;
|
|
|
import org.springframework.web.util.UriComponentsBuilder;
|
|
|
|
|
|
+import javax.crypto.spec.SecretKeySpec;
|
|
|
+
|
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
|
import static org.hamcrest.CoreMatchers.containsString;
|
|
|
import static org.mockito.ArgumentMatchers.any;
|
|
@@ -399,6 +402,54 @@ public class OidcClientRegistrationTests {
|
|
|
.andReturn();
|
|
|
}
|
|
|
|
|
|
+ @Test
|
|
|
+ public void requestWhenClientRegistersWithClientSecretJwtThenClientAuthenticationSuccess() throws Exception {
|
|
|
+ this.spring.register(AuthorizationServerConfiguration.class).autowire();
|
|
|
+
|
|
|
+ // @formatter:off
|
|
|
+ OidcClientRegistration clientRegistration = OidcClientRegistration.builder()
|
|
|
+ .clientName("client-name")
|
|
|
+ .redirectUri("https://client.example.com")
|
|
|
+ .grantType(AuthorizationGrantType.AUTHORIZATION_CODE.getValue())
|
|
|
+ .grantType(AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
|
|
|
+ .tokenEndpointAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_JWT.getValue())
|
|
|
+ .scope("scope1")
|
|
|
+ .scope("scope2")
|
|
|
+ .build();
|
|
|
+ // @formatter:on
|
|
|
+
|
|
|
+ OidcClientRegistration clientRegistrationResponse = registerClient(clientRegistration);
|
|
|
+
|
|
|
+ JwsHeader jwsHeader = JwsHeader.with(MacAlgorithm.HS256)
|
|
|
+ .build();
|
|
|
+
|
|
|
+ Instant issuedAt = Instant.now();
|
|
|
+ Instant expiresAt = issuedAt.plus(1, ChronoUnit.HOURS);
|
|
|
+ JwtClaimsSet jwtClaimsSet = JwtClaimsSet.builder()
|
|
|
+ .issuer(clientRegistrationResponse.getClientId())
|
|
|
+ .subject(clientRegistrationResponse.getClientId())
|
|
|
+ .audience(Collections.singletonList(asUrl(this.authorizationServerSettings.getIssuer(), this.authorizationServerSettings.getTokenEndpoint())))
|
|
|
+ .issuedAt(issuedAt)
|
|
|
+ .expiresAt(expiresAt)
|
|
|
+ .build();
|
|
|
+
|
|
|
+ JWKSet jwkSet = new JWKSet(TestJwks.jwk(
|
|
|
+ new SecretKeySpec(clientRegistrationResponse.getClientSecret().getBytes(), "HS256")).build());
|
|
|
+ JwtEncoder jwtClientAssertionEncoder = new NimbusJwtEncoder((jwkSelector, securityContext) -> jwkSelector.select(jwkSet));
|
|
|
+
|
|
|
+ Jwt jwtAssertion = jwtClientAssertionEncoder.encode(JwtEncoderParameters.from(jwsHeader, jwtClaimsSet));
|
|
|
+
|
|
|
+ this.mvc.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
|
|
|
+ .param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
|
|
|
+ .param(OAuth2ParameterNames.SCOPE, "scope1")
|
|
|
+ .param(OAuth2ParameterNames.CLIENT_ASSERTION_TYPE, "urn:ietf:params:oauth:client-assertion-type:jwt-bearer")
|
|
|
+ .param(OAuth2ParameterNames.CLIENT_ASSERTION, jwtAssertion.getTokenValue())
|
|
|
+ .param(OAuth2ParameterNames.CLIENT_ID, clientRegistrationResponse.getClientId()))
|
|
|
+ .andExpect(status().isOk())
|
|
|
+ .andExpect(jsonPath("$.access_token").isNotEmpty())
|
|
|
+ .andExpect(jsonPath("$.scope").value("scope1"));
|
|
|
+ }
|
|
|
+
|
|
|
private OidcClientRegistration registerClient(OidcClientRegistration clientRegistration) throws Exception {
|
|
|
// ***** (1) Obtain the "initial" access token used for registering the client
|
|
|
|