|
|
|
|
@ -3,6 +3,7 @@ package kr.re.etri.autoflow.service;
|
|
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
|
import jakarta.annotation.PostConstruct;
|
|
|
|
|
import kr.re.etri.autoflow.payload.request.EdgeSWVO;
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
|
|
|
import org.springframework.core.io.ByteArrayResource;
|
|
|
|
|
import org.springframework.http.*;
|
|
|
|
|
@ -11,6 +12,7 @@ import org.springframework.util.LinkedMultiValueMap;
|
|
|
|
|
import org.springframework.util.MultiValueMap;
|
|
|
|
|
import org.springframework.web.client.HttpClientErrorException;
|
|
|
|
|
import org.springframework.web.client.HttpServerErrorException;
|
|
|
|
|
import org.springframework.web.client.ResourceAccessException;
|
|
|
|
|
import org.springframework.web.client.RestTemplate;
|
|
|
|
|
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
|
|
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
|
|
|
@ -22,9 +24,11 @@ import java.net.URLEncoder;
|
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
|
|
import java.security.cert.X509Certificate;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
|
|
@Service
|
|
|
|
|
@Slf4j
|
|
|
|
|
public class ExternalAuthService {
|
|
|
|
|
|
|
|
|
|
private RestTemplate restTemplate;
|
|
|
|
|
@ -161,7 +165,7 @@ public class ExternalAuthService {
|
|
|
|
|
*/
|
|
|
|
|
public Map<String, Object> getSWPackageList(String id, String token) {
|
|
|
|
|
try {
|
|
|
|
|
// 1) 입력 검증: id에 URL/공격 문자열 포함 금지
|
|
|
|
|
// 1) 입력 검증
|
|
|
|
|
if (id == null || id.isBlank()) {
|
|
|
|
|
throw new IllegalArgumentException("잘못된 사용자 ID입니다.");
|
|
|
|
|
}
|
|
|
|
|
@ -169,15 +173,15 @@ public class ExternalAuthService {
|
|
|
|
|
throw new IllegalArgumentException("ID에 URL을 포함할 수 없습니다.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2) 안전하게 파라미터 인코딩 및 URL 구성 (base URL은 외부 입력에서 분리)
|
|
|
|
|
// 2) URL 구성
|
|
|
|
|
String safeId = URLEncoder.encode(id, StandardCharsets.UTF_8);
|
|
|
|
|
String url = String.format("%s?sw_group=-1&sw_type=-1&searchType=&searchText=&pageNum=1&pageSize=10&auth_id=%s&user_id=",
|
|
|
|
|
String url = String.format(
|
|
|
|
|
"%s?sw_group=-1&sw_type=-1&searchType=&searchText=&pageNum=1&pageSize=10&auth_id=%s&user_id=",
|
|
|
|
|
swSearchUrl, safeId);
|
|
|
|
|
|
|
|
|
|
// 3) URI 생성 (edgeSearchUrl이 올바른 형식인지 확인)
|
|
|
|
|
URI uri = URI.create(url);
|
|
|
|
|
|
|
|
|
|
// 추가 안전권장(선택) : 실제 호출되는 호스트가 설정한 base URL의 호스트와 동일한지 확인
|
|
|
|
|
// 3) 호스트 검증
|
|
|
|
|
URI baseUri = URI.create(swSearchUrl);
|
|
|
|
|
if (!uri.getHost().equalsIgnoreCase(baseUri.getHost())) {
|
|
|
|
|
throw new SecurityException("요청 호스트가 허용된 서비스와 일치하지 않습니다.");
|
|
|
|
|
@ -186,7 +190,7 @@ public class ExternalAuthService {
|
|
|
|
|
// 4) 요청 헤더 구성
|
|
|
|
|
HttpHeaders headers = new HttpHeaders();
|
|
|
|
|
headers.setBearerAuth(token);
|
|
|
|
|
headers.setAccept(java.util.List.of(MediaType.APPLICATION_JSON));
|
|
|
|
|
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
|
|
|
|
|
HttpEntity<Void> request = new HttpEntity<>(headers);
|
|
|
|
|
|
|
|
|
|
// 5) 요청 수행
|
|
|
|
|
@ -195,15 +199,31 @@ public class ExternalAuthService {
|
|
|
|
|
if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
|
|
|
|
|
return response.getBody();
|
|
|
|
|
} else {
|
|
|
|
|
throw new RuntimeException("외부 Edge 패키지 조회 실패");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (IllegalArgumentException iae) {
|
|
|
|
|
// 입력 검증 실패는 호출자에게 명확히 알릴 수 있음
|
|
|
|
|
throw iae;
|
|
|
|
|
throw new RuntimeException("외부 SW 패키지 조회 실패: " + response.getStatusCode());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (IllegalArgumentException | SecurityException ex) {
|
|
|
|
|
// 입력 관련 예외는 그대로 던짐
|
|
|
|
|
throw ex;
|
|
|
|
|
} catch (HttpClientErrorException httpEx) {
|
|
|
|
|
// 4xx (예: 401, 403, 404)
|
|
|
|
|
log.error("[SW API 호출 오류 - 클라이언트 측] Status: {}, Body: {}",
|
|
|
|
|
httpEx.getStatusCode(), httpEx.getResponseBodyAsString(), httpEx);
|
|
|
|
|
throw new RuntimeException("SW API 4xx 오류: " + httpEx.getStatusCode() + " - " + httpEx.getResponseBodyAsString(), httpEx);
|
|
|
|
|
} catch (HttpServerErrorException serverEx) {
|
|
|
|
|
// 5xx (서버 내부 오류)
|
|
|
|
|
log.error("[SW API 호출 오류 - 서버 측] Status: {}, Body: {}",
|
|
|
|
|
serverEx.getStatusCode(), serverEx.getResponseBodyAsString(), serverEx);
|
|
|
|
|
throw new RuntimeException("SW API 5xx 오류: " + serverEx.getStatusCode() + " - " + serverEx.getResponseBodyAsString(), serverEx);
|
|
|
|
|
} catch (ResourceAccessException connEx) {
|
|
|
|
|
// 네트워크/연결 예외
|
|
|
|
|
log.error("[SW API 호출 오류 - 연결 불가]", connEx);
|
|
|
|
|
throw new RuntimeException("SW API 연결 실패: " + connEx.getMessage(), connEx);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
// 내부 상세 예외는 래핑하여 외부에 노출하지 않음
|
|
|
|
|
throw new RuntimeException("외부 Edge API 호출 중 오류가 발생했습니다.");
|
|
|
|
|
// 그 외 모든 예외
|
|
|
|
|
log.error("[SW API 호출 중 알 수 없는 오류 발생]", e);
|
|
|
|
|
throw new RuntimeException("외부 SW API 호출 중 내부 오류: " + e.getClass().getSimpleName() + " - " + e.getMessage(), e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|