Skip to content

Commit

Permalink
Merge pull request #466 from catenax-ng/feature/TRI-1291-data-integri…
Browse files Browse the repository at this point in the history
…ty-testdata

Feature/tri 1291 data integrity testdata
  • Loading branch information
mkanal authored Aug 21, 2023
2 parents 8bdc933 + 6e8c653 commit d382f93
Show file tree
Hide file tree
Showing 23 changed files with 16,639 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .config/spotbugs-excludes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,9 @@
<Class name="org.eclipse.tractusx.irs.semanticshub.SemanticsHubClientImpl"/>
<Bug pattern="PATH_TRAVERSAL_IN,WEAK_FILENAMEUTILS"/>
</Match>
<Match>
<!-- The application is intended to access all files -->
<Class name="org.eclipse.tractusx.irs.testing.dataintegrity.TestdataTransformer"/>
<Bug pattern="PATH_TRAVERSAL_IN"/>
</Match>
</FindBugsFilter>
3 changes: 3 additions & 0 deletions DEPENDENCIES
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,11 @@ maven/mavencentral/org.apiguardian/apiguardian-api/1.1.2, Apache-2.0, approved,
maven/mavencentral/org.aspectj/aspectjweaver/1.9.19, EPL-1.0, approved, tools.aspectj
maven/mavencentral/org.assertj/assertj-core/3.24.2, Apache-2.0, approved, #6161
maven/mavencentral/org.bouncycastle/bcpkix-jdk18on/1.75, MIT, approved, #9166
maven/mavencentral/org.bouncycastle/bcpkix-jdk18on/1.76, MIT, approved, #9825
maven/mavencentral/org.bouncycastle/bcprov-jdk18on/1.75, MIT AND CC0-1.0, approved, #9167
maven/mavencentral/org.bouncycastle/bcprov-jdk18on/1.76, MIT AND CC0-1.0, approved, #9827
maven/mavencentral/org.bouncycastle/bcutil-jdk18on/1.75, MIT, approved, #9170
maven/mavencentral/org.bouncycastle/bcutil-jdk18on/1.76, MIT, approved, #9828
maven/mavencentral/org.checkerframework/checker-qual/3.33.0, MIT, approved, clearlydefined
maven/mavencentral/org.eclipse.edc/aggregate-service-spi/0.1.3, Apache-2.0, approved, technology.edc
maven/mavencentral/org.eclipse.edc/asset-spi/0.1.3, Apache-2.0, approved, technology.edc
Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ COPY irs-report-aggregate irs-report-aggregate
COPY irs-cucumber-tests irs-cucumber-tests
COPY docs docs
COPY irs-load-tests irs-load-tests
COPY irs-testdata-upload irs-testdata-upload

# the --mount option requires BuildKit.
RUN --mount=type=cache,target=/root/.m2 mvn -B clean package -pl :$BUILD_TARGET -am -DskipTests
Expand Down
87 changes: 87 additions & 0 deletions irs-testdata-upload/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.eclipse.tractusx.irs</groupId>
<artifactId>irs-parent-spring-boot</artifactId>
<version>${revision}</version>
<relativePath>../irs-parent-spring-boot</relativePath>
</parent>

<artifactId>irs-testdata-upload</artifactId>

<name>IRS Testdata Utilities</name>
<description>Item Relationship Service Testdata Utilities</description>

