diff --git a/WebContent/WEB-INF/springapp-servlet.xml b/WebContent/WEB-INF/springapp-servlet.xml index 66d4464..f0f58b4 100644 --- a/WebContent/WEB-INF/springapp-servlet.xml +++ b/WebContent/WEB-INF/springapp-servlet.xml @@ -110,7 +110,7 @@ - + diff --git a/http/client-man-auth-key-test.http b/http/client-man-auth-key-test.http index 040f379..e1ff35b 100644 --- a/http/client-man-auth-key-test.http +++ b/http/client-man-auth-key-test.http @@ -2,7 +2,7 @@ POST http://localhost:7090/monitoring/_onl/admin/authserver/clientMan.json?serviceType=APIGW Content-Type: application/json User-Agent: insomnia/10.1.1 -X-API-KEY: EAPIM_KEY +X-Internal-Token: {{internalApiToken}} action: insert target_host: stg @@ -118,4 +118,4 @@ target_host: stg "errTransformYn": "N" } ] -} \ No newline at end of file +} diff --git a/src/main/java/com/eactive/eai/rms/common/interceptor/ApiKeyInterceptor.java b/src/main/java/com/eactive/eai/rms/common/interceptor/ApiKeyInterceptor.java deleted file mode 100644 index dacde3f..0000000 --- a/src/main/java/com/eactive/eai/rms/common/interceptor/ApiKeyInterceptor.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.eactive.eai.rms.common.interceptor; - -import com.eactive.apim.portal.portalproperty.service.PortalPropertyService; -import java.io.IOException; -import java.util.Map; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; -import org.springframework.web.servlet.HandlerInterceptor; - -@Component -@Slf4j -public class ApiKeyInterceptor implements HandlerInterceptor { - - private static final String API_KEY_HEADER = "X-API-KEY"; - private static final String PORTAL_PROPERTY_GROUP = "Portal"; - - @Autowired - private PortalPropertyService portalPropertyService; - - @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - try { - String requestApiKey = request.getHeader(API_KEY_HEADER); - - if (StringUtils.isEmpty(requestApiKey)) { - log.warn("Request received without API key. URI: {}", request.getRequestURI()); - sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "API key is missing"); - return false; - } - - Map properties = portalPropertyService.getPortalPropertiesAsMap(PORTAL_PROPERTY_GROUP); - String validApiKey = properties.get("apiKey"); - - if (StringUtils.isEmpty(validApiKey)) { - log.error("API key not configured in properties"); - sendErrorResponse(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "API key is not configured"); - return false; - } - - if (!validApiKey.equals(requestApiKey)) { - log.warn("Invalid API key received. URI: {}", request.getRequestURI()); - sendErrorResponse(response, HttpServletResponse.SC_FORBIDDEN, "Invalid API key"); - return false; - } - - return true; - - } catch (Exception e) { - log.error("Error processing API key validation", e); - sendErrorResponse(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error processing request"); - return false; - } - } - - private void sendErrorResponse(HttpServletResponse response, int status, String message) throws IOException { - response.setStatus(status); - response.setContentType("application/json"); - response.getWriter().write(String.format("{\"error\": \"%s\"}", message)); - } -} diff --git a/src/main/java/com/eactive/eai/rms/common/interceptor/InternalApiTokenInterceptor.java b/src/main/java/com/eactive/eai/rms/common/interceptor/InternalApiTokenInterceptor.java new file mode 100644 index 0000000..63e32b5 --- /dev/null +++ b/src/main/java/com/eactive/eai/rms/common/interceptor/InternalApiTokenInterceptor.java @@ -0,0 +1,44 @@ +package com.eactive.eai.rms.common.interceptor; + +import com.eactive.apim.portal.common.internal.InternalApiTokenService; +import java.io.IOException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +/** + * {@code /_onl/**} 내부 연동 요청을 공유 내부 토큰으로 검증한다. + * + *

토큰과 헤더명은 PTL_PROPERTY {@code Portal / internal.api.header-name}, + * {@code Portal / internal.api.token}을 사용한다. admin은 토큰을 생성하지 않고 읽기 전용으로 + * 검증하므로, portal이 먼저 기동되어 토큰을 생성해야 한다.

