From 76064844c4c1820b2d2d604c2a06faede87228ae Mon Sep 17 00:00:00 2001 From: rajitha Date: Tue, 26 Sep 2023 12:56:06 +0530 Subject: [PATCH] Add generic logic to jit handlers --- .../JITEnrollmentCallbackHandler.java | 66 +++++++++++++- .../interceptor/JITEnrollmentHandler.java | 5 +- .../interceptor/JITProvisionHandler.java | 88 +++---------------- .../src/main/resources/conf/jit-config.xml | 32 +++++-- 4 files changed, 104 insertions(+), 87 deletions(-) diff --git a/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITEnrollmentCallbackHandler.java b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITEnrollmentCallbackHandler.java index 3d314bf79d..e0b33691b1 100644 --- a/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITEnrollmentCallbackHandler.java +++ b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITEnrollmentCallbackHandler.java @@ -36,14 +36,25 @@ import org.apache.http.HttpHeaders; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.wso2.carbon.utils.CarbonUtils; +import org.xml.sax.SAXException; 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 javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.io.File; import java.io.IOException; import java.util.Base64; +import java.util.Objects; @WebServlet( name = "JIT Enrollment callback handler", @@ -62,7 +73,8 @@ public class JITEnrollmentCallbackHandler extends HttpServlet { private String clientId; private String clientSecret; private String scope; - + private String JITConfigurationPath; + private JITEnrollmentData JITEnrollmentInfo; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) { gatewayUrl = request.getScheme() + HandlerConstants.SCHEME_SEPARATOR @@ -71,6 +83,7 @@ public class JITEnrollmentCallbackHandler extends HttpServlet { keyManagerUrl = request.getScheme() + HandlerConstants.SCHEME_SEPARATOR + System.getProperty(HandlerConstants.IOT_KM_HOST_ENV_VAR) + HandlerConstants.COLON + HandlerUtil.getKeyManagerPort(request.getScheme()); + JITConfigurationPath = CarbonUtils.getCarbonConfigDirPath() + File.separator + "jit-config.xml"; HttpSession session = request.getSession(false); try { if (session == null) { @@ -84,7 +97,7 @@ public class JITEnrollmentCallbackHandler extends HttpServlet { return; } - JITEnrollmentData JITEnrollmentInfo = (JITEnrollmentData) + JITEnrollmentInfo = (JITEnrollmentData) session.getAttribute(HandlerConstants.SESSION_JIT_ENROLLMENT_DATA_KEY); if (JITEnrollmentInfo == null) { response.sendError(HttpStatus.SC_UNAUTHORIZED); @@ -92,8 +105,7 @@ public class JITEnrollmentCallbackHandler extends HttpServlet { } applicationName = request.getContextPath().substring(1, request.getContextPath().indexOf("-ui-request-handler")); - scope = "perm:metadata:view perm:metadata:create perm:metadata:update perm:android:enroll " + - "perm:device:enroll perm:android:view-configuration"; + initializeJITEnrollmentConfigurations(); populateApplicationData(registerApplication()); persistAuthData(session, getToken()); response.sendRedirect(JITEnrollmentInfo.getRedirectUrl() + "?ownershipType=" + @@ -104,6 +116,52 @@ public class JITEnrollmentCallbackHandler extends HttpServlet { } } + private void initializeJITEnrollmentConfigurations() throws JITEnrollmentException { + try { + File JITConfigurationFile = new File(JITConfigurationPath); + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + Document JITConfigurationDoc = documentBuilder.parse(JITConfigurationFile); + JITConfigurationDoc.getDocumentElement().normalize(); + Element enrollmentScopes; + if (Objects.equals(JITEnrollmentInfo.getOs(), "android")) { + enrollmentScopes = (Element) JITConfigurationDoc. + getElementsByTagName("AndroidEnrollmentScopes").item(0); + } else if (Objects.equals(JITEnrollmentInfo.getOs(), "ios")) { + enrollmentScopes = (Element) JITConfigurationDoc. + getElementsByTagName("IOSEnrollmentScopes").item(0); + } else if (Objects.equals(JITEnrollmentInfo.getOs(), "windows")) { + enrollmentScopes = (Element) JITConfigurationDoc. + getElementsByTagName("IOSEnrollmentScopes").item(0); + } else { + String msg = "OS type not supported"; + if (log.isDebugEnabled()) { + log.error(msg); + } + throw new JITEnrollmentException(msg); + } + NodeList scopeList = enrollmentScopes.getElementsByTagName("Scope"); + StringBuilder scopeStr = new StringBuilder(); + for (int idx = 0; idx < scopeList.getLength(); idx++) { + Node scopeNode = scopeList.item(idx); + if (scopeNode.getNodeType() == Node.ELEMENT_NODE) { + Element scopeElement = (Element) scopeNode; + scopeStr.append(" ").append(scopeElement.getTextContent()); + } + } + scope = scopeStr.toString(); + } catch (ParserConfigurationException ex) { + String msg = "Error occurred when document builder creating the file configuration"; + throw new JITEnrollmentException(msg, ex); + } catch (IOException ex) { + String msg = "IO error occurred while parsing the JIT config file"; + throw new JITEnrollmentException(msg, ex); + } catch (SAXException ex) { + String msg = "Parse error occurred while parsing the JIT config document"; + throw new JITEnrollmentException(msg, ex); + } + } + /*** * Parse string data and build json object * @param data - Json string diff --git a/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITEnrollmentHandler.java b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITEnrollmentHandler.java index b13d4d904a..8ca9cdf98c 100644 --- a/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITEnrollmentHandler.java +++ b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITEnrollmentHandler.java @@ -19,10 +19,14 @@ package io.entgra.device.mgt.core.ui.request.interceptor; import io.entgra.device.mgt.core.ui.request.interceptor.beans.JITEnrollmentData; +import io.entgra.device.mgt.core.ui.request.interceptor.exceptions.JITEnrollmentException; import io.entgra.device.mgt.core.ui.request.interceptor.util.HandlerConstants; import io.entgra.device.mgt.core.ui.request.interceptor.util.HandlerUtil; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.w3c.dom.Document; +import org.wso2.carbon.utils.CarbonUtils; +import org.xml.sax.SAXException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; @@ -45,7 +49,6 @@ public class JITEnrollmentHandler extends HttpServlet { private String os; private String redirectUrl; private String tenantDomain; - @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) { try { diff --git a/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITProvisionHandler.java b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITProvisionHandler.java index 61f6614cc9..dec743289e 100644 --- a/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITProvisionHandler.java +++ b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITProvisionHandler.java @@ -65,14 +65,10 @@ import java.util.Objects; public class JITProvisionHandler extends HttpServlet { private static final Log log = LogFactory.getLog(JITProvisionHandler.class); private String tenantDomain; - private String adminUsername; private String clientId; private String JITServiceProviderName; - private String apiManagerUrl; - private String encodedAdminCredentials; private String encodedClientCredentials; private String JITConfigurationPath; - private String JITCallbackUrl; private String redirectUrl; @Override @@ -80,14 +76,11 @@ public class JITProvisionHandler extends HttpServlet { String keyManagerUrl = request.getScheme() + HandlerConstants.SCHEME_SEPARATOR + System.getProperty(HandlerConstants.IOT_KM_HOST_ENV_VAR) + HandlerConstants.COLON + HandlerUtil.getKeyManagerPort(request.getScheme()); - JITCallbackUrl = request.getScheme() + HandlerConstants.SCHEME_SEPARATOR + String JITCallbackUrl = request.getScheme() + HandlerConstants.SCHEME_SEPARATOR + System.getProperty(HandlerConstants.IOT_CORE_HOST_ENV_VAR) + HandlerConstants.COLON + HandlerUtil.getCorePort(request.getScheme()) + request.getContextPath() + HandlerConstants.JIT_PROVISION_CALLBACK_URL; - apiManagerUrl = request.getScheme() + HandlerConstants.SCHEME_SEPARATOR - + System.getProperty(HandlerConstants.IOT_APIM_HOST_ENV_VAR) - + HandlerConstants.COLON + HandlerUtil.getAPIManagerPort(request.getScheme()); JITConfigurationPath = CarbonUtils.getCarbonConfigDirPath() + File.separator + "jit-config.xml"; String scope = "openid"; tenantDomain = request.getParameter("tenantDomain"); @@ -103,7 +96,6 @@ public class JITProvisionHandler extends HttpServlet { return; } - populateServiceProvider(); persistJITData(request.getSession(true)); response.sendRedirect(keyManagerUrl + HandlerConstants.AUTHORIZATION_ENDPOINT + "?response_type=code" + @@ -116,24 +108,6 @@ public class JITProvisionHandler extends HttpServlet { } } - /*** - * Construct dynamic client registration request - * @return {@link HttpPost} DCR request - */ - private HttpPost buildDCRRequest() { - HttpPost DCRRequest = new HttpPost(apiManagerUrl + HandlerConstants.DCR_URL); - DCRRequest.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()); - DCRRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BASIC + encodedAdminCredentials); - JsonObject payload = new JsonObject(); - payload.addProperty("clientName", JITServiceProviderName); - payload.addProperty("owner", adminUsername); - payload.addProperty("saasApp", true); - payload.addProperty("grantType", HandlerConstants.CODE_GRANT_TYPE); - payload.addProperty("callbackUrl", JITCallbackUrl); - DCRRequest.setEntity(new StringEntity(payload.toString(), ContentType.APPLICATION_JSON)); - return DCRRequest; - } - /*** * Retrieve JIT data from current session if session exists, otherwise build and return * @param session - {@link HttpSession} @@ -158,56 +132,22 @@ public class JITProvisionHandler extends HttpServlet { session.setAttribute(HandlerConstants.SESSION_JIT_DATA_KEY, JITInfo); } - /*** - * Populate service provider details - * @throws JITProvisionException throws when dcr request fails due to IO exception - */ - private void populateServiceProvider() throws JITProvisionException { - try { - HttpPost DCRRequest = buildDCRRequest(); - ProxyResponse proxyResponse = HandlerUtil.execute(DCRRequest); - if (proxyResponse.getCode() == HttpStatus.SC_OK) { - JsonObject serviceProvider = parseResponseData(proxyResponse.getData()); - clientId = serviceProvider.get("clientId").getAsString(); - String clientSecret = serviceProvider.get("clientSecret").getAsString(); - String headerValue = clientId + ':' + clientSecret; - encodedClientCredentials = Base64.getEncoder().encodeToString(headerValue.getBytes()); - } - } catch (IOException ex) { - String msg = "Error exception occurred while executing proxy request"; - throw new JITProvisionException(msg, ex); - } - } - - /*** - * Parse string data and build json object - * @param data - Json string - * @return {@link JsonObject} Json object corresponding to provided json string - * @throws JITProvisionException throws when error occurred while parsing - */ - private JsonObject parseResponseData(String data) throws JITProvisionException { - JsonParser parser = new JsonParser(); - JsonElement responseData = parser.parse(data); - if (responseData.isJsonObject()) { - return responseData.getAsJsonObject(); - } - throw new JITProvisionException("Unexpected response body return"); - } - /*** * Find the tenant based configurations and return * @param tenantDomain - Domain of the tenant * @param document - Config doc * @return {@link Element} If config found return configuration element, otherwise null */ - private Element findTenantConfigs(String tenantDomain, Document document) { - NodeList tenantConfigurations = document.getElementsByTagName("TenantConfiguration"); - for (int idx = 0; idx < tenantConfigurations.getLength(); idx++) { - Node configNode = tenantConfigurations.item(idx); + private Element findServiceProvider(String tenantDomain, Document document) { + NodeList serviceProviderConfiguration = document.getElementsByTagName("ServiceProvider"); + for (int idx = 0; idx < serviceProviderConfiguration.getLength(); idx++) { + Node configNode = serviceProviderConfiguration.item(idx); if (configNode.getNodeType() == Node.ELEMENT_NODE) { Element configElement = (Element) configNode; if (Objects.equals(configElement.getAttributes(). - getNamedItem("tenantDomain").getNodeValue(), tenantDomain)) { + getNamedItem("tenantDomain").getNodeValue(), tenantDomain) && + Objects.equals(configElement.getAttributes().getNamedItem("name").getNodeValue(), + JITServiceProviderName)) { return configElement; } } @@ -227,12 +167,12 @@ public class JITProvisionHandler extends HttpServlet { DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); Document JITConfigurationDoc = documentBuilder.parse(JITConfigurationFile); JITConfigurationDoc.getDocumentElement().normalize(); - Element tenantConfig = findTenantConfigs(tenantDomain, JITConfigurationDoc); - if (tenantConfig == null) return false; - adminUsername = tenantConfig.getElementsByTagName("AdminUsername").item(0).getTextContent(); - String adminPassword = tenantConfig.getElementsByTagName("AdminPassword").item(0).getTextContent(); - String headerValue = adminUsername + ":" + adminPassword; - encodedAdminCredentials = Base64.getEncoder().encodeToString(headerValue.getBytes()); + Element serviceProvider = findServiceProvider(tenantDomain, JITConfigurationDoc); + if (serviceProvider == null) return false; + clientId = serviceProvider.getElementsByTagName("ClientId").item(0).getTextContent(); + String clientSecret = serviceProvider.getElementsByTagName("ClientSecret").item(0).getTextContent(); + String headerValue = clientId + ":" + clientSecret; + encodedClientCredentials = Base64.getEncoder().encodeToString(headerValue.getBytes()); return true; } catch (ParserConfigurationException ex) { String msg = "Error occurred when document builder creating the file configuration"; diff --git a/features/device-mgt/io.entgra.device.mgt.core.device.mgt.basics.feature/src/main/resources/conf/jit-config.xml b/features/device-mgt/io.entgra.device.mgt.core.device.mgt.basics.feature/src/main/resources/conf/jit-config.xml index ae22e570ab..ef59cd01f0 100644 --- a/features/device-mgt/io.entgra.device.mgt.core.device.mgt.basics.feature/src/main/resources/conf/jit-config.xml +++ b/features/device-mgt/io.entgra.device.mgt.core.device.mgt.basics.feature/src/main/resources/conf/jit-config.xml @@ -18,11 +18,27 @@ ~ under the License. --> - - - \ No newline at end of file + + + + perm:metadata:view + perm:metadata:create + perm:metadata:update + perm:android:enroll + perm:device:enroll + perm:android:view-configuration + + + + + + + + + + + + \ No newline at end of file