<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>1.76</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<version>1.76</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.javacrumbs.json-unit</groupId>
<artifactId>json-unit-assertj</artifactId>
<version>${json-unit-assertj.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>org.eclipse.tractusx.irs.testing.dataintegrity.TestdataTransformer</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/********************************************************************************
* Copyright (c) 2021,2022,2023
* 2022: ZF Friedrichshafen AG
* 2022: ISTOS GmbH
* 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
* 2022,2023: BOSCH AG
* Copyright (c) 2021,2022,2023 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://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.
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/
package org.eclipse.tractusx.irs.testing.dataintegrity;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.util.encoders.Hex;
import org.eclipse.tractusx.irs.testing.dataintegrity.models.IntegrityAspect;
import org.eclipse.tractusx.irs.testing.dataintegrity.models.IntegrityChildPart;
import org.eclipse.tractusx.irs.testing.dataintegrity.models.IntegrityReference;
import org.eclipse.tractusx.irs.testing.dataintegrity.models.SingleLevelBomAsBuiltPayload;
import org.eclipse.tractusx.irs.testing.dataintegrity.models.TestdataContainer;

/**
* Create and add a DataIntegrity AspectModels to a testdata set.
*/
@Slf4j
public class IntegrityAspectCreator {
public static final String SLBAB_IDENTIFIER = "urn:bamm:io.catenax.single_level_bom_as_built:1.0.0#SingleLevelBomAsBuilt";
public static final String DIL_IDENTIFIER = "urn:bamm:io.catenax.data_integrity:1.0.0#DataIntegrity";
public static final String CATENA_X_ID_IDENTIFIER = "catenaXId";
private final ObjectMapper objectMapper;
private final IntegritySigner integritySigner;

public IntegrityAspectCreator(final IntegritySigner integritySigner) {
this.integritySigner = integritySigner;
objectMapper = new ObjectMapper();
}

public String enrichTestdata(final String jsonData) throws IOException {
final TestdataContainer testdataContainer = objectMapper.readValue(jsonData, TestdataContainer.class);
final List<Map<String, Object>> testdata = testdataContainer.getContainer();

for (final Map<String, Object> digitalTwin : testdata) {
log.info("Building Integrity Aspect for '{}'", digitalTwin.get(CATENA_X_ID_IDENTIFIER));
addIntegrityAspect(digitalTwin, testdata);
}
return objectMapper.writeValueAsString(testdataContainer);
}

private String mapToString(final Object object) {
try {
return objectMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new IntegrityAspectException(e);
}
}

private <T> T readValue(final String data, final Class<T> type) {
try {
return objectMapper.readValue(data, type);
} catch (JsonProcessingException e) {
throw new IntegrityAspectException(e);
}
}

private void addIntegrityAspect(final Map<String, Object> digitalTwin, final List<Map<String, Object>> testdata) {
if (digitalTwin.containsKey(DIL_IDENTIFIER)) {
log.info("Integrity Aspect already present");
return;
}

if (digitalTwin.containsKey(SLBAB_IDENTIFIER)) {
final List<SingleLevelBomAsBuiltPayload> payloads = new ArrayList<>();
digitalTwin.entrySet()
.stream()
.filter(stringObjectEntry -> SLBAB_IDENTIFIER.equals(stringObjectEntry.getKey()))
.map(Map.Entry::getValue)
.map(this::mapToString)
.map(o -> readValue(o, SingleLevelBomAsBuiltPayload[].class))
.map(Arrays::asList)
.forEach(payloads::addAll);

if (!payloads.isEmpty()) {
final SingleLevelBomAsBuiltPayload singleLevelBomAsBuiltPayloads = payloads.stream()
.findFirst()
.orElseThrow();
singleLevelBomAsBuiltPayloads.getChildItems()
.stream()
.map(SingleLevelBomAsBuiltPayload.ChildData::getCatenaXId)
.map(id -> findDigitalTwinById(testdata, id))
.forEach(stringObjectMap -> addIntegrityAspect(stringObjectMap, testdata));

final List<IntegrityChildPart> integrityChildParts = new ArrayList<>();
singleLevelBomAsBuiltPayloads.getChildItems()
.stream()
.map(SingleLevelBomAsBuiltPayload.ChildData::getCatenaXId)
.map(id -> findDigitalTwinById(testdata, id))
.forEach(stringObjectMap -> {
final IntegrityChildPart integrityChildPart = createIntegrityChildPart(
stringObjectMap);
integrityChildParts.add(integrityChildPart);
});
final String cxId = (String) digitalTwin.get(CATENA_X_ID_IDENTIFIER);
final IntegrityAspect integrityAspect = new IntegrityAspect(cxId, integrityChildParts);
log.info("Adding integrity Aspect to Twin.");
digitalTwin.put(DIL_IDENTIFIER, List.of(integrityAspect));
}
}
}

private IntegrityChildPart createIntegrityChildPart(final Map<String, Object> childTwin) {
final List<IntegrityReference> references = new ArrayList<>();
final String cxId = (String) childTwin.get(CATENA_X_ID_IDENTIFIER);
log.info("Creating Integrity Part for ID: '{}'", cxId);
childTwin.entrySet()
.stream()
.filter(aspectModel -> !CATENA_X_ID_IDENTIFIER.equals(aspectModel.getKey()) && !"bpnl".equals(
aspectModel.getKey()))
.forEach(aspectModelEntry -> references.add(createIntegrityReference(aspectModelEntry)));
return new IntegrityChildPart(cxId, references);
}

protected IntegrityReference createIntegrityReference(final Map.Entry<String, Object> aspectModelEntry) {
final String aspectModel = mapToString(aspectModelEntry.getValue());
final Object[] strings = readValue(aspectModel, Object[].class);
try {
final byte[] payloadHash = integritySigner.hashString(mapToString(strings[0]));
final String payloadSignature = integritySigner.sign(payloadHash);
return new IntegrityReference(aspectModelEntry.getKey(), Hex.toHexString(payloadHash), payloadSignature);
} catch (CryptoException e) {
throw new IntegrityAspectException(e);
}
}

private Map<String, Object> findDigitalTwinById(final List<Map<String, Object>> testdata, final String catenaXId) {
for (final Map<String, Object> digitalTwin : testdata) {
final String twinCatenaXId = (String) digitalTwin.get(CATENA_X_ID_IDENTIFIER);
if (catenaXId.equals(twinCatenaXId)) {
return digitalTwin;
}
}
return Map.of();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/********************************************************************************
* Copyright (c) 2021,2022,2023
* 2022: ZF Friedrichshafen AG
* 2022: ISTOS GmbH
* 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
* 2022,2023: BOSCH AG
* Copyright (c) 2021,2022,2023 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://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.
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/
package org.eclipse.tractusx.irs.testing.dataintegrity;

/**
* Exception for IntegrityAspectCreator
*/
public class IntegrityAspectException extends RuntimeException {
public IntegrityAspectException(final Exception exception) {
super(exception);
}
public IntegrityAspectException(final String message) {
super(message);
}
public IntegrityAspectException(final String message, final Exception exception) {
super(message, exception);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/********************************************************************************
* Copyright (c) 2021,2022,2023
* 2022: ZF Friedrichshafen AG
* 2022: ISTOS GmbH
* 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
* 2022,2023: BOSCH AG
* Copyright (c) 2021,2022,2023 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://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.
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/
package org.eclipse.tractusx.irs.testing.dataintegrity;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;

import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.signers.RSADigestSigner;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

/**
* Utilities to hash, sign and verify data.
*/
public class IntegritySigner {
private final AsymmetricKeyParameter privKey;
private final AsymmetricKeyParameter publicKey;

public IntegritySigner(final AsymmetricKeyParameter privKey, final AsymmetricKeyParameter publicKey) {
Security.addProvider(new BouncyCastleProvider());
this.privKey = privKey;
this.publicKey = publicKey;
}

public byte[] hashString(final String data) {
final MessageDigest sha256Digest;
try {
sha256Digest = MessageDigest.getInstance("SHA3-256");

Check failure

Code scanning / CodeQL

Use of a potentially broken or risky cryptographic algorithm High test

Cryptographic algorithm
SHA3-256
may not be secure, consider using a different algorithm.
} catch (NoSuchAlgorithmException e) {
throw new IntegrityAspectException(e);
}
return sha256Digest.digest(data.getBytes(StandardCharsets.UTF_8));
}

public String sign(final byte[] hashedMessage) throws CryptoException {
final RSADigestSigner rsaDigestSigner = new RSADigestSigner(new SHA256Digest());
rsaDigestSigner.init(true, privKey);
rsaDigestSigner.update(hashedMessage, 0, hashedMessage.length);
final byte[] signature = rsaDigestSigner.generateSignature();
return Hex.toHexString(signature);
}

public boolean verify(final byte[] signature, final byte[] hashedMessage) {
final RSADigestSigner verifier = new RSADigestSigner(new SHA256Digest());
verifier.init(false, publicKey);
verifier.update(hashedMessage, 0, hashedMessage.length);
return verifier.verifySignature(signature);
}

}
Loading

0 comments on commit d382f93

Please sign in to comment.