OAuth 토큰 현황 조회 API 진단 항목 보강
- 캐시에 빈 토큰이 있거나 만료시각이 없으면 재발급되지 않음을 message 로 알림 - 그룹 내 어댑터별 ADAPTER_TOKEN_ISSUING_CLIENT_TYPE 을 adapterTokenServiceClasses 로 노출 - 스케줄러와 거래 중 재발급이 서로 다른 어댑터 속성을 쓰는 경우를 확인하기 위함 - 단위테스트 2건 추가
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
package com.eactive.eai.manage.oauthtoken;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
@@ -18,9 +20,22 @@ public class OAuthTokenStatusDTO {
|
||||
/** OAuth 인증 정보 사용 여부 (Y/N) */
|
||||
String useYn;
|
||||
|
||||
/** 토큰 발급에 사용하는 구현체 클래스명 (어댑터 속성 ADAPTER_TOKEN_ISSUING_CLIENT_TYPE) */
|
||||
/**
|
||||
* 스케줄러가 토큰을 발급할 때 사용하는 구현체 클래스명.
|
||||
*
|
||||
* AccessTokenManagerByDB.issueToken() 이 그룹의 어댑터 중 getAdapters().next() 하나만 골라
|
||||
* 그 어댑터의 ADAPTER_TOKEN_ISSUING_CLIENT_TYPE 을 쓰므로 여기서도 같은 방식으로 조회한다.
|
||||
*/
|
||||
String tokenServiceClass;
|
||||
|
||||
/**
|
||||
* 그룹에 속한 어댑터별 ADAPTER_TOKEN_ISSUING_CLIENT_TYPE. (어댑터명 → 클래스명)
|
||||
*
|
||||
* 어댑터마다 값이 다르면 스케줄러가 쓰는 구현체와 거래 중 재발급(retryAccessTokenVO) 때
|
||||
* 쓰이는 구현체가 달라진다. 그 불일치를 확인하기 위한 항목이다.
|
||||
*/
|
||||
Map<String, String> adapterTokenServiceClasses;
|
||||
|
||||
/** 토큰 발급 URL */
|
||||
String tokenUrl;
|
||||
|
||||
|
||||
@@ -3,7 +3,10 @@ package com.eactive.eai.manage.oauthtoken;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -75,6 +78,7 @@ public class OAuthTokenStatusService {
|
||||
dto.setTokenUrl(credential.getUrl());
|
||||
dto.setIntervalSec(credential.getIntervalSec());
|
||||
dto.setTokenServiceClass(findTokenServiceClass(adapterGroupName));
|
||||
dto.setAdapterTokenServiceClasses(findAdapterTokenServiceClasses(adapterGroupName));
|
||||
|
||||
AccessTokenVO accessToken;
|
||||
try {
|
||||
@@ -113,6 +117,15 @@ public class OAuthTokenStatusService {
|
||||
dto.setClientId(oauth2Token.getClientId());
|
||||
}
|
||||
|
||||
// 만료시각이 없는 토큰은 isExpired() 가 false 라 재발급 대상이 되지 않는다.
|
||||
// 빈 토큰이 캐시에 들어가면 기동 후 계속 그대로 사용되므로 조회 시 눈에 띄게 알린다.
|
||||
if (StringUtils.isBlank(accessToken.getAccessToken())) {
|
||||
dto.setMessage("캐시에 빈 토큰이 있습니다. 발급에 실패했는데도 구현체가 빈 토큰을 반환한 것으로 보입니다."
|
||||
+ " 만료시각이 없어 자동 재발급되지 않습니다.");
|
||||
} else if (expiration == null) {
|
||||
dto.setMessage("만료시각이 없어 자동 재발급되지 않습니다.");
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
@@ -139,6 +152,37 @@ public class OAuthTokenStatusService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 그룹에 속한 어댑터별로 토큰 발급 구현체 클래스명을 모은다.
|
||||
*
|
||||
* 스케줄러(issueToken)는 getAdapters().next() 로 어댑터 하나만 골라 쓰고, 거래 중 재발급
|
||||
* (retryAccessTokenVO)은 호출한 어댑터 자신의 속성을 쓴다. 어댑터마다 설정이 다르면
|
||||
* 서로 다른 구현체가 동작하므로 전체를 보여준다.
|
||||
*
|
||||
* @param adapterGroupName 어댑터그룹명
|
||||
* @return 어댑터명 → 구현체 클래스명. 조회 실패 시 빈 Map.
|
||||
*/
|
||||
private Map<String, String> findAdapterTokenServiceClasses(String adapterGroupName) {
|
||||
Map<String, String> result = new LinkedHashMap<String, String>();
|
||||
try {
|
||||
AdapterGroupVO gvo = AdapterManager.getInstance().getAdapterGroupVO(adapterGroupName);
|
||||
if (gvo == null) {
|
||||
return result;
|
||||
}
|
||||
Iterator<AdapterVO> adapters = gvo.getAdapters();
|
||||
while (adapters.hasNext()) {
|
||||
AdapterVO avo = adapters.next();
|
||||
Properties properties = AdapterPropManager.getInstance().getProperties(avo.getPropGroupName());
|
||||
result.put(avo.getName(), properties.getProperty(PROP_TOKEN_SERVICE_CLASS));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (logger.isDebug()) {
|
||||
logger.debug("어댑터별 토큰 발급 구현체 조회 실패. adapterGroupName : " + adapterGroupName);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* accessToken 앞 8자만 남기고 마스킹한다.
|
||||
*
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.eactive.eai.manage.oauthtoken;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
|
||||
@@ -178,6 +179,36 @@ class OAuthTokenStatusServiceTest {
|
||||
assertFalse(dto.toString().contains("super-secret"), "clientSecret 이 응답에 포함되면 안 된다");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("8-1. 캐시에 빈 토큰이 있으면 경고 메시지를 담는다")
|
||||
void 빈토큰경고() {
|
||||
registerCredential(GROUP);
|
||||
// 기존 구현체는 발급에 실패해도 빈 OAuth2AccessTokenVO 를 반환하고, 그게 그대로 캐시된다.
|
||||
Mockito.when(mockManager.peekAccessTokenVO(GROUP)).thenReturn(new OAuth2AccessTokenVO());
|
||||
|
||||
OAuthTokenStatusDTO dto = service.getStatus(GROUP);
|
||||
|
||||
assertTrue(dto.isCached());
|
||||
assertFalse(dto.isExpired());
|
||||
assertEquals(0, dto.getAccessTokenLength());
|
||||
assertTrue(dto.getMessage().contains("빈 토큰"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("8-2. 만료시각이 없는 토큰은 재발급되지 않음을 알린다")
|
||||
void 만료시각없음경고() {
|
||||
registerCredential(GROUP);
|
||||
OAuth2AccessTokenVO vo = new OAuth2AccessTokenVO();
|
||||
vo.setAccessToken("abcdefghijkl");
|
||||
Mockito.when(mockManager.peekAccessTokenVO(GROUP)).thenReturn(vo);
|
||||
|
||||
OAuthTokenStatusDTO dto = service.getStatus(GROUP);
|
||||
|
||||
assertTrue(dto.isCached());
|
||||
assertNull(dto.getExpiration());
|
||||
assertTrue(dto.getMessage().contains("재발급"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("9. 전체 목록은 등록된 어댑터그룹 수만큼 반환한다")
|
||||
void 전체목록() {
|
||||
|
||||
Reference in New Issue
Block a user