diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/ProxyResponse.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/ProxyResponse.java new file mode 100644 index 0000000000..da09527f3d --- /dev/null +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/ProxyResponse.java @@ -0,0 +1,42 @@ +package org.wso2.carbon.device.application.mgt.common; + +/* 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. + */ + +public class ProxyResponse { + + private int code; + private String url; + private String data; + private String executorResponse; + + public int getCode() { return code; } + + public void setCode(int code) { this.code = code; } + + public String getUrl() { return url; } + + public void setUrl(String url) { this.url = url; } + + public String getData() { return data; } + + public void setData(String data) { this.data = data; } + + public String getExecutorResponse() { return executorResponse; } + + public void setExecutorResponse(String executorResponse) { this.executorResponse = executorResponse; } +} diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.handler/src/main/java/org/wso2/carbon/device/application/mgt/handler/InvokerHandler.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.handler/src/main/java/org/wso2/carbon/device/application/mgt/handler/InvokerHandler.java index 9e7529b851..daf0c9ee57 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.handler/src/main/java/org/wso2/carbon/device/application/mgt/handler/InvokerHandler.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.handler/src/main/java/org/wso2/carbon/device/application/mgt/handler/InvokerHandler.java @@ -23,7 +23,6 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; 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.HttpDelete; import org.apache.http.client.methods.HttpGet; @@ -32,9 +31,10 @@ 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 org.wso2.carbon.device.application.mgt.handler.beans.AuthData; import org.wso2.carbon.device.application.mgt.handler.util.HandlerConstants; - +import org.wso2.carbon.device.application.mgt.handler.util.HandlerUtil; import javax.servlet.annotation.MultipartConfig; import javax.servlet.annotation.WebServlet; @@ -43,16 +43,12 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; -import java.io.PrintWriter; import static java.net.HttpURLConnection.HTTP_BAD_REQUEST; -import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR; import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; import static org.wso2.carbon.device.application.mgt.handler.util.HandlerUtil.execute; -import static org.wso2.carbon.device.application.mgt.handler.util.HandlerUtil.retrieveResponseString; -@MultipartConfig -@WebServlet("/invoke") +@MultipartConfig @WebServlet("/invoke") public class InvokerHandler extends HttpServlet { private static final Log log = LogFactory.getLog(LoginHandler.class); private static final long serialVersionUID = -6508020875358160165L; @@ -60,174 +56,171 @@ public class InvokerHandler extends HttpServlet { 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 { + HttpSession session = req.getSession(false); + if (session == null) { + resp.sendError(HTTP_UNAUTHORIZED, "Unauthorized, You are not logged in. Please log in to the portal"); + return false; + } + authData = (AuthData) session.getAttribute(HandlerConstants.SESSION_AUTH_DATA_KEY); + platform = (String) session.getAttribute(HandlerConstants.PLATFORM); + if (authData == null) { + resp.sendError(HTTP_UNAUTHORIZED, "Unauthorized, Access token couldn't found in the current session"); + return false; + } + + apiEndpoint = req.getParameter("api-endpoint"); + method = req.getParameter("method"); + serverUrl = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort(); + if (apiEndpoint == null || method == null) { + resp.sendError(HTTP_BAD_REQUEST, "Bad Request, Either api-endpoint or method is empty"); + 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; + } -// @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; -// } -// String accessToken = authData.getAccessToken(); -// executor.setHeader("Authorization", "Bearer " + accessToken); -// -// String result = execute(executor, HttpStatus.SC_OK); -// -//// unauthorized -//// if (response == null) { -//// resp.sendError(HTTP_INTERNAL_ERROR, "Empty response retried for the API call."); -//// return; -//// } -// -//// int responseCode = response.getStatusLine().getStatusCode(); -//// String result = retrieveResponseString(response); -// -// if (responseCode == HttpStatus.SC_UNAUTHORIZED && (result.contains("Access token expired") || result -// .contains("Invalid input. Access token validation failed"))) { -// if (!refreshToken(req, resp)) { -// return; -// } -// response = execute(executor); -// if (response == null) { -// resp.sendError(HTTP_INTERNAL_ERROR, "Empty response retried for the token renewal API call."); -// return; -// } -// responseCode = response.getStatusLine().getStatusCode(); -// result = retrieveResponseString(response); -// } -// if (responseCode != HttpStatus.SC_OK && responseCode != HttpStatus.SC_CREATED) { -// resp.sendError(responseCode, "Error response retrieved for the API call."); -// return; -// } -// try (PrintWriter writer = resp.getWriter()) { -// writer.write(result); -// } -// } 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 { -// HttpSession session = req.getSession(false); -// if (session == null) { -// resp.sendError(HTTP_UNAUTHORIZED, "Unauthorized, You are not logged in. Please log in to the portal"); -// return false; -// } -// authData = (AuthData) session.getAttribute(HandlerConstants.SESSION_AUTH_DATA_KEY); -// if (authData == null) { -// resp.sendError(HTTP_UNAUTHORIZED, "Unauthorized, Access token couldn't found in the current session"); -// return false; -// } -// -// apiEndpoint = req.getParameter("api-endpoint"); -// method = req.getParameter("method"); -// -// serverUrl = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort(); -// if (apiEndpoint == null || method == null) { -// resp.sendError(HTTP_BAD_REQUEST, "Bad Request, Either api-endpoint or method is empty"); -// 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) { -// resp.sendError(HTTP_UNAUTHORIZED, "Session is expired. Please log in to the server."); -// 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()); -// -// HttpResponse response = execute(tokenEndpoint); -// if (response == null) { -// resp.sendError(HTTP_INTERNAL_ERROR, -// "Internal Server Error, response of the token refresh API call is null."); -// return false; -// } else if ((response.getStatusLine().getStatusCode() != HttpStatus.SC_OK)) { -// resp.sendError(response.getStatusLine().getStatusCode(), -// "Error occured while getting new access token by using refresh token."); -// return false; -// } -// String tokenResult = retrieveResponseString(response); -// JsonParser jsonParser = new JsonParser(); -// -// JsonElement jTokenResult = jsonParser.parse(tokenResult); -// 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; -// } -// return false; -// } + 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/application-mgt/org.wso2.carbon.device.application.mgt.handler/src/main/java/org/wso2/carbon/device/application/mgt/handler/LoginHandler.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.handler/src/main/java/org/wso2/carbon/device/application/mgt/handler/LoginHandler.java index e09875702a..1035f27e1e 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.handler/src/main/java/org/wso2/carbon/device/application/mgt/handler/LoginHandler.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.handler/src/main/java/org/wso2/carbon/device/application/mgt/handler/LoginHandler.java @@ -22,16 +22,16 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonSyntaxException; +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.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.protocol.HTTP; -import org.wso2.carbon.device.application.mgt.common.config.UIConfiguration; +import org.wso2.carbon.device.application.mgt.common.ProxyResponse; import org.wso2.carbon.device.application.mgt.handler.beans.AuthData; import org.wso2.carbon.device.application.mgt.handler.exceptions.LoginException; import org.wso2.carbon.device.application.mgt.handler.util.HandlerConstants; @@ -50,8 +50,7 @@ import java.util.Base64; import static org.wso2.carbon.device.application.mgt.handler.util.HandlerUtil.execute; -@MultipartConfig -@WebServlet("/login") +@MultipartConfig @WebServlet("/login") public class LoginHandler extends HttpServlet { private static final Log log = LogFactory.getLog(LoginHandler.class); private static final long serialVersionUID = 9050048549140517002L; @@ -61,10 +60,8 @@ public class LoginHandler extends HttpServlet { private static String platform; private static String serverUrl; private static String uiConfigUrl; - private static JsonObject uiConfig; - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) { + @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) { try { validateLoginRequest(req, resp); DeviceManagementConfig deviceManagementConfig = DeviceConfigurationManager.getInstance() @@ -82,25 +79,38 @@ public class LoginHandler extends HttpServlet { HttpGet uiConfigEndpoint = new HttpGet(uiConfigUrl); JsonParser jsonParser = new JsonParser(); - String uiConfigJsonString = execute(uiConfigEndpoint,HttpStatus.SC_OK); - if (uiConfigJsonString.contains(HandlerConstants.EXECUTOR_XCEPTIO_PRFIX)){ + 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); - handleErrorResponse(resp, uiConfigJsonString); + HandlerUtil.handleError(req, resp, serverUrl, platform, uiConfigResponse); + return; } - JsonElement uiConfigJsonElement = jsonParser.parse(uiConfigJsonString); - JsonObject uiConfigAsJsonObject = null ; + 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()) { - uiConfigAsJsonObject = uiConfigJsonElement.getAsJsonObject(); + uiConfigJsonObject = uiConfigJsonElement.getAsJsonObject(); + httpSession.setAttribute(HandlerConstants.UI_CONFIG_KEY, uiConfigJsonObject); + httpSession.setAttribute(HandlerConstants.PLATFORM, serverUrl); } - if (uiConfigAsJsonObject == null) { - resp.sendRedirect(serverUrl + "/" + platform + HandlerConstants.DEFAULT_ERROR_CALLBACK); + 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 = uiConfigAsJsonObject.get("isSsoEnable").getAsBoolean(); - JsonArray tags = uiConfigAsJsonObject.get("appRegistration").getAsJsonObject().get("tags").getAsJsonArray(); - JsonArray scopes = uiConfigAsJsonObject.get("scopes").getAsJsonArray(); + 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"); @@ -112,18 +122,19 @@ public class LoginHandler extends HttpServlet { apiRegEndpoint.setHeader(HTTP.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()); apiRegEndpoint.setEntity(constructAppRegPayload(tags)); - String clientAppResult = execute(apiRegEndpoint, HttpStatus.SC_CREATED); + ProxyResponse clientAppResponse = execute(apiRegEndpoint); + String clientAppResult = clientAppResponse.getData(); - if (!clientAppResult.isEmpty() && persistTokenInSession(req, resp, clientAppResult, scopes)) { - resp.sendRedirect( - serverUrl + "/" + platform + uiConfigAsJsonObject.get(HandlerConstants.LOGIN_RESPONSE_KEY) - .getAsJsonObject().get("successCallback").getAsString()); + 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; } - resp.sendRedirect( - serverUrl + "/" + platform + uiConfigAsJsonObject.get(HandlerConstants.LOGIN_RESPONSE_KEY) - .getAsJsonObject().get(HandlerConstants.FAILURE_CALLBACK_KEY).getAsJsonObject() - .get(HandlerUtil.getStatusKey(HandlerConstants.INTERNAL_ERROR_CODE)).getAsString()); + HandlerUtil.handleError(req, resp, serverUrl, platform, null); } } catch (IOException e) { log.error("Error occured while sending the response into the socket. ", e); @@ -141,11 +152,9 @@ public class LoginHandler extends HttpServlet { * @param scopes - scopes defied in the application-mgt.xml * @throws LoginException - login exception throws when getting token result */ - private boolean persistTokenInSession(HttpServletRequest req, HttpServletResponse resp, String clientAppResult, - JsonArray scopes) throws LoginException { + private boolean getTokenAndPersistInSession(HttpServletRequest req, HttpServletResponse resp, + String clientAppResult, JsonArray scopes) throws LoginException { JsonParser jsonParser = new JsonParser(); - String tokenResult; - try { JsonElement jClientAppResult = jsonParser.parse(clientAppResult); if (jClientAppResult.isJsonObject()) { @@ -155,26 +164,37 @@ public class LoginHandler extends HttpServlet { String encodedClientApp = Base64.getEncoder() .encodeToString((clientId + ":" + clientSecret).getBytes()); - tokenResult = getTokenResult(encodedClientApp, scopes, resp); + ProxyResponse tokenResultResponse = getTokenResult(encodedClientApp, scopes); - if (tokenResult != null) { - 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; + 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; @@ -246,50 +266,27 @@ public class LoginHandler extends HttpServlet { * * @param encodedClientApp - Base64 encoded clientId:clientSecret. * @param scopes - Scopes which are retrieved by reading application-mgt configuration - * @param resp - {@link HttpServletResponse} * @return Invoke token endpoint and return the response as string. * @throws IOException IO exception throws if an error occured when invoking token endpoint */ - private String getTokenResult(String encodedClientApp, JsonArray scopes, HttpServletResponse resp) - throws IOException, LoginException { - - 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(); - } + private ProxyResponse getTokenResult(String encodedClientApp, JsonArray scopes) throws IOException { - StringEntity tokenEPPayload = new StringEntity( - "grant_type=password&username=" + username + "&password=" + password + "&scope=" + scopeString, - ContentType.APPLICATION_FORM_URLENCODED); - tokenEndpoint.setEntity(tokenEPPayload); + 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); - String tokenResult = execute(tokenEndpoint, HttpStatus.SC_OK); + if (scopeString != null) { + scopeString = scopeString.trim(); + } else { + scopeString = "default"; + } - if (tokenResult.contains(HandlerConstants.EXECUTOR_XCEPTIO_PRFIX)) { - log.error("Error occurred while getting token data by invoking " + serverUrl - + HandlerConstants.TOKEN_ENDPOINT); - handleErrorResponse(resp, tokenResult); - } - return tokenResult; - } + StringEntity tokenEPPayload = new StringEntity( + "grant_type=password&username=" + username + "&password=" + password + "&scope=" + scopeString, + ContentType.APPLICATION_FORM_URLENCODED); + tokenEndpoint.setEntity(tokenEPPayload); - /*** - * - * @param resp {@link HttpServletResponse} - * corresponding error page. - * @throws LoginException If an {@link IOException} occurs when redirecting to corresponding error page. - */ - private void handleErrorResponse(HttpServletResponse resp, String respMessage) throws LoginException { - try { - resp.sendRedirect(serverUrl + uiConfig.get(HandlerConstants.LOGIN_RESPONSE_KEY).getAsJsonObject() - .get(HandlerConstants.FAILURE_CALLBACK_KEY).getAsJsonObject() - .get(respMessage.split(HandlerConstants.EXECUTOR_XCEPTIO_PRFIX)[0]).getAsString()); - } catch (IOException e) { - throw new LoginException("Error occured while redirecting to corresponding error page. ", e); - } + return execute(tokenEndpoint); } } diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.handler/src/main/java/org/wso2/carbon/device/application/mgt/handler/util/HandlerConstants.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.handler/src/main/java/org/wso2/carbon/device/application/mgt/handler/util/HandlerConstants.java index ad241bce71..4ff23c4077 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.handler/src/main/java/org/wso2/carbon/device/application/mgt/handler/util/HandlerConstants.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.handler/src/main/java/org/wso2/carbon/device/application/mgt/handler/util/HandlerConstants.java @@ -28,11 +28,16 @@ public class HandlerConstants { 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 FAILURE_CALLBACK_KEY = "failureCallback"; public static final String API_COMMON_CONTEXT = "/api"; - public static final String EXECUTOR_XCEPTIO_PRFIX = "ExecutorException-"; + 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 = 300; diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.handler/src/main/java/org/wso2/carbon/device/application/mgt/handler/util/HandlerUtil.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.handler/src/main/java/org/wso2/carbon/device/application/mgt/handler/util/HandlerUtil.java index 4716fa6fe3..0f5c4d9d83 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.handler/src/main/java/org/wso2/carbon/device/application/mgt/handler/util/HandlerUtil.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.handler/src/main/java/org/wso2/carbon/device/application/mgt/handler/util/HandlerUtil.java @@ -17,9 +17,8 @@ package org.wso2.carbon.device.application.mgt.handler.util; -import com.google.gson.JsonElement; +import com.google.gson.Gson; import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.HttpResponse; @@ -28,16 +27,19 @@ 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.wso2.carbon.device.application.mgt.handler.exceptions.LoginException; +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); - private static JsonObject uiConfigAsJsonObject; /*** * @@ -46,9 +48,9 @@ public class HandlerUtil { * @return response as string * @throws IOException IO exception returns if error occurs when executing the httpMethod */ - public static String execute(T httpMethod, int expectedStatusCode) throws IOException { - HttpResponse response = null; + 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); @@ -57,46 +59,50 @@ public class HandlerUtil { response = client.execute(method); } + ProxyResponse proxyResponse = new ProxyResponse(); if (response == null) { - return HandlerConstants.EXECUTOR_XCEPTIO_PRFIX + getStatusKey(HandlerConstants.INTERNAL_ERROR_CODE); + 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(); - if ( statusCode != expectedStatusCode) { - return HandlerConstants.EXECUTOR_XCEPTIO_PRFIX + getStatusKey(statusCode); - } else { - try (BufferedReader rd = new BufferedReader( - new InputStreamReader(response.getEntity().getContent()))) { - StringBuilder result = new StringBuilder(); - String line; - while ((line = rd.readLine()) != null) { - result.append(line); + 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; } - return result.toString(); } + proxyResponse.setCode(statusCode); + proxyResponse + .setExecutorResponse(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + getStatusKey(statusCode)); + return proxyResponse; } } } } - /*** - * - * @param response {@link HttpResponse} - * @return {@link String} get the response payload by using Entity of the response - * @throws IOException if error occurs while reading the content of the response or reading {@link BufferedReader} - * object - */ - public static String retrieveResponseString (HttpResponse response) throws IOException{ - try (BufferedReader rd = new BufferedReader( - new InputStreamReader(response.getEntity().getContent()))) { - StringBuilder result = new StringBuilder(); - String line; - while ((line = rd.readLine()) != null) { - result.append(line); - } - return result.toString(); - } - } - /*** * * @param statusCode Provide status code, e.g:- 400, 401, 500 etc @@ -106,28 +112,28 @@ public class HandlerUtil { String statusCodeKey; switch (statusCode) { - case 500: + case HttpStatus.SC_INTERNAL_SERVER_ERROR: statusCodeKey = "internalServerError"; break; - case 400: + case HttpStatus.SC_BAD_REQUEST: statusCodeKey = "badRequest"; break; - case 401: + case HttpStatus.SC_UNAUTHORIZED: statusCodeKey = "unauthorized"; break; - case 403: + case HttpStatus.SC_FORBIDDEN: statusCodeKey = "forbidden"; break; - case 404: + case HttpStatus.SC_NOT_FOUND: statusCodeKey = "notFound"; break; - case 405: + case HttpStatus.SC_METHOD_NOT_ALLOWED: statusCodeKey = "methodNotAllowed"; break; - case 406: + case HttpStatus.SC_NOT_ACCEPTABLE: statusCodeKey = "notAcceptable"; break; - case 415: + case HttpStatus.SC_UNSUPPORTED_MEDIA_TYPE: statusCodeKey = "unsupportedMediaType"; break; default: @@ -137,33 +143,68 @@ public class HandlerUtil { return statusCodeKey; } + /*** * - * @param uiConfigUrl - JSON string of the UI configuration - * @return - True returns if UI config load is succeeded and False returns if it fails. Further, if call ie - * succeeded assign values for uiConfigAsJsonObject static variable. - * @throws LoginException IO exception could occur if an error occured when invoking end point for getting UI - * configs + * @param resp {@link HttpServletResponse} + * Return Error Response. */ - public static JsonObject loadUiConfig(String uiConfigUrl) throws LoginException { - try { - if (uiConfigAsJsonObject != null) { - return uiConfigAsJsonObject; - } - HttpGet uiConfigEndpoint = new HttpGet(uiConfigUrl); - JsonParser jsonParser = new JsonParser(); - String uiConfig = execute(uiConfigEndpoint,HttpStatus.SC_OK); - - JsonElement uiConfigJsonElement = jsonParser.parse(uiConfig); - if (uiConfigJsonElement.isJsonObject()) { - uiConfigAsJsonObject = uiConfigJsonElement.getAsJsonObject(); - return uiConfigAsJsonObject; + 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)); + } + + 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; + } - } catch (IOException e) { - throw new LoginException("Error occured while getting UI configs. ", e); + Gson gson = new Gson(); + resp.setStatus(proxyResponse.getCode()); + resp.setContentType("application/json"); + resp.setCharacterEncoding("UTF-8"); + proxyResponse.setExecutorResponse(null); + try (PrintWriter writer = resp.getWriter()) { + writer.write(gson.toJson(proxyResponse)); } - return null; } }