Skip to content

Commit

Permalink
Merge pull request #84 from InseeFr/develop
Browse files Browse the repository at this point in the history
feat: add management endpoints and cucumber tests
  • Loading branch information
BettyB979 authored Sep 20, 2024
2 parents eafe6ad + f7393e1 commit 7d0e01b
Show file tree
Hide file tree
Showing 135 changed files with 2,648 additions and 1,035 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ build/

### VS Code ###
.vscode/
src/main/resources/application-*.properties
55 changes: 46 additions & 9 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,25 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.1</version>
<version>3.3.4</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>fr.insee.survey</groupId>
<artifactId>platine-management</artifactId>
<version>2.4.2</version>
<version>2.6.0</version>
<name>platine-management</name>
<description>REST API for communication between DB and Platine-Management UI and Platine-My-Surveys UI</description>
<properties>
<java.version>21</java.version>
<springdoc-version>2.2.0</springdoc-version>
<modelmapper-version>3.1.0</modelmapper-version>
<springdoc-version>2.6.0</springdoc-version>
<modelmapper-version>3.2.0</modelmapper-version>
<jakarta-version>3.1.0</jakarta-version>
<jeasy-version>5.0.0</jeasy-version>
<easy-version>5.0.0</easy-version>
<postgres-version>42.7.3</postgres-version>
<javafaker-version>1.0.2</javafaker-version>
<sonar.organization>inseefr</sonar.organization>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
<cucumber.version>7.18.0</cucumber.version>
</properties>
<dependencies>
<dependency>
Expand Down Expand Up @@ -73,10 +75,19 @@
<version>${jakarta-version}</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
</dependency>

<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.3.9</version>
<version>${postgres-version}</version>
</dependency>
<!-- SECURITY -->
<dependency>
Expand All @@ -92,12 +103,36 @@
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>

<!--Cucumber-->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-spring</artifactId>
<version>${cucumber.version}</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit-platform-engine</artifactId>
<version>${cucumber.version}</version>
</dependency>



<!-- Fakers for poc data -->
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-random-core</artifactId>
<version>${jeasy-version}</version>
<version>${easy-version}</version>
</dependency>
<dependency>
<groupId>com.github.javafaker</groupId>
Expand Down Expand Up @@ -128,6 +163,8 @@
<scope>test</scope>
</dependency>



<!-- Actuator Metrics -->
<dependency>
<groupId>org.springframework.boot</groupId>
Expand All @@ -150,7 +187,7 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.11</version>
<version>0.8.12</version>
<executions>
<execution>
<id>prepare-agent</id>
Expand Down Expand Up @@ -202,4 +239,4 @@
</build>


</project>
</project>
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
package fr.insee.survey.datacollectionmanagement.config;


