diff --git a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/pom.xml b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/pom.xml
new file mode 100644
index 0000000000..16090c509e
--- /dev/null
+++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/pom.xml
@@ -0,0 +1,155 @@
+
+
+
+
+
+ ui-request-interceptor
+ io.entgra.devicemgt
+ 3.2.5-SNAPSHOT
+
+ 4.0.0
+
+ io.entgra.ui.request.interceptor
+
+ 3.2.5-SNAPSHOT
+ war
+ Entgra - Request Handling Proxy Servlet
+ Proxy Service for Request Handling in Entgra EMM/IOT Server.
+ http://wso2.org
+
+
+
+
+ maven-war-plugin
+
+ WEB-INF/lib/*cxf*.jar
+ ui-request-handler
+
+
+
+
+
+
+
+ deploy
+
+ compile
+
+
+ org.apache.maven.plugins
+ maven-antrun-plugin
+
+
+ compile
+
+ run
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ client
+
+ test
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.4.0
+
+
+ test
+
+ java
+
+
+
+
+
+
+
+
+
+
+
+ org.apache.cxf
+ cxf-rt-frontend-jaxws
+ provided
+
+
+ org.apache.cxf
+ cxf-rt-frontend-jaxrs
+ provided
+
+
+ org.apache.cxf
+ cxf-rt-transports-http
+ provided
+
+
+ javax.servlet
+ javax.servlet-api
+ provided
+
+
+ junit
+ junit
+ test
+
+
+ commons-logging
+ commons-logging
+
+
+
+ org.apache.httpcomponents
+ httpclient
+
+
+
+
+ org.apache.httpcomponents
+ httpcore
+
+
+ org.wso2.carbon.devicemgt
+ org.wso2.carbon.device.application.mgt.core
+ provided
+
+
+ org.wso2.carbon.devicemgt
+ org.wso2.carbon.device.application.mgt.common
+ provided
+
+
+
\ No newline at end of file
diff --git a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/InvokerHandler.java b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/InvokerHandler.java
new file mode 100644
index 0000000000..1dd968ecd5
--- /dev/null
+++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/InvokerHandler.java
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
+ *
+ * Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+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;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.HttpHeaders;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+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.wso2.carbon.device.application.mgt.common.ProxyResponse;
+
+import javax.servlet.annotation.MultipartConfig;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.IOException;
+import java.util.Enumeration;
+
+import static io.entgra.ui.request.interceptor.util.HandlerUtil.execute;
+
+@MultipartConfig
+@WebServlet(
+ name = "RequestHandlerServlet",
+ description = "This servlet intercepts the api requests initiated from the user interface and validate before" +
+ " forwarding to the backend",
+ urlPatterns = {
+ "/invoke/*"
+ }
+)
+public class InvokerHandler extends HttpServlet {
+ private static final Log log = LogFactory.getLog(LoginHandler.class);
+ private static final long serialVersionUID = -6508020875358160165L;
+// private static final HeaderGroup nonForwardingHeaders = new HeaderGroup();
+ private static AuthData authData;
+ private static String apiEndpoint;
+ private static String serverUrl;
+ private static String platform;
+
+// static {
+// // Initializing hop-by-hop headers to omit them from forwarding to the backend
+// String[] headers = {HttpHeaders.CONNECTION, HttpHeaders.TRANSFER_ENCODING, HttpHeaders.PROXY_AUTHENTICATE,
+// HttpHeaders.PROXY_AUTHORIZATION, HttpHeaders.UPGRADE, HttpHeaders.TE, HttpHeaders.TRAILER,
+// HandlerConstants.KEEP_ALIVE, HandlerConstants.PUBLIC};
+// for (String header : headers) {
+// nonForwardingHeaders.addHeader(new BasicHeader(header, null));
+// }
+// }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
+ try {
+ if (validateRequest(req, resp)) {
+ HttpPost postRequest = new HttpPost(generateBackendRequestURL(req));
+ if (StringUtils.isNotEmpty(req.getHeader(HttpHeaders.CONTENT_LENGTH)) ||
+ StringUtils.isNotEmpty(req.getHeader(HttpHeaders.TRANSFER_ENCODING))) {
+ InputStreamEntity entity = new InputStreamEntity(req.getInputStream(),
+ Long.parseLong(req.getHeader(HttpHeaders.CONTENT_LENGTH)));
+ postRequest.setEntity(entity);
+ }
+ copyRequestHeaders(req, postRequest);
+ postRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER + authData.getAccessToken());
+ ProxyResponse proxyResponse = execute(postRequest);
+
+ if (HandlerConstants.TOKEN_IS_EXPIRED.equals(proxyResponse.getExecutorResponse())) {
+ proxyResponse = retryRequestWithRefreshedToken(req, resp, postRequest);
+ if (proxyResponse == null) {
+ return;
+ }
+ }
+ if (proxyResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
+ log.error("Error occurred while invoking the API endpoint.");
+ HandlerUtil.handleError(req, resp, serverUrl, platform, proxyResponse);
+ return;
+ }
+ HandlerUtil.handleSuccess(req, resp, serverUrl, platform, proxyResponse);
+ }
+ } catch (IOException e) {
+ log.error("Error occurred when processing POST request.", e);
+ }
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
+ try {
+ if (validateRequest(req, resp)) {
+ HttpGet getRequest = new HttpGet(generateBackendRequestURL(req));
+ copyRequestHeaders(req, getRequest);
+ getRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER + authData.getAccessToken());
+ ProxyResponse proxyResponse = execute(getRequest);
+ if (HandlerConstants.TOKEN_IS_EXPIRED.equals(proxyResponse.getExecutorResponse())) {
+ proxyResponse = retryRequestWithRefreshedToken(req, resp, getRequest);
+ if (proxyResponse == null) {
+ return;
+ }
+ }
+ if (proxyResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
+ log.error("Error occurred while invoking the API endpoint.");
+ HandlerUtil.handleError(req, resp, serverUrl, platform, proxyResponse);
+ return;
+ }
+ HandlerUtil.handleSuccess(req, resp, serverUrl, platform, proxyResponse);
+ }
+ } catch (IOException e) {
+ log.error("Error occurred when processing GET request.", e);
+ }
+ }
+
+ @Override
+ protected void doPut(HttpServletRequest req, HttpServletResponse resp) {
+ try {
+ if (validateRequest(req, resp)) {
+ HttpPut putRequest = new HttpPut(generateBackendRequestURL(req));
+ if ((StringUtils.isNotEmpty(req.getHeader(HttpHeaders.CONTENT_LENGTH)) &&
+ Double.parseDouble(req.getHeader(HttpHeaders.CONTENT_LENGTH)) > 0) ||
+ StringUtils.isNotEmpty(req.getHeader(HttpHeaders.TRANSFER_ENCODING))) {
+ InputStreamEntity entity = new InputStreamEntity(req.getInputStream(),
+ Long.parseLong(req.getHeader(HttpHeaders.CONTENT_LENGTH)));
+ putRequest.setEntity(entity);
+ }
+ copyRequestHeaders(req, putRequest);
+ putRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER + authData.getAccessToken());
+ ProxyResponse proxyResponse = execute(putRequest);
+
+ if (HandlerConstants.TOKEN_IS_EXPIRED.equals(proxyResponse.getExecutorResponse())) {
+ proxyResponse = retryRequestWithRefreshedToken(req, resp, putRequest);
+ if (proxyResponse == null) {
+ return;
+ }
+ }
+ if (proxyResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
+ log.error("Error occurred while invoking the API endpoint.");
+ HandlerUtil.handleError(req, resp, serverUrl, platform, proxyResponse);
+ return;
+ }
+ HandlerUtil.handleSuccess(req, resp, serverUrl, platform, proxyResponse);
+ }
+ } catch (IOException e) {
+ log.error("Error occurred when processing PUT request.", e);
+ }
+ }
+
+ @Override
+ protected void doDelete(HttpServletRequest req, HttpServletResponse resp) {
+ try {
+ if (validateRequest(req, resp)) {
+ HttpDelete deleteRequest = new HttpDelete(generateBackendRequestURL(req));
+ copyRequestHeaders(req, deleteRequest);
+ deleteRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER + authData.getAccessToken());
+ ProxyResponse proxyResponse = execute(deleteRequest);
+ if (HandlerConstants.TOKEN_IS_EXPIRED.equals(proxyResponse.getExecutorResponse())) {
+ proxyResponse = retryRequestWithRefreshedToken(req, resp, deleteRequest);
+ if (proxyResponse == null) {
+ return;
+ }
+ }
+ if (proxyResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
+ log.error("Error occurred while invoking the API endpoint.");
+ HandlerUtil.handleError(req, resp, serverUrl, platform, proxyResponse);
+ return;
+ }
+ HandlerUtil.handleSuccess(req, resp, serverUrl, platform, proxyResponse);
+ }
+ } catch (IOException e) {
+ log.error("Error occurred when processing DELETE request.", e);
+ }
+ }
+
+ private String generateBackendRequestURL(HttpServletRequest req) {
+ StringBuilder urlBuilder = new StringBuilder();
+ urlBuilder.append(serverUrl).append(HandlerConstants.API_COMMON_CONTEXT).append(apiEndpoint);
+ if (StringUtils.isNotEmpty(req.getQueryString())) {
+ urlBuilder.append("?").append(req.getQueryString());
+ }
+ return urlBuilder.toString();
+ }
+
+ private void copyRequestHeaders(HttpServletRequest req, HttpRequestBase httpRequest) {
+ Enumeration headerNames = req.getHeaderNames();
+ while (headerNames.hasMoreElements()) {
+ String headerName = headerNames.nextElement();
+ if (headerName.equalsIgnoreCase(HttpHeaders.CONTENT_LENGTH) ||
+ headerName.equalsIgnoreCase(SM.COOKIE)) {
+ continue;
+ }
+ Enumeration headerValues = req.getHeaders(headerName);
+ while (headerValues.hasMoreElements()) {
+ httpRequest.setHeader(headerName, headerValues.nextElement());
+ }
+ }
+ }
+ /***
+ *
+ * @param req {@link HttpServletRequest}
+ * @param resp {@link HttpServletResponse}
+ * @return If request is a valid one, returns TRUE, otherwise return FALSE
+ * @throws IOException If and error occurs while witting error response to client side
+ */
+ private static boolean validateRequest(HttpServletRequest req, HttpServletResponse resp)
+ throws IOException {
+ serverUrl = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort();
+ apiEndpoint = req.getPathInfo();
+ HttpSession session = req.getSession(false);
+ if (session == null) {
+ log.error("Unauthorized, You are not logged in. Please log in to the portal");
+ ProxyResponse proxyResponse = new ProxyResponse();
+ proxyResponse.setCode(HttpStatus.SC_UNAUTHORIZED);
+ proxyResponse.setExecutorResponse(
+ HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + HandlerUtil.getStatusKey(HttpStatus.SC_UNAUTHORIZED));
+ HandlerUtil.handleError(req, resp, serverUrl, platform, proxyResponse);
+ return false;
+ }
+ authData = (AuthData) session.getAttribute(HandlerConstants.SESSION_AUTH_DATA_KEY);
+ platform = (String) session.getAttribute(HandlerConstants.PLATFORM);
+ if (authData == null) {
+ log.error("Unauthorized, Access token not found in the current session");
+ ProxyResponse proxyResponse = new ProxyResponse();
+ proxyResponse.setCode(HttpStatus.SC_UNAUTHORIZED);
+ proxyResponse.setExecutorResponse(
+ HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + HandlerUtil.getStatusKey(HttpStatus.SC_UNAUTHORIZED));
+ HandlerUtil.handleError(req, resp, serverUrl, platform, proxyResponse);
+ return false;
+ }
+
+ if (apiEndpoint == null || req.getMethod() == null) {
+ log.error("Bad Request, Either destination api-endpoint or method is empty");
+ ProxyResponse proxyResponse = new ProxyResponse();
+ proxyResponse.setCode(HttpStatus.SC_BAD_REQUEST);
+ proxyResponse.setExecutorResponse(
+ HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + HandlerUtil.getStatusKey(HttpStatus.SC_BAD_REQUEST));
+ HandlerUtil.handleError(req, resp, serverUrl, platform, proxyResponse);
+ 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 null
if failed.
+ * @throws IOException If an error occurs when try to retry the request.
+ */
+ private static ProxyResponse retryRequestWithRefreshedToken(HttpServletRequest req, HttpServletResponse resp,
+ HttpRequestBase httpRequest) throws IOException {
+ if (refreshToken(req, resp)) {
+ httpRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER + authData.getAccessToken());
+ ProxyResponse proxyResponse = execute(httpRequest);
+ if (proxyResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
+ log.error("Error occurred while invoking the API after refreshing the token.");
+ HandlerUtil.handleError(req, resp, serverUrl, platform, proxyResponse);
+ return null;
+ }
+ return proxyResponse;
+ }
+ return null;
+ }
+
+ /***
+ *
+ * @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(
+ serverUrl + HandlerConstants.API_COMMON_CONTEXT + 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.");
+ ProxyResponse proxyResponse = new ProxyResponse();
+ proxyResponse.setCode(HttpStatus.SC_UNAUTHORIZED);
+ proxyResponse.setExecutorResponse(
+ HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + HandlerUtil.getStatusKey(HttpStatus.SC_UNAUTHORIZED));
+ HandlerUtil.handleError(req, resp, serverUrl, platform, proxyResponse);
+ 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 = execute(tokenEndpoint);
+ if (tokenResultResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
+ log.error("Error occurred while refreshing access token.");
+ HandlerUtil.handleError(req, resp, serverUrl, platform, 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.");
+ ProxyResponse proxyResponse = new ProxyResponse();
+ proxyResponse.setCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
+ proxyResponse.setExecutorResponse(
+ HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + HandlerUtil.getStatusKey(HttpStatus.SC_INTERNAL_SERVER_ERROR));
+ HandlerUtil.handleError(req, resp, serverUrl, platform, proxyResponse);
+ return false;
+ }
+}
diff --git a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/LoginHandler.java b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/LoginHandler.java
new file mode 100644
index 0000000000..5f1167073d
--- /dev/null
+++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/LoginHandler.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
+ *
+ * Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package io.entgra.ui.request.interceptor;
+
+import com.google.gson.JsonArray;
+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.beans.AuthData;
+import io.entgra.ui.request.interceptor.exceptions.LoginException;
+import io.entgra.ui.request.interceptor.util.HandlerConstants;
+import io.entgra.ui.request.interceptor.util.HandlerUtil;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.HttpHeaders;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.protocol.HTTP;
+import org.wso2.carbon.device.application.mgt.common.ProxyResponse;
+import org.wso2.carbon.device.mgt.core.config.DeviceConfigurationManager;
+import org.wso2.carbon.device.mgt.core.config.DeviceManagementConfig;
+
+import javax.servlet.annotation.MultipartConfig;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.IOException;
+import java.util.Base64;
+
+import static io.entgra.ui.request.interceptor.util.HandlerUtil.execute;
+
+@MultipartConfig
+@WebServlet("/login")
+public class LoginHandler extends HttpServlet {
+ private static final Log log = LogFactory.getLog(LoginHandler.class);
+ private static final long serialVersionUID = 9050048549140517002L;
+
+ private static String username;
+ private static String password;
+ private static String platform;
+ private static String serverUrl;
+ private static String uiConfigUrl;
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
+ try {
+ validateLoginRequest(req, resp);
+ DeviceManagementConfig deviceManagementConfig = DeviceConfigurationManager.getInstance()
+ .getDeviceManagementConfig();
+ String adminUsername = deviceManagementConfig.getIdentityConfigurations().getAdminUsername();
+ String adminPwd = deviceManagementConfig.getIdentityConfigurations().getAdminPassword();
+
+ HttpSession httpSession = req.getSession(false);
+ if (httpSession != null) {
+ httpSession.invalidate();
+ }
+ httpSession = req.getSession(true);
+ //setting session to expiry in 5 mins
+ httpSession.setMaxInactiveInterval(Math.toIntExact(HandlerConstants.TIMEOUT));
+
+ HttpGet uiConfigEndpoint = new HttpGet(uiConfigUrl);
+ JsonParser jsonParser = new JsonParser();
+ ProxyResponse uiConfigResponse = execute(uiConfigEndpoint);
+ String executorResponse = uiConfigResponse.getExecutorResponse();
+ if (!StringUtils.isEmpty(executorResponse) && executorResponse
+ .contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
+ log.error("Error occurred while getting UI configurations by invoking " + uiConfigUrl);
+ HandlerUtil.handleError(req, resp, serverUrl, platform, uiConfigResponse);
+ return;
+ }
+
+ String uiConfig = uiConfigResponse.getData();
+ if (uiConfig == null){
+ log.error("UI config retrieval is failed, and didn't find UI configuration for App manager.");
+ HandlerUtil.handleError(req, resp, serverUrl, platform, null);
+ return;
+ }
+ JsonElement uiConfigJsonElement = jsonParser.parse(uiConfigResponse.getData());
+ JsonObject uiConfigJsonObject = null;
+ if (uiConfigJsonElement.isJsonObject()) {
+ uiConfigJsonObject = uiConfigJsonElement.getAsJsonObject();
+ httpSession.setAttribute(HandlerConstants.UI_CONFIG_KEY, uiConfigJsonObject);
+ httpSession.setAttribute(HandlerConstants.PLATFORM, serverUrl);
+ }
+ if (uiConfigJsonObject == null) {
+ log.error(
+ "Either UI config json element is not an json object or converting rom json element to json object is failed.");
+ HandlerUtil.handleError(req, resp, serverUrl, platform, null);
+ return;
+ }
+
+ boolean isSsoEnable = uiConfigJsonObject.get("isSsoEnable").getAsBoolean();
+ JsonArray tags = uiConfigJsonObject.get("appRegistration").getAsJsonObject().get("tags").getAsJsonArray();
+ JsonArray scopes = uiConfigJsonObject.get("scopes").getAsJsonArray();
+
+ if (isSsoEnable) {
+ log.debug("SSO is enabled");
+ } else {
+ // default login
+ HttpPost apiRegEndpoint = new HttpPost(serverUrl + HandlerConstants.APP_REG_ENDPOINT);
+ apiRegEndpoint.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BASIC + Base64.getEncoder()
+ .encodeToString((adminUsername + HandlerConstants.COLON + adminPwd).getBytes()));
+ apiRegEndpoint.setHeader(HTTP.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString());
+ apiRegEndpoint.setEntity(constructAppRegPayload(tags));
+
+ ProxyResponse clientAppResponse = execute(apiRegEndpoint);
+ String clientAppResult = clientAppResponse.getData();
+
+ if (!StringUtils.isEmpty(clientAppResult) && getTokenAndPersistInSession(req, resp,
+ clientAppResponse.getData(), scopes)) {
+ ProxyResponse proxyResponse = new ProxyResponse();
+ proxyResponse.setCode(HttpStatus.SC_OK);
+ proxyResponse.setUrl(serverUrl + "/" + platform + uiConfigJsonObject.get(HandlerConstants.LOGIN_RESPONSE_KEY)
+ .getAsJsonObject().get("successCallback").getAsString());
+ HandlerUtil.handleSuccess(req, resp, serverUrl, platform, proxyResponse);
+ return;
+ }
+ HandlerUtil.handleError(req, resp, serverUrl, platform, null);
+ }
+ } catch (IOException e) {
+ log.error("Error occured while sending the response into the socket. ", e);
+ } catch (JsonSyntaxException e) {
+ log.error("Error occured while parsing the response. ", e);
+ } catch (LoginException e) {
+ log.error("Error occured while getting token data. ", e);
+ }
+ }
+
+ /***
+ *
+ * @param req - {@link HttpServletRequest}
+ * @param clientAppResult - clientAppResult
+ * @param scopes - scopes defied in the application-mgt.xml
+ * @throws LoginException - login exception throws when getting token result
+ */
+ private boolean getTokenAndPersistInSession(HttpServletRequest req, HttpServletResponse resp,
+ String clientAppResult, JsonArray scopes) throws LoginException {
+ JsonParser jsonParser = new JsonParser();
+ try {
+ JsonElement jClientAppResult = jsonParser.parse(clientAppResult);
+ if (jClientAppResult.isJsonObject()) {
+ JsonObject jClientAppResultAsJsonObject = jClientAppResult.getAsJsonObject();
+ String clientId = jClientAppResultAsJsonObject.get("client_id").getAsString();
+ String clientSecret = jClientAppResultAsJsonObject.get("client_secret").getAsString();
+ String encodedClientApp = Base64.getEncoder()
+ .encodeToString((clientId + ":" + clientSecret).getBytes());
+
+ ProxyResponse tokenResultResponse = getTokenResult(encodedClientApp, scopes);
+
+ if (tokenResultResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
+ log.error("Error occurred while invoking the API to get token data.");
+ HandlerUtil.handleError(req, resp, serverUrl, platform, tokenResultResponse);
+ return false;
+ }
+ String tokenResult = tokenResultResponse.getData();
+ if (tokenResult == null){
+ log.error("Invalid token response is received.");
+ HandlerUtil.handleError(req, resp, serverUrl, platform, tokenResultResponse);
+ return false;
+ }
+
+ JsonElement jTokenResult = jsonParser.parse(tokenResult);
+ if (jTokenResult.isJsonObject()) {
+ JsonObject jTokenResultAsJsonObject = jTokenResult.getAsJsonObject();
+ HttpSession session = req.getSession(false);
+ if (session == null) {
+ return false;
+ }
+ AuthData authData = new AuthData();
+ authData.setClientId(clientId);
+ authData.setClientSecret(clientSecret);
+ authData.setEncodedClientApp(encodedClientApp);
+ authData.setAccessToken(jTokenResultAsJsonObject.get("access_token").getAsString());
+ authData.setRefreshToken(jTokenResultAsJsonObject.get("refresh_token").getAsString());
+ authData.setScope(jTokenResultAsJsonObject.get("scope").getAsString());
+ session.setAttribute(HandlerConstants.SESSION_AUTH_DATA_KEY, authData);
+ return true;
+
+ }
+ }
+ return false;
+ } catch (IOException e) {
+ throw new LoginException("Error occured while sending the response into the socket", e);
+ }
+ }
+
+ /***
+ *
+ * @param scopes - scope Json Array and it is retrieved by reading UI config.
+ * @return string value of the defined scopes
+ */
+ private String getScopeString(JsonArray scopes) {
+ if (scopes != null && scopes.size() > 0) {
+ StringBuilder builder = new StringBuilder();
+ for (JsonElement scope : scopes) {
+ String tmpscope = scope.getAsString() + " ";
+ builder.append(tmpscope);
+ }
+ return builder.toString();
+ } else {
+ return null;
+ }
+ }
+
+ /***
+ *
+ * @param req - {@link HttpServletRequest}
+ * Define username and password static parameters.
+ */
+ private static void validateLoginRequest(HttpServletRequest req, HttpServletResponse resp) throws LoginException {
+ username = req.getParameter("username");
+ password = req.getParameter("password");
+ platform = req.getParameter("platform");
+ serverUrl = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort();
+ uiConfigUrl = serverUrl + HandlerConstants.UI_CONFIG_ENDPOINT;
+
+ try {
+ if (platform == null) {
+ resp.sendRedirect(serverUrl + HandlerConstants.DEFAULT_ERROR_CALLBACK);
+ throw new LoginException("Invalid login request. Platform parameter is Null.");
+ }
+ if (username == null || password == null) {
+ resp.sendRedirect(serverUrl + "/" + platform + HandlerConstants.DEFAULT_ERROR_CALLBACK);
+ throw new LoginException(
+ " Invalid login request. Username or Password is not received for login request.");
+ }
+ } catch (IOException e) {
+ throw new LoginException("Error Occured while redirecting to default error page.", e);
+ }
+ }
+
+ /***
+ *
+ * @param tags - tags which are retrieved by reading app manager configuration
+ * @return {@link StringEntity} of the payload to create the client application
+ */
+ private StringEntity constructAppRegPayload(JsonArray tags) {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty(HandlerConstants.APP_NAME_KEY, HandlerConstants.PUBLISHER_APPLICATION_NAME);
+ jsonObject.addProperty("isAllowedToAllDomains", "false");
+ jsonObject.add(HandlerConstants.TAGS_KEY, tags);
+ String payload = jsonObject.toString();
+ return new StringEntity(payload, ContentType.APPLICATION_JSON);
+ }
+
+ /***
+ *
+ * @param encodedClientApp - Base64 encoded clientId:clientSecret.
+ * @param scopes - Scopes which are retrieved by reading application-mgt configuration
+ * @return Invoke token endpoint and return the response as string.
+ * @throws IOException IO exception throws if an error occured when invoking token endpoint
+ */
+ private ProxyResponse getTokenResult(String encodedClientApp, JsonArray scopes) throws IOException {
+
+ HttpPost tokenEndpoint = new HttpPost(serverUrl + HandlerConstants.TOKEN_ENDPOINT);
+ tokenEndpoint.setHeader("Authorization", "Basic " + encodedClientApp);
+ tokenEndpoint.setHeader("Content-Type", ContentType.APPLICATION_FORM_URLENCODED.toString());
+ String scopeString = getScopeString(scopes);
+
+ if (scopeString != null) {
+ scopeString = scopeString.trim();
+ } else {
+ scopeString = "default";
+ }
+
+ StringEntity tokenEPPayload = new StringEntity(
+ "grant_type=password&username=" + username + "&password=" + password + "&scope=" + scopeString,
+ ContentType.APPLICATION_FORM_URLENCODED);
+ tokenEndpoint.setEntity(tokenEPPayload);
+ return execute(tokenEndpoint);
+ }
+}
diff --git a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/beans/AuthData.java b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/beans/AuthData.java
new file mode 100644
index 0000000000..be6a8b570b
--- /dev/null
+++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/beans/AuthData.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
+ *
+ * Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package io.entgra.ui.request.interceptor.beans;
+
+
+public class AuthData implements java.io.Serializable {
+
+ private static final long serialVersionUID = -5156750882531944849L;
+
+ private String accessToken;
+ private String refreshToken;
+ private String username;
+ private String clientId;
+ private String clientSecret;
+ private String encodedClientApp;
+ private String scope;
+
+ public String getAccessToken() {
+ return accessToken;
+ }
+
+ public void setAccessToken(String accessToken) {
+ this.accessToken = accessToken;
+ }
+
+ public String getRefreshToken() {
+ return refreshToken;
+ }
+
+ public void setRefreshToken(String refreshToken) {
+ this.refreshToken = refreshToken;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getClientId() {
+ return clientId;
+ }
+
+ public void setClientId(String clientId) {
+ this.clientId = clientId;
+ }
+
+ public String getClientSecret() {
+ return clientSecret;
+ }
+
+ public void setClientSecret(String clientSecret) {
+ this.clientSecret = clientSecret;
+ }
+
+ public String getEncodedClientApp() {
+ return encodedClientApp;
+ }
+
+ public void setEncodedClientApp(String encodedClientApp) {
+ this.encodedClientApp = encodedClientApp;
+ }
+
+ public String getScope() {
+ return scope;
+ }
+
+ public void setScope(String scope) {
+ this.scope = scope;
+ }
+}
diff --git a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/exceptions/LoginException.java b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/exceptions/LoginException.java
new file mode 100644
index 0000000000..b33b74da73
--- /dev/null
+++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/exceptions/LoginException.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
+ *
+ * Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package io.entgra.ui.request.interceptor.exceptions;
+
+public class LoginException extends Exception {
+ public LoginException(String message) {
+ super(message);
+ }
+
+ public LoginException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public LoginException(Throwable cause) {
+ super(cause);
+ }
+
+ public LoginException(String message, Throwable cause,
+ boolean enableSuppression,
+ boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
+}
diff --git a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerConstants.java b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerConstants.java
new file mode 100644
index 0000000000..aa80d7fd66
--- /dev/null
+++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerConstants.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
+ *
+ * Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package io.entgra.ui.request.interceptor.util;
+
+public class HandlerConstants {
+ public static final String PUBLISHER_APPLICATION_NAME = "application-mgt-publisher";
+ public static final String APP_REG_ENDPOINT = "/api-application-registration/register";
+ public static final String UI_CONFIG_ENDPOINT = "/api/application-mgt/v1.0/config/ui-config";
+ public static final String TOKEN_ENDPOINT = "/oauth2/token";
+ public static final String PUBLIC = "Public";
+ public static final String KEEP_ALIVE = "Keep-Alive";
+ public static final String BASIC = "Basic ";
+ public static final String BEARER = "Bearer ";
+ public static final String COLON = ":";
+ public static final String TAGS_KEY = "tags";
+ public static final String APP_NAME_KEY = "applicationName";
+ public static final String SESSION_AUTH_DATA_KEY = "application-mgt";
+ public static final String UI_CONFIG_KEY = "ui-config";
+ public static final String PLATFORM = "platform";
+ public static final String SERVER_HOST = "server-host";
+ public static final String DEFAULT_ERROR_CALLBACK = "/pages/error/default";
+ public static final String LOGIN_RESPONSE_KEY = "loginResponse";
+ public static final String FAILURE_CALLBACK_KEY = "failureCallback";
+ public static final String API_COMMON_CONTEXT = "/api";
+ public static final String EXECUTOR_EXCEPTION_PREFIX = "ExecutorException-";
+ public static final String TOKEN_IS_EXPIRED = "ACCESS_TOKEN_IS_EXPIRED";
+
+ public static final int INTERNAL_ERROR_CODE = 500;
+ public static final long TIMEOUT = 1200;
+}
diff --git a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerUtil.java b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerUtil.java
new file mode 100644
index 0000000000..f3baea315f
--- /dev/null
+++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerUtil.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
+ *
+ * Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package io.entgra.ui.request.interceptor.util;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.wso2.carbon.device.application.mgt.common.ProxyResponse;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+
+public class HandlerUtil {
+
+ private static final Log log = LogFactory.getLog(HandlerUtil.class);
+
+ /***
+ *
+ * @param httpRequest - httpMethod e.g:- HttpPost, HttpGet
+ * @return response as string
+ * @throws IOException IO exception returns if error occurs when executing the httpMethod
+ */
+ public static ProxyResponse execute(HttpRequestBase httpRequest) throws IOException {
+ try (CloseableHttpClient client = HttpClients.createDefault()) {
+ HttpResponse response = client.execute(httpRequest);
+ ProxyResponse proxyResponse = new ProxyResponse();
+
+ if (response == null) {
+ proxyResponse.setCode(HandlerConstants.INTERNAL_ERROR_CODE);
+ proxyResponse.setExecutorResponse(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + getStatusKey(
+ HandlerConstants.INTERNAL_ERROR_CODE));
+ return proxyResponse;
+ } else {
+ int statusCode = response.getStatusLine().getStatusCode();
+ try (BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))) {
+ StringBuilder result = new StringBuilder();
+ String line;
+ while ((line = rd.readLine()) != null) {
+ result.append(line);
+ }
+
+ String jsonString = result.toString();
+ if (statusCode == HttpStatus.SC_OK || statusCode == HttpStatus.SC_CREATED) {
+ proxyResponse.setCode(statusCode);
+ proxyResponse.setData(jsonString);
+ proxyResponse.setExecutorResponse("SUCCESS");
+ return proxyResponse;
+ } else if (statusCode == HttpStatus.SC_UNAUTHORIZED) {
+ if (jsonString.contains("Access token expired") || jsonString
+ .contains("Invalid input. Access token validation failed")) {
+ proxyResponse.setCode(statusCode);
+ proxyResponse.setExecutorResponse("ACCESS_TOKEN_IS_EXPIRED");
+ return proxyResponse;
+ } else {
+ proxyResponse.setCode(statusCode);
+ proxyResponse.setData(jsonString);
+ proxyResponse.setExecutorResponse(
+ HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + getStatusKey(statusCode));
+ return proxyResponse;
+ }
+ }
+ proxyResponse.setCode(statusCode);
+ proxyResponse.setData(jsonString);
+ proxyResponse
+ .setExecutorResponse(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + getStatusKey(statusCode));
+ return proxyResponse;
+ }
+ }
+ }
+ }
+
+ /***
+ *
+ * @param statusCode Provide status code, e.g:- 400, 401, 500 etc
+ * @return relative status code key for given status code.
+ */
+ public static String getStatusKey (int statusCode){
+ String statusCodeKey;
+
+ switch (statusCode) {
+ case HttpStatus.SC_INTERNAL_SERVER_ERROR:
+ statusCodeKey = "internalServerError";
+ break;
+ case HttpStatus.SC_BAD_REQUEST:
+ statusCodeKey = "badRequest";
+ break;
+ case HttpStatus.SC_UNAUTHORIZED:
+ statusCodeKey = "unauthorized";
+ break;
+ case HttpStatus.SC_FORBIDDEN:
+ statusCodeKey = "forbidden";
+ break;
+ case HttpStatus.SC_NOT_FOUND:
+ statusCodeKey = "notFound";
+ break;
+ case HttpStatus.SC_METHOD_NOT_ALLOWED:
+ statusCodeKey = "methodNotAllowed";
+ break;
+ case HttpStatus.SC_NOT_ACCEPTABLE:
+ statusCodeKey = "notAcceptable";
+ break;
+ case HttpStatus.SC_UNSUPPORTED_MEDIA_TYPE:
+ statusCodeKey = "unsupportedMediaType";
+ break;
+ default:
+ statusCodeKey = "defaultPage";
+ break;
+ }
+ return statusCodeKey;
+ }
+
+
+ /***
+ *
+ * @param resp {@link HttpServletResponse}
+ * Return Error Response.
+ */
+ public static void handleError(HttpServletRequest req, HttpServletResponse resp, String serverUrl,
+ String platform, ProxyResponse proxyResponse) throws IOException {
+
+ HttpSession httpSession = req.getSession(true);
+ Gson gson = new Gson();
+ if (proxyResponse == null){
+ proxyResponse = new ProxyResponse();
+ proxyResponse.setCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
+ proxyResponse.setExecutorResponse(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + HandlerUtil
+ .getStatusKey(HandlerConstants.INTERNAL_ERROR_CODE));
+ }
+ if (platform == null){
+ platform = "default";
+ }
+
+ resp.setStatus(proxyResponse.getCode());
+ resp.setContentType("application/json");
+ resp.setCharacterEncoding("UTF-8");
+
+ if (httpSession != null) {
+ JsonObject uiConfig = (JsonObject) httpSession.getAttribute(HandlerConstants.UI_CONFIG_KEY);
+ if (uiConfig == null){
+ proxyResponse.setUrl(serverUrl + "/" + platform + HandlerConstants.DEFAULT_ERROR_CALLBACK);
+ } else{
+ proxyResponse.setUrl(serverUrl + uiConfig.get(HandlerConstants.LOGIN_RESPONSE_KEY).getAsJsonObject()
+ .get(HandlerConstants.FAILURE_CALLBACK_KEY).getAsJsonObject()
+ .get(proxyResponse.getExecutorResponse().split(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)[1])
+ .getAsString());
+ }
+ } else {
+ proxyResponse.setUrl(serverUrl + "/" + platform + HandlerConstants.DEFAULT_ERROR_CALLBACK);
+ }
+
+ proxyResponse.setExecutorResponse(null);
+ try (PrintWriter writer = resp.getWriter()) {
+ writer.write(gson.toJson(proxyResponse));
+ }
+ }
+
+ /***
+ *
+ * @param resp {@link HttpServletResponse}
+ * Return Success Response.
+ */
+ public static void handleSuccess(HttpServletRequest req, HttpServletResponse resp, String serverUrl,
+ String platform, ProxyResponse proxyResponse) throws IOException {
+ if (proxyResponse == null){
+ handleError(req,resp,serverUrl,platform,proxyResponse);
+ return;
+ }
+
+ resp.setStatus(proxyResponse.getCode());
+ resp.setContentType("application/json");
+ resp.setCharacterEncoding("UTF-8");
+
+ JSONObject response = new JSONObject();
+ String redirectUrl = proxyResponse.getUrl();
+ String responseData = proxyResponse.getData();
+
+ if (!StringUtils.isEmpty(redirectUrl)){
+ response.put("url", redirectUrl);
+ }
+ if (!StringUtils.isEmpty(responseData)){
+ try {
+ JSONObject responseDataJsonObj = new JSONObject(responseData);
+ response.put("data", responseDataJsonObj);
+ } catch (JSONException e) {
+ log.debug("Response data is not valid json string");
+ response.put("data", responseData);
+ }
+ }
+
+ try (PrintWriter writer = resp.getWriter()) {
+ writer.write(response.toString());
+ }
+ }
+
+}
diff --git a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/webapp/META-INF/webapp-classloading.xml b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/webapp/META-INF/webapp-classloading.xml
new file mode 100644
index 0000000000..cc5b3c66d7
--- /dev/null
+++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/webapp/META-INF/webapp-classloading.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+ false
+
+
+ Carbon
+
diff --git a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/webapp/WEB-INF/web.xml b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000000..066baa8fa6
--- /dev/null
+++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,103 @@
+
+
+
+ Entgra UI Request Interceptor Webapp
+
+ 60
+
+
+ doAuthentication
+ false
+
+
+
+
+ managed-api-enabled
+ false
+
+
+ managed-api-owner
+ admin
+
+
+ isSharedWithAllTenants
+ true
+
+
+
+ CorsFilter
+ org.apache.catalina.filters.CorsFilter
+
+ cors.allowed.origins
+ *
+
+
+ cors.allowed.methods
+ GET,POST,DELETE,PUT
+
+
+ cors.allowed.headers
+ Content-Type
+
+
+
+
+ HttpHeaderSecurityFilter
+ org.apache.catalina.filters.HttpHeaderSecurityFilter
+
+ hstsEnabled
+ false
+
+
+
+
+ ContentTypeBasedCachePreventionFilter
+ org.wso2.carbon.ui.filters.cache.ContentTypeBasedCachePreventionFilter
+
+ patterns
+ text/html" ,application/json" ,text/plain
+
+
+ filterAction
+ enforce
+
+
+ httpHeaders
+ Cache-Control: no-store, no-cache, must-revalidate, private
+
+
+
+
+ HttpHeaderSecurityFilter
+ /*
+
+
+
+ ContentTypeBasedCachePreventionFilter
+ /*
+
+
+
+ CorsFilter
+ /*
+
+
+
\ No newline at end of file
diff --git a/components/ui-request-interceptor/pom.xml b/components/ui-request-interceptor/pom.xml
new file mode 100644
index 0000000000..f362dfd78e
--- /dev/null
+++ b/components/ui-request-interceptor/pom.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+ carbon-devicemgt
+ org.wso2.carbon.devicemgt
+ 3.2.5-SNAPSHOT
+ ../../pom.xml
+
+ 4.0.0
+
+ io.entgra.devicemgt
+ ui-request-interceptor
+ Entgra - UI Request Interceptor Servlet
+
+ Proxy servlet to handle requests generated from UI applications to communicate with backend
+ APIs
+
+ pom
+
+ io.entgra.ui.request.interceptor
+
+
+
+
\ No newline at end of file
diff --git a/features/application-mgt/org.wso2.carbon.device.application.mgt.api.feature/pom.xml b/features/application-mgt/org.wso2.carbon.device.application.mgt.api.feature/pom.xml
index 1894f99265..b2a6ac81a6 100644
--- a/features/application-mgt/org.wso2.carbon.device.application.mgt.api.feature/pom.xml
+++ b/features/application-mgt/org.wso2.carbon.device.application.mgt.api.feature/pom.xml
@@ -86,29 +86,6 @@
-
- handler-copy
- package
-
- copy
-
-
-
-
- org.wso2.carbon.devicemgt
- org.wso2.carbon.device.application.mgt.handler
-
- ${project.version}
- war
- true
-
- ${project.build.directory}/maven-shared-archive-resources/webapps
-
- api#application-mgt-handler#v1.0.war
-
-
-
-
app-mgt-copy
package
diff --git a/features/application-mgt/org.wso2.carbon.device.application.mgt.api.feature/src/main/resources/p2.inf b/features/application-mgt/org.wso2.carbon.device.application.mgt.api.feature/src/main/resources/p2.inf
index 4b464ae7e7..5f658e814d 100644
--- a/features/application-mgt/org.wso2.carbon.device.application.mgt.api.feature/src/main/resources/p2.inf
+++ b/features/application-mgt/org.wso2.carbon.device.application.mgt.api.feature/src/main/resources/p2.inf
@@ -2,5 +2,4 @@ instructions.configure = \
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/webapps/);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.application.mgt.api_${feature.version}/webapps/api#application-mgt-publisher#v1.0.war,target:${installFolder}/../../deployment/server/webapps/api#application-mgt-publisher#v1.0.war,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.application.mgt.api_${feature.version}/webapps/api#application-mgt-store#v1.0.war,target:${installFolder}/../../deployment/server/webapps/api#application-mgt-store#v1.0.war,overwrite:true);\
-org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.application.mgt.api_${feature.version}/webapps/api#application-mgt-handler#v1.0.war,target:${installFolder}/../../deployment/server/webapps/api#application-mgt-handler#v1.0.war,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.application.mgt.api_${feature.version}/webapps/api#application-mgt#v1.0.war,target:${installFolder}/../../deployment/server/webapps/api#application-mgt#v1.0.war,overwrite:true);\
diff --git a/features/ui-request-interceptor/io.entgra.ui.request.interceptor.feature/pom.xml b/features/ui-request-interceptor/io.entgra.ui.request.interceptor.feature/pom.xml
new file mode 100644
index 0000000000..2080341a2d
--- /dev/null
+++ b/features/ui-request-interceptor/io.entgra.ui.request.interceptor.feature/pom.xml
@@ -0,0 +1,117 @@
+
+
+
+
+
+ ui-request-interceptor-feature
+ io.entgra.devicemgt
+ 3.2.5-SNAPSHOT
+
+ 4.0.0
+
+ io.entgra.ui.request.interceptor.feature
+ Entgra - UI Request Interceptor Feature
+
+ Proxy servlet to handle requests generated from UI applications to communicate with backend
+ APIs
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ request-handler-copy-war
+ package
+
+ copy
+
+
+
+
+ io.entgra.devicemgt
+ io.entgra.ui.request.interceptor
+ ${project.version}
+ war
+ true
+
+ ${project.build.directory}/maven-shared-archive-resources/webapps
+
+ ui-request-handler.war
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+
+
+ copy-resources
+ generate-resources
+
+ copy-resources
+
+
+ src/main/resources
+
+
+ resources
+
+ build.properties
+ p2.inf
+
+
+
+
+
+
+
+
+ org.wso2.maven
+ carbon-p2-plugin
+
+
+ p2-feature-generation
+ package
+
+ p2-feature-gen
+
+
+ io.entgra.ui.request.interceptor
+ ../../../features/etc/feature.properties
+
+
+ org.wso2.carbon.p2.category.type:server
+ org.eclipse.equinox.p2.type.group:false
+
+
+
+
+
+
+
+
+
diff --git a/features/ui-request-interceptor/io.entgra.ui.request.interceptor.feature/src/main/resources/build.properties b/features/ui-request-interceptor/io.entgra.ui.request.interceptor.feature/src/main/resources/build.properties
new file mode 100644
index 0000000000..fcc54d01b6
--- /dev/null
+++ b/features/ui-request-interceptor/io.entgra.ui.request.interceptor.feature/src/main/resources/build.properties
@@ -0,0 +1,3 @@
+instructions.configure = \
+org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/webapps/);\
+org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/io.entgra.ui.request.interceptor_${feature.version}/webapps/ui=request-handler.war,target:${installFolder}/../../deployment/server/webapps/ui=request-handler.war,overwrite:true);\
diff --git a/features/ui-request-interceptor/io.entgra.ui.request.interceptor.feature/src/main/resources/p2.inf b/features/ui-request-interceptor/io.entgra.ui.request.interceptor.feature/src/main/resources/p2.inf
new file mode 100644
index 0000000000..0875ae94ba
--- /dev/null
+++ b/features/ui-request-interceptor/io.entgra.ui.request.interceptor.feature/src/main/resources/p2.inf
@@ -0,0 +1,3 @@
+instructions.configure = \
+org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/webapps/);\
+org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/io.entgra.ui.request.interceptor_${feature.version}/webapps/ui-request-handler.war,target:${installFolder}/../../deployment/server/webapps/ui-request-handler.war,overwrite:true);\
diff --git a/features/ui-request-interceptor/pom.xml b/features/ui-request-interceptor/pom.xml
new file mode 100644
index 0000000000..dd3086e5d0
--- /dev/null
+++ b/features/ui-request-interceptor/pom.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+ carbon-devicemgt
+ org.wso2.carbon.devicemgt
+ 3.2.5-SNAPSHOT
+ ../../pom.xml
+
+ 4.0.0
+
+ io.entgra.devicemgt
+ ui-request-interceptor-feature
+ Entgra - UI Request Interceptor Feature
+
+ Proxy servlet to handle requests generated from UI applications to communicate with backend
+ APIs
+
+ pom
+
+ io.entgra.ui.request.interceptor.feature
+
+
diff --git a/pom.xml b/pom.xml
index e761f5ec6d..029e7a01d6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -44,6 +44,7 @@
components/certificate-mgt
components/webapp-authenticator-framework
components/email-sender
+ components/ui-request-interceptor
features/device-mgt
features/apimgt-extensions
features/application-mgt
@@ -52,6 +53,7 @@
features/certificate-mgt
features/oauth-extensions
features/email-sender
+ features/ui-request-interceptor
features/jwt-client
features/device-mgt-extensions