SUPPORT-8593: Fix

This commit is contained in:
Eduard Tihomirov 2024-10-09 08:03:41 +03:00
parent 8b87e2985e
commit 47069acb2b
7 changed files with 156 additions and 11 deletions

View file

@ -44,6 +44,9 @@ public class EsiaConfig {
@Value("${esia.token.url:aas/oauth2/v3/te}")
private String esiaTokenUrl;
@Value("${sign.verify.url}")
private String signVerifyUrl;
public String getEsiaScopes() {
String[] scopeItems = esiaScopes.split(",");
return String.join(" ", Arrays.stream(scopeItems).map(String::trim).toArray(String[]::new));
@ -86,4 +89,8 @@ public class EsiaConfig {
public String getEsiaTokenUrl() {
return esiaTokenUrl;
}
public String getSignVerifyUrl() {
return signVerifyUrl;
}
}

View file

@ -0,0 +1,54 @@
package ru.micord.ervu.security.esia.model;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
/**
* @author Eduard Tihomirov
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class EsiaHeader implements Serializable {
private static final long serialVersionUID = 1L;
private String alg;
private String ver;
private String sbt;
private String typ;
public String getAlg() {
return alg;
}
public void setAlg(String alg) {
this.alg = alg;
}
public String getVer() {
return ver;
}
public void setVer(String ver) {
this.ver = ver;
}
public String getSbt() {
return sbt;
}
public void setSbt(String sbt) {
this.sbt = sbt;
}
public String getTyp() {
return typ;
}
public void setTyp(String typ) {
this.typ = typ;
}
}

View file

@ -8,8 +8,7 @@ import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.ZonedDateTime;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import java.util.LinkedHashMap;
@ -27,10 +26,7 @@ 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.config.EsiaConfig;
import ru.micord.ervu.security.esia.model.FormUrlencoded;
import ru.micord.ervu.security.esia.model.EsiaAccessToken;
import ru.micord.ervu.security.esia.model.EsiaTokenResponse;
import ru.micord.ervu.security.esia.model.PersonModel;
import ru.micord.ervu.security.esia.model.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@ -195,6 +191,10 @@ public class EsiaAuthService {
cookiePath = request.getContextPath();
}
String accessToken = tokenResponse.getAccess_token();
boolean verifyResult = verifyToken(accessToken);
if (!verifyResult) {
throw new RuntimeException("Token not valid");
}
Cookie cookie = new Cookie("access_token", accessToken);
cookie.setHttpOnly(true);
cookie.setPath(cookiePath);
@ -288,6 +288,10 @@ public class EsiaAuthService {
throw new RuntimeException(tokenResponse.getError_description());
}
String accessToken = tokenResponse.getAccess_token();
boolean verifyResult = verifyToken(accessToken);
if (!verifyResult) {
throw new RuntimeException("Token not valid");
}
Cookie cookie = new Cookie("access_token", accessToken);
cookie.setHttpOnly(true);
String cookiePath = null;
@ -430,4 +434,41 @@ public class EsiaAuthService {
document.setIssueDate(personModel.getPassportModel().getIssueDate().toString());
return person;
}
private boolean verifyToken(String accessToken) {
EsiaAccessToken esiaAccessToken = personalDataService.readToken(accessToken);
EsiaHeader esiaHeader = personalDataService.readHeader(accessToken);
if (!esiaHeader.getSbt().equals("access") || !esiaHeader.getTyp().equals("JWT")) {
return false;
}
if (esiaAccessToken.getClient_id().equals(esiaConfig.getClientId()) && esiaAccessToken.getIss().equals(esiaConfig.getEsiaBaseUri())) {
LocalDateTime iatTime = LocalDateTime.ofInstant(Instant.ofEpochSecond(esiaAccessToken.getIat()), ZoneId.systemDefault());
LocalDateTime expTime = LocalDateTime.ofInstant(Instant.ofEpochSecond(esiaAccessToken.getExp()), ZoneId.systemDefault());
LocalDateTime currentTime = LocalDateTime.now();
if (currentTime.isAfter(iatTime) && expTime.isAfter(iatTime)) {
return signVerify(accessToken);
}
}
return false;
}
private boolean signVerify(String accessToken) {
try {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(esiaConfig.getSignVerifyUrl()))
.header("Content-Type", "text/plain")
.POST(HttpRequest.BodyPublishers.ofString(accessToken, StandardCharsets.UTF_8))
.build();
HttpResponse<String> response = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(esiaConfig.getConnectionTimeout()))
.build()
.send(request, HttpResponse.BodyHandlers.ofString());
errorHandler(response);
return true;
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View file

@ -10,6 +10,7 @@ import java.util.Base64;
import com.fasterxml.jackson.databind.ObjectMapper;
import ru.micord.ervu.security.esia.config.EsiaConfig;
import ru.micord.ervu.security.esia.model.EsiaAccessToken;
import ru.micord.ervu.security.esia.model.EsiaHeader;
import ru.micord.ervu.security.esia.model.PassportModel;
import ru.micord.ervu.security.esia.model.PersonModel;
import org.springframework.beans.factory.annotation.Autowired;
@ -31,11 +32,7 @@ public class EsiaPersonalDataService implements PersonalDataService {
@Override
public PersonModel getPersonModel(String accessToken) {
try {
byte[] decodedBytes = Base64.getDecoder()
.decode(
accessToken.substring(accessToken.indexOf('.') + 1, accessToken.lastIndexOf('.')));
String decodedString = new String(decodedBytes);
EsiaAccessToken esiaAccessToken = objectMapper.readValue(decodedString, EsiaAccessToken.class);
EsiaAccessToken esiaAccessToken = readToken(accessToken);
String prnsId = esiaAccessToken.getSbj_id();
PersonModel personModel = getPersonData(prnsId, accessToken);
personModel.setPassportModel(
@ -88,4 +85,42 @@ public class EsiaPersonalDataService implements PersonalDataService {
throw new RuntimeException(e);
}
}
@Override
public EsiaAccessToken readToken(String accessToken) {
try {
byte[] decodedBytes = Base64.getDecoder()
.decode(
accessToken.substring(accessToken.indexOf('.') + 1, accessToken.lastIndexOf('.'))
.replace('-', '+')
.replace('_', '/'));
String decodedString = new String(decodedBytes);
EsiaAccessToken esiaAccessToken = objectMapper.readValue(decodedString,
EsiaAccessToken.class
);
return esiaAccessToken;
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public EsiaHeader readHeader(String accessToken) {
try {
byte[] decodedBytes = Base64.getDecoder()
.decode(
accessToken.substring(0, accessToken.indexOf('.'))
.replace('-', '+')
.replace('_', '/'));
String decodedString = new String(decodedBytes);
EsiaHeader esiaHeader = objectMapper.readValue(decodedString,
EsiaHeader.class
);
return esiaHeader;
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View file

@ -1,5 +1,7 @@
package ru.micord.ervu.security.esia.service;
import ru.micord.ervu.security.esia.model.EsiaAccessToken;
import ru.micord.ervu.security.esia.model.EsiaHeader;
import ru.micord.ervu.security.esia.model.PersonModel;
/**
@ -8,4 +10,8 @@ import ru.micord.ervu.security.esia.model.PersonModel;
public interface PersonalDataService {
PersonModel getPersonModel(String accessToken);
EsiaAccessToken readToken(String accessToken);
EsiaHeader readHeader(String accessToken);
}