Skip to content

Commit 7541fc4

Browse files
committed
Merge branch 'main' into devBackOfficeUserAuth
2 parents a9c6fd2 + 31b4abc commit 7541fc4

File tree

16 files changed

+239
-102
lines changed

16 files changed

+239
-102
lines changed

src/main/java/fr/insee/genesis/configuration/auth/security/ApplicationRole.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ public enum ApplicationRole {
88
SCHEDULER,
99
READER,
1010
USER_BACK_OFFICE
11+
USER_BATCH_GENERIC
1112
}
1213

src/main/java/fr/insee/genesis/configuration/auth/security/OIDCSecurityConfig.java

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,31 @@
44
import lombok.RequiredArgsConstructor;
55
import lombok.Setter;
66
import lombok.extern.slf4j.Slf4j;
7+
import org.springframework.beans.factory.annotation.Value;
78
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
89
import org.springframework.boot.context.properties.ConfigurationProperties;
910
import org.springframework.context.annotation.Bean;
1011
import org.springframework.context.annotation.Configuration;
1112
import org.springframework.core.convert.converter.Converter;
1213
import org.springframework.http.HttpMethod;
13-
import org.springframework.security.config.Customizer;
14+
import org.springframework.security.authentication.AuthenticationManager;
15+
import org.springframework.security.authentication.ProviderManager;
1416
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
1517
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
1618
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
1719
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
1820
import org.springframework.security.config.http.SessionCreationPolicy;
1921
import org.springframework.security.core.GrantedAuthority;
2022
import org.springframework.security.oauth2.jwt.Jwt;
23+
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
2124
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
25+
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
26+
import org.springframework.security.oauth2.server.resource.authentication.JwtIssuerAuthenticationManagerResolver;
2227
import org.springframework.security.web.SecurityFilterChain;
23-
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
2428

2529
import java.util.Collection;
2630
import java.util.Collections;
31+
import java.util.HashMap;
2732
import java.util.List;
2833
import java.util.Map;
2934

