|
|
|
@ -68,6 +68,7 @@ import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResp |
|
|
|
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; |
|
|
|
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; |
|
|
|
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter; |
|
|
|
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter; |
|
|
|
import org.springframework.security.oauth2.jose.TestJwks; |
|
|
|
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.jose.jws.SignatureAlgorithm; |
|
|
|
import org.springframework.security.oauth2.jwt.JwsHeader; |
|
|
|
import org.springframework.security.oauth2.jwt.JwsHeader; |
|
|
|
import org.springframework.security.oauth2.jwt.Jwt; |
|
|
|
import org.springframework.security.oauth2.jwt.Jwt; |
|
|
|
@ -103,6 +104,8 @@ import org.springframework.test.web.servlet.MockMvc; |
|
|
|
import org.springframework.test.web.servlet.MvcResult; |
|
|
|
import org.springframework.test.web.servlet.MvcResult; |
|
|
|
import org.springframework.web.util.UriComponentsBuilder; |
|
|
|
import org.springframework.web.util.UriComponentsBuilder; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import javax.crypto.spec.SecretKeySpec; |
|
|
|
|
|
|
|
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat; |
|
|
|
import static org.assertj.core.api.Assertions.assertThat; |
|
|
|
import static org.hamcrest.CoreMatchers.containsString; |
|
|
|
import static org.hamcrest.CoreMatchers.containsString; |
|
|
|
import static org.mockito.ArgumentMatchers.any; |
|
|
|
import static org.mockito.ArgumentMatchers.any; |
|
|
|
@ -400,6 +403,55 @@ public class OidcClientRegistrationTests { |
|
|
|
.andReturn(); |
|
|
|
.andReturn(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// gh-1344
|
|
|
|
|
|
|
|
@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 { |
|
|
|
private OidcClientRegistration registerClient(OidcClientRegistration clientRegistration) throws Exception { |
|
|
|
// ***** (1) Obtain the "initial" access token used for registering the client
|
|
|
|
// ***** (1) Obtain the "initial" access token used for registering the client
|
|
|
|
|
|
|
|
|
|
|
|
|