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

core: replace policies with ids in ContractDefinition #1144

Merged
merged 3 commits into from
Apr 21, 2022
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Bugfixing DataManagementApi

* Restructure sql extension folder tree (#1154)
* Extract single `PolicyArchive` implementation (#1158)
* Replace `accessPolicy` and `contractPolicy` with `accessPolicyId` and `contractPolicyId` on `ContractDefinition` (#1144)

#### Removed

Expand Down
1 change: 1 addition & 0 deletions core/contract/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ dependencies {
testImplementation(project(":extensions:in-memory:assetindex-memory"))
testImplementation(project(":extensions:in-memory:contractdefinition-store-memory"))
testImplementation(project(":extensions:in-memory:negotiation-store-memory"))
testImplementation(project(":extensions:in-memory:policy-store-memory"))
testImplementation(testFixtures(project(":common:util")))
testImplementation(testFixtures(project(":launchers:junit")))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.eclipse.dataspaceconnector.spi.monitor.Monitor;
import org.eclipse.dataspaceconnector.spi.policy.PolicyEngine;
import org.eclipse.dataspaceconnector.spi.policy.store.PolicyArchive;
import org.eclipse.dataspaceconnector.spi.policy.store.PolicyStore;
import org.eclipse.dataspaceconnector.spi.retry.ExponentialWaitStrategy;
import org.eclipse.dataspaceconnector.spi.system.CoreExtension;
import org.eclipse.dataspaceconnector.spi.system.ExecutorInstrumentation;
Expand Down Expand Up @@ -93,6 +94,9 @@ public class ContractServiceExtension implements ServiceExtension {
@Inject
private PolicyEngine policyEngine;

@Inject
private PolicyStore policyStore;

@Override
public String name() {
return "Core Contract Service";
Expand Down Expand Up @@ -124,18 +128,13 @@ public void shutdown() {
}

private void registerServices(ServiceExtensionContext context) {
if (assetIndex == null) {
monitor.warning("No AssetIndex registered. Register one to create Contract Offers.");
assetIndex = new NullAssetIndex();
}

var definitionService = new ContractDefinitionServiceImpl(monitor, contractDefinitionStore, policyEngine);
var contractOfferService = new ContractOfferServiceImpl(agentService, definitionService, assetIndex);
var definitionService = new ContractDefinitionServiceImpl(monitor, contractDefinitionStore, policyEngine, policyStore);
context.registerService(ContractDefinitionService.class, definitionService);

var contractOfferService = new ContractOfferServiceImpl(agentService, definitionService, assetIndex, policyStore);
context.registerService(ContractOfferService.class, contractOfferService);

var validationService = new ContractValidationServiceImpl(agentService, () -> definitionService, assetIndex);
var validationService = new ContractValidationServiceImpl(agentService, definitionService, assetIndex, policyStore);
context.registerService(ContractValidationService.class, validationService);

var waitStrategy = context.hasService(NegotiationWaitStrategy.class) ? context.getService(NegotiationWaitStrategy.class) : new ExponentialWaitStrategy(DEFAULT_ITERATION_WAIT);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,25 @@
* Contributors:
* Daimler TSS GmbH - Initial API and Implementation
* Microsoft Corporation - Refactoring
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - improvements
*
*/

package org.eclipse.dataspaceconnector.contract.offer;

import org.eclipse.dataspaceconnector.policy.model.Policy;
import org.eclipse.dataspaceconnector.spi.agent.ParticipantAgent;
import org.eclipse.dataspaceconnector.spi.contract.offer.ContractDefinitionService;
import org.eclipse.dataspaceconnector.spi.contract.offer.store.ContractDefinitionStore;
import org.eclipse.dataspaceconnector.spi.monitor.Monitor;
import org.eclipse.dataspaceconnector.spi.policy.PolicyEngine;
import org.eclipse.dataspaceconnector.spi.policy.store.PolicyStore;
import org.eclipse.dataspaceconnector.spi.result.Result;
import org.eclipse.dataspaceconnector.spi.types.domain.contract.offer.ContractDefinition;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Optional;
import java.util.stream.Stream;

import static java.lang.String.format;
Expand All @@ -34,47 +39,60 @@
*/
public class ContractDefinitionServiceImpl implements ContractDefinitionService {
private final PolicyEngine policyEngine;
private final PolicyStore policyStore;
private final Monitor monitor;
private final ContractDefinitionStore definitionStore;

public ContractDefinitionServiceImpl(Monitor monitor, ContractDefinitionStore contractDefinitionStore, PolicyEngine policyEngine) {
public ContractDefinitionServiceImpl(Monitor monitor, ContractDefinitionStore contractDefinitionStore, PolicyEngine policyEngine, PolicyStore policyStore) {
this.monitor = monitor;
this.definitionStore = contractDefinitionStore;
this.policyEngine = policyEngine;
this.policyStore = policyStore;
}

@NotNull
@Override
public Stream<ContractDefinition> definitionsFor(ParticipantAgent agent) {
return definitionStore.findAll().stream().filter(definition -> evaluatePolicies(definition, agent));
return definitionStore.findAll().stream()
.filter(definition -> evaluatePolicies(definition, agent));
}

@Nullable
@Override
public ContractDefinition definitionFor(ParticipantAgent agent, String definitionId) {
var definitionOptional = definitionStore.findAll().stream().filter(d -> d.getId().equals(definitionId)).findFirst();
if (definitionOptional.isPresent()) {
var definition = definitionOptional.get();
if (evaluatePolicies(definition, agent)) {
return definition;
}
}
return null;
return definitionStore.findAll().stream()
.filter(d -> d.getId().equals(definitionId))
.findFirst()
.filter(definition -> evaluatePolicies(definition, agent))
.orElse(null);
}

/**
* Determines the applicability of a definition to an agent by evaluating the union of its access control and usage policies.
*/
private boolean evaluatePolicies(ContractDefinition definition, ParticipantAgent agent) {
var accessResult = policyEngine.evaluate(NEGOTIATION_SCOPE, definition.getAccessPolicy(), agent);
var accessResult = evaluate(definition.getAccessPolicyId(), agent);

if (accessResult.failed()) {
monitor.info(format("Problem evaluating access control policy for %s: \n%s", definition.getId(), String.join("\n", accessResult.getFailureMessages())));
return false;
}
var usageResult = policyEngine.evaluate(NEGOTIATION_SCOPE, definition.getContractPolicy(), agent);
if (usageResult.failed()) {
monitor.info(format("Problem evaluating usage control policy for %s: \n%s", definition.getId(), String.join("\n", usageResult.getFailureMessages())));

var controlResult = evaluate(definition.getContractPolicyId(), agent);

if (controlResult.failed()) {
monitor.info(format("Problem evaluating usage control policy for %s: \n%s", definition.getId(), String.join("\n", controlResult.getFailureMessages())));
return false;
}

return true;
}

@NotNull
private Result<Policy> evaluate(String policyId, ParticipantAgent agent) {
return Optional.of(policyId)
.map(policyStore::findById)
.map(policy -> policyEngine.evaluate(NEGOTIATION_SCOPE, policy, agent))
.orElse(Result.failure(format("Policy %s not found", policyId)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,29 @@
* Daimler TSS GmbH - Initial API and Implementation
* Microsoft Corporation - Refactoring
* Fraunhofer Institute for Software and Systems Engineering - extended method implementation
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - improvements
*
*/

package org.eclipse.dataspaceconnector.contract.offer;

import org.eclipse.dataspaceconnector.contract.common.ContractId;
import org.eclipse.dataspaceconnector.policy.model.Policy;
import org.eclipse.dataspaceconnector.spi.agent.ParticipantAgentService;
import org.eclipse.dataspaceconnector.spi.asset.AssetIndex;
import org.eclipse.dataspaceconnector.spi.contract.offer.ContractDefinitionService;
import org.eclipse.dataspaceconnector.spi.contract.offer.ContractOfferQuery;
import org.eclipse.dataspaceconnector.spi.contract.offer.ContractOfferService;
import org.eclipse.dataspaceconnector.spi.policy.store.PolicyStore;
import org.eclipse.dataspaceconnector.spi.types.domain.asset.Asset;
import org.eclipse.dataspaceconnector.spi.types.domain.contract.offer.ContractDefinition;
import org.eclipse.dataspaceconnector.spi.types.domain.contract.offer.ContractOffer;
import org.jetbrains.annotations.NotNull;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;

/**
Expand All @@ -37,41 +43,39 @@ public class ContractOfferServiceImpl implements ContractOfferService {
private final ParticipantAgentService agentService;
private final ContractDefinitionService definitionService;
private final AssetIndex assetIndex;
private final PolicyStore policyStore;

public ContractOfferServiceImpl(ParticipantAgentService agentService, ContractDefinitionService definitionService, AssetIndex assetIndex) {
this.agentService = Objects.requireNonNull(agentService, "ParticipantAgentService must not be null");
this.definitionService = Objects.requireNonNull(definitionService, "ContractDefinitionService must not be null");
this.assetIndex = Objects.requireNonNull(assetIndex, "AssetIndex must not be null");
public ContractOfferServiceImpl(ParticipantAgentService agentService, ContractDefinitionService definitionService, AssetIndex assetIndex, PolicyStore policyStore) {
this.agentService = agentService;
this.definitionService = definitionService;
this.assetIndex = assetIndex;
this.policyStore = policyStore;
}

@Override
@NotNull
public Stream<ContractOffer> queryContractOffers(ContractOfferQuery query) {
var agent = agentService.createFor(query.getClaimToken());
var definitions = definitionService.definitionsFor(agent);

return definitions.flatMap(definition -> {
var assets = assetIndex.queryAssets(definition.getSelectorExpression());
return assets.map(asset -> ContractOffer.Builder.newInstance()
.id(ContractId.createContractId(definition.getId()))
.policy(definition.getContractPolicy().withTarget(asset.getId()))
.asset(asset)
// TODO: this is a workaround for the bug described in https://github.com/eclipse-dataspaceconnector/DataSpaceConnector/issues/753
.provider(uri("urn:connector:provider"))
.consumer(uri("urn:connector:consumer"))
.build());
});
return definitionService.definitionsFor(agent)
.flatMap(definition -> {
var assets = assetIndex.queryAssets(definition.getSelectorExpression());
return Optional.of(definition.getContractPolicyId())
.map(policyStore::findById)
.map(policy -> assets.map(asset -> createContractOffer(definition, policy, asset)))
.orElseGet(Stream::empty);
});
}

/**
* swallows any exception during uri generation
*/
private URI uri(String str) {
try {
return new URI(str);
} catch (URISyntaxException ignored) {
return null;
}
@NotNull
private ContractOffer createContractOffer(ContractDefinition definition, Policy policy, Asset asset) {
return ContractOffer.Builder.newInstance()
.id(ContractId.createContractId(definition.getId()))
.policy(policy.withTarget(asset.getId()))
.asset(asset)
// TODO: this is a workaround for the bug described in https://github.com/eclipse-dataspaceconnector/DataSpaceConnector/issues/753
.provider(URI.create("urn:connector:provider"))
.consumer(URI.create("urn:connector:consumer"))
.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* Contributors:
* Microsoft Corporation - initial API and implementation
* Fraunhofer Institute for Software and Systems Engineering - improvements
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - improvements
*
*/

Expand All @@ -20,6 +21,7 @@
import org.eclipse.dataspaceconnector.spi.contract.offer.ContractDefinitionService;
import org.eclipse.dataspaceconnector.spi.contract.validation.ContractValidationService;
import org.eclipse.dataspaceconnector.spi.iam.ClaimToken;
import org.eclipse.dataspaceconnector.spi.policy.store.PolicyStore;
import org.eclipse.dataspaceconnector.spi.query.Criterion;
import org.eclipse.dataspaceconnector.spi.query.QuerySpec;
import org.eclipse.dataspaceconnector.spi.result.Result;
Expand All @@ -32,8 +34,8 @@
import java.time.Instant;
import java.util.ArrayList;
import java.util.Objects;
import java.util.function.Supplier;

import static java.lang.String.format;
import static org.eclipse.dataspaceconnector.contract.common.ContractId.DEFINITION_PART;
import static org.eclipse.dataspaceconnector.contract.common.ContractId.parseContractId;

Expand All @@ -43,13 +45,15 @@
public class ContractValidationServiceImpl implements ContractValidationService {

private final ParticipantAgentService agentService;
private final Supplier<ContractDefinitionService> definitionServiceSupplier;
private final ContractDefinitionService contractDefinitionService;
private final AssetIndex assetIndex;
private final PolicyStore policyStore;

public ContractValidationServiceImpl(ParticipantAgentService agentService, Supplier<ContractDefinitionService> definitionServiceSupplier, AssetIndex assetIndex) {
this.agentService = Objects.requireNonNull(agentService);
this.definitionServiceSupplier = Objects.requireNonNull(definitionServiceSupplier);
this.assetIndex = Objects.requireNonNull(assetIndex);
public ContractValidationServiceImpl(ParticipantAgentService agentService, ContractDefinitionService contractDefinitionService, AssetIndex assetIndex, PolicyStore policyStore) {
this.agentService = agentService;
this.contractDefinitionService = contractDefinitionService;
this.assetIndex = assetIndex;
this.policyStore = policyStore;
}

@Override
Expand All @@ -65,7 +69,7 @@ public Result<ContractOffer> validate(ClaimToken token, ContractOffer offer) {
}

var agent = agentService.createFor(token);
var contractDefinition = definitionServiceSupplier.get().definitionFor(agent, contractIdTokens[DEFINITION_PART]);
var contractDefinition = contractDefinitionService.definitionFor(agent, contractIdTokens[DEFINITION_PART]);
if (contractDefinition == null) {
return Result.failure("Invalid contract.");
}
Expand All @@ -78,12 +82,17 @@ public Result<ContractOffer> validate(ClaimToken token, ContractOffer offer) {
return Result.failure("Invalid target: " + offer.getAsset());
}

var sanitizedUsagePolicy = contractDefinition.getContractPolicy();
var contractPolicy = policyStore.findById(contractDefinition.getContractPolicyId());
if (contractPolicy == null) {
return Result.failure(format("Policy %s not found", contractDefinition.getContractPolicyId()));
}

var validatedOffer = ContractOffer.Builder.newInstance()
.id(offer.getId())
.asset(targetAsset)
.policy(sanitizedUsagePolicy)
.policy(contractPolicy)
.build();

return Result.success(validatedOffer);
}

Expand Down Expand Up @@ -115,7 +124,7 @@ public boolean validate(ClaimToken token, ContractAgreement agreement) {
return false;
}

return definitionServiceSupplier.get().definitionFor(agent, tokens[DEFINITION_PART]) != null;
return contractDefinitionService.definitionFor(agent, tokens[DEFINITION_PART]) != null;
// TODO validate counter-party
}

Expand Down
Loading