Skip to content

Commit

Permalink
fix: use new type-based Policy evaluation framework
Browse files Browse the repository at this point in the history
  • Loading branch information
paullatzelsperger committed Oct 18, 2024
1 parent 4f97137 commit dbe55d8
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 41 deletions.
1 change: 1 addition & 0 deletions extensions/dcp-impl/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ dependencies {
implementation(libs.edc.dcp.core)
implementation(libs.edc.spi.identity.trust)
implementation(libs.edc.spi.transform)
implementation(libs.edc.spi.catalog)
implementation(libs.edc.spi.identity.did)
implementation(libs.edc.lib.jws2020)
implementation(libs.edc.lib.transform)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@

package org.eclipse.edc.demo.dcp.core;

import org.eclipse.edc.iam.identitytrust.core.DcpScopeExtractorExtension;
import org.eclipse.edc.connector.controlplane.catalog.spi.policy.CatalogPolicyContext;
import org.eclipse.edc.iam.identitytrust.spi.scope.ScopeExtractorRegistry;
import org.eclipse.edc.iam.identitytrust.spi.verification.SignatureSuiteRegistry;
import org.eclipse.edc.iam.verifiablecredentials.spi.VcConstants;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.Issuer;
import org.eclipse.edc.iam.verifiablecredentials.spi.validation.TrustedIssuerRegistry;
import org.eclipse.edc.policy.context.request.spi.RequestCatalogPolicyContext;
import org.eclipse.edc.policy.context.request.spi.RequestContractNegotiationPolicyContext;
import org.eclipse.edc.policy.context.request.spi.RequestTransferProcessPolicyContext;
import org.eclipse.edc.policy.engine.spi.PolicyEngine;
import org.eclipse.edc.policy.engine.spi.PolicyValidatorRule;
import org.eclipse.edc.policy.model.Policy;
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
import org.eclipse.edc.security.signature.jws2020.Jws2020SignatureSuite;
import org.eclipse.edc.spi.system.ServiceExtension;
Expand Down Expand Up @@ -64,11 +69,11 @@ public void initialize(ServiceExtensionContext context) {
trustedIssuerRegistry.register(new Issuer("did:example:dataspace-issuer", Map.of()), WILDCARD);

// register a default scope provider
var contextMappingFunction = new DefaultScopeMappingFunction(Set.of(
"org.eclipse.edc.vc.type:MembershipCredential:read"));
policyEngine.registerPostValidator(DcpScopeExtractorExtension.CATALOG_REQUEST_SCOPE, contextMappingFunction);
policyEngine.registerPostValidator(DcpScopeExtractorExtension.NEGOTIATION_REQUEST_SCOPE, contextMappingFunction);
policyEngine.registerPostValidator(DcpScopeExtractorExtension.TRANSFER_PROCESS_REQUEST_SCOPE, contextMappingFunction);
var contextMappingFunction = new DefaultScopeMappingFunction(Set.of("org.eclipse.edc.vc.type:MembershipCredential:read"));

policyEngine.registerPostValidator(RequestCatalogPolicyContext.class, contextMappingFunction::apply);
policyEngine.registerPostValidator(RequestContractNegotiationPolicyContext.class, contextMappingFunction::apply);
policyEngine.registerPostValidator(RequestTransferProcessPolicyContext.class, contextMappingFunction::apply);


//register scope extractor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@

package org.eclipse.edc.demo.dcp.core;

import org.eclipse.edc.policy.context.request.spi.RequestPolicyContext;
import org.eclipse.edc.policy.engine.spi.PolicyContext;
import org.eclipse.edc.policy.engine.spi.PolicyValidatorRule;
import org.eclipse.edc.policy.model.Policy;
import org.eclipse.edc.spi.EdcException;
import org.eclipse.edc.spi.iam.RequestScope;
Expand All @@ -23,19 +25,16 @@
import java.util.Set;
import java.util.function.BiFunction;

public class DefaultScopeMappingFunction implements BiFunction<Policy, PolicyContext, Boolean> {
public class DefaultScopeMappingFunction implements PolicyValidatorRule<RequestPolicyContext> {
private final Set<String> defaultScopes;

public DefaultScopeMappingFunction(Set<String> defaultScopes) {
this.defaultScopes = defaultScopes;
}

@Override
public Boolean apply(Policy policy, PolicyContext policyContext) {
var requestScopeBuilder = policyContext.getContextData(RequestScope.Builder.class);
if (requestScopeBuilder == null) {
throw new EdcException("%s not set in policy context".formatted(RequestScope.Builder.class));
}
public Boolean apply(Policy policy, RequestPolicyContext requestPolicyContext) {
var requestScopeBuilder = requestPolicyContext.requestScopeBuilder();
var rq = requestScopeBuilder.build();
var existingScope = rq.getScopes();
var newScopes = new HashSet<>(defaultScopes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@

package org.eclipse.edc.demo.dcp.policy;

import org.eclipse.edc.policy.engine.spi.AtomicConstraintFunction;
import org.eclipse.edc.connector.controlplane.catalog.spi.policy.CatalogPolicyContext;
import org.eclipse.edc.connector.controlplane.contract.spi.policy.ContractNegotiationPolicyContext;
import org.eclipse.edc.connector.controlplane.contract.spi.policy.TransferProcessPolicyContext;
import org.eclipse.edc.policy.engine.spi.AtomicConstraintRuleFunction;
import org.eclipse.edc.policy.engine.spi.PolicyContext;
import org.eclipse.edc.policy.model.Duty;
import org.eclipse.edc.policy.model.Operator;
Expand All @@ -23,17 +26,44 @@
import java.util.Map;
import java.util.Objects;

public class DataAccessLevelFunction extends AbstractCredentialEvaluationFunction implements AtomicConstraintFunction<Duty> {
public abstract class DataAccessLevelFunction<C extends PolicyContext> extends AbstractCredentialEvaluationFunction implements AtomicConstraintRuleFunction<Duty, C> {

private static final String DATAPROCESSOR_CRED_TYPE = "DataProcessorCredential";

public static DataAccessLevelFunction<TransferProcessPolicyContext> createForTransferProcess() {
return new DataAccessLevelFunction<>() {
@Override
protected ParticipantAgent getAgent(TransferProcessPolicyContext policyContext) {
return policyContext.agent();
}
};
}

public static DataAccessLevelFunction<ContractNegotiationPolicyContext> createForNegotiation() {
return new DataAccessLevelFunction<>() {
@Override
protected ParticipantAgent getAgent(ContractNegotiationPolicyContext policyContext) {
return policyContext.agent();
}
};
}

public static DataAccessLevelFunction<CatalogPolicyContext> createForCatalog() {
return new DataAccessLevelFunction<>() {
@Override
protected ParticipantAgent getAgent(CatalogPolicyContext policyContext) {
return policyContext.agent();
}
};
}

@Override
public boolean evaluate(Operator operator, Object rightOperand, Duty duty, PolicyContext policyContext) {
public boolean evaluate(Operator operator, Object rightOperand, Duty duty, C policyContext) {
if (!operator.equals(Operator.EQ)) {
policyContext.reportProblem("Cannot evaluate operator %s, only %s is supported".formatted(operator, Operator.EQ));
return false;
}
var pa = policyContext.getContextData(ParticipantAgent.class);
var pa = getAgent(policyContext);
if (pa == null) {
policyContext.reportProblem("ParticipantAgent not found on PolicyContext");
return false;
Expand All @@ -56,18 +86,24 @@ public boolean evaluate(Operator operator, Object rightOperand, Duty duty, Polic
return version != null && Objects.equals(level, rightOperand);
});


}

public String key() {
return "DataAccess.level";
}

protected abstract ParticipantAgent getAgent(C policyContext);

@SuppressWarnings("unchecked")
private <T> T getClaim(String postfix, Map<String, Object> claims) {
return (T) claims.entrySet().stream().filter(e -> e.getKey().endsWith(postfix))
.findFirst()
.map(Map.Entry::getValue)
.orElse(null);
}

private static class ForCatalog extends DataAccessLevelFunction<CatalogPolicyContext> {

@Override
protected ParticipantAgent getAgent(CatalogPolicyContext policyContext) {
return policyContext.agent();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@

package org.eclipse.edc.demo.dcp.policy;

import org.eclipse.edc.policy.engine.spi.AtomicConstraintFunction;
import org.eclipse.edc.connector.controlplane.catalog.spi.policy.CatalogPolicyContext;
import org.eclipse.edc.connector.controlplane.contract.spi.policy.ContractNegotiationPolicyContext;
import org.eclipse.edc.connector.controlplane.contract.spi.policy.TransferProcessPolicyContext;
import org.eclipse.edc.policy.engine.spi.AtomicConstraintRuleFunction;
import org.eclipse.edc.policy.engine.spi.PolicyContext;
import org.eclipse.edc.policy.model.Operator;
import org.eclipse.edc.policy.model.Permission;
Expand All @@ -23,16 +26,46 @@
import java.time.Instant;
import java.util.Map;

public class MembershipCredentialEvaluationFunction extends AbstractCredentialEvaluationFunction implements AtomicConstraintFunction<Permission> {
public abstract class MembershipCredentialEvaluationFunction<C extends PolicyContext> extends AbstractCredentialEvaluationFunction implements AtomicConstraintRuleFunction<Permission, C> {
public static final String MEMBERSHIP_CONSTRAINT_KEY = "MembershipCredential";

private static final String MEMBERSHIP_CLAIM = "membership";
private static final String SINCE_CLAIM = "since";
private static final String ACTIVE = "active";

public static MembershipCredentialEvaluationFunction<CatalogPolicyContext> createForCatalog() {
return new MembershipCredentialEvaluationFunction<>() {

@Override
protected ParticipantAgent getAgent(CatalogPolicyContext policyContext) {
return policyContext.agent();
}
};
}

public static MembershipCredentialEvaluationFunction<TransferProcessPolicyContext> createForTransfer() {
return new MembershipCredentialEvaluationFunction<>() {

@Override
protected ParticipantAgent getAgent(TransferProcessPolicyContext policyContext) {
return policyContext.agent();
}
};
}

public static MembershipCredentialEvaluationFunction<ContractNegotiationPolicyContext> createForNegotiation() {
return new MembershipCredentialEvaluationFunction<>() {

@Override
protected ParticipantAgent getAgent(ContractNegotiationPolicyContext policyContext) {
return policyContext.agent();
}
};
}

@SuppressWarnings("unchecked")
@Override
public boolean evaluate(Operator operator, Object rightOperand, Permission permission, PolicyContext policyContext) {
public boolean evaluate(Operator operator, Object rightOperand, Permission permission, C policyContext) {
if (!operator.equals(Operator.EQ)) {
policyContext.reportProblem("Invalid operator '%s', only accepts '%s'".formatted(operator, Operator.EQ));
return false;
Expand All @@ -42,7 +75,7 @@ public boolean evaluate(Operator operator, Object rightOperand, Permission permi
return false;
}

var pa = policyContext.getContextData(ParticipantAgent.class);
var pa = getAgent(policyContext);
if (pa == null) {
policyContext.reportProblem("No ParticipantAgent found on context.");
return false;
Expand All @@ -63,4 +96,7 @@ public boolean evaluate(Operator operator, Object rightOperand, Permission permi
return membershipStartDate.isBefore(Instant.now());
});
}

protected abstract ParticipantAgent getAgent(C policyContext);

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@

package org.eclipse.edc.demo.dcp.policy;

import org.eclipse.edc.policy.engine.spi.AtomicConstraintFunction;
import org.eclipse.edc.connector.controlplane.catalog.spi.policy.CatalogPolicyContext;
import org.eclipse.edc.connector.controlplane.contract.spi.policy.ContractNegotiationPolicyContext;
import org.eclipse.edc.connector.controlplane.contract.spi.policy.TransferProcessPolicyContext;
import org.eclipse.edc.policy.engine.spi.AtomicConstraintRuleFunction;
import org.eclipse.edc.policy.engine.spi.PolicyContext;
import org.eclipse.edc.policy.engine.spi.PolicyEngine;
import org.eclipse.edc.policy.engine.spi.RuleBindingRegistry;
import org.eclipse.edc.policy.model.Duty;
Expand All @@ -24,9 +28,6 @@
import org.eclipse.edc.spi.system.ServiceExtensionContext;

import static org.eclipse.edc.demo.dcp.policy.MembershipCredentialEvaluationFunction.MEMBERSHIP_CONSTRAINT_KEY;
import static org.eclipse.edc.demo.dcp.policy.PolicyScopes.CATALOG_SCOPE;
import static org.eclipse.edc.demo.dcp.policy.PolicyScopes.NEGOTIATION_SCOPE;
import static org.eclipse.edc.demo.dcp.policy.PolicyScopes.TRANSFER_PROCESS_SCOPE;
import static org.eclipse.edc.policy.model.OdrlNamespace.ODRL_SCHEMA;

public class PolicyEvaluationExtension implements ServiceExtension {
Expand All @@ -39,38 +40,37 @@ public class PolicyEvaluationExtension implements ServiceExtension {

@Override
public void initialize(ServiceExtensionContext context) {
var fct = new MembershipCredentialEvaluationFunction();

bindPermissionFunction(fct, TRANSFER_PROCESS_SCOPE, MEMBERSHIP_CONSTRAINT_KEY);
bindPermissionFunction(fct, NEGOTIATION_SCOPE, MEMBERSHIP_CONSTRAINT_KEY);
bindPermissionFunction(fct, CATALOG_SCOPE, MEMBERSHIP_CONSTRAINT_KEY);

bindPermissionFunction(MembershipCredentialEvaluationFunction.createForTransfer(), TransferProcessPolicyContext.class, TransferProcessPolicyContext.TRANSFER_SCOPE, MEMBERSHIP_CONSTRAINT_KEY);
bindPermissionFunction(MembershipCredentialEvaluationFunction.createForNegotiation(), ContractNegotiationPolicyContext.class, ContractNegotiationPolicyContext.NEGOTIATION_SCOPE, MEMBERSHIP_CONSTRAINT_KEY);
bindPermissionFunction(MembershipCredentialEvaluationFunction.createForCatalog(), CatalogPolicyContext.class, CatalogPolicyContext.CATALOG_SCOPE, MEMBERSHIP_CONSTRAINT_KEY);

registerDataAccessLevelFunction();

}

private void registerDataAccessLevelFunction() {
var function = new DataAccessLevelFunction();
var accessLevelKey = function.key();
var accessLevelKey = "DataAccess.level";

bindDutyFunction(function, TRANSFER_PROCESS_SCOPE, accessLevelKey);
bindDutyFunction(function, NEGOTIATION_SCOPE, accessLevelKey);
bindDutyFunction(function, CATALOG_SCOPE, accessLevelKey);
bindDutyFunction(DataAccessLevelFunction.createForTransferProcess(), TransferProcessPolicyContext.class, TransferProcessPolicyContext.TRANSFER_SCOPE, accessLevelKey);
bindDutyFunction(DataAccessLevelFunction.createForNegotiation(), ContractNegotiationPolicyContext.class, ContractNegotiationPolicyContext.NEGOTIATION_SCOPE, accessLevelKey);
bindDutyFunction(DataAccessLevelFunction.createForCatalog(), CatalogPolicyContext.class, CatalogPolicyContext.CATALOG_SCOPE, accessLevelKey);
}

private void bindPermissionFunction(AtomicConstraintFunction<Permission> function, String scope, String constraintType) {
private <C extends PolicyContext> void bindPermissionFunction(AtomicConstraintRuleFunction<Permission, C> function, Class<C> contextClass, String scope, String constraintType) {
ruleBindingRegistry.bind("use", scope);
ruleBindingRegistry.bind(ODRL_SCHEMA + "use", scope);
ruleBindingRegistry.bind(constraintType, scope);

policyEngine.registerFunction(scope, Permission.class, constraintType, function);
policyEngine.registerFunction(contextClass, Permission.class, constraintType, function);
}

private void bindDutyFunction(AtomicConstraintFunction<Duty> function, String scope, String constraintType) {
private <C extends PolicyContext> void bindDutyFunction(AtomicConstraintRuleFunction<Duty, C> function, Class<C> contextClass, String scope, String constraintType) {
ruleBindingRegistry.bind("use", scope);
ruleBindingRegistry.bind(ODRL_SCHEMA + "use", scope);
ruleBindingRegistry.bind(constraintType, scope);

policyEngine.registerFunction(scope, Duty.class, constraintType, function);
policyEngine.registerFunction(contextClass, Duty.class, constraintType, function);
}
}
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ edc-vault-hashicorp = { module = "org.eclipse.edc:vault-hashicorp", version.ref
edc-spi-core = { module = "org.eclipse.edc:core-spi", version.ref = "edc" }
edc-spi-identity-trust = { module = "org.eclipse.edc:identity-trust-spi", version.ref = "edc" }
edc-spi-transform = { module = "org.eclipse.edc:transform-spi", version.ref = "edc" }
edc-spi-catalog = { module = "org.eclipse.edc:catalog-spi", version.ref = "edc" }
edc-spi-jwt = { module = "org.eclipse.edc:jwt-spi", version.ref = "edc" }
edc-spi-identity-did = { module = "org.eclipse.edc:identity-did-spi", version.ref = "edc" }

Expand Down

0 comments on commit dbe55d8

Please sign in to comment.