diff --git a/access-control-service-sql-impl/pom.xml b/access-control-service-sql-impl/pom.xml
index aa98f5a6..612d4b08 100644
--- a/access-control-service-sql-impl/pom.xml
+++ b/access-control-service-sql-impl/pom.xml
@@ -74,6 +74,10 @@
org.springframework
spring-tx
+
+ org.springframework.data
+ spring-data-jpa
+
jakarta.servlet
jakarta.servlet-api
diff --git a/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/controller/AccessControlApiDelegate.java b/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/controller/AccessControlApiDelegate.java
index 462f4dcd..9a615a7d 100644
--- a/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/controller/AccessControlApiDelegate.java
+++ b/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/controller/AccessControlApiDelegate.java
@@ -20,10 +20,63 @@
package org.eclipse.tractusx.semantics.accesscontrol.sql.controller;
+import java.util.List;
+
+import org.eclipse.tractusx.semantics.accesscontrol.sql.model.AccessRule;
+import org.eclipse.tractusx.semantics.accesscontrol.sql.model.converter.AccessRuleMapper;
import org.eclipse.tractusx.semantics.accesscontrol.sql.rest.api.AccessControlsApiDelegate;
+import org.eclipse.tractusx.semantics.accesscontrol.sql.rest.model.CreateAccessRule;
+import org.eclipse.tractusx.semantics.accesscontrol.sql.rest.model.GetAllAccessRules200Response;
+import org.eclipse.tractusx.semantics.accesscontrol.sql.rest.model.ReadUpdateAccessRule;
+import org.eclipse.tractusx.semantics.accesscontrol.sql.service.AccessControlPersistenceService;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
-//TODO: must be implemented
@Service
public class AccessControlApiDelegate implements AccessControlsApiDelegate {
+
+ private final AccessControlPersistenceService accessControlPersistenceService;
+ private final AccessRuleMapper accessRuleMapper;
+
+ public AccessControlApiDelegate( final AccessControlPersistenceService accessControlPersistenceService, AccessRuleMapper accessRuleMapper ) {
+ this.accessControlPersistenceService = accessControlPersistenceService;
+ this.accessRuleMapper = accessRuleMapper;
+ }
+
+ @Override
+ public ResponseEntity createNewAccessRule( CreateAccessRule createAccessRule ) {
+ AccessRule savedRule = accessControlPersistenceService.saveRule( accessRuleMapper.map( createAccessRule ) );
+ return ResponseEntity.status( HttpStatus.CREATED ).body( accessRuleMapper.map( savedRule ) );
+ }
+
+ @Override
+ public ResponseEntity deleteAccessRuleByRuleId( Long ruleId ) {
+ accessControlPersistenceService.deleteRule( ruleId );
+ return ResponseEntity.status( HttpStatus.NO_CONTENT ).build();
+ }
+
+ @Override
+ public ResponseEntity getAccessRuleByRuleId( Long ruleId ) {
+ return accessControlPersistenceService.getRuleById( ruleId )
+ .map( accessRuleMapper::map )
+ .map( rule -> ResponseEntity.ok().body( rule ) )
+ .orElse( ResponseEntity.notFound().build() );
+ }
+
+ @Override
+ public ResponseEntity getAllAccessRules() {
+ List items = accessControlPersistenceService.getAllRules().stream()
+ .map( accessRuleMapper::map )
+ .toList();
+ GetAllAccessRules200Response response = new GetAllAccessRules200Response();
+ response.setItems( items );
+ return ResponseEntity.ok().body( response );
+ }
+
+ @Override
+ public ResponseEntity updateAccessRuleByRuleId( Long ruleId, ReadUpdateAccessRule readUpdateAccessRule ) {
+ AccessRule updatedRule = accessControlPersistenceService.updateRule( ruleId, accessRuleMapper.map( readUpdateAccessRule ) );
+ return ResponseEntity.ok().body( accessRuleMapper.map( updatedRule ) );
+ }
}
diff --git a/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/model/AccessRule.java b/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/model/AccessRule.java
index 4ee62c2d..6a1fba54 100644
--- a/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/model/AccessRule.java
+++ b/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/model/AccessRule.java
@@ -29,20 +29,22 @@
import jakarta.persistence.Column;
import jakarta.persistence.Convert;
+import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Lob;
+import jakarta.persistence.Table;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Null;
import lombok.Data;
-//@Entity
-//@Table( name = "ACCESS_RULE" )
+@Entity
+@Table( name = "ACCESS_RULE" )
@Data
@ValidValidityPeriod( groups = { OnCreate.class, OnUpdate.class } )
public class AccessRule {
diff --git a/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/model/converter/CustomAccessRuleMapper.java b/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/model/converter/CustomAccessRuleMapper.java
index a1145405..7d86bdef 100644
--- a/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/model/converter/CustomAccessRuleMapper.java
+++ b/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/model/converter/CustomAccessRuleMapper.java
@@ -20,16 +20,28 @@
package org.eclipse.tractusx.semantics.accesscontrol.sql.model.converter;
+import org.apache.commons.lang3.StringUtils;
import org.eclipse.tractusx.semantics.accesscontrol.sql.model.AccessRule;
import org.mapstruct.AfterMapping;
import org.mapstruct.MappingTarget;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class CustomAccessRuleMapper {
+ private final String ownerTenant;
+
+ public CustomAccessRuleMapper( @Value( "${registry.idm.owning-tenant-id:}" ) String ownerTenant ) {
+ this.ownerTenant = StringUtils.stripToNull( ownerTenant );
+ }
+
@AfterMapping
- public void calledWithSourceAndTarget(Object anySource, @MappingTarget AccessRule target) {
+ public void calledWithTarget( @MappingTarget AccessRule target ) {
target.setTargetTenant( target.getPolicy().getBpn() );
+ // only fill Tid if null to avoid overwrites in case of updates
+ if ( target.getTid() == null ) {
+ target.setTid( ownerTenant );
+ }
}
}
diff --git a/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/repository/AccessControlRuleRepository.java b/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/repository/AccessControlRuleRepository.java
index a5e8be33..c2db565c 100644
--- a/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/repository/AccessControlRuleRepository.java
+++ b/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/repository/AccessControlRuleRepository.java
@@ -20,11 +20,24 @@
package org.eclipse.tractusx.semantics.accesscontrol.sql.repository;
+import java.time.Instant;
import java.util.List;
import org.eclipse.tractusx.semantics.accesscontrol.sql.model.AccessRule;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
-public interface AccessControlRuleRepository {
+@Repository
+public interface AccessControlRuleRepository extends JpaRepository {
- List findAllByBpnWithinValidityPeriod( String bpn, String bpnWildcard );
+ @Query( """
+ SELECT r
+ FROM AccessRule r
+ WHERE
+ r.targetTenant IN (:bpn, :bpnWildcard)
+ AND ( r.validFrom IS NULL OR r.validFrom <= :now )
+ AND ( r.validTo IS NULL OR r.validTo >= :now )
+ """ )
+ List findAllByBpnWithinValidityPeriod( String bpn, String bpnWildcard, Instant now );
}
diff --git a/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/repository/FileBasedAccessControlRuleRepository.java b/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/repository/FileBasedAccessControlRuleRepository.java
deleted file mode 100644
index 425e01ae..00000000
--- a/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/repository/FileBasedAccessControlRuleRepository.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH and others
- * Copyright (c) 2024 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
- ******************************************************************************/
-
-package org.eclipse.tractusx.semantics.accesscontrol.sql.repository;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.time.Instant;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-
-import org.eclipse.tractusx.semantics.accesscontrol.sql.model.AccessRule;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.dao.DataRetrievalFailureException;
-import org.springframework.stereotype.Repository;
-
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-@Repository
-public class FileBasedAccessControlRuleRepository implements AccessControlRuleRepository {
-
- private static final TypeReference> RULE_LIST_TYPE = new TypeReference<>() {
- };
- private final Path accessControlRulePath;
- private final ObjectMapper objectMapper;
-
- public FileBasedAccessControlRuleRepository(
- @Autowired ObjectMapper objectMapper,
- @Value( "${ACCESS_CONTROL_RULES_PATH:access-control-rules.json}" ) String accessControlRulePath ) {
- this.accessControlRulePath = Path.of( accessControlRulePath );
- this.objectMapper = objectMapper;
- }
-
- @Override
- public List findAllByBpnWithinValidityPeriod( final String bpn, final String bpnWildcard ) {
- try {
- Set bpns = Set.of( bpn, bpnWildcard );
- return objectMapper.readValue( accessControlRulePath.toFile(), RULE_LIST_TYPE ).stream()
- .filter( rule -> bpns.contains( rule.getTargetTenant() ) )
- .filter( rule -> {
- Instant now = Instant.now();
- final var validFromIsEmptyOrInThePast = Optional.ofNullable( rule.getValidFrom() )
- .map( now::isAfter )
- .orElse( true );
- final var validToIsEmptyOrInTheFuture = Optional.ofNullable( rule.getValidTo() )
- .map( now::isBefore )
- .orElse( true );
- return validFromIsEmptyOrInThePast && validToIsEmptyOrInTheFuture;
- } )
- .toList();
- } catch ( IOException e ) {
- throw new DataRetrievalFailureException( e.getMessage(), e );
- }
- }
-}
diff --git a/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/service/AccessControlPersistenceService.java b/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/service/AccessControlPersistenceService.java
new file mode 100644
index 00000000..20422077
--- /dev/null
+++ b/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/service/AccessControlPersistenceService.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH and others
+ * Copyright (c) 2024 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
+ ******************************************************************************/
+
+package org.eclipse.tractusx.semantics.accesscontrol.sql.service;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.eclipse.tractusx.semantics.accesscontrol.sql.model.AccessRule;
+
+public interface AccessControlPersistenceService {
+
+ List getAllRules();
+
+ Optional getRuleById( Long ruleId );
+
+ AccessRule saveRule( AccessRule rule );
+
+ AccessRule updateRule( Long ruleId, AccessRule rule );
+
+ void deleteRule( Long ruleId );
+
+}
diff --git a/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/service/AccessControlPersistenceServiceImpl.java b/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/service/AccessControlPersistenceServiceImpl.java
new file mode 100644
index 00000000..a216d224
--- /dev/null
+++ b/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/service/AccessControlPersistenceServiceImpl.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH and others
+ * Copyright (c) 2024 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
+ ******************************************************************************/
+
+package org.eclipse.tractusx.semantics.accesscontrol.sql.service;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.tractusx.semantics.accesscontrol.sql.model.AccessRule;
+import org.eclipse.tractusx.semantics.accesscontrol.sql.repository.AccessControlRuleRepository;
+import org.eclipse.tractusx.semantics.accesscontrol.sql.validation.OnCreate;
+import org.eclipse.tractusx.semantics.accesscontrol.sql.validation.OnUpdate;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.ConstraintViolationException;
+import jakarta.validation.Validator;
+
+@Service
+public class AccessControlPersistenceServiceImpl implements AccessControlPersistenceService {
+
+ private final AccessControlRuleRepository accessControlRuleRepository;
+ private final Validator validator;
+ private final String ownerTenant;
+
+ public AccessControlPersistenceServiceImpl(
+ AccessControlRuleRepository accessControlRuleRepository, Validator validator,
+ @Value( "${registry.idm.owning-tenant-id:}" ) String ownerTenant ) {
+ this.accessControlRuleRepository = accessControlRuleRepository;
+ this.validator = validator;
+ this.ownerTenant = Objects.requireNonNull( StringUtils.stripToNull( ownerTenant ), "OwnerTenantId is not set!" );
+ }
+
+ @Override
+ @Transactional( propagation = Propagation.REQUIRED, readOnly = true )
+ public List getAllRules() {
+ return accessControlRuleRepository.findAll();
+ }
+
+ @Override
+ @Transactional( propagation = Propagation.REQUIRED, readOnly = true )
+ public Optional getRuleById( Long ruleId ) {
+ return accessControlRuleRepository.findById( ruleId );
+ }
+
+ @Override
+ @Transactional( propagation = Propagation.REQUIRED )
+ public AccessRule saveRule( AccessRule rule ) {
+ verifyOwnerTenantId( rule );
+ Set> violations = validator.validate( rule, OnCreate.class );
+ if ( !violations.isEmpty() ) {
+ throw new ConstraintViolationException( violations );
+ }
+ return accessControlRuleRepository.saveAndFlush( rule );
+ }
+
+ @Override
+ @Transactional( propagation = Propagation.REQUIRED )
+ public AccessRule updateRule( Long ruleId, AccessRule rule ) {
+ verifyOwnerTenantId( rule );
+ verifyRuleId( ruleId, rule );
+ Set> violations = validator.validate( rule, OnUpdate.class );
+ if ( !violations.isEmpty() ) {
+ throw new ConstraintViolationException( violations );
+ }
+ final AccessRule entity = accessControlRuleRepository.findById( ruleId )
+ .orElseThrow( () -> new IllegalStateException( "Rule with Id: " + ruleId + " cannot be updated as it does not exist!" ) );
+ entity.setTid( rule.getTid() );
+ entity.setTargetTenant( rule.getTargetTenant() );
+ entity.setPolicy( rule.getPolicy() );
+ entity.setPolicyType( rule.getPolicyType() );
+ entity.setDescription( rule.getDescription() );
+ entity.setValidFrom( rule.getValidFrom() );
+ entity.setValidTo( rule.getValidTo() );
+ return accessControlRuleRepository.saveAndFlush( entity );
+ }
+
+ @Override
+ @Transactional( propagation = Propagation.REQUIRED )
+ public void deleteRule( Long ruleId ) {
+ accessControlRuleRepository.deleteById( ruleId );
+ }
+
+ private void verifyRuleId( Long ruleId, AccessRule rule ) {
+ if ( !Objects.equals( rule.getId(), ruleId ) ) {
+ throw new IllegalArgumentException( "RuleId must match the rule.id value!" );
+ }
+ }
+
+ private void verifyOwnerTenantId( AccessRule rule ) {
+ if ( !Objects.equals( rule.getTid(), ownerTenant ) ) {
+ throw new IllegalArgumentException( "TenantId must match the Id of the owner tenant: " + ownerTenant );
+ }
+ }
+}
diff --git a/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/service/SqlBackedAccessControlRuleService.java b/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/service/SqlBackedAccessControlRuleService.java
index 2095211f..51c857f2 100644
--- a/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/service/SqlBackedAccessControlRuleService.java
+++ b/access-control-service-sql-impl/src/main/java/org/eclipse/tractusx/semantics/accesscontrol/sql/service/SqlBackedAccessControlRuleService.java
@@ -20,6 +20,7 @@
package org.eclipse.tractusx.semantics.accesscontrol.sql.service;
+import java.time.Instant;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -37,11 +38,15 @@
import org.eclipse.tractusx.semantics.accesscontrol.sql.model.AccessRule;
import org.eclipse.tractusx.semantics.accesscontrol.sql.model.AccessRulePolicy;
import org.eclipse.tractusx.semantics.accesscontrol.sql.repository.AccessControlRuleRepository;
+import org.springframework.dao.DataAccessException;
import lombok.NonNull;
+import lombok.extern.slf4j.Slf4j;
+@Slf4j
public class SqlBackedAccessControlRuleService implements AccessControlRuleService {
+ private static final String NO_MATCHING_RULES_ARE_FOUND = "No matching rules are found.";
private final AccessControlRuleRepository repository;
private final String bpnWildcard;
@@ -97,11 +102,16 @@ public Map fetchVisibilityCriteriaForShells( Li
}
private Stream findPotentiallyMatchingAccessControlRules( String bpn ) throws DenyAccessException {
- List allByBpn = repository.findAllByBpnWithinValidityPeriod( bpn, bpnWildcard );
- if ( allByBpn == null || allByBpn.isEmpty() ) {
- throw new DenyAccessException( "No matching rules are found." );
+ try {
+ List allByBpn = repository.findAllByBpnWithinValidityPeriod( bpn, bpnWildcard, Instant.now() );
+ if ( allByBpn == null || allByBpn.isEmpty() ) {
+ throw new DenyAccessException( NO_MATCHING_RULES_ARE_FOUND );
+ }
+ return allByBpn.stream().map( AccessRule::getPolicy ).filter( policy -> !policy.getMandatorySpecificAssetIds().isEmpty() );
+ } catch ( DataAccessException e ) {
+ log.error( "Failed to fetch rules for BPN: " + bpn, e.getMessage() );
+ throw new DenyAccessException( NO_MATCHING_RULES_ARE_FOUND );
}
- return allByBpn.stream().map( AccessRule::getPolicy );
}
private Set findMatchingAccessControlRules( ShellVisibilityContext shellContext, String bpn ) throws DenyAccessException {
@@ -109,9 +119,8 @@ private Set findMatchingAccessControlRules( ShellVisibilityCon
.filter( accessControlRule -> shellContext.specificAssetIds().containsAll( accessControlRule.getMandatorySpecificAssetIds() ) )
.collect( Collectors.toSet() );
if ( matching.isEmpty() ) {
- throw new DenyAccessException( "No matching rules are found." );
+ throw new DenyAccessException( NO_MATCHING_RULES_ARE_FOUND );
}
return matching;
}
-
}
diff --git a/access-control-service-sql-impl/src/main/resources/static/access-control-openapi_schemas.yaml b/access-control-service-sql-impl/src/main/resources/static/access-control-openapi_schemas.yaml
index a476b692..f9026591 100644
--- a/access-control-service-sql-impl/src/main/resources/static/access-control-openapi_schemas.yaml
+++ b/access-control-service-sql-impl/src/main/resources/static/access-control-openapi_schemas.yaml
@@ -29,9 +29,8 @@ schemas:
description: The Id of the provider tenant
minLength: 1
maxLength: 36
- pattern: "^[0-9]{8}-[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{12}$"
type: string
- example: "00000000-1111-2222-3333-444444444444"
+ example: "BPNL00000000000B"
PolicyType:
description: Type of the policy. Only AAS supported.
type: string
@@ -80,6 +79,8 @@ schemas:
type: string
operator:
$ref: "#/schemas/OperatorType"
+ value:
+ type: string
values:
type: array
items:
@@ -89,7 +90,6 @@ schemas:
required:
- attribute
- operator
- - values
additionalProperties: false
AasPolicy:
description: Describes an AAS policy
@@ -99,9 +99,7 @@ schemas:
type: array
description: The components of the Access Rule Policy
items:
- "anyOf":
- - { $ref: "#/schemas/AccessRuleValue" }
- - { $ref: "#/schemas/AccessRuleValues" }
+ $ref: "#/schemas/AccessRuleValues"
minLength: 1
uniqueItems: true
required:
diff --git a/access-control-service-sql-impl/src/test/java/org/eclipse/tractusx/semantics/accesscontrol/sql/model/converter/AccessRuleMapperTest.java b/access-control-service-sql-impl/src/test/java/org/eclipse/tractusx/semantics/accesscontrol/sql/model/converter/AccessRuleMapperTest.java
index 76d3bb80..9c3d7569 100644
--- a/access-control-service-sql-impl/src/test/java/org/eclipse/tractusx/semantics/accesscontrol/sql/model/converter/AccessRuleMapperTest.java
+++ b/access-control-service-sql-impl/src/test/java/org/eclipse/tractusx/semantics/accesscontrol/sql/model/converter/AccessRuleMapperTest.java
@@ -36,8 +36,8 @@
import org.eclipse.tractusx.semantics.accesscontrol.sql.model.policy.AccessRulePolicyValue;
import org.eclipse.tractusx.semantics.accesscontrol.sql.model.policy.PolicyOperator;
import org.eclipse.tractusx.semantics.accesscontrol.sql.rest.model.AasPolicy;
-import org.eclipse.tractusx.semantics.accesscontrol.sql.rest.model.AasPolicyAccessRulesInner;
import org.eclipse.tractusx.semantics.accesscontrol.sql.rest.model.AccessRuleValue;
+import org.eclipse.tractusx.semantics.accesscontrol.sql.rest.model.AccessRuleValues;
import org.eclipse.tractusx.semantics.accesscontrol.sql.rest.model.CreateAccessRule;
import org.eclipse.tractusx.semantics.accesscontrol.sql.rest.model.OperatorType;
import org.eclipse.tractusx.semantics.accesscontrol.sql.rest.model.PolicyType;
@@ -58,7 +58,7 @@ class AccessRuleMapperTest {
private static final OffsetDateTime NOW_DATE = NOW.atOffset( ZoneOffset.UTC );
private static final OffsetDateTime ONE_MINUTE_AGO_DATE = ONE_MINUTE_AGO.atOffset( ZoneOffset.UTC );
- private final AccessRuleMapper underTest = new AccessRuleMapperImpl( new CustomAccessRuleMapper() );
+ private final AccessRuleMapper underTest = new AccessRuleMapperImpl( new CustomAccessRuleMapper(INPUT_BPNA) );
@Test
void testMapCreateAccessRuleWithFullyPopulatedDataExpectSuccess() {
@@ -74,7 +74,7 @@ void testMapCreateAccessRuleWithFullyPopulatedDataExpectSuccess() {
assertThat( actual )
.isNotNull()
.hasFieldOrPropertyWithValue( "id", null )
- .hasFieldOrPropertyWithValue( "tid", null )
+ .hasFieldOrPropertyWithValue( "tid", INPUT_BPNA )
.hasFieldOrPropertyWithValue( "targetTenant", INPUT_BPNA )
.hasFieldOrPropertyWithValue( "policyType", AccessRule.PolicyType.AAS )
.hasFieldOrPropertyWithValue( "description", INPUT_DESCRIPTION )
@@ -101,7 +101,7 @@ void testMapCreateAccessRuleWithMinimallyPopulatedDataExpectSuccess() {
assertThat( actual )
.isNotNull()
.hasFieldOrPropertyWithValue( "id", null )
- .hasFieldOrPropertyWithValue( "tid", null )
+ .hasFieldOrPropertyWithValue( "tid", INPUT_BPNA )
.hasFieldOrPropertyWithValue( "targetTenant", INPUT_BPNA )
.hasFieldOrPropertyWithValue( "policyType", AccessRule.PolicyType.AAS )
.hasFieldOrPropertyWithValue( "description", null )
@@ -202,16 +202,16 @@ void testMapReadAccessRuleWithFullyPopulatedDataExpectSuccess() {
assertThat( actual.getPolicy().getAccessRules() )
.isNotNull()
.hasSize( 4 )
- .contains( new AasPolicyAccessRulesInner().attribute( BPN_RULE_NAME ).operator( OperatorType.EQ ).value( INPUT_BPNB ).values( null ) )
- .contains( new AasPolicyAccessRulesInner().attribute( MANDATORY_SPECIFIC_ASSET_IDS_RULE_NAME ).operator( OperatorType.INCLUDES ).values(
+ .contains( new AccessRuleValues().attribute( BPN_RULE_NAME ).operator( OperatorType.EQ ).value( INPUT_BPNB ) )
+ .contains( new AccessRuleValues().attribute( MANDATORY_SPECIFIC_ASSET_IDS_RULE_NAME ).operator( OperatorType.INCLUDES ).values(
INPUT_MANDATORY_SPEC_ASSET_IDS.entrySet().stream()
.map( entry -> new AccessRuleValue().attribute( entry.getKey() ).operator( OperatorType.EQ ).value( entry.getValue() ) )
.collect( Collectors.toSet() ) ) )
- .contains( new AasPolicyAccessRulesInner().attribute( VISIBLE_SPECIFIC_ASSET_ID_NAMES_RULE_NAME ).operator( OperatorType.INCLUDES ).values(
+ .contains( new AccessRuleValues().attribute( VISIBLE_SPECIFIC_ASSET_ID_NAMES_RULE_NAME ).operator( OperatorType.INCLUDES ).values(
INPUT_VISIBLE_SPEC_ASSET_ID_NAMES.stream()
.map( item -> new AccessRuleValue().attribute( "name" ).operator( OperatorType.EQ ).value( item ) )
.collect( Collectors.toSet() ) ) )
- .contains( new AasPolicyAccessRulesInner().attribute( VISIBLE_SEMANTIC_IDS_RULE_NAME ).operator( OperatorType.INCLUDES ).values(
+ .contains( new AccessRuleValues().attribute( VISIBLE_SEMANTIC_IDS_RULE_NAME ).operator( OperatorType.INCLUDES ).values(
INPUT_VISIBLE_SEMANTIC_IDS.stream()
.map( item -> new AccessRuleValue().attribute( "modelUrn" ).operator( OperatorType.EQ ).value( item ) )
.collect( Collectors.toSet() ) ) );
@@ -238,30 +238,30 @@ void testMapReadAccessRuleWithMinimallyPopulatedDataExpectSuccess() {
assertThat( actual.getPolicy().getAccessRules() )
.isNotNull()
.hasSize( 4 )
- .contains( new AasPolicyAccessRulesInner().attribute( BPN_RULE_NAME ).operator( OperatorType.EQ ).value( INPUT_BPNB ).values( null ) )
- .contains( new AasPolicyAccessRulesInner().attribute( MANDATORY_SPECIFIC_ASSET_IDS_RULE_NAME ).operator( OperatorType.INCLUDES ).values(
+ .contains( new AccessRuleValues().attribute( BPN_RULE_NAME ).operator( OperatorType.EQ ).value( INPUT_BPNB ) )
+ .contains( new AccessRuleValues().attribute( MANDATORY_SPECIFIC_ASSET_IDS_RULE_NAME ).operator( OperatorType.INCLUDES ).values(
INPUT_MANDATORY_SPEC_ASSET_IDS.entrySet().stream()
.map( entry -> new AccessRuleValue().attribute( entry.getKey() ).operator( OperatorType.EQ ).value( entry.getValue() ) )
.collect( Collectors.toSet() ) ) )
- .contains(new AasPolicyAccessRulesInner().attribute( VISIBLE_SPECIFIC_ASSET_ID_NAMES_RULE_NAME )
+ .contains(new AccessRuleValues().attribute( VISIBLE_SPECIFIC_ASSET_ID_NAMES_RULE_NAME )
.operator( OperatorType.INCLUDES ).values( Set.of() ) )
- .contains( new AasPolicyAccessRulesInner().attribute( VISIBLE_SEMANTIC_IDS_RULE_NAME )
+ .contains( new AccessRuleValues().attribute( VISIBLE_SEMANTIC_IDS_RULE_NAME )
.operator( OperatorType.INCLUDES ).values( Set.of() ) );
}
@SuppressWarnings( "SameParameterValue" )
private AasPolicy generatePolicy( String bpn, Map msaId, Set vsaId, Set semId ) {
return new AasPolicy()
- .addAccessRulesItem( new AasPolicyAccessRulesInner().attribute( BPN_RULE_NAME ).operator( OperatorType.EQ ).value( bpn ) )
- .addAccessRulesItem( new AasPolicyAccessRulesInner().attribute( MANDATORY_SPECIFIC_ASSET_IDS_RULE_NAME ).values(
+ .addAccessRulesItem( new AccessRuleValues().attribute( BPN_RULE_NAME ).operator( OperatorType.EQ ).value( bpn ) )
+ .addAccessRulesItem( new AccessRuleValues().attribute( MANDATORY_SPECIFIC_ASSET_IDS_RULE_NAME ).values(
msaId.entrySet().stream()
.map( entity -> new AccessRuleValue().attribute( entity.getKey() ).operator( OperatorType.EQ ).value( entity.getValue() ) )
.collect( Collectors.toSet() ) ) )
- .addAccessRulesItem( new AasPolicyAccessRulesInner().attribute( VISIBLE_SPECIFIC_ASSET_ID_NAMES_RULE_NAME ).values(
+ .addAccessRulesItem( new AccessRuleValues().attribute( VISIBLE_SPECIFIC_ASSET_ID_NAMES_RULE_NAME ).values(
vsaId.stream()
.map( item -> new AccessRuleValue().attribute( "name" ).operator( OperatorType.EQ ).value( item ) )
.collect( Collectors.toSet() ) ) )
- .addAccessRulesItem( new AasPolicyAccessRulesInner().attribute( VISIBLE_SEMANTIC_IDS_RULE_NAME ).values(
+ .addAccessRulesItem( new AccessRuleValues().attribute( VISIBLE_SEMANTIC_IDS_RULE_NAME ).values(
semId.stream()
.map( item -> new AccessRuleValue().attribute( "modelUrn" ).operator( OperatorType.EQ ).value( item ) )
.collect( Collectors.toSet() ) ) );
diff --git a/access-control-service-sql-impl/src/test/java/org/eclipse/tractusx/semantics/accesscontrol/sql/repository/FileBasedAccessControlRuleRepositoryTest.java b/access-control-service-sql-impl/src/test/java/org/eclipse/tractusx/semantics/accesscontrol/sql/repository/FileBasedAccessControlRuleRepositoryTest.java
deleted file mode 100644
index eb9bf1d7..00000000
--- a/access-control-service-sql-impl/src/test/java/org/eclipse/tractusx/semantics/accesscontrol/sql/repository/FileBasedAccessControlRuleRepositoryTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH and others
- * Copyright (c) 2024 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
- ******************************************************************************/
-
-package org.eclipse.tractusx.semantics.accesscontrol.sql.repository;
-
-import static org.assertj.core.api.Assertions.*;
-
-import java.nio.file.Path;
-import java.util.List;
-import java.util.stream.Stream;
-
-import org.eclipse.tractusx.semantics.accesscontrol.sql.model.AccessRule;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.Arguments;
-import org.junit.jupiter.params.provider.MethodSource;
-import org.springframework.dao.DataRetrievalFailureException;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-class FileBasedAccessControlRuleRepositoryTest {
-
- private static final String PUBLIC_READABLE = "PUBLIC_READABLE";
- private final ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();
-
- public static Stream bpnFilteringProvider() {
- return Stream. builder()
- .add( Arguments.of( "BPNL00000000000A", List.of( 1L, 3L ) ) )
- .add( Arguments.of( "BPNL00000000000B", List.of() ) )
- .add( Arguments.of( "BPNL00000000000C", List.of( 2L ) ) )
- .build();
- }
-
- @SuppressWarnings( "DataFlowIssue" )
- @ParameterizedTest
- @MethodSource( "bpnFilteringProvider" )
- void testFindAllByBpnWithinValidityPeriodExpectFilteredResults( final String bpn, final List expectedRuleIds ) {
- final var filePath = Path.of( getClass().getResource( "/example-access-rules.json" ).getFile() );
- final var underTest = new FileBasedAccessControlRuleRepository( objectMapper, filePath.toAbsolutePath().toString() );
-
- List actual = underTest.findAllByBpnWithinValidityPeriod( bpn, PUBLIC_READABLE );
-
- final var actualIds = actual.stream().map( AccessRule::getId ).toList();
- assertThat( actualIds ).isEqualTo( expectedRuleIds );
- }
-
- @Test
- void testFindAllByBpnWithinValidityPeriodWithMissingResourceExpectException() {
- final var filePath = Path.of( "unknown.json" );
- final var underTest = new FileBasedAccessControlRuleRepository( objectMapper, filePath.toAbsolutePath().toString() );
-
- assertThatThrownBy( () -> underTest.findAllByBpnWithinValidityPeriod( "BPNL00000000000A", PUBLIC_READABLE ) )
- .isInstanceOf( DataRetrievalFailureException.class );
- }
-}
\ No newline at end of file
diff --git a/access-control-service-sql-impl/src/test/java/org/eclipse/tractusx/semantics/accesscontrol/sql/service/SqlBackedAccessControlRuleServiceTest.java b/access-control-service-sql-impl/src/test/java/org/eclipse/tractusx/semantics/accesscontrol/sql/service/SqlBackedAccessControlRuleServiceTest.java
index fbefd32e..1c44c853 100644
--- a/access-control-service-sql-impl/src/test/java/org/eclipse/tractusx/semantics/accesscontrol/sql/service/SqlBackedAccessControlRuleServiceTest.java
+++ b/access-control-service-sql-impl/src/test/java/org/eclipse/tractusx/semantics/accesscontrol/sql/service/SqlBackedAccessControlRuleServiceTest.java
@@ -21,19 +21,25 @@
package org.eclipse.tractusx.semantics.accesscontrol.sql.service;
import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
-import java.nio.file.Path;
+import java.io.File;
+import java.io.IOException;
+import java.time.Instant;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import java.util.UUID;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.tractusx.semantics.accesscontrol.api.exception.DenyAccessException;
import org.eclipse.tractusx.semantics.accesscontrol.api.model.ShellVisibilityContext;
import org.eclipse.tractusx.semantics.accesscontrol.api.model.SpecificAssetId;
+import org.eclipse.tractusx.semantics.accesscontrol.sql.model.AccessRule;
import org.eclipse.tractusx.semantics.accesscontrol.sql.repository.AccessControlRuleRepository;
-import org.eclipse.tractusx.semantics.accesscontrol.sql.repository.FileBasedAccessControlRuleRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
@@ -59,7 +65,6 @@ class SqlBackedAccessControlRuleServiceTest {
private static final SpecificAssetId REVISION_NUMBER_02 = new SpecificAssetId( REVISION_NUMBER, "02" );
private static final String BPNA = "BPNL00000000000A";
private static final String BPNB = "BPNL00000000000B";
- private static final String BPNC = "BPNL00000000000C";
private static final String TRACEABILITYV_1_1_0 = "Traceability" + "v1.1.0";
private static final String PRODUCT_CARBON_FOOTPRINTV_1_1_0 = "ProductCarbonFootprintv1.1.0";
private SqlBackedAccessControlRuleService underTest;
@@ -102,10 +107,24 @@ public static Stream matchingSpecificAssetIdVisibilityProvider() {
}
@BeforeEach
- void setUp() {
+ void setUp() throws IOException {
ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();
- final var filePath = Path.of( getClass().getResource( "/example-access-rules.json" ).getFile() );
- AccessControlRuleRepository repository = new FileBasedAccessControlRuleRepository( objectMapper, filePath.toAbsolutePath().toString() );
+ final var file = new File( Objects.requireNonNull( getClass().getResource( "/example-access-rules.json" ) ).getFile() );
+ final List allRules = objectMapper.readerForListOf( AccessRule.class ).readValue( file );
+ final var rulesByBpn = allRules.stream()
+ .filter( rule -> rule.getValidFrom() == null || rule.getValidFrom().isBefore( Instant.now() ) )
+ .filter( rule -> rule.getValidTo() == null || rule.getValidTo().isAfter( Instant.now() ) )
+ .collect( Collectors.groupingBy( AccessRule::getTargetTenant ) );
+ AccessControlRuleRepository repository = mock();
+ when( repository.findAll() ).thenReturn( allRules );
+ when( repository.findAllByBpnWithinValidityPeriod( anyString(), anyString(), any( Instant.class ) ) )
+ .thenAnswer( invocationOnMock -> {
+ String bpn = invocationOnMock.getArgument( 0, String.class );
+ String wildcard = invocationOnMock.getArgument( 1, String.class );
+ return Stream.of( bpn, wildcard )
+ .flatMap( key -> rulesByBpn.getOrDefault( key, Collections.emptyList() ).stream() )
+ .toList();
+ } );
underTest = new SqlBackedAccessControlRuleService( repository, "PUBLIC_READABLE" );
}
diff --git a/backend/pom.xml b/backend/pom.xml
index 84527807..b03f05bf 100644
--- a/backend/pom.xml
+++ b/backend/pom.xml
@@ -73,6 +73,10 @@
+
+ org.hibernate.validator
+ hibernate-validator
+
jakarta.validation
jakarta.validation-api
diff --git a/backend/src/main/java/org/eclipse/tractusx/semantics/ApiExceptionHandler.java b/backend/src/main/java/org/eclipse/tractusx/semantics/ApiExceptionHandler.java
index 3107e3ad..272d1fa5 100644
--- a/backend/src/main/java/org/eclipse/tractusx/semantics/ApiExceptionHandler.java
+++ b/backend/src/main/java/org/eclipse/tractusx/semantics/ApiExceptionHandler.java
@@ -22,6 +22,7 @@
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -43,6 +44,7 @@
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import jakarta.servlet.http.HttpServletRequest;
+import jakarta.validation.ConstraintViolationException;
@ControllerAdvice
public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
@@ -98,7 +100,19 @@ public ResponseEntity
+
+ org.hibernate.validator
+ hibernate-validator
+ 8.0.1.Final
+
jakarta.servlet
jakarta.servlet-api
@@ -300,12 +305,6 @@
${junit.version}
test
-
- org.hibernate.validator
- hibernate-validator
- 8.0.1.Final
- test
-
org.apache.tomcat.embed
tomcat-embed-el