From fdbddcf6061e0e4c19064149e2015383f14ed2cf Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 13 Jun 2025 09:34:25 +0100 Subject: [PATCH] Work around unwanted side-effect of getCredentials() Previously, we called getCredentials() to determine whether or not a repository requires authentication. Unfortunately, the method has the unwanted side-effect of assigning empty username and password credentials to a repository that previously did not require authentication and did not, therefore, have any credentials. These empty credentials can then cause subsequent failures because "Username must not be null!". There's no side-effect-free public API for accessing a repository's credentials. Instead, we're using some internal API on AuthenticationSupportedInternal. If this causes problems when upgrading to a new version of Gradle a different approach will be required. For example, we could pass in the repositories in two separate collections: those that require authentication and those that don't. Closes gh-45950 --- .../bomr/MavenMetadataVersionResolver.java | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MavenMetadataVersionResolver.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MavenMetadataVersionResolver.java index f7b5c581914..cebe7752e76 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MavenMetadataVersionResolver.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MavenMetadataVersionResolver.java @@ -31,6 +31,9 @@ import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; import org.gradle.api.artifacts.repositories.MavenArtifactRepository; +import org.gradle.api.artifacts.repositories.PasswordCredentials; +import org.gradle.api.credentials.Credentials; +import org.gradle.internal.artifacts.repositories.AuthenticationSupportedInternal; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; @@ -83,9 +86,10 @@ final class MavenMetadataVersionResolver implements VersionResolver { .toUri(); try { HttpHeaders headers = new HttpHeaders(); - String username = repository.getCredentials().getUsername(); + PasswordCredentials credentials = credentialsOf(repository); + String username = (credentials != null) ? credentials.getUsername() : null; if (username != null) { - headers.setBasicAuth(username, repository.getCredentials().getPassword()); + headers.setBasicAuth(username, credentials.getPassword()); } HttpEntity request = new HttpEntity<>(headers); String metadata = this.rest.exchange(url, HttpMethod.GET, request, String.class).getBody(); @@ -112,4 +116,25 @@ final class MavenMetadataVersionResolver implements VersionResolver { return versions; } + /** + * Retrives the configured credentials of the given {@code repository}. We cannot use + * {@link MavenArtifactRepository#getCredentials()} as, if the repository has no + * credentials, it has the unwanted side-effect of assigning an empty set of username + * and password credentials to the repository which may cause subsequent "Username + * must not be null!" failures. + * @param repository the repository that is the source of the credentials + * @return the configured password credentials or {@code null} + */ + private PasswordCredentials credentialsOf(MavenArtifactRepository repository) { + Credentials credentials = ((AuthenticationSupportedInternal) repository).getConfiguredCredentials().getOrNull(); + if (credentials != null) { + if (credentials instanceof PasswordCredentials passwordCredentials) { + return passwordCredentials; + } + throw new IllegalStateException("Repository '%s (%s)' has credentials '%s' that are not PasswordCredentials" + .formatted(repository.getName(), repository.getUrl(), credentials)); + } + return null; + } + }