diff --git a/pom.xml b/pom.xml index 0f7ffdb..27c0e85 100644 --- a/pom.xml +++ b/pom.xml @@ -101,6 +101,12 @@ + + org.springframework + spring-test + ${spring-version} + test + org.junit.jupiter junit-jupiter-engine diff --git a/src/main/java/DNPM/config/PluginConfiguration.java b/src/main/java/DNPM/config/PluginConfiguration.java index 654d4c4..0042fe4 100644 --- a/src/main/java/DNPM/config/PluginConfiguration.java +++ b/src/main/java/DNPM/config/PluginConfiguration.java @@ -1,7 +1,6 @@ package DNPM.config; import DNPM.database.SettingsRepository; -import DNPM.security.PersonPoolBasedPermissionEvaluator; import DNPM.services.*; import DNPM.services.consent.ConsentManagerServiceFactory; import DNPM.services.mtb.DefaultMtbService; @@ -13,7 +12,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; -import org.springframework.security.access.PermissionEvaluator; import javax.sql.DataSource; @@ -23,15 +21,10 @@ import javax.sql.DataSource; * @since 0.0.2 */ @Configuration -@ComponentScan(basePackages = "DNPM.analyzer") +@ComponentScan(basePackages = { "DNPM.analyzer", "DNPM.security" }) @EnableJpaRepositories(basePackages = "DNPM.database") public class PluginConfiguration { - @Bean - public PermissionEvaluator personBasedPermissionEvaluator(final DataSource dataSource) { - return new PersonPoolBasedPermissionEvaluator(dataSource); - } - @Bean public FormService formService(final DataSource dataSource) { return new DefaultFormService(dataSource); diff --git a/src/main/java/DNPM/security/IllegalSecuredObjectAccessException.java b/src/main/java/DNPM/security/IllegalSecuredObjectAccessException.java new file mode 100644 index 0000000..542b604 --- /dev/null +++ b/src/main/java/DNPM/security/IllegalSecuredObjectAccessException.java @@ -0,0 +1,13 @@ +package DNPM.security; + +public class IllegalSecuredObjectAccessException extends RuntimeException { + + public IllegalSecuredObjectAccessException() { + super(); + } + + public IllegalSecuredObjectAccessException(String message) { + super(message); + } + +} diff --git a/src/main/java/DNPM/security/PersonPoolBasedPermissionEvaluator.java b/src/main/java/DNPM/security/PersonPoolBasedPermissionEvaluator.java index 4d895e4..2eac69c 100644 --- a/src/main/java/DNPM/security/PersonPoolBasedPermissionEvaluator.java +++ b/src/main/java/DNPM/security/PersonPoolBasedPermissionEvaluator.java @@ -6,6 +6,7 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.security.access.PermissionEvaluator; import org.springframework.security.core.Authentication; import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; import javax.sql.DataSource; import java.io.Serializable; @@ -14,6 +15,7 @@ import java.util.List; /** * Permission-Evaluator zur Auswertung der Berechtigung auf Objekte aufgrund der Personenstammberechtigung */ +@Component public class PersonPoolBasedPermissionEvaluator implements PermissionEvaluator { private final JdbcTemplate jdbcTemplate; @@ -71,7 +73,7 @@ public class PersonPoolBasedPermissionEvaluator implements PermissionEvaluator { var userDetails = (UserDetails)authentication.getPrincipal(); return jdbcTemplate - .query(sql, new Object[]{userDetails.getUsername()}, (rs, rowNum) -> rs.getString("id")); + .query(sql, new Object[]{userDetails.getUsername()}, (rs, rowNum) -> rs.getString("kennung")); } diff --git a/src/main/java/DNPM/security/PersonPoolSecured.java b/src/main/java/DNPM/security/PersonPoolSecured.java new file mode 100644 index 0000000..cac0f78 --- /dev/null +++ b/src/main/java/DNPM/security/PersonPoolSecured.java @@ -0,0 +1,14 @@ +package DNPM.security; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface PersonPoolSecured { + + PermissionType value() default PermissionType.READ_WRITE; + +} diff --git a/src/main/java/DNPM/security/PersonPoolSecuredResult.java b/src/main/java/DNPM/security/PersonPoolSecuredResult.java new file mode 100644 index 0000000..0ca8edf --- /dev/null +++ b/src/main/java/DNPM/security/PersonPoolSecuredResult.java @@ -0,0 +1,14 @@ +package DNPM.security; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface PersonPoolSecuredResult { + + PermissionType value() default PermissionType.READ_WRITE; + +} diff --git a/src/main/java/DNPM/security/SecurityAspects.java b/src/main/java/DNPM/security/SecurityAspects.java new file mode 100644 index 0000000..a1fcd3f --- /dev/null +++ b/src/main/java/DNPM/security/SecurityAspects.java @@ -0,0 +1,74 @@ +package DNPM.security; + +import de.itc.onkostar.api.Patient; +import de.itc.onkostar.api.Procedure; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; + +import java.util.Arrays; + +@Component +@Aspect +public class SecurityAspects { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final PersonPoolBasedPermissionEvaluator permissionEvaluator; + + public SecurityAspects(PersonPoolBasedPermissionEvaluator permissionEvaluator) { + this.permissionEvaluator = permissionEvaluator; + } + + @AfterReturning(value = "@annotation(PersonPoolSecuredResult) ", returning = "patient") + public void afterPatient(Patient patient) { + if ( + null != patient + && ! permissionEvaluator.hasPermission(SecurityContextHolder.getContext().getAuthentication(), patient, PermissionType.READ_WRITE) + ) { + logger.warn("Rückgabe von Patient blockiert: {}", patient.getId()); + throw new IllegalSecuredObjectAccessException(); + } + } + + @AfterReturning(value = "@annotation(PersonPoolSecuredResult)", returning = "procedure") + public void afterProcedure(Procedure procedure) { + if ( + null != procedure + && ! permissionEvaluator.hasPermission(SecurityContextHolder.getContext().getAuthentication(), procedure, PermissionType.READ_WRITE) + ) { + logger.warn("Rückgabe von Prozedur blockiert: {}", procedure.getId()); + throw new IllegalSecuredObjectAccessException(); + } + } + + @Before(value = "@annotation(PersonPoolSecured)") + public void beforePatient(JoinPoint jp) { + Arrays.stream(jp.getArgs()) + .filter(arg -> arg instanceof Patient) + .forEach(patient -> { + if (! permissionEvaluator.hasPermission(SecurityContextHolder.getContext().getAuthentication(), patient, PermissionType.READ_WRITE)) { + logger.warn("Zugriff auf Patient blockiert: {}", ((Patient)patient).getId()); + throw new IllegalSecuredObjectAccessException(); + } + }); + } + + @Before(value = "@annotation(PersonPoolSecured)") + public void beforeProcedure(JoinPoint jp) { + Arrays.stream(jp.getArgs()) + .filter(arg -> arg instanceof Procedure) + .forEach(procedure -> { + if (! permissionEvaluator.hasPermission(SecurityContextHolder.getContext().getAuthentication(), procedure, PermissionType.READ_WRITE)) { + logger.warn("Zugriff auf Prozedur blockiert: {}", ((Procedure)procedure).getId()); + throw new IllegalSecuredObjectAccessException(); + } + }); + } + +}