Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 464ed59a3d | |||
| 5486489985 | |||
| 2bbd3824ed | |||
| 4ff3589557 | |||
| db2b34a355 | |||
| d79bcf8430 | |||
| e049420ca3 | |||
| 10bbd57c78 | |||
| 70c636d719 | |||
| 1b37fc5e1b | |||
| 9a730dc0b7 | |||
| 0ff2259f78 | |||
| 8231318f14 |
@@ -5,6 +5,7 @@ gradle.properties
|
||||
|
||||
src/main/generated
|
||||
WebContent/generated
|
||||
src/main/resources/version.info
|
||||
|
||||
# Eclipse #
|
||||
.metadata
|
||||
|
||||
Vendored
+15
@@ -73,6 +73,21 @@ pipeline {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SBOM(CycloneDX) -> xlsx. 산출물 eapim-online-sbom.xlsx 를 아티팩트로 보관.
|
||||
// 실패해도 배포는 진행하도록 UNSTABLE 로만 표시한다.
|
||||
stage('SBOM') {
|
||||
steps {
|
||||
catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') {
|
||||
sh 'gradle sbomXlsx --no-daemon -Pprofile=weblogic'
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
archiveArtifacts allowEmptyArchive: true, artifacts: 'build/reports/sbom/*.xlsx', fingerprint: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ plugins {
|
||||
id 'groovy'
|
||||
id 'war'
|
||||
id 'com.diffplug.eclipse.apt' version '3.41.1'
|
||||
id 'org.cyclonedx.bom' version '3.2.4'
|
||||
}
|
||||
|
||||
group 'com.eactvie'
|
||||
@@ -172,6 +173,54 @@ task initDirs() {
|
||||
file(generatedJavaDir).mkdirs()
|
||||
}
|
||||
|
||||
// version.info 를 classpath 리소스로 생성해 WAR의 WEB-INF/classes에 포함시킨다.
|
||||
// elink-online-common 등 공유 라이브러리 모듈이 아니라, 실제 배포 아티팩트(eapim-online.war)를
|
||||
// 만드는 이 루트 프로젝트에서 생성해야 "지금 배포된 게이트웨이가 정확히 어느 커밋인지"를
|
||||
// eapim-online 소스 변경 여부와 무관하게 항상 최신으로 반영한다.
|
||||
// ToolsController(/manage/tools/version, elink-online-common 모듈)는 이 파일을
|
||||
// Class.getResourceAsStream("/version.info")로 읽는데, WAR는 WEB-INF/classes와
|
||||
// WEB-INF/lib 전체가 하나의 클래스로더를 공유하므로 어느 모듈의 클래스에서 조회하든 찾을 수 있다.
|
||||
//
|
||||
// elink-online-common/elink-online-core/... 는 별도 저장소를 참조하는 git submodule이라
|
||||
// 루트(eapim-online)의 describe/dirty 만으로는 "어느 서브모듈이 바뀌었는지"를 알 수 없다
|
||||
// (서브모듈 포인터가 커밋되고 나면 루트는 다시 clean 해져서 -dirty 흔적도 사라진다).
|
||||
// 그래서 서브모듈 각각에 대해서도 describe를 실행해 module.<이름>=<결과> 형식으로 함께 기록한다.
|
||||
def describeGit(File dir) {
|
||||
try {
|
||||
def proc = "git describe --tags --always --dirty".execute(null, dir)
|
||||
// proc.text는 JVM/OS 기본 charset(Windows 환경에선 CP949 등)으로 stdout을 디코딩한다.
|
||||
// git 태그명은 UTF-8 바이트이므로 기본 charset이 UTF-8이 아니면 여기서 한글이 깨진다.
|
||||
// stream을 명시적으로 UTF-8로 읽어서 이 문제를 피한다.
|
||||
def output = proc.inputStream.getText("UTF-8")
|
||||
proc.waitFor()
|
||||
return (proc.exitValue() == 0) ? output.trim() : "unknown"
|
||||
} catch (Exception e) {
|
||||
logger.warn("${dir} git describe 실행 불가, unknown 으로 대체: ${e.message}")
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
task generateVersionInfo {
|
||||
doLast {
|
||||
def gitVersion = describeGit(projectDir)
|
||||
|
||||
def sb = new StringBuilder()
|
||||
sb.append("version=${gitVersion}\n")
|
||||
sb.append("buildTime=${new Date().format("yyyy-MM-dd HH:mm:ss")}\n")
|
||||
subprojects.sort { it.name }.each { sub ->
|
||||
if (file("${sub.projectDir}/.git").exists()) {
|
||||
sb.append("module.${sub.name}=${describeGit(sub.projectDir)}\n")
|
||||
}
|
||||
}
|
||||
|
||||
def versionInfoFile = file("$projectDir/src/main/resources/version.info")
|
||||
versionInfoFile.parentFile.mkdirs()
|
||||
versionInfoFile.write(sb.toString(), "UTF-8")
|
||||
}
|
||||
}
|
||||
|
||||
processResources.dependsOn generateVersionInfo
|
||||
|
||||
eclipse {
|
||||
wtp {
|
||||
component {
|
||||
@@ -201,3 +250,6 @@ eclipse {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// CycloneDX SBOM -> xlsx 변환 (gradle sbomXlsx)
|
||||
apply from: "$projectDir/gradle/sbom-xlsx.gradle"
|
||||
|
||||
+1
-1
Submodule elink-online-common updated: a923ff3f9f...4813a2ef0e
+1
-1
Submodule elink-online-core updated: 2929fc753f...495241c5d0
+1
-1
Submodule elink-online-core-jpa updated: 9620845daf...138621f2d0
+1
-1
Submodule elink-online-transformer updated: a1d822c2d7...375f0e0f15
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* CycloneDX SBOM(bom.json) -> Excel(xlsx) 변환 태스크.
|
||||
*
|
||||
* gradle sbomXlsx # cyclonedxBom 실행 후 변환
|
||||
* gradle sbomXlsx -PsbomJson=path.json # 기존 bom.json 사용(cyclonedxBom 생략)
|
||||
* gradle sbomXlsx -PsbomOut=out.xlsx # 출력 경로 지정
|
||||
*
|
||||
* buildscript 블록이 이 스크립트에만 적용되므로 POI 의존성이 메인 빌드
|
||||
* classpath 나 WAR 산출물에는 포함되지 않는다.
|
||||
*
|
||||
* 시트: 요약 / WAR 기준
|
||||
* 산출 기준은 war 태스크의 classpath(= runtimeClasspath) 이므로
|
||||
* test·annotationProcessor·developmentOnly·compileOnly 의존은 모두 제외된다.
|
||||
* bom.json 은 라이선스/해시/설명/직접-전이 판별을 위한 메타 소스로만 쓴다.
|
||||
*/
|
||||
buildscript {
|
||||
repositories {
|
||||
maven {
|
||||
url "https://nexus.eactive.synology.me:8090/repository/maven-public/"
|
||||
allowInsecureProtocol = true
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'org.apache.poi:poi-ooxml:3.17'
|
||||
}
|
||||
}
|
||||
|
||||
import groovy.json.JsonSlurper
|
||||
import org.apache.poi.ss.usermodel.BorderStyle
|
||||
import org.apache.poi.ss.usermodel.FillPatternType
|
||||
import org.apache.poi.ss.usermodel.HorizontalAlignment
|
||||
import org.apache.poi.ss.usermodel.IndexedColors
|
||||
import org.apache.poi.ss.usermodel.VerticalAlignment
|
||||
import org.apache.poi.ss.util.CellRangeAddress
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook
|
||||
|
||||
// 엑셀 셀 문자열 상한(32767)보다 여유를 둔 절단 길이
|
||||
ext.SBOM_CELL_LIMIT = 32000
|
||||
|
||||
task sbomXlsx {
|
||||
group = 'sbom'
|
||||
description = 'CycloneDX bom.json 을 WAR 수록 기준 xlsx 로 변환한다'
|
||||
|
||||
// -PsbomJson 으로 기존 산출물을 지정하면 재생성하지 않는다
|
||||
if (!project.hasProperty('sbomJson')) {
|
||||
dependsOn 'cyclonedxBom'
|
||||
}
|
||||
|
||||
doLast {
|
||||
File src = resolveBomJson(project)
|
||||
File out = project.hasProperty('sbomOut')
|
||||
? project.file(project.property('sbomOut'))
|
||||
: new File(project.buildDir, "reports/sbom/${sbomFileName(project)}")
|
||||
out.parentFile.mkdirs()
|
||||
|
||||
def bom = new JsonSlurper().parse(src, 'UTF-8')
|
||||
def deploy = collectDeployJars(project)
|
||||
def warRows = joinWarRows(deploy.jars, indexComponents(bom))
|
||||
|
||||
def wb = new XSSFWorkbook()
|
||||
def st = createStyles(wb)
|
||||
writeSummarySheet(wb, st, bom, warRows, src, deploy.label)
|
||||
writeWarSheet(wb, st, warRows)
|
||||
|
||||
out.withOutputStream { os -> wb.write(os) }
|
||||
wb.close()
|
||||
|
||||
int unmatched = warRows.count { it.matched == 'N' }
|
||||
logger.lifecycle("SBOM xlsx 생성: ${out.absolutePath} " +
|
||||
"(배포 수록 ${warRows.size()}개, SBOM 미매칭 ${unmatched}개, 원본 ${src.name})")
|
||||
}
|
||||
}
|
||||
|
||||
/** 산출 파일명: 배포 패키지명 기준 (war 있으면 war 파일명, 없으면 project 이름[-버전]) */
|
||||
String sbomFileName(Project p) {
|
||||
def warTask = p.tasks.findByName('war')
|
||||
if (warTask != null) {
|
||||
String archive = warTask.archiveFileName.get()
|
||||
return archive.replaceAll(/\.(war|jar|ear)$/, '') + '-sbom.xlsx'
|
||||
}
|
||||
String ver = (p.version == null || p.version.toString() in ['', 'unspecified']) ? '' : "-${p.version}"
|
||||
return "${p.name}${ver}-sbom.xlsx"
|
||||
}
|
||||
|
||||
/** bom.json 위치 결정: -PsbomJson > cyclonedxBom 산출 경로 후보 */
|
||||
File resolveBomJson(Project p) {
|
||||
if (p.hasProperty('sbomJson')) {
|
||||
File f = p.file(p.property('sbomJson'))
|
||||
if (!f.exists()) {
|
||||
throw new GradleException("bom.json 없음: ${f.absolutePath}")
|
||||
}
|
||||
return f
|
||||
}
|
||||
def candidates = [
|
||||
new File(p.buildDir, 'reports/cyclonedx/bom.json'),
|
||||
new File(p.buildDir, 'reports/bom.json'),
|
||||
]
|
||||
File found = candidates.find { it.exists() }
|
||||
if (found == null) {
|
||||
throw new GradleException(
|
||||
"bom.json 을 찾지 못했다. 확인한 경로: " + candidates*.absolutePath.join(', ') +
|
||||
"\n'gradle cyclonedxBom' 실행 후 재시도하거나 -PsbomJson=<경로> 로 지정한다.")
|
||||
}
|
||||
return found
|
||||
}
|
||||
|
||||
/**
|
||||
* 실제 배포물에 packaging 되는 jar 목록.
|
||||
* war 프로젝트는 war 태스크 classpath(= runtimeClasspath), 그 외는 runtimeClasspath 를
|
||||
* 기준으로 하므로 test/annotationProcessor/developmentOnly/compileOnly 는 자동으로 빠진다.
|
||||
*
|
||||
* @return [label: 기준 설명, jars: 행 목록]
|
||||
*/
|
||||
Map collectDeployJars(Project p) {
|
||||
def cfg = p.configurations.findByName('runtimeClasspath')
|
||||
if (cfg == null) {
|
||||
p.logger.warn("[${p.name}] runtimeClasspath 가 없어 배포 기준 시트를 비운다")
|
||||
return [label: '(없음)', jars: []]
|
||||
}
|
||||
|
||||
def warTask = p.tasks.findByName('war')
|
||||
def files
|
||||
String label
|
||||
if (warTask != null) {
|
||||
files = warTask.classpath.files
|
||||
label = 'WAR WEB-INF/lib (war 태스크 classpath)'
|
||||
} else {
|
||||
files = cfg.files
|
||||
label = 'runtimeClasspath (war 태스크 없음)'
|
||||
}
|
||||
|
||||
def coordByFile = [:]
|
||||
cfg.resolvedConfiguration.resolvedArtifacts.each { a ->
|
||||
def id = a.moduleVersion.id
|
||||
coordByFile[a.file] = [group: id.group, name: id.name, version: id.version]
|
||||
}
|
||||
def jars = files.findAll { it.name.endsWith('.jar') }.collect { f ->
|
||||
def c = coordByFile[f]
|
||||
[
|
||||
file : f.name,
|
||||
group : c?.group ?: '',
|
||||
name : c?.name ?: f.name.replaceAll(/\.jar$/, ''),
|
||||
version: c?.version ?: '',
|
||||
coord : c ? "${c.group}:${c.name}:${c.version}".toString() : '',
|
||||
]
|
||||
}.sort { it.file }
|
||||
|
||||
return [label: label, jars: jars]
|
||||
}
|
||||
|
||||
/** bom.json 컴포넌트를 'group:name:version' 키로 색인 (라이선스/해시/설명/직접-전이) */
|
||||
Map indexComponents(bom) {
|
||||
String rootRef = bom.metadata?.component?.'bom-ref'
|
||||
Set directRefs = (bom.dependencies?.find { it.ref == rootRef }?.dependsOn ?: []) as Set
|
||||
|
||||
def index = [:]
|
||||
bom.components?.each { c ->
|
||||
def hashes = [:]
|
||||
c.hashes?.each { h -> hashes[h.alg] = h.content }
|
||||
|
||||
def licenses = (c.licenses ?: []).collect { l ->
|
||||
l.license?.id ?: l.license?.name ?: l.expression ?: ''
|
||||
}.findAll { it }
|
||||
|
||||
index["${c.group ?: ''}:${c.name ?: ''}:${c.version ?: ''}".toString()] = [
|
||||
direct : directRefs.contains(c.'bom-ref') ? '직접' : '전이',
|
||||
licenses : licenses.join('; '),
|
||||
licenseList: licenses.isEmpty() ? ['(미상)'] : licenses,
|
||||
purl : c.purl ?: '',
|
||||
sha256 : hashes['SHA-256'] ?: '',
|
||||
sha1 : hashes['SHA-1'] ?: '',
|
||||
description: c.description ?: '',
|
||||
]
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
/** WAR jar 목록에 SBOM 메타를 좌표로 결합 */
|
||||
List joinWarRows(List warJars, Map index) {
|
||||
def result = []
|
||||
warJars.eachWithIndex { j, i ->
|
||||
def m = j.coord ? index[j.coord] : null
|
||||
result << [
|
||||
no : i + 1,
|
||||
file : j.file,
|
||||
group : j.group,
|
||||
name : j.name,
|
||||
version : j.version,
|
||||
direct : m?.direct ?: '',
|
||||
licenses : m?.licenses ?: '',
|
||||
licenseList: m?.licenseList ?: ['(미상)'],
|
||||
purl : m?.purl ?: '',
|
||||
sha256 : m?.sha256 ?: '',
|
||||
sha1 : m?.sha1 ?: '',
|
||||
matched : (m != null) ? 'Y' : 'N',
|
||||
description: m?.description ?: '',
|
||||
]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
Map createStyles(wb) {
|
||||
def headFont = wb.createFont()
|
||||
headFont.setBold(true)
|
||||
headFont.setColor(IndexedColors.WHITE.getIndex())
|
||||
|
||||
def head = wb.createCellStyle()
|
||||
head.setFont(headFont)
|
||||
head.setFillForegroundColor(IndexedColors.DARK_BLUE.getIndex())
|
||||
head.setFillPattern(FillPatternType.SOLID_FOREGROUND)
|
||||
head.setAlignment(HorizontalAlignment.CENTER)
|
||||
head.setVerticalAlignment(VerticalAlignment.CENTER)
|
||||
head.setBorderBottom(BorderStyle.THIN)
|
||||
|
||||
def body = wb.createCellStyle()
|
||||
body.setVerticalAlignment(VerticalAlignment.TOP)
|
||||
|
||||
def wrap = wb.createCellStyle()
|
||||
wrap.setVerticalAlignment(VerticalAlignment.TOP)
|
||||
wrap.setWrapText(true)
|
||||
|
||||
def labelFont = wb.createFont()
|
||||
labelFont.setBold(true)
|
||||
def label = wb.createCellStyle()
|
||||
label.setFont(labelFont)
|
||||
|
||||
return [head: head, body: body, wrap: wrap, label: label]
|
||||
}
|
||||
|
||||
/** 헤더 행 생성 + 폭 지정 + 틀고정 */
|
||||
def writeHeader(sheet, style, List<String> headers, List<Integer> widths) {
|
||||
def row = sheet.createRow(0)
|
||||
row.setHeightInPoints(20f)
|
||||
headers.eachWithIndex { h, i ->
|
||||
def cell = row.createCell(i)
|
||||
cell.setCellValue(h)
|
||||
cell.setCellStyle(style)
|
||||
sheet.setColumnWidth(i, widths[i] * 256)
|
||||
}
|
||||
sheet.createFreezePane(0, 1)
|
||||
}
|
||||
|
||||
def cellOf(row, int idx, value, style) {
|
||||
def cell = row.createCell(idx)
|
||||
String s = (value == null) ? '' : value.toString()
|
||||
if (s.length() > SBOM_CELL_LIMIT) {
|
||||
s = s.substring(0, SBOM_CELL_LIMIT) + '…(생략)'
|
||||
}
|
||||
cell.setCellValue(s)
|
||||
cell.setCellStyle(style)
|
||||
return cell
|
||||
}
|
||||
|
||||
def writeSummarySheet(wb, st, bom, List warRows, File src, String basisLabel) {
|
||||
def sheet = wb.createSheet('요약')
|
||||
def comp = bom.metadata?.component ?: [:]
|
||||
def tool = bom.metadata?.tools?.components?.getAt(0)
|
||||
Set licenseKinds = warRows.collectMany { it.licenseList } as Set
|
||||
|
||||
def items = [
|
||||
['대상 프로젝트', "${comp.group ?: ''}:${comp.name ?: ''}:${comp.version ?: ''}"],
|
||||
['산출 기준', "${basisLabel} — test/annotationProcessor/compileOnly 제외"],
|
||||
['BOM 포맷', "${bom.bomFormat ?: ''} ${bom.specVersion ?: ''}"],
|
||||
['serialNumber', bom.serialNumber ?: ''],
|
||||
['생성 시각', bom.metadata?.timestamp ?: ''],
|
||||
['생성 도구', tool ? "${tool.name} ${tool.version}" : ''],
|
||||
['원본 파일', src.absolutePath],
|
||||
['배포 수록 jar', warRows.size()],
|
||||
[' └ 직접 의존', warRows.count { it.direct == '직접' }],
|
||||
[' └ 전이 의존', warRows.count { it.direct == '전이' }],
|
||||
[' └ SBOM 미매칭', warRows.count { it.matched == 'N' }],
|
||||
['라이선스 종류', licenseKinds.size()],
|
||||
['라이선스 미상', warRows.count { it.licenses.isEmpty() }],
|
||||
]
|
||||
|
||||
writeHeader(sheet, st.head, ['항목', '값'], [30, 90])
|
||||
items.eachWithIndex { item, i ->
|
||||
def row = sheet.createRow(i + 1)
|
||||
cellOf(row, 0, item[0], st.label)
|
||||
cellOf(row, 1, item[1], st.body)
|
||||
}
|
||||
|
||||
// 라이선스 분포 (요약 하단)
|
||||
def byLicense = [:].withDefault { 0 }
|
||||
warRows.each { r -> r.licenseList.each { lic -> byLicense[lic] = byLicense[lic] + 1 } }
|
||||
def sorted = byLicense.entrySet().sort { a, b -> (b.value <=> a.value) ?: (a.key <=> b.key) }
|
||||
|
||||
int base = items.size() + 2
|
||||
def hdr = sheet.createRow(base)
|
||||
cellOf(hdr, 0, '라이선스', st.head)
|
||||
cellOf(hdr, 1, 'jar 수', st.head)
|
||||
sorted.eachWithIndex { e, i ->
|
||||
def row = sheet.createRow(base + 1 + i)
|
||||
cellOf(row, 0, e.key, st.body)
|
||||
cellOf(row, 1, e.value, st.body)
|
||||
}
|
||||
}
|
||||
|
||||
/** 실제 배포물(WAR WEB-INF/lib) 기준 시트 */
|
||||
def writeWarSheet(wb, st, List warRows) {
|
||||
def sheet = wb.createSheet('WAR 기준')
|
||||
def headers = ['No', 'jar 파일명', 'Group', 'Name', 'Version', '구분',
|
||||
'License', 'purl', 'SHA-256', 'SHA-1', 'SBOM매칭', 'Description']
|
||||
def widths = [6, 46, 32, 34, 16, 7, 30, 60, 40, 30, 10, 60]
|
||||
writeHeader(sheet, st.head, headers, widths)
|
||||
|
||||
warRows.eachWithIndex { r, i ->
|
||||
def row = sheet.createRow(i + 1)
|
||||
cellOf(row, 0, r.no, st.body)
|
||||
cellOf(row, 1, r.file, st.body)
|
||||
cellOf(row, 2, r.group, st.body)
|
||||
cellOf(row, 3, r.name, st.body)
|
||||
cellOf(row, 4, r.version, st.body)
|
||||
cellOf(row, 5, r.direct, st.body)
|
||||
cellOf(row, 6, r.licenses, st.body)
|
||||
cellOf(row, 7, r.purl, st.body)
|
||||
cellOf(row, 8, r.sha256, st.body)
|
||||
cellOf(row, 9, r.sha1, st.body)
|
||||
cellOf(row, 10, r.matched, st.body)
|
||||
cellOf(row, 11, r.description, st.wrap)
|
||||
}
|
||||
if (!warRows.isEmpty()) {
|
||||
sheet.setAutoFilter(new CellRangeAddress(0, warRows.size(), 0, headers.size() - 1))
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,8 @@ public class DJBApiAdapterController implements HttpAdapterServiceKey {
|
||||
|
||||
@Autowired
|
||||
DJBApiAdapterService service;
|
||||
|
||||
|
||||
EAIServerManager eaiServerManager;
|
||||
/**
|
||||
* DJErp OAuth 조기 적용을 위한 Controller
|
||||
*
|
||||
@@ -89,7 +90,13 @@ public class DJBApiAdapterController implements HttpAdapterServiceKey {
|
||||
|
||||
ResponseEntity<String> responseEntity = null;
|
||||
Properties transactionProp = new Properties();
|
||||
String uuid = UUIDGenerator.getUUID().toString().replaceAll("-", "");
|
||||
|
||||
if(eaiServerManager == null)
|
||||
eaiServerManager = EAIServerManager.getInstance();
|
||||
|
||||
String instid = eaiServerManager.getGroupInstId();
|
||||
String uuid = instid+UUIDGenerator.getUUID().toString().replaceAll("-", "");
|
||||
|
||||
transactionProp.setProperty(TransactionContextKeys.TRANSACTION_UUID, uuid);
|
||||
transactionProp.put(INBOUND_REQUESTED_TIME, receivedTimeStr);
|
||||
|
||||
@@ -154,14 +161,14 @@ public class DJBApiAdapterController implements HttpAdapterServiceKey {
|
||||
responseEntity = ResponseEntity.status(e1.getStatus()).contentType(mediaType).body(responseErrorMsg);
|
||||
} else if (e instanceof JwtAuthException) {
|
||||
responseErrorMsg = genErrorResponseMessage(adapterGroupName, adapterName,
|
||||
transactionProp, MessageUtil.ERROR_CODE_AP_ERROR, e, adptMsgType, encode, errorResponseFormat);
|
||||
transactionProp, MessageUtil.ERROR_CODE_AUTH_FAIL, e, adptMsgType, encode, errorResponseFormat);
|
||||
JwtAuthException e1 = (JwtAuthException) e;
|
||||
this.logError(servletRequest, adapterGroupName, e1.getCode(), responseErrorMsg, transactionProp, e);
|
||||
logger.error("ApiAdapterController] " + adapterGroupName + "-" + adapterName + ">>" + e.getMessage(), e);
|
||||
responseEntity = ResponseEntity.status(HttpStatus.UNAUTHORIZED).contentType(mediaType).body(responseErrorMsg);
|
||||
} else if (e instanceof HttpStatusException) {
|
||||
responseErrorMsg = genErrorResponseMessage(adapterGroupName, adapterName,
|
||||
transactionProp, MessageUtil.ERROR_CODE_AUTH_FAIL, e, adptMsgType, encode, errorResponseFormat);
|
||||
transactionProp, MessageUtil.ERROR_CODE_AP_ERROR, e, adptMsgType, encode, errorResponseFormat);
|
||||
logger.error("ApiAdapterController] " + adapterGroupName + "-" + adapterName + ">>" + e.getMessage());
|
||||
HttpStatusException e1 = (HttpStatusException) e;
|
||||
responseEntity = ResponseEntity.status(e1.getStatus()).contentType(mediaType).body(responseErrorMsg);
|
||||
|
||||
+3
-12
@@ -6,7 +6,6 @@ import java.util.Properties;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import com.eactive.eai.adapter.http.dynamic.filter.FilterException;
|
||||
@@ -16,6 +15,7 @@ import com.eactive.eai.common.security.ARIACryptoModuleExtension;
|
||||
import com.eactive.eai.common.security.CryptoModuleExtension;
|
||||
import com.eactive.eai.common.util.Logger;
|
||||
import com.eactive.eai.util.HexaConverter;
|
||||
import com.eactive.eai.util.JsonPathUtil;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
@@ -30,17 +30,8 @@ public class DecrytTestFilter implements HttpAdapterFilter {
|
||||
public Object doPreFilter(String adptGrpName, String adptName, Object message, Properties prop,
|
||||
HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
try {
|
||||
ObjectNode rootNode = null;
|
||||
String jsonStr = null;
|
||||
if (message instanceof String) {
|
||||
jsonStr = (String) message;
|
||||
} else if (message instanceof JSONObject) {
|
||||
jsonStr = ((JSONObject) message).toJSONString();
|
||||
} else {
|
||||
return message;
|
||||
}
|
||||
rootNode = (ObjectNode) OBJECT_MAPPER.readTree(jsonStr);
|
||||
|
||||
ObjectNode rootNode = (ObjectNode)JsonPathUtil.toTree(message);
|
||||
|
||||
JsonNode alg = rootNode.get("alg");
|
||||
JsonNode mode = rootNode.get("mode");
|
||||
JsonNode padding = rootNode.get("padding");
|
||||
|
||||
+3
-15
@@ -8,7 +8,6 @@ import javax.crypto.SecretKey;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import com.eactive.eai.adapter.http.dynamic.filter.FilterException;
|
||||
@@ -19,6 +18,7 @@ import com.eactive.eai.common.security.ARIACryptoModuleExtension;
|
||||
import com.eactive.eai.common.security.CryptoModuleExtension;
|
||||
import com.eactive.eai.common.util.Logger;
|
||||
import com.eactive.eai.util.HexaConverter;
|
||||
import com.eactive.eai.util.JsonPathUtil;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
@@ -33,20 +33,8 @@ public class EncrytTestFilter implements HttpAdapterFilter {
|
||||
public Object doPreFilter(String adptGrpName, String adptName, Object message, Properties prop,
|
||||
HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
try {
|
||||
ObjectNode rootNode = null;
|
||||
String jsonStr = null;
|
||||
if (message instanceof String) {
|
||||
jsonStr = (String) message;
|
||||
} else if (message instanceof ObjectNode) {
|
||||
rootNode = (ObjectNode) message;
|
||||
} else if (message instanceof JSONObject) {
|
||||
jsonStr = ((JSONObject) message).toJSONString();
|
||||
} else {
|
||||
return message;
|
||||
}
|
||||
if(rootNode == null)
|
||||
rootNode = (ObjectNode) OBJECT_MAPPER.readTree(jsonStr);
|
||||
|
||||
ObjectNode rootNode = (ObjectNode)JsonPathUtil.toTree(message);
|
||||
|
||||
// 1. HSM에서 키 가져오기
|
||||
byte[] hsmKeyBytes = null;
|
||||
JsonNode hsmKeyAlias = rootNode.get("hsmKeyAlias");
|
||||
|
||||
@@ -8,7 +8,6 @@ import java.util.Properties;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import com.eactive.eai.adapter.http.dynamic.filter.FilterException;
|
||||
@@ -18,6 +17,7 @@ import com.eactive.eai.common.util.Logger;
|
||||
import com.eactive.eai.custom.common.security.keyderiv.HsmContextSha256KeyDerivationStrategy;
|
||||
import com.eactive.eai.custom.common.security.keyderiv.HsmKeyAndIvSliceDerivationStrategy;
|
||||
import com.eactive.eai.util.HexaConverter;
|
||||
import com.eactive.eai.util.JsonPathUtil;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
@@ -32,17 +32,8 @@ public class GenKeyFilter implements HttpAdapterFilter {
|
||||
public Object doPreFilter(String adptGrpName, String adptName, Object message, Properties prop,
|
||||
HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
try {
|
||||
ObjectNode rootNode = null;
|
||||
String jsonStr = null;
|
||||
if (message instanceof String) {
|
||||
jsonStr = (String) message;
|
||||
} else if (message instanceof JSONObject) {
|
||||
jsonStr = ((JSONObject) message).toJSONString();
|
||||
} else {
|
||||
return message;
|
||||
}
|
||||
rootNode = (ObjectNode) OBJECT_MAPPER.readTree(jsonStr);
|
||||
|
||||
ObjectNode rootNode = (ObjectNode)JsonPathUtil.toTree(message);
|
||||
|
||||
JsonNode hsmKey = rootNode.get("hsmKey");
|
||||
JsonNode hsmIv = rootNode.get("hsmIv");
|
||||
JsonNode contextKey = rootNode.get("contextKey");
|
||||
|
||||
-766
@@ -1,766 +0,0 @@
|
||||
package com.eactive.eai.custom.adapter.http.dynamic.impl;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.fileupload.FileItem;
|
||||
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
||||
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.time.StopWatch;
|
||||
import org.apache.mina.common.ByteBuffer;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.JSONValue;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
|
||||
import com.eactive.eai.adapter.AdapterManager;
|
||||
import com.eactive.eai.adapter.AdapterPropManager;
|
||||
import com.eactive.eai.adapter.AdapterVO;
|
||||
import com.eactive.eai.adapter.Keys;
|
||||
import com.eactive.eai.adapter.http.HttpMemoryLogger;
|
||||
import com.eactive.eai.adapter.http.HttpMethodType;
|
||||
import com.eactive.eai.adapter.http.HttpStatusException;
|
||||
import com.eactive.eai.adapter.http.client.HttpClientAdapterServiceKey;
|
||||
import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceSupport;
|
||||
import com.eactive.eai.adapter.http.dynamic.filter.JwtAuthException;
|
||||
import com.eactive.eai.common.TransactionContextKeys;
|
||||
import com.eactive.eai.common.exception.ExceptionUtil;
|
||||
import com.eactive.eai.common.message.MessageType;
|
||||
import com.eactive.eai.common.util.CommonLib;
|
||||
import com.eactive.eai.common.util.HttpAdapterExtraLogUtil;
|
||||
import com.eactive.eai.common.util.Logger;
|
||||
import com.eactive.eai.common.util.MessageUtil;
|
||||
import com.eactive.eai.env.ElinkConfig;
|
||||
import com.eactive.eai.inbound.action.ActionFactory;
|
||||
import com.eactive.eai.inbound.action.RequestAction;
|
||||
import com.eactive.eai.inbound.processor.Processor;
|
||||
import com.eactive.eai.message.StandardMessageUtil;
|
||||
|
||||
/*
|
||||
* Kbank 가상계좌 INBOUND
|
||||
* @see com.eactive.eai.custom.adapter.http.dynamic.filter.VirtualAccountCryptoFilter
|
||||
* @Deprecated
|
||||
*/
|
||||
// FIXME : kbank - kbank에서는 Controller 방식을 사용하므로, 이 어댑터는 사용되지 않음 (VirtualAccountCryptoFilter 로 대체)
|
||||
public class HttpAdapterServiceVirtualAccount extends HttpAdapterServiceSupport {
|
||||
public static final String HEADER_GROUP = "HEADER_GROUP";
|
||||
// HEADER_GROUP JSON에 추가할 항목 정의, 없으면 전체 header 추가
|
||||
public static final String HEADER_KEYS = "HEADER_KEYS";
|
||||
public static final String HTTP_STATUS = "HTTP_STATUS";
|
||||
public static final String PROPERTIES_NAME_HTTP_REQUEST_METHOD = "httpRequestMethod";
|
||||
|
||||
static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER);
|
||||
private String logPrefix = "HttpAdapterServiceRest] ";
|
||||
|
||||
private static final String JSON_CONTENT_TYPE = "application/json";
|
||||
private static final String JSON_FIELD_NAME = "json-body";
|
||||
private static final String FILE_GROUP_NAME = "image-file";
|
||||
private static final String UPLOAD_ROOT_PATH = "UPLOAD_ROOT_PATH";
|
||||
|
||||
private Properties addCryptoFilter(Properties prop) {
|
||||
String cryptoFilterName = "com.eactive.eai.custom.adapter.http.dynamic.filter.VirtualAccountCryptoFilter";
|
||||
String addedPreFilter = prop.getProperty(PRE_FILTERS);
|
||||
String addedPostFilter = prop.getProperty(POST_FILTERS);
|
||||
|
||||
if(StringUtils.isBlank(addedPreFilter)) {
|
||||
addedPreFilter = cryptoFilterName;
|
||||
}
|
||||
else {
|
||||
addedPreFilter = addedPreFilter + "," +cryptoFilterName;
|
||||
}
|
||||
|
||||
if(StringUtils.isBlank(addedPostFilter)) {
|
||||
addedPostFilter = cryptoFilterName;
|
||||
}
|
||||
else {
|
||||
addedPostFilter = cryptoFilterName + "," +addedPostFilter;
|
||||
}
|
||||
|
||||
prop.setProperty(PRE_FILTERS, addedPreFilter);
|
||||
prop.setProperty(POST_FILTERS, addedPostFilter);
|
||||
return prop;
|
||||
}
|
||||
|
||||
private String readMultipartBody(HttpServletRequest request) throws Exception {
|
||||
String jsonString = null;
|
||||
// Create a factory for disk-based file items
|
||||
DiskFileItemFactory factory = new DiskFileItemFactory();
|
||||
|
||||
// Set the maximum size of the files to be uploaded
|
||||
factory.setSizeThreshold(1024 * 1024);
|
||||
|
||||
// Set the temporary directory to store uploaded files
|
||||
File tempDir = (File) request.getSession().getServletContext().getAttribute("javax.servlet.context.tempdir");
|
||||
factory.setRepository(tempDir);
|
||||
|
||||
ServletFileUpload upload = new ServletFileUpload(factory);
|
||||
Map<String, String> fileMap = new HashMap<>();
|
||||
|
||||
InputStream fin = null;
|
||||
try {
|
||||
byte[] buffer = new byte[1024];
|
||||
int read = 0;
|
||||
|
||||
List<FileItem> items = upload.parseRequest(request);
|
||||
for (FileItem item : items) {
|
||||
if (!item.isFormField()) {
|
||||
// file
|
||||
String fieldName = item.getFieldName();
|
||||
String fileName = item.getName();
|
||||
fin = item.getInputStream();
|
||||
ByteArrayOutputStream fo = new ByteArrayOutputStream();
|
||||
while ((read = fin.read(buffer)) > 0) {
|
||||
fo.write(buffer, 0, read);
|
||||
}
|
||||
int fileSize = fo.size();
|
||||
byte[] fileBytes = fo.toByteArray();
|
||||
String fileContents = new String(fileBytes);
|
||||
if (logger.isInfo()) {
|
||||
logger.info("[FILE]-------------------------------------------------->");
|
||||
logger.info("Field name = " + fieldName);
|
||||
logger.info("File name = " + fileName + " contents length = " + fileSize);
|
||||
logger.info("File Contents [" + fileContents + "]");
|
||||
logger.info("[FILE]<--------------------------------------------------");
|
||||
}
|
||||
fileMap.put(fileName, fileContents);
|
||||
fin.close();
|
||||
} else {
|
||||
// regular form field
|
||||
String fieldName = item.getFieldName();
|
||||
String fieldValue = item.getString();
|
||||
if (logger.isInfo()) {
|
||||
logger.info("[FIELD] " + fieldName + " [" + fieldValue + "]");
|
||||
}
|
||||
if (JSON_CONTENT_TYPE.equalsIgnoreCase(item.getContentType())
|
||||
|| JSON_FIELD_NAME.equals(fieldName)) {
|
||||
jsonString = fieldValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (logger.isInfo()) {
|
||||
logger.info("Json body [" + jsonString + "]");
|
||||
}
|
||||
|
||||
if (jsonString == null) {
|
||||
jsonString = "{}";
|
||||
} else {
|
||||
// parsing json & add file contents
|
||||
JSONObject jsonObject = (JSONObject) JSONValue.parse(jsonString);
|
||||
if (jsonObject == null) {
|
||||
jsonString = "{}";
|
||||
} else {
|
||||
JSONObject fileGroup = new JSONObject();
|
||||
|
||||
for (Map.Entry<String, String> entry : fileMap.entrySet()) {
|
||||
fileGroup.put("fileName", entry.getKey());
|
||||
fileGroup.put("fileContents", entry.getValue());
|
||||
}
|
||||
jsonObject.put(FILE_GROUP_NAME, fileGroup);
|
||||
jsonString = jsonObject.toJSONString();
|
||||
}
|
||||
}
|
||||
|
||||
if (logger.isInfo()) {
|
||||
logger.info("Json with file [" + jsonString + "]");
|
||||
}
|
||||
return jsonString;
|
||||
} catch (Exception e) {
|
||||
logger.error("Read multipart body error.", e);
|
||||
throw e;
|
||||
} finally {
|
||||
if (fin != null) {
|
||||
try {
|
||||
fin.close();
|
||||
} catch (Exception ex) {
|
||||
// empty
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String checkRootPath(String path) {
|
||||
if (StringUtils.isEmpty(path)) {
|
||||
logger.info("upload dir not set(UPLOAD_ROOT_PATH), use system temp " + path);
|
||||
return System.getProperty("java.io.tmpdir");
|
||||
}
|
||||
File file = new File(path);
|
||||
if (!file.exists()) {
|
||||
file.mkdirs();
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private String uploadMultipartBody(HttpServletRequest request, String uploadRootPath) throws Exception {
|
||||
String jsonString = null;
|
||||
// Create a factory for disk-based file items
|
||||
DiskFileItemFactory factory = new DiskFileItemFactory();
|
||||
|
||||
// Set the maximum size of the files to be uploaded
|
||||
factory.setSizeThreshold(1024 * 1024);
|
||||
|
||||
// Set the temporary directory to store uploaded files
|
||||
File tempDir = (File) request.getSession().getServletContext().getAttribute("javax.servlet.context.tempdir");
|
||||
factory.setRepository(tempDir);
|
||||
|
||||
ServletFileUpload upload = new ServletFileUpload(factory);
|
||||
try {
|
||||
// if not exist, create folders
|
||||
String uploadDir = checkRootPath(uploadRootPath);
|
||||
List<FileItem> items = upload.parseRequest(request);
|
||||
for (FileItem item : items) {
|
||||
if (!item.isFormField()) {
|
||||
// file
|
||||
String fieldName = item.getFieldName();
|
||||
String fileName = item.getName();
|
||||
String uploadFilePath = uploadDir + File.separator + fileName;
|
||||
File uploadFile = new File(uploadFilePath);
|
||||
item.write(uploadFile);
|
||||
|
||||
if (logger.isInfo()) {
|
||||
logger.info("[FILE]-------------------------------------------------->");
|
||||
logger.info("Field name = " + fieldName);
|
||||
logger.info("File name = " + fileName + " path = " + uploadFile.getAbsolutePath());
|
||||
logger.info("[FILE]<--------------------------------------------------");
|
||||
}
|
||||
} else {
|
||||
// regular form field
|
||||
String fieldName = item.getFieldName();
|
||||
String fieldValue = item.getString();
|
||||
if (logger.isInfo()) {
|
||||
logger.info("[FIELD] " + fieldName + " [" + fieldValue + "]");
|
||||
}
|
||||
if (JSON_CONTENT_TYPE.equalsIgnoreCase(item.getContentType())
|
||||
|| JSON_FIELD_NAME.equals(fieldName)) {
|
||||
jsonString = fieldValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (logger.isInfo()) {
|
||||
logger.info("Json body [" + jsonString + "]");
|
||||
}
|
||||
return jsonString;
|
||||
} catch (Exception e) {
|
||||
logger.error("Read multipart body error.", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "deprecation" })
|
||||
public void service(String adptGrpName, String adptName, HttpServletRequest request, HttpServletResponse response) {
|
||||
int traceLevel = 0;
|
||||
|
||||
AdapterVO adptVO = null;
|
||||
AdapterPropManager manager = null;
|
||||
|
||||
Properties httpProp = null;
|
||||
String responseType = null;
|
||||
String urlDecodeYn = null;
|
||||
String encode = null;
|
||||
|
||||
String traceLevelTemp = null;
|
||||
String relayRequestHeaderKeys = null;
|
||||
String headerGroupName = null;
|
||||
|
||||
boolean isParameterType = false;
|
||||
String message = null;
|
||||
|
||||
StopWatch stopWatch = null;
|
||||
Properties prop = null;
|
||||
String paramValue = null;
|
||||
String adptMsgType = null;
|
||||
String errorResponseFormat = null;
|
||||
String uploadRootPath = null;
|
||||
try {
|
||||
AdapterManager adapterManager = AdapterManager.getInstance();
|
||||
adptVO = adapterManager.getAdapterVO(adptGrpName, adptName);
|
||||
if (adptVO == null) {
|
||||
throw new Exception("Adapter not found error");
|
||||
}
|
||||
|
||||
manager = AdapterPropManager.getInstance();
|
||||
|
||||
httpProp = manager.getProperties(adptVO.getPropGroupName());
|
||||
responseType = httpProp.getProperty(RESPONSE_TYPE, "SYNC");
|
||||
urlDecodeYn = httpProp.getProperty(URL_DECODE_YN, "N");
|
||||
// encode = httpProp.getProperty(ENCODE, "UTF-8");
|
||||
encode = StringUtils.defaultIfBlank(adapterManager.getAdapterGroupVO(adptGrpName).getMessageEncode(),
|
||||
"UTF-8");
|
||||
traceLevelTemp = httpProp.getProperty(TRACE_LEVEL, "0");
|
||||
relayRequestHeaderKeys = httpProp.getProperty(HEADER_KEYS);
|
||||
headerGroupName = httpProp.getProperty(HEADER_GROUP);
|
||||
errorResponseFormat = httpProp.getProperty(ERROR_RESPONSE_FORMAT);
|
||||
uploadRootPath = httpProp.getProperty(UPLOAD_ROOT_PATH);
|
||||
prop = new Properties();
|
||||
prop.put(INBOUND_METHOD, request.getMethod());
|
||||
prop.put(INBOUND_URI, request.getRequestURI());
|
||||
prop.put(INBOUND_HEADER, getHeaders(request));
|
||||
prop.put(INBOUND_EXTPARAMS, StringUtils.defaultString(request.getQueryString()));
|
||||
if (StringUtils.equals(adptVO.getAdapterGroupVO().getType(), Keys.TYPE_REST)
|
||||
|| StringUtils.equals(adptVO.getAdapterGroupVO().getType(), Keys.TYPE_HTTP_CUSTOM)) {
|
||||
// /api/v1/public/getUserInfo.svc
|
||||
String extUrl = StringUtils.removeStart(request.getRequestURI(), request.getContextPath());
|
||||
prop.put(INBOUND_EXTURI, extUrl);
|
||||
} else {
|
||||
prop.put(INBOUND_EXTURI, getExtUri(request));
|
||||
}
|
||||
prop.put(Processor.REQUEST_ACTION, adptVO.getAdapterGroupVO().getRefClass());
|
||||
prop.put(API_PATH, httpProp.getProperty(API_PATH, ""));
|
||||
prop.put(PRE_FILTERS, httpProp.getProperty(PRE_FILTERS, ""));
|
||||
prop.put(POST_FILTERS, httpProp.getProperty(POST_FILTERS, ""));
|
||||
prop.put(PROPERTIES_NAME_HTTP_REQUEST_METHOD, request.getMethod());
|
||||
prop.put(ALLOW_IP, httpProp.getProperty(ALLOW_IP, ""));
|
||||
|
||||
isParameterType = false;
|
||||
try {
|
||||
traceLevel = Integer.parseInt(traceLevelTemp);
|
||||
} catch (Exception e) {
|
||||
traceLevel = 0;
|
||||
}
|
||||
|
||||
stopWatch = new StopWatch();
|
||||
stopWatch.start();
|
||||
|
||||
logger.debug("시작 >> encode = [" + encode + "]");
|
||||
|
||||
switch (HttpMethodType.getValue(request.getMethod())) {
|
||||
case GET:
|
||||
case DELETE:
|
||||
isParameterType = true;
|
||||
break;
|
||||
case POST:
|
||||
case PUT:
|
||||
if (StringUtils.contains(request.getContentType(), "application/x-www-form-urlencoded")) {
|
||||
isParameterType = true;
|
||||
} else {
|
||||
isParameterType = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (isParameterType) {
|
||||
paramValue = request.getQueryString();
|
||||
if (paramValue == null)
|
||||
paramValue = "";
|
||||
if (traceLevel >= 3) {
|
||||
HttpMemoryLogger.txlog(adptGrpName + adptName,
|
||||
"RECV " + "[" + paramValue + "]" + CommonLib.getDumpMessage(paramValue));
|
||||
}
|
||||
|
||||
// json으로 변환
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("{");
|
||||
Map<String, String[]> paramMap = assignParameterMap(request, adptGrpName, adptName, null, prop);
|
||||
int i = 0;
|
||||
for (Map.Entry<String, String[]> entry : paramMap.entrySet()) {
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append("\"").append(entry.getKey()).append("\":");
|
||||
String[] values = entry.getValue();
|
||||
if (values.length > 1) {
|
||||
// ["111", "222"]
|
||||
sb.append("[");
|
||||
for (int j = 0; j < values.length; j++) {
|
||||
if (j > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append("\"").append(JSONValue.escape(values[j])).append("\"");
|
||||
}
|
||||
sb.append("]");
|
||||
} else {
|
||||
sb.append("\"").append(JSONValue.escape(values[0])).append("\"");
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
sb.append("}");
|
||||
|
||||
paramValue = sb.toString();
|
||||
} else {
|
||||
if (ServletFileUpload.isMultipartContent(request)) {
|
||||
// TODO : 아래의 로직은 업무에 맞게 수정이 필요함.
|
||||
// 불필요할 경우 제거
|
||||
// if(StringUtils.isEmpty(uploadRootPath)) {
|
||||
// uploadRootPath = System.getProperty("java.io.tmpdir");
|
||||
// }
|
||||
|
||||
// 임시로직 : UPLOAD_ROOT_PATH 가 없는 경우에는 JSON에 추가
|
||||
if (StringUtils.isEmpty(uploadRootPath)) {
|
||||
paramValue = readMultipartBody(request);
|
||||
} else {
|
||||
paramValue = uploadMultipartBody(request, uploadRootPath);
|
||||
}
|
||||
// TEST : 테스트용 임시코드
|
||||
// response.setCharacterEncoding(encode);
|
||||
// response.getWriter().print(paramValue);
|
||||
// return;
|
||||
} else {
|
||||
ServletInputStream sis = request.getInputStream();
|
||||
ByteBuffer bb = ByteBuffer.allocate(1024).setAutoExpand(true);
|
||||
int i = 0;
|
||||
byte[] cbuf = new byte[1024];
|
||||
while ((i = sis.read(cbuf, 0, 1024)) != -1) {
|
||||
if (i == 1024) {
|
||||
bb.put(cbuf);
|
||||
} else {
|
||||
byte[] tail = new byte[i];
|
||||
System.arraycopy(cbuf, 0, tail, 0, i);
|
||||
bb.put(tail);
|
||||
}
|
||||
}
|
||||
byte[] data = new byte[bb.position()];
|
||||
bb.position(0);
|
||||
bb.get(data);
|
||||
paramValue = new String(data, encode);
|
||||
|
||||
if (traceLevel >= 3) {
|
||||
HttpMemoryLogger.txlog(adptGrpName + adptName,
|
||||
"RECV " + "[" + paramValue + "]" + CommonLib.getDumpMessage(paramValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (paramValue == null) { // parameter가 없는 경우때문에 처리
|
||||
paramValue = "";
|
||||
}
|
||||
|
||||
if (logger.isDebug()) {
|
||||
logger.debug("HttpAdapterServiceRest] RECV (" + adptGrpName + ") = [" + paramValue + "]\n"
|
||||
+ CommonLib.getDumpMessage(paramValue));
|
||||
}
|
||||
|
||||
if ("Y".equals(urlDecodeYn) && isParameterType) {
|
||||
message = URLDecoder.decode(paramValue);
|
||||
} else {
|
||||
message = paramValue;
|
||||
}
|
||||
|
||||
if (logger.isDebug()) {
|
||||
String[] msgArgs = new String[2];
|
||||
msgArgs[0] = adptGrpName;
|
||||
msgArgs[1] = message;
|
||||
String resMsg = ExceptionUtil.make("RICEAIAHA005", msgArgs);
|
||||
logger.debug(logPrefix + resMsg);
|
||||
}
|
||||
|
||||
adptMsgType = adptVO.getAdapterGroupVO().getMessageType();
|
||||
if (StringUtils.equals(adptMsgType, MessageType.JSON)) {
|
||||
response.setContentType(JSON_CONTENT_TYPE+"; charset="+encode);
|
||||
}
|
||||
|
||||
// HEADER_GROUP 셋팅
|
||||
if (MessageType.JSON.equals(adptMsgType) && StringUtils.isNotBlank(headerGroupName)
|
||||
&& StringUtils.isNotBlank(relayRequestHeaderKeys)) {
|
||||
JSONObject jsonMessage = (JSONObject) JSONValue.parse(message);
|
||||
JSONObject headerJson = new JSONObject();
|
||||
if (StringUtils.equalsIgnoreCase(relayRequestHeaderKeys, "ALL")) {
|
||||
for (Enumeration<String> e = request.getHeaderNames(); e.hasMoreElements();) {
|
||||
String key = e.nextElement();
|
||||
headerJson.put(key, request.getHeader(key));
|
||||
}
|
||||
} else {
|
||||
String[] relayKeyArr = org.springframework.util.StringUtils
|
||||
.tokenizeToStringArray(relayRequestHeaderKeys, ",");
|
||||
|
||||
for (String key : relayKeyArr) {
|
||||
String headerValue = request.getHeader(key);
|
||||
if (StringUtils.isNotBlank(headerValue)) {
|
||||
headerJson.put(key, headerValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (headerJson.size() > 0) {
|
||||
jsonMessage.put(headerGroupName, headerJson);
|
||||
message = jsonMessage.toJSONString();
|
||||
}
|
||||
}
|
||||
|
||||
if (message == null) {
|
||||
message = "";
|
||||
}
|
||||
|
||||
// com.eactive.eai.custom.adapter.http.dynamic.filter.VirtualAccountCryptoFilter
|
||||
prop = addCryptoFilter(prop);
|
||||
|
||||
// 로컬 서비스 호출 ,encoding 처리 추가
|
||||
String result = (String) service(adptGrpName, adptName, message, prop, request, response);
|
||||
|
||||
if (logger.isDebug()) {
|
||||
logger.debug("HttpAdapterServiceRest] result " + encode + " (" + adptGrpName + ") = [" + result + "]");
|
||||
}
|
||||
|
||||
stopWatch.stop();
|
||||
|
||||
String responseData = "";
|
||||
if (RESPONSE_TYPE_ASYNC.equals(responseType)) {
|
||||
if (stopWatch.getTime() > slowTranTime && (logger.isInfo())) {
|
||||
logger.info("HttpAdapterServiceRest] dummy response time = " + stopWatch.toString() + ", message = "
|
||||
+ message);
|
||||
|
||||
}
|
||||
if (result == null) {
|
||||
responseData = ElinkConfig.getAsyncDummyDataForAdapterGroup(adptGrpName);
|
||||
}
|
||||
|
||||
response.setCharacterEncoding(encode);
|
||||
response.getWriter().print(responseData);
|
||||
if (traceLevel >= 3) {
|
||||
HttpMemoryLogger.txlog(adptGrpName + adptName,
|
||||
"SEND " + "[" + responseData + "]" + CommonLib.getDumpMessage(responseData));
|
||||
}
|
||||
} else {
|
||||
responseData = result;
|
||||
logger.info("종료 >> encode = [" + encode + "]");
|
||||
|
||||
JSONObject dataObject = null;
|
||||
if (MessageType.JSON.equals(adptMsgType)) {
|
||||
dataObject = (JSONObject) JSONValue.parse(responseData);
|
||||
}
|
||||
|
||||
// HEADER_GROUP 하위 필드를 response Header에 세팅한다.
|
||||
HashMap<String, String> header = new HashMap<>();
|
||||
boolean redirect = assignHttpHeaders(header, dataObject, headerGroupName);
|
||||
|
||||
if (logger.isDebug()) {
|
||||
logger.debug("HttpAdapterServiceRest] response header field (" + adptGrpName + ") = ["
|
||||
+ header.toString() + "]");
|
||||
}
|
||||
|
||||
if (redirect) {
|
||||
response.setStatus(302);
|
||||
logger.debug("HttpAdapterServiceRest] set response status_code: 302");
|
||||
} else {
|
||||
String httpStatus = header.get(HTTP_STATUS);
|
||||
if (httpStatus != null && !"".equals(httpStatus))
|
||||
response.setStatus(Integer.parseInt(httpStatus));
|
||||
header.remove(HTTP_STATUS);
|
||||
}
|
||||
|
||||
// response header 셋팅
|
||||
for (Map.Entry<String, String> entry : header.entrySet()) {
|
||||
response.setHeader(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
if (dataObject != null) {
|
||||
responseData = dataObject.toJSONString();
|
||||
}
|
||||
|
||||
// UI와 통신시(UTF-8) 변환오류로 ENCODE 제거
|
||||
response.setCharacterEncoding(encode);
|
||||
response.getWriter().print(responseData);
|
||||
if (logger.isDebug()) {
|
||||
logger.debug("HttpAdapterServiceRest] SEND (" + adptGrpName + ") = [" + responseData + "]");
|
||||
logger.debug("HttpAdapterServiceRest] SEND (" + adptGrpName + ") = "
|
||||
+ CommonLib.getDumpMessage(responseData));
|
||||
}
|
||||
if (traceLevel >= 3) {
|
||||
HttpMemoryLogger.txlog(adptGrpName + adptName,
|
||||
"SEND " + "[" + responseData + "]" + CommonLib.getDumpMessage(responseData));
|
||||
}
|
||||
}
|
||||
} catch (HttpStatusException e) {
|
||||
if (traceLevel >= 3) {
|
||||
HttpMemoryLogger.error(adptGrpName + adptName, e.toString(), e);
|
||||
}
|
||||
logger.warn("HttpAdapter] " + adptGrpName + "-" + adptName + ">>" + e.getMessage());
|
||||
response.setStatus(e.getStatus());
|
||||
try {
|
||||
String errorMsg = MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode, e.getCode(),
|
||||
e.getMessage(), errorResponseFormat);
|
||||
response.getWriter().println(errorMsg);
|
||||
} catch (Exception ex) {
|
||||
// IGNORE
|
||||
}
|
||||
} catch (JwtAuthException e) {
|
||||
if (traceLevel >= 3) {
|
||||
HttpMemoryLogger.error(adptGrpName + adptName, e.toString(), e);
|
||||
}
|
||||
logger.error(logPrefix + adptGrpName + "-" + adptName + ">>" + e.getMessage(), e);
|
||||
response.setStatus(HttpStatus.UNAUTHORIZED.value());
|
||||
try {
|
||||
String errorMsg = MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode, e.getCode(),
|
||||
e.getMessage(), errorResponseFormat);
|
||||
response.getWriter().println(errorMsg);
|
||||
} catch (Exception ex) {
|
||||
// IGNORE
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (traceLevel >= 3) {
|
||||
HttpMemoryLogger.error(adptGrpName + adptName, e.toString(), e);
|
||||
}
|
||||
logger.error(logPrefix + adptGrpName + "-" + adptName + ">>" + e.getMessage(), e);
|
||||
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||
try {
|
||||
response.getWriter().println(e.getMessage());
|
||||
String errCode = ExceptionUtil.getErrorCode(e, "RECEAIAHA003");
|
||||
throw new Exception(errCode);
|
||||
} catch (Exception ex) {
|
||||
// IGNORE
|
||||
logger.warn(logPrefix + adptGrpName + "-" + adptName + ">>" + e.getMessage(), e);
|
||||
}
|
||||
} finally {
|
||||
String uuid = prop.getProperty(TransactionContextKeys.TRANSACTION_UUID);
|
||||
String url = prop.getProperty(HttpClientAdapterServiceKey.INBOUND_EXTURI);
|
||||
String method = prop.getProperty(HttpClientAdapterServiceKey.INBOUND_METHOD);
|
||||
String adapterGroupName = prop.getProperty(HttpClientAdapterServiceKey.ADAPTER_GROUP_NAME);
|
||||
String adapterName = prop.getProperty(HttpClientAdapterServiceKey.ADAPTER_NAME);
|
||||
int httpStatusCode = response.getStatus();
|
||||
HttpAdapterExtraLogUtil.insertHttpAdapterExtraLog(uuid, 400, adapterGroupName, adapterName, new HashMap<>(), url, method, httpStatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String[]> assignParameterMap(HttpServletRequest request, String adptGrpName, String adptName,
|
||||
Object requestBytes, Properties prop) {
|
||||
// PathVariable 체크
|
||||
if (StringUtils.equalsAnyIgnoreCase(request.getMethod(), HttpMethod.GET.name(), HttpMethod.DELETE.name())
|
||||
&& StringUtils.isBlank(request.getQueryString())) {
|
||||
try {
|
||||
String actionName = prop.getProperty(Processor.REQUEST_ACTION);
|
||||
RequestAction action = ActionFactory.createAction(actionName);
|
||||
action.setAdapterInfo(adptGrpName, adptName, prop);
|
||||
String[] keys = action.perform(requestBytes);
|
||||
String requestPath = keys[0];
|
||||
|
||||
// PathVariable 지원 추가
|
||||
String ruledPath = StandardMessageUtil.getMatchedKey(requestPath, actionName);
|
||||
if (!StringUtils.equals(requestPath, ruledPath) && StringUtils.contains(ruledPath, "{")) {
|
||||
Map<String, String> paramMap = new AntPathMatcher().extractUriTemplateVariables(ruledPath,
|
||||
requestPath);
|
||||
if (paramMap != null && paramMap.size() > 0) {
|
||||
Map<String, String[]> returnMap = new HashMap<>();
|
||||
for (String key : paramMap.keySet()) {
|
||||
if (StringUtils.equalsIgnoreCase(key, "method")) {
|
||||
continue;
|
||||
}
|
||||
returnMap.put(key, new String[] { paramMap.get(key) });
|
||||
}
|
||||
|
||||
return returnMap;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return request.getParameterMap();
|
||||
}
|
||||
|
||||
private void validateServiceAndAdapter(String adptGrpName, String adptName, byte[] requestBytes, Properties prop)
|
||||
throws JwtAuthException {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* request header 를 hashmap으로 조립
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
private Properties getHeaders(HttpServletRequest request) {
|
||||
Properties prop = new Properties();
|
||||
|
||||
Enumeration<String> headerNames = request.getHeaderNames();
|
||||
while (headerNames.hasMoreElements()) {
|
||||
String key = headerNames.nextElement();
|
||||
String value = request.getHeader(key);
|
||||
prop.setProperty(key, value);
|
||||
}
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
/**
|
||||
* adapter property의 HEADER_GROUP으로 정의된 (MFE_HEADER) 그룹의 하위 필드를 http Header에
|
||||
* 세팅한다.
|
||||
*
|
||||
* @param header
|
||||
* @param object
|
||||
*/
|
||||
private boolean assignHttpHeaders(HashMap<String, String> header, Object msg, String headerGroupName) {
|
||||
boolean redirect = false;
|
||||
|
||||
if (msg == null || StringUtils.isBlank(headerGroupName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (msg instanceof JSONObject) {
|
||||
JSONObject headerObject = (JSONObject) ((JSONObject) msg).get(headerGroupName);
|
||||
|
||||
if (headerObject == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// List<String> headerKeys = new ArrayList<>();
|
||||
for (Object key : headerObject.keySet()) {
|
||||
|
||||
Object obj = headerObject.get(key);
|
||||
if ((obj instanceof JSONObject) || (obj instanceof JSONArray)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
header.put((String) key, (String) obj);
|
||||
|
||||
if (StringUtils.equalsIgnoreCase((String) key, "Location")) {
|
||||
redirect = true;
|
||||
}
|
||||
}
|
||||
|
||||
((JSONObject) msg).remove(headerGroupName);
|
||||
}
|
||||
|
||||
return redirect;
|
||||
}
|
||||
|
||||
/**
|
||||
* 어댑터 명 이후의 URI값을 가져온다.
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
private String getExtUri(HttpServletRequest request) {
|
||||
String orgUri = request.getRequestURI().replaceAll(request.getContextPath(), "");
|
||||
String uri = getExtUri(orgUri, 3);
|
||||
if (uri != null && uri.trim().length() > 0) {
|
||||
return "/" + uri;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private static String getExtUri(String url, int length) {
|
||||
String[] urls = url.split("/");
|
||||
List<String> newUrls = new ArrayList<>();
|
||||
Collections.addAll(newUrls, urls);
|
||||
return StringUtils.join(newUrls.subList(length, urls.length).toArray(), "/");
|
||||
}
|
||||
|
||||
// public static void main(String[] args) throws Exception {
|
||||
// String orgUri = "/HTT/CbsInNetSys/abcd/123456";
|
||||
// String result = "";
|
||||
// result = getExtUri(orgUri, 3);
|
||||
// System.out.println(result);
|
||||
// }
|
||||
}
|
||||
@@ -28,7 +28,7 @@ public final class GUIDGeneratorDJB {
|
||||
|
||||
static {
|
||||
// 노드번호(2): 서버명 마지막 2자리, 없으면 "00"
|
||||
String serverName = System.getProperty("server.key", "");
|
||||
String serverName = System.getProperty(com.eactive.eai.common.server.Keys.SERVER_KEY, "");
|
||||
if (serverName.length() >= 2) {
|
||||
NODE_NO = serverName.substring(serverName.length() - 2);
|
||||
} else {
|
||||
|
||||
@@ -13,11 +13,9 @@ import com.eactive.eai.common.security.CryptoModuleService;
|
||||
/**
|
||||
* JEP 트랜스포머 함수 — DJB ERP 연동 암호화.
|
||||
*
|
||||
* 사용법: DJBErpEncryt(plainText, moduleName) DJBErpEncryt(plainText, moduleName,
|
||||
* groupSeq)
|
||||
* 사용법: DJBErpEncryt(plainText, moduleName)
|
||||
*
|
||||
* 파라미터: plainText : 암호화할 평문 (String) moduleName : DB에 등록된 암호화 모듈명 (String)
|
||||
* groupSeq : 키 도출용 그룹 시퀀스 (String, 선택). 미전달 시 빈 context로 호출.
|
||||
* 파라미터: plainText : 암호화할 평문 (String), moduleName : DB에 등록된 암호화 모듈명 (String)
|
||||
*
|
||||
* 반환값: Base64 인코딩된 암호문 (String)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user