SUPPORT-8579: Fix

This commit is contained in:
Eduard Tihomirov 2024-10-03 16:28:43 +03:00
parent 1d7e30eb64
commit d5082c3ce2
8 changed files with 147 additions and 72 deletions

View file

@ -1,40 +0,0 @@
package ru.micord.ervu.security.esia;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Eduard Tihomirov
*/
public class Tokens {
private static final Map<String, String> accessTokensMap = new ConcurrentHashMap<>();
private static final Map<String, String> refreshTokensMap = new ConcurrentHashMap<>();
public static void addAccessToken(String prnOid, String token) {
if (token != null) {
accessTokensMap.put(prnOid, token);
}
}
public static String getAccessToken(String prnOid) {
return accessTokensMap.get(prnOid);
}
public static void removeAccessToken(String prnOid) {
accessTokensMap.remove(prnOid);
}
public static void addRefreshToken(String prnOid, String token) {
if (token != null) {
refreshTokensMap.put(prnOid, token);
}
}
public static String getRefreshToken(String prnOid) {
return refreshTokensMap.get(prnOid);
}
public static void removeRefreshToken(String prnOid) {
refreshTokensMap.remove(prnOid);
}
}

View file

@ -27,7 +27,7 @@ import ru.micord.ervu.kafka.model.Document;
import ru.micord.ervu.kafka.model.Person;
import ru.micord.ervu.kafka.model.Response;
import ru.micord.ervu.kafka.service.ReplyingKafkaService;
import ru.micord.ervu.security.esia.Tokens;
import ru.micord.ervu.security.esia.token.TokensStore;
import ru.micord.ervu.security.esia.config.EsiaConfig;
import ru.micord.ervu.security.esia.model.FormUrlencoded;
import ru.micord.ervu.security.esia.model.EsiaAccessToken;
@ -205,10 +205,11 @@ public class EsiaAuthService {
String decodedString = new String(decodedBytes);
EsiaAccessToken esiaAccessToken = objectMapper.readValue(decodedString, EsiaAccessToken.class);
String prnOid = esiaAccessToken.getSbj_id();
Tokens.addAccessToken(prnOid, accessToken);
Tokens.addRefreshToken(prnOid, refreshToken);
Long expiresIn = tokenResponse.getExpires_in();
TokensStore.addAccessToken(prnOid, accessToken, expiresIn);
TokensStore.addRefreshToken(prnOid, refreshToken, expiresIn);
String ervuId = getErvuId(accessToken);
Token token = jwtTokenService.createAccessToken(esiaAccessToken.getSbj_id(), tokenResponse.getExpires_in(), ervuId);
Token token = jwtTokenService.createAccessToken(esiaAccessToken.getSbj_id(), expiresIn, ervuId);
Cookie authToken = new Cookie("auth_token", token.getValue());
authToken.setPath(cookiePath);
authToken.setHttpOnly(true);
@ -234,19 +235,7 @@ public class EsiaAuthService {
public void getEsiaTokensByRefreshToken(HttpServletRequest request, HttpServletResponse response) {
try {
String authTokenCookie = null;
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("auth_token")) {
authTokenCookie = cookie.getValue();
}
}
}
Token authJwtToken = jwtTokenService.getToken(authTokenCookie);
String[] split = authJwtToken.getUserAccountId().split(":");
String userId = split[0];
String refreshToken = Tokens.getRefreshToken(userId);
String refreshToken = jwtTokenService.getRefreshToken(request);
String clientId = esiaConfig.getClientId();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss xx");
ZonedDateTime dt = ZonedDateTime.now();
@ -307,10 +296,11 @@ public class EsiaAuthService {
String decodedString = new String(decodedBytes);
EsiaAccessToken esiaAccessToken = objectMapper.readValue(decodedString, EsiaAccessToken.class);
String prnOid = esiaAccessToken.getSbj_id();
Tokens.addAccessToken(prnOid, accessToken);
Tokens.addRefreshToken(prnOid, newRefreshToken);
Long expiresIn = tokenResponse.getExpires_in();
TokensStore.addAccessToken(prnOid, accessToken, expiresIn);
TokensStore.addRefreshToken(prnOid, newRefreshToken, expiresIn);
String ervuId = getErvuId(accessToken);
Token token = jwtTokenService.createAccessToken(esiaAccessToken.getSbj_id(), tokenResponse.getExpires_in(), ervuId);
Token token = jwtTokenService.createAccessToken(esiaAccessToken.getSbj_id(), expiresIn, ervuId);
Cookie authToken = new Cookie("auth_token", token.getValue());
authToken.setPath(cookiePath);
authToken.setHttpOnly(true);
@ -388,8 +378,8 @@ public class EsiaAuthService {
Token token = jwtTokenService.getToken(authToken);
String[] ids = token.getUserAccountId().split(":");
String userId = ids[0];
Tokens.removeAccessToken(userId);
Tokens.removeRefreshToken(userId);
TokensStore.removeAccessToken(userId);
TokensStore.removeRefreshToken(userId);
String logoutUrl = esiaConfig.getEsiaBaseUri() + esiaConfig.getEsiaLogoutUrl();
String redirectUrl = esiaConfig.getRedirectUrl();
URL url = new URL(logoutUrl);

View file

@ -0,0 +1,34 @@
package ru.micord.ervu.security.esia.token;
/**
* @author Eduard Tihomirov
*/
public class ExpiringToken {
private String accessToken;
private long expiryTime;
public ExpiringToken(String accessToken, long expiryTime) {
this.accessToken = accessToken;
this.expiryTime = expiryTime;
}
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public long getExpiryTime() {
return expiryTime;
}
public void setExpiryTime(long expiryTime) {
this.expiryTime = expiryTime;
}
boolean isExpired() {
return System.currentTimeMillis() > expiryTime;
}
}

View file

@ -0,0 +1,20 @@
package ru.micord.ervu.security.esia.token;
import net.javacrumbs.shedlock.core.SchedulerLock;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @author Eduard Tihomirov
*/
@Service
public class TokensClearShedulerService {
@Scheduled(cron = "${esia.token.clear.cron:0 0 */1 * * *}")
@SchedulerLock(name = "clearToken")
@Transactional
public void load() {
TokensStore.removeExpiredRefreshToken();
TokensStore.removeExpiredAccessToken();
}
}

View file

@ -0,0 +1,60 @@
package ru.micord.ervu.security.esia.token;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Eduard Tihomirov
*/
public class TokensStore {
private static final Map<String, ExpiringToken> accessTokensMap = new ConcurrentHashMap<>();
private static final Map<String, ExpiringToken> refreshTokensMap = new ConcurrentHashMap<>();
public static void addAccessToken(String prnOid, String token, long expiresIn) {
if (token != null) {
long expiryTime = System.currentTimeMillis() + 1000L * expiresIn;
accessTokensMap.put(prnOid, new ExpiringToken(token, expiryTime));
}
}
public static String getAccessToken(String prnOid) {
return accessTokensMap.get(prnOid).getAccessToken();
}
public static void removeExpiredAccessToken() {
for (String key : accessTokensMap.keySet()) {
ExpiringToken token = accessTokensMap.get(key);
if (token != null && token.isExpired()) {
accessTokensMap.remove(key);
}
}
}
public static void removeExpiredRefreshToken() {
for (String key : refreshTokensMap.keySet()) {
ExpiringToken token = refreshTokensMap.get(key);
if (token != null && token.isExpired()) {
refreshTokensMap.remove(key);
}
}
}
public static void removeAccessToken(String prnOid) {
accessTokensMap.remove(prnOid);
}
public static void addRefreshToken(String prnOid, String token, long expiresIn) {
if (token != null) {
long expiryTime = System.currentTimeMillis() + 1000L * expiresIn;
refreshTokensMap.put(prnOid, new ExpiringToken(token, expiryTime));
}
}
public static String getRefreshToken(String prnOid) {
return refreshTokensMap.get(prnOid).getAccessToken();
}
public static void removeRefreshToken(String prnOid) {
refreshTokensMap.remove(prnOid);
}
}

View file

@ -18,7 +18,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import ru.micord.ervu.security.esia.Tokens;
import ru.micord.ervu.security.esia.token.TokensStore;
import ru.micord.ervu.security.webbpm.jwt.JwtAuthentication;
import ru.micord.ervu.security.webbpm.jwt.model.Token;
@ -89,21 +89,29 @@ public class JwtTokenService {
}
public String getAccessToken(HttpServletRequest request) {
String authTokenStr = null;
return TokensStore.getAccessToken(getUserAccountId(request));
}
public String getRefreshToken(HttpServletRequest request) {
return TokensStore.getRefreshToken(getUserAccountId(request));
}
private String getUserAccountId(HttpServletRequest request) {
String authToken = null;
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("auth_token")) {
authTokenStr = cookie.getValue();
authToken = cookie.getValue();
}
}
}
if (authTokenStr == null) {
return null;
if (authToken != null) {
String[] ids = getToken(authToken).getUserAccountId().split(":");
return ids[0];
}
else {
throw new RuntimeException("Failed to get auth data. User unauthorized.");
}
Token authToken = getToken(authTokenStr);
String[] split = authToken.getUserAccountId().split(":");
String userId = split[0];
return Tokens.getAccessToken(userId);
}
}