+ */ +@Component +@RequiredArgsConstructor +@Slf4j +public class InternalApiTokenInterceptor implements HandlerInterceptor { + + private final InternalApiTokenService internalApiTokenService; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException { + String headerName = internalApiTokenService.findHeaderName(); + String presentedToken = request.getHeader(headerName); + + if (!internalApiTokenService.matchesReadOnly(presentedToken)) { + log.warn("Invalid internal API token. URI: {}, header: {}", request.getRequestURI(), headerName); + sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "Internal API token is invalid"); + return false; + } + return true; + } + + private void sendErrorResponse(HttpServletResponse response, int status, String message) throws IOException { + response.setStatus(status); + response.setContentType("application/json;charset=UTF-8"); + response.getWriter().write(String.format("{\"error\": \"%s\"}", message)); + } +} diff --git a/src/main/java/com/eactive/eai/rms/onl/apim/approval/user/PortalUserApprovalListener.java b/src/main/java/com/eactive/eai/rms/onl/apim/approval/user/PortalUserApprovalListener.java index 210c823..f152071 100644 --- a/src/main/java/com/eactive/eai/rms/onl/apim/approval/user/PortalUserApprovalListener.java +++ b/src/main/java/com/eactive/eai/rms/onl/apim/approval/user/PortalUserApprovalListener.java @@ -6,7 +6,6 @@ import com.eactive.apim.portal.approval.statemachine.listener.ApprovalListener; import com.eactive.apim.portal.portalorg.entity.PortalOrg; import com.eactive.apim.portal.portalorg.entity.PortalOrgEnums.ApprovalStatus; import com.eactive.apim.portal.portalorg.entity.PortalOrgEnums.OrgStatus; -import com.eactive.apim.portal.portalproperty.service.PortalPropertyService; import com.eactive.apim.portal.portaluser.entity.PortalUser; import com.eactive.apim.portal.portaluser.entity.PortalUserEnums; import com.eactive.apim.portal.template.entity.MessageCode; @@ -14,27 +13,15 @@ import com.eactive.apim.portal.template.service.MessageRecipient; import com.eactive.apim.portal.template.service.MessageSendService; import com.eactive.eai.rms.data.entity.onl.apim.portalorg.PortalOrgService; import com.eactive.eai.rms.data.entity.onl.apim.portaluser.PortalUserService; -import com.eactive.eai.rms.onl.apim.portalorg.PortalOrgUI; -import com.eactive.eai.rms.onl.apim.portalorg.PortalOrgUIMapper; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.HashMap; import java.util.Map; import lombok.RequiredArgsConstructor; -import org.apache.http.client.HttpClient; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.impl.client.HttpClientBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.client.RestTemplate; @Service @Transactional @@ -42,36 +29,9 @@ import org.springframework.web.client.RestTemplate; public class PortalUserApprovalListener implements ApprovalListener { private static final Logger logger = LoggerFactory.getLogger(PortalUserApprovalListener.class); - private static final String PORTAL_PROPERTY_GROUP = "Portal"; - private final PortalPropertyService portalPropertyService; private final PortalOrgService portalOrgService; private final PortalUserService portalUserService; private final MessageSendService messageSendService; - private final PortalOrgUIMapper portalOrgUIMapper; - - public static RestTemplate createRestTemplateWithTimeout(int connectTimeout) { - - RequestConfig requestConfig = RequestConfig.custom() - .setConnectionRequestTimeout(connectTimeout) - .setConnectTimeout(connectTimeout) - .setSocketTimeout(connectTimeout) - .build(); - - HttpClient httpClient = - HttpClientBuilder.create() - .setMaxConnTotal(50) - .setMaxConnPerRoute(20) - .setDefaultRequestConfig(requestConfig) - .build(); - - HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); - factory.setHttpClient(httpClient); - - RestTemplate restTemplate = new RestTemplate(); - restTemplate.setRequestFactory(factory); - - return restTemplate; - } @Override public void execute(Approval approval, Map options) throws ApprovalDeployException { @@ -88,7 +48,6 @@ public class PortalUserApprovalListener implements ApprovalListener { portalOrg.setOrgStatus(OrgStatus.ACTIVE); portalOrgService.save(portalOrg); - // syncStaging(portalOrgUIMapper.toVo(portalOrg)); sendApprovalResult(portalUser); } @@ -106,48 +65,6 @@ public class PortalUserApprovalListener implements ApprovalListener { messageSendService.sendMessage(MessageCode.MANAGER_WITH_ORG_REGISTER_APPROVED, recipient, params); } - /** - * @deprecated 광주은행에서는 사용하지 않음. (개발/운영 완전 분리) - * @param portalOrgUI - * @throws ApprovalDeployException - */ - private void syncStaging(PortalOrgUI portalOrgUI) throws ApprovalDeployException { - throw new RuntimeException("Unable use this method(syncStaging())"); - -// // 프록시를 통한 스테이징 서버 호출 추가 -// Map properties = portalPropertyService.getPortalPropertiesAsMap(PORTAL_PROPERTY_GROUP); -// String apiKey = properties.get("apiKey"); -// String proxyUrl = properties.get("portal.url"); -// String timeout = properties.getOrDefault("deploy.proxy_timeout", "10000"); -// String proxyEndpoint = proxyUrl + "/_onl/apim/portalorg/portalOrgMan.json"; -// -// HttpHeaders headers = new HttpHeaders(); -// headers.setContentType(MediaType.APPLICATION_JSON); -// headers.set("X-API-KEY", apiKey); -// headers.set("target_host", "stg"); -// headers.set("action", "insert"); -// -// portalOrgUI.setCompRegFile(null); -// HttpEntity request = new HttpEntity<>(portalOrgUI, headers); -// -// try { -// ResponseEntity response = createRestTemplateWithTimeout(Integer.parseInt(timeout)).exchange( -// proxyEndpoint, -// HttpMethod.POST, -// request, -// String.class -// ); -// -// if (!response.getStatusCode().is2xxSuccessful()) { -// logger.error("Failed to sync with staging server. Status: {}, Body: {}", response.getStatusCode(), response.getBody()); -// throw new ApprovalDeployException("기관 정보 배포에 실패 했습니다."); -// } -// } catch (Exception e) { -// logger.error("Failed to sync with staging server. {}", e.getMessage()); -// throw new ApprovalDeployException("기관 정보 배포에 실패 했습니다."); -// } - } - @Override public void rollback(Approval approval) { logger.debug("Rollback started for approval ID: {}, type: {}, status: {}",