Replace Spring Security Base64 with java.util equivalent#3857
Replace Spring Security Base64 with java.util equivalent#3857gdgenchev wants to merge 1 commit intocloudfoundry:developfrom
Conversation
Spring Security 7 removed the Base64 class from the spring-security-crypto.codec package. Replaced with java.util.Base64 in all files that used org.springframework.security.crypto.codec.Base64. Related to Spring Boot 4 migration.
7739960 to
00dbdae
Compare
There was a problem hiding this comment.
Pull request overview
Replaces deprecated Spring Security org.springframework.security.crypto.codec.Base64 usage with java.util.Base64 to maintain compatibility with Spring Security 6+ and prepare for Spring Security 7.
Changes:
- Swapped Spring Security Base64 imports for
java.util.Base64across several unit/integration tests. - Updated Basic Auth header construction to use
Base64.getEncoder().encode(...). - Updated
UserNotFoundEventto usejava.util.Base64for hashing/encoding the username in audit events.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/token/TokenMvcMockZonePathTests.java | Replace Spring Base64 with JDK Base64 in multiple Basic Auth header constructions. |
| uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/token/TokenMvcMockTests.java | Same Base64 replacement for token endpoint tests. |
| uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/limited/LimitedModeTokenMockMvcTests.java | Same Base64 replacement in limited-mode check_token test. |
| uaa/src/test/java/org/cloudfoundry/identity/uaa/login/LoginInfoEndpointDocs.java | Same Base64 replacement in REST docs test for autologin. |
| uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/ScimGroupEndpointsIntegrationTests.java | Same Base64 replacement in client-credentials token helper. |
| uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/NativeApplicationIntegrationTests.java | Same Base64 replacement in Basic auth header for negative test. |
| uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/CheckTokenEndpointIntegrationTests.java | Same Base64 replacement in forbidden check_token test. |
| server/src/test/java/org/cloudfoundry/identity/uaa/test/UaaTestAccounts.java | Same Base64 replacement for shared test helper building Basic auth headers. |
| server/src/main/java/org/cloudfoundry/identity/uaa/authentication/event/UserNotFoundEvent.java | Replace Spring Base64 with JDK Base64 in audit-event name hashing/encoding. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ScimUser developer = setUpUser(jdbcScimUserProvisioning, jdbcScimGroupMembershipManager, jdbcScimGroupProvisioning, userId, userScopes, OriginKeys.LOGIN_SERVER, IdentityZoneHolder.get().getId()); | ||
| String loginToken = testClient.getClientCredentialsOAuthAccessToken("login", "loginsecret", ""); | ||
| String basicAuthForLoginClient = new String(Base64.encode("%s:%s".formatted("login", "loginsecret").getBytes())); | ||
| String basicAuthForLoginClient = new String(Base64.getEncoder().encode("%s:%s".formatted("login", "loginsecret").getBytes())); |
There was a problem hiding this comment.
new String(Base64.getEncoder().encode(...)) relies on the platform default charset when converting the encoded bytes to a String. Use Base64.getEncoder().encodeToString(...) instead (and prefer getBytes(StandardCharsets.UTF_8) for the credential bytes) to make the Authorization header deterministic across platforms. This pattern appears multiple times in this file.
| String basicAuthForLoginClient = new String(Base64.getEncoder().encode("%s:%s".formatted("login", "loginsecret").getBytes())); | |
| String basicAuthForLoginClient = Base64.getEncoder().encodeToString("%s:%s".formatted("login", "loginsecret").getBytes(StandardCharsets.UTF_8)); |
| .header(AUTHORIZATION, | ||
| "Basic " + new String(Base64.encode((client.getClientId() + ":" + SECRET).getBytes()))) | ||
| "Basic " + new String(Base64.getEncoder().encode((client.getClientId() + ":" + SECRET).getBytes()))) |
There was a problem hiding this comment.
For Basic auth, avoid new String(Base64.getEncoder().encode(...)) because it depends on the default charset for the byte[]->String conversion. Prefer Base64.getEncoder().encodeToString((clientId + ":" + secret).getBytes(StandardCharsets.UTF_8)) (or US_ASCII for the encoded output) so the Authorization header is stable across environments.
| String body = mockMvc.perform( | ||
| post("/autologin") | ||
| .header("Authorization", "Basic " + new String(Base64.encode("admin:adminsecret".getBytes()))) | ||
| .header("Authorization", "Basic " + new String(Base64.getEncoder().encode("admin:adminsecret".getBytes()))) |
There was a problem hiding this comment.
"Basic " + new String(Base64.getEncoder().encode(...)) is charset-dependent due to new String(byte[]). Prefer Base64.getEncoder().encodeToString("admin:adminsecret".getBytes(StandardCharsets.UTF_8)) (or specify US_ASCII for the encoded output) to avoid platform-specific behavior.
| headers.set("Authorization", | ||
| "Basic " + new String(Base64.encode("%s:%s".formatted(clientId, clientSecret).getBytes()))); | ||
| "Basic " + new String(Base64.getEncoder().encode("%s:%s".formatted(clientId, clientSecret).getBytes()))); |
There was a problem hiding this comment.
Building the Basic auth header via new String(Base64.getEncoder().encode(...)) makes the result depend on the platform default charset. Use Base64.getEncoder().encodeToString(... ) and pass an explicit charset to getBytes(...) (e.g., StandardCharsets.UTF_8) so the header is deterministic.
| formData.add("scope", "cloud_controller.read"); | ||
| HttpHeaders headers = new HttpHeaders(); | ||
| headers.set("Authorization", "Basic " + new String(Base64.encode("no-such-client:".getBytes(StandardCharsets.UTF_8)))); | ||
| headers.set("Authorization", "Basic " + new String(Base64.getEncoder().encode("no-such-client:".getBytes(StandardCharsets.UTF_8)))); |
There was a problem hiding this comment.
Even though the input uses StandardCharsets.UTF_8, wrapping Base64.getEncoder().encode(...) in new String(...) still uses the platform default charset for decoding the Base64 bytes. Prefer Base64.getEncoder().encodeToString(...) to avoid charset-dependent behavior.
| headers.set("Authorization", "Basic " + new String(Base64.getEncoder().encode("no-such-client:".getBytes(StandardCharsets.UTF_8)))); | |
| headers.set("Authorization", "Basic " + Base64.getEncoder().encodeToString("no-such-client:".getBytes(StandardCharsets.UTF_8))); |
| formData.add("token", "FOO"); | ||
| HttpHeaders headers = new HttpHeaders(); | ||
| headers.set("Authorization", "Basic " + new String(Base64.encode("cf:".getBytes(UTF_8)))); | ||
| headers.set("Authorization", "Basic " + new String(Base64.getEncoder().encode("cf:".getBytes(UTF_8)))); |
There was a problem hiding this comment.
new String(Base64.getEncoder().encode(...)) uses the platform default charset to decode the encoded bytes, which is not guaranteed to be ASCII-compatible on all JVMs. Prefer Base64.getEncoder().encodeToString("cf:".getBytes(UTF_8)) (or specify US_ASCII for the output) for a deterministic Basic auth header.
| headers.set("Authorization", "Basic " + new String(Base64.getEncoder().encode("cf:".getBytes(UTF_8)))); | |
| headers.set("Authorization", "Basic " + Base64.getEncoder().encodeToString("cf:".getBytes(UTF_8))); |
| String credentials = | ||
| "%s:%s".formatted(URLEncoder.encode(username, StandardCharsets.UTF_8), URLEncoder.encode(password, StandardCharsets.UTF_8)); | ||
| return "Basic %s".formatted(new String(Base64.encode(credentials.getBytes()))); | ||
| return "Basic %s".formatted(new String(Base64.getEncoder().encode(credentials.getBytes()))); |
There was a problem hiding this comment.
new String(Base64.getEncoder().encode(credentials.getBytes())) is charset-dependent twice: getBytes() uses the platform default charset, and new String(...) decodes Base64 bytes using the platform default charset. Prefer Base64.getEncoder().encodeToString(credentials.getBytes(StandardCharsets.UTF_8)) to make the Basic auth header deterministic across platforms.
| return "Basic %s".formatted(new String(Base64.getEncoder().encode(credentials.getBytes()))); | |
| return "Basic %s".formatted(Base64.getEncoder().encodeToString(credentials.getBytes(StandardCharsets.UTF_8))); |
| // Store hash of name, to conceal accidental entry of sensitive info | ||
| // (e.g. password) | ||
| name = Utf8.decode(Base64.encode(MessageDigest.getInstance("SHA-1").digest(Utf8.encode(name)))); | ||
| name = Utf8.decode(Base64.getEncoder().encode(MessageDigest.getInstance("SHA-1").digest(Utf8.encode(name)))); |
There was a problem hiding this comment.
Since this change already moves off Spring Security's Base64, consider also removing the remaining org.springframework.security.crypto.codec.Utf8 usage here: Base64.getEncoder().encodeToString(MessageDigest...digest(name.getBytes(StandardCharsets.UTF_8))) produces the same value and avoids depending on Spring's deprecated codec utilities (which may also be removed in Spring Security 7).
| ScimUser developer = setUpUser(jdbcScimUserProvisioning, jdbcScimGroupMembershipManager, jdbcScimGroupProvisioning, userId, userScopes, OriginKeys.LOGIN_SERVER, IdentityZoneHolder.get().getId()); | ||
| String loginToken = testClient.getClientCredentialsOAuthAccessToken("login", "loginsecret", ""); | ||
| String basicAuthForLoginClient = new String(Base64.encode("%s:%s".formatted("login", "loginsecret").getBytes())); | ||
| String basicAuthForLoginClient = new String(Base64.getEncoder().encode("%s:%s".formatted("login", "loginsecret").getBytes())); |
There was a problem hiding this comment.
new String(Base64.getEncoder().encode(...)) is charset-dependent and can produce an invalid Base64 string on non-ASCII default charsets. Prefer Base64.getEncoder().encodeToString(...) and specify the input bytes charset (e.g., getBytes(StandardCharsets.UTF_8)) for Basic auth credentials. This pattern appears multiple times in this file.
| String basicAuthForLoginClient = new String(Base64.getEncoder().encode("%s:%s".formatted("login", "loginsecret").getBytes())); | |
| String basicAuthForLoginClient = Base64.getEncoder().encodeToString("%s:%s".formatted("login", "loginsecret").getBytes(StandardCharsets.UTF_8)); |
org.springframework.security.crypto.codec.Base64was deprecated in Spring Security 6 and later removed in Spring Security 7. Replaced withjava.util.Base64.