From c45bf855d6d147ca3dc101806c5dbc41abbd2610 Mon Sep 17 00:00:00 2001 From: d036670 Date: Thu, 2 May 2024 12:38:02 +0200 Subject: [PATCH 1/2] Refactoring: use namedJdbcTemplate bean instead of internal new object Allow to mock the objects in future e.g. if jdbcTemplate is a mock then sometimes such pattern new NamedParameterJdbcTemplate(jdbcTemplate) causes a not testable code block like in JdbcScimUserProvisioning For jdbcTemplate we create one instance and re-use it, therefore if NamedParameterJdbcTemplate is used in several beans, then we should do the same --- .../JdbcQueryableClientDetailsService.java | 4 ++-- .../uaa/resources/jdbc/AbstractQueryable.java | 7 +++---- .../resources/jdbc/JdbcPagingListFactory.java | 5 ++--- .../scim/jdbc/JdbcScimGroupProvisioning.java | 7 ++++--- .../scim/jdbc/JdbcScimUserProvisioning.java | 9 ++++---- .../MultitenantJdbcClientDetailsService.java | 6 +++--- .../src/main/resources/spring/data-source.xml | 6 +++++- .../account/PasswordChangeEndpointTests.java | 7 ++++--- .../UaaClientAuthenticationProviderTest.java | 6 +++--- ...GroupMappingAuthorizationManagerTests.java | 8 ++++--- ...inBootstrapMultipleSecretsUpdateTests.java | 5 ++++- .../uaa/client/ClientAdminBootstrapTests.java | 6 +++++- .../JdbcClientMetadataProvisioningTest.java | 6 +++++- ...dbcQueryableClientDetailsServiceTests.java | 21 ++++++++++--------- .../oauth/TokenRevocationEndpointTests.java | 10 ++++++--- .../ApprovalsAdminEndpointsTests.java | 6 +++++- .../LoginSamlAuthenticationProviderTests.java | 8 +++++-- .../ScimExternalGroupBootstrapTests.java | 8 ++++--- .../bootstrap/ScimGroupBootstrapTests.java | 10 ++++++--- .../bootstrap/ScimUserBootstrapTests.java | 10 ++++++--- ...imGroupExternalMembershipManagerTests.java | 8 +++++-- .../JdbcScimGroupMembershipManagerTests.java | 10 ++++++--- .../jdbc/JdbcScimGroupProvisioningTests.java | 7 +++++-- .../jdbc/JdbcScimUserProvisioningTests.java | 10 ++++++--- ...titenantJdbcClientDetailsServiceTests.java | 9 +++++++- 25 files changed, 130 insertions(+), 69 deletions(-) diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/client/JdbcQueryableClientDetailsService.java b/server/src/main/java/org/cloudfoundry/identity/uaa/client/JdbcQueryableClientDetailsService.java index d624aaf5689..57f5390cb7f 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/client/JdbcQueryableClientDetailsService.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/client/JdbcQueryableClientDetailsService.java @@ -10,8 +10,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.oauth2.provider.ClientDetails; import org.springframework.stereotype.Component; @@ -41,7 +41,7 @@ public class JdbcQueryableClientDetailsService public JdbcQueryableClientDetailsService( final @Qualifier("jdbcClientDetailsService") MultitenantJdbcClientDetailsService delegate, - final JdbcTemplate jdbcTemplate, + final @Qualifier("namedJdbcTemplate") NamedParameterJdbcTemplate jdbcTemplate, final JdbcPagingListFactory pagingListFactory) { super(jdbcTemplate, pagingListFactory, new ClientDetailsRowMapper()); this.delegate = delegate; diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/resources/jdbc/AbstractQueryable.java b/server/src/main/java/org/cloudfoundry/identity/uaa/resources/jdbc/AbstractQueryable.java index 28292abf8b2..976bafbc1dd 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/resources/jdbc/AbstractQueryable.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/resources/jdbc/AbstractQueryable.java @@ -4,7 +4,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.util.StringUtils; @@ -17,7 +16,7 @@ public abstract class AbstractQueryable implements Queryable { - private NamedParameterJdbcTemplate namedParameterJdbcTemplate; + protected final NamedParameterJdbcTemplate namedParameterJdbcTemplate; protected final JdbcPagingListFactory pagingListFactory; @@ -29,10 +28,10 @@ public abstract class AbstractQueryable implements Queryable { private int pageSize = 200; - protected AbstractQueryable(final JdbcTemplate jdbcTemplate, + protected AbstractQueryable(final NamedParameterJdbcTemplate namedParameterJdbcTemplate, final JdbcPagingListFactory pagingListFactory, final RowMapper rowMapper) { - this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate); + this.namedParameterJdbcTemplate = namedParameterJdbcTemplate; this.pagingListFactory = pagingListFactory; this.rowMapper = rowMapper; diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/resources/jdbc/JdbcPagingListFactory.java b/server/src/main/java/org/cloudfoundry/identity/uaa/resources/jdbc/JdbcPagingListFactory.java index 350c6983450..3aac0b1cb29 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/resources/jdbc/JdbcPagingListFactory.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/resources/jdbc/JdbcPagingListFactory.java @@ -15,7 +15,6 @@ import java.util.List; import java.util.Map; -import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; @@ -30,8 +29,8 @@ public class JdbcPagingListFactory { private NamedParameterJdbcTemplate jdbcTemplate; private LimitSqlAdapter limitSqlAdapter; - public JdbcPagingListFactory(JdbcTemplate jdbcTemplate, LimitSqlAdapter limitSqlAdapter) { - this.jdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate); + public JdbcPagingListFactory(NamedParameterJdbcTemplate jdbcTemplate, LimitSqlAdapter limitSqlAdapter) { + this.jdbcTemplate = jdbcTemplate; this.limitSqlAdapter = limitSqlAdapter; } diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimGroupProvisioning.java b/server/src/main/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimGroupProvisioning.java index 433fca9ae5a..86a93513111 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimGroupProvisioning.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimGroupProvisioning.java @@ -23,6 +23,7 @@ import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import java.sql.SQLException; import java.sql.Timestamp; @@ -73,12 +74,12 @@ public Logger getLogger() { private JdbcIdentityZoneProvisioning jdbcIdentityZoneProvisioning; public JdbcScimGroupProvisioning( - final JdbcTemplate jdbcTemplate, + final NamedParameterJdbcTemplate namedJdbcTemplate, final JdbcPagingListFactory pagingListFactory, final DbUtils dbUtils) throws SQLException { - super(jdbcTemplate, pagingListFactory, new ScimGroupRowMapper()); + super(namedJdbcTemplate, pagingListFactory, new ScimGroupRowMapper()); - this.jdbcTemplate = jdbcTemplate; + this.jdbcTemplate = namedJdbcTemplate.getJdbcTemplate(); final String quotedGroupsTableName = dbUtils.getQuotedIdentifier(GROUP_TABLE, jdbcTemplate); updateGroupSql = String.format( diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimUserProvisioning.java b/server/src/main/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimUserProvisioning.java index 2771ad26125..bb56a96ee41 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimUserProvisioning.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimUserProvisioning.java @@ -142,15 +142,15 @@ public Logger getLogger() { private boolean useCaseInsensitiveQueries = false; public JdbcScimUserProvisioning( - final JdbcTemplate jdbcTemplate, + final NamedParameterJdbcTemplate namedJdbcTemplate, final JdbcPagingListFactory pagingListFactory, final PasswordEncoder passwordEncoder, final IdentityZoneManager identityZoneManager, final JdbcIdentityZoneProvisioning jdbcIdentityZoneProvisioning ) { - super(jdbcTemplate, pagingListFactory, mapper); - Assert.notNull(jdbcTemplate); - this.jdbcTemplate = jdbcTemplate; + super(namedJdbcTemplate, pagingListFactory, mapper); + Assert.notNull(namedJdbcTemplate, "JdbcTemplate required"); + this.jdbcTemplate = namedJdbcTemplate.getJdbcTemplate(); setQueryConverter(new SimpleSearchQueryConverter()); this.passwordEncoder = passwordEncoder; this.jdbcIdentityZoneProvisioning = jdbcIdentityZoneProvisioning; @@ -251,7 +251,6 @@ public String[] mapFromInternal(final String[] attr) { return pagingListFactory.createJdbcPagingList(sql, where.getParams(), rowMapper, getPageSize()); } - final NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate); return namedParameterJdbcTemplate.query(sql, where.getParams(), rowMapper); } diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/zone/MultitenantJdbcClientDetailsService.java b/server/src/main/java/org/cloudfoundry/identity/uaa/zone/MultitenantJdbcClientDetailsService.java index e8d2646ca56..21d8b7ef439 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/zone/MultitenantJdbcClientDetailsService.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/zone/MultitenantJdbcClientDetailsService.java @@ -116,13 +116,13 @@ public class MultitenantJdbcClientDetailsService extends MultitenantClientServic private JdbcListFactory listFactory; public MultitenantJdbcClientDetailsService( - final JdbcTemplate jdbcTemplate, + final NamedParameterJdbcTemplate jdbcTemplate, final IdentityZoneManager identityZoneManager, final @Qualifier("cachingPasswordEncoder") PasswordEncoder passwordEncoder) { super(identityZoneManager); Assert.notNull(jdbcTemplate, "JDbcTemplate required"); - this.jdbcTemplate = jdbcTemplate; - this.listFactory = new DefaultJdbcListFactory(new NamedParameterJdbcTemplate(jdbcTemplate)); + this.jdbcTemplate = jdbcTemplate.getJdbcTemplate(); + this.listFactory = new DefaultJdbcListFactory(jdbcTemplate); this.passwordEncoder = passwordEncoder; } diff --git a/server/src/main/resources/spring/data-source.xml b/server/src/main/resources/spring/data-source.xml index 501e5bcccc7..b54a99eba38 100755 --- a/server/src/main/resources/spring/data-source.xml +++ b/server/src/main/resources/spring/data-source.xml @@ -73,8 +73,12 @@ + + + + - + diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/account/PasswordChangeEndpointTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/account/PasswordChangeEndpointTests.java index 206a076dfed..d88e7dde1ed 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/account/PasswordChangeEndpointTests.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/account/PasswordChangeEndpointTests.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.common.util.RandomValueStringGenerator; @@ -44,11 +45,11 @@ class PasswordChangeEndpointTests { private PasswordEncoder passwordEncoder; @BeforeEach - void setup(@Autowired JdbcTemplate jdbcTemplate) { + void setup(@Autowired JdbcTemplate jdbcTemplate, @Autowired NamedParameterJdbcTemplate namedJdbcTemplate) { mockIdentityZoneManager = mock(IdentityZoneManager.class); jdbcScimUserProvisioning = new JdbcScimUserProvisioning( - jdbcTemplate, - new JdbcPagingListFactory(jdbcTemplate, LimitSqlAdapterFactory.getLimitSqlAdapter()), + namedJdbcTemplate, + new JdbcPagingListFactory(namedJdbcTemplate, LimitSqlAdapterFactory.getLimitSqlAdapter()), passwordEncoder, mockIdentityZoneManager, new JdbcIdentityZoneProvisioning(jdbcTemplate)); final RandomValueStringGenerator generator = new RandomValueStringGenerator(); diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/UaaClientAuthenticationProviderTest.java b/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/UaaClientAuthenticationProviderTest.java index bafdabec684..eccf325eec2 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/UaaClientAuthenticationProviderTest.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/UaaClientAuthenticationProviderTest.java @@ -16,7 +16,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -50,7 +50,7 @@ class UaaClientAuthenticationProviderTest { private JwtClientAuthentication jwtClientAuthentication; @Autowired - JdbcTemplate jdbcTemplate; + private NamedParameterJdbcTemplate namedJdbcTemplate; @Autowired private PasswordEncoder passwordEncoder; @@ -61,7 +61,7 @@ void setUpForClientTests() { jwtClientAuthentication = mock(JwtClientAuthentication.class); when(mockIdentityZoneManager.getCurrentIdentityZoneId()).thenReturn(IdentityZone.getUaaZoneId()); - jdbcClientDetailsService = new MultitenantJdbcClientDetailsService(jdbcTemplate, mockIdentityZoneManager, passwordEncoder); + jdbcClientDetailsService = new MultitenantJdbcClientDetailsService(namedJdbcTemplate, mockIdentityZoneManager, passwordEncoder); UaaClientDetailsUserDetailsService clientDetailsService = new UaaClientDetailsUserDetailsService(jdbcClientDetailsService); client = createClient(); authenticationProvider = new ClientDetailsAuthenticationProvider(clientDetailsService, passwordEncoder, jwtClientAuthentication); diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/authorization/external/LdapGroupMappingAuthorizationManagerTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/authorization/external/LdapGroupMappingAuthorizationManagerTests.java index 729db110a11..3f4dd9433b5 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/authorization/external/LdapGroupMappingAuthorizationManagerTests.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/authorization/external/LdapGroupMappingAuthorizationManagerTests.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; @@ -58,12 +59,13 @@ class LdapGroupMappingAuthorizationManagerTests { @BeforeEach void initLdapGroupMappingAuthorizationManagerTests( @Autowired JdbcTemplate jdbcTemplate, - @Autowired LimitSqlAdapter limitSqlAdapter + @Autowired LimitSqlAdapter limitSqlAdapter, + @Autowired NamedParameterJdbcTemplate namedJdbcTemplate ) throws SQLException { TestUtils.cleanAndSeedDb(jdbcTemplate); - JdbcPagingListFactory pagingListFactory = new JdbcPagingListFactory(jdbcTemplate, limitSqlAdapter); + JdbcPagingListFactory pagingListFactory = new JdbcPagingListFactory(namedJdbcTemplate, limitSqlAdapter); DbUtils dbUtils = new DbUtils(); - gDB = new JdbcScimGroupProvisioning(jdbcTemplate, pagingListFactory, dbUtils); + gDB = new JdbcScimGroupProvisioning(namedJdbcTemplate, pagingListFactory, dbUtils); eDB = new JdbcScimGroupExternalMembershipManager(jdbcTemplate, dbUtils); ((JdbcScimGroupExternalMembershipManager) eDB).setScimGroupProvisioning(gDB); assertEquals(0, gDB.retrieveAll(IdentityZoneHolder.get().getId()).size()); diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/client/ClientAdminBootstrapMultipleSecretsUpdateTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/client/ClientAdminBootstrapMultipleSecretsUpdateTests.java index 771a7266bee..8971b6518b0 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/client/ClientAdminBootstrapMultipleSecretsUpdateTests.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/client/ClientAdminBootstrapMultipleSecretsUpdateTests.java @@ -9,6 +9,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.common.util.RandomValueStringGenerator; @@ -28,6 +29,8 @@ public class ClientAdminBootstrapMultipleSecretsUpdateTests { @Autowired private JdbcTemplate jdbcTemplate; + @Autowired + private NamedParameterJdbcTemplate namedJdbcTemplate; private RandomValueStringGenerator randomValueStringGenerator; private String autoApproveId; private String allowPublicId; @@ -47,7 +50,7 @@ void passwordHashFirstSecretDidNotChangeButSecondIsNullDuringBootstrap() throws PasswordEncoder encoder = new BackwardsCompatibleDelegatingPasswordEncoder(new BCryptPasswordEncoder(10)); IdentityZoneManager mockIdentityZoneManager = mock(IdentityZoneManager.class); when(mockIdentityZoneManager.getCurrentIdentityZoneId()).thenReturn(IdentityZone.getUaaZoneId()); - MultitenantJdbcClientDetailsService localJdbcClientDetailsService = new MultitenantJdbcClientDetailsService(jdbcTemplate, mockIdentityZoneManager, encoder); + MultitenantJdbcClientDetailsService localJdbcClientDetailsService = new MultitenantJdbcClientDetailsService(namedJdbcTemplate, mockIdentityZoneManager, encoder); ClientMetadataProvisioning localMetadataProvisioning = new JdbcClientMetadataProvisioning(localJdbcClientDetailsService, jdbcTemplate); ClientAdminBootstrap localAdminBootstrap = new ClientAdminBootstrap( encoder, diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/client/ClientAdminBootstrapTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/client/ClientAdminBootstrapTests.java index ab8da2e5de3..f61613f424a 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/client/ClientAdminBootstrapTests.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/client/ClientAdminBootstrapTests.java @@ -17,6 +17,7 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.crypto.password.PasswordEncoder; @@ -77,6 +78,9 @@ class ClientAdminBootstrapTests { @Autowired private JdbcTemplate jdbcTemplate; + @Autowired + private NamedParameterJdbcTemplate namedJdbcTemplate; + private String autoApproveId; private String allowPublicId; @@ -89,7 +93,7 @@ void setUpClientAdminTests() { IdentityZoneManager mockIdentityZoneManager = mock(IdentityZoneManager.class); when(mockIdentityZoneManager.getCurrentIdentityZoneId()).thenReturn(IdentityZone.getUaaZoneId()); - multitenantJdbcClientDetailsService = spy(new MultitenantJdbcClientDetailsService(jdbcTemplate, mockIdentityZoneManager, passwordEncoder)); + multitenantJdbcClientDetailsService = spy(new MultitenantJdbcClientDetailsService(namedJdbcTemplate, mockIdentityZoneManager, passwordEncoder)); clientMetadataProvisioning = new JdbcClientMetadataProvisioning(multitenantJdbcClientDetailsService, jdbcTemplate); diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/client/JdbcClientMetadataProvisioningTest.java b/server/src/test/java/org/cloudfoundry/identity/uaa/client/JdbcClientMetadataProvisioningTest.java index 4ef3a779db0..cb04e81b36b 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/client/JdbcClientMetadataProvisioningTest.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/client/JdbcClientMetadataProvisioningTest.java @@ -8,6 +8,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.security.crypto.password.PasswordEncoder; import java.net.URL; @@ -41,6 +42,9 @@ class JdbcClientMetadataProvisioningTest { @Autowired private JdbcTemplate jdbcTemplate; + @Autowired + private NamedParameterJdbcTemplate namedJdbcTemplate; + @Autowired private PasswordEncoder passwordEncoder; @@ -51,7 +55,7 @@ void createDatasource() { identityZoneId = "identityZoneId-" + randomValueStringGenerator.generate(); clientId = "clientId-" + randomValueStringGenerator.generate(); - MultitenantJdbcClientDetailsService clientService = new MultitenantJdbcClientDetailsService(jdbcTemplate, null, passwordEncoder); + MultitenantJdbcClientDetailsService clientService = new MultitenantJdbcClientDetailsService(namedJdbcTemplate, null, passwordEncoder); jdbcClientMetadataProvisioning = new JdbcClientMetadataProvisioning(clientService, jdbcTemplate); } diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/oauth/JdbcQueryableClientDetailsServiceTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/oauth/JdbcQueryableClientDetailsServiceTests.java index 732e1281c15..10ec7852da4 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/oauth/JdbcQueryableClientDetailsServiceTests.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/oauth/JdbcQueryableClientDetailsServiceTests.java @@ -14,6 +14,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.security.crypto.password.PasswordEncoder; import java.sql.SQLException; @@ -34,7 +35,7 @@ class JdbcQueryableClientDetailsServiceTests { private MultitenantJdbcClientDetailsService multitenantJdbcClientDetailsService; @Autowired - private JdbcTemplate jdbcTemplate; + private NamedParameterJdbcTemplate namedParameterJdbcTemplate; @Autowired private LimitSqlAdapter limitSqlAdapter; @@ -45,14 +46,14 @@ class JdbcQueryableClientDetailsServiceTests { @BeforeEach void setUp() { multitenantJdbcClientDetailsService = new MultitenantJdbcClientDetailsService( - jdbcTemplate, + namedParameterJdbcTemplate, null, passwordEncoder); jdbcQueryableClientDetailsService = new JdbcQueryableClientDetailsService( multitenantJdbcClientDetailsService, - jdbcTemplate, + namedParameterJdbcTemplate, new JdbcPagingListFactory( - jdbcTemplate, + namedParameterJdbcTemplate, limitSqlAdapter)); } @@ -100,25 +101,25 @@ private static void addClient( @Test void queryEquals() { - verifyScimEquality(jdbcTemplate, jdbcQueryableClientDetailsService, "zoneOneId"); + verifyScimEquality(namedParameterJdbcTemplate.getJdbcTemplate(), jdbcQueryableClientDetailsService, "zoneOneId"); } @Test void queryExists() { - verifyScimPresent(jdbcTemplate, jdbcQueryableClientDetailsService, "zoneOneId"); + verifyScimPresent(namedParameterJdbcTemplate.getJdbcTemplate(), jdbcQueryableClientDetailsService, "zoneOneId"); } @Test void queryEqualsInAnotherZone() { - verifyScimEquality(jdbcTemplate, jdbcQueryableClientDetailsService, "zoneOneId"); - verifyScimEquality(jdbcTemplate, jdbcQueryableClientDetailsService, "otherZoneId"); + verifyScimEquality(namedParameterJdbcTemplate.getJdbcTemplate(), jdbcQueryableClientDetailsService, "zoneOneId"); + verifyScimEquality(namedParameterJdbcTemplate.getJdbcTemplate(), jdbcQueryableClientDetailsService, "otherZoneId"); assertEquals(8, multitenantJdbcClientDetailsService.getTotalCount()); } @Test void queryExistsInAnotherZone() { - verifyScimPresent(jdbcTemplate, jdbcQueryableClientDetailsService, "zoneOneId"); - verifyScimPresent(jdbcTemplate, jdbcQueryableClientDetailsService, "otherZoneId"); + verifyScimPresent(namedParameterJdbcTemplate.getJdbcTemplate(), jdbcQueryableClientDetailsService, "zoneOneId"); + verifyScimPresent(namedParameterJdbcTemplate.getJdbcTemplate(), jdbcQueryableClientDetailsService, "otherZoneId"); assertEquals(8, multitenantJdbcClientDetailsService.getTotalCount()); } diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/oauth/TokenRevocationEndpointTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/oauth/TokenRevocationEndpointTests.java index 1d561692655..39405d6a3df 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/oauth/TokenRevocationEndpointTests.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/oauth/TokenRevocationEndpointTests.java @@ -26,6 +26,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.provider.ClientDetails; @@ -50,6 +51,9 @@ public class TokenRevocationEndpointTests { @Autowired JdbcTemplate jdbcTemplate; + @Autowired + NamedParameterJdbcTemplate namedJdbcTemplate; + @Autowired LimitSqlAdapter limitSqlAdapter; @@ -67,12 +71,12 @@ void setupForTokenRevocation() { IdentityZoneManager mockIdentityZoneManager = mock(IdentityZoneManager.class); when(mockIdentityZoneManager.getCurrentIdentityZoneId()).thenReturn(IdentityZone.getUaaZoneId()); - clientService = spy(new MultitenantJdbcClientDetailsService(jdbcTemplate, mockIdentityZoneManager, passwordEncoder)); + clientService = spy(new MultitenantJdbcClientDetailsService(namedJdbcTemplate, mockIdentityZoneManager, passwordEncoder)); clientService.addClientDetails(client, zoneId); ScimUserProvisioning userProvisioning = new JdbcScimUserProvisioning( - jdbcTemplate, - new JdbcPagingListFactory(jdbcTemplate, limitSqlAdapter), + namedJdbcTemplate, + new JdbcPagingListFactory(namedJdbcTemplate, limitSqlAdapter), passwordEncoder, new IdentityZoneManagerImpl(), new JdbcIdentityZoneProvisioning(jdbcTemplate)); JdbcRevocableTokenProvisioning provisioning = spy(new JdbcRevocableTokenProvisioning(jdbcTemplate, limitSqlAdapter, new TimeServiceImpl())); endpoint = spy(new TokenRevocationEndpoint(clientService, userProvisioning, provisioning)); diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/oauth/approval/ApprovalsAdminEndpointsTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/oauth/approval/ApprovalsAdminEndpointsTests.java index 387e027737c..406fcc1269f 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/oauth/approval/ApprovalsAdminEndpointsTests.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/oauth/approval/ApprovalsAdminEndpointsTests.java @@ -29,6 +29,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.security.crypto.password.PasswordEncoder; import org.cloudfoundry.identity.uaa.provider.NoSuchClientException; @@ -56,6 +57,9 @@ class ApprovalsAdminEndpointsTests { @Autowired JdbcTemplate jdbcTemplate; + @Autowired + NamedParameterJdbcTemplate namedJdbcTemplate; + @Autowired PasswordEncoder passwordEncoder; @@ -85,7 +89,7 @@ void initApprovalsAdminEndpointsTests() throws SQLException { when(mockSecurityContextAccessor.getUserId()).thenReturn(marissa.getId()); when(mockSecurityContextAccessor.isUser()).thenReturn(true); - MultitenantJdbcClientDetailsService clientDetailsService = new MultitenantJdbcClientDetailsService(jdbcTemplate, mockIdentityZoneManager, passwordEncoder); + MultitenantJdbcClientDetailsService clientDetailsService = new MultitenantJdbcClientDetailsService(namedJdbcTemplate, mockIdentityZoneManager, passwordEncoder); UaaClientDetails details = new UaaClientDetails("c1", "scim,clients", "read,write", "authorization_code, password, implicit, client_credentials", "update"); details.setAutoApproveScopes(Collections.singletonList("true")); diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/provider/saml/LoginSamlAuthenticationProviderTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/provider/saml/LoginSamlAuthenticationProviderTests.java index 981efad8473..ef7bdafb2d0 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/provider/saml/LoginSamlAuthenticationProviderTests.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/provider/saml/LoginSamlAuthenticationProviderTests.java @@ -69,6 +69,7 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.security.authentication.BadCredentialsException; @@ -162,6 +163,9 @@ class LoginSamlAuthenticationProviderTests { @Autowired private JdbcTemplate jdbcTemplate; + @Autowired + NamedParameterJdbcTemplate namedJdbcTemplate; + @Autowired private LimitSqlAdapter limitSqlAdapter; @@ -179,14 +183,14 @@ void configureProvider() throws SAMLException, SecurityException, DecryptionExce DbUtils dbUtils = new DbUtils(); ScimGroupProvisioning groupProvisioning = new JdbcScimGroupProvisioning( - jdbcTemplate, new JdbcPagingListFactory(jdbcTemplate, limitSqlAdapter), dbUtils); + namedJdbcTemplate, new JdbcPagingListFactory(namedJdbcTemplate, limitSqlAdapter), dbUtils); identityZoneManager.getCurrentIdentityZone().getConfig().getUserConfig().setDefaultGroups(Collections.singletonList(UAA_USER)); identityZoneManager.getCurrentIdentityZone().getConfig().getUserConfig().setAllowedGroups(Arrays.asList(UAA_USER, SAML_USER, SAML_ADMIN,SAML_TEST,SAML_NOT_MAPPED, UAA_SAML_USER,UAA_SAML_ADMIN,UAA_SAML_TEST)); groupProvisioning.createOrGet(new ScimGroup(null, UAA_USER, identityZoneManager.getCurrentIdentityZone().getId()), identityZoneManager.getCurrentIdentityZone().getId()); providerDefinition = new SamlIdentityProviderDefinition(); - userProvisioning = new JdbcScimUserProvisioning(jdbcTemplate, new JdbcPagingListFactory(jdbcTemplate, limitSqlAdapter), passwordEncoder, new IdentityZoneManagerImpl(), new JdbcIdentityZoneProvisioning(jdbcTemplate)); + userProvisioning = new JdbcScimUserProvisioning(namedJdbcTemplate, new JdbcPagingListFactory(namedJdbcTemplate, limitSqlAdapter), passwordEncoder, new IdentityZoneManagerImpl(), new JdbcIdentityZoneProvisioning(jdbcTemplate)); uaaSamlUser = groupProvisioning.create(new ScimGroup(null, UAA_SAML_USER, IdentityZone.getUaaZoneId()), identityZoneManager.getCurrentIdentityZone().getId()); diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/scim/bootstrap/ScimExternalGroupBootstrapTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/scim/bootstrap/ScimExternalGroupBootstrapTests.java index eb5c0e764ae..074cce258fb 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/scim/bootstrap/ScimExternalGroupBootstrapTests.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/scim/bootstrap/ScimExternalGroupBootstrapTests.java @@ -16,6 +16,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import java.sql.SQLException; import java.util.Arrays; @@ -37,15 +38,16 @@ class ScimExternalGroupBootstrapTests { @BeforeEach void setUp( @Autowired JdbcTemplate jdbcTemplate, - @Autowired LimitSqlAdapter limitSqlAdapter + @Autowired LimitSqlAdapter limitSqlAdapter, + @Autowired NamedParameterJdbcTemplate namedJdbcTemplate ) throws SQLException { IdentityZone zone = new IdentityZone(); zone.setId(RandomStringUtils.randomAlphabetic(10)); IdentityZoneHolder.set(zone); - JdbcPagingListFactory pagingListFactory = new JdbcPagingListFactory(jdbcTemplate, limitSqlAdapter); + JdbcPagingListFactory pagingListFactory = new JdbcPagingListFactory(namedJdbcTemplate, limitSqlAdapter); DbUtils dbUtils = new DbUtils(); - JdbcScimGroupProvisioning gDB = new JdbcScimGroupProvisioning(jdbcTemplate, pagingListFactory, dbUtils); + JdbcScimGroupProvisioning gDB = new JdbcScimGroupProvisioning(namedJdbcTemplate, pagingListFactory, dbUtils); eDB = new JdbcScimGroupExternalMembershipManager(jdbcTemplate, dbUtils); ((JdbcScimGroupExternalMembershipManager) eDB).setScimGroupProvisioning(gDB); assertEquals(0, gDB.retrieveAll(IdentityZoneHolder.get().getId()).size()); diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/scim/bootstrap/ScimGroupBootstrapTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/scim/bootstrap/ScimGroupBootstrapTests.java index 374abc66d7f..1376ce4bd07 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/scim/bootstrap/ScimGroupBootstrapTests.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/scim/bootstrap/ScimGroupBootstrapTests.java @@ -22,6 +22,7 @@ import org.springframework.core.env.MapPropertySource; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.util.StringUtils; @@ -54,6 +55,9 @@ class ScimGroupBootstrapTests { @Autowired private JdbcTemplate jdbcTemplate; + @Autowired + NamedParameterJdbcTemplate namedJdbcTemplate; + @Autowired private LimitSqlAdapter limitSqlAdapter; @@ -63,10 +67,10 @@ class ScimGroupBootstrapTests { @BeforeEach void initScimGroupBootstrapTests() throws SQLException { JdbcTemplate template = jdbcTemplate; - JdbcPagingListFactory pagingListFactory = new JdbcPagingListFactory(template, limitSqlAdapter); + JdbcPagingListFactory pagingListFactory = new JdbcPagingListFactory(namedJdbcTemplate, limitSqlAdapter); DbUtils dbUtils = new DbUtils(); - gDB = new JdbcScimGroupProvisioning(template, pagingListFactory, dbUtils); - uDB = new JdbcScimUserProvisioning(template, pagingListFactory, passwordEncoder, new IdentityZoneManagerImpl(), new JdbcIdentityZoneProvisioning(jdbcTemplate)); + gDB = new JdbcScimGroupProvisioning(namedJdbcTemplate, pagingListFactory, dbUtils); + uDB = new JdbcScimUserProvisioning(namedJdbcTemplate, pagingListFactory, passwordEncoder, new IdentityZoneManagerImpl(), new JdbcIdentityZoneProvisioning(jdbcTemplate)); mDB = new JdbcScimGroupMembershipManager(template, new TimeServiceImpl(), uDB, null, dbUtils); mDB.setScimGroupProvisioning(gDB); diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/scim/bootstrap/ScimUserBootstrapTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/scim/bootstrap/ScimUserBootstrapTests.java index 6c9c171186b..9a34635321d 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/scim/bootstrap/ScimUserBootstrapTests.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/scim/bootstrap/ScimUserBootstrapTests.java @@ -36,6 +36,7 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; @@ -85,15 +86,18 @@ class ScimUserBootstrapTests { @Autowired private JdbcTemplate jdbcTemplate; + @Autowired + NamedParameterJdbcTemplate namedJdbcTemplate; + @Autowired private PasswordEncoder passwordEncoder; @BeforeEach void init() throws SQLException { - JdbcPagingListFactory pagingListFactory = new JdbcPagingListFactory(jdbcTemplate, LimitSqlAdapterFactory.getLimitSqlAdapter()); - jdbcScimUserProvisioning = spy(new JdbcScimUserProvisioning(jdbcTemplate, pagingListFactory, passwordEncoder, new IdentityZoneManagerImpl(), new JdbcIdentityZoneProvisioning(jdbcTemplate))); + JdbcPagingListFactory pagingListFactory = new JdbcPagingListFactory(namedJdbcTemplate, LimitSqlAdapterFactory.getLimitSqlAdapter()); + jdbcScimUserProvisioning = spy(new JdbcScimUserProvisioning(namedJdbcTemplate, pagingListFactory, passwordEncoder, new IdentityZoneManagerImpl(), new JdbcIdentityZoneProvisioning(jdbcTemplate))); DbUtils dbUtils = new DbUtils(); - jdbcScimGroupProvisioning = new JdbcScimGroupProvisioning(jdbcTemplate, pagingListFactory, dbUtils); + jdbcScimGroupProvisioning = new JdbcScimGroupProvisioning(namedJdbcTemplate, pagingListFactory, dbUtils); jdbcScimGroupMembershipManager = new JdbcScimGroupMembershipManager( jdbcTemplate, new TimeServiceImpl(), jdbcScimUserProvisioning, null, dbUtils); jdbcScimGroupMembershipManager.setScimGroupProvisioning(jdbcScimGroupProvisioning); diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimGroupExternalMembershipManagerTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimGroupExternalMembershipManagerTests.java index 849a5fe3cf4..994fd495c54 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimGroupExternalMembershipManagerTests.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimGroupExternalMembershipManagerTests.java @@ -17,6 +17,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.security.oauth2.common.util.RandomValueStringGenerator; import java.sql.SQLException; @@ -47,6 +48,9 @@ class JdbcScimGroupExternalMembershipManagerTests { @Autowired private JdbcTemplate jdbcTemplate; + @Autowired + private NamedParameterJdbcTemplate namedJdbcTemplate; + @Autowired private DataSource dataSource; @@ -65,8 +69,8 @@ void setUp() throws SQLException { JdbcTemplate template = new JdbcTemplate(dataSource); dbUtils = new DbUtils(); - JdbcPagingListFactory pagingListFactory = new JdbcPagingListFactory(template, limitSqlAdapter); - gdao = new JdbcScimGroupProvisioning(template, pagingListFactory, dbUtils); + JdbcPagingListFactory pagingListFactory = new JdbcPagingListFactory(namedJdbcTemplate, limitSqlAdapter); + gdao = new JdbcScimGroupProvisioning(namedJdbcTemplate, pagingListFactory, dbUtils); JdbcScimGroupMembershipManager jdbcScimGroupMembershipManager = new JdbcScimGroupMembershipManager( jdbcTemplate, new TimeServiceImpl(), null, null, dbUtils); diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimGroupMembershipManagerTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimGroupMembershipManagerTests.java index 7ce4d04d581..bab6d77d67d 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimGroupMembershipManagerTests.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimGroupMembershipManagerTests.java @@ -29,6 +29,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.security.core.Authentication; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.common.util.RandomValueStringGenerator; @@ -86,6 +87,9 @@ class JdbcScimGroupMembershipManagerTests { @Autowired private JdbcTemplate jdbcTemplate; + @Autowired + private NamedParameterJdbcTemplate namedJdbcTemplate; + @Autowired private LimitSqlAdapter limitSqlAdapter; @@ -100,9 +104,9 @@ void setUp() throws SQLException { dbUtils = new DbUtils(); - JdbcPagingListFactory pagingListFactory = new JdbcPagingListFactory(jdbcTemplate, limitSqlAdapter); - JdbcScimUserProvisioning jdbcScimUserProvisioning = new JdbcScimUserProvisioning(jdbcTemplate, pagingListFactory, passwordEncoder, new IdentityZoneManagerImpl(), new JdbcIdentityZoneProvisioning(jdbcTemplate)); - jdbcScimGroupProvisioning = new JdbcScimGroupProvisioning(jdbcTemplate, pagingListFactory, dbUtils); + JdbcPagingListFactory pagingListFactory = new JdbcPagingListFactory(namedJdbcTemplate, limitSqlAdapter); + JdbcScimUserProvisioning jdbcScimUserProvisioning = new JdbcScimUserProvisioning(namedJdbcTemplate, pagingListFactory, passwordEncoder, new IdentityZoneManagerImpl(), new JdbcIdentityZoneProvisioning(jdbcTemplate)); + jdbcScimGroupProvisioning = new JdbcScimGroupProvisioning(namedJdbcTemplate, pagingListFactory, dbUtils); jdbcScimGroupMembershipManager = new JdbcScimGroupMembershipManager( jdbcTemplate, new TimeServiceImpl(), jdbcScimUserProvisioning, null, dbUtils); diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimGroupProvisioningTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimGroupProvisioningTests.java index 36f526ddee7..a133411c5fa 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimGroupProvisioningTests.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimGroupProvisioningTests.java @@ -27,6 +27,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.security.oauth2.common.util.RandomValueStringGenerator; import java.security.SecureRandom; @@ -58,6 +59,8 @@ class JdbcScimGroupProvisioningTests { @Autowired private JdbcTemplate jdbcTemplate; @Autowired + private NamedParameterJdbcTemplate namedJdbcTemplate; + @Autowired private LimitSqlAdapter limitSqlAdapter; private JdbcScimGroupProvisioning dao; @@ -94,8 +97,8 @@ void initJdbcScimGroupProvisioningTests() throws SQLException { validateGroupCountInZone(0, zoneId); DbUtils dbUtils = new DbUtils(); - dao = spy(new JdbcScimGroupProvisioning(jdbcTemplate, - new JdbcPagingListFactory(jdbcTemplate, limitSqlAdapter), + dao = spy(new JdbcScimGroupProvisioning(namedJdbcTemplate, + new JdbcPagingListFactory(namedJdbcTemplate, limitSqlAdapter), dbUtils)); users = mock(ScimUserProvisioning.class); diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimUserProvisioningTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimUserProvisioningTests.java index 5196d8585ae..f4e65986255 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimUserProvisioningTests.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimUserProvisioningTests.java @@ -67,6 +67,7 @@ import org.springframework.dao.OptimisticLockingFailureException; import org.springframework.http.HttpStatus; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.Authentication; import org.springframework.security.crypto.password.PasswordEncoder; @@ -94,6 +95,9 @@ class JdbcScimUserProvisioningTests { @Autowired private JdbcTemplate jdbcTemplate; + + @Autowired + NamedParameterJdbcTemplate namedJdbcTemplate; private String joeEmail; private final String JOE_NAME = "joe"; @@ -103,7 +107,7 @@ void setUp(@Autowired LimitSqlAdapter limitSqlAdapter) { joeId = "joeId-" + UUID.randomUUID().toString().substring("joeId-".length()); joeEmail = "joe@joe.com"; String mabelId = "mabelId-" + UUID.randomUUID().toString().substring("mabelId-".length()); - pagingListFactory = new JdbcPagingListFactory(jdbcTemplate, limitSqlAdapter); + pagingListFactory = new JdbcPagingListFactory(namedJdbcTemplate, limitSqlAdapter); currentIdentityZoneId = "currentIdentityZoneId-" + randomString(); IdentityZone idz = new IdentityZone(); @@ -111,7 +115,7 @@ void setUp(@Autowired LimitSqlAdapter limitSqlAdapter) { idzManager = new IdentityZoneManagerImpl(); idzManager.setCurrentIdentityZone(idz); - jdbcScimUserProvisioning = new JdbcScimUserProvisioning(jdbcTemplate, pagingListFactory, passwordEncoder, idzManager, jdbcIdentityZoneProvisioning); + jdbcScimUserProvisioning = new JdbcScimUserProvisioning(namedJdbcTemplate, pagingListFactory, passwordEncoder, idzManager, jdbcIdentityZoneProvisioning); SimpleSearchQueryConverter filterConverter = new SimpleSearchQueryConverter(); Map replaceWith = new HashMap<>(); @@ -671,7 +675,7 @@ void cannotCreateScimUserWithEmptyEmail() { void canReadScimUserWithMissingEmail() { // Create a user with no email address, reflecting previous behavior - JdbcScimUserProvisioning noValidateProvisioning = new JdbcScimUserProvisioning(jdbcTemplate, pagingListFactory, passwordEncoder, new IdentityZoneManagerImpl(), new JdbcIdentityZoneProvisioning(jdbcTemplate)) { + JdbcScimUserProvisioning noValidateProvisioning = new JdbcScimUserProvisioning(namedJdbcTemplate, pagingListFactory, passwordEncoder, new IdentityZoneManagerImpl(), new JdbcIdentityZoneProvisioning(jdbcTemplate)) { @Override public ScimUser retrieve(String id, String zoneId) { ScimUser createdUserId = new ScimUser(); diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/zone/MultitenantJdbcClientDetailsServiceTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/zone/MultitenantJdbcClientDetailsServiceTests.java index 05342c264b2..57c22d0facd 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/zone/MultitenantJdbcClientDetailsServiceTests.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/zone/MultitenantJdbcClientDetailsServiceTests.java @@ -17,6 +17,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; @@ -76,6 +77,7 @@ class MultitenantJdbcClientDetailsServiceTests { private String dbRequestedUserGroups = "uaa.user,uaa.something"; private UaaClientDetails baseClientDetails; private JdbcTemplate spyJdbcTemplate; + private NamedParameterJdbcTemplate spyNamedJdbcTemplate; private IdentityZoneManager mockIdentityZoneManager; private String currentZoneId; @@ -85,16 +87,21 @@ class MultitenantJdbcClientDetailsServiceTests { @Autowired private JdbcTemplate jdbcTemplate; + @Autowired + private NamedParameterJdbcTemplate namedJdbcTemplate; + @BeforeEach void setup() { randomValueStringGenerator = new AlphanumericRandomValueStringGenerator(); jdbcTemplate.update("DELETE FROM oauth_client_details"); SecurityContextHolder.getContext().setAuthentication(mock(Authentication.class)); + spyNamedJdbcTemplate = spy(namedJdbcTemplate); spyJdbcTemplate = spy(jdbcTemplate); mockIdentityZoneManager = mock(IdentityZoneManager.class); currentZoneId = "currentZoneId-" + randomValueStringGenerator.generate(); when(mockIdentityZoneManager.getCurrentIdentityZoneId()).thenReturn(currentZoneId); - service = spy(new MultitenantJdbcClientDetailsService(spyJdbcTemplate, mockIdentityZoneManager, passwordEncoder)); + when(spyNamedJdbcTemplate.getJdbcTemplate()).thenReturn(spyJdbcTemplate); + service = spy(new MultitenantJdbcClientDetailsService(spyNamedJdbcTemplate, mockIdentityZoneManager, passwordEncoder)); baseClientDetails = new UaaClientDetails(); String clientId = "client-with-id-" + new AlphanumericRandomValueStringGenerator(36).generate(); From 6121e65d31ddde03762c3fdb278f343d73f41f2c Mon Sep 17 00:00:00 2001 From: d036670 Date: Tue, 7 May 2024 09:45:07 +0200 Subject: [PATCH 2/2] rebase --- .../uaa/resources/jdbc/AbstractQueryable.java | 3 +- .../scim/jdbc/JdbcScimUserProvisioning.java | 56 ++-------- .../jdbc/JdbcScimUserProvisioningTests.java | 103 ++++++++++++++++++ 3 files changed, 117 insertions(+), 45 deletions(-) diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/resources/jdbc/AbstractQueryable.java b/server/src/main/java/org/cloudfoundry/identity/uaa/resources/jdbc/AbstractQueryable.java index 976bafbc1dd..5e5b473d3ed 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/resources/jdbc/AbstractQueryable.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/resources/jdbc/AbstractQueryable.java @@ -13,6 +13,7 @@ import java.util.stream.Collectors; import static com.google.common.primitives.Ints.tryParse; +import static org.cloudfoundry.identity.uaa.resources.jdbc.SearchQueryConverter.ProcessedFilter.ORDER_BY; public abstract class AbstractQueryable implements Queryable { @@ -86,7 +87,7 @@ public List query(String filter, String sortBy, boolean ascending, String zon private String getQuerySQL(SearchQueryConverter.ProcessedFilter where) { if (where.hasOrderBy()) { - return getBaseSqlQuery() + " where (" + where.getSql().replace(where.ORDER_BY, ")" + where.ORDER_BY); + return getBaseSqlQuery() + " where (" + where.getSql().replace(ORDER_BY, ")" + ORDER_BY); } else { return getBaseSqlQuery() + " where (" + where.getSql() + ")"; } diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimUserProvisioning.java b/server/src/main/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimUserProvisioning.java index fe852a33740..793027b7bce 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimUserProvisioning.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimUserProvisioning.java @@ -29,14 +29,13 @@ import java.util.Map; import java.util.UUID; import java.util.regex.Pattern; -import java.util.stream.Stream; import org.cloudfoundry.identity.uaa.audit.event.SystemDeletable; import org.cloudfoundry.identity.uaa.constants.OriginKeys; -import org.cloudfoundry.identity.uaa.resources.AttributeNameMapper; import org.cloudfoundry.identity.uaa.resources.ResourceMonitor; import org.cloudfoundry.identity.uaa.resources.jdbc.AbstractQueryable; import org.cloudfoundry.identity.uaa.resources.jdbc.JdbcPagingListFactory; +import org.cloudfoundry.identity.uaa.resources.jdbc.SearchQueryConverter; import org.cloudfoundry.identity.uaa.resources.jdbc.SearchQueryConverter.ProcessedFilter; import org.cloudfoundry.identity.uaa.resources.jdbc.SimpleSearchQueryConverter; import org.cloudfoundry.identity.uaa.scim.ScimMeta; @@ -139,7 +138,7 @@ public Logger getLogger() { private final JdbcIdentityZoneProvisioning jdbcIdentityZoneProvisioning; private final IdentityZoneManager identityZoneManager; - private boolean useCaseInsensitiveQueries = false; + private SearchQueryConverter joinConverter; public JdbcScimUserProvisioning( final NamedParameterJdbcTemplate namedJdbcTemplate, @@ -161,8 +160,8 @@ public void setTimeService(TimeService timeService) { this.timeService = timeService; } - public void setUseCaseInsensitiveQueries(final boolean useCaseInsensitiveQueries) { - this.useCaseInsensitiveQueries = useCaseInsensitiveQueries; + public void setJoinConverter(SearchQueryConverter joinConverter) { + this.joinConverter = joinConverter; } @Override @@ -191,45 +190,13 @@ public List retrieveByScimFilterOnlyActive( final boolean ascending, final String zoneId ) { - /* We cannot reuse the query converter from the superclass here since the later query operates on both the - * "users" and the "identity_provider" table and they both have a column named "id". Since the SCIM filter might - * contain clauses on the "id" field, we must ensure that the "id" of the "users" table is used, which is done - * by attaching an AttributeNameMapper. */ - final SimpleSearchQueryConverter queryConverter = new SimpleSearchQueryConverter(); - - // ensure that the generated query handles the case-insensitivity of the underlying DB correctly - queryConverter.setDbCaseInsensitive(useCaseInsensitiveQueries); - - validateOrderBy(queryConverter.map(sortBy)); - + validateOrderBy(sortBy); /* since the two tables used in the query ('users' and 'identity_provider') have columns with identical names, * we must ensure that the columns of 'users' are used in the WHERE clause generated for the SCIM filter */ - final AttributeNameMapper attributeNameMapper = new AttributeNameMapper() { - @Override - public String mapToInternal(final String attr) { - // in the later query, 'users' will have the alias 'u' - return "u." + attr; - } - - @Override - public String[] mapToInternal(final String[] attr) { - return Stream.of(attr).map(this::mapToInternal).toArray(String[]::new); - } - - @Override - public String mapFromInternal(final String attr) { - return attr.substring(2); - } - - @Override - public String[] mapFromInternal(final String[] attr) { - return Stream.of(attr).map(this::mapFromInternal).toArray(String[]::new); - } - }; - queryConverter.setAttributeNameMapper(attributeNameMapper); + String joinName = joinConverter.getJoinName(); // build WHERE clause - final ProcessedFilter where = queryConverter.convert(filter, sortBy, ascending, zoneId); + final ProcessedFilter where = joinConverter.convert(filter, sortBy, ascending, zoneId); final String whereClauseScimFilter = where.getSql(); String whereClause = "idp.active is true and ("; if (where.hasOrderBy()) { @@ -239,11 +206,14 @@ public String[] mapFromInternal(final String[] attr) { } final String userFieldsWithPrefix = Arrays.stream(USER_FIELDS.split(",")) - .map(field -> "u." + field) + .map(field -> joinName + "." + field) .collect(joining(", ")); + String joinStatement = String.format( + "%s join identity_provider idp on %s.origin = idp.origin_key and %s.identity_zone_id = idp.identity_zone_id", joinName, joinName, joinName); final String sql = String.format( - "select %s from users u join identity_provider idp on u.origin = idp.origin_key and u.identity_zone_id = idp.identity_zone_id where %s", + "select %s from users %s where %s", userFieldsWithPrefix, + joinStatement, whereClause ); @@ -251,7 +221,6 @@ public String[] mapFromInternal(final String[] attr) { return pagingListFactory.createJdbcPagingList(sql, where.getParams(), rowMapper, getPageSize()); } - final NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate); return namedParameterJdbcTemplate.query(sql, where.getParams(), rowMapper); } @@ -571,7 +540,6 @@ public int deleteByUser(String userId, String zoneId) { return 1; } - private static final class ScimUserRowMapper implements RowMapper { @Override public ScimUser mapRow(ResultSet rs, int rowNum) throws SQLException { diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimUserProvisioningTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimUserProvisioningTests.java index f4e65986255..a816b8b332b 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimUserProvisioningTests.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/JdbcScimUserProvisioningTests.java @@ -17,8 +17,14 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.contains; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.sql.Timestamp; @@ -37,6 +43,7 @@ import org.cloudfoundry.identity.uaa.audit.event.EntityDeletedEvent; import org.cloudfoundry.identity.uaa.constants.OriginKeys; import org.cloudfoundry.identity.uaa.provider.IdentityProvider; +import org.cloudfoundry.identity.uaa.resources.JoinAttributeNameMapper; import org.cloudfoundry.identity.uaa.resources.SimpleAttributeNameMapper; import org.cloudfoundry.identity.uaa.resources.jdbc.JdbcPagingListFactory; import org.cloudfoundry.identity.uaa.resources.jdbc.LimitSqlAdapter; @@ -67,6 +74,7 @@ import org.springframework.dao.OptimisticLockingFailureException; import org.springframework.http.HttpStatus; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.Authentication; @@ -124,6 +132,9 @@ void setUp(@Autowired LimitSqlAdapter limitSqlAdapter) { replaceWith.put("phoneNumbers\\.value", "phoneNumber"); filterConverter.setAttributeNameMapper(new SimpleAttributeNameMapper(replaceWith)); jdbcScimUserProvisioning.setQueryConverter(filterConverter); + SimpleSearchQueryConverter joinConverter = new SimpleSearchQueryConverter(); + joinConverter.setAttributeNameMapper(new JoinAttributeNameMapper("u")); + jdbcScimUserProvisioning.setJoinConverter(joinConverter); addUser(jdbcTemplate, joeId, JOE_NAME, passwordEncoder.encode("joespassword"), joeEmail, "Joe", "User", "+1-222-1234567", currentIdentityZoneId); @@ -301,6 +312,98 @@ void retrieveByScimFilterOnlyActive() { Assertions.assertThat(usernames).isEmpty(); } + @Test + void retrieveByScimFilterNoPaging() { + JdbcPagingListFactory notInUse = mock(JdbcPagingListFactory.class); + jdbcScimUserProvisioning = new JdbcScimUserProvisioning(namedJdbcTemplate, notInUse, passwordEncoder, new IdentityZoneManagerImpl(), + new JdbcIdentityZoneProvisioning(jdbcTemplate)); + SimpleSearchQueryConverter joinConverter = new SimpleSearchQueryConverter(); + joinConverter.setAttributeNameMapper(new JoinAttributeNameMapper("u")); + jdbcScimUserProvisioning.setJoinConverter(joinConverter); + String originActive = randomString(); + addIdentityProvider(jdbcTemplate, currentIdentityZoneId, originActive, true); + + String originInactive = randomString(); + addIdentityProvider(jdbcTemplate, currentIdentityZoneId, originInactive, false); + + ScimUser user1 = new ScimUser(null, "jo@foo.com", "Jo", "User"); + user1.addEmail("jo@blah.com"); + user1.setOrigin(originActive); + ScimUser created1 = jdbcScimUserProvisioning.createUser(user1, "j8hyqpassX", currentIdentityZoneId); + + ScimUser user2 = new ScimUser(null, "jo2@foo.com", "Jo", "User"); + user2.addEmail("jo2@blah.com"); + user2.setOrigin(originInactive); + ScimUser created2 = jdbcScimUserProvisioning.createUser(user2, "j8hyqpassX", currentIdentityZoneId); + + String scimFilter = String.format("id eq '%s' or username eq '%s' or origin eq '%s'", created1.getId(), created2.getUserName(), created2.getOrigin()); + jdbcScimUserProvisioning.setPageSize(0); + List result = jdbcScimUserProvisioning.retrieveByScimFilterOnlyActive( + scimFilter, + null, + false, + currentIdentityZoneId + ); + Assertions.assertThat(result).isNotNull(); + List usernames = result.stream().map(ScimUser::getUserName).collect(toList()); + Assertions.assertThat(usernames).isSorted(); + verify(notInUse, never()).createJdbcPagingList(anyString(), any(Map.class), any(RowMapper.class), any(Integer.class)); + // another option to query without paging + jdbcScimUserProvisioning.setPageSize(Integer.MAX_VALUE); + jdbcScimUserProvisioning.setPageSize(0); + jdbcScimUserProvisioning.retrieveByScimFilterOnlyActive( + scimFilter, + null, + false, + currentIdentityZoneId + ); + verify(notInUse, never()).createJdbcPagingList(anyString(), any(Map.class), any(RowMapper.class), any(Integer.class)); + // positive check, now with paging + jdbcScimUserProvisioning.setPageSize(1); + jdbcScimUserProvisioning.retrieveByScimFilterOnlyActive( + scimFilter, + null, + false, + currentIdentityZoneId + ); + verify(notInUse, times(1)).createJdbcPagingList(anyString(), any(Map.class), any(RowMapper.class), any(Integer.class)); + } + + @Test + void retrieveByScimFilterUsingLower() { + JdbcPagingListFactory notInUse = mock(JdbcPagingListFactory.class); + NamedParameterJdbcTemplate mockedJdbcTemplate = mock(NamedParameterJdbcTemplate.class); + SimpleSearchQueryConverter joinConverter = new SimpleSearchQueryConverter(); + joinConverter.setAttributeNameMapper(new JoinAttributeNameMapper("u")); + jdbcScimUserProvisioning = new JdbcScimUserProvisioning(mockedJdbcTemplate, pagingListFactory, passwordEncoder, idzManager, jdbcIdentityZoneProvisioning); + jdbcScimUserProvisioning.setJoinConverter(joinConverter); + + String scimFilter = "id eq '1111' or username eq 'j4hyqpassX' or origin eq 'uaa'"; + jdbcScimUserProvisioning.setPageSize(0); + // MYSQL default, no LOWER statement in query + joinConverter.setDbCaseInsensitive(true); + List result = jdbcScimUserProvisioning.retrieveByScimFilterOnlyActive( + scimFilter, + null, + false, + currentIdentityZoneId + ); + Assertions.assertThat(result).isNotNull(); + verify(mockedJdbcTemplate).query(contains("u.id = "), any(Map.class), any(RowMapper.class)); + verify(mockedJdbcTemplate, never()).query(contains("LOWER(u.id) = LOWER("), any(Map.class), any(RowMapper.class)); + // POSTGRESQL and HSQL default + joinConverter.setDbCaseInsensitive(false); + result = jdbcScimUserProvisioning.retrieveByScimFilterOnlyActive( + scimFilter, + null, + false, + currentIdentityZoneId + ); + Assertions.assertThat(result).isNotNull(); + verify(notInUse, never()).createJdbcPagingList(anyString(), any(Map.class), any(RowMapper.class), any(Integer.class)); + verify(mockedJdbcTemplate).query(contains("LOWER(u.id) = LOWER("), any(Map.class), any(RowMapper.class)); + } + @Test void retrieveByScimFilter_IncludeInactive() { final String originActive = randomString();