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
feature/appm-store/pbac
Madawa Soysa 6 years ago
parent 368186f573
commit 2260bd004d

@ -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;
}
}

@ -21,13 +21,13 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>request-handler</artifactId> <artifactId>ui-request-interceptor</artifactId>
<groupId>io.entgra.devicemgt</groupId> <groupId>io.entgra.devicemgt</groupId>
<version>3.2.5-SNAPSHOT</version> <version>3.2.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>io.entgra.request.handler</artifactId> <artifactId>io.entgra.ui.request.interceptor</artifactId>
<version>3.2.5-SNAPSHOT</version> <version>3.2.5-SNAPSHOT</version>
<packaging>war</packaging> <packaging>war</packaging>
@ -41,7 +41,7 @@
<artifactId>maven-war-plugin</artifactId> <artifactId>maven-war-plugin</artifactId>
<configuration> <configuration>
<packagingExcludes>WEB-INF/lib/*cxf*.jar</packagingExcludes> <packagingExcludes>WEB-INF/lib/*cxf*.jar</packagingExcludes>
<warName>api#application-mgt-handler#v1.0</warName> <warName>ui-request-handler</warName>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
@ -66,7 +66,7 @@
<tasks> <tasks>
<copy todir="${basedir}/../../../repository/deployment/server/webapps" overwrite="true"> <copy todir="${basedir}/../../../repository/deployment/server/webapps" overwrite="true">
<fileset dir="${basedir}/target"> <fileset dir="${basedir}/target">
<include name="api#application-mgt-handler#v1.0.war" /> <include name="ui-request-handler.war" />
</fileset> </fileset>
</copy> </copy>
</tasks> </tasks>

@ -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<String> headerNames = req.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
if (headerName.equalsIgnoreCase(HttpHeaders.CONTENT_LENGTH) ||
headerName.equalsIgnoreCase(SM.COOKIE)) {
continue;
}
Enumeration<String> 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 <code>null</code> 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;
}
}

@ -16,20 +16,21 @@
* under the License. * under the License.
*/ */
package io.entgra.request.handler; package io.entgra.ui.request.interceptor;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import io.entgra.request.handler.beans.AuthData; import io.entgra.ui.request.interceptor.beans.AuthData;
import io.entgra.request.handler.exceptions.LoginException; import io.entgra.ui.request.interceptor.exceptions.LoginException;
import io.entgra.request.handler.util.HandlerConstants; import io.entgra.ui.request.interceptor.util.HandlerConstants;
import io.entgra.request.handler.util.HandlerUtil; import io.entgra.ui.request.interceptor.util.HandlerUtil;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
@ -49,7 +50,7 @@ import javax.servlet.http.HttpSession;
import java.io.IOException; import java.io.IOException;
import java.util.Base64; import java.util.Base64;
import static io.entgra.request.handler.util.HandlerUtil.execute; import static io.entgra.ui.request.interceptor.util.HandlerUtil.execute;
@MultipartConfig @MultipartConfig
@WebServlet("/login") @WebServlet("/login")
@ -120,7 +121,7 @@ public class LoginHandler extends HttpServlet {
} else { } else {
// default login // default login
HttpPost apiRegEndpoint = new HttpPost(serverUrl + HandlerConstants.APP_REG_ENDPOINT); 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())); .encodeToString((adminUsername + HandlerConstants.COLON + adminPwd).getBytes()));
apiRegEndpoint.setHeader(HTTP.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()); apiRegEndpoint.setHeader(HTTP.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString());
apiRegEndpoint.setEntity(constructAppRegPayload(tags)); apiRegEndpoint.setEntity(constructAppRegPayload(tags));

