diff --git a/backend/pom.xml b/backend/pom.xml index 8daa6f80..bbb583f3 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -5,7 +5,7 @@ ru.micord.ervu.lkrp ul - 1.9.4 + 1.9.5 ru.micord.ervu.lkrp.ul backend diff --git a/backend/src/main/java/ervu/client/fileupload/WebDavClient.java b/backend/src/main/java/ervu/client/fileupload/WebDavClient.java index 6e7fee62..b343bed6 100644 --- a/backend/src/main/java/ervu/client/fileupload/WebDavClient.java +++ b/backend/src/main/java/ervu/client/fileupload/WebDavClient.java @@ -11,6 +11,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.util.Arrays; import java.util.Comparator; @@ -34,6 +35,7 @@ import ervu.model.webdav.Server; import org.apache.http.client.ClientProtocolException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.InputStreamResource; import org.springframework.core.io.Resource; @@ -44,6 +46,7 @@ import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Retryable; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; +import ru.micord.ervu.security.esia.config.EsiaConfig; /** * @author Alexandr Shalaginov @@ -60,6 +63,10 @@ public class WebDavClient { private String password; @Value("${webdav.bad_servers.cache.expire.seconds:120}") private long cacheExpireSec; + @Value("${request.timeout:20}") + private long requestTimeout; + @Value("${connection.timeout:10}") + private long connectionTimeout; private List servers; private LoadingCache badServersCache; @@ -167,10 +174,14 @@ public class WebDavClient { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(username, password.toCharArray()); } - }).build(); + }) + .connectTimeout(Duration.ofSeconds(connectionTimeout)) + .build(); HttpRequest httpRequest = HttpRequest.newBuilder().uri(URI.create(url)) - .GET().build(); + .GET() + .timeout(Duration.ofSeconds(requestTimeout)) + .build(); HttpResponse response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofInputStream() diff --git a/backend/src/main/java/ru/micord/ervu/kafka/service/impl/BaseReplyingKafkaServiceImpl.java b/backend/src/main/java/ru/micord/ervu/kafka/service/impl/BaseReplyingKafkaServiceImpl.java index 60d6f0b6..572d218b 100644 --- a/backend/src/main/java/ru/micord/ervu/kafka/service/impl/BaseReplyingKafkaServiceImpl.java +++ b/backend/src/main/java/ru/micord/ervu/kafka/service/impl/BaseReplyingKafkaServiceImpl.java @@ -1,11 +1,14 @@ package ru.micord.ervu.kafka.service.impl; +import java.lang.invoke.MethodHandles; import java.util.Optional; import java.util.concurrent.ExecutionException; import org.apache.kafka.clients.consumer.ConsumerRecord; import org.apache.kafka.clients.producer.ProducerRecord; import org.apache.kafka.common.header.internals.RecordHeader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.kafka.requestreply.ReplyingKafkaTemplate; import org.springframework.kafka.requestreply.RequestReplyFuture; import org.springframework.kafka.support.KafkaHeaders; @@ -17,7 +20,7 @@ import ru.micord.ervu.kafka.service.ReplyingKafkaService; */ @Service public class BaseReplyingKafkaServiceImpl implements ReplyingKafkaService { - + private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private final ReplyingKafkaTemplate replyingKafkaTemplate; public BaseReplyingKafkaServiceImpl( @@ -28,16 +31,22 @@ public class BaseReplyingKafkaServiceImpl implements ReplyingKafkaService { public String sendMessageAndGetReply(String requestTopic, String replyTopic, String requestMessage) { + long startTime = System.currentTimeMillis(); ProducerRecord record = new ProducerRecord<>(requestTopic, requestMessage); record.headers().add(new RecordHeader(KafkaHeaders.REPLY_TOPIC, replyTopic.getBytes())); RequestReplyFuture replyFuture = replyingKafkaTemplate.sendAndReceive(record); try { - return Optional.ofNullable(replyFuture.get()) + String result = Optional.ofNullable(replyFuture.get()) .map(ConsumerRecord::value) .orElseThrow(() -> new RuntimeException("Kafka return result is null.")); + LOGGER.info("Thread {} - KafkaSendMessageAndGetReply: {} ms", + Thread.currentThread().getId(), System.currentTimeMillis() - startTime); + return result; } catch (InterruptedException | ExecutionException e) { + LOGGER.error("Thread {} - KafkaSendMessageAndGetReply: {} ms", + Thread.currentThread().getId(), System.currentTimeMillis() - startTime); throw new RuntimeException("Failed to get kafka response.", e); } } diff --git a/backend/src/main/java/ru/micord/ervu/security/esia/config/EsiaConfig.java b/backend/src/main/java/ru/micord/ervu/security/esia/config/EsiaConfig.java index 937368d7..5a0ddc6c 100644 --- a/backend/src/main/java/ru/micord/ervu/security/esia/config/EsiaConfig.java +++ b/backend/src/main/java/ru/micord/ervu/security/esia/config/EsiaConfig.java @@ -38,10 +38,10 @@ public class EsiaConfig { @Value("${esia.client.cert.hash}") private String clientCertHash; - @Value("${esia.request.timeout:60}") + @Value("${request.timeout:20}") private long requestTimeout; - @Value("${esia.connection.timeout:30}") + @Value("${connection.timeout:10}") private long connectionTimeout; @Value("${esia.logout.url:idp/ext/Logout}") 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 022dedb4..b6887743 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 @@ -19,6 +19,7 @@ import java.util.UUID; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import ervu.service.okopf.OkopfService; import org.springframework.stereotype.Service; @@ -241,12 +242,14 @@ public class EsiaAuthService { throw new EsiaException(e); } finally { - LOGGER.info("Thread {}: SignSecret: {}ms RequestAccessToken: {}ms VerifySecret: {}ms", + LOGGER.info("Thread {} - SignSecret: {} ms RequestAccessToken: {} ms VerifySecret: {} ms", Thread.currentThread().getId(), timeSignSecret, timeRequestAccessToken, timeVerifySecret); } + OrgInfo orgInfo = null; try { + orgInfo = getOrgInfo(esiaAccessTokenStr); hasRole = ulDataService.checkRole(esiaAccessTokenStr); - String ervuId = getErvuId(esiaAccessTokenStr, prnOid); + String ervuId = getErvuId(prnOid, orgInfo); createTokenAndAddCookie(response, prnOid, ervuId, hasRole, expiresIn); if (!hasRole) { LOGGER.error("The user with id = " + prnOid + " does not have the required role"); @@ -333,7 +336,8 @@ public class EsiaAuthService { Long expiresIn = tokenResponse.getExpires_in(); EsiaTokensStore.addAccessToken(prnOid, esiaAccessTokenStr, expiresIn); EsiaTokensStore.addRefreshToken(prnOid, esiaNewRefreshToken, expiresIn); - String ervuId = getErvuId(esiaAccessTokenStr, prnOid); + OrgInfo orgInfo = getOrgInfo(esiaAccessTokenStr); + String ervuId = getErvuId(prnOid, orgInfo); createTokenAndAddCookie(response, esiaAccessToken.getSbj_id(), ervuId, true, expiresIn); } catch (Exception e) { @@ -353,6 +357,7 @@ public class EsiaAuthService { .uri(URI.create(esiaConfig.getSignUrl())) .header("Content-Type", "text/plain") .POST(HttpRequest.BodyPublishers.ofString(requestBody, StandardCharsets.UTF_8)) + .timeout(Duration.ofSeconds(esiaConfig.getRequestTimeout())) .build(); HttpResponse response = HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(esiaConfig.getConnectionTimeout())) @@ -392,10 +397,23 @@ public class EsiaAuthService { } } - public String getErvuId(String accessToken, String prnOid) { - long timeRequestPersonDataOrg = 0, timeRequestPersonDataEmployee = 0, timeRequestPersonDataChief = 0, timeRequestIdERVU = 0; + public String getErvuId(String prnOid, OrgInfo orgInfo) throws JsonProcessingException { + orgInfo.setOrgTypeName(okopfService.findTitleByLeg(orgInfo.getOrgTypeLeg())); + String kafkaResponse = replyingKafkaService.sendMessageAndGetReply(requestTopic, + requestReplyTopic, objectMapper.writeValueAsString(orgInfo) + ); + ErvuOrgResponse ervuOrgResponse = objectMapper.readValue(kafkaResponse, ErvuOrgResponse.class); + String ervuId = ervuOrgResponse.getData().getErvuId(); + if (!StringUtils.hasText(ervuId)) { + throw new EsiaException("No ervuId for prnOid = " + prnOid); + } + return ervuId; + } + + private OrgInfo getOrgInfo(String accessToken) { + long startTime = System.currentTimeMillis(); + long timeRequestPersonDataOrg = 0, timeRequestPersonDataEmployee = 0, timeRequestPersonDataChief = 0; try { - long startTime = System.currentTimeMillis(); OrganizationModel organizationModel = ulDataService.getOrganizationModel(accessToken); timeRequestPersonDataOrg = System.currentTimeMillis() - startTime; startTime = System.currentTimeMillis(); @@ -404,27 +422,12 @@ public class EsiaAuthService { startTime = System.currentTimeMillis(); EmployeeModel chiefModel = ulDataService.getChiefEmployeeModel(accessToken); timeRequestPersonDataChief = System.currentTimeMillis() - startTime; - OrgInfo orgInfo = copyToOrgInfo(organizationModel, employeeModel, chiefModel); - orgInfo.setOrgTypeName(okopfService.findTitleByLeg(orgInfo.getOrgTypeLeg())); - startTime = System.currentTimeMillis(); - String kafkaResponse = replyingKafkaService.sendMessageAndGetReply(requestTopic, - requestReplyTopic, objectMapper.writeValueAsString(orgInfo) - ); - timeRequestIdERVU = System.currentTimeMillis() - startTime; - ErvuOrgResponse ervuOrgResponse = objectMapper.readValue(kafkaResponse, ErvuOrgResponse.class); - String ervuId = ervuOrgResponse.getData().getErvuId(); - - if (!StringUtils.hasText(ervuId)) { - throw new EsiaException("No ervuId for prnOid = " + prnOid); - } - return ervuId; - } - catch (Exception e) { - throw new EsiaException(e); + return copyToOrgInfo(organizationModel, employeeModel, chiefModel); } finally { - LOGGER.info("Thread {}: RequestPersonDataOrg: {}ms RequestPersonDataEmployee: {}ms RequestPersonDataChief: {}ms RequestIdERVU: {}ms", - Thread.currentThread().getId(), timeRequestPersonDataOrg, timeRequestPersonDataEmployee, timeRequestPersonDataChief, timeRequestIdERVU); + LOGGER.info("Thread {} - RequestPersonDataOrg: {} ms RequestPersonDataEmployee: {} ms RequestPersonDataChief: {} ms", + Thread.currentThread().getId(), timeRequestPersonDataOrg, timeRequestPersonDataEmployee, timeRequestPersonDataChief + ); } } @@ -546,6 +549,7 @@ public class EsiaAuthService { .uri(URI.create(esiaConfig.getSignVerifyUrl())) .header("Content-Type", "text/plain") .POST(HttpRequest.BodyPublishers.ofString(accessToken, StandardCharsets.UTF_8)) + .timeout(Duration.ofSeconds(esiaConfig.getRequestTimeout())) .build(); return HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(esiaConfig.getConnectionTimeout())) diff --git a/distribution/pom.xml b/distribution/pom.xml index 456e6dad..70880482 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -4,7 +4,7 @@ ru.micord.ervu.lkrp ul - 1.9.4 + 1.9.5 ru.micord.ervu.lkrp.ul diff --git a/frontend/pom.xml b/frontend/pom.xml index 256e9ec8..9d24d18d 100644 --- a/frontend/pom.xml +++ b/frontend/pom.xml @@ -4,7 +4,7 @@ ru.micord.ervu.lkrp ul - 1.9.4 + 1.9.5 ru.micord.ervu.lkrp.ul diff --git a/frontend/src/resources/template/app/component/app_header.html b/frontend/src/resources/template/app/component/app_header.html index 4d618a54..6445b794 100644 --- a/frontend/src/resources/template/app/component/app_header.html +++ b/frontend/src/resources/template/app/component/app_header.html @@ -1,7 +1,7 @@