-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(policy): add constraint function to evaluate gaia-x compliance
- Loading branch information
1 parent
fbfb0f1
commit ee3c0f1
Showing
6 changed files
with
295 additions
and
2 deletions.
There are no files selected for viewing
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
57 changes: 57 additions & 0 deletions
57
.../src/main/java/org/eclipse/edc/trustframework/policy/core/GaiaxCorePoliciesExtension.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,57 @@ | ||
/* | ||
* Copyright (c) 2023 GAIA-X | ||
* | ||
* 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: | ||
* GAIA-X - initial API and implementation | ||
* | ||
*/ | ||
|
||
package org.eclipse.edc.trustframework.policy.core; | ||
|
||
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.eclipse.edc.runtime.metamodel.annotation.Extension; | ||
import org.eclipse.edc.runtime.metamodel.annotation.Inject; | ||
import org.eclipse.edc.spi.monitor.Monitor; | ||
import org.eclipse.edc.spi.system.ServiceExtension; | ||
import org.eclipse.edc.spi.system.ServiceExtensionContext; | ||
import org.eclipse.edc.trustframework.policy.core.compliance.GaiaxComplianceConstraintFunction; | ||
|
||
import static org.eclipse.edc.policy.engine.spi.PolicyEngine.ALL_SCOPES; | ||
|
||
@Extension(value = GaiaxCorePoliciesExtension.GAIA_X_CORE_POLICIES_NAME) | ||
public class GaiaxCorePoliciesExtension implements ServiceExtension { | ||
|
||
private static final String ALL_SCOPE = "*"; | ||
|
||
public static final String GAIA_X_CORE_POLICIES_NAME = "Gaia-X Core Policies"; | ||
|
||
private static final String GAIAX_COMPLIANCE = "gx:compliance"; | ||
|
||
@Inject | ||
private PolicyEngine policyEngine; | ||
|
||
@Inject | ||
private RuleBindingRegistry ruleBindingRegistry; | ||
|
||
@Inject | ||
private Monitor monitor; | ||
|
||
@Override | ||
public String name() { | ||
return GAIA_X_CORE_POLICIES_NAME; | ||
} | ||
|
||
@Override | ||
public void initialize(ServiceExtensionContext context) { | ||
policyEngine.registerFunction(ALL_SCOPES, Permission.class, GAIAX_COMPLIANCE, new GaiaxComplianceConstraintFunction(monitor)); | ||
ruleBindingRegistry.bind(GAIAX_COMPLIANCE, ALL_SCOPE); | ||
} | ||
} |
95 changes: 95 additions & 0 deletions
95
.../eclipse/edc/trustframework/policy/core/compliance/GaiaxComplianceConstraintFunction.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,95 @@ | ||
/* | ||
* Copyright (c) 2023 GAIA-X | ||
* | ||
* 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: | ||
* GAIA-X - initial implementation | ||
* | ||
*/ | ||
|
||
package org.eclipse.edc.trustframework.policy.core.compliance; | ||
|
||
import org.eclipse.edc.identityhub.spi.credentials.model.Credential; | ||
import org.eclipse.edc.policy.engine.spi.AtomicConstraintFunction; | ||
import org.eclipse.edc.policy.engine.spi.PolicyContext; | ||
import org.eclipse.edc.policy.model.Operator; | ||
import org.eclipse.edc.policy.model.Permission; | ||
import org.eclipse.edc.spi.monitor.Monitor; | ||
|
||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
/** | ||
* A function for evaluating Gaia-X compliance credentials. | ||
*/ | ||
public class GaiaxComplianceConstraintFunction implements AtomicConstraintFunction<Permission> { | ||
|
||
private static final String GAIAX_COMPLIANCE_ID = "id"; | ||
private static final String GAIAX_COMPLIANCE_TYPE = "type"; | ||
private static final String GAIAX_COMPLIANCE_INTEGRITY = "integrity"; | ||
private static final String GAIAX_COMPLIANCE_TYPE_VALUE = "gx:compliance"; | ||
private final Monitor monitor; | ||
|
||
public GaiaxComplianceConstraintFunction(Monitor monitor) { | ||
this.monitor = monitor; | ||
} | ||
|
||
/** | ||
* Performs the evaluation | ||
* | ||
* @param operator the operator | ||
* @param rightValue the right-side expression for the constraint; the concrete type may be a string, primitive or object such as a JSON-LD encoded collection. | ||
* @param rule the rule associated with the constraint | ||
* @param context the policy context | ||
* @return match with right value and operator and validity of Gaia-x compliance credential | ||
*/ | ||
@Override | ||
public boolean evaluate(Operator operator, Object rightValue, Permission rule, PolicyContext context) { | ||
var complianceCredentials = getComplianceCredentials(context.getParticipantAgent().getClaims()); | ||
return switch (operator) { | ||
case EQ -> rightValue.equals(areComplianceCredentialsValid(complianceCredentials)); | ||
case NEQ -> !rightValue.equals(areComplianceCredentialsValid(complianceCredentials)); | ||
default -> { | ||
monitor.warning("Provided operator is not implemented"); | ||
yield false; | ||
} | ||
}; | ||
} | ||
|
||
private boolean areComplianceCredentialsValid(List<Map<String, String>> complianceCredentials) { | ||
return !complianceCredentials.isEmpty() && complianceCredentials.stream() | ||
.noneMatch(credential -> credential.get(GAIAX_COMPLIANCE_ID).isBlank() || | ||
credential.get(GAIAX_COMPLIANCE_INTEGRITY).isBlank()); | ||
} | ||
|
||
private List<Map<String, String>> getComplianceCredentials(Map<String, Object> claims) { | ||
return claims.values().stream() | ||
.map(this::buildComplianceObject) | ||
.filter(vc -> GAIAX_COMPLIANCE_TYPE_VALUE.equals(vc.get(GAIAX_COMPLIANCE_TYPE))) | ||
.filter(vc -> vc.get(GAIAX_COMPLIANCE_ID) != null && | ||
vc.get(GAIAX_COMPLIANCE_INTEGRITY) != null) | ||
.toList(); | ||
} | ||
|
||
private Map<String, String> buildComplianceObject(Object object) { | ||
var complianceCredentialSubject = new HashMap<String, String>(); | ||
var credential = (Credential) object; | ||
complianceCredentialSubject.put(GAIAX_COMPLIANCE_ID, credential.getCredentialSubject().getId()); | ||
complianceCredentialSubject.put(GAIAX_COMPLIANCE_TYPE, getCredentialProperty(credential, GAIAX_COMPLIANCE_TYPE)); | ||
complianceCredentialSubject.put(GAIAX_COMPLIANCE_INTEGRITY, getCredentialProperty(credential, GAIAX_COMPLIANCE_INTEGRITY)); | ||
return complianceCredentialSubject; | ||
} | ||
|
||
private String getCredentialProperty(Object object, String claimKey) { | ||
var credential = (Credential) object; | ||
var claims = credential.getCredentialSubject().getClaims(); | ||
return (String) claims.get(claimKey); | ||
} | ||
|
||
} |
15 changes: 15 additions & 0 deletions
15
...ies-core/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension
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,15 @@ | ||
# | ||
# Copyright (c) 2023 GAIA-X | ||
# | ||
# 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: | ||
# GAIA-X - initial API and implementation | ||
# | ||
# | ||
|
||
org.eclipse.edc.trustframework.policy.core.GaiaxCorePoliciesExtension |
119 changes: 119 additions & 0 deletions
119
...ipse/edc/trustframework/policy/core/compliance/GaiaxComplianceConstraintFunctionTest.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,119 @@ | ||
/* | ||
* Copyright (c) 2023 GAIA-X | ||
* | ||
* 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: | ||
* GAIA-X - initial implementation | ||
* | ||
*/ | ||
|
||
package org.eclipse.edc.trustframework.policy.core.compliance; | ||
|
||
import org.eclipse.edc.identityhub.spi.credentials.model.Credential; | ||
import org.eclipse.edc.identityhub.spi.credentials.model.CredentialSubject; | ||
import org.eclipse.edc.identityhub.spi.credentials.model.VerifiableCredential; | ||
import org.eclipse.edc.policy.engine.PolicyContextImpl; | ||
import org.eclipse.edc.policy.model.Operator; | ||
import org.eclipse.edc.policy.model.Permission; | ||
import org.eclipse.edc.spi.agent.ParticipantAgent; | ||
import org.eclipse.edc.spi.monitor.Monitor; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import java.sql.Date; | ||
import java.time.Instant; | ||
import java.time.temporal.ChronoUnit; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.UUID; | ||
import java.util.stream.Collectors; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.mockito.Mockito.mock; | ||
|
||
class GaiaxComplianceConstraintFunctionTest { | ||
|
||
private static final Monitor MONITOR = mock(Monitor.class); | ||
private GaiaxComplianceConstraintFunction function; | ||
|
||
@BeforeEach | ||
public void setUp() { | ||
function = new GaiaxComplianceConstraintFunction(MONITOR); | ||
} | ||
|
||
@Test | ||
void shouldBeTrueWhenValidCredentialIsPresent() { | ||
var credentialSubject = CredentialSubject.Builder.newInstance() | ||
.id("did:web:did-host:company1") | ||
.claim("integrity", "sha256-40f94d5a0da1afb4b48cb5472dd04407123dbd60a0c8ab30cf2b00b1c9ea42f4") | ||
.claim("type", "gx:compliance") | ||
.build(); | ||
var policyContext = createPolicyContext(List.of(buildCredential(credentialSubject))); | ||
|
||
var result = function.evaluate(Operator.EQ, true, anyPermission(), policyContext); | ||
|
||
assertThat(result).isTrue(); | ||
} | ||
|
||
@Test | ||
void shouldBeFalseWhenNoCredentialIsPresent() { | ||
var policyContext = createPolicyContext(new ArrayList<>()); | ||
|
||
var result = function.evaluate(Operator.EQ, true, anyPermission(), policyContext); | ||
|
||
assertThat(result).isFalse(); | ||
} | ||
|
||
@Test | ||
void shouldBeFalseWhenCredentialsAreNotValid() { | ||
var credentialSubject = CredentialSubject.Builder.newInstance() | ||
.id("did:web:did-host:company1") | ||
.claim("type", "gx:compliance") | ||
.build(); | ||
var policyContext = createPolicyContext(List.of(buildCredential(credentialSubject))); | ||
|
||
var result = function.evaluate(Operator.EQ, true, anyPermission(), policyContext); | ||
|
||
assertThat(result).isFalse(); | ||
} | ||
|
||
@Test | ||
void shouldBeFalseWhenCredentialsTypeIsNotPresent() { | ||
var credentialSubject = CredentialSubject.Builder.newInstance() | ||
.id("did:web:did-host:company1") | ||
.claim("integrity", "sha256-40f94d5a0da1afb4b48cb5472dd04407123dbd60a0c8ab30cf2b00b1c9ea42f4") | ||
.build(); | ||
var policyContext = createPolicyContext(List.of(buildCredential(credentialSubject))); | ||
|
||
var result = function.evaluate(Operator.EQ, true, anyPermission(), policyContext); | ||
|
||
assertThat(result).isFalse(); | ||
} | ||
|
||
private static PolicyContextImpl createPolicyContext(List<Credential> credentials) { | ||
var credentialsMap = credentials.stream() | ||
.collect(Collectors.toMap(Credential::getId, credential -> (Object) credential)); | ||
var participantAgent = new ParticipantAgent(credentialsMap, Map.of()); | ||
return new PolicyContextImpl(participantAgent, Map.of()); | ||
} | ||
|
||
private Credential buildCredential(CredentialSubject credentialSubject) { | ||
return Credential.Builder.newInstance() | ||
.id(UUID.randomUUID().toString()) | ||
.context(VerifiableCredential.DEFAULT_CONTEXT) | ||
.issuer("issuer") | ||
.issuanceDate(Date.from(Instant.now().truncatedTo(ChronoUnit.SECONDS))) | ||
.credentialSubject(credentialSubject) | ||
.build(); | ||
} | ||
|
||
private Permission anyPermission() { | ||
return Permission.Builder.newInstance().build(); | ||
} | ||
} |
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 |
---|---|---|
@@ -1,5 +1,5 @@ | ||
distributionBase=GRADLE_USER_HOME | ||
distributionPath=wrapper/dists | ||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip | ||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip | ||
zipStoreBase=GRADLE_USER_HOME | ||
zipStorePath=wrapper/dists |