From 368186f573e61c63157c503fc5cabdb29288dad8 Mon Sep 17 00:00:00 2001 From: Madawa Soysa Date: Tue, 11 Jun 2019 11:22:16 +1000 Subject: [PATCH 1/2] Move App Manager Request Handler to a New Component Fixes entgra/product-iots#104 --- .../io.entgra.request.handler/pom.xml | 155 +++++++++ .../request/handler/InvokerHandler.java | 240 ++++++++++++++ .../entgra/request/handler/LoginHandler.java | 294 ++++++++++++++++++ .../request/handler/beans/AuthData.java | 89 ++++++ .../handler/exceptions/LoginException.java | 39 +++ .../handler/util/HandlerConstants.java | 45 +++ .../request/handler/util/HandlerUtil.java | 234 ++++++++++++++ .../webapp/META-INF/webapp-classloading.xml | 35 +++ .../src/main/webapp/WEB-INF/web.xml | 103 ++++++ components/request-handler/pom.xml | 40 +++ .../pom.xml | 23 -- .../src/main/resources/p2.inf | 1 - .../io.entgra.request.handler.feature/pom.xml | 112 +++++++ .../src/main/resources/build.properties | 1 + .../src/main/resources/p2.inf | 3 + features/request-handler/pom.xml | 40 +++ pom.xml | 2 + 17 files changed, 1432 insertions(+), 24 deletions(-) create mode 100644 components/request-handler/io.entgra.request.handler/pom.xml create mode 100644 components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/InvokerHandler.java create mode 100644 components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/LoginHandler.java create mode 100644 components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/beans/AuthData.java create mode 100644 components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/exceptions/LoginException.java create mode 100644 components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/util/HandlerConstants.java create mode 100644 components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/util/HandlerUtil.java create mode 100644 components/request-handler/io.entgra.request.handler/src/main/webapp/META-INF/webapp-classloading.xml create mode 100644 components/request-handler/io.entgra.request.handler/src/main/webapp/WEB-INF/web.xml create mode 100644 components/request-handler/pom.xml create mode 100644 features/request-handler/io.entgra.request.handler.feature/pom.xml create mode 100644 features/request-handler/io.entgra.request.handler.feature/src/main/resources/build.properties create mode 100644 features/request-handler/io.entgra.request.handler.feature/src/main/resources/p2.inf create mode 100644 features/request-handler/pom.xml diff --git a/components/request-handler/io.entgra.request.handler/pom.xml b/components/request-handler/io.entgra.request.handler/pom.xml new file mode 100644 index 0000000000..88f207fd96 --- /dev/null +++ b/components/request-handler/io.entgra.request.handler/pom.xml @@ -0,0 +1,155 @@ + + + + + + request-handler + io.entgra.devicemgt + 3.2.5-SNAPSHOT + + 4.0.0 + + io.entgra.request.handler + + 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 + api#application-mgt-handler#v1.0 + + + + + + + + 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/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/InvokerHandler.java b/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/InvokerHandler.java new file mode 100644 index 0000000000..cff1725b50 --- /dev/null +++ b/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/InvokerHandler.java @@ -0,0 +1,240 @@ +/* + * 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.request.handler; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import io.entgra.request.handler.beans.AuthData; +import io.entgra.request.handler.util.HandlerConstants; +import io.entgra.request.handler.util.HandlerUtil; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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.entity.ContentType; +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 static io.entgra.request.handler.util.HandlerUtil.execute; +import static java.net.HttpURLConnection.HTTP_BAD_REQUEST; + +@MultipartConfig +@WebServlet("/invoke") +public class InvokerHandler extends HttpServlet { + private static final Log log = LogFactory.getLog(LoginHandler.class); + private static final long serialVersionUID = -6508020875358160165L; + private static AuthData authData; + private static String apiEndpoint; + private static String method; + private static String serverUrl; + private static String platform; + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) { + try { + if (!validateRequest(req, resp)) { + return; + } + HttpRequestBase executor = constructExecutor(req); + if (executor == null) { + resp.sendError(HTTP_BAD_REQUEST, "Bad Request, method: " + method + " is not supported"); + return; + } + executor.setHeader(HandlerConstants.AUTHORIZATION_HEADER_KEY, "Bearer " + authData.getAccessToken()); + ProxyResponse proxyResponse = execute(executor); + + if (HandlerConstants.TOKEN_IS_EXPIRED.equals(proxyResponse.getExecutorResponse())) { + if (!refreshToken(req, resp)) { + return; + } + executor.setHeader(HandlerConstants.AUTHORIZATION_HEADER_KEY, "Bearer " + authData.getAccessToken()); + proxyResponse = execute(executor); + 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; + } + } + 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 occured when processing invoke call.", e); + } + } + + /*** + * + * @param req {@link HttpServletRequest} + * @return {@link HttpRequestBase} if method equals to either GET, POST, PUT or DELETE otherwise returns NULL. + */ + private HttpRequestBase constructExecutor(HttpServletRequest req) { + String payload = req.getParameter("payload"); + String contentType = req.getParameter("content-type"); + if (contentType == null || contentType.isEmpty()) { + contentType = ContentType.APPLICATION_JSON.toString(); + } + + HttpRequestBase executor; + if (HttpGet.METHOD_NAME.equalsIgnoreCase(method)) { + executor = new HttpGet(serverUrl + HandlerConstants.API_COMMON_CONTEXT + apiEndpoint); + } else if (HttpPost.METHOD_NAME.equalsIgnoreCase(method)) { + executor = new HttpPost(serverUrl + HandlerConstants.API_COMMON_CONTEXT + apiEndpoint); + StringEntity payloadEntity = new StringEntity(payload, ContentType.create(contentType)); + ((HttpPost) executor).setEntity(payloadEntity); + } else if (HttpPut.METHOD_NAME.equalsIgnoreCase(method)) { + executor = new HttpPut(serverUrl + HandlerConstants.API_COMMON_CONTEXT + apiEndpoint); + StringEntity payloadEntity = new StringEntity(payload, ContentType.create(contentType)); + ((HttpPut) executor).setEntity(payloadEntity); + } else if (HttpDelete.METHOD_NAME.equalsIgnoreCase(method)) { + executor = new HttpDelete(serverUrl + HandlerConstants.API_COMMON_CONTEXT + apiEndpoint); + } else { + return null; + } + return executor; + } + + /*** + * + * @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.getParameter("api-endpoint"); + method = req.getParameter("method"); + 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 couldn't 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 || method == null) { + log.error("Bad Request, Either 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; + } + + /*** + * + * @param req {@link HttpServletRequest} + * @param resp {@link HttpServletResponse} + * @return If successfully renew tokens, returns TRUE otherwise return FALSE + * @throws IOException If and error occurs while witting error response to client side or invoke token renewal API + */ + private static boolean refreshToken(HttpServletRequest req, HttpServletResponse resp) throws IOException { + 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("Authorization", "Basic " + encodedClientApp); + tokenEndpoint.setHeader("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/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/LoginHandler.java b/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/LoginHandler.java new file mode 100644 index 0000000000..051ee35504 --- /dev/null +++ b/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/LoginHandler.java @@ -0,0 +1,294 @@ +/* + * 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.request.handler; + +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.request.handler.beans.AuthData; +import io.entgra.request.handler.exceptions.LoginException; +import io.entgra.request.handler.util.HandlerConstants; +import io.entgra.request.handler.util.HandlerUtil; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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.request.handler.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(HandlerConstants.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/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/beans/AuthData.java b/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/beans/AuthData.java new file mode 100644 index 0000000000..3ad73d6e8e --- /dev/null +++ b/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/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.request.handler.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/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/exceptions/LoginException.java b/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/exceptions/LoginException.java new file mode 100644 index 0000000000..d792924fa4 --- /dev/null +++ b/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/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.request.handler.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/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/util/HandlerConstants.java b/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/util/HandlerConstants.java new file mode 100644 index 0000000000..6088adfae7 --- /dev/null +++ b/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/util/HandlerConstants.java @@ -0,0 +1,45 @@ +/* + * 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.request.handler.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 AUTHORIZATION = "Authorization"; + public static final String BASIC = "Basic "; + 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 AUTHORIZATION_HEADER_KEY = "Authorization"; + 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/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/util/HandlerUtil.java b/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/util/HandlerUtil.java new file mode 100644 index 0000000000..357a9ac1ed --- /dev/null +++ b/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/util/HandlerUtil.java @@ -0,0 +1,234 @@ +/* + * 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.request.handler.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.HttpGet; +import org.apache.http.client.methods.HttpPost; +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 httpMethod - httpMethod e.g:- HttpPost, HttpGet + * @param - HttpPost or HttpGet class + * @return response as string + * @throws IOException IO exception returns if error occurs when executing the httpMethod + */ + public static ProxyResponse execute(T httpMethod) throws IOException { + try (CloseableHttpClient client = HttpClients.createDefault()) { + HttpResponse response = null; + if (httpMethod instanceof HttpPost) { + HttpPost method = (HttpPost) httpMethod; + response = client.execute(method); + } else if (httpMethod instanceof HttpGet) { + HttpGet method = (HttpGet) httpMethod; + response = client.execute(method); + } + + 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/request-handler/io.entgra.request.handler/src/main/webapp/META-INF/webapp-classloading.xml b/components/request-handler/io.entgra.request.handler/src/main/webapp/META-INF/webapp-classloading.xml new file mode 100644 index 0000000000..cc5b3c66d7 --- /dev/null +++ b/components/request-handler/io.entgra.request.handler/src/main/webapp/META-INF/webapp-classloading.xml @@ -0,0 +1,35 @@ + + + + + + + + + false + + + Carbon + diff --git a/components/request-handler/io.entgra.request.handler/src/main/webapp/WEB-INF/web.xml b/components/request-handler/io.entgra.request.handler/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..c4e45edcf6 --- /dev/null +++ b/components/request-handler/io.entgra.request.handler/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,103 @@ + + + + Entgra Request Handler 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/request-handler/pom.xml b/components/request-handler/pom.xml new file mode 100644 index 0000000000..19004986bb --- /dev/null +++ b/components/request-handler/pom.xml @@ -0,0 +1,40 @@ + + + + + + carbon-devicemgt + org.wso2.carbon.devicemgt + 3.2.5-SNAPSHOT + ../../pom.xml + + 4.0.0 + + io.entgra.devicemgt + request-handler + Entgra - Request Handling Proxy + pom + + io.entgra.request.handler + + + + \ 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/request-handler/io.entgra.request.handler.feature/pom.xml b/features/request-handler/io.entgra.request.handler.feature/pom.xml new file mode 100644 index 0000000000..13b2fa10d3 --- /dev/null +++ b/features/request-handler/io.entgra.request.handler.feature/pom.xml @@ -0,0 +1,112 @@ + + + + + + request-handler-feature + io.entgra.devicemgt + 3.2.5-SNAPSHOT + + 4.0.0 + + io.entgra.request.handler.feature + Entgra - Request Handling Proxy Feature + + + + org.apache.maven.plugins + maven-dependency-plugin + + + request-handler-copy + package + + copy + + + + + io.entgra.devicemgt + io.entgra.request.handler + ${project.version} + war + true + + ${project.build.directory}/maven-shared-archive-resources/webapps + + api#application-mgt-handler#v1.0.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.request.handler + ../../../features/etc/feature.properties + + + org.wso2.carbon.p2.category.type:server + org.eclipse.equinox.p2.type.group:false + + + + + + + + + \ No newline at end of file diff --git a/features/request-handler/io.entgra.request.handler.feature/src/main/resources/build.properties b/features/request-handler/io.entgra.request.handler.feature/src/main/resources/build.properties new file mode 100644 index 0000000000..9c86577d76 --- /dev/null +++ b/features/request-handler/io.entgra.request.handler.feature/src/main/resources/build.properties @@ -0,0 +1 @@ +custom = true diff --git a/features/request-handler/io.entgra.request.handler.feature/src/main/resources/p2.inf b/features/request-handler/io.entgra.request.handler.feature/src/main/resources/p2.inf new file mode 100644 index 0000000000..4b6600f708 --- /dev/null +++ b/features/request-handler/io.entgra.request.handler.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.request.handler_${feature.version}/webapps/api#application-mgt-handler#v1.0.war,target:${installFolder}/../../deployment/server/webapps/api#application-mgt-handler#v1.0.war,overwrite:true);\ diff --git a/features/request-handler/pom.xml b/features/request-handler/pom.xml new file mode 100644 index 0000000000..33c8984d0c --- /dev/null +++ b/features/request-handler/pom.xml @@ -0,0 +1,40 @@ + + + + + + carbon-devicemgt + org.wso2.carbon.devicemgt + 3.2.5-SNAPSHOT + ../../pom.xml + + 4.0.0 + + io.entgra.devicemgt + request-handler-feature + Entgra - Request Handling Proxy Feature + pom + + io.entgra.request.handler.feature + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index e761f5ec6d..a4e06e74b4 100644 --- a/pom.xml +++ b/pom.xml @@ -44,6 +44,7 @@ components/certificate-mgt components/webapp-authenticator-framework components/email-sender + components/request-handler features/device-mgt features/apimgt-extensions features/application-mgt @@ -52,6 +53,7 @@ features/certificate-mgt features/oauth-extensions features/email-sender + features/request-handler features/jwt-client features/device-mgt-extensions From 2260bd004d120c237da9b44718ecd9c319f6ff23 Mon Sep 17 00:00:00 2001 From: Madawa Soysa Date: Mon, 17 Jun 2019 15:58:44 +1000 Subject: [PATCH 2/2] Implement GET/POST/PUT/DELETE methods and refactor module name This commit implements the related HTTP methods in the request interceptor servlet to intercept and send the request to the backend. Also refactored the module name request-handler -> ui-request-interceptor. Fixes entgra/product-iots#108 --- .../request/handler/InvokerHandler.java | 240 ------------ .../io.entgra.ui.request.interceptor}/pom.xml | 8 +- .../request/interceptor/InvokerHandler.java | 362 ++++++++++++++++++ .../ui/request/interceptor}/LoginHandler.java | 15 +- .../request/interceptor}/beans/AuthData.java | 2 +- .../exceptions/LoginException.java | 2 +- .../interceptor}/util/HandlerConstants.java | 7 +- .../interceptor}/util/HandlerUtil.java | 21 +- .../webapp/META-INF/webapp-classloading.xml | 0 .../src/main/webapp/WEB-INF/web.xml | 2 +- .../ui-request-interceptor}/pom.xml | 10 +- .../src/main/resources/build.properties | 1 - .../src/main/resources/p2.inf | 3 - .../pom.xml | 21 +- .../src/main/resources/build.properties | 3 + .../src/main/resources/p2.inf | 3 + .../ui-request-interceptor}/pom.xml | 14 +- pom.xml | 4 +- 18 files changed, 423 insertions(+), 295 deletions(-) delete mode 100644 components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/InvokerHandler.java rename components/{request-handler/io.entgra.request.handler => ui-request-interceptor/io.entgra.ui.request.interceptor}/pom.xml (95%) create mode 100644 components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/InvokerHandler.java rename components/{request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler => ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor}/LoginHandler.java (96%) rename components/{request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler => ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor}/beans/AuthData.java (97%) rename components/{request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler => ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor}/exceptions/LoginException.java (95%) rename components/{request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler => ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor}/util/HandlerConstants.java (90%) rename components/{request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler => ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor}/util/HandlerUtil.java (92%) rename components/{request-handler/io.entgra.request.handler => ui-request-interceptor/io.entgra.ui.request.interceptor}/src/main/webapp/META-INF/webapp-classloading.xml (100%) rename components/{request-handler/io.entgra.request.handler => ui-request-interceptor/io.entgra.ui.request.interceptor}/src/main/webapp/WEB-INF/web.xml (97%) rename {features/request-handler => components/ui-request-interceptor}/pom.xml (80%) delete mode 100644 features/request-handler/io.entgra.request.handler.feature/src/main/resources/build.properties delete mode 100644 features/request-handler/io.entgra.request.handler.feature/src/main/resources/p2.inf rename features/{request-handler/io.entgra.request.handler.feature => ui-request-interceptor/io.entgra.ui.request.interceptor.feature}/pom.xml (87%) create mode 100644 features/ui-request-interceptor/io.entgra.ui.request.interceptor.feature/src/main/resources/build.properties create mode 100644 features/ui-request-interceptor/io.entgra.ui.request.interceptor.feature/src/main/resources/p2.inf rename {components/request-handler => features/ui-request-interceptor}/pom.xml (79%) diff --git a/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/InvokerHandler.java b/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/InvokerHandler.java deleted file mode 100644 index cff1725b50..0000000000 --- a/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/InvokerHandler.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * 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.request.handler; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import io.entgra.request.handler.beans.AuthData; -import io.entgra.request.handler.util.HandlerConstants; -import io.entgra.request.handler.util.HandlerUtil; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -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.entity.ContentType; -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 static io.entgra.request.handler.util.HandlerUtil.execute; -import static java.net.HttpURLConnection.HTTP_BAD_REQUEST; - -@MultipartConfig -@WebServlet("/invoke") -public class InvokerHandler extends HttpServlet { - private static final Log log = LogFactory.getLog(LoginHandler.class); - private static final long serialVersionUID = -6508020875358160165L; - private static AuthData authData; - private static String apiEndpoint; - private static String method; - private static String serverUrl; - private static String platform; - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) { - try { - if (!validateRequest(req, resp)) { - return; - } - HttpRequestBase executor = constructExecutor(req); - if (executor == null) { - resp.sendError(HTTP_BAD_REQUEST, "Bad Request, method: " + method + " is not supported"); - return; - } - executor.setHeader(HandlerConstants.AUTHORIZATION_HEADER_KEY, "Bearer " + authData.getAccessToken()); - ProxyResponse proxyResponse = execute(executor); - - if (HandlerConstants.TOKEN_IS_EXPIRED.equals(proxyResponse.getExecutorResponse())) { - if (!refreshToken(req, resp)) { - return; - } - executor.setHeader(HandlerConstants.AUTHORIZATION_HEADER_KEY, "Bearer " + authData.getAccessToken()); - proxyResponse = execute(executor); - 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; - } - } - 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 occured when processing invoke call.", e); - } - } - - /*** - * - * @param req {@link HttpServletRequest} - * @return {@link HttpRequestBase} if method equals to either GET, POST, PUT or DELETE otherwise returns NULL. - */ - private HttpRequestBase constructExecutor(HttpServletRequest req) { - String payload = req.getParameter("payload"); - String contentType = req.getParameter("content-type"); - if (contentType == null || contentType.isEmpty()) { - contentType = ContentType.APPLICATION_JSON.toString(); - } - - HttpRequestBase executor; - if (HttpGet.METHOD_NAME.equalsIgnoreCase(method)) { - executor = new HttpGet(serverUrl + HandlerConstants.API_COMMON_CONTEXT + apiEndpoint); - } else if (HttpPost.METHOD_NAME.equalsIgnoreCase(method)) { - executor = new HttpPost(serverUrl + HandlerConstants.API_COMMON_CONTEXT + apiEndpoint); - StringEntity payloadEntity = new StringEntity(payload, ContentType.create(contentType)); - ((HttpPost) executor).setEntity(payloadEntity); - } else if (HttpPut.METHOD_NAME.equalsIgnoreCase(method)) { - executor = new HttpPut(serverUrl + HandlerConstants.API_COMMON_CONTEXT + apiEndpoint); - StringEntity payloadEntity = new StringEntity(payload, ContentType.create(contentType)); - ((HttpPut) executor).setEntity(payloadEntity); - } else if (HttpDelete.METHOD_NAME.equalsIgnoreCase(method)) { - executor = new HttpDelete(serverUrl + HandlerConstants.API_COMMON_CONTEXT + apiEndpoint); - } else { - return null; - } - return executor; - } - - /*** - * - * @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.getParameter("api-endpoint"); - method = req.getParameter("method"); - 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 couldn't 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 || method == null) { - log.error("Bad Request, Either 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; - } - - /*** - * - * @param req {@link HttpServletRequest} - * @param resp {@link HttpServletResponse} - * @return If successfully renew tokens, returns TRUE otherwise return FALSE - * @throws IOException If and error occurs while witting error response to client side or invoke token renewal API - */ - private static boolean refreshToken(HttpServletRequest req, HttpServletResponse resp) throws IOException { - 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("Authorization", "Basic " + encodedClientApp); - tokenEndpoint.setHeader("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/request-handler/io.entgra.request.handler/pom.xml b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/pom.xml similarity index 95% rename from components/request-handler/io.entgra.request.handler/pom.xml rename to components/ui-request-interceptor/io.entgra.ui.request.interceptor/pom.xml index 88f207fd96..16090c509e 100644 --- a/components/request-handler/io.entgra.request.handler/pom.xml +++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/pom.xml @@ -21,13 +21,13 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - request-handler + ui-request-interceptor io.entgra.devicemgt 3.2.5-SNAPSHOT 4.0.0 - io.entgra.request.handler + io.entgra.ui.request.interceptor 3.2.5-SNAPSHOT war @@ -41,7 +41,7 @@ maven-war-plugin WEB-INF/lib/*cxf*.jar - api#application-mgt-handler#v1.0 + ui-request-handler @@ -66,7 +66,7 @@ - + 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/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/LoginHandler.java b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/LoginHandler.java similarity index 96% rename from components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/LoginHandler.java rename to components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/LoginHandler.java index 051ee35504..5f1167073d 100644 --- a/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/LoginHandler.java +++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/LoginHandler.java @@ -16,20 +16,21 @@ * under the License. */ -package io.entgra.request.handler; +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.request.handler.beans.AuthData; -import io.entgra.request.handler.exceptions.LoginException; -import io.entgra.request.handler.util.HandlerConstants; -import io.entgra.request.handler.util.HandlerUtil; +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; @@ -49,7 +50,7 @@ import javax.servlet.http.HttpSession; import java.io.IOException; import java.util.Base64; -import static io.entgra.request.handler.util.HandlerUtil.execute; +import static io.entgra.ui.request.interceptor.util.HandlerUtil.execute; @MultipartConfig @WebServlet("/login") @@ -120,7 +121,7 @@ public class LoginHandler extends HttpServlet { } else { // default login HttpPost apiRegEndpoint = new HttpPost(serverUrl + HandlerConstants.APP_REG_ENDPOINT); - apiRegEndpoint.setHeader(HandlerConstants.AUTHORIZATION, HandlerConstants.BASIC + Base64.getEncoder() + 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)); diff --git a/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/beans/AuthData.java b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/beans/AuthData.java similarity index 97% rename from components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/beans/AuthData.java rename to components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/beans/AuthData.java index 3ad73d6e8e..be6a8b570b 100644 --- a/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/beans/AuthData.java +++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/beans/AuthData.java @@ -16,7 +16,7 @@ * under the License. */ -package io.entgra.request.handler.beans; +package io.entgra.ui.request.interceptor.beans; public class AuthData implements java.io.Serializable { diff --git a/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/exceptions/LoginException.java b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/exceptions/LoginException.java similarity index 95% rename from components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/exceptions/LoginException.java rename to components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/exceptions/LoginException.java index d792924fa4..b33b74da73 100644 --- a/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/exceptions/LoginException.java +++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/exceptions/LoginException.java @@ -16,7 +16,7 @@ * under the License. */ -package io.entgra.request.handler.exceptions; +package io.entgra.ui.request.interceptor.exceptions; public class LoginException extends Exception { public LoginException(String message) { diff --git a/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/util/HandlerConstants.java b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerConstants.java similarity index 90% rename from components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/util/HandlerConstants.java rename to components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerConstants.java index 6088adfae7..aa80d7fd66 100644 --- a/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/util/HandlerConstants.java +++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerConstants.java @@ -16,20 +16,21 @@ * under the License. */ -package io.entgra.request.handler.util; +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 AUTHORIZATION = "Authorization"; + 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 AUTHORIZATION_HEADER_KEY = "Authorization"; public static final String UI_CONFIG_KEY = "ui-config"; public static final String PLATFORM = "platform"; public static final String SERVER_HOST = "server-host"; diff --git a/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/util/HandlerUtil.java b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerUtil.java similarity index 92% rename from components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/util/HandlerUtil.java rename to components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerUtil.java index 357a9ac1ed..f3baea315f 100644 --- a/components/request-handler/io.entgra.request.handler/src/main/java/io/entgra/request/handler/util/HandlerUtil.java +++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerUtil.java @@ -16,7 +16,7 @@ * under the License. */ -package io.entgra.request.handler.util; +package io.entgra.ui.request.interceptor.util; import com.google.gson.Gson; import com.google.gson.JsonObject; @@ -25,8 +25,7 @@ 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.HttpGet; -import org.apache.http.client.methods.HttpPost; +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; @@ -47,23 +46,15 @@ public class HandlerUtil { /*** * - * @param httpMethod - httpMethod e.g:- HttpPost, HttpGet - * @param - HttpPost or HttpGet 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(T httpMethod) throws IOException { + public static ProxyResponse execute(HttpRequestBase httpRequest) throws IOException { try (CloseableHttpClient client = HttpClients.createDefault()) { - HttpResponse response = null; - if (httpMethod instanceof HttpPost) { - HttpPost method = (HttpPost) httpMethod; - response = client.execute(method); - } else if (httpMethod instanceof HttpGet) { - HttpGet method = (HttpGet) httpMethod; - response = client.execute(method); - } - + 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( diff --git a/components/request-handler/io.entgra.request.handler/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 similarity index 100% rename from components/request-handler/io.entgra.request.handler/src/main/webapp/META-INF/webapp-classloading.xml rename to components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/webapp/META-INF/webapp-classloading.xml diff --git a/components/request-handler/io.entgra.request.handler/src/main/webapp/WEB-INF/web.xml b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/webapp/WEB-INF/web.xml similarity index 97% rename from components/request-handler/io.entgra.request.handler/src/main/webapp/WEB-INF/web.xml rename to components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/webapp/WEB-INF/web.xml index c4e45edcf6..066baa8fa6 100644 --- a/components/request-handler/io.entgra.request.handler/src/main/webapp/WEB-INF/web.xml +++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/webapp/WEB-INF/web.xml @@ -19,7 +19,7 @@ - Entgra Request Handler Webapp + Entgra UI Request Interceptor Webapp 60 diff --git a/features/request-handler/pom.xml b/components/ui-request-interceptor/pom.xml similarity index 80% rename from features/request-handler/pom.xml rename to components/ui-request-interceptor/pom.xml index 33c8984d0c..f362dfd78e 100644 --- a/features/request-handler/pom.xml +++ b/components/ui-request-interceptor/pom.xml @@ -29,11 +29,15 @@ 4.0.0 io.entgra.devicemgt - request-handler-feature - Entgra - Request Handling Proxy Feature + 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.request.handler.feature + io.entgra.ui.request.interceptor diff --git a/features/request-handler/io.entgra.request.handler.feature/src/main/resources/build.properties b/features/request-handler/io.entgra.request.handler.feature/src/main/resources/build.properties deleted file mode 100644 index 9c86577d76..0000000000 --- a/features/request-handler/io.entgra.request.handler.feature/src/main/resources/build.properties +++ /dev/null @@ -1 +0,0 @@ -custom = true diff --git a/features/request-handler/io.entgra.request.handler.feature/src/main/resources/p2.inf b/features/request-handler/io.entgra.request.handler.feature/src/main/resources/p2.inf deleted file mode 100644 index 4b6600f708..0000000000 --- a/features/request-handler/io.entgra.request.handler.feature/src/main/resources/p2.inf +++ /dev/null @@ -1,3 +0,0 @@ -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.request.handler_${feature.version}/webapps/api#application-mgt-handler#v1.0.war,target:${installFolder}/../../deployment/server/webapps/api#application-mgt-handler#v1.0.war,overwrite:true);\ diff --git a/features/request-handler/io.entgra.request.handler.feature/pom.xml b/features/ui-request-interceptor/io.entgra.ui.request.interceptor.feature/pom.xml similarity index 87% rename from features/request-handler/io.entgra.request.handler.feature/pom.xml rename to features/ui-request-interceptor/io.entgra.ui.request.interceptor.feature/pom.xml index 13b2fa10d3..2080341a2d 100644 --- a/features/request-handler/io.entgra.request.handler.feature/pom.xml +++ b/features/ui-request-interceptor/io.entgra.ui.request.interceptor.feature/pom.xml @@ -21,14 +21,19 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - request-handler-feature + ui-request-interceptor-feature io.entgra.devicemgt 3.2.5-SNAPSHOT 4.0.0 - io.entgra.request.handler.feature - Entgra - Request Handling Proxy Feature + 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 + + @@ -36,7 +41,7 @@ maven-dependency-plugin - request-handler-copy + request-handler-copy-war package copy @@ -45,14 +50,14 @@ io.entgra.devicemgt - io.entgra.request.handler + io.entgra.ui.request.interceptor ${project.version} war true ${project.build.directory}/maven-shared-archive-resources/webapps - api#application-mgt-handler#v1.0.war + ui-request-handler.war @@ -95,7 +100,7 @@ p2-feature-gen - io.entgra.request.handler + io.entgra.ui.request.interceptor ../../../features/etc/feature.properties @@ -109,4 +114,4 @@ - \ No newline at end of file + 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/components/request-handler/pom.xml b/features/ui-request-interceptor/pom.xml similarity index 79% rename from components/request-handler/pom.xml rename to features/ui-request-interceptor/pom.xml index 19004986bb..dd3086e5d0 100644 --- a/components/request-handler/pom.xml +++ b/features/ui-request-interceptor/pom.xml @@ -29,12 +29,14 @@ 4.0.0 io.entgra.devicemgt - request-handler - Entgra - Request Handling Proxy + 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.request.handler + io.entgra.ui.request.interceptor.feature - - - \ No newline at end of file + diff --git a/pom.xml b/pom.xml index a4e06e74b4..029e7a01d6 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ components/certificate-mgt components/webapp-authenticator-framework components/email-sender - components/request-handler + components/ui-request-interceptor features/device-mgt features/apimgt-extensions features/application-mgt @@ -53,7 +53,7 @@ features/certificate-mgt features/oauth-extensions features/email-sender - features/request-handler + features/ui-request-interceptor features/jwt-client features/device-mgt-extensions