Skip to content

Commit

Permalink
Merge pull request #142 from catenax-ng/main
Browse files Browse the repository at this point in the history
IRS bugfix release 3.3.2
  • Loading branch information
ds-jkreutzfeld authored Jul 31, 2023
2 parents f1837ab + ee03e4e commit 66abc97
Show file tree
Hide file tree
Showing 26 changed files with 805,847 additions and 100 deletions.
13 changes: 13 additions & 0 deletions .github/workflows/integration-test-DEV.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ on:
push:
branches:
- 'main'
paths-ignore:
- '**/*.md'
- '**/*.txt'
- 'charts/**'
- '.config/**'
- 'docs/**'
- 'local/**'
- 'irs-load-tests/**'

# Cancel previous Test executions if a new one is triggered.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
trigger-integration-test:
Expand Down
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [3.3.2] - 2023-07-31
### Fixed
- BPN is now passed on correctly when traversing the item graph
- EDC Policies now get validated regardless of the type of constraint.
- EDC Policies of type FrameworkAgreement are now validated correctly.
- Fixed error in BPN handling for IRS Batch requests

## [3.3.1] - 2023-07-24
### Fixed
- Added missing field `businessPartner` for relationship aspect SingleLevelUsageAsBuilt
Expand Down Expand Up @@ -291,7 +298,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Unresolved
- **Select Aspects you need** You are able to select the needed aspects for which you want to collect the correct endpoint information.

