diff --git a/backend/src/main/java/ru/micord/ervu/security/esia/controller/EsiaController.java b/backend/src/main/java/ru/micord/ervu/security/esia/controller/EsiaController.java index 0a94fe36..09cba861 100644 --- a/backend/src/main/java/ru/micord/ervu/security/esia/controller/EsiaController.java +++ b/backend/src/main/java/ru/micord/ervu/security/esia/controller/EsiaController.java @@ -32,8 +32,8 @@ public class EsiaController { } @GetMapping(value = "/esia/auth", params = "code") - public ResponseEntity esiaAuth(@RequestParam("code") String code, HttpServletRequest request, HttpServletResponse response) { - return esiaAuthService.getEsiaTokensByCode(code, request, response); + public ResponseEntity esiaAuth(@RequestParam("code") String code, @RequestParam("error") String error, HttpServletRequest request, HttpServletResponse response) { + return esiaAuthService.getEsiaTokensByCode(code, error, request, response); } @PostMapping(value = "/esia/refresh") 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 9d7a6d27..a9245a95 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 @@ -15,6 +15,7 @@ import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Objects; import java.util.UUID; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; @@ -52,12 +53,15 @@ import ru.micord.ervu.security.webbpm.jwt.helper.SecurityHelper; import ru.micord.ervu.security.webbpm.jwt.service.JwtTokenService; import ru.micord.ervu.security.webbpm.jwt.model.Token; +import static ru.micord.ervu.security.webbpm.jwt.util.SecurityUtil.getCurrentUsername; + /** * @author Eduard Tihomirov */ @Service public class EsiaAuthService { private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + private static final Long EXPIRES_IN = 3600L; @Autowired private ObjectMapper objectMapper; @Autowired @@ -157,8 +161,16 @@ public class EsiaAuthService { return uriBuilder.toString(); } - public ResponseEntity getEsiaTokensByCode(String esiaAuthCode, HttpServletRequest request, HttpServletResponse response) { + public ResponseEntity getEsiaTokensByCode(String esiaAuthCode, String error, + HttpServletRequest request, HttpServletResponse response) { try { + if (error != null) { + createTokenAndAddCookie(response, null, null, false, EXPIRES_IN); + return new ResponseEntity<>( + "Произошла неизвестная ошибка. Обратитесь к системному администратору", + HttpStatus.FORBIDDEN + ); + } String clientId = esiaConfig.getClientId(); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss xx"); ZonedDateTime dt = ZonedDateTime.now(); @@ -223,20 +235,7 @@ public class EsiaAuthService { Long expiresIn = tokenResponse.getExpires_in(); TokensStore.addAccessToken(prnOid, esiaAccessTokenStr, expiresIn); TokensStore.addRefreshToken(prnOid, esiaRefreshTokenStr, expiresIn); - Token token = jwtTokenService.createAccessToken(esiaAccessToken.getSbj_id(), expiresIn, ervuId, hasRole); - int expiry = tokenResponse.getExpires_in().intValue(); - Cookie accessCookie = securityHelper.createAccessCookie(token.getValue(), expiry); - response.addCookie(accessCookie); - UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = - new UsernamePasswordAuthenticationToken(token.getUserAccountId(), null); - SecurityContext context = SecurityContextHolder.createEmptyContext(); - JwtAuthentication jwtAuthentication = new JwtAuthentication(usernamePasswordAuthenticationToken, - esiaAccessToken.getSbj_id(), token.getValue()); - authenticationManager.authenticate(jwtAuthentication); - context.setAuthentication(jwtAuthentication); - SecurityContextHolder.setContext(context); - Cookie authMarkerCookie = securityHelper.createAuthMarkerCookie("true", expiry); - response.addCookie(authMarkerCookie); + createTokenAndAddCookie(response, esiaAccessToken.getSbj_id(), ervuId, hasRole, expiresIn); if (!hasRole) { LOGGER.error("The user with id = " + prnOid + " does not have the required role"); return new ResponseEntity<>( @@ -247,7 +246,14 @@ public class EsiaAuthService { return ResponseEntity.ok("Authentication successful"); } catch (Exception e) { - throw new RuntimeException(e); + createTokenAndAddCookie(response, null, null, false, EXPIRES_IN); + String messageId = getMessageId(e); + String messageWithId = String.format("[%s] %s", messageId, e.getMessage()); + LOGGER.error(messageWithId, e); + return new ResponseEntity<>( + "Произошла ошибка " + messageId + ". Обратитесь к системному администратору", + HttpStatus.FORBIDDEN + ); } } @@ -309,19 +315,7 @@ public class EsiaAuthService { TokensStore.addAccessToken(prnOid, accessToken, expiresIn); TokensStore.addRefreshToken(prnOid, newRefreshToken, expiresIn); String ervuId = getErvuId(accessToken, prnOid); - Token token = jwtTokenService.createAccessToken(esiaAccessToken.getSbj_id(), expiresIn, ervuId, true); - int expiry = tokenResponse.getExpires_in().intValue(); - Cookie accessCookie = securityHelper.createAccessCookie(token.getValue(), expiry); - response.addCookie(accessCookie); - UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = - new UsernamePasswordAuthenticationToken(token.getUserAccountId(), null); - SecurityContext context = SecurityContextHolder.createEmptyContext(); - JwtAuthentication authentication = new JwtAuthentication(usernamePasswordAuthenticationToken, - esiaAccessToken.getSbj_id(), token.getValue()); - context.setAuthentication(authentication); - SecurityContextHolder.setContext(context); - Cookie authMarkerCookie = securityHelper.createAuthMarkerCookie("true", expiry); - response.addCookie(authMarkerCookie); + createTokenAndAddCookie(response, esiaAccessToken.getSbj_id(), ervuId, true, expiresIn); } catch (Exception e) { throw new RuntimeException(e); @@ -457,4 +451,28 @@ public class EsiaAuthService { employee.setOrgOid(employeeModel.getOrgOid()); return employee; } + + private String getMessageId(Exception exception) { + return Integer.toUnsignedString(Objects + .hashCode(getCurrentUsername()), 36) + + "-" + + Integer.toUnsignedString(exception.hashCode(), 36); + } + + private void createTokenAndAddCookie(HttpServletResponse response, String userId, String ervuId, + Boolean hasRole, Long expiresIn) { + Token token = jwtTokenService.createAccessToken(userId, expiresIn, ervuId, hasRole); + Cookie accessCookie = securityHelper.createAccessCookie(token.getValue(), expiresIn.intValue()); + response.addCookie(accessCookie); + UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = + new UsernamePasswordAuthenticationToken(token.getUserAccountId(), null); + SecurityContext context = SecurityContextHolder.createEmptyContext(); + JwtAuthentication authentication = new JwtAuthentication(usernamePasswordAuthenticationToken, + userId, token.getValue()); + context.setAuthentication(authentication); + authenticationManager.authenticate(authentication); + SecurityContextHolder.setContext(context); + Cookie authMarkerCookie = securityHelper.createAuthMarkerCookie("true", expiresIn.intValue()); + response.addCookie(authMarkerCookie); + } } 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 b2314e37..170c3b6f 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 @@ -5,6 +5,8 @@ import java.nio.charset.StandardCharsets; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.util.WebUtils; @@ -42,4 +44,12 @@ public final class SecurityUtil { Cookie cookie = WebUtils.getCookie(httpRequest, AUTH_TOKEN); return cookie != null ? cookie.getValue() : null; } + + public static String getCurrentUsername() { + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + if (auth != null && auth.isAuthenticated()) { + return auth.getName(); + } + return null; + } } diff --git a/frontend/src/ts/modules/security/guard/auth.guard.ts b/frontend/src/ts/modules/security/guard/auth.guard.ts index 89fba5b9..3e8861b6 100644 --- a/frontend/src/ts/modules/security/guard/auth.guard.ts +++ b/frontend/src/ts/modules/security/guard/auth.guard.ts @@ -34,18 +34,8 @@ export abstract class AuthGuard implements CanActivate { if (isAccess) { return true; } - else if (error) { - let userErrorMessage = 'Произошла неизвестная ошибка. Обратитесь к системному администратору'; - let errorCode = this.extractCode(errorDescription); - if (errorCode) { - userErrorMessage = EsiaErrorDetail.getDescription(errorCode); - } - let errorMessage = error + ', error description = ' + errorDescription; - this.messageService.error(userErrorMessage) - throw new Error(errorMessage); - } - else if (code) { - const params = new HttpParams().set('code', code); + if (code || error) { + const params = new HttpParams().set('code', code).set('error', error); this.httpClient.get("esia/auth", { params: params, responseType: 'text', observe: 'response', headers: { @@ -61,8 +51,20 @@ export abstract class AuthGuard implements CanActivate { let errorMessage = reason.error.messages != null ? reason.error.messages : reason.error.replaceAll('\\', ''); - this.messageService.error(errorMessage); - console.error(reason); + if (error) { + errorMessage = 'Произошла неизвестная ошибка. Обратитесь к системному администратору'; + let errorCode = this.extractCode(errorDescription); + if (errorCode) { + errorMessage = EsiaErrorDetail.getDescription(errorCode); + } + let consoleError = error + ', error description = ' + errorDescription; + this.messageService.error(errorMessage); + console.error(consoleError); + } + else { + this.messageService.error(errorMessage); + console.error(reason); + } }); return false; }