From 57ea732e2c11bec065e32c98f699ae2e867f212b Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 10 Feb 2016 16:22:35 +0100 Subject: [PATCH] Verify Artifactory authentication before release build. We now explicitly access an Artifactory resource to verify authentication so that it's less likely the deployment and promotion will fail later on. Added "artifactory verify" as command to be executed from the shell. --- .../data/release/cli/ReleaseCommands.java | 2 + .../release/deployment/ArtifactoryClient.java | 38 +++++++++++++++-- .../deployment/ArtifactoryCommands.java | 38 +++++++++++++++++ .../deployment/DeploymentConfiguration.java | 7 ++-- .../deployment/DeploymentOperations.java | 4 ++ .../deployment/DeploymentProperties.java | 10 +++++ .../data/release/git/GitProperties.java | 5 ++- .../data/release/jira/GitHubIssueTracker.java | 8 +--- .../data/release/utils/ExecutionUtils.java | 1 - .../release/utils/HttpBasicCredentials.java | 42 +++++++++++++++++++ 10 files changed, 139 insertions(+), 16 deletions(-) create mode 100644 src/main/java/org/springframework/data/release/deployment/ArtifactoryCommands.java create mode 100644 src/main/java/org/springframework/data/release/utils/HttpBasicCredentials.java diff --git a/src/main/java/org/springframework/data/release/cli/ReleaseCommands.java b/src/main/java/org/springframework/data/release/cli/ReleaseCommands.java index 952dd07..49848dd 100644 --- a/src/main/java/org/springframework/data/release/cli/ReleaseCommands.java +++ b/src/main/java/org/springframework/data/release/cli/ReleaseCommands.java @@ -102,6 +102,8 @@ public class ReleaseCommands implements CommandMarker { } else { + deployment.verifyAuthentication(); + List deploymentInformation = build.performRelease(iteration); git.commit(iteration, "Release version %s."); deploymentInformation.forEach(deployment::promote); diff --git a/src/main/java/org/springframework/data/release/deployment/ArtifactoryClient.java b/src/main/java/org/springframework/data/release/deployment/ArtifactoryClient.java index 5d7cffa..0b26e90 100644 --- a/src/main/java/org/springframework/data/release/deployment/ArtifactoryClient.java +++ b/src/main/java/org/springframework/data/release/deployment/ArtifactoryClient.java @@ -59,15 +59,32 @@ class ArtifactoryClient { try { template.postForEntity(uri, new PromotionRequest(information.getTargetRepository()), String.class); } catch (HttpClientErrorException o_O) { - handle(o_O, module); + handle("Promotion failed!", o_O, module); } } - private void handle(HttpClientErrorException o_O, ModuleIteration module) { + public void verify() { + + URI verificationResource = properties.getServer().getVerificationResource(); try { - logger.log(module, "Promotion failed!"); + logger.log("Artifactory", "Verifying authentication using a GET call to %s.", verificationResource); + + template.getForEntity(verificationResource, String.class); + + logger.log("Artifactory", "Authentication verified!"); + + } catch (HttpClientErrorException o_O) { + handle("Authentication verification failed!", o_O); + } + } + + private void handle(String log, HttpClientErrorException o_O, ModuleIteration module) { + + try { + + logger.log(module, log); Errors errors = new ObjectMapper().readValue(o_O.getResponseBodyAsByteArray(), Errors.class); errors.getErrors().forEach(error -> logger.log(module, error)); @@ -78,6 +95,21 @@ class ArtifactoryClient { } } + private void handle(String log, HttpClientErrorException o_O) { + + try { + + logger.log("Artifactory Client", log); + + Errors errors = new ObjectMapper().readValue(o_O.getResponseBodyAsByteArray(), Errors.class); + errors.getErrors().forEach(error -> logger.log("Artifactory Client", error)); + errors.getMessages().forEach(message -> logger.log("Artifactory Client", message)); + + } catch (IOException e) { + throw new RuntimeException(e); + } + } + public void deleteArtifacts(DeploymentInformation information) { template.delete(properties.getServer().getDeleteBuildResource(information)); } diff --git a/src/main/java/org/springframework/data/release/deployment/ArtifactoryCommands.java b/src/main/java/org/springframework/data/release/deployment/ArtifactoryCommands.java new file mode 100644 index 0000000..b916a0b --- /dev/null +++ b/src/main/java/org/springframework/data/release/deployment/ArtifactoryCommands.java @@ -0,0 +1,38 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.deployment; + +import lombok.RequiredArgsConstructor; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.release.CliComponent; +import org.springframework.shell.core.CommandMarker; +import org.springframework.shell.core.annotation.CliCommand; + +/** + * @author Oliver Gierke + */ +@CliComponent +@RequiredArgsConstructor(onConstructor = @__(@Autowired) ) +public class ArtifactoryCommands implements CommandMarker { + + private final DeploymentOperations deployment; + + @CliCommand(value = "artifactory verify", help = "Verifies authentication at Artifactory.") + public void verify() { + deployment.verifyAuthentication(); + } +} diff --git a/src/main/java/org/springframework/data/release/deployment/DeploymentConfiguration.java b/src/main/java/org/springframework/data/release/deployment/DeploymentConfiguration.java index 634a471..d7bcb7b 100644 --- a/src/main/java/org/springframework/data/release/deployment/DeploymentConfiguration.java +++ b/src/main/java/org/springframework/data/release/deployment/DeploymentConfiguration.java @@ -50,7 +50,7 @@ class DeploymentConfiguration { public RestTemplate artifactoryRestTemplate() { RestTemplate template = new RestTemplate(); - template.setInterceptors(Arrays.asList(new AuthenticatingClientHttpRequestInterceptor(properties.getApiKey()))); + template.setInterceptors(Arrays.asList(new AuthenticatingClientHttpRequestInterceptor(properties))); return template; } @@ -58,7 +58,7 @@ class DeploymentConfiguration { @RequiredArgsConstructor private static class AuthenticatingClientHttpRequestInterceptor implements ClientHttpRequestInterceptor { - private final @NonNull String apiKey; + private final @NonNull DeploymentProperties properties; /* * (non-Javadoc) @@ -68,7 +68,8 @@ class DeploymentConfiguration { public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { - request.getHeaders().add("X-Api-Key", apiKey); + request.getHeaders().add("X-Api-Key", properties.getApiKey()); + request.getHeaders().add("Authentication", properties.getCredentials().toString()); return execution.execute(request, body); } diff --git a/src/main/java/org/springframework/data/release/deployment/DeploymentOperations.java b/src/main/java/org/springframework/data/release/deployment/DeploymentOperations.java index eab57cd..107c33e 100644 --- a/src/main/java/org/springframework/data/release/deployment/DeploymentOperations.java +++ b/src/main/java/org/springframework/data/release/deployment/DeploymentOperations.java @@ -32,6 +32,10 @@ public class DeploymentOperations { private final ArtifactoryClient client; + public void verifyAuthentication() { + client.verify(); + } + /** * Promotes the artifacts identified by the given {@link DeploymentInformation}. * diff --git a/src/main/java/org/springframework/data/release/deployment/DeploymentProperties.java b/src/main/java/org/springframework/data/release/deployment/DeploymentProperties.java index fad0f0a..0ef5458 100644 --- a/src/main/java/org/springframework/data/release/deployment/DeploymentProperties.java +++ b/src/main/java/org/springframework/data/release/deployment/DeploymentProperties.java @@ -20,6 +20,7 @@ import lombok.Data; import java.net.URI; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.data.release.utils.HttpBasicCredentials; import org.springframework.stereotype.Component; import org.springframework.util.Assert; import org.springframework.web.util.UriTemplate; @@ -69,11 +70,16 @@ public class DeploymentProperties { return server.getUri().toString().concat("/").concat(stagingRepository); } + public HttpBasicCredentials getCredentials() { + return new HttpBasicCredentials(username, password); + } + @Data public static class Server { private static final String PROMOTION_RESOURCE = "/api/build/promote/{buildName}/{buildNumber}"; private static final String DELETE_BUILD_RESOURCE = "/api/build/{buildName}?buildNumbers={buildNumber}&artifacts=1"; + private static final String VERIFICATION_RESOURCE = "/api/storage/test-libs-staging-local"; private String uri; @@ -94,5 +100,9 @@ public class DeploymentProperties { return new UriTemplate(uri.concat(DELETE_BUILD_RESOURCE)).expand(information.getBuildInfoParameters()); } + + public URI getVerificationResource() { + return URI.create(uri.concat(VERIFICATION_RESOURCE)); + } } } diff --git a/src/main/java/org/springframework/data/release/git/GitProperties.java b/src/main/java/org/springframework/data/release/git/GitProperties.java index c35f460..0b2244d 100644 --- a/src/main/java/org/springframework/data/release/git/GitProperties.java +++ b/src/main/java/org/springframework/data/release/git/GitProperties.java @@ -24,6 +24,7 @@ import javax.annotation.PostConstruct; import org.eclipse.jgit.transport.CredentialsProvider; import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.data.release.utils.HttpBasicCredentials; import org.springframework.stereotype.Component; import org.springframework.util.Assert; @@ -58,7 +59,7 @@ public class GitProperties { return new UsernamePasswordCredentialsProvider(username, password); } - public String getAuthenticationHeader() { - return username.concat(":").concat(password); + public HttpBasicCredentials getHttpCredentials() { + return new HttpBasicCredentials(username, password); } } diff --git a/src/main/java/org/springframework/data/release/jira/GitHubIssueTracker.java b/src/main/java/org/springframework/data/release/jira/GitHubIssueTracker.java index 54bbc04..d8f3d50 100644 --- a/src/main/java/org/springframework/data/release/jira/GitHubIssueTracker.java +++ b/src/main/java/org/springframework/data/release/jira/GitHubIssueTracker.java @@ -18,9 +18,7 @@ package org.springframework.data.release.jira; import lombok.RequiredArgsConstructor; import java.net.URI; -import java.nio.charset.Charset; import java.util.Arrays; -import java.util.Base64; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -154,12 +152,8 @@ class GitHubIssueTracker implements IssueTracker { private HttpHeaders getAuthenticationHeaders() { - byte[] encodedAuth = Base64.getEncoder() - .encode(properties.getAuthenticationHeader().getBytes(Charset.forName("US-ASCII"))); - String authHeader = "Basic " + new String(encodedAuth); - HttpHeaders headers = new HttpHeaders(); - headers.set("Authorization", authHeader); + headers.set("Authorization", properties.getHttpCredentials().toString()); return headers; } diff --git a/src/main/java/org/springframework/data/release/utils/ExecutionUtils.java b/src/main/java/org/springframework/data/release/utils/ExecutionUtils.java index cc05c98..4708427 100644 --- a/src/main/java/org/springframework/data/release/utils/ExecutionUtils.java +++ b/src/main/java/org/springframework/data/release/utils/ExecutionUtils.java @@ -51,7 +51,6 @@ public class ExecutionUtils { throw new RuntimeException(o_O); } })).collect(Collectors.toList()).forEach(future -> future.join()); - } /** diff --git a/src/main/java/org/springframework/data/release/utils/HttpBasicCredentials.java b/src/main/java/org/springframework/data/release/utils/HttpBasicCredentials.java new file mode 100644 index 0000000..7a18d25 --- /dev/null +++ b/src/main/java/org/springframework/data/release/utils/HttpBasicCredentials.java @@ -0,0 +1,42 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.utils; + +import lombok.Value; + +import java.nio.charset.Charset; +import java.util.Base64; + +/** + * @author Oliver Gierke + */ +@Value +public class HttpBasicCredentials { + + private final String username, password; + + /* + * (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + + String header = username.concat(":").concat(password); + byte[] encodedAuth = Base64.getEncoder().encode(header.getBytes(Charset.forName("US-ASCII"))); + + return "Basic ".concat(new String(encodedAuth)); + } +}