Skip to content

Commit e61c03f

Browse files
committed
Fix to allow multiple PasswordEncoder beans
Closes gh-18645
1 parent 2c97b33 commit e61c03f

2 files changed

Lines changed: 40 additions & 18 deletions

File tree

config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2ConfigurerUtils.java

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,9 @@
1616

1717
package org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization;
1818

19-
import java.util.Map;
20-
2119
import com.nimbusds.jose.jwk.source.JWKSource;
2220
import com.nimbusds.jose.proc.SecurityContext;
2321

24-
import org.springframework.beans.factory.BeanFactoryUtils;
2522
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
2623
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
2724
import org.springframework.context.ApplicationContext;
@@ -45,7 +42,6 @@
4542
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;
4643
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
4744
import org.springframework.util.Assert;
48-
import org.springframework.util.StringUtils;
4945

5046
/**
5147
* Utility methods for the OAuth 2.0 Configurers.
@@ -224,24 +220,12 @@ static <T> T getBean(HttpSecurity httpSecurity, ResolvableType type) {
224220
}
225221

226222
static <T> T getOptionalBean(HttpSecurity httpSecurity, Class<T> type) {
227-
Map<String, T> beansMap = BeanFactoryUtils
228-
.beansOfTypeIncludingAncestors(httpSecurity.getSharedObject(ApplicationContext.class), type);
229-
if (beansMap.size() > 1) {
230-
throw new NoUniqueBeanDefinitionException(type, beansMap.size(),
231-
"Expected single matching bean of type '" + type.getName() + "' but found " + beansMap.size() + ": "
232-
+ StringUtils.collectionToCommaDelimitedString(beansMap.keySet()));
233-
}
234-
return (!beansMap.isEmpty() ? beansMap.values().iterator().next() : null);
223+
return httpSecurity.getSharedObject(ApplicationContext.class).getBeanProvider(type).getIfUnique();
235224
}
236225

237226
@SuppressWarnings("unchecked")
238227
static <T> T getOptionalBean(HttpSecurity httpSecurity, ResolvableType type) {
239-
ApplicationContext context = httpSecurity.getSharedObject(ApplicationContext.class);
240-
String[] names = context.getBeanNamesForType(type);
241-
if (names.length > 1) {
242-
throw new NoUniqueBeanDefinitionException(type, names);
243-
}
244-
return (names.length == 1) ? (T) context.getBean(names[0]) : null;
228+
return (T) httpSecurity.getSharedObject(ApplicationContext.class).getBeanProvider(type).getIfUnique();
245229
}
246230

247231
}

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.springframework.context.annotation.Bean;
4646
import org.springframework.context.annotation.Configuration;
4747
import org.springframework.context.annotation.Import;
48+
import org.springframework.context.annotation.Primary;
4849
import org.springframework.http.HttpHeaders;
4950
import org.springframework.jdbc.core.JdbcOperations;
5051
import org.springframework.jdbc.core.JdbcTemplate;
@@ -158,6 +159,8 @@ public class OAuth2ClientCredentialsGrantTests {
158159

159160
private static AuthenticationFailureHandler authenticationFailureHandler;
160161

162+
private static PasswordEncoder passwordEncoder;
163+
161164
public final SpringTestContext spring = new SpringTestContext(this);
162165

163166
@Autowired
@@ -183,6 +186,9 @@ public static void init() {
183186
authenticationProvidersConsumer = mock(Consumer.class);
184187
authenticationSuccessHandler = mock(AuthenticationSuccessHandler.class);
185188
authenticationFailureHandler = mock(AuthenticationFailureHandler.class);
189+
passwordEncoder = mock(PasswordEncoder.class);
190+
given(passwordEncoder.matches(any(), any())).willReturn(true);
191+
given(passwordEncoder.upgradeEncoding(any())).willReturn(false);
186192
db = new EmbeddedDatabaseBuilder().generateUniqueName(true)
187193
.setType(EmbeddedDatabaseType.HSQL)
188194
.setScriptEncoding("UTF-8")
@@ -496,6 +502,26 @@ public void requestWhenTokenRequestWithDPoPProofThenReturnDPoPBoundAccessToken()
496502
.andExpect(jsonPath("$.token_type").value(OAuth2AccessToken.TokenType.DPOP.getValue()));
497503
}
498504

505+
@Test
506+
public void requestWhenTokenRequestWithMultiplePasswordEncodersThenPrimaryPasswordEncoderUsed() throws Exception {
507+
this.spring.register(AuthorizationServerConfigurationWithMultiplePasswordEncoders.class).autowire();
508+
509+
RegisteredClient registeredClient = TestRegisteredClients.registeredClient2().build();
510+
this.registeredClientRepository.save(registeredClient);
511+
512+
this.mvc
513+
.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
514+
.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
515+
.param(OAuth2ParameterNames.SCOPE, "scope1 scope2")
516+
.header(HttpHeaders.AUTHORIZATION,
517+
"Basic " + encodeBasicAuth(registeredClient.getClientId(), registeredClient.getClientSecret())))
518+
.andExpect(status().isOk())
519+
.andExpect(jsonPath("$.access_token").isNotEmpty())
520+
.andExpect(jsonPath("$.scope").value("scope1 scope2"));
521+
522+
verify(passwordEncoder).matches(any(), any());
523+
}
524+
499525
private static String generateDPoPProof(String tokenEndpointUri) {
500526
// @formatter:off
501527
Map<String, Object> publicJwk = TestJwks.DEFAULT_EC_JWK
@@ -658,4 +684,16 @@ AuthorizationServerSettings authorizationServerSettings() {
658684

659685
}
660686

687+
@EnableWebSecurity
688+
@Configuration(proxyBeanMethods = false)
689+
static class AuthorizationServerConfigurationWithMultiplePasswordEncoders extends AuthorizationServerConfiguration {
690+
691+
@Primary
692+
@Bean
693+
PasswordEncoder primaryPasswordEncoder() {
694+
return passwordEncoder;
695+
}
696+
697+
}
698+
661699
}

0 commit comments

Comments
 (0)