From 216680bb5048f2b66b27e673be03706223d35933 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 22 Apr 2025 14:34:22 -0600 Subject: [PATCH] Update Deprecated Spring Jdbc Usage --- .../security/acls/jdbc/JdbcAclService.java | 4 +- .../acls/jdbc/JdbcMutableAclService.java | 7 +- .../acls/jdbc/JdbcAclServiceTests.java | 2 +- .../core/userdetails/jdbc/JdbcDaoImpl.java | 13 ++-- .../provisioning/JdbcUserDetailsManager.java | 8 +-- .../JdbcUserCredentialRepository.java | 64 ++++++++++++------- 6 files changed, 55 insertions(+), 43 deletions(-) diff --git a/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcAclService.java b/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcAclService.java index e499577388..f8dbb687e6 100644 --- a/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcAclService.java +++ b/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcAclService.java @@ -100,8 +100,8 @@ public class JdbcAclService implements AclService { @Override public List findChildren(ObjectIdentity parentIdentity) { Object[] args = { parentIdentity.getIdentifier().toString(), parentIdentity.getType() }; - List objects = this.jdbcOperations.query(this.findChildrenSql, args, - (rs, rowNum) -> mapObjectIdentityRow(rs)); + List objects = this.jdbcOperations.query(this.findChildrenSql, + (rs, rowNum) -> mapObjectIdentityRow(rs), args); return (!objects.isEmpty()) ? objects : null; } diff --git a/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcMutableAclService.java b/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcMutableAclService.java index 93f68dd3e7..9b8eb5acbc 100644 --- a/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcMutableAclService.java +++ b/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcMutableAclService.java @@ -190,8 +190,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS * @return the primary key or null if not found */ protected Long createOrRetrieveClassPrimaryKey(String type, boolean allowCreate, Class idType) { - List classIds = this.jdbcOperations.queryForList(this.selectClassPrimaryKey, new Object[] { type }, - Long.class); + List classIds = this.jdbcOperations.queryForList(this.selectClassPrimaryKey, Long.class, type); if (!classIds.isEmpty()) { return classIds.get(0); @@ -242,8 +241,8 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS * @return the primary key or null if not found */ protected Long createOrRetrieveSidPrimaryKey(String sidName, boolean sidIsPrincipal, boolean allowCreate) { - List sidIds = this.jdbcOperations.queryForList(this.selectSidPrimaryKey, - new Object[] { sidIsPrincipal, sidName }, Long.class); + List sidIds = this.jdbcOperations.queryForList(this.selectSidPrimaryKey, Long.class, sidIsPrincipal, + sidName); if (!sidIds.isEmpty()) { return sidIds.get(0); } diff --git a/acl/src/test/java/org/springframework/security/acls/jdbc/JdbcAclServiceTests.java b/acl/src/test/java/org/springframework/security/acls/jdbc/JdbcAclServiceTests.java index 6253c29702..60feb59220 100644 --- a/acl/src/test/java/org/springframework/security/acls/jdbc/JdbcAclServiceTests.java +++ b/acl/src/test/java/org/springframework/security/acls/jdbc/JdbcAclServiceTests.java @@ -109,7 +109,7 @@ public class JdbcAclServiceTests { List result = new ArrayList<>(); result.add(new ObjectIdentityImpl(Object.class, "5577")); Object[] args = { "1", "org.springframework.security.acls.jdbc.JdbcAclServiceTests$MockLongIdDomainObject" }; - given(this.jdbcOperations.query(anyString(), eq(args), any(RowMapper.class))).willReturn(result); + given(this.jdbcOperations.query(anyString(), any(RowMapper.class), eq(args))).willReturn(result); ObjectIdentity objectIdentity = new ObjectIdentityImpl(MockLongIdDomainObject.class, 1L); List objectIdentities = this.aclService.findChildren(objectIdentity); assertThat(objectIdentities).hasSize(1); diff --git a/core/src/main/java/org/springframework/security/core/userdetails/jdbc/JdbcDaoImpl.java b/core/src/main/java/org/springframework/security/core/userdetails/jdbc/JdbcDaoImpl.java index 9772cf8a62..582fddb2f4 100644 --- a/core/src/main/java/org/springframework/security/core/userdetails/jdbc/JdbcDaoImpl.java +++ b/core/src/main/java/org/springframework/security/core/userdetails/jdbc/JdbcDaoImpl.java @@ -226,10 +226,10 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements UserDetailsService, M * @return a list of GrantedAuthority objects for the user */ protected List loadUserAuthorities(String username) { - return getJdbcTemplate().query(this.authoritiesByUsernameQuery, new String[] { username }, (rs, rowNum) -> { + return getJdbcTemplate().query(this.authoritiesByUsernameQuery, (rs, rowNum) -> { String roleName = JdbcDaoImpl.this.rolePrefix + rs.getString(2); return new SimpleGrantedAuthority(roleName); - }); + }, username); } /** @@ -238,11 +238,10 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements UserDetailsService, M * @return a list of GrantedAuthority objects for the user */ protected List loadGroupAuthorities(String username) { - return getJdbcTemplate().query(this.groupAuthoritiesByUsernameQuery, new String[] { username }, - (rs, rowNum) -> { - String roleName = getRolePrefix() + rs.getString(3); - return new SimpleGrantedAuthority(roleName); - }); + return getJdbcTemplate().query(this.groupAuthoritiesByUsernameQuery, (rs, rowNum) -> { + String roleName = getRolePrefix() + rs.getString(3); + return new SimpleGrantedAuthority(roleName); + }, username); } /** diff --git a/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java b/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java index a32c1a87da..b5f80e2946 100644 --- a/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java +++ b/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java @@ -336,8 +336,7 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa @Override public boolean userExists(String username) { - List users = getJdbcTemplate().queryForList(this.userExistsSql, new String[] { username }, - String.class); + List users = getJdbcTemplate().queryForList(this.userExistsSql, String.class, username); if (users.size() > 1) { throw new IncorrectResultSizeDataAccessException("More than one user found with name '" + username + "'", 1); @@ -353,7 +352,7 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa @Override public List findUsersInGroup(String groupName) { Assert.hasText(groupName, "groupName should have text"); - return getJdbcTemplate().queryForList(this.findUsersInGroupSql, new String[] { groupName }, String.class); + return getJdbcTemplate().queryForList(this.findUsersInGroupSql, String.class, groupName); } @Override @@ -422,8 +421,7 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa public List findGroupAuthorities(String groupName) { this.logger.debug("Loading authorities for group '" + groupName + "'"); Assert.hasText(groupName, "groupName should have text"); - return getJdbcTemplate().query(this.groupAuthoritiesSql, new String[] { groupName }, - this.grantedAuthorityMapper); + return getJdbcTemplate().query(this.groupAuthoritiesSql, this.grantedAuthorityMapper, groupName); } private GrantedAuthority mapToGrantedAuthority(ResultSet rs, int rowNum) throws SQLException { diff --git a/web/src/main/java/org/springframework/security/web/webauthn/management/JdbcUserCredentialRepository.java b/web/src/main/java/org/springframework/security/web/webauthn/management/JdbcUserCredentialRepository.java index 660daf6008..2ce023afe1 100644 --- a/web/src/main/java/org/springframework/security/web/webauthn/management/JdbcUserCredentialRepository.java +++ b/web/src/main/java/org/springframework/security/web/webauthn/management/JdbcUserCredentialRepository.java @@ -33,7 +33,6 @@ import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jdbc.core.PreparedStatementSetter; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.SqlParameterValue; -import org.springframework.jdbc.support.lob.DefaultLobHandler; import org.springframework.jdbc.support.lob.LobCreator; import org.springframework.jdbc.support.lob.LobHandler; import org.springframework.security.web.webauthn.api.AuthenticatorTransport; @@ -62,11 +61,11 @@ import org.springframework.util.CollectionUtils; */ public final class JdbcUserCredentialRepository implements UserCredentialRepository { - private RowMapper credentialRecordRowMapper = new CredentialRecordRowMapper(); + private RowMapper credentialRecordRowMapper = new CredentialRecordRowMapper(ResultSet::getBytes); private Function> credentialRecordParametersMapper = new CredentialRecordParametersMapper(); - private LobHandler lobHandler = new DefaultLobHandler(); + private SetBytes setBytes = PreparedStatement::setBytes; private final JdbcOperations jdbcOperations; @@ -159,22 +158,16 @@ public final class JdbcUserCredentialRepository implements UserCredentialReposit private void insertCredentialRecord(CredentialRecord record) { List parameters = this.credentialRecordParametersMapper.apply(record); - try (LobCreator lobCreator = this.lobHandler.getLobCreator()) { - PreparedStatementSetter pss = new LobCreatorArgumentPreparedStatementSetter(lobCreator, - parameters.toArray()); - this.jdbcOperations.update(SAVE_CREDENTIAL_RECORD_SQL, pss); - } + PreparedStatementSetter pss = new BlobArgumentPreparedStatementSetter(this.setBytes, parameters.toArray()); + this.jdbcOperations.update(SAVE_CREDENTIAL_RECORD_SQL, pss); } private int updateCredentialRecord(CredentialRecord record) { List parameters = this.credentialRecordParametersMapper.apply(record); SqlParameterValue credentialId = parameters.remove(0); parameters.add(credentialId); - try (LobCreator lobCreator = this.lobHandler.getLobCreator()) { - PreparedStatementSetter pss = new LobCreatorArgumentPreparedStatementSetter(lobCreator, - parameters.toArray()); - return this.jdbcOperations.update(UPDATE_CREDENTIAL_RECORD_SQL, pss); - } + PreparedStatementSetter pss = new BlobArgumentPreparedStatementSetter(this.setBytes, parameters.toArray()); + return this.jdbcOperations.update(UPDATE_CREDENTIAL_RECORD_SQL, pss); } @Override @@ -195,10 +188,18 @@ public final class JdbcUserCredentialRepository implements UserCredentialReposit /** * Sets a {@link LobHandler} for large binary fields and large text field parameters. * @param lobHandler the lob handler + * @deprecated {@link LobHandler} is deprecated without replacement, as such this + * method will also be removed without replacement */ + @Deprecated(since = "6.5", forRemoval = true) public void setLobHandler(LobHandler lobHandler) { Assert.notNull(lobHandler, "lobHandler cannot be null"); - this.lobHandler = lobHandler; + this.setBytes = (ps, index, bytes) -> { + try (LobCreator creator = lobHandler.getLobCreator()) { + creator.setBlobAsBytes(ps, index, bytes); + } + }; + this.credentialRecordRowMapper = new CredentialRecordRowMapper(lobHandler::getBlobAsBytes); } private static class CredentialRecordParametersMapper @@ -246,13 +247,25 @@ public final class JdbcUserCredentialRepository implements UserCredentialReposit } - private static final class LobCreatorArgumentPreparedStatementSetter extends ArgumentPreparedStatementSetter { + private interface SetBytes { - private final LobCreator lobCreator; + void setBytes(PreparedStatement ps, int index, byte[] bytes) throws SQLException; - private LobCreatorArgumentPreparedStatementSetter(LobCreator lobCreator, Object[] args) { + } + + private interface GetBytes { + + byte[] getBytes(ResultSet rs, String columnName) throws SQLException; + + } + + private static final class BlobArgumentPreparedStatementSetter extends ArgumentPreparedStatementSetter { + + private final SetBytes setBytes; + + private BlobArgumentPreparedStatementSetter(SetBytes setBytes, Object[] args) { super(args); - this.lobCreator = lobCreator; + this.setBytes = setBytes; } @Override @@ -264,7 +277,7 @@ public final class JdbcUserCredentialRepository implements UserCredentialReposit "Value of blob parameter must be byte[]"); } byte[] valueBytes = (byte[]) paramValue.getValue(); - this.lobCreator.setBlobAsBytes(ps, parameterPosition, valueBytes); + this.setBytes.setBytes(ps, parameterPosition, valueBytes); return; } } @@ -275,14 +288,17 @@ public final class JdbcUserCredentialRepository implements UserCredentialReposit private static class CredentialRecordRowMapper implements RowMapper { - private LobHandler lobHandler = new DefaultLobHandler(); + private final GetBytes getBytes; + + CredentialRecordRowMapper(GetBytes getBytes) { + this.getBytes = getBytes; + } @Override public CredentialRecord mapRow(ResultSet rs, int rowNum) throws SQLException { Bytes credentialId = Bytes.fromBase64(new String(rs.getString("credential_id").getBytes())); Bytes userEntityUserId = Bytes.fromBase64(new String(rs.getString("user_entity_user_id").getBytes())); - ImmutablePublicKeyCose publicKey = new ImmutablePublicKeyCose( - this.lobHandler.getBlobAsBytes(rs, "public_key")); + ImmutablePublicKeyCose publicKey = new ImmutablePublicKeyCose(this.getBytes.getBytes(rs, "public_key")); long signatureCount = rs.getLong("signature_count"); boolean uvInitialized = rs.getBoolean("uv_initialized"); boolean backupEligible = rs.getBoolean("backup_eligible"); @@ -291,13 +307,13 @@ public final class JdbcUserCredentialRepository implements UserCredentialReposit boolean backupState = rs.getBoolean("backup_state"); Bytes attestationObject = null; - byte[] rawAttestationObject = this.lobHandler.getBlobAsBytes(rs, "attestation_object"); + byte[] rawAttestationObject = this.getBytes.getBytes(rs, "attestation_object"); if (rawAttestationObject != null) { attestationObject = new Bytes(rawAttestationObject); } Bytes attestationClientDataJson = null; - byte[] rawAttestationClientDataJson = this.lobHandler.getBlobAsBytes(rs, "attestation_client_data_json"); + byte[] rawAttestationClientDataJson = this.getBytes.getBytes(rs, "attestation_client_data_json"); if (rawAttestationClientDataJson != null) { attestationClientDataJson = new Bytes(rawAttestationClientDataJson); }