APP 어댑터용 토큰생성 Proc

This commit is contained in:
Yunsam.Eo
2025-12-03 10:30:53 +09:00
parent e000fb03de
commit 7a4c601007
@@ -0,0 +1,477 @@
package com.eactive.eai.custom.adapter.app.impl;
import java.text.ParseException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
//import org.codehaus.jackson.map.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.TokenRequest;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import com.eactive.eai.adapter.app.BusinessApplication;
import com.eactive.eai.adapter.http.dynamic.filter.ApiAuthFilter;
import com.eactive.eai.adapter.http.dynamic.filter.JwtAuthException;
//import com.eactive.eai.adapter.http.dynamic.filter.JwtAuthFilter;
import com.eactive.eai.authserver.service.OAuth2Manager;
import com.eactive.eai.authserver.util.BeanUtils;
import com.eactive.eai.authserver.vo.ClientVO;
import com.eactive.eai.common.util.Logger;
//import com.nimbusds.jwt.SignedJWT;
/**
* JWT 토큰을 발급한다.(인증은 요청시스템에서 수행하고 토큰만 발급)
*
* @author
*
*/
public class JwtTokenCreator implements BusinessApplication {
public static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
private static final boolean VERYFY_CLIENT_SECRET = true;
private static final String[] GRANT_TYPES = { "client_credentials", "authorization_code", "password",
"refresh_token" };
@SuppressWarnings("unchecked")
@Override
public Object executeApplication(Properties prop, Object messageBytes, Properties tempProp) throws Exception {
// 응답전문용 Json Object
JSONObject resObject = new JSONObject();
try {
if (messageBytes == null) {
throw new Exception("Message is null.");
}
String message = new String((byte[]) messageBytes);
if (StringUtils.isBlank(message)) {
throw new Exception("Message is empty.");
}
/**
* {
* "grant_type":"client_credentials",
* "client_id":"WNHZOadBfB9UCPPuq6YArKUW87elXmZX",
* "client_secret":"JhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9",
* "scope":"manage",
* "expires_in":3600,
* "resource_ids":"aaa, bbb",
* "authorities":"ROLE_ADM, ROLE_DEV",
* "user_name":"aaaaaaaaaaaaaa",
* "support_refresh_token_yn": "Y",
* "refresh_token_expires_in":86400,
* "refresh_token":"JhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOj~~",
* "iss":"AZABBB0000",
* "aud":"ZZAAAA0000"
* }
*/
boolean isVerifyClientSecret = VERYFY_CLIENT_SECRET;
// 요청전문 Json Object
JSONObject jsonObject = (JSONObject) JSONValue.parse(message);
/* 2022.5.25. yseo
* 복합거래여부 확인, 복합거래의 경우 요청전문의 내용을 응답전문에 그대로 복사
* 복합거래 : 토큰발급 이후 2차 처리를 위한 Outbound Adapter를 다시 호출하는 거래
* 복합거래 대상 EAIServiceCD는 APP Adapter의 프로퍼티(SVC_CD)에 등록해서 관리.
*/
String svcCds = prop.getProperty("SVC_CD");
String[] svcCdArr = org.springframework.util.StringUtils.tokenizeToStringArray(svcCds, ",");
Boolean isComplex = ArrayUtils.contains(svcCdArr, tempProp.getProperty("EAISvcCd"))?true:false;
if(isComplex) {
resObject = jsonObject;
}
logger.debug("1. isComplex : [" + isComplex + "]");
String grantType = (String) jsonObject.get(OAuth2Utils.GRANT_TYPE);
if (!ArrayUtils.contains(GRANT_TYPES, grantType)) {
throw new JwtAuthException("unsupported_grant_type", "Unsupported grant type");
}
logger.debug("2. grantType : [" + grantType + "]");
String clientId = (String) jsonObject.get(OAuth2Utils.CLIENT_ID);
if (StringUtils.isBlank(clientId)) {
throw new JwtAuthException("invalid_client", "Bad client credentials(client_id is empty)");
/* clientId에 허용된 grantType인지 확인 2022.05.23 yseo*/
} else {
veryfyGrantType(clientId, grantType);
}
logger.debug("3. clientId : [" + clientId + "]");
/* grantType = "client_credentials" 이면 client_secret 체크 2022.05.23 yseo
* Mydata 관련해서는 무조건 체크해야함.
*/
// if (!StringUtils.equalsIgnoreCase(grantType, "client_credentials")) isVerifyClientSecret = false;
if (isVerifyClientSecret) {
String clientSecret = (String) jsonObject.get("client_secret");
if (StringUtils.isBlank(clientSecret)) {
throw new JwtAuthException("invalid_client", "Bad client credentials(client_secret is empty)");
}
veryfyClientSecret(clientId, clientSecret);
logger.debug("4. clientSecret : [" + clientSecret + "]");
}
Set<String> scopeSet = assignScope((String) jsonObject.get(OAuth2Utils.SCOPE));
if (scopeSet == null || scopeSet.size() == 0) {
if (!StringUtils.equals(grantType, "refresh_token")) {
throw new Exception("scope is empty.");
}
}
logger.debug("5. scopeSet : [" + scopeSet + "]");
Set<String> resourceIdSet = assignResourceIds((String) jsonObject.get("resource"));
Set<GrantedAuthority> authoritiesSet = assignAuthorities((String) jsonObject.get("authorities"));
String userName = (String) jsonObject.get("user_name");
if (StringUtils.equals(grantType, "password") || StringUtils.equals(grantType, "authorization_code")) {
if (StringUtils.isBlank(userName)) {
throw new Exception("user_name is empty.");
}
}
logger.debug("6. userName : [" + userName + "]");
/* 요청정보에 expires_in(토큰유효기간) 값이 없는 경우, client정보에 등록된 유효기간 찾아 대체 2022.05.23 yseo*/
String expIn = String.valueOf(jsonObject.get(OAuth2AccessToken.EXPIRES_IN));
Long expiresIn = null;
if (StringUtils.isNumeric(expIn)) {
expiresIn = Long.parseLong(expIn);
} else if (StringUtils.isBlank(expIn) || StringUtils.equalsIgnoreCase("null", expIn)) {
expiresIn = assignDefaultExpiresIn(clientId, "expires_in");
} else {
throw new Exception("expires_in is not numeric.");
}
logger.debug("7. expiresIn : [" + expIn + "]");
// Long expiresIn = (Long) jsonObject.get(OAuth2AccessToken.EXPIRES_IN);
// if (expiresIn == null) {
// expiresIn = assignDefaultExpiresIn(clientId, "expires_in");
// }
boolean supportRefreshToken = BooleanUtils.toBoolean((String) jsonObject.getOrDefault("support_refresh_token_yn", "N"));
/* 요청정보에 refresh_token_expires_in(리프레시토큰유효기간) 값이 없는 경우, client정보에 등록된 유효기간 찾아 대체 2022.05.23 yseo*/
String refreshExpIn = String.valueOf(jsonObject.get("refresh_token_expires_in"));
Long refreshTokenExpiresIn = null;
if (supportRefreshToken && StringUtils.isNumeric(refreshExpIn)) {
refreshTokenExpiresIn = Long.parseLong(refreshExpIn);
} else if (supportRefreshToken && (StringUtils.isBlank(refreshExpIn) || StringUtils.equalsIgnoreCase("null", refreshExpIn))) {
refreshTokenExpiresIn = assignDefaultExpiresIn(clientId, "refresh_token_expires_in");
} else if (supportRefreshToken) {
throw new Exception("refresh_token_expires_in is not numeric.");
}
logger.debug("8. refreshTokenExpiresIn : [" + refreshExpIn + "]");
// Long refreshTokenExpiresIn = (Long) jsonObject.get("refresh_token_expires_in");
// if (supportRefreshToken && refreshTokenExpiresIn == null) {
// refreshTokenExpiresIn = assignDefaultExpiresIn(clientId, "refresh_token_expires_in");
// }
String refreshToken = (String) jsonObject.get("refresh_token");
if (StringUtils.equals(grantType, "refresh_token") && StringUtils.isBlank(refreshToken)) {
throw new JwtAuthException("invalid_token", "refresh_token is empty.");
}
logger.debug("9. refreshToken : [" + refreshToken + "]");
String iss = (String) jsonObject.get("iss");
// if (StringUtils.isBlank(iss)) {
// iss = assignDefaultStringValue(clientId, "iss");
// }
// logger.debug("10. iss : [" + iss + "]");
//
String aud = (String) jsonObject.get("aud");
// if (StringUtils.isBlank(aud)) {
// aud = assignDefaultStringValue(clientId, "aud");
// }
// logger.debug("11. aud : [" + aud + "]");
String tokenStr = createToken(grantType, clientId, scopeSet, resourceIdSet, authoritiesSet, userName, expiresIn,
supportRefreshToken, refreshTokenExpiresIn, refreshToken, iss, aud);
// logger.debug("#####created tokenStr==>"+tokenStr);
//20211122 bearer -> Bearer로 변환철. mydata api준수
JSONObject jsonObj = (JSONObject) JSONValue.parse(tokenStr);
String tokenType = (String)jsonObj.get("token_type");
if(StringUtils.isNotBlank(tokenType) && StringUtils.equalsIgnoreCase(tokenType, "bearer")) {
jsonObj.put("token_type","Bearer");
}
jsonObj.remove("jti");
jsonObj.put("resource", (String) jsonObject.get("resource"));
if (StringUtils.equals(grantType, "password") || StringUtils.equals(grantType, "authorization_code")) {
jsonObj.put("refresh_token_expires_in", refreshTokenExpiresIn-1);
}
tokenStr = jsonObj.toJSONString();
logger.debug("##### Bearer checked tokenStr==>"+tokenStr);
// 복합거래의 경우 발급된 토큰정보를 "TOKEN_DATAGROUP" 그룹으로 추가
if(isComplex) {
resObject.put("TOKEN_DATAGROUP", jsonObj);
} else {
resObject.putAll(jsonObj);
}
String resStr = resObject.toJSONString();
return resStr.getBytes();
} catch (JwtAuthException e) {
logger.error(e);
JSONObject errorJson = new JSONObject();
errorJson.put("error", e.getCode());
errorJson.put("error_description", e.getMessage());
resObject.putAll(errorJson);
return resObject.toJSONString().getBytes();
} catch (Exception e) {
logger.error(e);
JSONObject errorJson = new JSONObject();
errorJson.put("error", "invalid_request");
errorJson.put("error_description", e.getMessage());
resObject.putAll(errorJson);
return resObject.toJSONString().getBytes();
}
}
private Set<String> assignResourceIds(String resourceIds) throws Exception {
if (StringUtils.isBlank(resourceIds)) {
return null;
}
String[] arr = org.springframework.util.StringUtils.tokenizeToStringArray(resourceIds, ",");
Set<String> resourceIdSet = new HashSet<String>();
for (String resourceId : arr) {
resourceIdSet.add(resourceId);
}
return resourceIdSet;
}
private void veryfyGrantType(String clientId, String grantType) throws JwtAuthException {
ClientDetails details = OAuth2Manager.getInstance().getClientDeatilsStore().get(clientId);
if (details == null) {
throw new JwtAuthException("invalid_client", "Bad client credentials(not found)");
}
if (!details.getAuthorizedGrantTypes().contains(grantType)) {
throw new JwtAuthException("unsupported_grant_type", "Unsupported grant type for ClientID");
}
}
private void veryfyClientSecret(String clientId, String clientSecret) throws JwtAuthException {
ClientDetails details = OAuth2Manager.getInstance().getClientDeatilsStore().get(clientId);
if (details == null) {
throw new JwtAuthException("invalid_client", "Bad client credentials(not found)");
}
if (!StringUtils.equals(details.getClientSecret(), clientSecret)) {
throw new JwtAuthException("invalid_client", "Bad client credentials");
}
}
private Long assignDefaultExpiresIn(String clientId, String flag) throws JwtAuthException {
ClientDetails details = OAuth2Manager.getInstance().getClientDeatilsStore().get(clientId);
Long retLong = null;
if (details == null) {
throw new JwtAuthException("invalid_client", "Bad client credentials(not found)");
}
if (StringUtils.equals(flag, "expires_in") && StringUtils.isNotBlank(details.getAccessTokenValiditySeconds().toString())) {
retLong = new Long(details.getAccessTokenValiditySeconds());
} else if (StringUtils.equals(flag, "refresh_token_expires_in") && StringUtils.isNotBlank(details.getRefreshTokenValiditySeconds().toString())) {
retLong = new Long(details.getRefreshTokenValiditySeconds());
} else {
throw new JwtAuthException("invalid_client", "Bad expires_in/refresh_token_expires_in(not found)");
}
return retLong;
}
private String assignDefaultStringValue(String clientId, String flag) throws Exception {
ClientVO client = (ClientVO) OAuth2Manager.getInstance().getClientDeatilsStore().get(clientId);
String retStr = "";
if (client == null) {
throw new JwtAuthException("invalid_client", "Bad client credentials(not found)");
}
if (StringUtils.equals(flag, "iss") && StringUtils.isNotBlank(client.getIssuer())) {
retStr = client.getIssuer();
} else if (StringUtils.equals(flag, "aud") && StringUtils.isNotBlank(client.getAudience())) {
retStr = client.getAudience();
} else {
throw new Exception("iss/aud is null.");
}
logger.info("===================>"+flag+" : ["+retStr+"]");
return retStr;
}
private Set<String> assignScope(String scopes) throws Exception {
if (StringUtils.isBlank(scopes)) {
return new HashSet<String>();
}
String[] arr = org.springframework.util.StringUtils.tokenizeToStringArray(scopes, " ");
Set<String> scopeSet = new HashSet<String>();
for (String scope : arr) {
scopeSet.add(scope);
}
return scopeSet;
}
private Set<GrantedAuthority> assignAuthorities(String authorities) throws Exception {
if (StringUtils.isBlank(authorities)) {
return new HashSet<GrantedAuthority>();
}
String[] arr = org.springframework.util.StringUtils.tokenizeToStringArray(authorities, ",");
Set<GrantedAuthority> authoritiesSet = new HashSet<GrantedAuthority>();
for (String authority : arr) {
authoritiesSet.add(new SimpleGrantedAuthority(authority));
}
return authoritiesSet;
}
private String createToken(String grantType, String clientId, Set<String> scopeSet, Set<String> resourceIdSet,
Set<GrantedAuthority> authoritiesSet, String userName, Long expiresIn, boolean supportRefreshToken,
Long refreshTokenExpiresIn, String refreshToken, String issuer, String audience) throws Exception {
HashMap<String, String> authorizationParameters = new HashMap<String, String>();
authorizationParameters.put(OAuth2Utils.GRANT_TYPE, grantType);
authorizationParameters.put(OAuth2Utils.CLIENT_ID, clientId);
// authorizationParameters.put("iss", issuer);
// authorizationParameters.put("aud", audience);
if (StringUtils.equals(grantType, "password") || StringUtils.equals(grantType, "authorization_code")) {
authorizationParameters.put("user_name", userName);
}
Set<String> responseType = new HashSet<String>();
responseType.add(grantType);
OAuth2Request authorizationRequest = new OAuth2Request(authorizationParameters, clientId, authoritiesSet, true,
scopeSet, resourceIdSet, "", responseType, null);
Authentication authentication = null;
if (StringUtils.equals(grantType, "password") || StringUtils.equals(grantType, "authorization_code")) {
User userPrincipal = new User(userName, "", true, true, true, true, authoritiesSet);
authentication = new UsernamePasswordAuthenticationToken(userPrincipal, null, authoritiesSet);
}
OAuth2Authentication authenticationRequest = new OAuth2Authentication(authorizationRequest, authentication);
authenticationRequest.setAuthenticated(true);
DefaultTokenServices tokenServices = createDefaultTokenServices(supportRefreshToken, expiresIn,
refreshTokenExpiresIn);
OAuth2AccessToken accessToken = null;
if (StringUtils.equals(grantType, "refresh_token")) {
tokenServices.setReuseRefreshToken(true);
TokenRequest tokenRequest = new TokenRequest(authorizationParameters, clientId, scopeSet, grantType);
accessToken = tokenServices.refreshAccessToken(refreshToken, tokenRequest);
} else {
accessToken = tokenServices.createAccessToken(authenticationRequest);
}
logger.debug("accessToken=" + accessToken.toString());
return new ObjectMapper().writeValueAsString(accessToken);
}
private DefaultTokenServices createDefaultTokenServices(boolean supportRefreshToken, Long expiresIn,
Long refreshTokenExpiresIn) throws Exception {
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter()));
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore());
tokenServices.setSupportRefreshToken(supportRefreshToken);
tokenServices.setTokenEnhancer(tokenEnhancerChain);
if (expiresIn != null) {
tokenServices.setAccessTokenValiditySeconds(expiresIn.intValue());
}
if (supportRefreshToken && refreshTokenExpiresIn != null) {
tokenServices.setRefreshTokenValiditySeconds(refreshTokenExpiresIn.intValue());
}
return tokenServices;
}
private TokenEnhancer tokenEnhancer() {
// return BeanUtils.getBean("tokenEnhancer", TokenEnhancer.class);
return (TokenEnhancer) accessTokenConverter();
}
private JwtAccessTokenConverter accessTokenConverter() {
return BeanUtils.getBean("jwtAccessTokenConverter", JwtAccessTokenConverter.class);
}
private TokenStore tokenStore() {
return new JwtTokenStore((JwtAccessTokenConverter) accessTokenConverter());
}
public static void main(String args[]){
// String token = "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImRlZmF1bHRfc3NsX2tleSJ9.ew0KICAiaXNzIjogIkExQUFFUjAwMDAiLA0KICAiYXVkIjoiWlZBQUVNMDAwMCIsDQogICJqdGkiOiJlYmI4NmUyMi03YzZmLTQzZDItOTZiMy05NjU0MTAyZTE1M2MiLA0KICAiZXhwIjoiMTYzNjk2ODcwOSIsDQogICJzY29wZSI6ImJhbmsubGlzdCINCn0.nF0JeCHJHn7yBzhjEnge_Eqi0aAeD_WTt0iUB2V2VPJV9zWgMW-Npr3fCXlmYP5HoTjeQES5ftrxWLlLMaxRPHDKWwafgwLm3eQt9r_x_j0PRn-KpoZ9xTWy3oKCQvP0DN0IQepLZfM214nCrjdSPCV17oUS03cBW0lIDmXeROSR2auAMZvkSQqF74E_QLEKF3XLk0MM3Jz4nZp1bBj3PfJyCxjy2ibp12TN0vHccGmSItqANsbeVn0sQybdIraNzb9bptLwWe8WYyn3XugEA9-bavPOSPwrGgLENBnHnzWj1L8yS0rXuEjydCwf6HMAbpNVHQpicM0Q3xdl5W1PBA";
// String[] components = token.split("\\s");
//String r "refresh_token_expires_in":"604800","refresh_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImRlZmF1bHRfc3NsX2tleSJ9.ew0KICAiaXNzIjogIkExQUFFUjAwMDAiLA0KICAiYXVkIjoiWlZBQUVNMDAwMCIsDQogICJqdGkiOiIwMzI5Y2M3Zi04Y2U2LTQxNzQtYTc5Ny1mMWRjNjg1ZmM5NDAiLA0KICAiZXhwIjoiMTYzNjk2ODcwOSINCn0.dQx6kWm1JCEgueZjUsQJYNDBu2i4P1-jVLKgUH6aX2aBFunlUBtk_zMMFIJb3OvQpz8qPc9xhs1MkM2YHdpJlNleHY3GhhjiQMfYeiCU9yOzv-zuyvOY1pCO0McmHJNdFcxoQfHHFNm4yFay3dOAFE0Z3FQ74nwxrgnzKSucrHCKyGz0pHdLWnWxHNrJMZ4NmaSyPRxU3qxdWFe1soxqgTqpW_SQkTl3D5SWXgevc6zihPPpFhCSOJ39RrJlIVSH1IY5NRAm71AoaZ6ooLsLvPNED3Z7rG-g9coKEU_DASeCNslRZrP0D3azqswFeu-np3zFZUTrgP_TNT6FFReEnA";
try {
JwtTokenCreator jtc = new JwtTokenCreator();
// String me="\"d\"";
String message= "{\"refresh_token_expires_in\":\"86400\",\"refresh_token\":null,\"grant_type\":\"authorization_code\",\"support_refresh_token_in\":\"Y\",\"user_name\":\"aaa\",\"scope\":\"bank.list\",\"expires_in\":\"3600\",\"client_id\":\"ZZAAAAPacQmv3ZVhtPISDSA9jb9AWjak\"}";
JSONObject jsonObject = (JSONObject) JSONValue.parse(message);
String grantType = (String) jsonObject.get(OAuth2Utils.GRANT_TYPE);
String clientId = (String) jsonObject.get(OAuth2Utils.CLIENT_ID);
// String clientSecret = (String) jsonObject.get("client_secret");
Set<String> scopeSet;
Properties prop = null;
byte[] msgBytes = null;
msgBytes = message.getBytes();
jtc.executeApplication(prop, msgBytes, prop);
// scopeSet = jtc.assignScope((String) jsonObject.get(OAuth2Utils.SCOPE));
//
//
// Set<String> resourceIdSet = jtc.assignResourceIds((String) jsonObject.get("resource_ids"));
// Set<GrantedAuthority> authoritiesSet = jtc.assignAuthorities((String) jsonObject.get("authorities"));
//
// String userName = (String) jsonObject.get("user_name");
//
//
// Long expiresIn = Long.parseLong(jsonObject.get(OAuth2AccessToken.EXPIRES_IN).toString());
// Long refreshTokenExpiresIn = Long.parseLong(jsonObject.get("refresh_token_expires_in").toString());
//// Long expiresIn = (Long) jsonObject.get(OAuth2AccessToken.EXPIRES_IN);
//// Long refreshTokenExpiresIn = (Long) jsonObject.get("refresh_token_expires_in");
// boolean supportRefreshToken = BooleanUtils
// .toBoolean((String) jsonObject.getOrDefault("support_refresh_token_yn", "Y"));
//
// String refreshToken = (String) jsonObject.get("refresh_token");
//
// jtc.createToken( grantType, clientId, scopeSet, resourceIdSet,authoritiesSet, userName, expiresIn, supportRefreshToken,
// refreshTokenExpiresIn, refreshToken);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}