Skip to content

Commit

Permalink
Merge pull request #325 from bci-oss/feature/286-implement-crud-acces…
Browse files Browse the repository at this point in the history
…s-management-api__06-sql-repository

feat: Implementation of CRUD API for Access management APIs - Implement SQL repository and service
  • Loading branch information
tunacicek authored Feb 20, 2024
2 parents 655d23a + d28d43b commit 7165366
Show file tree
Hide file tree
Showing 25 changed files with 658 additions and 266 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>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<ReadUpdateAccessRule> createNewAccessRule( CreateAccessRule createAccessRule ) {
AccessRule savedRule = accessControlPersistenceService.saveRule( accessRuleMapper.map( createAccessRule ) );
return ResponseEntity.status( HttpStatus.CREATED ).body( accessRuleMapper.map( savedRule ) );
}

@Override
public ResponseEntity<Void> deleteAccessRuleByRuleId( Long ruleId ) {
accessControlPersistenceService.deleteRule( ruleId );
return ResponseEntity.status( HttpStatus.NO_CONTENT ).build();
}

@Override
public ResponseEntity<ReadUpdateAccessRule> getAccessRuleByRuleId( Long ruleId ) {
return accessControlPersistenceService.getRuleById( ruleId )
.map( accessRuleMapper::map )
.map( rule -> ResponseEntity.ok().body( rule ) )
.orElse( ResponseEntity.notFound().build() );
}

@Override
public ResponseEntity<GetAllAccessRules200Response> getAllAccessRules() {
List<ReadUpdateAccessRule> items = accessControlPersistenceService.getAllRules().stream()
.map( accessRuleMapper::map )
.toList();
GetAllAccessRules200Response response = new GetAllAccessRules200Response();
response.setItems( items );
return ResponseEntity.ok().body( response );
}

@Override
public ResponseEntity<ReadUpdateAccessRule> updateAccessRuleByRuleId( Long ruleId, ReadUpdateAccessRule readUpdateAccessRule ) {
AccessRule updatedRule = accessControlPersistenceService.updateRule( ruleId, accessRuleMapper.map( readUpdateAccessRule ) );
return ResponseEntity.ok().body( accessRuleMapper.map( updatedRule ) );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<AccessRule, Long> {

List<AccessRule> 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<AccessRule> findAllByBpnWithinValidityPeriod( String bpn, String bpnWildcard, Instant now );
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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<AccessRule> getAllRules();

Optional<AccessRule> getRuleById( Long ruleId );

AccessRule saveRule( AccessRule rule );

AccessRule updateRule( Long ruleId, AccessRule rule );

void deleteRule( Long ruleId );

}
Original file line number Diff line number Diff line change
@@ -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<AccessRule> getAllRules() {
return accessControlRuleRepository.findAll();
}

@Override
@Transactional( propagation = Propagation.REQUIRED, readOnly = true )
public Optional<AccessRule> getRuleById( Long ruleId ) {
return accessControlRuleRepository.findById( ruleId );
}

@Override
@Transactional( propagation = Propagation.REQUIRED )
public AccessRule saveRule( AccessRule rule ) {
verifyOwnerTenantId( rule );
Set<ConstraintViolation<AccessRule>> 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<ConstraintViolation<AccessRule>> 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 );
}
}
}
Loading

0 comments on commit 7165366

Please sign in to comment.