Merge branch 'develop' into feature/ERVU-590

This commit is contained in:
m.epshtein 2025-11-19 11:46:57 +03:00
commit 84cfb974f4
9 changed files with 79 additions and 43 deletions

View file

@ -142,9 +142,9 @@ public class EmployeeInfoFileUploadService {
UserIdsPair userIdsPair = SecurityUtil.getUserIdsPair();
LocalDateTime now = LocalDateTime.now();
String departureDateTime = DateUtils.convertToString(now);
if (userIdsPair == null || !isValidCsvWithSig(multipartFile, signFile)) {
return false;
validateCsvWithSigFormat(multipartFile, signFile);
if (userIdsPair == null) {
throw new FileUploadException("userIdsPair is null");
}
String esiaUserId = userIdsPair.getEsiaUserId();
String ervuId = userIdsPair.getErvuId();
@ -424,10 +424,11 @@ public class EmployeeInfoFileUploadService {
clearS3(response);
}
private boolean isValidCsvWithSig(MultipartFile file, MultipartFile signFile) {
private void validateCsvWithSigFormat(MultipartFile file, MultipartFile signFile) {
if (file == null || signFile == null || file.getOriginalFilename() == null
|| signFile.getOriginalFilename() == null) {
return false;
throw new FileUploadException("Failed to process files: " + file + ", " +
signFile);
}
Tika tika = new Tika();
MimeTypes defaultMimeTypes = MimeTypes.getDefaultMimeTypes();
@ -449,19 +450,18 @@ public class EmployeeInfoFileUploadService {
".sig");
if (!isCsv) {
LOGGER.info("Invalid main file: name={}, mimeType={}", fileName, fileMimeType);
LOGGER.error("Invalid main file: name={}, mimeType={}", fileName, fileMimeType);
throw new LocalizedException("file_format_invalid", MESSAGE_SOURCE, fileName);
}
if (!isSig) {
LOGGER.info("Invalid signature file: name={}, mimeType={}", signFileName, signMimeType);
LOGGER.error("Invalid signature file: name={}, mimeType={}", signFileName, signMimeType);
throw new LocalizedException("file_format_invalid", MESSAGE_SOURCE, fileName);
}
return isCsv && isSig;
}
catch (MimeTypeException | IOException e) {
LOGGER.error("Failed to process files: {}, {}", file.getOriginalFilename(),
throw new FileUploadException("Failed to process files: " + file.getOriginalFilename() + ", " +
signFile.getOriginalFilename(), e
);
return false;
}
}

View file

@ -0,0 +1,26 @@
package ru.micord.ervu.controller;
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import ru.micord.ervu.security.webbpm.jwt.service.JwtTokenService;
/**
* @author Adel Kalimullin
*/
@RestController
public class UploadAccessController {
private final JwtTokenService jwtTokenService;
public UploadAccessController(JwtTokenService jwtTokenService) {
this.jwtTokenService = jwtTokenService;
}
@GetMapping("/upload/access")
public ResponseEntity<Boolean> checkUploadPermission(HttpServletRequest request) {
boolean fileUploadAllowed = jwtTokenService.isFileUploadAllowed(request);
return ResponseEntity.ok(fileUploadAllowed);
}
}

View file

@ -6,6 +6,5 @@ public class SecurityConstants {
public static final String AUTH_MARKER = "webbpm.ervu-lkrp-ul";
public static final String PRNS_UUID = "prns_uuid_ul";
public static final String STICKY_SESSION = "stickysession";
public static final String UPLOAD_ALLOWED_MARKER = "upload_allowed";
public static final String EMPLOYEE_DOCUMENT_PATH = "/employee/document";
}

View file

@ -556,7 +556,7 @@ public class EsiaAuthService {
private void createTokenAndAddCookie(HttpServletResponse response, String userId, String ervuId,
Boolean hasRole, Boolean fileUploadAllowed, Long expiresIn) {
Token token = jwtTokenService.createAccessToken(userId, expiresIn, ervuId, hasRole, fileUploadAllowed);
securityHelper.addAccessCookies(response, token.getValue(), expiresIn.intValue(), fileUploadAllowed);
securityHelper.addAccessCookies(response, token.getValue(), expiresIn.intValue());
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(token.getUserAccountId(), null);
SecurityContext context = SecurityContextHolder.createEmptyContext();

View file

@ -17,7 +17,6 @@ import static org.springframework.web.context.request.RequestAttributes.REFERENC
import static ru.micord.ervu.security.SecurityConstants.AUTH_MARKER;
import static ru.micord.ervu.security.SecurityConstants.AUTH_TOKEN;
import static ru.micord.ervu.security.SecurityConstants.PRNS_UUID;
import static ru.micord.ervu.security.SecurityConstants.UPLOAD_ALLOWED_MARKER;
public final class SecurityHelper {
@Value("${cookie.path:#{null}}")
@ -46,14 +45,6 @@ public final class SecurityHelper {
.httpOnly(false)
.build();
addResponseCookie(response, emptyAuthMarker);
ResponseCookie emptyUploadAllowed = createCookie(UPLOAD_ALLOWED_MARKER, null, "/")
.maxAge(0)
.secure(false)
.httpOnly(false)
.build();
addResponseCookie(response, emptyUploadAllowed);
clearCookie(response, PRNS_UUID, accessCookiePath);
}
@ -61,8 +52,7 @@ public final class SecurityHelper {
response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString());
}
public void addAccessCookies(HttpServletResponse response, String cookieValue, int expiry,
Boolean fileUploadAllowed) {
public void addAccessCookies(HttpServletResponse response, String cookieValue, int expiry) {
ResponseCookie authTokenCookie = createCookie(AUTH_TOKEN, cookieValue, accessCookiePath)
.maxAge(expiry)
.build();
@ -74,15 +64,6 @@ public final class SecurityHelper {
.httpOnly(false)
.build();
addResponseCookie(response, authMarker);
if (fileUploadAllowed) {
ResponseCookie uploadAllowedCookie = createCookie(UPLOAD_ALLOWED_MARKER, "true", "/")
.maxAge(expiry)
.secure(false)
.httpOnly(false)
.build();
addResponseCookie(response, uploadAllowedCookie);
}
}
public ResponseCookie.ResponseCookieBuilder createCookie(String name, String value, String path) {

View file

@ -97,11 +97,20 @@ public class JwtTokenService {
}
public String getUserAccountId(HttpServletRequest request) {
String authToken = extractAuthToken(request);
Token validatedToken = getValidatedToken(request);
String[] ids = validatedToken.getUserAccountId().split(":");
return ids[0];
}
public boolean isFileUploadAllowed(HttpServletRequest request) {
Token validatedToken = getValidatedToken(request);
return validatedToken.isFileUploadAllowed();
}
public Token getValidatedToken(HttpServletRequest request) {
String authToken = extractAuthToken(request);
if (authToken != null) {
String[] ids = getToken(authToken).getUserAccountId().split(":");
return ids[0];
return getToken(authToken);
}
else {
throw new UnauthorizedException("Failed to get auth data. User unauthorized.");

View file

@ -7,7 +7,7 @@ cert_untrusted_root=Сертификат или цепочка сертифик
cert_is_not_time_valid=Этот сертификат или один из сертификатов в цепочке сертификатов является недопустимым по времени
file_sign_validate=Некорректная электронная подпись
mchd_validate_agent=Некорректная машиночитаемая доверенность. Представитель не совпадает с подписантом
mchd_null=Отсутствует машиночитаемая доверенность. Подписант не является руководителем организации.
mchd_null=Подписант не является руководителем организации и отсутствует машиночитаемая доверенность.
sign_ogrn_null=Приложена электронная подпись физического лица.
sign_ogrn_invalid=Файл подписан не той организацией, под которой была осуществлена загрузка.
mchd_status_invalid=Недействующая машиночитаемая доверенность.
@ -20,4 +20,5 @@ mchd_validate_principal=Некорректная машиночитаемая д
av_file_infected=Файлы заражены вирусом
mchd_cant_parse=Некорректный формат машиночитаемой доверенности
mchd_esia_error=Некорректная машиночитаемая доверенность. Доверенность не найдена.
mchd_no_sign_rights=В доверенности (МЧД) нет полномочия "Подписание сведений о воинском учете организации для загрузки в личный кабинет юридических лиц ГИС ЕРВУ"
mchd_no_sign_rights=В доверенности (МЧД) нет полномочия "Подписание сведений о воинском учете организации для загрузки в личный кабинет юридических лиц ГИС ЕРВУ"
file_format_invalid=Неверный формат или расширения файла {0}

View file

@ -20,4 +20,5 @@ mchd_validate_principal=Некорректная машиночитаемая д
av_file_infected=Файлы заражены вирусом
mchd_cant_parse=Некорректный формат машиночитаемой доверенности
mchd_esia_error=Некорректная машиночитаемая доверенность. Доверенность не найдена.
mchd_no_sign_rights=В доверенности (МЧД) нет полномочия "Подписание сведений о воинском учете организации для загрузки в личный кабинет юридических лиц ГИС ЕРВУ"
mchd_no_sign_rights=В доверенности (МЧД) нет полномочия "Подписание сведений о воинском учете организации для загрузки в личный кабинет юридических лиц ГИС ЕРВУ"
file_format_invalid=Неверный формат или расширения файла {0}

View file

@ -1,15 +1,34 @@
import {Behavior, Visible} from "@webbpm/base-package";
import {CookieService} from "ngx-cookie";
import {HttpClient} from "@angular/common/http";
import {AuthenticationService} from "../modules/security/authentication.service";
export class FileUploadChecker extends Behavior {
private cookieService: CookieService;
private httpClient: HttpClient;
private authService: AuthenticationService;
private allowed: boolean = false;
initialize() {
this.cookieService = this.injector.get(CookieService);
this.httpClient = this.injector.get(HttpClient);
this.authService = this.injector.get(AuthenticationService);
}
postStart() {
super.postStart();
if (this.authService.isAuthenticated()){
this.checkUploadPermission();
}
}
@Visible()
public fileUploadAllowed(): boolean {
return this.cookieService.get("upload_allowed") != null;
return this.allowed;
}
private checkUploadPermission(): void {
this.httpClient.get<boolean>('upload/access')
.toPromise()
.then(response => {
this.allowed = response;
});
}
}