From 66bdc4cb016c6426d1aa7409bf86beec8d63f6fb Mon Sep 17 00:00:00 2001 From: Eduard Tihomirov Date: Fri, 6 Sep 2024 11:32:40 +0300 Subject: [PATCH] SUPPORT-8474: Fix --- backend/src/main/java/ervu/model/Data.java | 31 +++++++ .../main/java/ervu/model/ErvuOrgResponse.java | 41 ++++++++++ .../ervu/service/kafka/ErvuKafkaConfig.java | 81 +++++++++++++++++++ .../kafka/service/ErvuKafkaService.java | 41 ++++++++++ .../esia/service/EsiaAuthService.java | 32 ++++++-- .../webbpm/jwt/service/JwtTokenService.java | 4 +- config/patches/default.cli | 1 + 7 files changed, 221 insertions(+), 10 deletions(-) create mode 100644 backend/src/main/java/ervu/model/Data.java create mode 100644 backend/src/main/java/ervu/model/ErvuOrgResponse.java create mode 100644 backend/src/main/java/ervu/service/kafka/ErvuKafkaConfig.java create mode 100644 backend/src/main/java/ervu/service/kafka/service/ErvuKafkaService.java diff --git a/backend/src/main/java/ervu/model/Data.java b/backend/src/main/java/ervu/model/Data.java new file mode 100644 index 00000000..0cd99cb3 --- /dev/null +++ b/backend/src/main/java/ervu/model/Data.java @@ -0,0 +1,31 @@ +package ervu.model; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * @author Eduard Tihomirov + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class Data implements Serializable { + private static final long serialVersionUID = 1L; + private String orgId_ERVU; + private String prnOid; + + public String getOrgId_ERVU() { + return orgId_ERVU; + } + + public void setOrgId_ERVU(String orgId_ERVU) { + this.orgId_ERVU = orgId_ERVU; + } + + public String getPrnOid() { + return prnOid; + } + + public void setPrnOid(String prnOid) { + this.prnOid = prnOid; + } +} diff --git a/backend/src/main/java/ervu/model/ErvuOrgResponse.java b/backend/src/main/java/ervu/model/ErvuOrgResponse.java new file mode 100644 index 00000000..56da8fa0 --- /dev/null +++ b/backend/src/main/java/ervu/model/ErvuOrgResponse.java @@ -0,0 +1,41 @@ +package ervu.model; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * @author Eduard Tihomirov + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class ErvuOrgResponse implements Serializable { + + private static final long serialVersionUID = 1L; + private boolean success; + private String message; + private Data data; + + public boolean getSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Data getData() { + return data; + } + + public void setData(Data data) { + this.data = data; + } +} diff --git a/backend/src/main/java/ervu/service/kafka/ErvuKafkaConfig.java b/backend/src/main/java/ervu/service/kafka/ErvuKafkaConfig.java new file mode 100644 index 00000000..bc120349 --- /dev/null +++ b/backend/src/main/java/ervu/service/kafka/ErvuKafkaConfig.java @@ -0,0 +1,81 @@ +package ervu.service.kafka; + +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.apache.kafka.common.serialization.StringSerializer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.annotation.EnableKafka; +import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; +import org.springframework.kafka.core.*; +import org.springframework.kafka.listener.ConcurrentMessageListenerContainer; +import org.springframework.kafka.requestreply.ReplyingKafkaTemplate; + +import java.util.HashMap; +import java.util.Map; + +@Configuration +@EnableKafka +public class ErvuKafkaConfig { + + @Value("${ervu-kafka.bootstrap-servers}") + private String bootstrapServers; + + @Value("${ervu-kafka.reply-topic}:ervu.organization.response") + private String replyTopic; + + @Value("${ervu-kafka.group-id}") + private String groupId; + + @Bean + public ProducerFactory producerFactory() { + Map configProps = new HashMap<>(); + configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); + configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + return new DefaultKafkaProducerFactory<>(configProps); + } + + @Bean + public KafkaTemplate kafkaTemplate() { + return new KafkaTemplate<>(producerFactory()); + } + + @Bean + public ConsumerFactory consumerFactory() { + Map configProps = new HashMap<>(); + configProps.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); + configProps.put(ConsumerConfig.GROUP_ID_CONFIG, groupId); + configProps.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + configProps.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + return new DefaultKafkaConsumerFactory<>(configProps); + } + + @Bean + public ConcurrentKafkaListenerContainerFactory kafkaListenerContainerFactory() { + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(consumerFactory()); + return factory; + } + + @Bean + public ConcurrentMessageListenerContainer replyContainer( + ConcurrentKafkaListenerContainerFactory factory) { + ConcurrentMessageListenerContainer container = factory.createContainer( + replyTopic); + container.getContainerProperties().setGroupId(groupId); + return container; + } + + @Bean + public ReplyingKafkaTemplate replyingKafkaTemplate( + ProducerFactory pf, + ConcurrentMessageListenerContainer container) { + ReplyingKafkaTemplate replyingKafkaTemplate = + new ReplyingKafkaTemplate<>(pf, container); + replyingKafkaTemplate.setCorrelationHeaderName("messageID"); + return replyingKafkaTemplate; + } +} diff --git a/backend/src/main/java/ervu/service/kafka/service/ErvuKafkaService.java b/backend/src/main/java/ervu/service/kafka/service/ErvuKafkaService.java new file mode 100644 index 00000000..8f428f68 --- /dev/null +++ b/backend/src/main/java/ervu/service/kafka/service/ErvuKafkaService.java @@ -0,0 +1,41 @@ +package ervu.service.kafka.service; + +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.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.kafka.requestreply.ReplyingKafkaTemplate; +import org.springframework.kafka.requestreply.RequestReplyFuture; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.stereotype.Service; + +/** + * @author Eduard Tihomirov + */ +@Service +public class ErvuKafkaService { + + @Value("${ervu-kafka.reply-topic}:ervu.organization.request") + private String requestReplyTopic; + + @Value("${ervu-kafka.request-topic}:ervu.organization.response") + private String requestTopic; + + @Autowired + private ReplyingKafkaTemplate replyingKafkaTemplate; + + public String sendMessageAndGetReply(String requestMessage) + throws ExecutionException, InterruptedException { + ProducerRecord record = new ProducerRecord<>(requestTopic, requestMessage); + record.headers().add(new RecordHeader(KafkaHeaders.REPLY_TOPIC, requestReplyTopic.getBytes())); + + RequestReplyFuture replyFuture = replyingKafkaTemplate.sendAndReceive( + record); + ConsumerRecord consumerRecord = replyFuture.get(); + + return consumerRecord.value(); + } +} 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 c5d9dd19..8a2a39c6 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,7 +19,9 @@ import javax.servlet.http.HttpServletResponse; import com.fasterxml.jackson.databind.ObjectMapper; import ervu.model.Brhs; import ervu.model.Employee; +import ervu.model.ErvuOrgResponse; import ervu.model.OrgInfo; +import ervu.service.kafka.service.ErvuKafkaService; import org.apache.kafka.clients.consumer.Consumer; import org.apache.kafka.clients.consumer.ConsumerRecords; import org.apache.kafka.common.utils.Bytes; @@ -51,6 +53,9 @@ public class EsiaAuthService { @Autowired private JwtTokenService jwtTokenService; + @Autowired + private ErvuKafkaService ervuKafkaService; + public String generateAuthCodeUrl() { try { String clientId = esiaConfig.getClientId(); @@ -193,7 +198,8 @@ public class EsiaAuthService { response.addCookie(cookieRefresh); EsiaAccessToken esiaAccessToken = ulDataService.readToken(accessToken); - Token token = jwtTokenService.createAccessToken(esiaAccessToken.getSbj_id(), tokenResponse.getExpires_in()); + String ervuId = getErvuId(accessToken); + Token token = jwtTokenService.createAccessToken(esiaAccessToken.getSbj_id(), tokenResponse.getExpires_in(), ervuId); Cookie isAuthToken = new Cookie("auth_token", token.getValue()); isAuthToken.setPath("/"); response.addCookie(isAuthToken); @@ -277,7 +283,8 @@ public class EsiaAuthService { cookieRefresh.setPath("/"); response.addCookie(cookieRefresh); EsiaAccessToken esiaAccessToken = ulDataService.readToken(accessToken); - Token token = jwtTokenService.createAccessToken(esiaAccessToken.getSbj_id(), tokenResponse.getExpires_in()); + String ervuId = getErvuId(accessToken); + Token token = jwtTokenService.createAccessToken(esiaAccessToken.getSbj_id(), tokenResponse.getExpires_in(), ervuId); Cookie isAuthToken = new Cookie("auth_token", token.getValue()); isAuthToken.setPath("/"); response.addCookie(isAuthToken); @@ -350,12 +357,21 @@ public class EsiaAuthService { } } - public String getErvuId(String accessToken, HttpServletResponse response) { - OrganizationModel organizationModel = ulDataService.getOrganizationModel(accessToken); - EmployeeModel employeeModel = ulDataService.getEmployeeModel(accessToken); - EmployeeModel chiefModel = ulDataService.getChiefEmployeeModel(accessToken); - OrgInfo orgInfo = copyToOrgInfo(organizationModel, employeeModel, chiefModel); - + public String getErvuId(String accessToken) { + try { + OrganizationModel organizationModel = ulDataService.getOrganizationModel(accessToken); + EmployeeModel employeeModel = ulDataService.getEmployeeModel(accessToken); + EmployeeModel chiefModel = ulDataService.getChiefEmployeeModel(accessToken); + OrgInfo orgInfo = copyToOrgInfo(organizationModel, employeeModel, chiefModel); + String kafkaResponse = ervuKafkaService.sendMessageAndGetReply(objectMapper.writeValueAsString(orgInfo)); + ErvuOrgResponse ervuOrgResponse= objectMapper.readValue(kafkaResponse, ErvuOrgResponse.class); + return ervuOrgResponse.getData().getOrgId_ERVU(); + } + catch (Exception e) { + throw new RuntimeException(e); + } + + } private OrgInfo copyToOrgInfo(OrganizationModel organizationModel, EmployeeModel employeeModel, EmployeeModel chiefModel ) { diff --git a/backend/src/main/java/ru/micord/ervu/security/webbpm/jwt/service/JwtTokenService.java b/backend/src/main/java/ru/micord/ervu/security/webbpm/jwt/service/JwtTokenService.java index e075bf58..5689e8ec 100644 --- a/backend/src/main/java/ru/micord/ervu/security/webbpm/jwt/service/JwtTokenService.java +++ b/backend/src/main/java/ru/micord/ervu/security/webbpm/jwt/service/JwtTokenService.java @@ -38,11 +38,11 @@ public class JwtTokenService { this.SIGNING_KEY = Keys.hmacShaKeyFor(encodedKey); } - public Token createAccessToken(String userAccountId, Long expiresIn) { + public Token createAccessToken(String userAccountId, Long expiresIn, String ervuId) { Date expirationDate = new Date(System.currentTimeMillis() + 1000L * expiresIn); String value = Jwts.builder() - .setSubject(userAccountId) + .setSubject(userAccountId + ":" + ervuId) .setIssuer(tokenIssuerName) .setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(expirationDate) diff --git a/config/patches/default.cli b/config/patches/default.cli index d1589c12..c75d7d51 100644 --- a/config/patches/default.cli +++ b/config/patches/default.cli @@ -50,3 +50,4 @@ xa-data-source add \ /system-property=sign-url:add(value="https://ervu-sign-dev.k8s.micord.ru/sign") /system-property=esia-uri.logout:add(value="https://esia-portal1.test.gosuslugi.ru/idp/ext/Logout") /system-property=client-cert-hash:add(value="04508B4B0B58776A954A0E15F574B4E58799D74C61EE020B3330716C203E3BDD") +/system-property=ervu-kafka.bootstrap-servers:add(value="localhost:9092")