Skip to content

Commit

Permalink
Merge branch 'release/2024.03.13'
Browse files Browse the repository at this point in the history
  • Loading branch information
Fabien committed Mar 13, 2024
2 parents f7df276 + c945023 commit d2aed7c
Show file tree
Hide file tree
Showing 24 changed files with 109 additions and 128 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,13 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@EnableWebMvc
@SpringBootApplication(scanBasePackages = "fr.dossierfacile")
@EntityScan(basePackages = "fr.dossierfacile")
@EnableJpaRepositories(basePackages = "fr.dossierfacile")
@ComponentScan(basePackages = "fr.dossierfacile")
@EnableAsync
@EnableScheduling
@Slf4j
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,9 @@ public boolean isRequestIgnored(HttpServletRequest request) {
@Override
public Map<String, String> getAdditionalContextElements() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || authentication.getPrincipal() == null) {
if (authentication == null || authentication.getPrincipal() == null || !(authentication.getPrincipal() instanceof Jwt principal)) {
return Map.of();
}
Jwt principal = (Jwt) authentication.getPrincipal();
Map<String, String> map = new TreeMap<>();
map.put(EMAIL, principal.getClaimAsString("email"));
return map;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,50 +1,13 @@
package fr.dossierfacile.api.dossierfacileapiowner.config;

import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.web.client.RestTemplate;

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

@Configuration
public class GeneralConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}


@Bean
public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier, ServletEndpointsSupplier servletEndpointsSupplier, ControllerEndpointsSupplier controllerEndpointsSupplier, EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties, WebEndpointProperties webEndpointProperties, Environment environment) {
List<ExposableEndpoint<?>> allEndpoints = new ArrayList();
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
allEndpoints.addAll(webEndpoints);
allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
String basePath = webEndpointProperties.getBasePath();
EndpointMapping endpointMapping = new EndpointMapping(basePath);
boolean shouldRegisterLinksMapping = this.shouldRegisterLinksMapping(webEndpointProperties, environment, basePath);
return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes, corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath), shouldRegisterLinksMapping, null);
}


