-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1291 from wolf4ood/chore/more_iatp_tests
chore: add more iatp tests
- Loading branch information
Showing
2 changed files
with
279 additions
and
0 deletions.
There are no files selected for viewing
211 changes: 211 additions & 0 deletions
211
...iatp-tests/src/test/java/org/eclipse/tractusx/edc/tests/transfer/CredentialSpoofTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
|
||
} |
68 changes: 68 additions & 0 deletions
68
...ne/iatp-tests/src/test/java/org/eclipse/tractusx/edc/tests/transfer/IatpParticipants.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
|
||
} |