@ -16,7 +16,7 @@
* under the License. * under the License.
*/ */
package io.entgra.request.handler.beans; package io.entgra.ui.request.interceptor.beans;
public class AuthData implements java.io.Serializable { public class AuthData implements java.io.Serializable {

@ -16,7 +16,7 @@
* under the License. * under the License.
*/ */
package io.entgra.request.handler.exceptions; package io.entgra.ui.request.interceptor.exceptions;
public class LoginException extends Exception { public class LoginException extends Exception {
public LoginException(String message) { public LoginException(String message) {

@ -16,20 +16,21 @@
* under the License. * under the License.
*/ */
package io.entgra.request.handler.util; package io.entgra.ui.request.interceptor.util;
public class HandlerConstants { public class HandlerConstants {
public static final String PUBLISHER_APPLICATION_NAME = "application-mgt-publisher"; 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 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 UI_CONFIG_ENDPOINT = "/api/application-mgt/v1.0/config/ui-config";
public static final String TOKEN_ENDPOINT = "/oauth2/token"; 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 BASIC = "Basic ";
public static final String BEARER = "Bearer ";
public static final String COLON = ":"; public static final String COLON = ":";
public static final String TAGS_KEY = "tags"; public static final String TAGS_KEY = "tags";
public static final String APP_NAME_KEY = "applicationName"; public static final String APP_NAME_KEY = "applicationName";
public static final String SESSION_AUTH_DATA_KEY = "application-mgt"; 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 UI_CONFIG_KEY = "ui-config";
public static final String PLATFORM = "platform"; public static final String PLATFORM = "platform";
public static final String SERVER_HOST = "server-host"; public static final String SERVER_HOST = "server-host";

@ -16,7 +16,7 @@
* under the License. * 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.Gson;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
@ -25,8 +25,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.HttpClients;
import org.json.JSONException; import org.json.JSONException;
@ -47,23 +46,15 @@ public class HandlerUtil {
/*** /***
* *
* @param httpMethod - httpMethod e.g:- HttpPost, HttpGet * @param httpRequest - httpMethod e.g:- HttpPost, HttpGet
* @param <T> - HttpPost or HttpGet class
* @return response as string * @return response as string
* @throws IOException IO exception returns if error occurs when executing the httpMethod * @throws IOException IO exception returns if error occurs when executing the httpMethod
*/ */
public static <T> ProxyResponse execute(T httpMethod) throws IOException { public static ProxyResponse execute(HttpRequestBase httpRequest) throws IOException {
try (CloseableHttpClient client = HttpClients.createDefault()) { try (CloseableHttpClient client = HttpClients.createDefault()) {
HttpResponse response = null; HttpResponse response = client.execute(httpRequest);
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(); ProxyResponse proxyResponse = new ProxyResponse();
if (response == null) { if (response == null) {
proxyResponse.setCode(HandlerConstants.INTERNAL_ERROR_CODE); proxyResponse.setCode(HandlerConstants.INTERNAL_ERROR_CODE);
proxyResponse.setExecutorResponse(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + getStatusKey( proxyResponse.setExecutorResponse(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + getStatusKey(

@ -19,7 +19,7 @@
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5"> version="2.5">
<display-name>Entgra Request Handler Webapp</display-name> <display-name>Entgra UI Request Interceptor Webapp</display-name>
<session-config> <session-config>
<session-timeout>60</session-timeout> <session-timeout>60</session-timeout>
</session-config> </session-config>

@ -29,11 +29,15 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>io.entgra.devicemgt</groupId> <groupId>io.entgra.devicemgt</groupId>
<artifactId>request-handler-feature</artifactId> <artifactId>ui-request-interceptor</artifactId>
<name>Entgra - Request Handling Proxy Feature</name> <name>Entgra - UI Request Interceptor Servlet</name>
<description>
Proxy servlet to handle requests generated from UI applications to communicate with backend
APIs
</description>
<packaging>pom</packaging> <packaging>pom</packaging>
<modules> <modules>
<module>io.entgra.request.handler.feature</module> <module>io.entgra.ui.request.interceptor</module>
</modules> </modules>

@ -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);\

@ -21,14 +21,19 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>request-handler-feature</artifactId> <artifactId>ui-request-interceptor-feature</artifactId>
<groupId>io.entgra.devicemgt</groupId> <groupId>io.entgra.devicemgt</groupId>
<version>3.2.5-SNAPSHOT</version> <version>3.2.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>io.entgra.request.handler.feature</artifactId> <artifactId>io.entgra.ui.request.interceptor.feature</artifactId>
<name>Entgra - Request Handling Proxy Feature</name> <name>Entgra - UI Request Interceptor Feature</name>
<description>
Proxy servlet to handle requests generated from UI applications to communicate with backend
APIs
</description>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
@ -36,7 +41,7 @@
<artifactId>maven-dependency-plugin</artifactId> <artifactId>maven-dependency-plugin</artifactId>
<executions> <executions>
<execution> <execution>
<id>request-handler-copy</id> <id>request-handler-copy-war</id>
<phase>package</phase> <phase>package</phase>
<goals> <goals>
<goal>copy</goal> <goal>copy</goal>
@ -45,14 +50,14 @@
<artifactItems> <artifactItems>
<artifactItem> <artifactItem>
<groupId>io.entgra.devicemgt</groupId> <groupId>io.entgra.devicemgt</groupId>
<artifactId>io.entgra.request.handler</artifactId> <artifactId>io.entgra.ui.request.interceptor</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<type>war</type> <type>war</type>
<overWrite>true</overWrite> <overWrite>true</overWrite>
<outputDirectory> <outputDirectory>
${project.build.directory}/maven-shared-archive-resources/webapps ${project.build.directory}/maven-shared-archive-resources/webapps
</outputDirectory> </outputDirectory>
<destFileName>api#application-mgt-handler#v1.0.war</destFileName> <destFileName>ui-request-handler.war</destFileName>
</artifactItem> </artifactItem>
</artifactItems> </artifactItems>
</configuration> </configuration>
@ -95,7 +100,7 @@
<goal>p2-feature-gen</goal> <goal>p2-feature-gen</goal>
</goals> </goals>
<configuration> <configuration>
<id>io.entgra.request.handler</id> <id>io.entgra.ui.request.interceptor</id>
<propertiesFile>../../../features/etc/feature.properties</propertiesFile> <propertiesFile>../../../features/etc/feature.properties</propertiesFile>
<adviceFile> <adviceFile>
<properties> <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);\

@ -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);\

@ -29,12 +29,14 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>io.entgra.devicemgt</groupId> <groupId>io.entgra.devicemgt</groupId>
<artifactId>request-handler</artifactId> <artifactId>ui-request-interceptor-feature</artifactId>
<name>Entgra - Request Handling Proxy</name> <name>Entgra - UI Request Interceptor Feature</name>
<description>
Proxy servlet to handle requests generated from UI applications to communicate with backend
APIs
</description>
<packaging>pom</packaging> <packaging>pom</packaging>
<modules> <modules>
<module>io.entgra.request.handler</module> <module>io.entgra.ui.request.interceptor.feature</module>
</modules> </modules>
</project> </project>

@ -44,7 +44,7 @@
<module>components/certificate-mgt</module> <module>components/certificate-mgt</module>
<module>components/webapp-authenticator-framework</module> <module>components/webapp-authenticator-framework</module>
<module>components/email-sender</module> <module>components/email-sender</module>
<module>components/request-handler</module> <module>components/ui-request-interceptor</module>
<module>features/device-mgt</module> <module>features/device-mgt</module>
<module>features/apimgt-extensions</module> <module>features/apimgt-extensions</module>
<module>features/application-mgt</module> <module>features/application-mgt</module>
@ -53,7 +53,7 @@
<module>features/certificate-mgt</module> <module>features/certificate-mgt</module>
<module>features/oauth-extensions</module> <module>features/oauth-extensions</module>
<module>features/email-sender</module> <module>features/email-sender</module>
<module>features/request-handler</module> <module>features/ui-request-interceptor</module>
<module>features/jwt-client</module> <module>features/jwt-client</module>
<module>features/device-mgt-extensions</module> <module>features/device-mgt-extensions</module>
</modules> </modules>

Loading…
Cancel
Save