Skip to content

Commit

Permalink
Merge pull request #41 from consiglionazionaledellericerche/40-implem…
Browse files Browse the repository at this point in the history
…entare-endpoint-per-securecheck

40 implementare endpoint per securecheck
  • Loading branch information
criluc authored Jul 5, 2024
2 parents 2e6e5d1 + 90de2e1 commit b6f3159
Show file tree
Hide file tree
Showing 9 changed files with 389 additions and 128 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.4.1] - 2024-07-05
### Added
- API Rest per il controllo della secure.check

## [0.4.0] - 2024-06-04
### Added
- API Rest per inserimento delle assenze
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.4.0
0.4.1
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,11 @@
<version>${dbunit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jadira.usertype</groupId>
<artifactId>usertype.core</artifactId>
<version>6.0.1.GA</version>
</dependency>
</dependencies>

<build>
Expand Down
268 changes: 152 additions & 116 deletions src/main/java/it/cnr/iit/epas/controller/v4/AbsencesController.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@
import it.cnr.iit.epas.models.absences.CategoryTab;
import it.cnr.iit.epas.models.absences.GroupAbsenceType;
import it.cnr.iit.epas.models.absences.JustifiedType;
import it.cnr.iit.epas.security.SecureUtils;
import it.cnr.iit.epas.security.SecurityRules;
import java.time.LocalDate;
import java.util.HashMap;
Expand Down Expand Up @@ -118,7 +117,6 @@ public class AbsencesGroupsController {
private final AbsenceManager absenceManager;
private final PersonFinder personFinder;
private final SecurityRules rules;
private SecureUtils secureUtils;

/**
* Elenco delle assenze in un mese.
Expand Down Expand Up @@ -561,23 +559,17 @@ public ResponseEntity<Set<AbsenceTypeDto>> findCode(
personFinder.getPerson(id, fiscalCode)
.orElseThrow(() -> new EntityNotFoundException("Person not found"));

log.debug("AbsenceController::absencesInPeriod person = {}", person);

rules.checkifPermitted(person);

HashMap<String, String> categoryTab = new HashMap<String, String>();
for (CategoryTab ct : categoryTabDao.findAll()) {
log.debug("CategoryTab name {}", ct.name);
categoryTab.put(ct.getLabel(), ct.name);
}

// AbsenceForm absenceForm = absenceService.buildAbsenceForm(person, fromDate, null, null, null,
// null, true, null, null, null, null, false, false);
Set<AbsenceTypeDto> allTakableDto = Sets.newHashSet();
for (GroupAbsenceType group : absenceComponentDao.allGroupAbsenceType(false)) {
for (AbsenceType abt : group.getTakableAbsenceBehaviour().getTakableCodes()) {
if (abt.defaultTakableGroup() == null) {
log.debug("Il defaultTakable è null per {}", abt.getCode());
abt.defaultTakableGroup();
}
}
Expand All @@ -588,8 +580,6 @@ public ResponseEntity<Set<AbsenceTypeDto>> findCode(
dto = absenceFormMapper.convert(abst);
dto.setCategoryTabName(Optional.ofNullable(abst.defaultTakableGroup().category.tab.name));
allTakableDto.add(dto);
log.debug("defaultTakableGroup defaultTakableGroup {}",
abst.defaultTakableGroup().category.tab.name);
}
}

Expand Down
94 changes: 94 additions & 0 deletions src/main/java/it/cnr/iit/epas/controller/v4/SecureController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright (C) 2024 Consiglio Nazionale delle Ricerche
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package it.cnr.iit.epas.controller.v4;

import java.util.Optional;

import javax.transaction.Transactional;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.security.SecurityRequirements;
import io.swagger.v3.oas.annotations.tags.Tag;
import it.cnr.iit.epas.config.OpenApiConfiguration;
import it.cnr.iit.epas.controller.v4.utils.ApiRoutes;
import it.cnr.iit.epas.security.SecurityService;
import it.cnr.iit.epas.security.SecurityService.EntityType;
import lombok.RequiredArgsConstructor;

/**
* Metodi REST per la verifica dei permessi.
*/
@SecurityRequirements(
value = {
@SecurityRequirement(name = OpenApiConfiguration.BEARER_AUTHENTICATION),
@SecurityRequirement(name = OpenApiConfiguration.BASIC_AUTHENTICATION)
})
@Tag(
name = "Secure Controller",
description = "Controllo di sicurezza su path e riferimenti agli oggetti.")
@Transactional
@RequiredArgsConstructor
@RestController
@RequestMapping(ApiRoutes.BASE_PATH + "/secure")
public class SecureController {

private final SecurityService securityService;

/**
* Visualizzazione delle informazioni di accesso ad un controller.
*/
@Operation(
summary = "Verifica se l'utente corrente ha l'accesso ad un certo endpoint REST.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "Restituita l'autorizzazione true/false di accedere all'endpoint indicato"),
@ApiResponse(responseCode = "401",
description = "Autenticazione non presente", content = @Content),
@ApiResponse(responseCode = "403",
description = "Utente che ha effettuato la richiesta non autorizzato a visualizzare"
+ " i permessi di questo controller",
content = @Content),
@ApiResponse(responseCode = "404",
description = "Entity non trovata con l'id fornito",
content = @Content)
})
@GetMapping("/check")
public ResponseEntity<Boolean> secureCheck(
@RequestParam("method") String method,
@RequestParam("path") String path,
@RequestParam("entityType") Optional<EntityType> entityType,
@RequestParam("targetType") Optional<EntityType> targetType,
@RequestParam("id") Optional<Long> id,
@RequestParam("year") Optional<Integer> year,
@RequestParam("month") Optional<Integer> month) throws Exception {

return ResponseEntity.ok(
securityService.secureCheck(method, path, entityType, targetType, id, year, month));

}

}
6 changes: 6 additions & 0 deletions src/main/java/it/cnr/iit/epas/models/base/BaseEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.TypeDefs;
import org.hibernate.envers.NotAudited;
import org.jadira.usertype.dateandtime.joda.PersistentYearMonthAsString;
import org.joda.time.YearMonth;


/**
* Default base class per sovrascrivere la generazione delle nuove chiavi primarie.
Expand All @@ -38,6 +43,7 @@
@Getter
@Setter
@MappedSuperclass
@TypeDefs(@TypeDef(name = "YearMonth", defaultForType = YearMonth.class, typeClass = PersistentYearMonthAsString.class))
public abstract class BaseEntity implements Serializable {

private static final long serialVersionUID = 4849404810311166199L;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/it/cnr/iit/epas/security/SecurityRules.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public void checkifPermitted(Object target) {
}
}

private boolean check(String method, String permission, Object target) {
public boolean check(String method, String permission, Object target) {
// Ripuliamo la stringa dalle eventuali espressioni regolari derivanti dai path
// Es. /v1/ruoloutente/{id:^\d+$} -> /v1/ruoloutente/{id}
final String normalized = PATH_PARAMS_PATTERN.matcher(permission).replaceAll("}");
Expand Down
126 changes: 126 additions & 0 deletions src/main/java/it/cnr/iit/epas/security/SecurityService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* Copyright (C) 2024 Consiglio Nazionale delle Ricerche
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package it.cnr.iit.epas.security;

import org.joda.time.YearMonth;
import java.util.Optional;

import org.springframework.stereotype.Service;

import it.cnr.iit.epas.dao.AbsenceDao;
import it.cnr.iit.epas.dao.OfficeDao;
import it.cnr.iit.epas.dao.PersonDao;
import it.cnr.iit.epas.dao.PersonDayDao;
import it.cnr.iit.epas.models.base.BaseEntity;
import lombok.RequiredArgsConstructor;
import lombok.val;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@RequiredArgsConstructor
@Service
public class SecurityService {

public enum EntityType {
Office, Person, Absence, PersonDay, YearMonth
}

private final SecurityRules rules;

private final OfficeDao officeDao;
private final PersonDao personDao;
private final AbsenceDao absenceDao;
private final PersonDayDao personDayDao;

public Boolean secureCheck(String method, String path,
Optional<EntityType> entityType, Optional<EntityType> targetType,
Optional<Long> id, Optional<Integer> year, Optional<Integer> month
) throws Exception {

BaseEntity entity = null;
Object entityToTarget = null;

log.debug("SecurityService::secureCheck method= {}, path = {}, id = {}, year = {}, month = {},"
+ " target={}", method, path, id, year, month, entityType);

if (entityType.isPresent() && id.isPresent()) {
switch (entityType.get()) {
case Office: {
val office = officeDao.getOfficeById(id.get());
entity = office;
entityToTarget = office;
break;
}
case Person: {
val person = personDao.byId(id.get()).orElse(null);
entity = person;
if (targetType.isPresent() && targetType.get().equals(EntityType.Office)) {
entityToTarget = person.getOffice();
} else {
entityToTarget = person;
}
break;
}
case Absence: {
val absence = absenceDao.byId(id.get()).orElse(null);
entity = absence;
if (targetType.isPresent()) {
if (targetType.get().equals(EntityType.Absence)) {
entityToTarget = absence;
} else if (targetType.get().equals(EntityType.Office)) {
entityToTarget = absence.getPersonDay().getPerson().getOffice();
}
} else {
//Il default per i controlli sulle assenze è la verifica sulla Person.
entityToTarget = absence.getPersonDay().getPerson();
}
break;
}
case PersonDay: {
val personDay = personDayDao.getPersonDayById(id.get());
entity = personDay;
if (targetType.isPresent()) {
if (targetType.get().equals(EntityType.PersonDay)) {
entityToTarget = personDay;
} else if (targetType.get().equals(EntityType.Office)) {
entityToTarget = personDay.getPerson().getOffice();
}
} else {
//Il default per i controlli sui personDay è la verifica sulla Person.
entityToTarget = personDay.getPerson();
}
break;
}
case YearMonth: {
val yearMonth = new YearMonth(year.get(), month.get());
entityToTarget = yearMonth;
break;
}
default:
throw new IllegalArgumentException("Unexpected value: " + entityType.get());
}
}

log.debug("SecurityService::secureCheck method= {}, path = {}, id = {}, year = {}, month = {},"
+ "targetFromObject={}, targetToOject={}",
method, path, id, year, month, entity, entityToTarget);

//controllo le drools in base alla path, method e target
return rules.check(method, path, entityToTarget);
}

}

0 comments on commit b6f3159

Please sign in to comment.