@@ -43,29 +48,36 @@ public class OIDCSecurityConfig {
4348
private final RoleConfiguration roleConfiguration;
4449
private final SecurityTokenProperties inseeSecurityTokenProperties;
4550

51+
@Value("${fr.insee.genesis.security.resourceserver.jwt.issuer-uri}")
52+
String issuerUri;
53+
54+
@Value("${fr.insee.genesis.security.resourceserver.dmz.jwt.issuer-uri}")
55+
String issuerUriDmz;
56+
4657
@Bean
47-
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
58+
public SecurityFilterChain filterChain(HttpSecurity http, JwtIssuerAuthenticationManagerResolver authenticationManagerResolver) throws Exception {
4859
http
4960
.csrf(AbstractHttpConfigurer::disable)
50-
.sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
51-
for (var pattern : whitelistMatchers) {
52-
http.authorizeHttpRequests(authorize ->
53-
authorize
54-
.requestMatchers(AntPathRequestMatcher.antMatcher(pattern)).permitAll()
55-
);
56-
}
57-
http
58-
.authorizeHttpRequests(configure -> configure
61+
.sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
62+
.authorizeHttpRequests(authorize -> authorize
63+
// Whitelisted paths sans auth
64+
.requestMatchers(whitelistMatchers).permitAll()
65+
66+
// Secured reader-access paths
5967
.requestMatchers(HttpMethod.GET,"/questionnaires/**").hasRole(String.valueOf(ApplicationRole.READER))
6068
.requestMatchers(HttpMethod.GET,"/modes/**").hasRole(String.valueOf(ApplicationRole.READER))
6169
.requestMatchers(HttpMethod.GET,"/interrogations/**").hasRole(String.valueOf(ApplicationRole.READER))
6270
.requestMatchers(HttpMethod.GET,"/campaigns/**").hasRole(String.valueOf(ApplicationRole.READER))
71+
72+
//All others require authentication
6373
.anyRequest().authenticated()
6474
)
65-
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
75+
.oauth2ResourceServer(
76+
oauth2 -> oauth2.authenticationManagerResolver(authenticationManagerResolver));
6677
return http.build();
6778
}
6879

80+
6981
@Bean
7082
JwtAuthenticationConverter jwtAuthenticationConverter() {
7183
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
@@ -75,6 +87,26 @@ JwtAuthenticationConverter jwtAuthenticationConverter() {
7587
}
7688

7789

90+
91+
@Bean
92+
public JwtIssuerAuthenticationManagerResolver authenticationManagerResolver() {
93+
final List<String> issuers = List.of(issuerUri,issuerUriDmz);
94+
Map<String, AuthenticationManager> authenticationManagers = new HashMap<>();
95+
96+
for (String issuer : issuers) {
97+
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder
98+
.withJwkSetUri(issuer + "/protocol/openid-connect/certs")
99+
.build();
100+
101+
JwtAuthenticationProvider provider = new JwtAuthenticationProvider(jwtDecoder);
102+
provider.setJwtAuthenticationConverter(jwtAuthenticationConverter());
103+
104+
AuthenticationManager manager = new ProviderManager(provider);
105+
authenticationManagers.put(issuer, manager);
106+
}
107+
return new JwtIssuerAuthenticationManagerResolver(authenticationManagers::get);
108+
}
109+
78110
Converter<Jwt, Collection<GrantedAuthority>> jwtGrantedAuthoritiesConverter() {
79111
return new Converter<Jwt, Collection<GrantedAuthority>>() {
80112
@Override

src/main/java/fr/insee/genesis/configuration/auth/security/RoleConfiguration.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ public class RoleConfiguration {
3737
@Value("#{'${app.role.scheduler.claims}'.split(',')}")
3838
private List<String> schedulerClaims;
3939

40+
@Value("#{'${app.role.batch-generic.claims}'.split(',')}")
41+
private List<String> batchGenericClaims;
42+
43+
4044
public Map<String, List<String>> getRolesByClaim() {
4145
return rolesByClaim;
4246
}
@@ -56,6 +60,7 @@ static RoleHierarchy roleHierarchy() {
5660
.role(ApplicationRole.ADMIN.toString()).implies(ApplicationRole.USER_BACK_OFFICE.toString())
5761
.role(ApplicationRole.ADMIN.toString()).implies(ApplicationRole.COLLECT_PLATFORM.toString())
5862
.role(ApplicationRole.ADMIN.toString()).implies(ApplicationRole.SCHEDULER.toString())
63+
.role(ApplicationRole.ADMIN.toString()).implies(ApplicationRole.USER_BATCH_GENERIC.toString())
5964
.role(ApplicationRole.USER_KRAFTWERK.toString()).implies(ApplicationRole.READER.toString())
6065
.role(ApplicationRole.USER_PLATINE.toString()).implies(ApplicationRole.READER.toString())
6166
.role(ApplicationRole.USER_BACK_OFFICE.toString()).implies(ApplicationRole.READER.toString())
@@ -110,6 +115,11 @@ public void initialization() {
110115
.computeIfAbsent(claim, k -> new ArrayList<>())
111116
.add(String.valueOf(ApplicationRole.SCHEDULER)));
112117

118+
//Add claims for the USER_BATCH_GENERIC role
119+
batchGenericClaims.forEach(claim -> rolesByClaim
120+
.computeIfAbsent(claim, k -> new ArrayList<>())
121+
.add(String.valueOf(ApplicationRole.USER_BATCH_GENERIC)));
122+
113123
log.info("Roles configuration : {}", rolesByClaim);
114124
}
115125
}

src/main/java/fr/insee/genesis/controller/rest/responses/RawResponseController.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,17 +191,18 @@ public ResponseEntity<Map<String, List<String>>> getProcessedDataIdsSinceHours(
191191
Map<String, List<String>> result = lunaticJsonRawDataApiPort.findProcessedIdsgroupedByQuestionnaireSince(LocalDateTime.now().minusHours(hours).minusMinutes(10));
192192
return ResponseEntity.ok(result);
193193
}
194-
@Operation(summary = "Get lunatic JSON data from one campaign in Genesis Database, filtered by optional start and end dates")
194+
195+
@Operation(summary = "Get lunatic JSON data from one campaign in Genesis Database, filtered by start and end dates")
195196
@GetMapping(path = "/lunatic-json/{campaignId}")
196-
@PreAuthorize("hasRole('USER_KRAFTWERK')")
197+
@PreAuthorize("hasRole('USER_BATCH_GENERIC')")
197198
public ResponseEntity<PagedModel<LunaticJsonRawDataModel>> getRawResponsesFromJsonBody(
198199
@PathVariable String campaignId,
199200
@RequestParam(value = "startDate", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) Instant startDate,
200201
@RequestParam(value = "endDate", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) Instant endDate,
201202
@RequestParam(value = "page", defaultValue = "0") int page,
202203
@RequestParam(value = "size", defaultValue = "1000") int size
203204
) {
204-
log.info("Try to read raw JSONs for campaign {}, with startDate={} and endDate={}", campaignId, startDate, endDate);
205+
log.info("Try to read raw JSONs for campaign {}, with startDate={} and endDate={} - page={} - size={}", campaignId, startDate, endDate,page,size);
205206
Pageable pageable = PageRequest.of(page, size);
206207
Page<LunaticJsonRawDataModel> rawResponses = lunaticJsonRawDataApiPort.findRawDataByCampaignIdAndDate(campaignId, startDate, endDate, pageable);
207208
log.info("rawResponses=" + rawResponses.getContent().size());

src/main/java/fr/insee/genesis/domain/service/surveyunit/SurveyUnitService.java

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package fr.insee.genesis.domain.service.surveyunit;
22

3+
import fr.insee.bpm.metadata.model.VariableType;
34
import fr.insee.bpm.metadata.model.VariablesMap;
45
import fr.insee.genesis.controller.dto.CampaignWithQuestionnaire;
5-
import fr.insee.genesis.domain.model.surveyunit.InterrogationId;
66
import fr.insee.genesis.controller.dto.QuestionnaireWithCampaign;
77
import fr.insee.genesis.controller.dto.SurveyUnitDto;
88
import fr.insee.genesis.controller.dto.SurveyUnitInputDto;
@@ -11,6 +11,7 @@
1111
import fr.insee.genesis.controller.dto.VariableStateDto;
1212
import fr.insee.genesis.controller.services.MetadataService;
1313
import fr.insee.genesis.domain.model.surveyunit.DataState;
14+
import fr.insee.genesis.domain.model.surveyunit.InterrogationId;
1415
import fr.insee.genesis.domain.model.surveyunit.Mode;
1516
import fr.insee.genesis.domain.model.surveyunit.SurveyUnitModel;
1617
import fr.insee.genesis.domain.model.surveyunit.VarIdScopeTuple;
@@ -600,19 +601,25 @@ private Object getValueWithType(String variableName, String value, VariablesMap
600601
}
601602
if(value == null) return null;
602603
if(value.isEmpty()) return value;
603-
switch (variablesMap.getVariable(variableName).getType()){
604-
case INTEGER -> {
605-
return Integer.parseInt(value);
606-
}
607-
case BOOLEAN -> {
608-
return Boolean.parseBoolean(value);
609-
}
610-
case NUMBER -> {
611-
return Double.parseDouble(value);
612-
}
613-
default -> {
614-
return value;
604+
VariableType variableType = variablesMap.getVariable(variableName).getType();
605+
try {
606+
switch (variableType) {
607+
case INTEGER -> {
608+
return Integer.parseInt(value);
609+
}
610+
case BOOLEAN -> {
611+
return Boolean.parseBoolean(value);
612+
}
613+
case NUMBER -> {
614+
return Double.parseDouble(value);
615+
}
616+
default -> {
617+
return value;
618+
}
615619
}
620+
}catch (NumberFormatException e){
621+
log.warn("Invalid value {} for variable {}, expected type {}", value, variableName, variableType);
622+
return value;
616623
}
617624
}
618625

src/main/java/fr/insee/genesis/infrastructure/adapter/LunaticJsonRawDataMongoAdapter.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import fr.insee.genesis.Constants;
44
import fr.insee.genesis.domain.model.surveyunit.GroupedInterrogation;
5-
import fr.insee.genesis.domain.model.surveyunit.InterrogationId;
65
import fr.insee.genesis.domain.model.surveyunit.Mode;
76
import fr.insee.genesis.domain.model.surveyunit.rawdata.LunaticJsonRawDataModel;
87
import fr.insee.genesis.domain.ports.spi.LunaticJsonRawDataPersistencePort;

src/main/resources/application-dev.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ app.role.user-platine.claims=***
2323
app.role.reader.claims=***
2424
app.role.collect-platform.claims=***
2525
app.role.scheduler.claims=***
26+
app.role.batch-generic.claims=***
2627

2728
#--------------------------------------------------------------------------
2829
# Survey quality tool

src/main/resources/application-preprod.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ app.role.user-platine.claims=***
2323
app.role.reader.claims=***
2424
app.role.collect-platform.claims=***
2525
app.role.scheduler.claims=***
26-
26+
app.role.batch-generic.claims=***
2727
#--------------------------------------------------------------------------
2828
# Survey quality tool
2929
#--------------------------------------------------------------------------

src/main/resources/application-prod.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ app.role.user-platine.claims=***
2323
app.role.reader.claims=***
2424
app.role.collect-platform.claims=***
2525
app.role.scheduler.claims=***
26+
app.role.batch-generic.claims=***
2627

2728
#--------------------------------------------------------------------------
2829
# Survey quality tool

src/main/resources/application-test-cucumber.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ app.role.user-back-office.claims=utilisateur_Back_Office
99
app.role.reader.claims=lecteur_traiter
1010
app.role.collect-platform.claims=protools
1111
app.role.scheduler.claims=scheduler_traiter
12+
app.role.batch-generic.claims=utilisateur_batch_generic
1213

1314
logging.file.name = /logs/genesis-api.log
1415

0 commit comments

Comments
 (0)