-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: improve BPN validation * add SQL persistence * add base test class, inmem tests * revert build * deprecation * documentation, cleanup * cleanup * added migration * renamed extension * pr remarks * add D-R * md lint
- Loading branch information
1 parent
cd2466e
commit d8b54dd
Showing
29 changed files
with
1,292 additions
and
8 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
42 changes: 42 additions & 0 deletions
42
docs/development/decision-records/2023-08-03_improve_bpn_validation/README.md
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,42 @@ | ||
# Removal of manually curated CHANGELOG.md | ||
|
||
## Decision | ||
|
||
The BPN validation extension will be improved in the following aspects: | ||
|
||
1. Instead of hard-coding them on policies, BPNs are stored in a database (in-mem + Postgres) | ||
2. BPNs are grouped to enable stable policies | ||
3. More `Operator`s are supported | ||
4. Database entries can be manipulated using a REST API | ||
|
||
## Rationale | ||
|
||
Hard-coding BPNs on policies is quite inflexible and does not scale, because when a new business partner joins or leaves | ||
the network, all participants would have to update all their policies, which is a significant migration effort. Instead, | ||
a structure has to be defined where that situation can be handled in a less intrusive and involved way. This effectively | ||
will remove the need to update/migrate policies. | ||
|
||
## Approach | ||
|
||
Every BPN is associated with one or more groups, for example `BPN0000001` -> `["gold_member"]`. It is important to note, | ||
that these groups are _internal_ tags that every participant maintains on their own, they are not claims in | ||
VerifiableCredentials (the BPN would be a claim, however). A new policy constraint is introduced, that looks like this: | ||
|
||
```json | ||
{ | ||
"constraint": { | ||
"leftOperand": "https://w3id.org/tractusx/v0.0.1/ns/BusinessPartnerGroup", | ||
"operator": "isAnyOf", | ||
"rightOperand": [ | ||
"gold_customer", | ||
"platin_partner" | ||
] | ||
} | ||
} | ||
``` | ||
|
||
NB: the `leftOperand` must be an IRI as mandated by ODRL, thus it must either be prefixed with the namespace (as shown | ||
in the example), or using a vocabulary entry in the JSON-LD context, i.e. `tx:BusinessPartnerGroup`. Supported operators | ||
will be: `eq, neq, in, isAllOf, isAnyOf, isNoneOf`. | ||
|
||
Manipulating the BPN -> group associations can be done through a REST API. |
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,36 @@ | ||
/* | ||
* Copyright (c) 2021,2022 Contributors to the Eclipse Foundation | ||
* | ||
* See the NOTICE file(s) distributed with this work for additional | ||
* information regarding copyright ownership. | ||
* | ||
* 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 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations | ||
* under the License. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
plugins { | ||
`java-library` | ||
`maven-publish` | ||
`java-test-fixtures` | ||
} | ||
|
||
dependencies { | ||
implementation(project(":spi:core-spi")) | ||
api(libs.edc.spi.core) | ||
implementation(libs.edc.spi.policy) | ||
implementation(libs.edc.spi.contract) | ||
implementation(libs.edc.spi.policyengine) | ||
|
||
testFixturesImplementation(libs.edc.junit) | ||
testFixturesImplementation(libs.junit.jupiter.api) | ||
testFixturesImplementation(libs.assertj) | ||
} |
78 changes: 78 additions & 0 deletions
78
...g/eclipse/tractusx/edc/validation/businesspartner/BusinessPartnerEvaluationExtension.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,78 @@ | ||
/* | ||
* 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.validation.businesspartner; | ||
|
||
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.system.ServiceExtension; | ||
import org.eclipse.edc.spi.system.ServiceExtensionContext; | ||
import org.eclipse.tractusx.edc.validation.businesspartner.functions.BusinessPartnerGroupFunction; | ||
import org.eclipse.tractusx.edc.validation.businesspartner.spi.BusinessPartnerGroupStore; | ||
|
||
import static org.eclipse.edc.connector.contract.spi.offer.ContractDefinitionResolver.CATALOGING_SCOPE; | ||
import static org.eclipse.edc.connector.contract.spi.validation.ContractValidationService.NEGOTIATION_SCOPE; | ||
import static org.eclipse.edc.connector.contract.spi.validation.ContractValidationService.TRANSFER_SCOPE; | ||
|
||
/** | ||
* Registers a {@link org.eclipse.tractusx.edc.validation.businesspartner.functions.BusinessPartnerGroupFunction} for the following scopes: | ||
* <ul> | ||
* <li>{@link org.eclipse.edc.connector.contract.spi.offer.ContractDefinitionResolver#CATALOGING_SCOPE}</li> | ||
* <li>{@link org.eclipse.edc.connector.contract.spi.validation.ContractValidationService#NEGOTIATION_SCOPE}</li> | ||
* <li>{@link org.eclipse.edc.connector.contract.spi.validation.ContractValidationService#TRANSFER_SCOPE}</li> | ||
* </ul> | ||
* The rule to which the function is bound is {@link BusinessPartnerGroupFunction#BUSINESS_PARTNER_CONSTRAINT_KEY}. That means, that policies that are bound to these scopes look | ||
* like this: | ||
* <pre> | ||
* { | ||
* "constraint": { | ||
* "leftOperand": "https://w3id.org/tractusx/v0.0.1/ns/BusinessPartnerGroup", | ||
* "operator": "isAnyOf", | ||
* "rightOperand": ["gold_customer","platin_partner"] | ||
* } | ||
* } | ||
* </pre> | ||
* <p> | ||
* Note that the {@link BusinessPartnerGroupFunction} is an {@link org.eclipse.edc.policy.engine.spi.AtomicConstraintFunction}, thus it is registered with the {@link PolicyEngine} for the {@link Permission} class. | ||
*/ | ||
@Extension(value = "Registers a function to evaluate whether a BPN number is covered by a certain policy or not", categories = {"policy", "contract"}) | ||
public class BusinessPartnerEvaluationExtension implements ServiceExtension { | ||
|
||
private static final String USE = "USE"; | ||
@Inject | ||
private RuleBindingRegistry ruleBindingRegistry; | ||
@Inject | ||
private PolicyEngine policyEngine; | ||
@Inject | ||
private BusinessPartnerGroupStore store; | ||
|
||
@Override | ||
public void initialize(ServiceExtensionContext context) { | ||
var function = new BusinessPartnerGroupFunction(store); | ||
|
||
bindToScope(function, TRANSFER_SCOPE); | ||
bindToScope(function, NEGOTIATION_SCOPE); | ||
bindToScope(function, CATALOGING_SCOPE); | ||
} | ||
|
||
private void bindToScope(BusinessPartnerGroupFunction function, String scope) { | ||
ruleBindingRegistry.bind(USE, scope); | ||
ruleBindingRegistry.bind(BusinessPartnerGroupFunction.BUSINESS_PARTNER_CONSTRAINT_KEY, scope); | ||
|
||
policyEngine.registerFunction(scope, Permission.class, BusinessPartnerGroupFunction.BUSINESS_PARTNER_CONSTRAINT_KEY, function); | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
...lipse/tractusx/edc/validation/businesspartner/defaults/DefaultStoreProviderExtension.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,29 @@ | ||
/* | ||
* 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.validation.businesspartner.defaults; | ||
|
||
import org.eclipse.edc.runtime.metamodel.annotation.Extension; | ||
import org.eclipse.edc.runtime.metamodel.annotation.Provider; | ||
import org.eclipse.edc.spi.system.ServiceExtension; | ||
import org.eclipse.tractusx.edc.validation.businesspartner.spi.BusinessPartnerGroupStore; | ||
|
||
@Extension("Provides a default BusinessPartnerGroupStore") | ||
public class DefaultStoreProviderExtension implements ServiceExtension { | ||
|
||
@Provider(isDefault = true) | ||
public BusinessPartnerGroupStore createInMemStore() { | ||
return new InMemoryBusinessPartnerGroupStore(); | ||
} | ||
} |
61 changes: 61 additions & 0 deletions
61
...e/tractusx/edc/validation/businesspartner/defaults/InMemoryBusinessPartnerGroupStore.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,61 @@ | ||
/* | ||
* 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.validation.businesspartner.defaults; | ||
|
||
import org.eclipse.edc.spi.result.StoreResult; | ||
import org.eclipse.tractusx.edc.validation.businesspartner.spi.BusinessPartnerGroupStore; | ||
|
||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
public class InMemoryBusinessPartnerGroupStore implements BusinessPartnerGroupStore { | ||
private final Map<String, List<String>> cache = new HashMap<>(); | ||
|
||
@Override | ||
public StoreResult<List<String>> resolveForBpn(String businessPartnerNumber) { | ||
var entry = cache.get(businessPartnerNumber); | ||
return entry == null ? | ||
StoreResult.notFound(NOT_FOUND_TEMPLATE.formatted(businessPartnerNumber)) : | ||
StoreResult.success(entry); | ||
} | ||
|
||
@Override | ||
public StoreResult<Void> save(String businessPartnerNumber, List<String> groups) { | ||
//to maintain behavioural consistency with the SQL store | ||
if (cache.containsKey(businessPartnerNumber)) { | ||
return StoreResult.alreadyExists(ALREADY_EXISTS_TEMPLATE.formatted(businessPartnerNumber)); | ||
} | ||
cache.put(businessPartnerNumber, groups); | ||
return StoreResult.success(); | ||
} | ||
|
||
@Override | ||
public StoreResult<Void> delete(String businessPartnerNumber) { | ||
|
||
return cache.remove(businessPartnerNumber) == null ? | ||
StoreResult.notFound(NOT_FOUND_TEMPLATE.formatted(businessPartnerNumber)) : | ||
StoreResult.success(); | ||
} | ||
|
||
@Override | ||
public StoreResult<Void> update(String businessPartnerNumber, List<String> groups) { | ||
if (cache.containsKey(businessPartnerNumber)) { | ||
cache.put(businessPartnerNumber, groups); | ||
return StoreResult.success(); | ||
} | ||
return StoreResult.notFound(NOT_FOUND_TEMPLATE.formatted(businessPartnerNumber)); | ||
} | ||
} |
Oops, something went wrong.