Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(policy): #487

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
*
* 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
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
*
*/

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

import org.eclipse.edc.policy.engine.spi.PolicyEngine;
import org.eclipse.edc.policy.engine.spi.RuleBindingRegistry;
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
import org.eclipse.edc.spi.system.ServiceExtension;
import org.eclipse.edc.spi.system.ServiceExtensionContext;

import static org.eclipse.tractusx.edc.policy.cx.summary.SummaryConstraintFunctionsProvider.registerBindings;
import static org.eclipse.tractusx.edc.policy.cx.summary.SummaryConstraintFunctionsProvider.registerFunctions;

/**
* Provides implementations of standard CX usage policies.
*/
public class CxPolicyExtension implements ServiceExtension {
private static final String NAME = "CX Policy";

@Inject
private PolicyEngine policyEngine;

@Inject
private RuleBindingRegistry bindingRegistry;

@Override
public String name() {
return NAME;
}

@Override
public void initialize(ServiceExtensionContext context) {
registerFunctions(policyEngine);
registerBindings(bindingRegistry);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ public interface PolicyNamespaces {
String W3C_VC_NS = W3C_VC_PREFIX + "/v1";
String W3_VP_PROPERTY = W3C_VC_PREFIX + "/vp";

String TX_NS = "https://w3id.org/2023/catenax/credentials/";
String TX_SUMMARY_NS = TX_NS + "summary";
String TX_SUMMARY_NS_V1 = TX_SUMMARY_NS + "/v1";
String TX_USE_CASE_NS = TX_NS + "usecase";
String TX_USE_CASE_NS_V1 = TX_USE_CASE_NS + "/v1";
String CX_NS = "https://w3id.org/2023/catenax/credentials/";
String CX_SUMMARY_NS = CX_NS + "summary";
String CX_SUMMARY_NS_V1 = CX_SUMMARY_NS + "/v1";
String CX_USE_CASE_NS = CX_NS + "usecase";
String CX_USE_CASE_NS_V1 = CX_USE_CASE_NS + "/v1";

String TX_SUMMARY_CREDENTIAL = "SummaryCredential";
String CX_SUMMARY_CREDENTIAL = "SummaryCredential";

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import static org.eclipse.edc.policy.model.Operator.GT;
import static org.eclipse.tractusx.edc.policy.cx.common.JsonLdTypeFunctions.extractObjectsOfType;
import static org.eclipse.tractusx.edc.policy.cx.common.JsonLdValueFunctions.extractStringValue;
import static org.eclipse.tractusx.edc.policy.cx.common.PolicyNamespaces.TX_USE_CASE_NS;
import static org.eclipse.tractusx.edc.policy.cx.common.PolicyNamespaces.CX_USE_CASE_NS;
import static org.eclipse.tractusx.edc.policy.cx.common.PolicyNamespaces.W3_VP_PROPERTY;

/**
Expand All @@ -51,7 +51,7 @@
*/
public class FrameworkAgreementConstraintFunction extends AbstractVpConstraintFunction {
private static final String ACTIVE = "active";
public static final String CONTRACT_VERSION_PROPERTY = TX_USE_CASE_NS + "/contractVersion";
public static final String CONTRACT_VERSION_PROPERTY = CX_USE_CASE_NS + "/contractVersion";

private String agreementType;
private String agreementVersion;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@
* Verifies the presence of an entry in the {@link #SUMMARY_CREDENTIAL_ITEMS} of a summary credential token.
*/
public class SummaryConstraintFunction extends AbstractVpConstraintFunction {
private static final String SUMMARY_CREDENTIAL_TYPE = PolicyNamespaces.TX_SUMMARY_NS + "/SummaryCredential";
private static final String SUMMARY_CREDENTIAL_ITEMS = PolicyNamespaces.TX_SUMMARY_NS + "/items";
private static final String SUMMARY_CREDENTIAL_TYPE = PolicyNamespaces.CX_SUMMARY_NS + "/SummaryCredential";
private static final String SUMMARY_CREDENTIAL_ITEMS = PolicyNamespaces.CX_SUMMARY_NS + "/items";
private static final String CREDENTIAL_SUBJECT = "credentialSubject";

private static final String ACTIVE = "active";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package org.eclipse.tractusx.edc.policy.cx.summary;

import org.eclipse.edc.policy.engine.spi.PolicyEngine;
import org.eclipse.edc.policy.engine.spi.RuleBindingRegistry;
import org.eclipse.edc.policy.model.Permission;

import java.util.Map;
Expand All @@ -35,14 +36,14 @@ public class SummaryConstraintFunctionsProvider {
* Mappings from policy constraint left operand values to the corresponding item value in the summary VP.
*/
static final Map<String, String> CREDENTIAL_MAPPINGS = Map.of(
"Membership", "cx-active-member",
"Dismantler", "cx-dismantler",
"FrameworkAgreement.pcf", "cx-pcf",
"FrameworkAgreement.sustainability", "cx-sustainability",
"FrameworkAgreement.quality", "cx-quality",
"FrameworkAgreement.traceability", "cx-traceability",
"FrameworkAgreement.behavioraltwin", "cx-behavior-twin",
"BPN", "cx-bpn"
"Membership", "MembershipCredential",
"Dismantler", "DismantlerCredential",
"FrameworkAgreement.pcf", "PcfCredential",
"FrameworkAgreement.sustainability", "SustainabilityCredential",
"FrameworkAgreement.quality", "QualityCredential",
"FrameworkAgreement.traceability", "TraceabilityCredential",
"FrameworkAgreement.behavioraltwin", "BehaviorTwinCredential",
"BPN", "BpnCredential"
);

/**
Expand All @@ -54,24 +55,35 @@ public static void registerFunctions(PolicyEngine engine) {
engine.registerPreValidator(NEGOTIATION_REQUEST_SCOPE, tokenPolicyFunction);
engine.registerPreValidator(TRANSFER_PROCESS_REQUEST_SCOPE, tokenPolicyFunction);

CREDENTIAL_MAPPINGS.forEach((credentialName, summaryType) -> {
CREDENTIAL_MAPPINGS.forEach((constraintName, summaryType) -> {

engine.registerFunction(CATALOG_SCOPE,
Permission.class,
credentialName,
constraintName,
new SummaryConstraintFunction(summaryType));

engine.registerFunction(NEGOTIATION_SCOPE,
Permission.class,
credentialName,
constraintName,
new SummaryConstraintFunction(summaryType));

engine.registerFunction(TRANSFER_PROCESS_SCOPE,
Permission.class,
credentialName,
constraintName,
new SummaryConstraintFunction(summaryType));
});

}

public static void registerBindings(RuleBindingRegistry registry) {
CREDENTIAL_MAPPINGS.forEach((constraintName, summaryType) -> {
registry.bind(constraintName, CATALOG_REQUEST_SCOPE);
registry.bind(constraintName, NEGOTIATION_REQUEST_SCOPE);
registry.bind(constraintName, TRANSFER_PROCESS_REQUEST_SCOPE);
registry.bind(constraintName, CATALOG_SCOPE);
registry.bind(constraintName, NEGOTIATION_SCOPE);
registry.bind(constraintName, TRANSFER_PROCESS_SCOPE);
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.function.BiFunction;

import static java.lang.String.format;
import static org.eclipse.tractusx.edc.policy.cx.common.PolicyNamespaces.CX_SUMMARY_CREDENTIAL;

/**
* Includes a summary credential in the token parameters.
Expand All @@ -34,7 +35,7 @@ public Boolean apply(Policy policy, PolicyContext context) {
if (params == null) {
throw new EdcException(format("%s not set in policy context", TokenParameters.Builder.class.getName()));
}
// TODO set summary credential when we upgrade to the latest EDC snapshot
params.additional(CX_SUMMARY_CREDENTIAL, CX_SUMMARY_CREDENTIAL);
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#
# Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
#
# 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
#
# SPDX-License-Identifier: Apache-2.0
#
# Contributors:
# Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
#
#

org.eclipse.tractusx.edc.policy.cx.CxPolicyExtension

Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import static org.eclipse.edc.policy.model.Operator.EQ;
import static org.eclipse.edc.policy.model.Operator.GEQ;
import static org.eclipse.edc.policy.model.Operator.GT;
import static org.eclipse.tractusx.edc.policy.cx.common.PolicyNamespaces.TX_USE_CASE_NS_V1;
import static org.eclipse.tractusx.edc.policy.cx.common.PolicyNamespaces.CX_USE_CASE_NS_V1;
import static org.eclipse.tractusx.edc.policy.cx.common.PolicyNamespaces.W3_VP_PROPERTY;
import static org.eclipse.tractusx.edc.policy.cx.fixtures.JsonLdTextFixtures.createObjectMapper;
import static org.eclipse.tractusx.edc.policy.cx.fixtures.JsonLdTextFixtures.expand;
Expand All @@ -41,7 +41,7 @@
import static org.mockito.Mockito.when;

class FrameworkAgreementConstraintFunctionTest {
private static final Map<String, String> CONTEXT_CACHE = Map.of(TX_USE_CASE_NS_V1, USE_CASE_CONTEXT);
private static final Map<String, String> CONTEXT_CACHE = Map.of(CX_USE_CASE_NS_V1, USE_CASE_CONTEXT);
private Permission permission;
private PolicyContext context;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

import static org.assertj.core.api.Assertions.assertThat;
import static org.eclipse.edc.policy.model.Operator.EQ;
import static org.eclipse.tractusx.edc.policy.cx.common.PolicyNamespaces.TX_SUMMARY_NS_V1;
import static org.eclipse.tractusx.edc.policy.cx.common.PolicyNamespaces.CX_SUMMARY_NS_V1;
import static org.eclipse.tractusx.edc.policy.cx.common.PolicyNamespaces.W3_VP_PROPERTY;
import static org.eclipse.tractusx.edc.policy.cx.fixtures.JsonLdTextFixtures.createObjectMapper;
import static org.eclipse.tractusx.edc.policy.cx.fixtures.JsonLdTextFixtures.expand;
Expand All @@ -37,8 +37,8 @@
import static org.mockito.Mockito.when;

public class SummaryConstraintFunctionTest {
private static final Map<String, String> CONTEXT_CACHE = Map.of(TX_SUMMARY_NS_V1, SummaryContext.SUMMARY_CONTEXT);
public static final String CX_QUALITY = "cx-quality";
private static final Map<String, String> CONTEXT_CACHE = Map.of(CX_SUMMARY_NS_V1, SummaryContext.SUMMARY_CONTEXT);
public static final String CX_QUALITY = "QualityCredential";
private Permission permission;
private PolicyContext context;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package org.eclipse.tractusx.edc.policy.cx.summary;

import org.eclipse.edc.policy.engine.spi.PolicyEngine;
import org.eclipse.edc.policy.engine.spi.RuleBindingRegistry;
import org.eclipse.edc.policy.model.Permission;
import org.junit.jupiter.api.Test;

Expand All @@ -24,6 +25,7 @@
import static org.eclipse.tractusx.edc.policy.cx.common.PolicyScopes.NEGOTIATION_SCOPE;
import static org.eclipse.tractusx.edc.policy.cx.common.PolicyScopes.TRANSFER_PROCESS_REQUEST_SCOPE;
import static org.eclipse.tractusx.edc.policy.cx.common.PolicyScopes.TRANSFER_PROCESS_SCOPE;
import static org.eclipse.tractusx.edc.policy.cx.summary.SummaryConstraintFunctionsProvider.registerBindings;
import static org.eclipse.tractusx.edc.policy.cx.summary.SummaryConstraintFunctionsProvider.registerFunctions;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
Expand All @@ -34,7 +36,7 @@
class SummaryConstraintFunctionsProviderTest {

@Test
void verify_registrations() {
void verify_function_registrations() {
var policyEngine = mock(PolicyEngine.class);

registerFunctions(policyEngine);
Expand All @@ -48,7 +50,21 @@ void verify_registrations() {
assertSummaryFunctionsRegistered(NEGOTIATION_SCOPE, policyEngine, credentialName);
assertSummaryFunctionsRegistered(TRANSFER_PROCESS_SCOPE, policyEngine, credentialName);
});
}

@Test
void verify_binding_registrations() {
var bindingRegistry = mock(RuleBindingRegistry.class);

registerBindings(bindingRegistry);

assertRuleTypeRegistered("Membership", bindingRegistry);
assertRuleTypeRegistered("Dismantler", bindingRegistry);
assertRuleTypeRegistered("FrameworkAgreement.pcf", bindingRegistry);
assertRuleTypeRegistered("FrameworkAgreement.sustainability", bindingRegistry);
assertRuleTypeRegistered("FrameworkAgreement.quality", bindingRegistry);
assertRuleTypeRegistered("FrameworkAgreement.traceability", bindingRegistry);
assertRuleTypeRegistered("FrameworkAgreement.behavioraltwin", bindingRegistry);
}

private void assertTokenFunctionsRegistered(String scope, PolicyEngine policyEngine) {
Expand All @@ -63,4 +79,13 @@ private void assertSummaryFunctionsRegistered(String scope, PolicyEngine policyE
any(SummaryConstraintFunction.class));
}

private void assertRuleTypeRegistered(String ruleType, RuleBindingRegistry bindingRegistry) {
verify(bindingRegistry, times(1)).bind(ruleType, CATALOG_REQUEST_SCOPE);
verify(bindingRegistry, times(1)).bind(ruleType, CATALOG_SCOPE);
verify(bindingRegistry, times(1)).bind(ruleType, NEGOTIATION_REQUEST_SCOPE);
verify(bindingRegistry, times(1)).bind(ruleType, NEGOTIATION_SCOPE);
verify(bindingRegistry, times(1)).bind(ruleType, TRANSFER_PROCESS_REQUEST_SCOPE);
verify(bindingRegistry, times(1)).bind(ruleType, TRANSFER_PROCESS_SCOPE);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,16 @@ public interface SummaryCredential {
"type": "Summary-List",
"name": "CX-Credentials",
"items": [
"cx-active-member",
"cx-dismantler",
"cx-pcf",
"cx-sustainability",
"cx-quality",
"cx-traceability",
"cx-behavior-twin",
"cx-bpn"
"MembershipCredential",
"DismantlerCredential",
"PcfCredential",
"SustainabilityCredential",
"QualityCredential",
"TraceabilityCredential",
"BehaviorTwinCredential",
"BpnCredential"
],
"contract-templates": "https://public.catena-x.org/contracts/"
"contractTemplates": "https://public.catena-x.org/contracts/"
},
"proof": {
"type": "Ed25519Signature2018",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
*
* 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
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
*
*/

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

import org.eclipse.edc.policy.engine.spi.PolicyContext;
import org.eclipse.edc.policy.model.Policy;
import org.eclipse.edc.spi.iam.TokenParameters;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.eclipse.tractusx.edc.policy.cx.common.PolicyNamespaces.CX_SUMMARY_CREDENTIAL;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

class SummaryTokenPolicyFunctionTest {

@Test
void verify_add_credential() {
var function = new SummaryTokenPolicyFunction();

var context = mock(PolicyContext.class);
var builder = TokenParameters.Builder.newInstance().audience("aud");
when(context.getContextData(eq(TokenParameters.Builder.class))).thenReturn(builder);

var policy = Policy.Builder.newInstance().build();

function.apply(policy, context);

assertThat(builder.build().getAdditional().containsKey(CX_SUMMARY_CREDENTIAL)).isTrue();
}
}