Skip to content

Commit

Permalink
chore: fixes after more tests (#1207)
Browse files Browse the repository at this point in the history
* chore: fixes after more tests

* chore: deps file
  • Loading branch information
wolf4ood committed Apr 9, 2024
1 parent ea38686 commit bac9ea0
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 11 deletions.
6 changes: 3 additions & 3 deletions DEPENDENCIES
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,9 @@ maven/mavencentral/dev.failsafe/failsafe/3.3.2, Apache-2.0, approved, #9268
maven/mavencentral/info.picocli/picocli/4.7.5, Apache-2.0, approved, #4365
maven/mavencentral/io.github.classgraph/classgraph/4.8.154, MIT, approved, CQ22530
maven/mavencentral/io.github.classgraph/classgraph/4.8.165, MIT, approved, CQ22530
maven/mavencentral/io.micrometer/micrometer-commons/1.12.4, Apache-2.0 AND (Apache-2.0 AND MIT), approved, #11679
maven/mavencentral/io.micrometer/micrometer-core/1.12.4, Apache-2.0 AND (Apache-2.0 AND MIT), approved, #11678
maven/mavencentral/io.micrometer/micrometer-observation/1.12.4, Apache-2.0, approved, #11680
maven/mavencentral/io.micrometer/micrometer-commons/1.12.5, Apache-2.0 AND (Apache-2.0 AND MIT), approved, #11679
maven/mavencentral/io.micrometer/micrometer-core/1.12.5, Apache-2.0 AND (Apache-2.0 AND MIT), approved, #11678
maven/mavencentral/io.micrometer/micrometer-observation/1.12.5, Apache-2.0, approved, #11680
maven/mavencentral/io.netty/netty-buffer/4.1.100.Final, Apache-2.0, approved, CQ21842
maven/mavencentral/io.netty/netty-buffer/4.1.101.Final, Apache-2.0, approved, CQ21842
maven/mavencentral/io.netty/netty-buffer/4.1.108.Final, Apache-2.0, approved, CQ21842
Expand Down
2 changes: 2 additions & 0 deletions edc-controlplane/edc-controlplane-base/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ dependencies {

// needed for BPN validation
runtimeOnly(project(":edc-extensions:bpn-validation"))
// Credentials CX policies
runtimeOnly(project(":edc-extensions:cx-policy"))

// needed for IATP integration
runtimeOnly(project(":core:json-ld-core"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

package org.eclipse.tractusx.edc.policy.cx.common;

import org.eclipse.edc.iam.verifiablecredentials.spi.model.CredentialSubject;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.VerifiableCredential;
import org.eclipse.edc.policy.engine.spi.DynamicAtomicConstraintFunction;
import org.eclipse.edc.policy.engine.spi.PolicyContext;
Expand All @@ -29,6 +30,7 @@

import java.util.Collection;
import java.util.List;
import java.util.Optional;

/**
* This is a base class for dynamically bound Tractus-X constraint evaluation functions that implements some basic common functionality and defines some
Expand Down Expand Up @@ -77,4 +79,9 @@ protected Result<List<VerifiableCredential>> getCredentialList(ParticipantAgent
return Result.success(vcList);
}

protected Object getClaimOrDefault(CredentialSubject subject, String namespace, String property, Object def) {
return Optional.ofNullable(subject.getClaims().get(namespace + property))
.or(() -> Optional.ofNullable(subject.getClaims().get(property)))
.orElse(def);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@
*/
public class DismantlerCredentialConstraintFunction extends AbstractDynamicCredentialConstraintFunction {

public static final String ALLOWED_VEHICLE_BRANDS = CX_CREDENTIAL_NS + "allowedVehicleBrands";
public static final String ALLOWED_VEHICLE_BRANDS_LITERAL = "allowedVehicleBrands";
public static final String DISMANTLER_LITERAL = "Dismantler";
// allows to encode multiple values in a single string in the right-operand. Policies don't handle list-type right-operands well.
public static final String RIGHT_OPERAND_LIST_SEPARATOR = ",";
private static final String ALLOWED_ACTIVITIES = CX_CREDENTIAL_NS + "activityType";
private static final String ALLOWED_ACTIVITIES_LITERAL = "activityType";

@Override
public boolean evaluate(Object leftOperand, Operator operator, Object rightOperand, Permission permission, PolicyContext context) {
Expand Down Expand Up @@ -97,10 +97,10 @@ public boolean evaluate(Object leftOperand, Operator operator, Object rightOpera

} else if (leftOperand.equals(CX_POLICY_NS + DISMANTLER_LITERAL + ".activityType")) {
if (hasInvalidOperand(operator, rightOperand, context)) return false;
predicate = predicate.and(getCredentialPredicate(ALLOWED_ACTIVITIES, operator, rightOperand));
predicate = predicate.and(getCredentialPredicate(ALLOWED_ACTIVITIES_LITERAL, operator, rightOperand));
} else if (leftOperand.equals(CX_POLICY_NS + DISMANTLER_LITERAL + ".allowedBrands")) {
if (hasInvalidOperand(operator, rightOperand, context)) return false;
predicate = predicate.and(getCredentialPredicate(ALLOWED_VEHICLE_BRANDS, operator, rightOperand));
predicate = predicate.and(getCredentialPredicate(ALLOWED_VEHICLE_BRANDS_LITERAL, operator, rightOperand));
} else {
context.reportProblem("Invalid left-operand: must be 'Dismantler[.activityType | .allowedBrands ], but was '%s'".formatted(leftOperand));
return false;
Expand Down Expand Up @@ -129,7 +129,7 @@ private Predicate<VerifiableCredential> getCredentialPredicate(String credential
var allowedValues = getList(rightOperand);
// the filter predicate is determined by the operator
return credential -> credential.getCredentialSubject().stream().anyMatch(subject -> {
var claimsFromCredential = getList(subject.getClaims().getOrDefault(credentialSubjectProperty, List.of()));
var claimsFromCredential = getList(getClaimOrDefault(subject, CX_CREDENTIAL_NS, credentialSubjectProperty, List.of()));
return switch (operator) {
case EQ -> claimsFromCredential.equals(allowedValues);
case NEQ -> !claimsFromCredential.equals(allowedValues);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
* credential that satisfies the {@code subtype} requirement.
*/
public class FrameworkAgreementCredentialConstraintFunction extends AbstractDynamicCredentialConstraintFunction {
public static final String CONTRACT_VERSION_PROPERTY = CX_CREDENTIAL_NS + "contractVersion";
public static final String CONTRACT_VERSION_LITERAL = "contractVersion";
public static final String FRAMEWORK_AGREEMENT_LITERAL = "FrameworkAgreement";

/**
Expand Down Expand Up @@ -176,7 +176,7 @@ private List<Predicate<VerifiableCredential>> createPredicates(String subtype, @
list.add(new CredentialTypePredicate(CX_CREDENTIAL_NS, capitalize(subtype) + CREDENTIAL_LITERAL));

if (version != null) {
list.add(credential -> credential.getCredentialSubject().stream().anyMatch(cs -> version.equals(cs.getClaims().getOrDefault(CONTRACT_VERSION_PROPERTY, null))));
list.add(credential -> credential.getCredentialSubject().stream().anyMatch(cs -> version.equals(getClaimOrDefault(cs, CX_CREDENTIAL_NS, CONTRACT_VERSION_LITERAL, null))));
}
return list;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,53 @@ public static VerifiableCredential.Builder createCredential(String type, String
.build());
}

public static VerifiableCredential.Builder createPlainFrameworkCredential(String type, String version) {
return VerifiableCredential.Builder.newInstance()
.types(List.of("VerifiableCredential", type))
.id(UUID.randomUUID().toString())
.issuer(new Issuer(UUID.randomUUID().toString(), Map.of("prop1", "val1")))
.expirationDate(Instant.now().plus(365, ChronoUnit.DAYS))
.issuanceDate(Instant.now())
.credentialSubject(CredentialSubject.Builder.newInstance()
.id("subject-id")
.claim("holderIdentifier", "did:web:holder")
.claim("contractVersion", version)
.claim("contractTemplate", "https://public.catena-x.org/contracts/pcf.v1.pdf")
.build());
}

public static VerifiableCredential.Builder createPcfCredential() {
return createCredential("PcfCredential", "1.0.0");
}

public static VerifiableCredential.Builder createPlainPcfCredential() {
return createPlainFrameworkCredential("PcfCredential", "1.0.0");
}

public static VerifiableCredential.Builder createDismantlerCredential(String... brands) {
return createDismantlerCredential(Arrays.asList(brands), "vehicleDismantle");
}

public static VerifiableCredential.Builder createPlainDismantlerCredential(String... brands) {
return createPlainDismantlerCredential(Arrays.asList(brands), "vehicleDismantle");
}

public static VerifiableCredential.Builder createPlainDismantlerCredential(Collection<String> brands, String... activityType) {
var at = activityType.length == 1 ? activityType[0] : List.of(activityType);
return VerifiableCredential.Builder.newInstance()
.types(List.of("VerifiableCredential", "DismantlerCredential"))
.id(UUID.randomUUID().toString())
.issuer(new Issuer(UUID.randomUUID().toString(), Map.of("prop1", "val1")))
.expirationDate(Instant.now().plus(365, ChronoUnit.DAYS))
.issuanceDate(Instant.now())
.credentialSubject(CredentialSubject.Builder.newInstance()
.id("subject-id")
.claim("holderIdentifier", "did:web:holder")
.claim("allowedVehicleBrands", brands)
.claim("activityType", at)
.build());
}

public static VerifiableCredential.Builder createDismantlerCredential(Collection<String> brands, String... activityType) {
var at = activityType.length == 1 ? activityType[0] : List.of(activityType);
return VerifiableCredential.Builder.newInstance()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import static org.eclipse.tractusx.edc.edr.spi.CoreConstants.CX_POLICY_NS;
import static org.eclipse.tractusx.edc.policy.cx.CredentialFunctions.createDismantlerCredential;
import static org.eclipse.tractusx.edc.policy.cx.CredentialFunctions.createPcfCredential;
import static org.eclipse.tractusx.edc.policy.cx.CredentialFunctions.createPlainDismantlerCredential;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.startsWith;
Expand Down Expand Up @@ -101,6 +102,12 @@ void evaluate_eq_satisfied() {
assertThat(function.evaluate(CX_POLICY_NS + "Dismantler", Operator.EQ, "active", null, context)).isTrue();
}

@Test
void evaluate_eq_withoutNamespace() {
when(participantAgent.getClaims()).thenReturn(Map.of("vc", List.of(createDismantlerCredential("Tatra", "Moskvich").build())));
assertThat(function.evaluate(CX_POLICY_NS + "Dismantler", Operator.EQ, "active", null, context)).isTrue();
}

@Test
void evaluate_eq_notSatisfied() {
when(participantAgent.getClaims()).thenReturn(Map.of("vc", List.of(createPcfCredential().build())));
Expand Down Expand Up @@ -148,6 +155,13 @@ void evaluate_eq_list() {
assertThat(function.evaluate(CX_POLICY_NS + "Dismantler.allowedBrands", Operator.EQ, List.of("Tatra", "Moskvich"), null, context)).isTrue();
}

@DisplayName("Constraint (list) must match credential EXACTLY")
@Test
void evaluate_eq_list_withoutNamespace() {
when(participantAgent.getClaims()).thenReturn(Map.of("vc", List.of(createPlainDismantlerCredential("Tatra", "Moskvich").build())));
assertThat(function.evaluate(CX_POLICY_NS + "Dismantler.allowedBrands", Operator.EQ, List.of("Tatra", "Moskvich"), null, context)).isTrue();
}

@DisplayName("Constraint (list) must credential EXACTLY - failure")
@Test
void evaluate_eq_list_notSatisfied() {
Expand Down Expand Up @@ -299,6 +313,13 @@ void evaluate_eq_list() {
assertThat(function.evaluate(CX_POLICY_NS + "Dismantler.activityType", Operator.EQ, List.of("vehicleDismantle", "vehicleScrap"), null, context)).isTrue();
}

@DisplayName("Constraint (list) must match credential EXACTLY")
@Test
void evaluate_eq_list_withoutNamespace() {
when(participantAgent.getClaims()).thenReturn(Map.of("vc", List.of(createPlainDismantlerCredential(brands, "vehicleDismantle", "vehicleScrap").build())));
assertThat(function.evaluate(CX_POLICY_NS + "Dismantler.activityType", Operator.EQ, List.of("vehicleDismantle", "vehicleScrap"), null, context)).isTrue();
}

@DisplayName("Constraint (list) must credential EXACTLY - failure")
@Test
void evaluate_eq_list_notSatisfied() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import static org.eclipse.tractusx.edc.edr.spi.CoreConstants.CX_POLICY_NS;
import static org.eclipse.tractusx.edc.policy.cx.CredentialFunctions.createCredential;
import static org.eclipse.tractusx.edc.policy.cx.CredentialFunctions.createPcfCredential;
import static org.eclipse.tractusx.edc.policy.cx.CredentialFunctions.createPlainPcfCredential;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.startsWith;
import static org.mockito.Mockito.mock;
Expand Down Expand Up @@ -284,6 +285,15 @@ void evaluate_rightOperand_withVersion() {
assertThat(function.evaluate(CX_POLICY_NS + "FrameworkAgreement", Operator.EQ, "pcf:4.2.0", permission, context)).isFalse();
}

@Test
void evaluate_withoutNamespace() {
when(participantAgent.getClaims()).thenReturn(Map.of(
"vc", List.of(createPlainPcfCredential().build())
));
assertThat(function.evaluate(CX_POLICY_NS + "FrameworkAgreement", Operator.EQ, "pcf:1.0.0", permission, context)).isTrue();
assertThat(function.evaluate(CX_POLICY_NS + "FrameworkAgreement", Operator.EQ, "pcf:4.2.0", permission, context)).isFalse();
}

@Test
void evaluate_rightOperandMissesSubtype() {
when(participantAgent.getClaims()).thenReturn(Map.of(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,6 @@ private String extractCredentialType(String leftOperand, Object rightValue) {
}

private String capitalize(String input) {
return input.substring(0, 1).toUpperCase() + input.substring(1).toLowerCase();
return input.substring(0, 1).toUpperCase() + input.substring(1);
}
}

0 comments on commit bac9ea0

Please sign in to comment.