View file

@ -32,4 +32,6 @@ ERVU_KAFKA_SUBPOENA_EXTRACT_REPLY_TOPIC=ervu.subpoena.info.response
ERVU_KAFKA_REGISTRY_EXTRACT_REQUEST_TOPIC=ervu.extract.info.request
ERVU_KAFKA_REGISTRY_EXTRACT_REPLY_TOPIC=ervu.extract.info.response
ERVU_KAFKA_EXTRACT_HEADER_CLASS=Request@urn://rostelekom.ru/ERVU-extractFromRegistryTR/1.0.3
ERVU_KAFKA_DOC_LOGIN_MODULE=org.apache.kafka.common.security.scram.ScramLoginModule
ERVU_KAFKA_DOC_LOGIN_MODULE=org.apache.kafka.common.security.scram.ScramLoginModule
ESIA_TOKEN_CLEAR_CRON=0 0 */1 * * *

View file

@ -80,6 +80,7 @@
<property name="ervu.kafka.registry.extract.request.topic" value="ervu.extract.info.request"/>
<property name="ervu.kafka.registry.extract.reply.topic" value="ervu.extract.info.response"/>
<property name="ervu.kafka.extract.header.class" value="request@urn://rostelekom.ru/ERVU-extractFromRegistryTR/1.0.3"/>
<property name="esia.token.clear.cron" value="0 0 */1 * * *"/>
</system-properties>
<management>
<audit-log>