Skip to content

Commit

Permalink
Merge pull request #1291 from wolf4ood/chore/more_iatp_tests
Browse files Browse the repository at this point in the history
chore: add more iatp tests
  • Loading branch information
wolf4ood authored May 8, 2024
2 parents cf1ac5d + fd92b43 commit 395bbe3
Show file tree
Hide file tree
Showing 2 changed files with 279 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
/********************************************************************************
* Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
*
* 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.edc.tests.transfer;

import jakarta.json.JsonObject;
import org.eclipse.edc.iam.did.spi.document.DidDocument;
import org.eclipse.edc.iam.did.spi.document.Service;
import org.eclipse.edc.iam.identitytrust.spi.model.PresentationResponseMessage;
import org.eclipse.edc.identityhub.spi.store.CredentialStore;
import org.eclipse.edc.identityhub.spi.verifiablecredentials.generator.VerifiablePresentationService;
import org.eclipse.edc.identityhub.spi.verifiablecredentials.model.VerifiableCredentialResource;
import org.eclipse.edc.jsonld.spi.JsonLd;
import org.eclipse.edc.junit.annotations.EndToEndTest;
import org.eclipse.edc.spi.EdcException;
import org.eclipse.edc.spi.query.QuerySpec;
import org.eclipse.edc.spi.result.Result;
import org.eclipse.edc.transform.spi.TypeTransformerRegistry;
import org.eclipse.tractusx.edc.tests.transfer.iatp.harness.IatpParticipant;
import org.eclipse.tractusx.edc.tests.transfer.iatp.runtime.IatpParticipantRuntime;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.mockserver.integration.ClientAndServer;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

import static org.eclipse.edc.util.io.Ports.getFreePort;
import static org.eclipse.tractusx.edc.tests.TestRuntimeConfiguration.BPN_SUFFIX;
import static org.eclipse.tractusx.edc.tests.helpers.PolicyHelperFunctions.bnpPolicy;
import static org.eclipse.tractusx.edc.tests.transfer.iatp.harness.IatpHelperFunctions.configureParticipant;
import static org.eclipse.tractusx.edc.tests.transfer.iatp.runtime.Runtimes.iatpRuntime;
import static org.eclipse.tractusx.edc.tests.transfer.iatp.runtime.Runtimes.stsRuntime;
import static org.hamcrest.Matchers.not;
import static org.mockserver.model.HttpRequest.request;
import static org.mockserver.model.HttpResponse.response;

@EndToEndTest
public class CredentialSpoofTest implements IatpParticipants {

public static final String MALICIOUS_ACTOR_NAME = "MALICIOUS";
public static final String MALICIOUS_ACTOR_BPN = MALICIOUS_ACTOR_NAME + BPN_SUFFIX;
protected static final IatpParticipant MALICIOUS_ACTOR = IatpParticipant.Builder.newInstance()
.name(MALICIOUS_ACTOR_NAME)
.id(MALICIOUS_ACTOR_BPN)
.stsUri(STS.stsUri())
.stsClientId(MALICIOUS_ACTOR_BPN)
.stsClientSecret("client_secret")
.trustedIssuer(DATASPACE_ISSUER_PARTICIPANT.didUrl())
.dimUri(DIM_URI)
.did(IatpParticipants.did(MALICIOUS_ACTOR_NAME))
.build();

@RegisterExtension
protected static final IatpParticipantRuntime MALICIOUS_ACTOR_RUNTIME = iatpRuntime(MALICIOUS_ACTOR.getName(), MALICIOUS_ACTOR.iatpConfiguration(PROVIDER, CONSUMER), MALICIOUS_ACTOR.getKeyPair());
@RegisterExtension
protected static final IatpParticipantRuntime CONSUMER_RUNTIME = iatpRuntime(CONSUMER.getName(), CONSUMER.iatpConfiguration(PROVIDER, MALICIOUS_ACTOR), CONSUMER.getKeyPair());
@RegisterExtension
protected static final IatpParticipantRuntime PROVIDER_RUNTIME = iatpRuntime(PROVIDER.getName(), PROVIDER.iatpConfiguration(CONSUMER, MALICIOUS_ACTOR), PROVIDER.getKeyPair());
@RegisterExtension
protected static final IatpParticipantRuntime STS_RUNTIME = stsRuntime(STS.getName(), STS.stsConfiguration(CONSUMER, PROVIDER, MALICIOUS_ACTOR), STS.getKeyPair());
private static final Integer MOCKED_CS_SERVICE_PORT = getFreePort();
protected ClientAndServer server;


@BeforeAll
static void prepare() {

// create the DIDs cache
var dids = new HashMap<String, DidDocument>();
dids.put(DATASPACE_ISSUER_PARTICIPANT.didUrl(), DATASPACE_ISSUER_PARTICIPANT.didDocument());
dids.put(CONSUMER.getDid(), CONSUMER.getDidDocument());
dids.put(PROVIDER.getDid(), PROVIDER.getDidDocument());
dids.put(MALICIOUS_ACTOR.getDid(), maliciousActorDidDocument(MALICIOUS_ACTOR.getDidDocument()));

configureParticipant(DATASPACE_ISSUER_PARTICIPANT, CONSUMER, CONSUMER_RUNTIME, dids, STS_RUNTIME);
configureParticipant(DATASPACE_ISSUER_PARTICIPANT, PROVIDER, PROVIDER_RUNTIME, dids, STS_RUNTIME);
configureParticipant(DATASPACE_ISSUER_PARTICIPANT, MALICIOUS_ACTOR, MALICIOUS_ACTOR_RUNTIME, dids, STS_RUNTIME);

}

private static DidDocument maliciousActorDidDocument(DidDocument didDocument) {
var service = new Service();
service.setId("#credential-service");
service.setType("CredentialService");
service.setServiceEndpoint("http://%s:%d".formatted("localhost", MOCKED_CS_SERVICE_PORT));
return DidDocument.Builder.newInstance()
.id(didDocument.getId())
.verificationMethod(didDocument.getVerificationMethod())
.service(List.of(service))
.build();
}

@BeforeEach
void setup() {
server = ClientAndServer.startClientAndServer("localhost", getFreePort(), MOCKED_CS_SERVICE_PORT);
}

@AfterEach
void shutdown() {
server.stop();
}

@Test
@DisplayName("Malicious actor should not impersonate a consumer by creating a VP with the consumer membership credential")
void shouldNotImpersonateConsumer_withWrappedConsumerCredential() {
var assetId = "api-asset-1";


Map<String, Object> dataAddress = Map.of(
"baseUrl", "http://mock",
"type", "HttpData",
"contentType", "application/json"
);

var presentationService = MALICIOUS_ACTOR_RUNTIME.getService(VerifiablePresentationService.class);

withMock((membershipCredential) -> presentationService.createPresentation(MALICIOUS_ACTOR.getDid(), List.of(membershipCredential.getVerifiableCredential()), null, PROVIDER.getDid()));

PROVIDER.createAsset(assetId, Map.of(), dataAddress);

var policy = createAccessPolicy(CONSUMER.getBpn());
var accessPolicyId = PROVIDER.createPolicyDefinition(policy);
var contractPolicyId = PROVIDER.createPolicyDefinition(policy);
PROVIDER.createContractDefinition(assetId, "def-1", accessPolicyId, contractPolicyId);

MALICIOUS_ACTOR.getCatalog(PROVIDER)
.log().ifError()
.statusCode(not(200));

}

@Test
@DisplayName("Malicious actor should not impersonate a consumer sending a valid consumer VP")
void shouldNotImpersonateConsumer_withConsumerPresentation() {
var assetId = "api-asset-1";


Map<String, Object> dataAddress = Map.of(
"baseUrl", "http://mock",
"type", "HttpData",
"contentType", "application/json"
);

var presentationService = CONSUMER_RUNTIME.getService(VerifiablePresentationService.class);

withMock((membershipCredential) -> presentationService.createPresentation(CONSUMER.getDid(), List.of(membershipCredential.getVerifiableCredential()), null, PROVIDER.getDid()));

PROVIDER.createAsset(assetId, Map.of(), dataAddress);

var policy = createAccessPolicy(CONSUMER.getBpn());
var accessPolicyId = PROVIDER.createPolicyDefinition(policy);
var contractPolicyId = PROVIDER.createPolicyDefinition(policy);
PROVIDER.createContractDefinition(assetId, "def-1", accessPolicyId, contractPolicyId);

MALICIOUS_ACTOR.getCatalog(PROVIDER)
.log().ifError()
.statusCode(not(200));

}

void withMock(Function<VerifiableCredentialResource, Result<PresentationResponseMessage>> response) {

var store = CONSUMER_RUNTIME.getService(CredentialStore.class);

var sokratesMembershipCredential = store.query(QuerySpec.max()).getContent()
.stream().filter(c -> c.getVerifiableCredential().credential().getType().contains("MembershipCredential"))
.findFirst()
.orElseThrow();

var transformerRegistry = MALICIOUS_ACTOR_RUNTIME.getService(TypeTransformerRegistry.class);
var jsonLd = MALICIOUS_ACTOR_RUNTIME.getService(JsonLd.class);


server.when(request().withMethod("POST").withPath("/presentations/query")).respond((request -> {
var json = response.apply(sokratesMembershipCredential)
.compose(presentation -> transformerRegistry.transform(presentation, JsonObject.class))
.compose(jsonLd::compact)
.orElseThrow(failure -> new EdcException(failure.getFailureDetail()));

return response().withStatusCode(200).withBody(json.toString());
}));
}

protected JsonObject createAccessPolicy(String bpn) {
return bnpPolicy(bpn);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/********************************************************************************
* Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
*
* 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.edc.tests.transfer;

import org.eclipse.tractusx.edc.tests.transfer.iatp.harness.DataspaceIssuer;
import org.eclipse.tractusx.edc.tests.transfer.iatp.harness.IatpParticipant;
import org.eclipse.tractusx.edc.tests.transfer.iatp.harness.StsParticipant;

import java.net.URI;

import static org.eclipse.edc.util.io.Ports.getFreePort;
import static org.eclipse.tractusx.edc.tests.TestRuntimeConfiguration.CONSUMER_BPN;
import static org.eclipse.tractusx.edc.tests.TestRuntimeConfiguration.CONSUMER_NAME;
import static org.eclipse.tractusx.edc.tests.TestRuntimeConfiguration.PROVIDER_BPN;
import static org.eclipse.tractusx.edc.tests.TestRuntimeConfiguration.PROVIDER_NAME;

public interface IatpParticipants {

URI DIM_URI = URI.create("http://localhost:" + getFreePort());
DataspaceIssuer DATASPACE_ISSUER_PARTICIPANT = new DataspaceIssuer();
StsParticipant STS = StsParticipant.Builder.newInstance()
.id("STS")
.name("STS")
.build();
IatpParticipant CONSUMER = IatpParticipant.Builder.newInstance()
.name(CONSUMER_NAME)
.id(CONSUMER_BPN)
.stsUri(STS.stsUri())
.stsClientId(CONSUMER_BPN)
.stsClientSecret("client_secret")
.trustedIssuer(DATASPACE_ISSUER_PARTICIPANT.didUrl())
.dimUri(DIM_URI)
.did(did(CONSUMER_NAME))
.build();

IatpParticipant PROVIDER = IatpParticipant.Builder.newInstance()
.name(PROVIDER_NAME)
.id(PROVIDER_BPN)
.stsUri(STS.stsUri())
.stsClientId(PROVIDER_BPN)
.stsClientSecret("client_secret")
.trustedIssuer(DATASPACE_ISSUER_PARTICIPANT.didUrl())
.dimUri(DIM_URI)
.did(did(PROVIDER_NAME))
.build();

static String did(String name) {
return "did:example:" + name.toLowerCase();
}

}

0 comments on commit 395bbe3

Please sign in to comment.