Upgrade client secret when available

Closes gh-1099
This commit is contained in:
Shannon Pamperl
2023-02-27 10:23:39 -06:00
committed by Joe Grandja
parent d197c188ba
commit 0255a24849
6 changed files with 81 additions and 12 deletions

View File

@@ -85,6 +85,11 @@ public class ClientSecretAuthenticationProviderTests {
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return NoOpPasswordEncoder.getInstance().matches(rawPassword, encodedPassword);
}
@Override
public boolean upgradeEncoding(String encodedPassword) {
return true;
}
});
this.authenticationProvider.setPasswordEncoder(this.passwordEncoder);
}
@@ -222,6 +227,28 @@ public class ClientSecretAuthenticationProviderTests {
assertThat(authenticationResult.getRegisteredClient()).isEqualTo(registeredClient);
}
@Test
public void authenticateWhenValidCredentialsAndNonExpiredThenPasswordUpgraded() {
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
.thenReturn(registeredClient);
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
registeredClient.getClientId(), ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret(), null);
OAuth2ClientAuthenticationToken authenticationResult =
(OAuth2ClientAuthenticationToken) this.authenticationProvider.authenticate(authentication);
verify(this.passwordEncoder).matches(any(), any());
verify(this.passwordEncoder).upgradeEncoding(any());
verify(this.passwordEncoder).encode(any());
verify(this.registeredClientRepository).save(any());
assertThat(authenticationResult.isAuthenticated()).isTrue();
assertThat(registeredClient).isNotSameAs(authenticationResult.getPrincipal());
assertThat(authenticationResult.getPrincipal().toString()).isEqualTo(registeredClient.getClientId());
assertThat(authenticationResult.getCredentials().toString()).isEqualTo(registeredClient.getClientSecret());
assertThat(authenticationResult.getRegisteredClient()).isEqualTo(registeredClient);
}
@Test
public void authenticateWhenAuthorizationCodeGrantAndValidCredentialsThenAuthenticated() {
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();

View File

@@ -153,12 +153,12 @@ public class InMemoryRegisteredClientRepositoryTests {
}
@Test
public void saveWhenExistingIdThenThrowIllegalArgumentException() {
public void saveWhenExistingIdThenUpdate() {
RegisteredClient registeredClient = createRegisteredClient(
this.registration.getId(), "client-id-2", "client-secret-2");
assertThatIllegalArgumentException()
.isThrownBy(() -> this.clients.save(registeredClient))
.withMessage("Registered client must be unique. Found duplicate identifier: " + registeredClient.getId());
this.registration.getId(), "client-id", "client-secret-2");
this.clients.save(registeredClient);
RegisteredClient savedClient = this.clients.findByClientId(registeredClient.getClientId());
assertThat(savedClient.getClientSecret()).isEqualTo("client-secret-2");
}
@Test

View File

@@ -55,6 +55,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
@@ -231,6 +232,27 @@ public class OAuth2ClientCredentialsGrantTests {
verify(jwtCustomizer).customize(any());
}
@Test
public void requestWhenTokenRequestPostsClientCredentialsThenTokenResponseAndSecretUpgraded() throws Exception {
this.spring.register(AuthorizationServerConfigurationCustomPasswordEncoder.class).autowire();
String clientSecret = "secret-2";
RegisteredClient registeredClient = TestRegisteredClients.registeredClient2().clientSecret("{noop}" + clientSecret).build();
this.registeredClientRepository.save(registeredClient);
this.mvc.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
.param(OAuth2ParameterNames.SCOPE, "scope1 scope2")
.param(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId())
.param(OAuth2ParameterNames.CLIENT_SECRET, clientSecret))
.andExpect(status().isOk())
.andExpect(jsonPath("$.access_token").isNotEmpty())
.andExpect(jsonPath("$.scope").value("scope1 scope2"));
verify(jwtCustomizer).customize(any());
assertThat(this.registeredClientRepository.findByClientId(registeredClient.getClientId()).getClientSecret()).startsWith("{bcrypt}");
}
@Test
public void requestWhenTokenEndpointCustomizedThenUsed() throws Exception {
this.spring.register(AuthorizationServerConfigurationCustomTokenEndpoint.class).autowire();
@@ -429,6 +451,15 @@ public class OAuth2ClientCredentialsGrantTests {
// @formatter:on
}
@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
static class AuthorizationServerConfigurationCustomPasswordEncoder extends AuthorizationServerConfiguration {
@Override
PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
}
@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
static class AuthorizationServerConfigurationCustomClientAuthentication extends AuthorizationServerConfiguration {