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 00000000000..88f207fd963
--- /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 00000000000..cff1725b50d
--- /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 00000000000..051ee355044
--- /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 00000000000..3ad73d6e8ea
--- /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 00000000000..d792924fa48
--- /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 00000000000..6088adfae7f
--- /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 00000000000..357a9ac1ed1
--- /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 00000000000..cc5b3c66d7c
--- /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 00000000000..c4e45edcf61
--- /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 00000000000..19004986bb9
--- /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 1894f992657..b2a6ac81a65 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 4b464ae7e76..5f658e814db 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 00000000000..13b2fa10d3d
--- /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 00000000000..9c86577d768
--- /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 00000000000..4b6600f7083
--- /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 00000000000..33c8984d0ce
--- /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 e761f5ec6d7..a4e06e74b43 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