mirror of
https://repository.entgra.net/community/device-mgt-core.git
synced 2025-10-06 02:01:45 +00:00
Merge branch 'master' into 'master'
Login cache improvements and Refresh token handling improvements See merge request entgra/carbon-device-mgt!789
This commit is contained in:
commit
76deadcf41
@ -32,6 +32,7 @@ public class UIConfiguration {
|
||||
private List<String> scopes;
|
||||
private boolean isSsoEnable;
|
||||
private int sessionTimeOut;
|
||||
private int loginCacheCapacity;
|
||||
|
||||
@XmlElement(name = "AppRegistration", required=true)
|
||||
public AppRegistration getAppRegistration() {
|
||||
@ -69,4 +70,13 @@ public class UIConfiguration {
|
||||
public void setSessionTimeOut(int sessionTimeOut) {
|
||||
this.sessionTimeOut = sessionTimeOut;
|
||||
}
|
||||
|
||||
@XmlElement(name = "LoginCacheCapacity")
|
||||
public int getLoginCacheCapacity() {
|
||||
return loginCacheCapacity;
|
||||
}
|
||||
|
||||
public void setLoginCacheCapacity(int loginCacheCapacity) {
|
||||
this.loginCacheCapacity = loginCacheCapacity;
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,9 +18,6 @@
|
||||
|
||||
package io.entgra.ui.request.interceptor;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import io.entgra.ui.request.interceptor.beans.AuthData;
|
||||
import io.entgra.ui.request.interceptor.util.HandlerConstants;
|
||||
import io.entgra.ui.request.interceptor.util.HandlerUtil;
|
||||
@ -43,7 +40,6 @@ import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.cookie.SM;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.InputStreamEntity;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.entity.mime.HttpMultipartMode;
|
||||
import org.apache.http.entity.mime.MultipartEntityBuilder;
|
||||
import org.apache.http.entity.mime.content.InputStreamBody;
|
||||
@ -84,7 +80,7 @@ public class InvokerHandler extends HttpServlet {
|
||||
ProxyResponse proxyResponse = HandlerUtil.execute(postRequest);
|
||||
|
||||
if (HandlerConstants.TOKEN_IS_EXPIRED.equals(proxyResponse.getExecutorResponse())) {
|
||||
proxyResponse = retryRequestWithRefreshedToken(req, resp, postRequest);
|
||||
proxyResponse = HandlerUtil.retryRequestWithRefreshedToken(req, resp, postRequest, apiEndpoint);
|
||||
if (proxyResponse == null) {
|
||||
return;
|
||||
}
|
||||
@ -112,15 +108,19 @@ public class InvokerHandler extends HttpServlet {
|
||||
getRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER + authData.getAccessToken());
|
||||
ProxyResponse proxyResponse = HandlerUtil.execute(getRequest);
|
||||
if (HandlerConstants.TOKEN_IS_EXPIRED.equals(proxyResponse.getExecutorResponse())) {
|
||||
proxyResponse = retryRequestWithRefreshedToken(req, resp, getRequest);
|
||||
proxyResponse = HandlerUtil.retryRequestWithRefreshedToken(req, resp, getRequest, apiEndpoint);
|
||||
if (proxyResponse == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (proxyResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
|
||||
log.error("Error occurred while invoking the GET API endpoint.");
|
||||
HandlerUtil.handleError(resp, proxyResponse);
|
||||
return;
|
||||
if (proxyResponse.getCode() == HttpStatus.SC_UNAUTHORIZED) {
|
||||
proxyResponse = HandlerUtil.retryRequestWithRefreshedToken(req, resp, getRequest, apiEndpoint);
|
||||
} else {
|
||||
log.error("Error occurred while invoking the GET API endpoint.");
|
||||
HandlerUtil.handleError(resp, proxyResponse);
|
||||
return;
|
||||
}
|
||||
}
|
||||
HandlerUtil.handleSuccess(resp, proxyResponse);
|
||||
}
|
||||
@ -138,7 +138,7 @@ public class InvokerHandler extends HttpServlet {
|
||||
headRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER + authData.getAccessToken());
|
||||
ProxyResponse proxyResponse = HandlerUtil.execute(headRequest);
|
||||
if (HandlerConstants.TOKEN_IS_EXPIRED.equals(proxyResponse.getExecutorResponse())) {
|
||||
proxyResponse = retryRequestWithRefreshedToken(req, resp, headRequest);
|
||||
proxyResponse = HandlerUtil.retryRequestWithRefreshedToken(req, resp, headRequest, apiEndpoint);
|
||||
if (proxyResponse == null) {
|
||||
return;
|
||||
}
|
||||
@ -165,7 +165,7 @@ public class InvokerHandler extends HttpServlet {
|
||||
ProxyResponse proxyResponse = HandlerUtil.execute(putRequest);
|
||||
|
||||
if (HandlerConstants.TOKEN_IS_EXPIRED.equals(proxyResponse.getExecutorResponse())) {
|
||||
proxyResponse = retryRequestWithRefreshedToken(req, resp, putRequest);
|
||||
proxyResponse = HandlerUtil.retryRequestWithRefreshedToken(req, resp, putRequest, apiEndpoint);
|
||||
if (proxyResponse == null) {
|
||||
return;
|
||||
}
|
||||
@ -193,7 +193,7 @@ public class InvokerHandler extends HttpServlet {
|
||||
deleteRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER + authData.getAccessToken());
|
||||
ProxyResponse proxyResponse = HandlerUtil.execute(deleteRequest);
|
||||
if (HandlerConstants.TOKEN_IS_EXPIRED.equals(proxyResponse.getExecutorResponse())) {
|
||||
proxyResponse = retryRequestWithRefreshedToken(req, resp, deleteRequest);
|
||||
proxyResponse = HandlerUtil.retryRequestWithRefreshedToken(req, resp, deleteRequest, apiEndpoint);
|
||||
if (proxyResponse == null) {
|
||||
return;
|
||||
}
|
||||
@ -304,7 +304,7 @@ public class InvokerHandler extends HttpServlet {
|
||||
apiEndpoint = System.getProperty("iot.reporting.webapp.host");
|
||||
if (StringUtils.isBlank(apiEndpoint)){
|
||||
log.error("Reporting Endpoint is not defined in the iot-server.sh properly.");
|
||||
handleError(resp, HttpStatus.SC_INTERNAL_SERVER_ERROR);
|
||||
HandlerUtil.handleError(resp, HttpStatus.SC_INTERNAL_SERVER_ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -312,125 +312,22 @@ public class InvokerHandler extends HttpServlet {
|
||||
HttpSession session = req.getSession(false);
|
||||
if (session == null) {
|
||||
log.error("Unauthorized, You are not logged in. Please log in to the portal");
|
||||
handleError(resp, HttpStatus.SC_UNAUTHORIZED);
|
||||
HandlerUtil.handleError(resp, HttpStatus.SC_UNAUTHORIZED);
|
||||
return false;
|
||||
}
|
||||
|
||||
authData = (AuthData) session.getAttribute(HandlerConstants.SESSION_AUTH_DATA_KEY);
|
||||
if (authData == null) {
|
||||
log.error("Unauthorized, Access token not found in the current session");
|
||||
handleError(resp, HttpStatus.SC_UNAUTHORIZED);
|
||||
HandlerUtil.handleError(resp, HttpStatus.SC_UNAUTHORIZED);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (req.getMethod() == null) {
|
||||
log.error("Bad Request, Request method is empty");
|
||||
handleError(resp, HttpStatus.SC_BAD_REQUEST);
|
||||
HandlerUtil.handleError(resp, HttpStatus.SC_BAD_REQUEST);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retry request again after refreshing the access token
|
||||
*
|
||||
* @param req incoming {@link HttpServletRequest}
|
||||
* @param resp resp {@link HttpServletResponse}
|
||||
* @param httpRequest subclass of {@link HttpRequestBase} related to the current request.
|
||||
* @return {@link ProxyResponse} if successful and <code>null</code> if failed.
|
||||
* @throws IOException If an error occurs when try to retry the request.
|
||||
*/
|
||||
private ProxyResponse retryRequestWithRefreshedToken(HttpServletRequest req, HttpServletResponse resp,
|
||||
HttpRequestBase httpRequest) throws IOException {
|
||||
if (refreshToken(req, resp)) {
|
||||
httpRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER + authData.getAccessToken());
|
||||
ProxyResponse proxyResponse = HandlerUtil.execute(httpRequest);
|
||||
if (proxyResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
|
||||
log.error("Error occurred while invoking the API after refreshing the token.");
|
||||
HandlerUtil.handleError(resp, proxyResponse);
|
||||
return null;
|
||||
}
|
||||
return proxyResponse;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/***
|
||||
* This method is responsible to get the refresh token
|
||||
*
|
||||
* @param req {@link HttpServletRequest}
|
||||
* @param resp {@link HttpServletResponse}
|
||||
* @return If successfully renew tokens, returns TRUE otherwise return FALSE
|
||||
* @throws IOException If an error occurs while witting error response to client side or invoke token renewal API
|
||||
*/
|
||||
private static boolean refreshToken(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws IOException {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("refreshing the token");
|
||||
}
|
||||
HttpPost tokenEndpoint = new HttpPost(
|
||||
apiEndpoint + HandlerConstants.TOKEN_ENDPOINT);
|
||||
HttpSession session = req.getSession(false);
|
||||
if (session == null) {
|
||||
log.error("Couldn't find a session, hence it is required to login and proceed.");
|
||||
handleError(resp, HttpStatus.SC_UNAUTHORIZED);
|
||||
return false;
|
||||
}
|
||||
|
||||
StringEntity tokenEndpointPayload = new StringEntity(
|
||||
"grant_type=refresh_token&refresh_token=" + authData.getRefreshToken() + "&scope=PRODUCTION",
|
||||
ContentType.APPLICATION_FORM_URLENCODED);
|
||||
|
||||
tokenEndpoint.setEntity(tokenEndpointPayload);
|
||||
String encodedClientApp = authData.getEncodedClientApp();
|
||||
tokenEndpoint.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BASIC +
|
||||
encodedClientApp);
|
||||
tokenEndpoint.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.toString());
|
||||
|
||||
ProxyResponse tokenResultResponse = HandlerUtil.execute(tokenEndpoint);
|
||||
if (tokenResultResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
|
||||
log.error("Error occurred while refreshing access token.");
|
||||
HandlerUtil.handleError(resp, tokenResultResponse);
|
||||
return false;
|
||||
}
|
||||
|
||||
JsonParser jsonParser = new JsonParser();
|
||||
JsonElement jTokenResult = jsonParser.parse(tokenResultResponse.getData());
|
||||
|
||||
if (jTokenResult.isJsonObject()) {
|
||||
JsonObject jTokenResultAsJsonObject = jTokenResult.getAsJsonObject();
|
||||
AuthData newAuthData = new AuthData();
|
||||
|
||||
newAuthData.setAccessToken(jTokenResultAsJsonObject.get("access_token").getAsString());
|
||||
newAuthData.setRefreshToken(jTokenResultAsJsonObject.get("refresh_token").getAsString());
|
||||
newAuthData.setScope(jTokenResultAsJsonObject.get("scope").getAsString());
|
||||
newAuthData.setClientId(authData.getClientId());
|
||||
newAuthData.setClientSecret(authData.getClientSecret());
|
||||
newAuthData.setEncodedClientApp(authData.getEncodedClientApp());
|
||||
newAuthData.setUsername(authData.getUsername());
|
||||
authData = newAuthData;
|
||||
session.setAttribute(HandlerConstants.SESSION_AUTH_DATA_KEY, newAuthData);
|
||||
return true;
|
||||
}
|
||||
|
||||
log.error("Error Occurred in token renewal process.");
|
||||
handleError(resp, HttpStatus.SC_INTERNAL_SERVER_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle error requests
|
||||
*
|
||||
* @param resp {@link HttpServletResponse}
|
||||
* @param errorCode HTTP error status code
|
||||
* @throws IOException If error occurred when trying to send the error response.
|
||||
*/
|
||||
private static void handleError(HttpServletResponse resp, int errorCode)
|
||||
throws IOException {
|
||||
ProxyResponse proxyResponse = new ProxyResponse();
|
||||
proxyResponse.setCode(errorCode);
|
||||
proxyResponse.setExecutorResponse(
|
||||
HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + HandlerUtil.getStatusKey(errorCode));
|
||||
HandlerUtil.handleError(resp, proxyResponse);
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import io.entgra.ui.request.interceptor.beans.AuthData;
|
||||
import io.entgra.ui.request.interceptor.cache.LoginCacheManager;
|
||||
import io.entgra.ui.request.interceptor.cache.LoginCache;
|
||||
import io.entgra.ui.request.interceptor.cache.OAuthApp;
|
||||
import io.entgra.ui.request.interceptor.cache.OAuthAppCacheKey;
|
||||
import io.entgra.ui.request.interceptor.exceptions.LoginException;
|
||||
@ -39,7 +39,6 @@ import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.protocol.HTTP;
|
||||
import io.entgra.ui.request.interceptor.beans.ProxyResponse;
|
||||
import org.json.JSONString;
|
||||
|
||||
import javax.servlet.annotation.MultipartConfig;
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
@ -80,10 +79,9 @@ public class LoginHandler extends HttpServlet {
|
||||
httpSession.setMaxInactiveInterval(sessionTimeOut);
|
||||
|
||||
// Check if OAuth app cache exists. If not create a new application.
|
||||
LoginCacheManager loginCacheManager = new LoginCacheManager();
|
||||
loginCacheManager.initializeCacheManager();
|
||||
LoginCache loginCache = HandlerUtil.getLoginCache(httpSession);
|
||||
OAuthAppCacheKey oAuthAppCacheKey = new OAuthAppCacheKey(HandlerConstants.PUBLISHER_APPLICATION_NAME, username);
|
||||
OAuthApp oAuthApp = loginCacheManager.getOAuthAppCache(oAuthAppCacheKey);
|
||||
OAuthApp oAuthApp = loginCache.getOAuthAppCache(oAuthAppCacheKey);
|
||||
|
||||
if (oAuthApp == null) {
|
||||
HttpPost apiRegEndpoint = new HttpPost(gatewayUrl + HandlerConstants.APP_REG_ENDPOINT);
|
||||
@ -111,8 +109,6 @@ public class LoginHandler extends HttpServlet {
|
||||
clientSecret = jClientAppResultAsJsonObject.get("client_secret").getAsString();
|
||||
encodedClientApp = Base64.getEncoder()
|
||||
.encodeToString((clientId + HandlerConstants.COLON + clientSecret).getBytes());
|
||||
|
||||
oAuthAppCacheKey = new OAuthAppCacheKey(HandlerConstants.PUBLISHER_APPLICATION_NAME, username);
|
||||
oAuthApp = new OAuthApp(
|
||||
HandlerConstants.PUBLISHER_APPLICATION_NAME,
|
||||
username,
|
||||
@ -120,7 +116,7 @@ public class LoginHandler extends HttpServlet {
|
||||
clientSecret,
|
||||
encodedClientApp
|
||||
);
|
||||
loginCacheManager.addOAuthAppToCache(oAuthAppCacheKey, oAuthApp);
|
||||
loginCache.addOAuthAppToCache(oAuthAppCacheKey, oAuthApp);
|
||||
}
|
||||
|
||||
if (getTokenAndPersistInSession(req, resp, clientId, clientSecret, encodedClientApp, scopes)) {
|
||||
|
||||
@ -23,7 +23,7 @@ import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import io.entgra.ui.request.interceptor.cache.LoginCacheManager;
|
||||
import io.entgra.ui.request.interceptor.cache.LoginCache;
|
||||
import io.entgra.ui.request.interceptor.cache.OAuthApp;
|
||||
import io.entgra.ui.request.interceptor.cache.OAuthAppCacheKey;
|
||||
import io.entgra.ui.request.interceptor.util.HandlerConstants;
|
||||
@ -81,9 +81,9 @@ public class SsoLoginHandler extends HttpServlet {
|
||||
|
||||
private JsonObject uiConfigJsonObject;
|
||||
private HttpSession httpSession;
|
||||
|
||||
private LoginCacheManager loginCacheManager;
|
||||
private LoginCache loginCache;
|
||||
private OAuthApp oAuthApp;
|
||||
private OAuthAppCacheKey oAuthAppCacheKey;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
|
||||
@ -99,13 +99,23 @@ public class SsoLoginHandler extends HttpServlet {
|
||||
baseContextPath = req.getContextPath();
|
||||
applicationName = baseContextPath.substring(1, baseContextPath.indexOf("-ui-request-handler"));
|
||||
|
||||
// Check if oauth app cache is available
|
||||
loginCacheManager = new LoginCacheManager();
|
||||
loginCacheManager.initializeCacheManager();
|
||||
oAuthApp = loginCacheManager.getOAuthAppCache(
|
||||
new OAuthAppCacheKey(applicationName, adminUsername)
|
||||
);
|
||||
String iotsCorePort = System.getProperty(HandlerConstants.IOT_CORE_HTTPS_PORT_ENV_VAR);
|
||||
if (HandlerConstants.HTTP_PROTOCOL.equals(req.getScheme())) {
|
||||
iotsCorePort = System.getProperty(HandlerConstants.IOT_CORE_HTTP_PORT_ENV_VAR);
|
||||
}
|
||||
gatewayUrl = req.getScheme() + HandlerConstants.SCHEME_SEPARATOR + System.getProperty(HandlerConstants.IOT_GW_HOST_ENV_VAR)
|
||||
+ HandlerConstants.COLON + HandlerUtil.getGatewayPort(req.getScheme());
|
||||
iotsCoreUrl = req.getScheme() + HandlerConstants.SCHEME_SEPARATOR + System.getProperty(HandlerConstants.IOT_CORE_HOST_ENV_VAR)
|
||||
+ HandlerConstants.COLON + iotsCorePort;
|
||||
|
||||
// Fetch ui config and persists in session
|
||||
String uiConfigUrl = iotsCoreUrl + HandlerConstants.UI_CONFIG_ENDPOINT;
|
||||
uiConfigJsonObject = HandlerUtil.getUIConfigAndPersistInSession(uiConfigUrl, gatewayUrl, httpSession, resp);
|
||||
|
||||
// Retrieving login cache and do a DCR if the cache is not available.
|
||||
loginCache = HandlerUtil.getLoginCache(httpSession);
|
||||
oAuthAppCacheKey = new OAuthAppCacheKey(applicationName, adminUsername);
|
||||
oAuthApp = loginCache.getOAuthAppCache(oAuthAppCacheKey);
|
||||
if (oAuthApp == null) {
|
||||
dynamicClientRegistration(req, resp);
|
||||
}
|
||||
@ -143,19 +153,6 @@ public class SsoLoginHandler extends HttpServlet {
|
||||
*/
|
||||
private void dynamicClientRegistration(HttpServletRequest req, HttpServletResponse resp) {
|
||||
try {
|
||||
String iotsCorePort = System.getProperty(HandlerConstants.IOT_CORE_HTTPS_PORT_ENV_VAR);
|
||||
|
||||
if (HandlerConstants.HTTP_PROTOCOL.equals(req.getScheme())) {
|
||||
iotsCorePort = System.getProperty(HandlerConstants.IOT_CORE_HTTP_PORT_ENV_VAR);
|
||||
}
|
||||
|
||||
gatewayUrl = req.getScheme() + HandlerConstants.SCHEME_SEPARATOR + System.getProperty(HandlerConstants.IOT_GW_HOST_ENV_VAR)
|
||||
+ HandlerConstants.COLON + HandlerUtil.getGatewayPort(req.getScheme());
|
||||
iotsCoreUrl = req.getScheme() + HandlerConstants.SCHEME_SEPARATOR + System.getProperty(HandlerConstants.IOT_CORE_HOST_ENV_VAR)
|
||||
+ HandlerConstants.COLON + iotsCorePort;
|
||||
String uiConfigUrl = iotsCoreUrl + HandlerConstants.UI_CONFIG_ENDPOINT;
|
||||
|
||||
uiConfigJsonObject = HandlerUtil.getUIConfigAndPersistInSession(uiConfigUrl, gatewayUrl, httpSession, resp);
|
||||
JsonArray tags = uiConfigJsonObject.get("appRegistration").getAsJsonObject().get("tags").getAsJsonArray();
|
||||
JsonArray scopes = uiConfigJsonObject.get("scopes").getAsJsonArray();
|
||||
sessionTimeOut = Integer.parseInt(String.valueOf(uiConfigJsonObject.get("sessionTimeOut")));
|
||||
@ -191,9 +188,8 @@ public class SsoLoginHandler extends HttpServlet {
|
||||
}
|
||||
|
||||
// cache the oauth app credentials
|
||||
OAuthAppCacheKey oAuthAppCacheKey = new OAuthAppCacheKey(applicationName, adminUsername);
|
||||
oAuthApp = new OAuthApp(applicationName, adminUsername, clientId, clientSecret, encodedClientApp);
|
||||
loginCacheManager.addOAuthAppToCache(oAuthAppCacheKey, oAuthApp);
|
||||
loginCache.addOAuthAppToCache(oAuthAppCacheKey, oAuthApp);
|
||||
}
|
||||
|
||||
// Get the details of the registered application
|
||||
|
||||
@ -76,9 +76,13 @@ public class UserHandler extends HttpServlet {
|
||||
ProxyResponse tokenStatus = HandlerUtil.execute(tokenEndpoint);
|
||||
|
||||
if (tokenStatus.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
|
||||
log.error("Error occurred while invoking the API to get token status.");
|
||||
HandlerUtil.handleError(resp, tokenStatus);
|
||||
return;
|
||||
if (tokenStatus.getCode() == HttpStatus.SC_UNAUTHORIZED) {
|
||||
tokenStatus = HandlerUtil.retryRequestWithRefreshedToken(req, resp, tokenEndpoint, serverUrl);
|
||||
} else {
|
||||
log.error("Error occurred while invoking the API to get token status.");
|
||||
HandlerUtil.handleError(resp, tokenStatus);
|
||||
return;
|
||||
}
|
||||
}
|
||||
String tokenData = tokenStatus.getData();
|
||||
if (tokenData == null) {
|
||||
|
||||
@ -18,25 +18,19 @@
|
||||
|
||||
package io.entgra.ui.request.interceptor.cache;
|
||||
|
||||
import io.entgra.ui.request.interceptor.util.HandlerConstants;
|
||||
|
||||
import javax.cache.Cache;
|
||||
import javax.cache.CacheManager;
|
||||
import javax.cache.Caching;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
/**
|
||||
* Contains necessary functions to manage oAuth app cache during login handling
|
||||
*/
|
||||
public class LoginCacheManager {
|
||||
public class LoginCache {
|
||||
|
||||
private CacheManager cacheManager = null;
|
||||
private Cache<OAuthAppCacheKey, OAuthApp> cache = null;
|
||||
private final LinkedHashMap<OAuthAppCacheKey, OAuthApp> cache;
|
||||
private final int capacity;
|
||||
|
||||
/**
|
||||
* Initialize the cache manager if it is not already initialized
|
||||
*/
|
||||
public void initializeCacheManager() {
|
||||
cacheManager = Caching.getCacheManagerFactory().getCacheManager(HandlerConstants.LOGIN_CACHE);
|
||||
public LoginCache(int capacity) {
|
||||
this.capacity = capacity;
|
||||
this.cache = new LinkedHashMap<>(capacity);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -46,7 +40,9 @@ public class LoginCacheManager {
|
||||
* @param oAuthApp - The value of the cache which contains OAuth app data
|
||||
*/
|
||||
public void addOAuthAppToCache(OAuthAppCacheKey oAuthAppCacheKey, OAuthApp oAuthApp) {
|
||||
cache = cacheManager.getCache(HandlerConstants.LOGIN_CACHE);
|
||||
if (cache.size() == capacity) {
|
||||
cache.remove(cache.entrySet().iterator().next().getKey());
|
||||
}
|
||||
cache.put(oAuthAppCacheKey, oAuthApp);
|
||||
}
|
||||
|
||||
@ -57,7 +53,13 @@ public class LoginCacheManager {
|
||||
* @return - Returns OAuthApp object
|
||||
*/
|
||||
public OAuthApp getOAuthAppCache(OAuthAppCacheKey oAuthAppCacheKey) {
|
||||
cache = cacheManager.getCache(HandlerConstants.LOGIN_CACHE);
|
||||
return cache.get(oAuthAppCacheKey);
|
||||
OAuthApp oAuthApp = cache.get(oAuthAppCacheKey);
|
||||
if (oAuthApp != null) {
|
||||
if (cache.size() == capacity) {
|
||||
cache.remove(oAuthAppCacheKey);
|
||||
cache.put(oAuthAppCacheKey, oAuthApp);
|
||||
}
|
||||
}
|
||||
return oAuthApp;
|
||||
}
|
||||
}
|
||||
@ -55,7 +55,7 @@ public class HandlerConstants {
|
||||
public static final String PASSWORD_GRANT_TYPE = "password";
|
||||
public static final String JWT_BEARER_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:jwt-bearer";
|
||||
public static final String PRODUCTION_KEY = "PRODUCTION";
|
||||
public static final String LOGIN_CACHE = "LOGIN_CACHE";
|
||||
public static final String LOGIN_CACHE_CAPACITY_KEY = "loginCacheCapacity";
|
||||
|
||||
public static final String SCHEME_SEPARATOR = "://";
|
||||
public static final String COLON = ":";
|
||||
|
||||
@ -23,13 +23,17 @@ import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import io.entgra.ui.request.interceptor.beans.AuthData;
|
||||
import io.entgra.ui.request.interceptor.cache.LoginCache;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.http.Consts;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.entity.ContentType;
|
||||
@ -60,6 +64,9 @@ import java.io.StringWriter;
|
||||
public class HandlerUtil {
|
||||
|
||||
private static final Log log = LogFactory.getLog(HandlerUtil.class);
|
||||
private static LoginCache loginCache = null;
|
||||
private static boolean isLoginCacheInitialized = false;
|
||||
private static AuthData authData;
|
||||
|
||||
/***
|
||||
*
|
||||
@ -166,9 +173,11 @@ public class HandlerUtil {
|
||||
|
||||
|
||||
/***
|
||||
* Handle error requests.
|
||||
*
|
||||
* @param resp {@link HttpServletResponse}
|
||||
* Return Error Response.
|
||||
* @param proxyResponse {@link ProxyResponse}
|
||||
* @throws IOException If error occurred when trying to send the error response.
|
||||
*/
|
||||
public static void handleError(HttpServletResponse resp, ProxyResponse proxyResponse) throws IOException {
|
||||
Gson gson = new Gson();
|
||||
@ -188,6 +197,22 @@ public class HandlerUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle error requests with custom error codes.
|
||||
*
|
||||
* @param resp {@link HttpServletResponse}
|
||||
* @param errorCode HTTP error status code
|
||||
* @throws IOException If error occurred when trying to send the error response.
|
||||
*/
|
||||
public static void handleError(HttpServletResponse resp, int errorCode)
|
||||
throws IOException {
|
||||
ProxyResponse proxyResponse = new ProxyResponse();
|
||||
proxyResponse.setCode(errorCode);
|
||||
proxyResponse.setExecutorResponse(
|
||||
HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + HandlerUtil.getStatusKey(errorCode));
|
||||
HandlerUtil.handleError(resp, proxyResponse);
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* @param resp {@link HttpServletResponse}
|
||||
@ -400,4 +425,136 @@ public class HandlerUtil {
|
||||
|
||||
return stringOutput;
|
||||
}
|
||||
|
||||
/***
|
||||
* Search a key from a given json string object.
|
||||
*
|
||||
* @param jsonObjectString - json object in string format.
|
||||
* @param key - the key to be searched.
|
||||
* @return string value of the key value.
|
||||
*/
|
||||
private static String searchFromJsonObjectString(String jsonObjectString, String key) {
|
||||
JsonParser jsonParser = new JsonParser();
|
||||
JsonElement jsonElement = jsonParser.parse(jsonObjectString);
|
||||
JsonObject jsonObject = jsonElement.getAsJsonObject();
|
||||
return jsonObject.get(key).getAsString();
|
||||
}
|
||||
|
||||
/***
|
||||
* Initializes the login cache.
|
||||
*
|
||||
* @param httpSession - current active HttpSession.
|
||||
*/
|
||||
private static void initializeLoginCache(HttpSession httpSession) {
|
||||
String uiConfig = httpSession.getAttribute(HandlerConstants.UI_CONFIG_KEY).toString();
|
||||
int capacity = Integer.parseInt(searchFromJsonObjectString(uiConfig, HandlerConstants.LOGIN_CACHE_CAPACITY_KEY));
|
||||
loginCache = new LoginCache(capacity);
|
||||
}
|
||||
|
||||
/***
|
||||
* Retrieves login cache and initializes if its not done already.
|
||||
*
|
||||
* @param httpSession - current active HttpSession.
|
||||
*/
|
||||
public static LoginCache getLoginCache(HttpSession httpSession) {
|
||||
if (!isLoginCacheInitialized || loginCache == null) {
|
||||
isLoginCacheInitialized = true;
|
||||
initializeLoginCache(httpSession);
|
||||
}
|
||||
return loginCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retry request again after refreshing the access token
|
||||
*
|
||||
* @param req incoming {@link HttpServletRequest}
|
||||
* @param resp resp {@link HttpServletResponse}
|
||||
* @param httpRequest subclass of {@link HttpRequestBase} related to the current request.
|
||||
* @return {@link ProxyResponse} if successful and <code>null</code> if failed.
|
||||
* @throws IOException If an error occurs when try to retry the request.
|
||||
*/
|
||||
public static ProxyResponse retryRequestWithRefreshedToken(HttpServletRequest req, HttpServletResponse resp,
|
||||
HttpRequestBase httpRequest, String apiEndpoint) throws IOException {
|
||||
if (refreshToken(req, resp, apiEndpoint)) {
|
||||
HttpSession session = req.getSession(false);
|
||||
if (session == null) {
|
||||
log.error("Unauthorized, You are not logged in. Please log in to the portal");
|
||||
handleError(resp, HttpStatus.SC_UNAUTHORIZED);
|
||||
return null;
|
||||
}
|
||||
httpRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER + authData.getAccessToken());
|
||||
ProxyResponse proxyResponse = HandlerUtil.execute(httpRequest);
|
||||
if (proxyResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
|
||||
log.error("Error occurred while invoking the API after refreshing the token.");
|
||||
HandlerUtil.handleError(resp, proxyResponse);
|
||||
return null;
|
||||
}
|
||||
return proxyResponse;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/***
|
||||
* This method is responsible to get the refresh token
|
||||
*
|
||||
* @param req {@link HttpServletRequest}
|
||||
* @param resp {@link HttpServletResponse}
|
||||
* @return If successfully renew tokens, returns TRUE otherwise return FALSE
|
||||
* @throws IOException If an error occurs while witting error response to client side or invoke token renewal API
|
||||
*/
|
||||
private static boolean refreshToken(HttpServletRequest req, HttpServletResponse resp, String gatewayUrl)
|
||||
throws IOException {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("refreshing the token");
|
||||
}
|
||||
HttpPost tokenEndpoint = new HttpPost(
|
||||
gatewayUrl + HandlerConstants.TOKEN_ENDPOINT);
|
||||
HttpSession session = req.getSession(false);
|
||||
if (session == null) {
|
||||
log.error("Couldn't find a session, hence it is required to login and proceed.");
|
||||
handleError(resp, HttpStatus.SC_UNAUTHORIZED);
|
||||
return false;
|
||||
}
|
||||
|
||||
authData = (AuthData) session.getAttribute(HandlerConstants.SESSION_AUTH_DATA_KEY);
|
||||
StringEntity tokenEndpointPayload = new StringEntity(
|
||||
"grant_type=refresh_token&refresh_token=" + authData.getRefreshToken() + "&scope=PRODUCTION",
|
||||
ContentType.APPLICATION_FORM_URLENCODED);
|
||||
|
||||
tokenEndpoint.setEntity(tokenEndpointPayload);
|
||||
String encodedClientApp = authData.getEncodedClientApp();
|
||||
tokenEndpoint.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BASIC +
|
||||
encodedClientApp);
|
||||
tokenEndpoint.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.toString());
|
||||
|
||||
ProxyResponse tokenResultResponse = HandlerUtil.execute(tokenEndpoint);
|
||||
if (tokenResultResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
|
||||
log.error("Error occurred while refreshing access token.");
|
||||
HandlerUtil.handleError(resp, tokenResultResponse);
|
||||
return false;
|
||||
}
|
||||
|
||||
JsonParser jsonParser = new JsonParser();
|
||||
JsonElement jTokenResult = jsonParser.parse(tokenResultResponse.getData());
|
||||
|
||||
if (jTokenResult.isJsonObject()) {
|
||||
JsonObject jTokenResultAsJsonObject = jTokenResult.getAsJsonObject();
|
||||
AuthData newAuthData = new AuthData();
|
||||
|
||||
newAuthData.setAccessToken(jTokenResultAsJsonObject.get("access_token").getAsString());
|
||||
newAuthData.setRefreshToken(jTokenResultAsJsonObject.get("refresh_token").getAsString());
|
||||
newAuthData.setScope(jTokenResultAsJsonObject.get("scope").getAsString());
|
||||
newAuthData.setClientId(authData.getClientId());
|
||||
newAuthData.setClientSecret(authData.getClientSecret());
|
||||
newAuthData.setEncodedClientApp(authData.getEncodedClientApp());
|
||||
newAuthData.setUsername(authData.getUsername());
|
||||
authData = newAuthData;
|
||||
session.setAttribute(HandlerConstants.SESSION_AUTH_DATA_KEY, newAuthData);
|
||||
return true;
|
||||
}
|
||||
|
||||
log.error("Error Occurred in token renewal process.");
|
||||
handleError(resp, HttpStatus.SC_INTERNAL_SERVER_ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,6 +22,8 @@
|
||||
<EnableSSO>true</EnableSSO>
|
||||
<!-- session time out in seconds -->
|
||||
<SessionTimeOut>3600</SessionTimeOut>
|
||||
<!-- maximum number of login cache entries -->
|
||||
<LoginCacheCapacity>10000</LoginCacheCapacity>
|
||||
<AppRegistration>
|
||||
<Tags>
|
||||
<Tag>application_management</Tag>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user