private boolean shouldRegisterLinksMapping(WebEndpointProperties webEndpointProperties, Environment environment, String basePath) {
return webEndpointProperties.getDiscovery().isEnabled() && (StringUtils.isNotBlank(basePath) || ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public class ResourceServerConfig {
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.addFilterBefore(new ConnectionContextFilter(), FilterSecurityInterceptor.class)
.formLogin(AbstractHttpConfigurer::disable)
.httpBasic(AbstractHttpConfigurer::disable)
.csrf(AbstractHttpConfigurer::disable)
.addFilterBefore(new WebhookFilter(token, headerName), BasicAuthenticationFilter.class)
Expand All @@ -56,12 +57,12 @@ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

@Bean
CorsConfigurationSource corsConfigurationSource() {
var configuration = new CorsConfiguration();
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOriginPatterns(Collections.singletonList("*"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("Access-Control-Allow-Headers", "Access-Control-Allow-Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", "Origin", "Cache-Control", "Content-Type", "Authorization", "Baggage", "Sentry-trace"));
configuration.setAllowedMethods(Arrays.asList("DELETE", "GET", "POST", "PATCH", "PUT"));
var source = new UrlBasedCorsConfigurationSource();
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
* DossierFacile will send callback request at change on tenant status.
* This filter check if callback request contain a valid x-api-key.
*/
public class WebhookFilter extends OncePerRequestFilter {
private final String token;
private final String headerName;
Expand Down Expand Up @@ -49,6 +53,4 @@ protected boolean shouldNotFilter(@NotNull HttpServletRequest request) {
RequestMatcher matcher = new NegatedRequestMatcher(uriMatcher);
return matcher.matches(request);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
<includeMdcKeyName>client</includeMdcKeyName>
<includeMdcKeyName>user</includeMdcKeyName>
<includeMdcKeyName>request_id</includeMdcKeyName>
<includeMdcKeyName>response_status</includeMdcKeyName>
<includeMdcKeyName>email</includeMdcKeyName>
</encoder>
</appender>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
.cors(withDefaults())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/swagger-ui.html", "/swagger-ui/**", "/v3/api-docs/**",
"/api/register/account", "/api/register/confirmAccount/**",
"/api/register/account", "/api/tenant/doNotArchive/**",
"/api/auth/**", "/api/user/forgotPassword", "/api/user/createPassword/**",
"/api/document/**", "/api/application/full/**", "/api/application/light/**",
"/api/application/fullPdf/**", "/api/tenant/property/**",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@ public boolean isRequestIgnored(HttpServletRequest request) {
@Override
public Map<String, String> getAdditionalContextElements() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || authentication.getPrincipal() == null) {
if (authentication == null || authentication.getPrincipal() == null || !(authentication.getPrincipal() instanceof Jwt principal)) {
return Map.of();
}
Jwt principal = (Jwt) authentication.getPrincipal();
Map<String, String> map = new TreeMap<>();
map.put(CLIENT_ID, principal.getClaimAsString("azp"));
map.put(KC_ID, principal.getClaimAsString("sub"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ public class RegisterController {

private final TenantMapper tenantMapper;
private final TenantService tenantService;
private final UserService userService;
private final AuthenticationFacade authenticationFacade;
private final LogService logService;

Expand All @@ -52,13 +51,6 @@ public ResponseEntity<TenantModel> account(@Validated(Dossier.class) @RequestBod
return ok(tenantModel);
}

@GetMapping("/confirmAccount/{token}")
public ResponseEntity<Void> confirmAccount(@PathVariable String token) {
long tenantId = userService.confirmAccount(token);
logService.saveLog(LogType.EMAIL_ACCOUNT_VALIDATED, tenantId);
return ok().build();
}

@PreAuthorize("hasPermissionOnTenant(#namesForm.tenantId)")
@PostMapping(value = "/names", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<TenantModel> names(@Validated(Dossier.class) @RequestBody NamesForm namesForm) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,9 @@ public ResponseEntity<String> sendFileByMail(@RequestBody ShareFileByMailForm sh
}
return ok("");
}
@GetMapping("/doNotArchive/{token}")
public ResponseEntity<Void> doNotArchive(@PathVariable String token) {
tenantService.doNotArchive(token);
return ok().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,8 @@
import fr.dossierfacile.api.front.service.interfaces.TenantService;
import fr.dossierfacile.api.front.service.interfaces.UserApiService;
import fr.dossierfacile.api.front.util.Obfuscator;
import fr.dossierfacile.common.entity.ApartmentSharing;
import fr.dossierfacile.common.entity.ApartmentSharingLink;
import fr.dossierfacile.common.entity.Tenant;
import fr.dossierfacile.common.entity.UserApi;
import fr.dossierfacile.common.enums.ApartmentSharingLinkType;
import fr.dossierfacile.common.enums.LogType;
import fr.dossierfacile.common.enums.PartnerCallBackType;
import fr.dossierfacile.common.enums.TenantFileStatus;
import fr.dossierfacile.common.enums.TenantType;
import fr.dossierfacile.common.entity.*;
import fr.dossierfacile.common.enums.*;
import fr.dossierfacile.common.model.TenantUpdate;
import fr.dossierfacile.common.repository.ApartmentSharingLinkRepository;
import fr.dossierfacile.common.repository.ApartmentSharingRepository;
Expand All @@ -30,6 +23,7 @@
import fr.dossierfacile.common.service.interfaces.PartnerCallBackService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
Expand Down Expand Up @@ -61,17 +55,30 @@ public <T> TenantModel saveStepRegister(Tenant tenant, T formStep, StepRegister
}

@Override
public void updateLastLoginDateAndResetWarnings(Tenant tenant) {
tenant.setLastLoginDate(LocalDateTime.now());
tenant.setWarnings(0);
if (tenant.getStatus() == TenantFileStatus.ARCHIVED) {
tenant.setStatus(TenantFileStatus.INCOMPLETE);
partnerCallBackService.sendCallBack(tenant, PartnerCallBackType.RETURNED_ACCOUNT);
public void updateLastLoginDateAndResetWarnings(Tenant tenantToUpdate) {
LocalDateTime currentTime = LocalDateTime.now();
for (Tenant tenant : tenantToUpdate.getApartmentSharing().getTenants()) {
if (tenant.getId() == tenantToUpdate.getId() || StringUtils.isBlank(tenant.getEmail())) {
tenant.setLastLoginDate(currentTime);
tenant.setWarnings(0);
if (tenant.getStatus() == TenantFileStatus.ARCHIVED) {
tenant.setStatus(TenantFileStatus.INCOMPLETE);
partnerCallBackService.sendCallBack(tenant, PartnerCallBackType.RETURNED_ACCOUNT);
}
log.info("Updating last_login_date of tenant with ID [" + tenant.getId() + "]");
tenantRepository.save(tenant);
}
}
log.info("Updating last_login_date of tenant with ID [" + tenant.getId() + "]");
tenantRepository.save(tenant);
}

@Override
@Transactional
public void doNotArchive(String token) {
ConfirmationToken confirmationToken = confirmationTokenService.findByToken(token);
Tenant tenant = tenantRepository.getReferenceById(confirmationToken.getUser().getId());
tenant.setConfirmationToken(null);
updateLastLoginDateAndResetWarnings(tenant);
logService.saveLog(LogType.DO_NOT_ARCHIVE, tenant.getId());
}
@Override
@Transactional
public Tenant create(Tenant tenant) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,13 @@
import fr.dossierfacile.api.front.model.tenant.TenantModel;
import fr.dossierfacile.api.front.repository.PasswordRecoveryTokenRepository;
import fr.dossierfacile.api.front.repository.UserRepository;
import fr.dossierfacile.api.front.service.interfaces.ApartmentSharingService;
import fr.dossierfacile.api.front.service.interfaces.KeycloakService;
import fr.dossierfacile.api.front.service.interfaces.MailService;
import fr.dossierfacile.api.front.service.interfaces.PasswordRecoveryTokenService;
import fr.dossierfacile.api.front.service.interfaces.UserApiService;
import fr.dossierfacile.api.front.service.interfaces.UserService;
import fr.dossierfacile.common.entity.ApartmentSharing;
import fr.dossierfacile.common.entity.ConfirmationToken;
import fr.dossierfacile.common.entity.PasswordRecoveryToken;
import fr.dossierfacile.common.entity.Tenant;
import fr.dossierfacile.common.entity.User;
import fr.dossierfacile.common.entity.UserApi;
import fr.dossierfacile.api.front.service.interfaces.*;
import fr.dossierfacile.common.entity.*;
import fr.dossierfacile.common.enums.ApplicationType;
import fr.dossierfacile.common.enums.LogType;
import fr.dossierfacile.common.enums.PartnerCallBackType;
import fr.dossierfacile.common.enums.TenantType;
import fr.dossierfacile.common.exceptions.ConfirmationTokenNotFoundException;
import fr.dossierfacile.common.model.WebhookDTO;
import fr.dossierfacile.common.repository.ConfirmationTokenRepository;
import fr.dossierfacile.common.repository.TenantCommonRepository;
import fr.dossierfacile.common.service.interfaces.LogService;
import fr.dossierfacile.common.service.interfaces.PartnerCallBackService;
Expand All @@ -35,7 +23,6 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
Expand All @@ -44,7 +31,6 @@
@RequiredArgsConstructor
@Slf4j
public class UserServiceImpl implements UserService {
private final ConfirmationTokenRepository confirmationTokenRepository;
private final UserRepository userRepository;
private final PasswordRecoveryTokenRepository passwordRecoveryTokenRepository;
private final MailService mailService;
Expand All @@ -58,24 +44,6 @@ public class UserServiceImpl implements UserService {
private final ApartmentSharingService apartmentSharingService;
private final TenantCommonService tenantCommonService;

@Override
@Transactional
public long confirmAccount(String token) {
ConfirmationToken confirmationToken = confirmationTokenRepository.findByToken(token).orElseThrow(() -> new ConfirmationTokenNotFoundException(token));
User user = confirmationToken.getUser();
user.setEnabled(true);
user.setConfirmationToken(null);
user.setLastLoginDate(LocalDateTime.now());
userRepository.save(user);
confirmationTokenRepository.delete(confirmationToken);
if (user.getKeycloakId() != null) {
keycloakService.confirmKeycloakUser(user.getKeycloakId());
// else we assume it's a partner account
}
tenantRepository.resetWarnings(user.getId());
return user.getId();
}

@Override
public TenantModel createPassword(User user, String password) {
keycloakService.createKeyCloakPassword(user.getKeycloakId(), password);
Expand All @@ -90,7 +58,7 @@ public TenantModel createPassword(String token, String password) {
// check if keycloak is correctly synchronised
User user = passwordRecoveryToken.getUser();
var keycloakId = keycloakService.getKeycloakId(user.getEmail());
if (!StringUtils.equals(keycloakId, user.getKeycloakId())){
if (!StringUtils.equals(keycloakId, user.getKeycloakId())) {
log.warn("Tenant keycloakId has been synchronized - user_id: " + user.getId());
user.setKeycloakId(keycloakId);
userRepository.save(user);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,6 @@ public interface TenantService {
List<TenantUpdate> findTenantUpdateByLastUpdateAndPartner(LocalDateTime from, UserApi userApi, Long limit, boolean includeDeleted, boolean includeRevoked);

void sendFileByMail(Tenant tenant, String email, String shareType);

void doNotArchive(String token);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
import fr.dossierfacile.common.entity.User;

public interface UserService {
long confirmAccount(String token);

TenantModel createPassword(User user, String password);

TenantModel createPassword(String token, String password);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
<includeMdcKeyName>user</includeMdcKeyName>
<includeMdcKeyName>email</includeMdcKeyName>
<includeMdcKeyName>request_id</includeMdcKeyName>
<includeMdcKeyName>response_status</includeMdcKeyName>
</encoder>
</appender>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public abstract class AbstractConnectionContextFilter extends HttpFilter {

private static final String URI = "uri";
private static final String REQUEST_ID = "request_id";
private static final String RESPONSE_STATUS = "response_status";

@Override
protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
Expand All @@ -40,7 +41,16 @@ protected void doFilter(HttpServletRequest request, HttpServletResponse response
try {
chain.doFilter(request, response);
} finally {
log.info("Response: status={}, method={}, path={}", response.getStatus(), request.getMethod(), request.getRequestURI());
if (response.getStatus() != 200) {
MDC.put(RESPONSE_STATUS, String.valueOf(response.getStatus()));
if (response.getStatus() < 400) {
log.info("Response: status={}, method={}, path={}", response.getStatus(), request.getMethod(), request.getRequestURI());
} else if (response.getStatus() < 500) {
log.warn("Response: status={}, method={}, path={}", response.getStatus(), request.getMethod(), request.getRequestURI());
} else {
log.error("Response: status={}, method={}, path={}", response.getStatus(), request.getMethod(), request.getRequestURI());
}
}
MDC.clear();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public enum LogType {
FIRST_ACCOUNT_WARNING_FOR_DOCUMENT_DELETION,
SECOND_ACCOUNT_WARNING_FOR_DOCUMENT_DELETION,
DOCUMENT_DELETION_AFTER_2_ACCOUNT_WARNINGS,
DO_NOT_ARCHIVE,
FC_ACCOUNT_CREATION,
FC_ACCOUNT_LINK,
PARTNER_ACCESS_REVOKED,
Expand Down
Loading

0 comments on commit d2aed7c

Please sign in to comment.