Code development platform for open source projects from the European Union institutions :large_blue_circle: EU Login authentication by SMS has been phased out. To see alternatives please check here

Skip to content
Snippets Groups Projects
Commit 802a5361 authored by Flavio Ferraioli's avatar Flavio Ferraioli
Browse files

Merge branch 'release' into 'main'

RC 0.5.0

See merge request !99
parents 70172ff4 b1092beb
No related branches found
No related tags found
2 merge requests!139Feature/align,!99RC 0.5.0
Pipeline #210903 passed with warnings
Showing
with 484 additions and 48 deletions
PROJECT_VERSION_NUMBER="0.0.4" PROJECT_VERSION_NUMBER="0.5.0"
...@@ -7,29 +7,30 @@ ...@@ -7,29 +7,30 @@
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.1</version> <version>3.3.2</version>
<relativePath/> <!-- lookup parent from repository --> <relativePath/> <!-- lookup parent from repository -->
</parent> </parent>
<groupId>com.aruba.simpl</groupId> <groupId>com.aruba.simpl</groupId>
<artifactId>simpl-parent</artifactId> <artifactId>simpl-parent</artifactId>
<version>0.0.4-SNAPSHOT</version> <version>0.5.0-RC</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<properties> <properties>
<java.version>17</java.version> <java.version>21</java.version>
<spring-cloud.version>2023.0.3</spring-cloud.version> <spring-cloud.version>2023.0.3</spring-cloud.version>
<mapstruct.version>1.5.5.Final</mapstruct.version> <mapstruct.version>1.5.5.Final</mapstruct.version>
<lombok-mapstruct.version>0.2.0</lombok-mapstruct.version> <lombok-mapstruct.version>0.2.0</lombok-mapstruct.version>
<springdoc.version>2.6.0</springdoc.version> <springdoc.version>2.6.0</springdoc.version>
<bouncycastle.version>1.78.1</bouncycastle.version> <bouncycastle.version>1.78.1</bouncycastle.version>
<keycloak-admin.version>24.0.5</keycloak-admin.version> <keycloak-admin.version>25.0.5</keycloak-admin.version>
<jug.version>5.1.0</jug.version> <jug.version>5.1.0</jug.version>
<dagger.version>2.51.1</dagger.version>
<instancio.version>4.8.1</instancio.version> <instancio.version>4.8.1</instancio.version>
<wiremock.version>3.9.1</wiremock.version> <wiremock.version>3.9.1</wiremock.version>
<spotless.version>2.43.0</spotless.version> <spotless.version>2.43.0</spotless.version>
<spring-shell.version>3.3.1</spring-shell.version> <spring-shell.version>3.3.1</spring-shell.version>
<simpl.common.logging.version>1.0.0-SNAPSHOT.39.1a139b97</simpl.common.logging.version>
<simpl.httpclient.version>${project.version}</simpl.httpclient.version>
</properties> </properties>
<modules> <modules>
...@@ -50,21 +51,36 @@ ...@@ -50,21 +51,36 @@
<artifactId>simpl-commons-data</artifactId> <artifactId>simpl-commons-data</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency> <dependency>
<groupId>com.aruba.simpl</groupId> <groupId>com.aruba.simpl</groupId>
<artifactId>certificate-revocation-common</artifactId> <artifactId>certificate-revocation-common</artifactId>
<version>${project.version}</version> <version>${simpl.httpclient.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.aruba.simpl</groupId> <groupId>com.aruba.simpl</groupId>
<artifactId>simpl-http-client</artifactId> <artifactId>simpl-http-client</artifactId>
<version>${project.version}</version> <version>${simpl.httpclient.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.aruba.simpl</groupId> <groupId>com.aruba.simpl</groupId>
<artifactId>simpl-test-lib</artifactId> <artifactId>simpl-test-lib</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>eu.simpl</groupId>
<artifactId>SIMPL_COMMON_LOGGING</artifactId>
<version>${simpl.common.logging.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.springdoc</groupId> <groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
...@@ -98,11 +114,6 @@ ...@@ -98,11 +114,6 @@
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
<dependency>
<groupId>com.google.dagger</groupId>
<artifactId>dagger</artifactId>
<version>${dagger.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.fasterxml.uuid</groupId> <groupId>com.fasterxml.uuid</groupId>
<artifactId>java-uuid-generator</artifactId> <artifactId>java-uuid-generator</artifactId>
...@@ -190,6 +201,25 @@ ...@@ -190,6 +201,25 @@
</compilerArgs> </compilerArgs>
</configuration> </configuration>
</plugin> </plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.12</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins> </plugins>
</pluginManagement> </pluginManagement>
...@@ -198,6 +228,10 @@ ...@@ -198,6 +228,10 @@
<groupId>com.diffplug.spotless</groupId> <groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId> <artifactId>spotless-maven-plugin</artifactId>
</plugin> </plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
</plugin>
</plugins> </plugins>
</build> </build>
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>com.aruba.simpl</groupId> <groupId>com.aruba.simpl</groupId>
<artifactId>simpl-parent</artifactId> <artifactId>simpl-parent</artifactId>
<version>0.0.4-SNAPSHOT</version> <version>0.5.0-RC</version>
</parent> </parent>
<artifactId>simpl-commons-data</artifactId> <artifactId>simpl-commons-data</artifactId>
......
package com.aruba.simpl.common.model.dto; package com.aruba.simpl.common.model.dto;
import java.time.LocalDate; import java.time.Instant;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
...@@ -8,5 +8,5 @@ import lombok.experimental.Accessors; ...@@ -8,5 +8,5 @@ import lombok.experimental.Accessors;
@Accessors(chain = true) @Accessors(chain = true)
public class CertificateDTO { public class CertificateDTO {
private String publicKey; private String publicKey;
private LocalDate expiryDate; private Instant expiryDate;
} }
package com.aruba.simpl.common.model.dto; package com.aruba.simpl.common.model.dto;
import com.aruba.simpl.common.model.enums.ParticipantType; import com.aruba.simpl.common.model.enums.ParticipantType;
import com.aruba.simpl.common.model.validators.CreateOperation;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.time.Instant; import java.time.Instant;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
...@@ -18,19 +18,19 @@ public class IdentityAttributeDTO { ...@@ -18,19 +18,19 @@ public class IdentityAttributeDTO {
private UUID id; private UUID id;
@NotBlank(groups = CreateOperation.class) @NotBlank
private String code; private String code;
@NotBlank(groups = CreateOperation.class) @NotBlank
private String name; private String name;
private String description; private String description;
@Getter(AccessLevel.NONE) @Getter(AccessLevel.NONE)
private Boolean assignableToRoles; @NotNull private Boolean assignableToRoles;
@Getter(AccessLevel.NONE) @Getter(AccessLevel.NONE)
private Boolean enabled; @NotNull private Boolean enabled;
private Instant creationTimestamp; private Instant creationTimestamp;
......
...@@ -2,11 +2,9 @@ package com.aruba.simpl.common.model.dto; ...@@ -2,11 +2,9 @@ package com.aruba.simpl.common.model.dto;
import com.aruba.simpl.common.model.enums.ParticipantType; import com.aruba.simpl.common.model.enums.ParticipantType;
import com.aruba.simpl.common.model.enums.Status; import com.aruba.simpl.common.model.enums.Status;
import com.aruba.simpl.common.model.validators.CreateOperation;
import jakarta.validation.constraints.Email; import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDate;
import java.util.UUID; import java.util.UUID;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
...@@ -17,12 +15,12 @@ public class ParticipantDTO { ...@@ -17,12 +15,12 @@ public class ParticipantDTO {
private UUID id; private UUID id;
@Email() @Email
private String userEmail; private String userEmail;
private ParticipantType participantType; private ParticipantType participantType;
@NotBlank(groups = CreateOperation.class) @NotBlank
private String organization; private String organization;
private Status status; private Status status;
...@@ -35,5 +33,5 @@ public class ParticipantDTO { ...@@ -35,5 +33,5 @@ public class ParticipantDTO {
private String certificateId; private String certificateId;
private LocalDate expiryDate; private Instant expiryDate;
} }
package com.aruba.simpl.common.model.validators; package com.aruba.simpl.common.model.validators;
public interface CreateOperation {} import jakarta.validation.groups.Default;
public interface CreateOperation extends Default {}
package com.aruba.simpl.common.model.validators; package com.aruba.simpl.common.model.validators;
public interface UpdateOperation {} import jakarta.validation.groups.Default;
public interface UpdateOperation extends Default {}
...@@ -7,14 +7,14 @@ ...@@ -7,14 +7,14 @@
<parent> <parent>
<groupId>com.aruba.simpl</groupId> <groupId>com.aruba.simpl</groupId>
<artifactId>simpl-parent</artifactId> <artifactId>simpl-parent</artifactId>
<version>0.0.4-SNAPSHOT</version> <version>0.5.0-RC</version>
</parent> </parent>
<artifactId>simpl-spring-boot-starter</artifactId> <artifactId>simpl-spring-boot-starter</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<properties> <properties>
<spring-boot-processor.version>3.3.1</spring-boot-processor.version> <spring-boot-processor.version>3.3.2</spring-boot-processor.version>
</properties> </properties>
<dependencies> <dependencies>
...@@ -22,11 +22,29 @@ ...@@ -22,11 +22,29 @@
<groupId>com.aruba.simpl</groupId> <groupId>com.aruba.simpl</groupId>
<artifactId>simpl-commons-data</artifactId> <artifactId>simpl-commons-data</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.aruba.simpl</groupId>
<artifactId>simpl-http-client</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>eu.simpl</groupId>
<artifactId>SIMPL_COMMON_LOGGING</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<optional>true</optional>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId> <artifactId>spring-boot-starter-data-redis</artifactId>
...@@ -47,6 +65,11 @@ ...@@ -47,6 +65,11 @@
<artifactId>spring-boot-starter-data-jpa</artifactId> <artifactId>spring-boot-starter-data-jpa</artifactId>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<optional>true</optional>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId> <artifactId>spring-boot-starter-security</artifactId>
...@@ -105,4 +128,15 @@ ...@@ -105,4 +128,15 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<repositories>
<repository>
<id>simpl-http-client-library</id>
<url>https://code.europa.eu/api/v4/projects/859/packages/maven</url>
</repository>
<repository>
<id>logging-library</id>
<url>https://code.europa.eu/api/v4/projects/897/packages/maven</url>
</repository>
</repositories>
</project> </project>
\ No newline at end of file
package com.aruba.simpl.common.argumentresolvers;
import org.springframework.core.MethodParameter;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.web.service.invoker.HttpRequestValues;
import org.springframework.web.service.invoker.HttpServiceArgumentResolver;
public class PageableArgumentResolver implements HttpServiceArgumentResolver {
@Override
public boolean resolve(Object argument, MethodParameter parameter, HttpRequestValues.Builder requestValues) {
if (!parameter.getParameterType().equals(Pageable.class)) {
return false;
}
if (argument != null) {
var pageable = (Pageable) argument;
if (pageable.isPaged()) {
requestValues.addRequestParameter("page", String.valueOf(pageable.getPageNumber()));
requestValues.addRequestParameter("size", String.valueOf(pageable.getPageSize()));
}
Sort sort = pageable.getSort();
if (sort.isSorted()) {
for (Sort.Order order : sort) {
requestValues.addRequestParameter(
"sort",
order.getProperty() + "," + order.getDirection().name());
}
}
}
return true;
}
}
package com.aruba.simpl.common.argumentresolvers;
import com.aruba.simpl.common.exceptions.RuntimeWrapperException;
import java.lang.reflect.Field;
import java.util.Objects;
import java.util.stream.Stream;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.core.MethodParameter;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.service.invoker.HttpRequestValues;
import org.springframework.web.service.invoker.HttpServiceArgumentResolver;
@Log4j2
public class QueryParamsArgumentResolver implements HttpServiceArgumentResolver {
@Override
public boolean resolve(Object argument, MethodParameter parameter, HttpRequestValues.Builder requestValues) {
if (!parameter.hasParameterAnnotation(ModelAttribute.class)) {
return false;
}
if (hasNestedObjects(argument)) {
return false;
}
Stream.of(argument.getClass().getDeclaredFields())
.filter(field -> isNotNull(field, argument))
.forEach(field ->
requestValues.addRequestParameter(field.getName(), String.valueOf(getValue(field, argument))));
return true;
}
private boolean hasNestedObjects(Object argument) {
return Stream.of(argument.getClass().getDeclaredFields())
.map(field -> getValue(field, argument))
.filter(Objects::nonNull)
.anyMatch(obj -> !BeanUtils.isSimpleProperty(obj.getClass()));
}
private boolean isNotNull(Field field, Object argument) {
var obj = getValue(field, argument);
if (obj == null) {
return false;
}
if (obj instanceof String s) {
return StringUtils.hasText(s);
}
return true;
}
@SuppressWarnings("all")
private Object getValue(Field field, Object argument) {
try {
field.setAccessible(true);
var obj = field.get(argument);
field.setAccessible(false);
return obj;
} catch (IllegalAccessException e) {
field.setAccessible(false);
throw new RuntimeWrapperException(e);
} finally {
field.setAccessible(false);
}
}
}
package com.aruba.simpl.common.aspects; package com.aruba.simpl.common.aspects;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.extern.log4j.Log4j2;
import org.apache.logging.log4j.Level;
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;
@Log4j2
@Aspect @Aspect
public class LoggingAspect { public class LoggingAspect {
private final Logger logger = LoggerFactory.getLogger(LoggingAspect.class); private final LoggingLevels loggingLevels;
private final Map<Class<?>, Stringifier> stringifiers;
private final Level loggingLevel; public LoggingAspect(LoggingLevels loggingLevels, List<Stringifier> stringifiers) {
this.loggingLevels = loggingLevels;
public LoggingAspect(Level loggingLevel) { this.stringifiers =
this.loggingLevel = loggingLevel; stringifiers.stream().collect(Collectors.toMap(Stringifier::appliesTo, Function.identity()));
} }
@Pointcut("@within(org.springframework.stereotype.Service)") @Pointcut("@within(org.springframework.stereotype.Service)")
...@@ -29,11 +34,46 @@ public class LoggingAspect { ...@@ -29,11 +34,46 @@ public class LoggingAspect {
var targetClass = joinPoint.getTarget().getClass(); var targetClass = joinPoint.getTarget().getClass();
var targetMethod = joinPoint.getSignature(); var targetMethod = joinPoint.getSignature();
var args = joinPoint.getArgs(); var args = joinPoint.getArgs();
logger.atLevel(loggingLevel) log.atLevel(loggingLevels.service())
.log("Invoking %s.%s(%s)" .log("Invoking service method %s.%s(%s)"
.formatted( .formatted(
targetClass.getName(), targetClass.getName(),
targetMethod.getName(), targetMethod.getName(),
Arrays.stream(args).map(Object::toString).collect(Collectors.joining(", ")))); Arrays.stream(args).map(stringify()).collect(Collectors.joining(", "))));
}
private Function<Object, String> stringify() {
return arg -> getStringifier(arg).stringify(arg);
}
private Stringifier getStringifier(Object arg) {
return Optional.ofNullable(stringifiers.get(arg.getClass())).orElse(Stringifier.Default);
}
public static class Stringifier {
private final Class<?> clazz;
private final Function<Object, String> toString;
public static <T> Stringifier create(Class<T> clazz, Function<T, String> toString) {
return new Stringifier(clazz, o -> o.getClass() == clazz ? toString.apply(clazz.cast(o)) : o.toString());
} }
private Stringifier(Class<?> clazz, Function<Object, String> toString) {
this.clazz = clazz;
this.toString = toString;
}
public String stringify(Object object) {
return toString.apply(object);
}
public Class<?> appliesTo() {
return clazz;
}
public static final Stringifier Default = new Stringifier(Object.class, Object::toString);
}
public record LoggingLevels(Level service) {}
} }
package com.aruba.simpl.common.autoconfigurations; package com.aruba.simpl.common.autoconfigurations;
import com.aruba.simpl.common.aspects.LoggingAspect; import com.aruba.simpl.common.aspects.LoggingAspect;
import org.slf4j.event.Level; import java.util.List;
import org.apache.logging.log4j.Level;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
...@@ -12,7 +13,9 @@ public class LoggingAspectAutoConfiguration { ...@@ -12,7 +13,9 @@ public class LoggingAspectAutoConfiguration {
@Bean @Bean
@ConditionalOnProperty(prefix = "logging.aspect", name = "enabled", havingValue = "true") @ConditionalOnProperty(prefix = "logging.aspect", name = "enabled", havingValue = "true")
public LoggingAspect loggingAspect(@Value("${logging.aspect.level:INFO}") Level loggingLevel) { public LoggingAspect loggingAspect(
return new LoggingAspect(loggingLevel); @Value("${logging.service.level:INFO}") Level serviceLoggingLevel,
List<LoggingAspect.Stringifier> customStringifiers) {
return new LoggingAspect(new LoggingAspect.LoggingLevels(serviceLoggingLevel), customStringifiers);
} }
} }
package com.aruba.simpl.common.autoconfigurations;
import static eu.simpl.MessageBuilder.buildMessage;
import eu.simpl.types.HttpLogMessage;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.extern.log4j.Log4j2;
import org.apache.logging.log4j.Level;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.actuate.web.exchanges.HttpExchange;
import org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;
import org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository;
import org.springframework.boot.actuate.web.exchanges.Include;
import org.springframework.boot.actuate.web.exchanges.servlet.HttpExchangesFilter;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
@Log4j2
@AutoConfiguration
@ConditionalOnClass(HttpExchangesFilter.class)
@ConditionalOnProperty(prefix = "logging.http", name = "enabled", havingValue = "true")
public class LoggingHttpAutoConfiguration {
@Bean
public HttpExchangesFilter httpExchangesFilter(HttpExchangeRepository httpExchangeRepository) {
return new HttpExchangesFilter(
httpExchangeRepository,
Stream.concat(Include.defaultIncludes().stream(), Set.of(Include.PRINCIPAL).stream())
.collect(Collectors.toSet()));
}
@Bean
public HttpExchangeRepository loggingHttpExchangeRepository(
@Value("${logging.service.level:INFO}") Level serviceLoggingLevel) {
return new LoggingHttpExchangeRepository(serviceLoggingLevel);
}
public static class LoggingHttpExchangeRepository extends InMemoryHttpExchangeRepository {
private final Level level;
public LoggingHttpExchangeRepository(Level level) {
this.level = level;
}
@Override
public void add(HttpExchange exchange) {
log.atLevel(level)
.log(buildMessage(HttpLogMessage.builder()
.msg("%s %s"
.formatted(
exchange.getRequest().getMethod(),
exchange.getRequest().getUri().getPath()))
.httpStatus(Objects.toString(exchange.getResponse().getStatus()))
.httpExecutionTime(
Objects.toString(exchange.getTimeTaken().toMillis()))
.user(Optional.ofNullable(exchange.getPrincipal())
.map(HttpExchange.Principal::getName)
.orElse(null))
.build()));
super.add(exchange);
}
}
}
package com.aruba.simpl.common.exceptions; package com.aruba.simpl.common.exceptions;
import com.aruba.simpl.common.model.dto.ErrorDTO; import com.aruba.simpl.common.model.dto.ErrorDTO;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.ElementKind;
import jakarta.validation.Path;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.slf4j.Logger; import java.util.stream.Collectors;
import org.slf4j.LoggerFactory; import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.stream.Streams;
import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.*; import org.springframework.http.*;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
...@@ -23,16 +27,16 @@ import org.springframework.web.context.request.WebRequest; ...@@ -23,16 +27,16 @@ import org.springframework.web.context.request.WebRequest;
import org.springframework.web.multipart.support.MissingServletRequestPartException; import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
@Log4j2
@RestControllerAdvice @RestControllerAdvice
@Component @Component
public class RestExceptionHandler extends ResponseEntityExceptionHandler { public class RestExceptionHandler extends ResponseEntityExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(RestExceptionHandler.class);
private static final String SQL_UNIQUE_KEY_ERROR = "23505"; private static final String SQL_UNIQUE_KEY_ERROR = "23505";
@ResponseStatus(HttpStatus.CONFLICT) @ResponseStatus(HttpStatus.CONFLICT)
@ExceptionHandler(value = DataIntegrityViolationException.class) @ExceptionHandler(value = DataIntegrityViolationException.class)
private ErrorDTO handleConstraintViolationException(DataIntegrityViolationException e) { private ErrorDTO handleDataIntegrityViolationException(DataIntegrityViolationException e) {
logError(e); logError(e);
if (e.getCause() instanceof org.hibernate.exception.ConstraintViolationException ex if (e.getCause() instanceof org.hibernate.exception.ConstraintViolationException ex
&& Objects.equals(ex.getSQLException().getSQLState(), SQL_UNIQUE_KEY_ERROR)) { && Objects.equals(ex.getSQLException().getSQLState(), SQL_UNIQUE_KEY_ERROR)) {
...@@ -137,6 +141,27 @@ public class RestExceptionHandler extends ResponseEntityExceptionHandler { ...@@ -137,6 +141,27 @@ public class RestExceptionHandler extends ResponseEntityExceptionHandler {
.toList()); .toList());
} }
@ExceptionHandler(value = ConstraintViolationException.class)
private ResponseEntity<Object> handleConstraintViolationException(ConstraintViolationException ex) {
logError(ex);
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(ex.getConstraintViolations().stream()
.map(v -> new ErrorDTO()
.setError("Error on field [ %s ], rejected value [ %s ] with reason [ %s ]"
.formatted(
getFieldPath(v.getPropertyPath()),
v.getInvalidValue(),
v.getMessage())))
.toList());
}
private String getFieldPath(Path propertyPath) {
return Streams.of(propertyPath)
.filter(node -> node.getKind() == ElementKind.PROPERTY)
.map(Path.Node::getName)
.collect(Collectors.joining("."));
}
@Override @Override
protected ResponseEntity<Object> handleMissingServletRequestPart( protected ResponseEntity<Object> handleMissingServletRequestPart(
MissingServletRequestPartException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) { MissingServletRequestPartException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
......
...@@ -22,4 +22,7 @@ public interface CertificateExchange { ...@@ -22,4 +22,7 @@ public interface CertificateExchange {
@GetExchange(url = "{certificateId}", accept = MediaType.APPLICATION_OCTET_STREAM_VALUE) @GetExchange(url = "{certificateId}", accept = MediaType.APPLICATION_OCTET_STREAM_VALUE)
StreamingResponseBody downloadCertificate(@PathVariable UUID certificateId); StreamingResponseBody downloadCertificate(@PathVariable UUID certificateId);
@GetExchange("{certificateId}/validity")
CertificateDTO checkCertificateValidity(@PathVariable UUID certificateId);
} }
package com.aruba.simpl.common.exchanges; package com.aruba.simpl.common.exchanges.identityprovider;
import com.aruba.simpl.common.model.dto.ParticipantExtendedDTO;
import jakarta.validation.Valid;
import java.util.UUID; import java.util.UUID;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.service.annotation.GetExchange; import org.springframework.web.service.annotation.GetExchange;
import org.springframework.web.service.annotation.HttpExchange; import org.springframework.web.service.annotation.HttpExchange;
import org.springframework.web.service.annotation.PostExchange;
@HttpExchange("cli") @HttpExchange("cli")
public interface OnboardingCliExchange { public interface IdentityProviderCliExchange {
@ResponseStatus(HttpStatus.CREATED)
@PostExchange("participant")
UUID createParticipant(@RequestBody @Valid ParticipantExtendedDTO participantDTO, @RequestHeader HttpHeaders token);
@GetExchange("certificate/{certificateId}") @GetExchange("certificate/{certificateId}")
Resource getCertificate(@PathVariable UUID certificateId, @RequestHeader HttpHeaders token); Resource getCertificate(@PathVariable UUID certificateId, @RequestHeader HttpHeaders token);
......
package com.aruba.simpl.common.exchanges.identityprovider;
import com.aruba.simpl.common.model.dto.ParticipantDTO;
import com.aruba.simpl.common.model.dto.ParticipantExtendedDTO;
import com.aruba.simpl.common.model.filters.ParticipantFilter;
import com.aruba.simpl.common.model.responses.PageResponse;
import com.aruba.simpl.common.model.validators.CreateOperation;
import jakarta.validation.Valid;
import java.util.List;
import java.util.UUID;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.service.annotation.GetExchange;
import org.springframework.web.service.annotation.HttpExchange;
import org.springframework.web.service.annotation.PostExchange;
import org.springframework.web.service.annotation.PutExchange;
@HttpExchange("participant")
public interface ParticipantExchange {
@ResponseStatus(HttpStatus.CREATED)
@PostExchange
UUID create(@RequestBody @Validated(CreateOperation.class) ParticipantExtendedDTO participantDTO);
@ResponseStatus(HttpStatus.CREATED)
@PostExchange(value = "attachment", contentType = MediaType.MULTIPART_FORM_DATA_VALUE)
void uploadAttachment(@RequestPart MultipartFile attachment);
@PreAuthorize("hasRole('NOTARY')")
@PutExchange("{userId}")
void outcome(
@PathVariable UUID userId,
@RequestParam boolean approve,
@RequestBody List<UUID> identityAttributesExcluded);
@GetExchange
ParticipantDTO currentUser();
// @PreAuthorize("hasRole('NOTARY')")
@GetExchange("search")
PageResponse<ParticipantDTO> search(
@ParameterObject @Valid ParticipantFilter filter, @ParameterObject Pageable pageable);
}
package com.aruba.simpl.common.exchanges.mtls;
import com.aruba.simpl.common.model.dto.IdentityAttributeDTO;
import com.aruba.simpl.common.model.dto.IdentityAttributeWithOwnershipDTO;
import com.aruba.simpl.common.model.dto.ParticipantWithIdentityAttributesDTO;
import feign.Headers;
import feign.Param;
import feign.RequestLine;
import java.util.List;
public interface AuthorityExchange extends ParticipantExchange {
@RequestLine("POST /identity-api/mtls/token")
String token();
@RequestLine("PATCH /identity-api/mtls/public-key")
@Headers("Content-Type: text/plain")
void sendTierOnePublicKey(String tierOnePublicKey);
@RequestLine("GET /identity-api/mtls/echo")
@Headers("Ephemeral-Proof: {ephemeralProof}")
ParticipantWithIdentityAttributesDTO echo(@Param String ephemeralProof);
@RequestLine("GET /sap-api/mtls/identity-attribute")
@Headers("Ephemeral-Proof: {ephemeralProof}")
List<IdentityAttributeWithOwnershipDTO> getIdentityAttributesWithOwnership(@Param String ephemeralProof);
@RequestLine("GET /sap-api/mtls/identity-attribute/{certificateId}")
@Headers("Ephemeral-Proof: {ephemeralProof}")
List<IdentityAttributeDTO> getIdentityAttributesByCertificateIdInUri(
@Param String certificateId, @Param String ephemeralProof);
}
package com.aruba.simpl.common.exchanges.mtls;
import com.aruba.simpl.common.model.dto.ParticipantWithIdentityAttributesDTO;
import feign.Headers;
import feign.Param;
import feign.RequestLine;
public interface ParticipantExchange {
@RequestLine("GET /user-api/mtls/ping")
@Headers("Ephemeral-Proof: {ephemeralProof}")
ParticipantWithIdentityAttributesDTO ping(@Param String ephemeralProof);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment