SUPPORT-8593: Fix
This commit is contained in:
parent
8b87e2985e
commit
47069acb2b
7 changed files with 156 additions and 11 deletions
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ ESIA_CLIENT_CERT_HASH=04508B4B0B58776A954A0E15F574B4E58799D74C61EE020B3330716C20
|
|||
ESIA_REDIRECT_URL=https://lkrp-dev.micord.ru/fl/
|
||||
|
||||
SIGN_URL=https://ervu-sign-dev.k8s.micord.ru/sign
|
||||
SIGN_VERIFY_URL=https://ervu-sign-dev.k8s.micord.ru/verify
|
||||
|
||||
ERVU_KAFKA_BOOTSTRAP_SERVERS=localhost:9092
|
||||
ERVU_KAFKA_USERNAME=user1
|
||||
|
|
|
|||
|
|
@ -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="sign.verify.url" value="https://ervu-sign-dev.k8s.micord.ru/verify"/>
|
||||
</system-properties>
|
||||
<management>
|
||||
<audit-log>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue