Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
b263024
Add unprocessed raw data endpoint
alexisszmundy Dec 19, 2024
ff82ef8
Add data processing
alexisszmundy Dec 20, 2024
e44151b
Add variable type storage
alexisszmundy Dec 20, 2024
c07fdea
Add exception management + fix after mongo tests
alexisszmundy Dec 20, 2024
65517c9
Merge branch 'main' into devRawDataProcessing
alexisszmundy Dec 23, 2024
265347c
refactors
alexisszmundy Dec 30, 2024
7a57e42
Removed unused
alexisszmundy Jan 6, 2025
80f2fdf
Store variablesmap in variabletype collection
alexisszmundy Jan 6, 2025
f5e3dbe
Merge branch 'main' into devRawDataProcessing
alicela Jan 9, 2025
61ca83f
fix: remove unused
alicela Jan 9, 2025
275fd5b
Merge branch 'main' into devRawDataProcessing
alexisszmundy Jan 9, 2025
0cf7a1d
fix: cucumber definitions with vartype
alexisszmundy Jan 9, 2025
6d19845
Merge branch 'devRawDataProcessing' of https://github.com/InseeFr/Gen…
alicela Jan 10, 2025
70d916d
Fix for sonar
alicela Jan 20, 2025
f3fd06b
build: refactors
alexisszmundy Jan 21, 2025
96881e0
feat: Disabled save Metadata when processing due to mapping problem
alexisszmundy Jan 21, 2025
1651366
Merge branch 'main' into devRawDataProcessing
alexisszmundy Feb 5, 2025
7257f87
fix: use VariableModel not CollectedVariable
alexisszmundy Feb 5, 2025
aeecb7c
fix: After merge fixes
alexisszmundy Feb 5, 2025
90e4a67
feat: adding roles to access endpoints
loichenninger Feb 18, 2025
7bb7385
Merge branch 'main' into devRawDataProcessing
alexisszmundy Feb 20, 2025
23bf782
feat: input JSON raw data structure check and adaptations to lunatic …
alexisszmundy Feb 21, 2025
c5def6f
test: add raw data processing functional test
alexisszmundy Feb 24, 2025
3bdac3e
feat: add data verification on raw data processing
alexisszmundy Feb 24, 2025
2457ae9
Merge branch 'main' into devRawDataProcessing
alexisszmundy Feb 24, 2025
53e70e5
feat: add roles and use PreAuthorize on response controller
loichenninger Feb 27, 2025
ab10013
test: create ControllerAccessTest
loichenninger Feb 27, 2025
d7dea54
refactor: move properties from applications.properties to dev properties
loichenninger Feb 27, 2025
9f59a18
refactor: added refactors from Init raw response controller
alexisszmundy Feb 28, 2025
b8e342d
Merge branch 'main' into devRawDataProcessing
alexisszmundy Feb 28, 2025
70a2d69
fix: GroupUtils instead of LoopIdentifier
alexisszmundy Feb 28, 2025
aa25fed
fix: Mockito not creating mock
alexisszmundy Feb 28, 2025
6a9c22b
chore: remove unused imports
alexisszmundy Feb 28, 2025
7d3759a
test: more tests
loichenninger Mar 3, 2025
001fb5a
build: add Spring profile Test
loichenninger Mar 4, 2025
f9f5504
fix: error on parentId (group parent) name
loichenninger Mar 5, 2025
fd5dff3
fix: can't see endpoints in swagger
loichenninger Mar 7, 2025
bfca7b5
fix: empty values should be send too
loichenninger Mar 7, 2025
64b5172
test: on fix empty values should be return too
loichenninger Mar 7, 2025
cfe4967
chore: clean up
loichenninger Mar 11, 2025
f043d23
fix: remove test properties
loichenninger Mar 12, 2025
6570eb9
fix: ask for roles in token
loichenninger Mar 12, 2025
854eb2e
Merge branch 'main' into devHabilitation
loichenninger Mar 13, 2025
0c4fb7a
fix: avoid error 500 if no claims in token
loichenninger Mar 13, 2025
2be08f9
fix: check if claims is null to avoid null pointer exception
loichenninger Mar 13, 2025
1d76bb1
chore: renaming raw controller services
loichenninger Mar 14, 2025
12e61f8
fix: remove code used for testing
loichenninger Mar 14, 2025
4baf785
fix: change mapper to read raw data in db
loichenninger Mar 18, 2025
b095e4e
test: update to take into account the changes
loichenninger Mar 18, 2025
216340c
refactor: RawData model change
loichenninger Mar 19, 2025
6035763
build: WIP on process data corresponding tests are deactivated
loichenninger Mar 19, 2025
2f4d79e
feat: forgot to add recordDate when saving the data
loichenninger Mar 19, 2025
602e107
chore: response message with more details
loichenninger Mar 19, 2025
7f8db99
chore: unnecessary code
loichenninger Mar 19, 2025
5b14413
Merge branch 'devRawDataProcessing' into develop
loichenninger Mar 19, 2025
c8347b3
Merge branch 'devHabilitation' into develop
loichenninger Mar 19, 2025
90da2aa
feat: add roles in new RawResponseController
loichenninger Mar 19, 2025
4aa9c65
build: deactivate temporarly tests on habilitations
loichenninger Mar 19, 2025
f871779
fix: activate OIDC by default
loichenninger Mar 20, 2025
6804728
fix: test for saving raw data
alicela Mar 20, 2025
a65d5cd
Merge branch 'devRawDataProcessing' into develop
alicela Mar 20, 2025
b4cf2e0
test: add profile for cucumber
alicela Mar 20, 2025
ae84e25
test: fix test with and without auth
alicela Mar 20, 2025
c193730
test: fix cucumber tests
loichenninger Mar 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,12 @@
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-spring</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>


