From a1f99453ca629c18753a8835e406e621fa1cb560 Mon Sep 17 00:00:00 2001 From: Ketan Padegaonkar Date: Tue, 3 Oct 2017 14:52:13 +0530 Subject: [PATCH] Improve checksums for agent jar(s) download (#3884) Before this commit the (md5) checksums for various jars are were encoded in base64 and hex encoding: curl -s https://example.com/go/admin/latest-agent.status -I | grep MD5 Agent-Content-MD5: xcOIJGRG6DVEndmh+ngL0w== Agent-Launcher-Content-MD5: YZZ/8vOLt9tme93YVwtoIg== Agent-Plugins-Content-MD5: 0fc9e52a2619dedfd7973959b8c92063 TFS-SDK-Content-MD5: FDZDpIK84xCKx0EO+HZu9A== This caused problems when checksums were verified because the agent was always verifying passwords using base64, and the plugins zip was encoded in hex format, causing the agent to re-download the plugins.zip every time it was started up. Additionally there was another bug with how the `agent-plugins.zip` checksum was computed. The checksum was computed was basically the equivalent of: `cat [list of plugin.jar] | md5sum`. Whereas it should have been: `zip [list of plugin.jar] | md5sum` --- .../go/agent/launcher/DownloadableFile.java | 21 ++-- .../agent/launcher/DownloadableFileTest.java | 4 +- .../launcher/ServerBinaryDownloaderTest.java | 14 ++- .../thoughtworks/go/util/FileDigester.java | 102 ----------------- .../go/util/FileDigesterTest.java | 105 ------------------ .../go/plugin/infra/commons/PluginsZip.java | 29 +---- .../plugin/infra/commons/PluginsZipTest.java | 15 --- .../AgentRegistrationController.java | 12 +- .../AgentRegistrationControllerTest.java | 22 ++-- .../go/agent/testhelper/FakeGoServer.java | 15 ++- 10 files changed, 58 insertions(+), 281 deletions(-) delete mode 100644 base/src/com/thoughtworks/go/util/FileDigester.java delete mode 100644 base/test/com/thoughtworks/go/util/FileDigesterTest.java diff --git a/agent-common/src/com/thoughtworks/go/agent/launcher/DownloadableFile.java b/agent-common/src/com/thoughtworks/go/agent/launcher/DownloadableFile.java index 84c7b9033da..1d2ab6ef94a 100644 --- a/agent-common/src/com/thoughtworks/go/agent/launcher/DownloadableFile.java +++ b/agent-common/src/com/thoughtworks/go/agent/launcher/DownloadableFile.java @@ -1,30 +1,33 @@ -/*************************GO-LICENSE-START********************************* - * Copyright 2016 ThoughtWorks, Inc. +/* + * Copyright 2017 ThoughtWorks, Inc. * * 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 + * 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. - *************************GO-LICENSE-END***********************************/ + */ package com.thoughtworks.go.agent.launcher; import com.thoughtworks.go.agent.ServerUrlGenerator; import com.thoughtworks.go.agent.common.util.Downloader; -import com.thoughtworks.go.util.FileDigester; +import org.apache.commons.io.IOUtils; import org.apache.commons.io.output.NullOutputStream; +import javax.xml.bind.DatatypeConverter; import java.io.File; import java.io.FileInputStream; import java.net.MalformedURLException; import java.net.URL; +import java.security.DigestInputStream; +import java.security.MessageDigest; public enum DownloadableFile { AGENT("admin/agent", Downloader.AGENT_BINARY), @@ -62,9 +65,11 @@ public String toString() { protected static boolean matchChecksum(File localFile, String expectedSignature) { try (FileInputStream input = new FileInputStream(localFile)) { - FileDigester fileDigester = new FileDigester(input, new NullOutputStream()); - fileDigester.copy(); - return expectedSignature.equals(fileDigester.md5()); + MessageDigest digester = MessageDigest.getInstance("MD5"); + try (DigestInputStream digest = new DigestInputStream(input, digester)) { + IOUtils.copy(digest, new NullOutputStream()); + } + return expectedSignature.equalsIgnoreCase(DatatypeConverter.printHexBinary(digester.digest())); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/agent-common/test/com/thoughtworks/go/agent/launcher/DownloadableFileTest.java b/agent-common/test/com/thoughtworks/go/agent/launcher/DownloadableFileTest.java index 93c9f3f34a3..be8c30fae0c 100644 --- a/agent-common/test/com/thoughtworks/go/agent/launcher/DownloadableFileTest.java +++ b/agent-common/test/com/thoughtworks/go/agent/launcher/DownloadableFileTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 ThoughtWorks, Inc. + * Copyright 2017 ThoughtWorks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,7 +36,7 @@ public class DownloadableFileTest { @Test public void shouldReturnTrueIfChecksumIsEqual() throws Exception { File inputFile = new File("test-resources/checksum.txt"); - assertTrue(DownloadableFile.matchChecksum(inputFile, "FlCLOoC4KK/RMxgAO1hibg==")); + assertTrue(DownloadableFile.matchChecksum(inputFile, "16508b3a80b828afd13318003b58626e")); } /* diff --git a/agent-common/test/com/thoughtworks/go/agent/launcher/ServerBinaryDownloaderTest.java b/agent-common/test/com/thoughtworks/go/agent/launcher/ServerBinaryDownloaderTest.java index a5b5b96ffa2..44459d61c8e 100644 --- a/agent-common/test/com/thoughtworks/go/agent/launcher/ServerBinaryDownloaderTest.java +++ b/agent-common/test/com/thoughtworks/go/agent/launcher/ServerBinaryDownloaderTest.java @@ -22,6 +22,8 @@ import com.thoughtworks.go.mothers.ServerUrlGeneratorMother; import com.thoughtworks.go.util.SslVerificationMode; import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.io.output.NullOutputStream; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.impl.client.CloseableHttpClient; @@ -30,12 +32,14 @@ import org.junit.Test; import org.junit.rules.ExpectedException; +import javax.xml.bind.DatatypeConverter; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.net.UnknownHostException; +import java.security.DigestInputStream; +import java.security.MessageDigest; -import static com.thoughtworks.go.util.FileDigester.md5DigestOfStream; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; import static org.mockito.Matchers.any; @@ -61,8 +65,12 @@ public void shouldSetMd5AndSSLPortHeaders() throws Exception { ServerBinaryDownloader downloader = new ServerBinaryDownloader(ServerUrlGeneratorMother.generatorFor("localhost", server.getPort()), null, SslVerificationMode.NONE); downloader.downloadIfNecessary(DownloadableFile.AGENT); - try(BufferedInputStream stream = new BufferedInputStream(new FileInputStream(DownloadableFile.AGENT.getLocalFile()))) { - assertThat(downloader.getMd5(), is(md5DigestOfStream(stream))); + MessageDigest digester = MessageDigest.getInstance("MD5"); + try (BufferedInputStream stream = new BufferedInputStream(new FileInputStream(DownloadableFile.AGENT.getLocalFile()))) { + try (DigestInputStream digest = new DigestInputStream(stream, digester)) { + IOUtils.copy(digest, new NullOutputStream()); + } + assertThat(downloader.getMd5(), is(DatatypeConverter.printHexBinary(digester.digest()).toLowerCase())); } assertThat(downloader.getSslPort(), is(String.valueOf(server.getSecurePort()))); } diff --git a/base/src/com/thoughtworks/go/util/FileDigester.java b/base/src/com/thoughtworks/go/util/FileDigester.java deleted file mode 100644 index 2d6bcace0cb..00000000000 --- a/base/src/com/thoughtworks/go/util/FileDigester.java +++ /dev/null @@ -1,102 +0,0 @@ -/*************************GO-LICENSE-START********************************* - * Copyright 2015 ThoughtWorks, Inc. - * - * 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. - *************************GO-LICENSE-END***********************************/ - -package com.thoughtworks.go.util; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.io.comparator.NameFileComparator; -import org.apache.commons.io.output.NullOutputStream; - -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import java.util.Base64; - -public class FileDigester { - private final InputStream input; - private final OutputStream output; - private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; - private MessageDigest md; - - public FileDigester(InputStream input, OutputStream output) { - this.input = input; - this.output = output; - } - - // Copied from IOUtils with extra stuff for digesting - public long copy() throws IOException { - try { - md = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException e) { - throw ExceptionUtils.bomb(e); - } - byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; - long count = 0; - int n; - while (-1 != (n = input.read(buffer))) { - md.update(buffer, 0, n); - output.write(buffer, 0, n); - count += n; - } - return count; - } - - public String md5() { - if (md == null) { - throw new IllegalStateException("You must call copy() to copy the file before trying to obtain the digest"); - } - return Base64.getEncoder().encodeToString(md.digest()); - } - - public static String md5DigestOfFile(File file) throws IOException { - FileInputStream stream = null; - try { - stream = new FileInputStream(file); - return md5DigestOfStream(stream); - } finally { - IOUtils.closeQuietly(stream); - } - } - - public static String md5DigestOfFolderContent(File directory) throws IOException { - File[] files = directory.listFiles(); - Arrays.sort(files, NameFileComparator.NAME_COMPARATOR); - StringBuilder md5 = new StringBuilder(); - for (File file : files) { - if (file.isDirectory()) - md5.append(md5DigestOfFolderContent(file)); - else - md5.append(file.getName() + md5DigestOfFile(file)); - } - return md5DigestOfStream(new ByteArrayInputStream(md5.toString().getBytes(StandardCharsets.UTF_8))); - } - - public static String md5DigestOfStream(InputStream stream) throws IOException { - try { - return copyAndDigest(stream, new NullOutputStream()); - } finally { - IOUtils.closeQuietly(stream); - } - } - - public static String copyAndDigest(InputStream inputStream, OutputStream outputStream) throws IOException { - FileDigester digester = new FileDigester(inputStream, outputStream); - digester.copy(); - return digester.md5(); - } -} diff --git a/base/test/com/thoughtworks/go/util/FileDigesterTest.java b/base/test/com/thoughtworks/go/util/FileDigesterTest.java deleted file mode 100644 index 99f76a7f65b..00000000000 --- a/base/test/com/thoughtworks/go/util/FileDigesterTest.java +++ /dev/null @@ -1,105 +0,0 @@ -/*************************GO-LICENSE-START********************************* - * Copyright 2015 ThoughtWorks, Inc. - * - * 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. - *************************GO-LICENSE-END***********************************/ - -package com.thoughtworks.go.util; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -import java.io.File; -import java.io.IOException; - -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - -public class FileDigesterTest { - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); - - @Before - public void setUp() throws Exception { - temporaryFolder.create(); - } - - @After - public void tearDown() throws Exception { - temporaryFolder.delete(); - } - - @Test - public void shouldReturnSameMd5ForSameData() throws Exception { - String digest1 = FileDigester.md5DigestOfFile(createFileWithSampleData("test1.txt")); - assertThat("md5 should not be empty", digest1.length() > 0, is(true)); - String digest2 = FileDigester.md5DigestOfFile(createFileWithSampleData("test2.txt")); - assertThat(digest1, is(digest2)); - } - - @Test - public void shouldReturnSameMd5ForSameFolderContents() throws Exception { - String digest1 = FileDigester.md5DigestOfFolderContent(createFolderWithSampleData("test1", 3)); - assertThat("md5 should not be empty", digest1.length() > 0, is(true)); - temporaryFolder.delete(); - temporaryFolder.create(); - String digest2 = FileDigester.md5DigestOfFolderContent(createFolderWithSampleData("test1", 3)); - assertThat(digest1, is(digest2)); - } - - @Test - public void shouldReturnDifferentMd5ForSameFileContentButDifferentFileName() throws Exception { - String digest1 = FileDigester.md5DigestOfFolderContent(createFolderWithSampleData("test1", 1)); - assertThat("md5 should not be empty", digest1.length() > 0, is(true)); - temporaryFolder.delete(); - temporaryFolder.create(); - String digest2 = FileDigester.md5DigestOfFolderContent(createFolderWithSampleData("test2", 1)); - assertThat(digest1, not(digest2)); - } - - @Test - public void shouldReturnConsistentMd5BySortingTheFileList() throws Exception { - String digest1 = FileDigester.md5DigestOfFolderContent(createFolderWithSampleData("test", 3)); - assertThat("md5 should not be empty", digest1.length() > 0, is(true)); - assertThat(digest1, is("qGpmuFY5fs+Ap0jLQTWeXQ==")); - } - - @Test - public void shouldThrowExceptionIfITryToGetMd5WithoutDigestingFile() { - FileDigester fileDigester = new FileDigester(null, null); - try { - fileDigester.md5(); - fail("Should have thrown an invalid state exception"); - } catch (Exception ignored) { - } - } - - private File createFileWithSampleData(String fileName) throws IOException { - File tempFile = temporaryFolder.newFile(fileName); - FileUtil.writeContentToFile("sample data", tempFile); - return tempFile; - } - - private File createFolderWithSampleData(String fileNamePrefix, int count) throws IOException { - for (int i = 0; i < count; i++) { - File file = temporaryFolder.newFile(fileNamePrefix + i); - FileUtil.writeContentToFile("sample plugin for plugin " + count, file); - } - return temporaryFolder.getRoot(); - } -} diff --git a/plugin-infra/go-plugin-infra/src/com/thoughtworks/go/plugin/infra/commons/PluginsZip.java b/plugin-infra/go-plugin-infra/src/com/thoughtworks/go/plugin/infra/commons/PluginsZip.java index a84858a4e23..d5004ad3c88 100644 --- a/plugin-infra/go-plugin-infra/src/com/thoughtworks/go/plugin/infra/commons/PluginsZip.java +++ b/plugin-infra/go-plugin-infra/src/com/thoughtworks/go/plugin/infra/commons/PluginsZip.java @@ -23,8 +23,6 @@ import com.thoughtworks.go.util.SystemEnvironment; import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.digest.DigestUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.io.output.NullOutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -32,10 +30,9 @@ import java.io.BufferedOutputStream; import java.io.File; -import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.file.Files; -import java.security.DigestInputStream; +import java.security.DigestOutputStream; import java.security.MessageDigest; import java.util.Comparator; import java.util.List; @@ -93,7 +90,8 @@ public void create() { checkFilesAccessibility(bundledPlugins, externalPlugins); reset(); - try (ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(destZipFile)))) { + MessageDigest md5Digest = DigestUtils.getMd5Digest(); + try (ZipOutputStream zos = new ZipOutputStream(new DigestOutputStream(new BufferedOutputStream(new FileOutputStream(destZipFile)), md5Digest))) { for (GoPluginDescriptor taskPlugin : agentPlugins()) { String zipEntryPrefix = "external/"; @@ -105,10 +103,11 @@ public void create() { Files.copy(new File(taskPlugin.pluginFileLocation()).toPath(), zos); zos.closeEntry(); } - md5DigestOfPlugins = computeMd5DigestOfPlugins(); } catch (Exception e) { LOG.error("Could not create zip of plugins for agent to download.", e); } + + md5DigestOfPlugins = Hex.encodeHexString(md5Digest.digest()); } private void reset() { @@ -117,27 +116,9 @@ private void reset() { } public String md5() { - if (md5DigestOfPlugins == null) { - return computeMd5DigestOfPlugins(); - } return md5DigestOfPlugins; } - private String computeMd5DigestOfPlugins() { - try { - MessageDigest md5Digest = DigestUtils.getMd5Digest(); - List taskPlugins = agentPlugins(); - for (GoPluginDescriptor taskPlugin : taskPlugins) { - try (DigestInputStream digest = new DigestInputStream(new FileInputStream(taskPlugin.pluginFileLocation()), md5Digest)) { - IOUtils.copy(digest, new NullOutputStream()); - } - } - return Hex.encodeHexString(md5Digest.digest()); - } catch (Exception e) { - throw new RuntimeException("Could not compute md5 of plugins.", e); - } - } - private List agentPlugins() { if (taskPlugins.isEmpty()) { List agentPlugins = pluginManager.plugins().stream(). diff --git a/plugin-infra/go-plugin-infra/test/com/thoughtworks/go/plugin/infra/commons/PluginsZipTest.java b/plugin-infra/go-plugin-infra/test/com/thoughtworks/go/plugin/infra/commons/PluginsZipTest.java index 4c0ec9e4977..46c8e470d4d 100644 --- a/plugin-infra/go-plugin-infra/test/com/thoughtworks/go/plugin/infra/commons/PluginsZipTest.java +++ b/plugin-infra/go-plugin-infra/test/com/thoughtworks/go/plugin/infra/commons/PluginsZipTest.java @@ -158,21 +158,6 @@ public void shouldUpdateChecksumIfFileIsReCreated() throws Exception { assertThat(pluginsZip.md5(), is(not(oldMd5))); } - @Test - public void shouldGetChecksumOfExistingFile() throws Exception { - String md5 = pluginsZip.md5(); - assertThat(md5, is(notNullValue())); - } - - @Test - public void shouldThrowExceptionWhileRetrievingChecksumOfUnavailableFile() throws Exception { - expectedException.expect(RuntimeException.class); - expectedException.expectMessage(containsString("Could not compute md5 of plugins.")); - - temporaryFolder.delete(); - pluginsZip.md5(); - } - @Test(expected = FileAccessRightsCheckException.class) public void shouldFailGracefullyWhenExternalFileCannotBeRead() throws Exception { File bundledPluginsDir = temporaryFolder.newFolder("plugins-bundled-ext"); diff --git a/server/src/com/thoughtworks/go/server/controller/AgentRegistrationController.java b/server/src/com/thoughtworks/go/server/controller/AgentRegistrationController.java index 7a3fab75e47..06ac9b2eb43 100644 --- a/server/src/com/thoughtworks/go/server/controller/AgentRegistrationController.java +++ b/server/src/com/thoughtworks/go/server/controller/AgentRegistrationController.java @@ -32,6 +32,7 @@ import com.thoughtworks.go.server.service.result.HttpOperationResult; import com.thoughtworks.go.util.SystemEnvironment; import com.thoughtworks.go.util.TimeProvider; +import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -53,7 +54,6 @@ import java.util.List; import java.util.Map; -import static com.thoughtworks.go.util.FileDigester.md5DigestOfStream; import static org.apache.commons.lang.StringUtils.isBlank; import static org.apache.commons.lang.StringUtils.isNotBlank; @@ -141,13 +141,9 @@ public void populateTFSSDKChecksum() throws IOException { } private String getChecksumFor(final InputStreamSrc src) throws IOException { - InputStream inputStream = null; - String checksum = null; - try { - inputStream = src.invoke(); - checksum = md5DigestOfStream(inputStream); - } finally { - IOUtils.closeQuietly(inputStream); + String checksum; + try (InputStream inputStream = src.invoke()) { + checksum = DigestUtils.md5Hex(inputStream); } assert (checksum != null); return checksum; diff --git a/server/test/unit/com/thoughtworks/go/server/controller/AgentRegistrationControllerTest.java b/server/test/unit/com/thoughtworks/go/server/controller/AgentRegistrationControllerTest.java index 582b99877a8..1c0b1d92191 100644 --- a/server/test/unit/com/thoughtworks/go/server/controller/AgentRegistrationControllerTest.java +++ b/server/test/unit/com/thoughtworks/go/server/controller/AgentRegistrationControllerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 ThoughtWorks, Inc. + * Copyright 2017 ThoughtWorks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ import com.thoughtworks.go.util.SystemEnvironment; import com.thoughtworks.go.util.TestFileUtil; import com.thoughtworks.go.util.TimeProvider; +import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.junit.Before; @@ -43,7 +44,6 @@ import java.io.InputStream; import java.util.Arrays; -import static com.thoughtworks.go.util.FileDigester.md5DigestOfStream; import static org.hamcrest.Matchers.is; import static org.junit.Assert.*; import static org.mockito.Mockito.*; @@ -142,15 +142,15 @@ public void checkAgentStatusShouldIncludeMd5Checksum_forAgent_forLauncher_whenCh controller.checkAgentStatus(response); try (InputStream stream = new TFSJarDetector.DevelopmentServerTFSJarDetector(systemEnvironment).getJarURL().openStream()) { - assertEquals(md5DigestOfStream(stream), response.getHeader(SystemEnvironment.AGENT_TFS_SDK_MD5_HEADER)); + assertEquals(DigestUtils.md5Hex(stream), response.getHeader(SystemEnvironment.AGENT_TFS_SDK_MD5_HEADER)); } try (InputStream stream = JarDetector.create(systemEnvironment, "agent-launcher.jar")) { - assertEquals(md5DigestOfStream(stream), response.getHeader(SystemEnvironment.AGENT_LAUNCHER_CONTENT_MD5_HEADER)); + assertEquals(DigestUtils.md5Hex(stream), response.getHeader(SystemEnvironment.AGENT_LAUNCHER_CONTENT_MD5_HEADER)); } try (InputStream stream = JarDetector.create(systemEnvironment, "agent.jar")) { - assertEquals(md5DigestOfStream(stream), response.getHeader(SystemEnvironment.AGENT_CONTENT_MD5_HEADER)); + assertEquals(DigestUtils.md5Hex(stream), response.getHeader(SystemEnvironment.AGENT_CONTENT_MD5_HEADER)); } assertEquals("plugins-zip-md5", response.getHeader(SystemEnvironment.AGENT_PLUGINS_ZIP_MD5_HEADER)); @@ -163,7 +163,7 @@ public void headShouldIncludeMd5ChecksumAndServerUrl_forAgent() throws Exception assertEquals("8443", response.getHeader("Cruise-Server-Ssl-Port")); try (InputStream stream = JarDetector.create(systemEnvironment, "agent.jar")) { - assertEquals(md5DigestOfStream(stream), response.getHeader("Content-MD5")); + assertEquals(DigestUtils.md5Hex(stream), response.getHeader("Content-MD5")); } } @@ -173,7 +173,7 @@ public void headShouldIncludeMd5ChecksumAndServerUrl_forAgentLauncher() throws E assertEquals("8443", response.getHeader("Cruise-Server-Ssl-Port")); try (InputStream stream = JarDetector.create(systemEnvironment, "agent-launcher.jar")) { - assertEquals(md5DigestOfStream(stream), response.getHeader("Content-MD5")); + assertEquals(DigestUtils.md5Hex(stream), response.getHeader("Content-MD5")); } } @@ -184,7 +184,7 @@ public void contentShouldIncludeMd5Checksum_forAgent() throws Exception { assertEquals("application/octet-stream", response.getContentType()); try (InputStream stream = JarDetector.create(systemEnvironment, "agent.jar")) { - assertEquals(md5DigestOfStream(stream), response.getHeader("Content-MD5")); + assertEquals(DigestUtils.md5Hex(stream), response.getHeader("Content-MD5")); } try (InputStream is = JarDetector.create(systemEnvironment, "agent.jar")) { assertTrue(Arrays.equals(IOUtils.toByteArray(is), response.getContentAsByteArray())); @@ -198,7 +198,7 @@ public void contentShouldIncludeMd5Checksum_forAgentLauncher() throws Exception assertEquals("application/octet-stream", response.getContentType()); try (InputStream stream = JarDetector.create(systemEnvironment, "agent-launcher.jar")) { - assertEquals(md5DigestOfStream(stream), response.getHeader("Content-MD5")); + assertEquals(DigestUtils.md5Hex(stream), response.getHeader("Content-MD5")); } try (InputStream is = JarDetector.create(systemEnvironment, "agent-launcher.jar")) { assertTrue(Arrays.equals(IOUtils.toByteArray(is), response.getContentAsByteArray())); @@ -233,7 +233,7 @@ public void shouldReturnAgentPluginsZipWhenRequested() throws Exception { public void shouldReturnChecksumOfTfsJar() throws Exception { controller.checkTfsImplVersion(response); try (InputStream stream = new TFSJarDetector.DevelopmentServerTFSJarDetector(systemEnvironment).getJarURL().openStream()) { - assertEquals(md5DigestOfStream(stream), response.getHeader("Content-MD5")); + assertEquals(DigestUtils.md5Hex(stream), response.getHeader("Content-MD5")); } } @@ -243,7 +243,7 @@ public void shouldRenderTheTfsJar() throws Exception { assertEquals("application/octet-stream", response.getContentType()); try (InputStream stream = new TFSJarDetector.DevelopmentServerTFSJarDetector(systemEnvironment).getJarURL().openStream()) { - assertEquals(md5DigestOfStream(stream), response.getHeader("Content-MD5")); + assertEquals(DigestUtils.md5Hex(stream), response.getHeader("Content-MD5")); } try (InputStream is = new TFSJarDetector.DevelopmentServerTFSJarDetector(systemEnvironment).getJarURL().openStream()) { assertTrue(Arrays.equals(IOUtils.toByteArray(is), response.getContentAsByteArray())); diff --git a/test-utils/src/com/thoughtworks/go/agent/testhelper/FakeGoServer.java b/test-utils/src/com/thoughtworks/go/agent/testhelper/FakeGoServer.java index d1de5df53b4..7f8c932f308 100644 --- a/test-utils/src/com/thoughtworks/go/agent/testhelper/FakeGoServer.java +++ b/test-utils/src/com/thoughtworks/go/agent/testhelper/FakeGoServer.java @@ -18,6 +18,7 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; +import org.apache.commons.io.output.NullOutputStream; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.server.*; import org.eclipse.jetty.servlet.ServletHolder; @@ -30,12 +31,14 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.xml.bind.DatatypeConverter; import java.io.*; +import java.security.DigestInputStream; +import java.security.MessageDigest; import java.util.EnumSet; import java.util.Properties; import static com.thoughtworks.go.agent.testhelper.FakeGoServer.TestResource.*; -import static com.thoughtworks.go.util.FileDigester.md5DigestOfStream; public class FakeGoServer extends ExternalResource { public enum TestResource { @@ -51,8 +54,14 @@ public enum TestResource { } public String getMd5() throws IOException { - try (InputStream in = source.getInputStream()) { - return md5DigestOfStream(in); + try (InputStream input = source.getInputStream()) { + MessageDigest digester = MessageDigest.getInstance("MD5"); + try (DigestInputStream digest = new DigestInputStream(input, digester)) { + IOUtils.copy(digest, new NullOutputStream()); + } + return DatatypeConverter.printHexBinary(digester.digest()).toLowerCase(); + } catch (Exception e) { + throw new RuntimeException(e); } }