diff --git a/backend/src/main/java/ru/micord/ervu/security/LogoutSuccessHandler.java b/backend/src/main/java/ru/micord/ervu/security/LogoutSuccessHandler.java index 9993b23..3867b41 100644 --- a/backend/src/main/java/ru/micord/ervu/security/LogoutSuccessHandler.java +++ b/backend/src/main/java/ru/micord/ervu/security/LogoutSuccessHandler.java @@ -25,9 +25,7 @@ public class LogoutSuccessHandler public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { String url = esiaAuthService.logout(request, response); - response.setStatus(HttpServletResponse.SC_OK); - response.getWriter().write(url); - response.getWriter().flush(); + response.sendRedirect(url); CsrfToken csrfToken = this.csrfTokenRepository.generateToken(request); this.csrfTokenRepository.saveToken(csrfToken, request, response); } diff --git a/backend/src/main/java/ru/micord/ervu/security/esia/service/EsiaAuthService.java b/backend/src/main/java/ru/micord/ervu/security/esia/service/EsiaAuthService.java index f8ae592..671029d 100644 --- a/backend/src/main/java/ru/micord/ervu/security/esia/service/EsiaAuthService.java +++ b/backend/src/main/java/ru/micord/ervu/security/esia/service/EsiaAuthService.java @@ -13,7 +13,6 @@ import java.time.format.DateTimeFormatter; import java.util.LinkedHashMap; import java.util.Map; import java.util.UUID; -import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -204,8 +203,7 @@ public class EsiaAuthService { Response ervuIdResponse = getErvuIdResponse(esiaAccessTokenStr); Token token = jwtTokenService.createAccessToken(esiaAccessToken.getSbj_id(), expiresIn, ervuIdResponse.getErvuId()); int expiry = tokenResponse.getExpires_in().intValue(); - Cookie accessCookie = securityHelper.createAccessCookie(token.getValue(), expiry); - response.addCookie(accessCookie); + securityHelper.addAccessCookies(response, token.getValue(), expiry); UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(token.getUserAccountId(), null); SecurityContext context = SecurityContextHolder.createEmptyContext(); @@ -214,8 +212,6 @@ public class EsiaAuthService { authenticationManager.authenticate(jwtAuthentication); context.setAuthentication(jwtAuthentication); SecurityContextHolder.setContext(context); - Cookie authMarkerCookie = securityHelper.createAuthMarkerCookie("true", expiry); - response.addCookie(authMarkerCookie); return ResponseEntity.ok("Authentication successful"); } catch (Exception e) { @@ -281,8 +277,7 @@ public class EsiaAuthService { Response ervuIdResponse = getErvuIdResponse(esiaAccessTokenStr); Token token = jwtTokenService.createAccessToken(esiaAccessToken.getSbj_id(), expiresIn, ervuIdResponse.getErvuId()); int expiry = tokenResponse.getExpires_in().intValue(); - Cookie accessCookie = securityHelper.createAccessCookie(token.getValue(), expiry); - response.addCookie(accessCookie); + securityHelper.addAccessCookies(response, token.getValue(), expiry); UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(token.getUserAccountId(), null); SecurityContext context = SecurityContextHolder.createEmptyContext(); @@ -291,8 +286,6 @@ public class EsiaAuthService { authenticationManager.authenticate(jwtAuthentication); context.setAuthentication(jwtAuthentication); SecurityContextHolder.setContext(context); - Cookie authMarkerCookie = securityHelper.createAuthMarkerCookie("true", expiry); - response.addCookie(authMarkerCookie); } catch (Exception e) { throw new RuntimeException(e); diff --git a/backend/src/main/java/ru/micord/ervu/security/webbpm/jwt/helper/SecurityHelper.java b/backend/src/main/java/ru/micord/ervu/security/webbpm/jwt/helper/SecurityHelper.java index 0a222c7..9c966f6 100644 --- a/backend/src/main/java/ru/micord/ervu/security/webbpm/jwt/helper/SecurityHelper.java +++ b/backend/src/main/java/ru/micord/ervu/security/webbpm/jwt/helper/SecurityHelper.java @@ -1,43 +1,89 @@ package ru.micord.ervu.security.webbpm.jwt.helper; -import javax.servlet.http.Cookie; +import java.net.IDN; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import javax.annotation.PostConstruct; +import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Value; -import ru.micord.ervu.security.webbpm.jwt.util.SecurityUtil; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseCookie; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import static org.springframework.web.context.request.RequestAttributes.REFERENCE_REQUEST; import static ru.micord.ervu.security.webbpm.jwt.util.SecurityUtil.AUTH_MARKER; import static ru.micord.ervu.security.webbpm.jwt.util.SecurityUtil.AUTH_TOKEN; -import static ru.micord.ervu.security.webbpm.jwt.util.SecurityUtil.createCookie; public final class SecurityHelper { @Value("${cookie.path:#{null}}") private String accessCookiePath; + @Value("${cookie.domain:#{null}}") + private String accessCookieDomain; + @Value("${cookie.secure:false}") + private boolean accessCookieSecure; + @Value("${cookie.same.site:Lax}") + private String accessCookieSameSite; + + @PostConstruct + private void init() { + + if (accessCookieDomain != null) { + accessCookieDomain = IDN.toASCII(accessCookieDomain); + } + } public void clearAccessCookies(HttpServletResponse response) { - Cookie tokenCookie = createCookie(AUTH_TOKEN, null, null); - tokenCookie.setMaxAge(0); - tokenCookie.setPath(accessCookiePath); - tokenCookie.setHttpOnly(true); - response.addCookie(tokenCookie); + ResponseCookie emptyAuthToken = createCookie(AUTH_TOKEN, null, accessCookiePath) + .maxAge(0).build(); + addResponseCookie(response, emptyAuthToken); - Cookie markerCookie = createCookie(AUTH_MARKER, null, null); - markerCookie.setMaxAge(0); - markerCookie.setPath("/"); - response.addCookie(markerCookie); + ResponseCookie emptyAuthMarker = createCookie(AUTH_MARKER, null, "/") + .maxAge(0) + .secure(false) + .httpOnly(false) + .build(); + addResponseCookie(response, emptyAuthMarker); } - public Cookie createAccessCookie(String cookieValue, int expiry) { - Cookie authToken = createCookie(SecurityUtil.AUTH_TOKEN, cookieValue, accessCookiePath); - authToken.setPath(accessCookiePath); - authToken.setMaxAge(expiry); - return authToken; + private void addResponseCookie(HttpServletResponse response, ResponseCookie cookie) { + response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString()); } - public Cookie createAuthMarkerCookie(String cookieValue, int expiry) { - Cookie marker = createCookie(AUTH_MARKER, cookieValue, "/"); - marker.setMaxAge(expiry); - marker.setHttpOnly(false); - return marker; + public void addAccessCookies(HttpServletResponse response, String cookieValue, int expiry) { + ResponseCookie authTokenCookie = createCookie(AUTH_TOKEN, cookieValue, accessCookiePath) + .maxAge(expiry) + .build(); + addResponseCookie(response, authTokenCookie); + + ResponseCookie authMarker = createCookie(AUTH_MARKER, "true", "/") + .maxAge(expiry) + .secure(false) + .httpOnly(false) + .build(); + addResponseCookie(response, authMarker); + } + + public ResponseCookie.ResponseCookieBuilder createCookie(String name, String value, String path) { + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + + if (requestAttributes == null) { + throw new IllegalStateException("Must be called only in request context"); + } + HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference( + REFERENCE_REQUEST); + + if (request == null) { + throw new IllegalStateException("Must be called only in request context"); + } + String cookieValue = value != null ? URLEncoder.encode(value, StandardCharsets.UTF_8) : ""; + return ResponseCookie.from(name, cookieValue) + .path(path != null ? path : request.getContextPath()) + .httpOnly(true) + .domain(accessCookieDomain) + .secure(accessCookieSecure) + .sameSite(accessCookieSameSite); } } diff --git a/backend/src/main/java/ru/micord/ervu/security/webbpm/jwt/util/SecurityUtil.java b/backend/src/main/java/ru/micord/ervu/security/webbpm/jwt/util/SecurityUtil.java index 69019f1..9dbc11a 100644 --- a/backend/src/main/java/ru/micord/ervu/security/webbpm/jwt/util/SecurityUtil.java +++ b/backend/src/main/java/ru/micord/ervu/security/webbpm/jwt/util/SecurityUtil.java @@ -23,24 +23,6 @@ public final class SecurityUtil { //empty } - public static Cookie createCookie(String name, String value, String path) { - String cookieValue = value != null ? URLEncoder.encode(value, StandardCharsets.UTF_8) : null; - Cookie cookie = new Cookie(name, cookieValue); - RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); - HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference( - REFERENCE_REQUEST); - - if (path != null) { - cookie.setPath(path); - } - else { - cookie.setPath(request.getContextPath()); - } - cookie.setHttpOnly(true); - - return cookie; - } - public static String extractAuthToken(HttpServletRequest httpRequest) { Cookie cookie = WebUtils.getCookie(httpRequest, AUTH_TOKEN); return cookie != null ? cookie.getValue() : null; diff --git a/frontend/index.webpack.html b/frontend/index.webpack.html index 871a82c..8aac9d4 100644 --- a/frontend/index.webpack.html +++ b/frontend/index.webpack.html @@ -4,6 +4,11 @@ Личный кабинет физ.лица + + + + diff --git a/frontend/src/resources/template/app/component/log_out.html b/frontend/src/resources/template/app/component/log_out.html index f488796..a691d3f 100644 --- a/frontend/src/resources/template/app/component/log_out.html +++ b/frontend/src/resources/template/app/component/log_out.html @@ -1,6 +1,10 @@
Мои данные - +
+ +
- \ No newline at end of file +
+ +