<dependency>
Expand Down
31 changes: 31 additions & 0 deletions qodana.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#-------------------------------------------------------------------------------#
# Qodana analysis is configured by qodana.yaml file #
# https://www.jetbrains.com/help/qodana/qodana-yaml.html #
#-------------------------------------------------------------------------------#
version: "1.0"

#Specify inspection profile for code analysis
profile:
name: qodana.starter

#Enable inspections
#include:
# - name: <SomeEnabledInspectionId>

#Disable inspections
#exclude:
# - name: <SomeDisabledInspectionId>
# paths:
# - <path/where/not/run/inspection>

projectJDK: 21 #(Applied in CI/CD pipeline)

#Execute shell command before Qodana execution (Applied in CI/CD pipeline)
#bootstrap: sh ./prepare-qodana.sh

#Install IDE plugins before Qodana execution (Applied in CI/CD pipeline)
#plugins:
# - id: <plugin.id> #(plugin id can be found at https://plugins.jetbrains.com)

#Specify Qodana linter for analysis (Applied in CI/CD pipeline)
linter: jetbrains/qodana-jvm-community:latest
2 changes: 2 additions & 0 deletions src/main/java/fr/insee/genesis/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ public class Constants {
"(^([0-9]|[0-2][0-9]|3[0-1])[\\-\\/]([0-9]|1[0-2]|0[1-9])[\\-\\/]([0-9]{4})$)";
public static final String FILTER_RESULT_PREFIX = "FILTER_RESULT_";
public static final String MISSING_SUFFIX = "_MISSING";
public static final String MONGODB_LUNATIC_RAWDATA_COLLECTION_NAME = "lunaticjsondata";
private static final String[] ENO_VARIABLES = {"COMMENT_QE","COMMENT_UE","HEURE_REMPL","MIN_REMPL"};

public static final String MONGODB_SCHEDULE_COLLECTION_NAME = "schedules";
public static final String LOOP_NAME_PREFIX = "BOUCLE";
public static final String MONGODB_RESPONSE_COLLECTION_NAME = "responses";
public static final String MONGODB_VARIABLETYPE_COLLECTION_NAME = "variabletypes";
public static final String VOLUMETRY_FOLDER_NAME = "genesis_volumetries";
public static final String VOLUMETRY_FILE_SUFFIX = "_VOLUMETRY";
public static final String VOLUMETRY_FILE_DATE_FORMAT = "yyyy_MM_dd";
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/fr/insee/genesis/configuration/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Configuration;

import java.nio.file.Path;

@Configuration
@Getter
@EnableCaching
public class Config {

/******************************************************/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package fr.insee.genesis.configuration.auth.security;

public enum ApplicationRole {
ADMIN,
USER_KRAFTWERK,
USER_PLATINE,
COLLECT_PLATFORM,
READER
}

Original file line number Diff line number Diff line change
@@ -1,48 +1,120 @@
package fr.insee.genesis.configuration.auth.security;

import fr.insee.genesis.configuration.Config;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
@Slf4j
@ConditionalOnProperty(name = "fr.insee.genesis.authentication", havingValue = "OIDC")
@ConfigurationProperties(prefix = "fr.insee.genesis.security")
@RequiredArgsConstructor
public class OIDCSecurityConfig {

Config config;
@Autowired
public OIDCSecurityConfig(Config config) {
this.config = config;
}
@Getter
@Setter
private String[] whitelistMatchers;
private static final String ROLE_PREFIX = "ROLE_";
private final RoleConfiguration roleConfiguration;
private final SecurityTokenProperties inseeSecurityTokenProperties;

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
for (var pattern : config.getWhiteList()) {
http.authorizeHttpRequests(authorize ->
authorize
.requestMatchers(AntPathRequestMatcher.antMatcher(pattern)).permitAll()
);
}
http
.authorizeHttpRequests(configurer -> configurer
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
return http.build();
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
for (var pattern : whitelistMatchers) {
http.authorizeHttpRequests(authorize ->
authorize
.requestMatchers(AntPathRequestMatcher.antMatcher(pattern)).permitAll()
);
}
http
.authorizeHttpRequests(configurer -> configurer
.requestMatchers(HttpMethod.GET,"/questionnaires/**").hasRole(String.valueOf(ApplicationRole.READER))
.requestMatchers(HttpMethod.GET,"/modes/**").hasRole(String.valueOf(ApplicationRole.READER))
.requestMatchers(HttpMethod.GET,"/interrogations/**").hasRole(String.valueOf(ApplicationRole.READER))
.requestMatchers(HttpMethod.GET,"/campaigns/**").hasRole(String.valueOf(ApplicationRole.READER))
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
return http.build();
}

@Bean
JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
jwtAuthenticationConverter.setPrincipalClaimName(inseeSecurityTokenProperties.getOidcClaimUsername());
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter());
return jwtAuthenticationConverter;
}


Converter<Jwt, Collection<GrantedAuthority>> jwtGrantedAuthoritiesConverter() {
return new Converter<Jwt, Collection<GrantedAuthority>>() {
@Override
@SuppressWarnings({"unchecked"})
public Collection<GrantedAuthority> convert(Jwt source) {

String[] claimPath = inseeSecurityTokenProperties.getOidcClaimRole().split("\\.");
Map<String, Object> claims = source.getClaims();
try {
for (int i = 0; i < claimPath.length - 1; i++) {
claims = (Map<String, Object>) claims.get(claimPath[i]);
}
if (claims != null) {
List<String> tokenClaims = (List<String>) claims.getOrDefault(claimPath[claimPath.length - 1], List.of());
// Collect distinct values from mapping associated with input keys
List<String> claimedRoles = tokenClaims.stream()
.filter(roleConfiguration.getRolesByClaim()::containsKey) // Ensure the key exists in the mapping
.flatMap(key -> roleConfiguration.getRolesByClaim().get(key).stream()) // Get the list of values associated with the key
.distinct() // Remove duplicates
.toList();

return Collections.unmodifiableCollection(claimedRoles.stream().map(s -> new GrantedAuthority() {
@Override
public String getAuthority() {
return ROLE_PREFIX + s;
}

@Override
public String toString() {
return getAuthority();
}
}).toList());
}
} catch (ClassCastException e) {
// role path not correctly found, assume that no role for this user
return List.of();
}
return List.of();
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package fr.insee.genesis.configuration.auth.security;

import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Configuration
@Slf4j
public class RoleConfiguration {

//Mapping des claims du jeton sur les roles applicatifs
@Value("#{'${app.role.admin.claims}'.split(',')}")
private List<String> adminClaims;
@Value("#{'${app.role.user-kraftwerk.claims}'.split(',')}")
private List<String> userKraftwerkClaims;
@Value("#{'${app.role.user-platine.claims}'.split(',')}")
private List<String> userPlatineClaims;
@Value("#{'${app.role.reader.claims}'.split(',')}")
private List<String> readerClaims;
@Value("#{'${app.role.collect-platform.claims}'.split(',')}")
private List<String> collectPlatformClaims;

public Map<String, List<String>> getRolesByClaim() {
return rolesByClaim;
}

private Map<String, List<String>> rolesByClaim;

//Defines a role hierarchy
//ADMIN implies USER role too
//USER implies READER role too
//so an admin has 2 roles: ADMIN/USER
@Bean
static RoleHierarchy roleHierarchy() {
return RoleHierarchyImpl.withDefaultRolePrefix()
.role(ApplicationRole.ADMIN.toString()).implies(ApplicationRole.USER_KRAFTWERK.toString())
.role(ApplicationRole.ADMIN.toString()).implies(ApplicationRole.USER_PLATINE.toString())
.role(ApplicationRole.ADMIN.toString()).implies(ApplicationRole.COLLECT_PLATFORM.toString())
.role(ApplicationRole.USER_KRAFTWERK.toString()).implies(ApplicationRole.READER.toString())
.role(ApplicationRole.USER_PLATINE.toString()).implies(ApplicationRole.READER.toString())
.build();
}

// and, if using pre-post method security also add
@Bean
static MethodSecurityExpressionHandler methodSecurityExpressionHandler(RoleHierarchy roleHierarchy) {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setRoleHierarchy(roleHierarchy);
return expressionHandler;
}

@PostConstruct
public void initialization() {

rolesByClaim = new HashMap<>();

// Ajout des claims pour le rôle ADMIN
adminClaims.forEach(claim -> rolesByClaim
.computeIfAbsent(claim, k -> new ArrayList<>())
.add(String.valueOf(ApplicationRole.ADMIN)));

// Ajout des claims pour le rôle USER_KRAFTWERK
userKraftwerkClaims.forEach(claim -> rolesByClaim
.computeIfAbsent(claim, k -> new ArrayList<>())
.add(String.valueOf(ApplicationRole.USER_KRAFTWERK)));

// Ajout des claims pour le rôle USER_PLATINE
userPlatineClaims.forEach(claim -> rolesByClaim
.computeIfAbsent(claim, k -> new ArrayList<>())
.add(String.valueOf(ApplicationRole.USER_PLATINE)));

// Ajout des claims pour le rôle COLLECT_PLATFORM
collectPlatformClaims.forEach(claim -> rolesByClaim
.computeIfAbsent(claim, k -> new ArrayList<>())
.add(String.valueOf(ApplicationRole.COLLECT_PLATFORM)));

// Ajout des claims pour le rôle READER
readerClaims.forEach(claim -> rolesByClaim
.computeIfAbsent(claim, k -> new ArrayList<>())
.add(String.valueOf(ApplicationRole.READER)));


log.info("Roles configuration : {}", rolesByClaim);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package fr.insee.genesis.configuration.auth.security;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration
@ConfigurationProperties(
prefix = "fr.insee.genesis.security.token"
)
@Data
public class SecurityTokenProperties {

//Chemin pour récupérer la liste des rôles dans le jwt (token)
private String oidcClaimRole;
//Chemin pour récupérer le username dans le jwt (token)
private String oidcClaimUsername;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package fr.insee.genesis.controller.dto.rawdata;

import lombok.Builder;

@Builder
public record LunaticJsonRawDataUnprocessedDto(String campaignId, String interrogationId){}
Loading
Loading