Merge pull request #171 from bsinno/fix_device_simulator

Fixed auth problem in device simulator. Fixed equals ignore case in MD5 check.
This commit is contained in:
Kai Zimmermann
2016-05-10 14:32:33 +02:00
2 changed files with 100 additions and 17 deletions

View File

@@ -8,6 +8,8 @@
*/
package org.eclipse.hawkbit.simulator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -41,6 +43,8 @@ import org.eclipse.hawkbit.simulator.event.ProgressUpdate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import com.google.common.eventbus.EventBus;
@@ -114,6 +118,11 @@ public class DeviceSimulatorUpdater {
}
private static final class DeviceSimulatorUpdateThread implements Runnable {
/**
*
*/
private static final int MINIMUM_TOKENLENGTH_FOR_HINT = 6;
private static final Random rndSleep = new SecureRandom();
private final AbstractSimulatedDevice device;
@@ -193,7 +202,8 @@ public class DeviceSimulatorUpdater {
switch (entry.getKey()) {
case HTTP:
case HTTPS:
status.add(downloadUrl(entry.getValue(), targetToken, artifact.getHashes().getSha1()));
status.add(downloadUrl(entry.getValue(), targetToken, artifact.getHashes().getSha1(),
artifact.getSize()));
break;
default:
// not supported yet
@@ -202,37 +212,60 @@ public class DeviceSimulatorUpdater {
});
}
private static UpdateStatus downloadUrl(final String url, final String targetToken, final String sha1Hash) {
LOGGER.debug("Downloading {}", url);
private static UpdateStatus downloadUrl(final String url, final String targetToken, final String sha1Hash,
final long size) {
LOGGER.debug("Downloading {} with token {}, expected sha1 hash {} and size {}", url,
hideTokenDetails(targetToken), sha1Hash, size);
long overallread = 0;
try {
final CloseableHttpClient httpclient = createHttpClientThatAcceptsAllServerCerts();
final HttpGet request = new HttpGet(url);
request.addHeader("TargetToken", targetToken);
request.addHeader(HttpHeaders.AUTHORIZATION, "TargetToken " + targetToken);
final String sha1HashResult;
try (final CloseableHttpResponse response = httpclient.execute(request)) {
if (response.getStatusLine().getStatusCode() != HttpStatus.OK.value()) {
final String message = wrongStatusCode(url, response);
return new UpdateStatus(ResponseStatus.ERROR, message);
}
if (response.getEntity().getContentLength() != size) {
final String message = wrongContentLength(url, size, response);
return new UpdateStatus(ResponseStatus.ERROR, message);
}
final File tempFile = File.createTempFile("uploadFile", null);
final MessageDigest md = MessageDigest.getInstance("SHA-1");
try (final DigestOutputStream dos = new DigestOutputStream(new FileOutputStream(tempFile), md)) {
overallread = ByteStreams.copy(response.getEntity().getContent(), dos);
sha1HashResult = BaseEncoding.base16().lowerCase().encode(md.digest());
try (final BufferedOutputStream bdos = new BufferedOutputStream(dos)) {
try (BufferedInputStream bis = new BufferedInputStream(response.getEntity().getContent())) {
overallread = ByteStreams.copy(bis, bdos);
}
}
} finally {
tempFile.delete();
if (tempFile != null && !tempFile.delete()) {
LOGGER.error("Could not delete temporary file: {}", tempFile);
}
}
if (overallread != size) {
final String message = incompleteRead(url, size, overallread);
return new UpdateStatus(ResponseStatus.ERROR, message);
}
sha1HashResult = BaseEncoding.base16().lowerCase().encode(md.digest());
}
if (!sha1Hash.equals(sha1HashResult)) {
final String message = "Download " + url + " failed with SHA1 hash missmatch (Expected: " + sha1Hash
+ " but got: " + sha1HashResult + ")";
LOGGER.debug(message);
if (!sha1Hash.equalsIgnoreCase(sha1HashResult)) {
final String message = wrongHash(url, sha1Hash, overallread, sha1HashResult);
return new UpdateStatus(ResponseStatus.ERROR, message);
}
} catch (IOException | KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
LOGGER.error("Failed to download {}", url, e);
LOGGER.error("Failed to download {} with {}", url, e.getMessage());
return new UpdateStatus(ResponseStatus.ERROR, "Failed to download " + url + ": " + e.getMessage());
}
@@ -241,6 +274,48 @@ public class DeviceSimulatorUpdater {
return new UpdateStatus(ResponseStatus.SUCCESSFUL, message);
}
private static String hideTokenDetails(final String targetToken) {
if (targetToken.isEmpty()) {
return "<EMTPTY!>";
}
if (targetToken.length() <= MINIMUM_TOKENLENGTH_FOR_HINT) {
return "***";
}
return targetToken.substring(0, 2) + "***"
+ targetToken.substring(targetToken.length() - 2, targetToken.length());
}
private static String wrongHash(final String url, final String sha1Hash, final long overallread,
final String sha1HashResult) {
final String message = "Download " + url + " failed with SHA1 hash missmatch (Expected: " + sha1Hash
+ " but got: " + sha1HashResult + ") (" + overallread + " bytes)";
LOGGER.error(message);
return message;
}
private static String incompleteRead(final String url, final long size, final long overallread) {
final String message = "Download " + url + " is incomplete (Expected: " + size + " but got: " + overallread
+ ")";
LOGGER.error(message);
return message;
}
private static String wrongContentLength(final String url, final long size,
final CloseableHttpResponse response) {
final String message = "Download " + url + " has wrong content length (Expected: " + size + " but got: "
+ response.getEntity().getContentLength() + ")";
LOGGER.error(message);
return message;
}
private static String wrongStatusCode(final String url, final CloseableHttpResponse response) {
final String message = "Download " + url + " failed (" + response.getStatusLine().getStatusCode() + ")";
LOGGER.error(message);
return message;
}
private static CloseableHttpClient createHttpClientThatAcceptsAllServerCerts()
throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
final SSLContextBuilder builder = new SSLContextBuilder();

View File

@@ -8,11 +8,14 @@
*/
package org.eclipse.hawkbit.artifact.repository;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -122,7 +125,11 @@ public class ArtifactStore implements ArtifactRepository {
LOGGER.debug("storing file {} of content {}", filename, contentType);
tempFile = File.createTempFile("uploadFile", null);
try (final FileOutputStream os = new FileOutputStream(tempFile)) {
return store(content, contentType, os, tempFile, hash);
try (BufferedOutputStream bos = new BufferedOutputStream(os)) {
try (BufferedInputStream bis = new BufferedInputStream(content)) {
return store(content, contentType, bos, tempFile, hash);
}
}
}
} catch (final IOException | MongoException e1) {
throw new ArtifactStoreException(e1.getMessage(), e1);
@@ -162,7 +169,7 @@ public class ArtifactStore implements ArtifactRepository {
}
private DbArtifact store(final InputStream content, final String contentType, final FileOutputStream os,
private DbArtifact store(final InputStream content, final String contentType, final OutputStream os,
final File tempFile, final DbArtifactHash hash) {
final GridFsArtifact storedArtifact;
try {
@@ -185,7 +192,8 @@ public class ArtifactStore implements ArtifactRepository {
throw new ArtifactStoreException(e.getMessage(), e);
}
if (hash != null && hash.getMd5() != null && !storedArtifact.getHashes().getMd5().equals(hash.getMd5())) {
if (hash != null && hash.getMd5() != null
&& !storedArtifact.getHashes().getMd5().equalsIgnoreCase(hash.getMd5())) {
throw new HashNotMatchException("The given md5 hash " + hash.getMd5()
+ " not matching the calculated md5 hash " + storedArtifact.getHashes().getMd5(),
HashNotMatchException.MD5);
@@ -195,8 +203,8 @@ public class ArtifactStore implements ArtifactRepository {
}
private static String computeSHA1Hash(final InputStream stream, final FileOutputStream os,
final String providedSHA1Sum) throws NoSuchAlgorithmException, IOException {
private static String computeSHA1Hash(final InputStream stream, final OutputStream os, final String providedSHA1Sum)
throws NoSuchAlgorithmException, IOException {
String sha1Hash;
// compute digest
final MessageDigest md = MessageDigest.getInstance("SHA-1");