You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
autoflow-server-mgmt/src/main/java/kr/re/etri/autoflow/controllers/ExternalAuthController.java

237 lines
9.1 KiB

package kr.re.etri.autoflow.controllers;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.PostConstruct;
import kr.re.etri.autoflow.payload.request.EdgeSWVO;
import kr.re.etri.autoflow.service.EdgeSWUploadService;
import kr.re.etri.autoflow.service.ExternalAuthService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.*;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api/external-auth")
@Tag(name = "ExternalAuthController", description = "외부 백엔드 로그인 및 Bearer 토큰 조회 API")
@RequiredArgsConstructor
@Slf4j
public class ExternalAuthController {
private final ExternalAuthService externalAuthService;
private final EdgeSWUploadService edgeSWUploadService;
private RestTemplate restTemplate;
@PostConstruct
public void init() {
this.restTemplate = createUnsafeRestTemplate();
}
/**
* SSL RestTemplate
*/
private RestTemplate createUnsafeRestTemplate() {
try {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
return new RestTemplate(requestFactory);
} catch (Exception e) {
throw new RuntimeException("Failed to create unsafe RestTemplate", e);
}
}
@Operation(summary = "외부 로그인 후 사용자 정보 조회", description = "외부 Spring 백엔드에 로그인 요청 후 id, name, token을 반환합니다.")
@PostMapping("/signin")
public ResponseEntity<ApiResponse> signin(@RequestBody SigninRequest request) {
try {
Map<String, Object> userInfo = externalAuthService.getUserInfo(request.id(), request.password());
return ResponseEntity.ok(ApiResponse.success(userInfo));
} catch (Exception e) {
return ResponseEntity.ok(ApiResponse.failure(e.getMessage()));
}
}
// @Operation(
// summary = "S3 업로드 + 외부 DB 등록",
// description = "파일을 S3에 업로드하고 외부 DB에 등록합니다.",
// security = @SecurityRequirement(name = "bearerAuth") // 여기서 SecurityScheme 연결
// )
// @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
// public ResponseEntity<String> uploadEdgeSW(
// @RequestParam("files") List<MultipartFile> files,
// @RequestParam("sw_id") String swId,
// @RequestParam("sw_version") String swVersion,
// @RequestParam("sw_name") String swName,
// @RequestParam("creation_datetime") String creationDatetime,
// @RequestParam("auth_id") String authId
// ) {
// try {
// EdgeSWVO edgeSWVO = new EdgeSWVO();
// edgeSWVO.setFiles(files);
// edgeSWVO.setSw_id(swId);
// edgeSWVO.setSw_version(swVersion);
// edgeSWVO.setSw_name(swName);
// edgeSWVO.setCreation_datetime(creationDatetime);
// edgeSWVO.setAuth_id(authId);
//
// String result = edgeSWUploadService.uploadAndSend(edgeSWVO);
// return ResponseEntity.ok(result);
//
// } catch (Exception e) {
// return ResponseEntity.internalServerError().body("업로드 실패: " + e.getMessage());
// }
// }
@Operation(
summary = "외부 DB 등록 + 파일 업로드",
description = "S3 업로드된 파일 정보를 외부 DB에 등록합니다. 파일도 함께 업로드 가능",
security = @SecurityRequirement(name = "bearerAuth")
)
@PostMapping(value = "/register-with-file", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<String> registerWithFile(
@RequestParam("sw_id") String swId,
@RequestParam("sw_version") int swVersion,
@RequestParam("sw_name") String swName,
@RequestParam("auth_id") String authId,
@RequestParam
@Schema(description = "엣지 패키지 정보", example = "14", required = true)
Integer edPkgSerial,
@RequestParam
@Schema(description = "압축여부(0:단일,1:묶음)", example = "1", required = true)
Integer archiveType,
@RequestParam
@Schema(description = "비밀글 여부 (true/false)", example = "false", required = true)
String secretAt,
@RequestParam
@Schema(description = "설치 위치", example = "/etc/test/", required = true)
String downloadLocation,
@RequestParam("user_id")
@Schema(description = "사용자 ID", example = "admin", required = true) String userId,
@RequestParam("creation_datetime")
@Schema(
description = "생성 일시 (ISO-8601 형식, UTC)",
example = "2025-10-20T11:46:49.848Z",
required = true
)
String creationDatetime,
@RequestPart(value = "file", required = false) MultipartFile file
) {
try {
// VO 생성
EdgeSWVO edgeSWVO = new EdgeSWVO();
edgeSWVO.setSw_id(swId);
edgeSWVO.setSw_version(swVersion);
edgeSWVO.setSw_name(swName);
edgeSWVO.setAuth_id(authId);
edgeSWVO.setUser_id(userId);
edgeSWVO.setCreation_datetime(creationDatetime);
edgeSWVO.setEd_pkg_serial(edPkgSerial);
edgeSWVO.setArchive_type(archiveType);
edgeSWVO.setDownload_location(downloadLocation);
edgeSWVO.setSecret_at(secretAt);
// 파일이 있으면 S3 업로드
if (file != null && !file.isEmpty()) {
edgeSWUploadService.uploadFilesToS3Only(edgeSWVO, file);
}
// DB 등록 (파일 업로드 성공 후)
String result = edgeSWUploadService.registerMetadata(edgeSWVO);
return ResponseEntity.ok(result);
} catch (IOException ioe) {
log.error("S3 파일 업로드 실패", ioe);
return ResponseEntity.internalServerError().body("파일 업로드 실패: " + ioe.getMessage());
} catch (Exception e) {
log.error("DB 등록 실패", e);
return ResponseEntity.internalServerError().body("DB 등록 실패: " + e.getMessage());
}
}
// DTO: 요청
public static record SigninRequest(String id, String password) { }
// DTO: 응답
public static class ApiResponse {
private boolean success;
private Object data;
private String errorMessage;
public ApiResponse(boolean success, Object data, String errorMessage) {
this.success = success;
this.data = data;
this.errorMessage = errorMessage;
}
public static ApiResponse success(Object data) {
return new ApiResponse(true, data, null);
}
public static ApiResponse failure(String errorMessage) {
return new ApiResponse(false, null, errorMessage);
}
public boolean isSuccess() { return success; }
public Object getData() { return data; }
public String getErrorMessage() { return errorMessage; }
}
}