Skip to content

Commit

Permalink
Merge pull request #306 from bci-oss/feature/287-extend-dtr-apis-for-…
Browse files Browse the repository at this point in the history
…access-management__03-add-validity-periods

feat: Extend DTR APIs for Access management - Add validity periods
  • Loading branch information
tunacicek authored Feb 6, 2024
2 parents 83085e1 + 5c2e2f2 commit 383fc18
Show file tree
Hide file tree
Showing 12 changed files with 269 additions and 32 deletions.
4 changes: 4 additions & 0 deletions access-control-service-sql-impl/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>

<!-- Tests -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

package org.eclipse.tractusx.semantics.accesscontrol.sql.model;

import java.time.Instant;

import org.eclipse.tractusx.semantics.accesscontrol.sql.model.converter.AccessRulePolicyConverter;

import jakarta.persistence.Column;
Expand Down Expand Up @@ -57,11 +59,17 @@ public enum PolicyType {
private PolicyType policyType;

@Lob
@Column( name = "policy", nullable = false)
@Column( name = "policy", nullable = false )
@Convert( converter = AccessRulePolicyConverter.class )
private AccessRulePolicy policy;

@Column( name = "description", length = 256 )
private String description;

@Column( name = "valid_from" )
private Instant validFrom;

@Column( name = "valid_to" )
private Instant validTo;

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@
@Data
public class AccessRulePolicy {

private static final String BPN_RULE_NAME = "bpn";
private static final String MANDATORY_SPECIFIC_ASSET_IDS_RULE_NAME = "mandatorySpecificAssetIds";
private static final String VISIBLE_SPECIFIC_ASSET_ID_NAMES_RULE_NAME = "visibleSpecificAssetIdNames";
private static final String VISIBLE_SEMANTIC_IDS_RULE_NAME = "visibleSemanticIds";
static final String BPN_RULE_NAME = "bpn";
static final String MANDATORY_SPECIFIC_ASSET_IDS_RULE_NAME = "mandatorySpecificAssetIds";
static final String VISIBLE_SPECIFIC_ASSET_ID_NAMES_RULE_NAME = "visibleSpecificAssetIdNames";
static final String VISIBLE_SEMANTIC_IDS_RULE_NAME = "visibleSemanticIds";

@JsonProperty( "accessRules" )
private Set<AccessRulePolicyValue> accessRules;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@

public class AccessRulePolicyConverter implements AttributeConverter<AccessRulePolicy, String> {

private final ObjectMapper objectMapper = new ObjectMapper();
private static final ObjectMapper SHARED_OBJECT_MAPPER = new ObjectMapper();

@Override
public String convertToDatabaseColumn( AccessRulePolicy attribute ) {
try {
return objectMapper.writeValueAsString( attribute );
return SHARED_OBJECT_MAPPER.writeValueAsString( attribute );
} catch ( JsonProcessingException e ) {
throw new JsonConversionException( e );
}
Expand All @@ -44,7 +44,7 @@ public String convertToDatabaseColumn( AccessRulePolicy attribute ) {
@Override
public AccessRulePolicy convertToEntityAttribute( String dbData ) {
try {
return objectMapper.readValue( dbData, AccessRulePolicy.class );
return SHARED_OBJECT_MAPPER.readValue( dbData, AccessRulePolicy.class );
} catch ( JsonProcessingException e ) {
throw new JsonConversionException( e );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@

public interface AccessControlRuleRepository {

List<AccessRule> findAllByBpn( String bpn );
List<AccessRule> findAllByBpnWithinValidityPeriod( String bpn );
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@

import java.io.IOException;
import java.nio.file.Path;
import java.time.Instant;
import java.util.List;
import java.util.Optional;

import org.eclipse.tractusx.semantics.accesscontrol.sql.model.AccessRule;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -49,10 +51,20 @@ public FileBasedAccessControlRuleRepository(
}

@Override
public List<AccessRule> findAllByBpn( String bpn ) {
public List<AccessRule> findAllByBpnWithinValidityPeriod( String bpn ) {
try {
return objectMapper.readValue( accessControlRulePath.toFile(), RULE_LIST_TYPE ).stream()
.filter( rule -> rule.getTargetTenant().equals( bpn ) )
.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 );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public Set<org.eclipse.tractusx.semantics.accesscontrol.api.model.AccessRule> fe
}

private Stream<AccessRulePolicy> findPotentiallyMatchingAccessControlRules( String bpn ) throws DenyAccessException {
List<AccessRule> allByBpn = repository.findAllByBpn( bpn );
List<AccessRule> allByBpn = repository.findAllByBpnWithinValidityPeriod( bpn );
if ( allByBpn == null || allByBpn.isEmpty() ) {
throw new DenyAccessException( "No matching rules are found." );
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*******************************************************************************
* Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH and others
*
* 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.model;

import static org.assertj.core.api.Assertions.assertThat;
import static org.eclipse.tractusx.semantics.accesscontrol.sql.model.AccessRulePolicy.*;

import java.util.Set;

import org.eclipse.tractusx.semantics.accesscontrol.api.model.SpecificAssetId;
import org.eclipse.tractusx.semantics.accesscontrol.sql.model.policy.AccessRulePolicyValue;
import org.eclipse.tractusx.semantics.accesscontrol.sql.model.policy.PolicyOperator;
import org.junit.jupiter.api.Test;

class AccessRulePolicyTest {

private static final String A = "A";
private static final String B = "B";
private static final String NAME = "name";
private static final String VALUE_1 = "1";
private static final String VALUE_2 = "2";
private static final AccessRulePolicyValue A1 = new AccessRulePolicyValue( A, PolicyOperator.EQUALS, VALUE_1, null );
private static final AccessRulePolicyValue B2 = new AccessRulePolicyValue( B, PolicyOperator.EQUALS, VALUE_2, null );
private static final AccessRulePolicyValue NAME_A = new AccessRulePolicyValue( NAME, PolicyOperator.EQUALS, A, null );
private static final AccessRulePolicyValue NAME_B = new AccessRulePolicyValue( NAME, PolicyOperator.EQUALS, B, null );
private static final AccessRulePolicyValue BPN_A = new AccessRulePolicyValue( BPN_RULE_NAME, PolicyOperator.EQUALS, A, null );
private static final AccessRulePolicyValue MANDATORY_SPECIFIC_ASSET_IDS_A1_B2 = new AccessRulePolicyValue(
MANDATORY_SPECIFIC_ASSET_IDS_RULE_NAME, PolicyOperator.INCLUDES, null, Set.of( A1, B2 ) );
private static final AccessRulePolicyValue VISIBLE_SPECIFIC_ASSET_ID_NAMES_A_B = new AccessRulePolicyValue(
VISIBLE_SPECIFIC_ASSET_ID_NAMES_RULE_NAME, PolicyOperator.INCLUDES, null, Set.of( NAME_A, NAME_B ) );
private static final AccessRulePolicyValue VISIBLE_SEMANTIC_IDS_A_B = new AccessRulePolicyValue(
VISIBLE_SEMANTIC_IDS_RULE_NAME, PolicyOperator.INCLUDES, null, Set.of( NAME_A, NAME_B ) );

@Test
void testGetMandatorySpecificAssetIdsExpectMap() {
final var underTest = new AccessRulePolicy();
underTest.setAccessRules( Set.of( MANDATORY_SPECIFIC_ASSET_IDS_A1_B2 ) );

final var actual = underTest.getMandatorySpecificAssetIds();

assertThat( actual ).hasSize( 2 )
.isEqualTo( Set.of( new SpecificAssetId( A, VALUE_1 ), new SpecificAssetId( B, VALUE_2 ) ) );
}

@Test
void testGetVisibleSpecificAssetIdNamesExpectSetOfNames() {
final var underTest = new AccessRulePolicy();
underTest.setAccessRules( Set.of( VISIBLE_SPECIFIC_ASSET_ID_NAMES_A_B ) );

final var actual = underTest.getVisibleSpecificAssetIdNames();

assertThat( actual ).hasSize( 2 )
.isEqualTo( Set.of( A, B ) );
}

@Test
void testGetVisibleSemanticIdsExpectSetOfNames() {
final var underTest = new AccessRulePolicy();
underTest.setAccessRules( Set.of( VISIBLE_SEMANTIC_IDS_A_B ) );

final var actual = underTest.getVisibleSemanticIds();

assertThat( actual ).hasSize( 2 )
.isEqualTo( Set.of( A, B ) );
}

@Test
void testGetBpnExpectSingleValue() {
final var underTest = new AccessRulePolicy();
underTest.setAccessRules( Set.of( BPN_A ) );

final var actual = underTest.getBpn();

assertThat( actual ).isEqualTo( A );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*******************************************************************************
* Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH and others
*
* 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.model.converter;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Set;

import org.eclipse.tractusx.semantics.accesscontrol.sql.model.AccessRulePolicy;
import org.eclipse.tractusx.semantics.accesscontrol.sql.model.policy.AccessRulePolicyValue;
import org.eclipse.tractusx.semantics.accesscontrol.sql.model.policy.PolicyOperator;
import org.junit.jupiter.api.Test;

class AccessRulePolicyConverterTest {
private static final AccessRulePolicyValue A_EQ_1_RULE_VALUE = new AccessRulePolicyValue( "A", PolicyOperator.EQUALS, "1", null );
private static final AccessRulePolicyValue B_EQ_2_RULE_VALUE = new AccessRulePolicyValue( "B", PolicyOperator.EQUALS, "2", null );
private static final AccessRulePolicyValue CA_EQ_1_RULE_VALUE = new AccessRulePolicyValue( "CA", PolicyOperator.EQUALS, "1", null );
private static final AccessRulePolicyValue CB_EQ_2_RULE_VALUE = new AccessRulePolicyValue( "CB", PolicyOperator.EQUALS, "2", null );
private static final AccessRulePolicyValue C_INCLUDES_CA1_AND_CB2_RULE_VALUE = new AccessRulePolicyValue( "C", PolicyOperator.INCLUDES, null,
Set.of( CA_EQ_1_RULE_VALUE, CB_EQ_2_RULE_VALUE ) );

@Test
void testConvertToEntityAttributeWithTheResultOfConvertToDatabaseColumnExpectOriginalObject() {
final var policy = new AccessRulePolicy();
policy.setAccessRules( Set.of( A_EQ_1_RULE_VALUE, B_EQ_2_RULE_VALUE, C_INCLUDES_CA1_AND_CB2_RULE_VALUE ) );
final var underTest = new AccessRulePolicyConverter();

final var columnValue = underTest.convertToDatabaseColumn( policy );
final var actual = underTest.convertToEntityAttribute( columnValue );

assertThat(actual).isEqualTo( policy );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@

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.Collectors;
import java.util.stream.Stream;

import org.assertj.core.api.Assertions;
import org.eclipse.tractusx.semantics.accesscontrol.sql.model.AccessRule;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
Expand All @@ -36,8 +36,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;

class FileBasedAccessControlRuleRepositoryTest {

private final ObjectMapper objectMapper = new ObjectMapper();
private final ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();

public static Stream<Arguments> bpnFilteringProvider() {
return Stream.<Arguments> builder()
Expand All @@ -50,22 +49,22 @@ public static Stream<Arguments> bpnFilteringProvider() {
@SuppressWarnings( "DataFlowIssue" )
@ParameterizedTest
@MethodSource( "bpnFilteringProvider" )
void testFindAllByBpnExpectFilteredResults( final String bpn, final List<String> expectedRuleIds ) {
void testFindAllByBpnWithinValidityPeriodExpectFilteredResults( final String bpn, final List<Long> expectedRuleIds ) {
final var filePath = Path.of( getClass().getResource( "/example-access-rules.json" ).getFile() );
final var underTest = new FileBasedAccessControlRuleRepository( objectMapper, filePath.toAbsolutePath().toString() );

List<AccessRule> actual = underTest.findAllByBpn( bpn );
List<AccessRule> actual = underTest.findAllByBpnWithinValidityPeriod( bpn );

final var actualIds = actual.stream().map( AccessRule::getId ).toList();
Assertions.assertThat( actualIds ).isEqualTo( expectedRuleIds );
assertThat( actualIds ).isEqualTo( expectedRuleIds );
}

@Test
void testFindAllByBpnWithMissingResourceExpectException() {
void testFindAllByBpnWithinValidityPeriodWithMissingResourceExpectException() {
final var filePath = Path.of( "unknown.json" );
final var underTest = new FileBasedAccessControlRuleRepository( objectMapper, filePath.toAbsolutePath().toString() );

Assertions.assertThatThrownBy( () -> underTest.findAllByBpn( "BPNL00000000000A" ) )
assertThatThrownBy( () -> underTest.findAllByBpnWithinValidityPeriod( "BPNL00000000000A" ) )
.isInstanceOf( DataRetrievalFailureException.class );
}
}
Loading

0 comments on commit 383fc18

Please sign in to comment.