Skip to content

Commit

Permalink
DDI supports sha256 (#869)
Browse files Browse the repository at this point in the history
* Add SHA256 file hash to ddi GET outputs

Signed-off-by: Alexander Dobler <alexander.dobler3@bosch-si.com>

* Integrate review findings for SHA256 changes

Signed-off-by: Alexander Dobler <alexander.dobler3@bosch-si.com>

* Renamed hashes to base16hases in store() parameters

Signed-off-by: Alexander Dobler <alexander.dobler3@bosch-si.com>

* Added missing javadoc according to sonarqube findings

Signed-off-by: Alexander Dobler <alexander.dobler3@bosch-si.com>
  • Loading branch information
dobleralex authored and Dominic Schabel committed Jul 29, 2019
1 parent fba6cf9 commit bde3548
Show file tree
Hide file tree
Showing 20 changed files with 131 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,14 @@ public ArtifactFilesystem getArtifactBySha1(final String tenant, final String sh
return null;
}

return new ArtifactFilesystem(file, sha1, new DbArtifactHash(sha1, null), file.length(), null);
return new ArtifactFilesystem(file, sha1, new DbArtifactHash(sha1, null, null), file.length(), null);
}

@Override
protected AbstractDbArtifact store(final String tenant, final String sha1Hash16, final String mdMD5Hash16,
final String contentType, final String tempFile) throws IOException {
protected AbstractDbArtifact store(final String tenant, final DbArtifactHash base16Hashes, final String contentType, final String tempFile) throws IOException {

final File file = new File(tempFile);
return renameFileToSHA1Naming(tenant, file, new ArtifactFilesystem(file, sha1Hash16,
new DbArtifactHash(sha1Hash16, mdMD5Hash16), file.length(), contentType));
return renameFileToSHA1Naming(tenant, file, new ArtifactFilesystem(file, base16Hashes.getSha1(), base16Hashes, file.length(), contentType));
}

private ArtifactFilesystem renameFileToSHA1Naming(final String tenant, final File file,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class ArtifactFilesystemTest {
public void getInputStreamOfNonExistingFileThrowsException() {
final File file = new File("fileWhichTotalDoesNotExists");
final ArtifactFilesystem underTest = new ArtifactFilesystem(file, "fileWhichTotalDoesNotExists",
new DbArtifactHash("1", "2"), 0L, null);
new DbArtifactHash("1", "2", "3"), 0L, null);
try {
underTest.getFileInputStream();
Assertions.fail("Expected a FileNotFoundException because file does not exists");
Expand All @@ -48,7 +48,7 @@ public void getInputStreamOfExistingFile() throws IOException {
createTempFile.deleteOnExit();

final ArtifactFilesystem underTest = new ArtifactFilesystem(createTempFile,
ArtifactFilesystemTest.class.getSimpleName(), new DbArtifactHash("1", "2"), 0L, null);
ArtifactFilesystemTest.class.getSimpleName(), new DbArtifactHash("1", "2", "3"), 0L, null);
final byte[] buffer = new byte[1024];
IOUtils.read(underTest.getFileInputStream(), buffer);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,27 +42,31 @@ public abstract class AbstractArtifactRepository implements ArtifactRepository {
// is not used security related
@SuppressWarnings("squid:S2070")
public AbstractDbArtifact store(final String tenant, final InputStream content, final String filename,
final String contentType, final DbArtifactHash hash) {
final String contentType, final DbArtifactHash providedHashes) {
final MessageDigest mdSHA1;
final MessageDigest mdMD5;
final MessageDigest mdSHA256;
try {
mdSHA1 = MessageDigest.getInstance("SHA1");
mdMD5 = MessageDigest.getInstance("MD5");
mdSHA256 = MessageDigest.getInstance("SHA-256");
} catch (final NoSuchAlgorithmException e) {
throw new ArtifactStoreException(e.getMessage(), e);
}

String tempFile = null;
try (final DigestInputStream inputstream = wrapInDigestInputStream(content, mdSHA1, mdMD5)) {
try (final DigestInputStream inputstream = wrapInDigestInputStream(content, mdSHA1, mdMD5, mdSHA256)) {

tempFile = storeTempFile(inputstream);

final String sha1Hash16 = BaseEncoding.base16().lowerCase().encode(mdSHA1.digest());
final String md5Hash16 = BaseEncoding.base16().lowerCase().encode(mdMD5.digest());
final String sha256Hash16 = BaseEncoding.base16().lowerCase().encode(mdSHA256.digest());

checkHashes(sha1Hash16, md5Hash16, hash);
checkHashes(sha1Hash16, md5Hash16, sha256Hash16, providedHashes);

return store(sanitizeTenant(tenant), sha1Hash16, md5Hash16, contentType, tempFile);
return store(sanitizeTenant(tenant), new DbArtifactHash(sha1Hash16, md5Hash16, sha256Hash16), contentType,
tempFile);
} catch (final IOException e) {
throw new ArtifactStoreException(e.getMessage(), e);
} finally {
Expand Down Expand Up @@ -100,27 +104,35 @@ private static File createTempFile() {
}
}

private static void checkHashes(final String sha1Hash16, final String md5Hash16, final DbArtifactHash hash) {
if (hash == null) {
private static void checkHashes(final String sha1Hash16, final String md5Hash16, final String sha256Hash16,
final DbArtifactHash providedHashes) {
if (providedHashes == null) {
return;
}
if (hash.getSha1() != null && !sha1Hash16.equals(hash.getSha1())) {
throw new HashNotMatchException("The given sha1 hash " + hash.getSha1()
+ " does not match with the calcualted sha1 hash " + sha1Hash16, HashNotMatchException.SHA1);
if (areHashesNotMatching(providedHashes.getSha1(), sha1Hash16)) {
throw new HashNotMatchException("The given sha1 hash " + providedHashes.getSha1()
+ " does not match the calculated sha1 hash " + sha1Hash16, HashNotMatchException.SHA1);
}
if (hash.getMd5() != null && !md5Hash16.equals(hash.getMd5())) {
throw new HashNotMatchException(
"The given md5 hash " + hash.getMd5() + " does not match with the calcualted md5 hash " + md5Hash16,
HashNotMatchException.MD5);
if (areHashesNotMatching(providedHashes.getMd5(), md5Hash16)) {
throw new HashNotMatchException("The given md5 hash " + providedHashes.getMd5()
+ " does not match the calculated md5 hash " + md5Hash16, HashNotMatchException.MD5);
}
if (areHashesNotMatching(providedHashes.getSha256(), sha256Hash16)) {
throw new HashNotMatchException("The given sha256 hash " + providedHashes.getSha256()
+ " does not match the calculated sha256 hash " + sha256Hash16, HashNotMatchException.SHA256);
}
}

private static boolean areHashesNotMatching(String providedHashValue, String hashValue) {
return providedHashValue != null && !hashValue.equals(providedHashValue);
}

protected abstract AbstractDbArtifact store(final String tenant, final String sha1Hash16, final String mdMD5Hash16,
protected abstract AbstractDbArtifact store(final String tenant, final DbArtifactHash base16Hashes,
final String contentType, final String tempFile) throws IOException;

private static DigestInputStream wrapInDigestInputStream(final InputStream input, final MessageDigest mdSHA1,
final MessageDigest mdMD5) {
return new DigestInputStream(new DigestInputStream(input, mdMD5), mdSHA1);
final MessageDigest mdMD5, final MessageDigest mdSHA256) {
return new DigestInputStream(new DigestInputStream(new DigestInputStream(input, mdSHA256), mdMD5), mdSHA1);
}

protected static String sanitizeTenant(final String tenant) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public class HashNotMatchException extends RuntimeException {

public static final String SHA1 = "SHA-1";
public static final String MD5 = "MD5";
public static final String SHA256 = "SHA-256";

private final String hashFunction;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,22 @@ public class DbArtifactHash {

private final String md5;

private final String sha256;

/**
* Constructor.
*
* @param sha1
* the sha1 hash
* @param md5
* the md5 hash
* @param sha256
* the sha256 hash
*/
public DbArtifactHash(final String sha1, final String md5) {
public DbArtifactHash(final String sha1, final String md5, final String sha256) {
this.sha1 = sha1;
this.md5 = md5;
this.sha256 = sha256;
}

public String getSha1() {
Expand All @@ -39,4 +44,7 @@ public String getMd5() {
return md5;
}

public String getSha256() {
return sha256;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -167,14 +167,14 @@ public void testSendDownloadRequesWithSoftwareModulesAndNoArtifacts() {
}

@Test
@Description("Verifies that download and install event with software moduls and artifacts works")
@Description("Verifies that download and install event with software modules and artifacts works")
public void testSendDownloadRequest() {
DistributionSet dsA = testdataFactory.createDistributionSet(UUID.randomUUID().toString());
SoftwareModule module = dsA.getModules().iterator().next();
final List<AbstractDbArtifact> receivedList = new ArrayList<>();
for (final Artifact artifact : testdataFactory.createArtifacts(module.getId())) {
receivedList.add(new ArtifactFilesystem(new File("./test"), artifact.getSha1Hash(),
new DbArtifactHash(artifact.getSha1Hash(), null), artifact.getSize(), null));
new DbArtifactHash(artifact.getSha1Hash(), null, null), artifact.getSize(), null));
}
module = softwareModuleManagement.get(module.getId()).get();
dsA = distributionSetManagement.get(dsA.getId()).get();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ public interface Artifact extends TenantAwareBaseEntity {
*/
String getSha1Hash();

/**
* @return SHA-256 hash of the artifact.
*/
String getSha256Hash();

/**
* @return size of the artifact in bytes.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public class ArtifactUpload {

private final String providedSha1Sum;

private final String providedSha256Sum;

private final boolean overrideExisting;

private final String contentType;
Expand Down Expand Up @@ -90,6 +92,7 @@ public ArtifactUpload(final InputStream inputStream, final long moduleId, final
this.filename = filename;
this.providedMd5Sum = providedMd5Sum;
this.providedSha1Sum = providedSha1Sum;
this.providedSha256Sum = null;
this.overrideExisting = overrideExisting;
this.contentType = contentType;
this.filesize = filesize;
Expand All @@ -115,6 +118,10 @@ public String getProvidedSha1Sum() {
return providedSha1Sum;
}

public String getProvidedSha256Sum() {
return providedSha256Sum;
}

public boolean overrideExisting() {
return overrideExisting;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ private AbstractDbArtifact storeArtifact(final ArtifactUpload artifactUpload) {
try {
return artifactRepository.store(tenantAware.getCurrentTenant(), artifactUpload.getInputStream(),
artifactUpload.getFilename(), artifactUpload.getContentType(),
new DbArtifactHash(artifactUpload.getProvidedSha1Sum(), artifactUpload.getProvidedMd5Sum()));
new DbArtifactHash(artifactUpload.getProvidedSha1Sum(), artifactUpload.getProvidedMd5Sum(), artifactUpload.getProvidedSha256Sum()));
} catch (final ArtifactStoreException e) {
throw new ArtifactUploadFailedException(e);
} catch (final HashNotMatchException e) {
Expand Down Expand Up @@ -256,6 +256,7 @@ private Artifact storeArtifactMetadata(final SoftwareModule softwareModule, fina
artifact = new JpaArtifact(result.getHashes().getSha1(), providedFilename, softwareModule);
}
artifact.setMd5Hash(result.getHashes().getMd5());
artifact.setSha256Hash(result.getHashes().getSha256());
artifact.setSha1Hash(result.getHashes().getSha1());
artifact.setSize(result.getSize());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ public class JpaArtifact extends AbstractJpaTenantAwareBaseEntity implements Art
@Column(name = "md5_hash", length = 32, updatable = false, nullable = true)
private String md5Hash;

@Column(name = "sha256_hash", length = 64, updatable = false, nullable = true)
private String sha256Hash;

@Column(name = "file_size", updatable = false)
private long size;

Expand Down Expand Up @@ -94,6 +97,11 @@ public String getSha1Hash() {
return sha1Hash;
}

@Override
public String getSha256Hash() {
return sha256Hash;
}

public void setMd5Hash(final String md5Hash) {
this.md5Hash = md5Hash;
}
Expand All @@ -102,6 +110,11 @@ public void setSha1Hash(final String sha1Hash) {
this.sha1Hash = sha1Hash;
}

public void setSha256Hash(final String sha256Hash) {
this.sha256Hash = sha256Hash;
}


@Override
public long getSize() {
return size;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE sp_artifact ADD COLUMN sha256_hash CHAR(64);
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE sp_artifact ADD COLUMN sha256_hash CHAR(64);
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE sp_artifact ADD COLUMN sha256_hash CHAR(64);
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE sp_artifact ADD sha256_hash CHAR(64);
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ public void createArtifact() throws IOException {
.isEqualTo(HashGeneratorUtils.generateSHA1(randomBytes));
assertThat(artifactManagement.getByFilename("file1").get().getMd5Hash())
.isEqualTo(HashGeneratorUtils.generateMD5(randomBytes));
assertThat(artifactManagement.getByFilename("file1").get().getSha256Hash())
.isEqualTo(HashGeneratorUtils.generateSHA256(randomBytes));

assertThat(artifactRepository.findAll()).hasSize(4);
assertThat(softwareModuleRepository.findAll()).hasSize(3);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
*/
package org.eclipse.hawkbit.ddi.json.model;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;

/**
Expand All @@ -23,6 +25,10 @@ public class DdiArtifactHash {
@JsonProperty
private String md5;

@JsonProperty
@JsonInclude(Include.NON_NULL)
private String sha256;

/**
* Default constructor.
*/
Expand All @@ -34,11 +40,16 @@ public DdiArtifactHash() {
* Public constructor.
*
* @param sha1
* sha1 hash of the artifact
* @param md5
* md5 hash of the artifact
* @param sha256
* sha256 hash of the artifact
*/
public DdiArtifactHash(final String sha1, final String md5) {
public DdiArtifactHash(final String sha1, final String md5, final String sha256) {
this.sha1 = sha1;
this.md5 = md5;
this.sha256 = sha256;
}

/**
Expand All @@ -55,4 +66,10 @@ public String getMd5() {
return md5;
}

/**
* @return the sha256
*/
public String getSha256() {
return sha256;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ static List<DdiArtifact> createArtifacts(final Target target, final SoftwareModu
private static DdiArtifact createArtifact(final Target target, final ArtifactUrlHandler artifactUrlHandler,
final Artifact artifact, final SystemManagement systemManagement, final HttpRequest request) {
final DdiArtifact file = new DdiArtifact();
file.setHashes(new DdiArtifactHash(artifact.getSha1Hash(), artifact.getMd5Hash()));
file.setHashes(new DdiArtifactHash(artifact.getSha1Hash(), artifact.getMd5Hash(), artifact.getSha256Hash()));
file.setFilename(artifact.getFilename());
file.setSize(artifact.getSize());

Expand Down
Loading

0 comments on commit bde3548

Please sign in to comment.