package com.eactive.eai.authserver.custom; import java.time.LocalDateTime; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; import org.json.simple.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.security.oauth2.provider.ClientDetails; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import com.eactive.eai.adapter.http.dynamic.filter.JwtAuthException; import com.eactive.eai.authserver.config.RequestContextData; import com.eactive.eai.authserver.dao.TokenIssuanceLogDAO; import com.eactive.eai.authserver.service.BearerTokenService; import com.eactive.eai.authserver.service.OAuth2Manager; import com.eactive.eai.authserver.vo.ClientVO; import com.eactive.eai.common.logger.EAIDBLogControl; import com.eactive.eai.common.util.Logger; import com.eactive.eai.common.util.MessageUtil; import com.eactive.eai.data.entity.onl.authserver.TokenIssuanceLog; @RestController @RequestMapping("/auth/oauth/v2") public class BearerTokenController { public static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT); private final BearerTokenService tokenService; @Autowired private TokenIssuanceLogDAO tokenIssuanceLogDAO; public BearerTokenController(BearerTokenService tokenService) { this.tokenService = tokenService; } @RequestMapping( value = "/token", method = {RequestMethod.POST, RequestMethod.GET} ) public ResponseEntity issueCAToken(HttpServletRequest request, @RequestParam MultiValueMap req) throws JwtAuthException { JSONObject resObject = new JSONObject(); String clientId = req.getFirst("client_id"); String grantType = req.getFirst("grant_type"); String clientSecret = req.getFirst("client_secret"); String scopes = req.getFirst("scope"); try { RequestContextData data = new RequestContextData(); data.setClientId(request.getParameter("client_id")); data.setIpAddress(extractIpAddress(request)); data.setGrantType(request.getParameter("grant_type")); data.setScope(request.getParameter("scope")); data.setUsername(request.getParameter("username")); data.setResource(request.getParameter("resource")); RequestContextData.ThreadLocalRequestContext.set(data); if (!StringUtils.equals(grantType, "client_credentials") ) { throw new JwtAuthException("unsupported_grant_type", "Unsupported grant type"); } ClientDetails clientDetails = OAuth2Manager.getInstance().getClientDeatilsStore().get(clientId); if (clientDetails == null) { throw new JwtAuthException("invalid_client", "Bad client credentials(not found)"); } String tokenType = "Bearer"; Long expiresIn = Long.valueOf(clientDetails.getAccessTokenValiditySeconds()); String[] reqScopeArr = org.springframework.util.StringUtils.tokenizeToStringArray(scopes, " "); Set scopeSet = new HashSet(); for (String scope : reqScopeArr) { scopeSet.add(scope); } veryfyClient(clientDetails, clientSecret, scopeSet); String token = tokenService.generateCAToken(clientId, expiresIn, scopeSet); Map tokenMap = new HashMap<>(); tokenMap.put("token_type", tokenType); tokenMap.put("access_token", token); tokenMap.put("expires_in", expiresIn); tokenMap.put("scope", scopes); // ... and so on for all key-value pairs resObject.putAll(tokenMap); logTokenIssuance(true,false, resObject.toJSONString(), token); return ResponseEntity.ok(resObject); } catch (JwtAuthException e) { logger.error("Token request[/auth/oauth/v2/token] => clientId: {}, grantType: {}, scope: {}", clientId, grantType, scopes); logger.error(e); String errorJson = MessageUtil.makeJsonErrorMessage(MessageUtil.ERROR_CODE_AUTH_FAIL, e.getMessage()); logTokenIssuance(false ,false, e.getMessage(), null); return ResponseEntity.status(401).body(errorJson); } catch (Exception e) { logger.error("Token request[/auth/oauth/v2/token] => clientId: {}, grantType: {}, scope: {}", clientId, grantType, scopes); logger.error(e); String errorJson = MessageUtil.makeJsonErrorMessage(MessageUtil.ERROR_CODE_AP_ERROR, e.getMessage()); logTokenIssuance(false ,false, e.getMessage(), null); return ResponseEntity.status(500).body(errorJson); }finally { RequestContextData.ThreadLocalRequestContext.clear(); } } private String extractIpAddress(HttpServletRequest request) { String ipAddress = request.getHeader("X-Forwarded-For"); if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("WL-Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("HTTP_CLIENT_IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getRemoteAddr(); } return ipAddress; } private void logTokenIssuance(boolean isSuccess, boolean isRestrictionExempt, String resultMessage, String accessToken) { try { if (!EAIDBLogControl.isEnable()) { logger.warn("DB logging is disabled. Skipping token issuance logging."); return; } RequestContextData data = RequestContextData.ThreadLocalRequestContext.get(); OAuth2Manager.getInstance(); TokenIssuanceLog log = new TokenIssuanceLog(); String clientId = data.getClientId(); log.setClientId(clientId); if(StringUtils.isNotBlank(clientId)) { ClientVO clientVO = OAuth2Manager.getInstance().getClientInfo(clientId); log.setAppName(clientVO.getClientName()); log.setOrgId(clientVO.getOrgId()); log.setOrgName(clientVO.getOrgName()); } log.setGrantType(data.getGrantType()); log.setScope(data.getScope()); log.setIpAddress(data.getIpAddress()); log.setSuccessYn(isSuccess ? "Y" : "N"); log.setIssuanceDateTime(LocalDateTime.now()); log.setRestrictionExemptYn(isRestrictionExempt ? "Y" : "N"); log.setResultMessage(resultMessage); log.setAccessToken(accessToken); // Add access token value to the log tokenIssuanceLogDAO.saveTokenIssuanceLog(log); } catch (Throwable th) { logger.error("Error while logging token issuance: " + th.getMessage(), th); } } private void veryfyClient(ClientDetails clientDetails, String clientSecret, Set scopeSet) throws JwtAuthException { if (!StringUtils.equals(clientDetails.getClientSecret(), clientSecret)) { throw new JwtAuthException("invalid_client", "Bad client credentials(client_secret is empty or not match)"); } if (scopeSet.isEmpty()) { throw new JwtAuthException("invalid_client", "Bad client credentials(Scope is empty)"); } if (!clientDetails.getScope().containsAll(scopeSet)) { throw new JwtAuthException("invalid_client", "Bad client credentials(Include unacceptable scope)"); } } }