[Unreleased]: https://github.com/eclipse-tractusx/item-relationship-service/compare/3.3.1...HEAD
[Unreleased]: https://github.com/eclipse-tractusx/item-relationship-service/compare/3.3.2...HEAD
[3.3.2]: https://github.com/eclipse-tractusx/item-relationship-service/compare/3.3.1...3.3.2
[3.3.1]: https://github.com/eclipse-tractusx/item-relationship-service/compare/3.3.0...3.3.1
[3.3.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/3.2.1...3.3.0
[3.2.1]: https://github.com/eclipse-tractusx/item-relationship-service/compare/3.2.0...3.2.1
Expand Down
7 changes: 7 additions & 0 deletions charts/irs-helm/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [6.4.0] - 2023-07-31
### Added
- New option to configure accepted operands for policy checks via `edc.catalog.policies.acceptedRightOperands` and `edc.catalog.policies.acceptedLeftOperands`

### Changed
- Update IRS version to 3.3.2

## [6.3.1] - 2023-07-24
### Changed
- Update IRS version to 3.3.1
Expand Down
4 changes: 2 additions & 2 deletions charts/irs-helm/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 6.3.1
version: 6.4.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "3.3.1"
appVersion: "3.3.2"
dependencies:
- name: common
repository: https://charts.bitnami.com/bitnami
Expand Down
5 changes: 5 additions & 0 deletions charts/irs-helm/templates/configmap-spring-app-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ data:
path: {{ tpl (.Values.edc.submodel.path | default "/submodel") . | quote }}
urn-prefix: {{ tpl (.Values.edc.submodel.urnprefix | default "/urn") . | quote }}
catalog:
policies:
acceptedRightOperands: {{ .Values.edc.catalog.policies.acceptedRightOperands | default "" | quote }}
acceptedLeftOperands: {{ .Values.edc.catalog.policies.acceptedLeftOperands | default "" | quote }}
edc:
catalog:
policies:
Expand Down
4 changes: 3 additions & 1 deletion charts/irs-helm/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,9 @@ edc:
policies:
# IRS will only negotiate contracts for offers with a policy as defined in the allowedNames list.
# If a requested asset does not provide one of these policies, a tombstone will be created and this node will not be processed.
allowedNames: ID 3.0 Trace, ID 3.1 Trace, R2_Traceability # List of comma separated names of the policies to accept.
allowedNames: ID 3.0 Trace, ID 3.1 Trace, R2_Traceability, FrameworkAgreement.traceability, Membership # List of comma separated names of the policies to accept.
acceptedRightOperands: active # List of comma separated names of the rightOperands to accept.
acceptedLeftOperands: PURPOSE # List of comma separated names of the leftOperands to accept.

discovery:
endpoint: # EDC Discovery Service endpoint
Expand Down
2 changes: 2 additions & 0 deletions docs/src/docs/administration/configuration.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ You can define the URLs as well as most of the secrets yourself.
The Keycloak, MIW and Vault configuration / secrets depend on your setup and might need to be provided externally.
*Note: IRS currently does not support any roles or rights for the API. As long as you provide a valid access token, you can use the IRS API to view and control all jobs on the IRS instance.*
include::irs-spring-config.adoc[leveloffset=+1]
== Helm configuration IRS (values.yaml)
Expand Down
2 changes: 2 additions & 0 deletions docs/src/docs/arc42/cross-cutting/safety-security.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ JWT token should also contain two fields:
- `view_irs` role inside `resource_access` claim,
- BPN claim which is equal to the configuration value from `API_ALLOWED_BPN` property

*Note: IRS currently does not support any other roles or rights. As long as you provide a valid token with the content listed above, you can access the IRS API to view and control all jobs on the IRS instance.*

=== IRS as DTR client
The IRS acts as a client for the Digital Twin Registry (DTR), which is also secured using OAuth2.0 / Open ID Connect. The IRS uses client credentials to authenticate requests to the DTR. Due to this, the IRS account needs to have access to every item in the DTR, unrelated to the permissions of the account calling the IRS API.

Expand Down
2 changes: 1 addition & 1 deletion docs/src/docs/arc42/cross-cutting/under-the-hood.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Data validation happens at two points:

- IRS API: the data sent by the client is validated to match the model defined in the IRS. If the validation fails, the IRS sends a HTTP 400 response and indicates the problem to the caller.
- Submodel payload: each time a submodel payload is requested from via EDC, the data is validated against the model defined in the SemanticHub for the matching aspect type.
- EDC Contract Offer Policy: each time IRS consumes data over the EDC, the policies of the offered contract will be validated. Only policies which are defined via the PolicyStory will be accepted.
- EDC Contract Offer Policy: each time IRS consumes data over the EDC, the policies of the offered contract will be validated. IDs of so-called "Rahmenverträgen" or Framework-Agreements can be added to the IRS Policy Store to be accepted by the IRS. If a Contract Offer does not match any of the IDs store in Policy Store, the contract offer will be declined and no data will be consumed.

== Caching

Expand Down
5 changes: 5 additions & 0 deletions docs/src/docs/arc42/glossary.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,9 @@
|Traversal Aspect |aka Edge: Aspect which the IRS uses for traversal through the data chain. Identified by a parent-child or a child-parent relationship.

Samples: SingleLevelBomAsPlanned, SingleLevelBomAsBuilt and SingleLevelUsageAsBuilt
|Verifiable Credential (VC) | For more information see: https://github.com/eclipse-tractusx/ssi-docu/tree/main/docs/architecture/cx-3-2/3.%20Verifiable%20Credentials[Verifiable Credentials]
|Eclipse Dataspace Connector (EDC) | For more information see: https://github.com/eclipse-tractusx/tractusx-edc
|Managed Identity Wallet (MIW) | For more information see: https://github.com/eclipse-tractusx/managed-identity-wallet
|Self-Sovereign Identity (SSI) | For more information see: https://github.com/eclipse-tractusx/ssi-docu/tree/main/docs/architecture/cx-3-2
|PolicyStore | The Policy Store is an IRS component which provides an interface for getting, adding and deleting accepted IRS EDC policies. These policies will be used to validate EDC contract offers.
|===
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ component [**IRSApplication**] <<System>> {

component [**CatenaX-Network**] <<CX-Environment>> {
component [**IAM/KeyCloak**] <<System>> as IAM_IRS
component [**MIW**] <<System>> as IAM_DAPS
component [**MIW**] <<System>> as identity_wallet
}

component [**Tier/OEM**] <<Tier/OEM-Environment>> {
Expand All @@ -35,13 +35,13 @@ IrsApiConsumer -right(0- IRS
IrsApiConsumer <.r.> IAM_IRS
IRS <.d.> EDC
IRS <.l.> IAM_IRS
EDC <..> IAM_DAPS
EDC <..> identity_wallet
EDC <..> EDCProviderOEM
EDC <...> EDCProviderTier1
EDC <....> EDCProviderTier11
IAM_DAPS <..> EDCProviderOEM
IAM_DAPS <...> EDCProviderTier1
IAM_DAPS <....> EDCProviderTier11
identity_wallet <..> EDCProviderOEM
identity_wallet <...> EDCProviderTier1
identity_wallet <....> EDCProviderTier11
EDCProviderOEM <..> SubmodelServerOEM
EDCProviderTier1 <..> SubmodelServerTier1
EDCProviderTier11 <..> SubmodelServerTier11
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.List;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.tractusx.irs.aaswrapper.job.AASTransferProcess;
import org.eclipse.tractusx.irs.aaswrapper.job.ItemContainer;
import org.eclipse.tractusx.irs.component.JobParameter;
Expand Down Expand Up @@ -55,6 +56,13 @@ public DigitalTwinDelegate(final AbstractDelegate nextStep,
public ItemContainer process(final ItemContainer.ItemContainerBuilder itemContainerBuilder, final JobParameter jobData,
final AASTransferProcess aasTransferProcess, final PartChainIdentificationKey itemId) {

if (StringUtils.isBlank(itemId.getBpn())) {
log.warn("Could not process item with id {} because no BPN was provided. Creating Tombstone.",
itemId.getGlobalAssetId());
return itemContainerBuilder.tombstone(
Tombstone.from(itemId.getGlobalAssetId(), null, "Can't get relationship without a BPN", 0,
ProcessStep.DIGITAL_TWIN_REQUEST)).build();
}
try {
itemContainerBuilder.shell(digitalTwinRegistryService.fetchShells(
List.of(new DigitalTwinRegistryKey(itemId.getGlobalAssetId(), itemId.getBpn()))
Expand Down
8 changes: 4 additions & 4 deletions irs-api/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,10 @@ irs-edc-client:
connect: PT90S # HTTP connect timeout for the submodel client

catalog:
cache:
enabled: true # Set to false to disable caching
ttl: P1D # Time after which a cached Item is no longer valid and the real catalog is called instead
maxCachedItems: 64000 # Maximum amount of cached catalog items
policies:
acceptedRightOperands: active # List of comma separated names of the rightOperands to accept.
acceptedLeftOperands: PURPOSE # List of comma separated names of the leftOperands to accept.

edc:
catalog:
policies:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ void shouldFillItemContainerWithShell() throws RegistryServiceException {
}

private static PartChainIdentificationKey createKey() {
return PartChainIdentificationKey.builder().globalAssetId("itemId").bpn("bpn123").build();
}
private static PartChainIdentificationKey createKeyWithoutBpn() {
return PartChainIdentificationKey.builder().globalAssetId("itemId").build();
}

Expand All @@ -86,4 +89,19 @@ void shouldCatchRestClientExceptionAndPutTombstone() throws RegistryServiceExcep
ProcessStep.DIGITAL_TWIN_REQUEST);
}

@Test
void shouldCreateTombstoneIfBPNEmpty() {
// when
final ItemContainer result = digitalTwinDelegate.process(ItemContainer.builder(), jobParameter(),
new AASTransferProcess("id", 0), createKeyWithoutBpn());

// then
assertThat(result).isNotNull();
assertThat(result.getTombstones()).hasSize(1);
assertThat(result.getTombstones().get(0).getCatenaXId()).isEqualTo("itemId");
assertThat(result.getTombstones().get(0).getProcessingError().getErrorDetail()).isEqualTo("Can't get relationship without a BPN");
assertThat(result.getTombstones().get(0).getProcessingError().getProcessStep()).isEqualTo(
ProcessStep.DIGITAL_TWIN_REQUEST);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ class BatchControllerTest {
private AuthorizationService authorizationService;

@Test
@Disabled("Disabled - failing on pipeline")
void shouldReturnUnauthorizedWhenAuthenticationIsMissing() throws Exception {
this.mockMvc.perform(post("/irs/orders").contentType(MediaType.APPLICATION_JSON)
.content(new ObjectMapper().writeValueAsString(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ void shouldStartNextBatchWhenPreviousFinished() {
@Test
void shouldPublishBatchOrderProcessingFinishedEventWhenAllBatchesCompleted() {
// given
final int numberOfJobs = 10;
final int timeout = 60;
final BatchOrder batchOrder = BatchOrder.builder()
.batchOrderId(BATCH_ORDER_ID)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,16 @@

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.edc.policy.model.AndConstraint;
import org.eclipse.edc.policy.model.AtomicConstraint;
import org.eclipse.edc.policy.model.Constraint;
import org.eclipse.edc.policy.model.MultiplicityConstraint;
import org.eclipse.edc.policy.model.Operator;
import org.eclipse.edc.policy.model.OrConstraint;
import org.eclipse.edc.policy.model.Permission;
import org.eclipse.edc.policy.model.Policy;
import org.eclipse.edc.policy.model.XoneConstraint;
import org.eclipse.tractusx.irs.data.StringMapper;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriUtils;

Expand All @@ -49,6 +51,10 @@
public class PolicyCheckerService {

private final AcceptedPoliciesProvider policyStore;
@Value("${irs-edc-client.catalog.policies.acceptedRightOperands:active}")
private final List<String> acceptedRightOperands;
@Value("${irs-edc-client.catalog.policies.acceptedLeftOperands:PURPOSE}")
private final List<String> acceptedLeftOperands;

public boolean isValid(final Policy policy) {
final List<PolicyDefinition> policyList = getAllowedPolicies();
Expand All @@ -57,23 +63,20 @@ public boolean isValid(final Policy policy) {
if (getValidStoredPolicyIds().contains("*")) {
return true;
}
return policy.getPermissions()
.stream()
.anyMatch(permission -> policyList.stream()
.anyMatch(allowedPolicy -> isValid(permission, allowedPolicy)));
return policy.getPermissions().stream().allMatch(permission -> isValid(permission, policyList));
}

@NotNull
private List<PolicyDefinition> getAllowedPolicies() {
final List<String> policyIds = getValidStoredPolicyIds();
final List<PolicyDefinition> allowedPolicies = new ArrayList<>();
allowedPolicies.addAll(policyIds.stream().map(policy -> createPolicy("idsc:PURPOSE", policy)).toList());
allowedPolicies.addAll(policyIds.stream().map(policy -> createPolicy(policy, "active")).toList());
acceptedRightOperands.forEach(rightOperand -> allowedPolicies.addAll(
policyIds.stream().map(policy -> createPolicy(policy, rightOperand)).toList()));
acceptedLeftOperands.forEach(leftOperand -> allowedPolicies.addAll(
policyIds.stream().map(policy -> createPolicy(leftOperand, policy)).toList()));

return allowedPolicies;
}

@NotNull
private List<String> getValidStoredPolicyIds() {
return policyStore.getAcceptedPolicies()
.stream()
Expand All @@ -83,29 +86,50 @@ private List<String> getValidStoredPolicyIds() {
.toList();
}

private boolean isValid(final Permission permission, final PolicyDefinition policyDefinition) {
return permission.getAction().getType().equals(policyDefinition.getPermissionActionType())
&& permission.getConstraints().stream().anyMatch(constraint -> isValid(constraint, policyDefinition));
private boolean isValid(final Permission permission, final List<PolicyDefinition> policyDefinitions) {
final boolean permissionTypesMatch = policyDefinitions.stream()
.allMatch(
policyDefinition -> policyDefinition.getPermissionActionType()
.equals(permission.getAction()
.getType()));
final boolean constraintsMatch = permission.getConstraints()
.stream()
.allMatch(constraint -> isValid(constraint, policyDefinitions));
return permissionTypesMatch && constraintsMatch;
}

private boolean isValid(final Constraint constraint, final PolicyDefinition policyDefinition) {
private boolean isValid(final Constraint constraint, final List<PolicyDefinition> policyDefinitions) {
if (constraint instanceof AtomicConstraint atomicConstraint) {
return AtomicConstraintValidator.builder()
.atomicConstraint(atomicConstraint)
.leftExpressionValue(policyDefinition.getLeftExpressionValue())
.rightExpressionValue(policyDefinition.getRightExpressionValue())
.expectedOperator(
Operator.valueOf(policyDefinition.getConstraintOperator()))
.build()
.isValid();
} else if (constraint instanceof MultiplicityConstraint multiplicityConstraint) {
return multiplicityConstraint.getConstraints()
.stream()
.anyMatch(constraint1 -> isValid(constraint1, policyDefinition));
return validateAtomicConstraint(atomicConstraint, policyDefinitions);
} else if (constraint instanceof AndConstraint andConstraint) {
return andConstraint.getConstraints().stream().allMatch(constr -> isValid(constr, policyDefinitions));
} else if (constraint instanceof OrConstraint orConstraint) {
return orConstraint.getConstraints().stream().anyMatch(constr -> isValid(constr, policyDefinitions));
} else if (constraint instanceof XoneConstraint xoneConstraint) {
return xoneConstraint.getConstraints().stream().filter(constr -> isValid(constr, policyDefinitions)).count()
== 1;
}
return false;
}

private boolean validateAtomicConstraint(final AtomicConstraint atomicConstraint,
final PolicyDefinition policyDefinition) {
return AtomicConstraintValidator.builder()
.atomicConstraint(atomicConstraint)
.leftExpressionValue(policyDefinition.getLeftExpressionValue())
.rightExpressionValue(policyDefinition.getRightExpressionValue())
.expectedOperator(Operator.valueOf(policyDefinition.getConstraintOperator()))
.build()
.isValid();
}

private boolean validateAtomicConstraint(final AtomicConstraint atomicConstraint,
final List<PolicyDefinition> policyDefinitions) {
return policyDefinitions.stream()
.anyMatch(policyDefinition -> validateAtomicConstraint(atomicConstraint,
policyDefinition));
}

private PolicyDefinition createPolicy(final String leftExpression, final String rightExpression) {
return PolicyDefinition.builder()
.permissionActionType("USE")
Expand Down
Loading

0 comments on commit 66abc97

Please sign in to comment.