import fr.insee.survey.datacollectionmanagement.config.auth.user.AuthUser;
import fr.insee.survey.datacollectionmanagement.config.auth.user.UserProvider;
import fr.insee.survey.datacollectionmanagement.constants.AuthConstants;
import fr.insee.survey.datacollectionmanagement.config.auth.user.AuthenticationUserHelper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.ThreadContext;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
Expand All @@ -22,37 +18,25 @@
@RequiredArgsConstructor
public class LogInterceptor implements HandlerInterceptor {

private final ApplicationConfig applicationConfig;
private final AuthenticationUserHelper authenticationUserHelper;

private final UserProvider userProvider;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {

String fishTag = UUID.randomUUID().toString();
String method = request.getMethod();
String operationPath = request.getRequestURI();

String userId = null;

switch (applicationConfig.getAuthType()) {
Authentication authentication = authenticationUserHelper.getCurrentUser();
ThreadContext.put("user", authentication.getName().toUpperCase());

case AuthConstants.OIDC:
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
AuthUser currentAuthUser = userProvider.getUser(authentication);
userId = (currentAuthUser != null && currentAuthUser.getId() != null ? currentAuthUser.getId() : "anonymous");
ThreadContext.put("user", userId.toUpperCase());
break;
default:
userId = "GUEST";
break;
}

ThreadContext.put("id", fishTag);
ThreadContext.put("path", operationPath);
ThreadContext.put("method", method);


log.info("[" + userId.toUpperCase() + "] - [" + method + "] - [" + operationPath + "]");
log.info("[" + authentication.getName().toUpperCase() + "] - [" + method + "] - [" + operationPath + "]");
return true;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package fr.insee.survey.datacollectionmanagement.config;

import fr.insee.survey.datacollectionmanagement.config.auth.user.UserProvider;
import fr.insee.survey.datacollectionmanagement.config.auth.user.AuthenticationUserHelper;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand All @@ -11,19 +11,16 @@
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {

private final ApplicationConfig applicationConfig;

private final UserProvider userProvider;
private final AuthenticationUserHelper authenticationUserHelper;

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(this.myLogInterceptor());
//.addPathPatterns("api/**");
}

@Bean
public LogInterceptor myLogInterceptor() {
return new LogInterceptor(applicationConfig,userProvider);
return new LogInterceptor(authenticationUserHelper);
}

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package fr.insee.survey.datacollectionmanagement.config.auth.security;

import fr.insee.survey.datacollectionmanagement.config.ApplicationConfig;
import fr.insee.survey.datacollectionmanagement.config.auth.user.AuthUser;
import fr.insee.survey.datacollectionmanagement.config.auth.user.UserProvider;
import lombok.AllArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
Expand All @@ -16,8 +14,6 @@
import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter;
import org.springframework.security.web.header.writers.XXssProtectionHeaderWriter;

import java.util.Collections;

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
Expand Down Expand Up @@ -56,11 +52,6 @@ SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
@Bean
@Order(1)
SecurityFilterChain filterPublicUrlsChain(HttpSecurity http) throws Exception {
return publicSecurityFilterChainConfiguration.buildSecurityPublicFilterChain(http, config.getPublicUrls()); }
@Bean
public UserProvider getUserProvider() {
return auth -> new AuthUser("anonymous", Collections.emptyList());
return publicSecurityFilterChainConfiguration.buildSecurityPublicFilterChain(http, config.getPublicUrls());
}


}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package fr.insee.survey.datacollectionmanagement.config.auth.security;

import fr.insee.survey.datacollectionmanagement.config.ApplicationConfig;
import fr.insee.survey.datacollectionmanagement.config.auth.user.AuthorityRoleEnum;
import lombok.AllArgsConstructor;
import lombok.NonNull;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
Expand All @@ -13,27 +15,39 @@
@AllArgsConstructor
public class GrantedAuthorityConverter implements Converter<Jwt, Collection<GrantedAuthority>> {

private final Map<String, SimpleGrantedAuthority> grantedRoles;
ApplicationConfig applicationConfig;

public GrantedAuthorityConverter(ApplicationConfig applicationConfig) {
this.applicationConfig = applicationConfig;
this.grantedRoles = new HashMap<>();
fillGrantedRoles(applicationConfig.getRoleAdmin(), AuthorityRoleEnum.ADMIN);
fillGrantedRoles(applicationConfig.getRoleRespondent(), AuthorityRoleEnum.RESPONDENT);
fillGrantedRoles(applicationConfig.getRoleInternalUser(), AuthorityRoleEnum.INTERNAL_USER);
fillGrantedRoles(applicationConfig.getRoleWebClient(), AuthorityRoleEnum.WEB_CLIENT);
}

@SuppressWarnings("unchecked")
@Override
public Collection<GrantedAuthority> convert(Jwt jwt) {
public Collection<GrantedAuthority> convert(@NonNull Jwt jwt) {
Map<String, Object> claims = jwt.getClaims();
List<String> roles = (List<String>) claims.get(applicationConfig.getRoleClaim());
List<String> authorizedRoles = new ArrayList<>();
authorizedRoles.addAll(applicationConfig.getRoleAdmin());
authorizedRoles.addAll(applicationConfig.getRoleRespondent());
authorizedRoles.addAll(applicationConfig.getRoleInternalUser());
authorizedRoles.addAll(applicationConfig.getRoleWebClient());

return roles.stream()
.map(role -> {
if (authorizedRoles.contains(role)) {
return new SimpleGrantedAuthority(role);
}
return null;
})
.filter(Objects::nonNull)
.filter(role -> !role.isBlank())
.filter(grantedRoles::containsKey)
.map(grantedRoles::get)
.collect(Collectors.toCollection(ArrayList::new));
}

private void fillGrantedRoles(List<String> listRoles, AuthorityRoleEnum roleEnum) {

for (String role : listRoles ) {
this.grantedRoles.putIfAbsent(role,
new SimpleGrantedAuthority(roleEnum.securityRole()));
}

}
}

Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package fr.insee.survey.datacollectionmanagement.config.auth.security;

import fr.insee.survey.datacollectionmanagement.config.ApplicationConfig;
import fr.insee.survey.datacollectionmanagement.config.auth.user.AuthUser;
import fr.insee.survey.datacollectionmanagement.config.auth.user.UserProvider;
import fr.insee.survey.datacollectionmanagement.constants.AuthConstants;
import fr.insee.survey.datacollectionmanagement.constants.Constants;
import lombok.RequiredArgsConstructor;
Expand All @@ -27,7 +25,6 @@
import org.springframework.security.web.header.writers.XXssProtectionHeaderWriter;

import java.util.Collection;
import java.util.List;

@Configuration
@EnableWebSecurity
Expand Down Expand Up @@ -80,18 +77,7 @@ SecurityFilterChain filterPublicUrlsChain(HttpSecurity http) throws Exception {
String tokenUrl = config.getKeyCloakUrl() + "/realms/" + config.getKeycloakRealm() + "/protocol/openid-connect/token";
String authorizedConnectionHost = config.getAuthType().equals(AuthConstants.OIDC) ?
" " + tokenUrl : "";
return publicSecurityFilterChainConfiguration.buildSecurityPublicFilterChain(http, config.getPublicUrls(), authorizedConnectionHost); }

@Bean
public UserProvider getUserProvider() {
return auth -> {
if ("anonymousUser".equals(auth.getPrincipal()))
return null; //init request, or request without authentication
final Jwt jwt = (Jwt) auth.getPrincipal();
List<String> tryRoles = jwt.getClaimAsStringList(config.getRoleClaim());
String tryId = jwt.getClaimAsString(config.getIdClaim());
return new AuthUser(tryId, tryRoles);
};
return publicSecurityFilterChainConfiguration.buildSecurityPublicFilterChain(http, config.getPublicUrls(), authorizedConnectionHost);
}

@Bean
Expand All @@ -105,7 +91,4 @@ JwtAuthenticationConverter jwtAuthenticationConverter(ApplicationConfig applicat
Converter<Jwt, Collection<GrantedAuthority>> jwtGrantedAuthoritiesConverter(ApplicationConfig applicationConfig) {
return new GrantedAuthorityConverter(applicationConfig);
}



}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package fr.insee.survey.datacollectionmanagement.config.auth.user;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

@Component
public class AuthenticationUserHelper {

public Authentication getCurrentUser(){
return SecurityContextHolder.getContext().getAuthentication();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package fr.insee.survey.datacollectionmanagement.config.auth.user;

public class AuthorityPrivileges {
private AuthorityPrivileges() {
throw new IllegalArgumentException("Constant class");
}

public static final String HAS_MANAGEMENT_PRIVILEGES = "hasAnyRole('INTERNAL_USER', 'WEB_CLIENT', 'ADMIN')";
public static final String HAS_REPONDENT_PRIVILEGES = "hasRole('RESPONDENT')";
public static final String HAS_REPONDENT_LIMITATED_PRIVILEGES = "hasRole('RESPONDENT') && #id.toLowerCase() == authentication.name.toLowerCase() ";
public static final String HAS_ADMIN_PRIVILEGES = "hasAnyRole('WEB_CLIENT', 'ADMIN)";
public static final String HAS_USER_PRIVILEGES = "hasAnyRole('INTERNAL_USER', 'WEB_CLIENT', 'RESPONDENT', 'ADMIN')";


}
Loading

0 comments on commit 7d0e01b

Please sign in to comment.