mirror of
https://repository.entgra.net/community/device-mgt-core.git
synced 2025-10-06 02:01:45 +00:00
Merge pull request 'Add JIT base provision and enrollment handlers' (#230) from rajitha/device-mgt-core:jit-feature into master
Reviewed-on: https://repository.entgra.net/community/device-mgt-core/pulls/230
This commit is contained in:
commit
9ae64c718c
@ -0,0 +1,28 @@
|
||||
package io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@ApiModel(value = "InvitationMailProfile", description = "Holds data related to JIT Enrollment invitation mails")
|
||||
public class InvitationMailProfile {
|
||||
@ApiModelProperty(name = "username", value = "Username (same as username in external IDP)", required = true)
|
||||
private String username;
|
||||
@ApiModelProperty(name = "mail", value = "Mail will be sent to this mail address", required = true)
|
||||
private String mail;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getMail() {
|
||||
return mail;
|
||||
}
|
||||
|
||||
public void setMail(String mail) {
|
||||
this.mail = mail;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
package io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ApiModel(value = "JITEnrollmentInvitation", description = "Holds data related to JIT enrollment invitations")
|
||||
public class JITEnrollmentInvitation {
|
||||
@ApiModelProperty(name = "mailProfiles", value = "Mail profiles to send mail invitations", required = true)
|
||||
private List<InvitationMailProfile> mailProfiles;
|
||||
@ApiModelProperty(name = "ownershipType", value = "Ownership type of the enrollment", required = true)
|
||||
private String ownershipType;
|
||||
@ApiModelProperty(name = "deviceType", value = "Device type", required = true)
|
||||
private String deviceType;
|
||||
@ApiModelProperty(name = "sp", value = "Service provider name", required = true)
|
||||
private String sp;
|
||||
|
||||
public List<InvitationMailProfile> getMailProfiles() {
|
||||
return mailProfiles;
|
||||
}
|
||||
|
||||
public void setMailProfiles(List<InvitationMailProfile> mailProfiles) {
|
||||
this.mailProfiles = mailProfiles;
|
||||
}
|
||||
|
||||
public String getOwnershipType() {
|
||||
return ownershipType;
|
||||
}
|
||||
|
||||
public void setOwnershipType(String ownershipType) {
|
||||
this.ownershipType = ownershipType;
|
||||
}
|
||||
|
||||
public String getDeviceType() {
|
||||
return deviceType;
|
||||
}
|
||||
|
||||
public void setDeviceType(String deviceType) {
|
||||
this.deviceType = deviceType;
|
||||
}
|
||||
|
||||
public String getSp() {
|
||||
return sp;
|
||||
}
|
||||
|
||||
public void setSp(String sp) {
|
||||
this.sp = sp;
|
||||
}
|
||||
}
|
||||
@ -18,33 +18,34 @@
|
||||
package io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.api;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import io.swagger.annotations.SwaggerDefinition;
|
||||
import io.swagger.annotations.Info;
|
||||
import io.swagger.annotations.ExtensionProperty;
|
||||
import io.swagger.annotations.Extension;
|
||||
import io.swagger.annotations.Tag;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import io.swagger.annotations.ApiResponse;
|
||||
import io.swagger.annotations.ApiResponses;
|
||||
import io.swagger.annotations.ResponseHeader;
|
||||
import org.apache.axis2.transport.http.HTTPConstants;
|
||||
import io.entgra.device.mgt.core.apimgt.annotations.Scopes;
|
||||
import io.entgra.device.mgt.core.apimgt.annotations.Scope;
|
||||
import io.entgra.device.mgt.core.device.mgt.common.invitation.mgt.DeviceEnrollmentInvitation;
|
||||
import io.entgra.device.mgt.core.apimgt.annotations.Scopes;
|
||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.ActivityList;
|
||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.BasicUserInfo;
|
||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.BasicUserInfoList;
|
||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.Credential;
|
||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.EnrollmentInvitation;
|
||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.ErrorResponse;
|
||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.JITEnrollmentInvitation;
|
||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.OldPasswordResetWrapper;
|
||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.PermissionList;
|
||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.RoleList;
|
||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.UserInfo;
|
||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.UserStoreList;
|
||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.util.Constants;
|
||||
import io.entgra.device.mgt.core.device.mgt.common.invitation.mgt.DeviceEnrollmentInvitation;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import io.swagger.annotations.ApiResponse;
|
||||
import io.swagger.annotations.ApiResponses;
|
||||
import io.swagger.annotations.Extension;
|
||||
import io.swagger.annotations.ExtensionProperty;
|
||||
import io.swagger.annotations.Info;
|
||||
import io.swagger.annotations.ResponseHeader;
|
||||
import io.swagger.annotations.SwaggerDefinition;
|
||||
import io.swagger.annotations.Tag;
|
||||
import org.apache.axis2.transport.http.HTTPConstants;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.ws.rs.Consumes;
|
||||
@ -54,7 +55,6 @@ import javax.ws.rs.HeaderParam;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
@ -940,6 +940,49 @@ public interface UserManagementService {
|
||||
required = true)
|
||||
@Valid EnrollmentInvitation enrollmentInvitation);
|
||||
|
||||
@POST
|
||||
@Path("/jit-enrollment-invite")
|
||||
@ApiOperation(
|
||||
produces = MediaType.APPLICATION_JSON,
|
||||
httpMethod = HTTPConstants.HEADER_POST,
|
||||
value = "Sending Enrollment Invitations to email address",
|
||||
notes = "Send the a mail inviting recipients to enroll devices.",
|
||||
tags = "User Management",
|
||||
extensions = {
|
||||
@Extension(properties = {
|
||||
@ExtensionProperty(name = Constants.SCOPE, value = "perm:users:send-invitation")
|
||||
})
|
||||
}
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(
|
||||
code = 200,
|
||||
message = "OK. \n Successfully sent the invitation mail."),
|
||||
@ApiResponse(
|
||||
code = 400,
|
||||
message = "Bad Request. \n Invalid request or validation error.",
|
||||
response = ErrorResponse.class),
|
||||
@ApiResponse(
|
||||
code = 404,
|
||||
message = "Not Found. \n The specified resource does not exist.\n",
|
||||
response = ErrorResponse.class),
|
||||
@ApiResponse(
|
||||
code = 415,
|
||||
message = "Unsupported media type. \n The format of the requested entity was not supported.\n",
|
||||
response = ErrorResponse.class),
|
||||
@ApiResponse(
|
||||
code = 500,
|
||||
message = "Internal Server Error. \n " +
|
||||
"Server error occurred while updating the user credentials.",
|
||||
response = ErrorResponse.class)
|
||||
})
|
||||
Response inviteExternalUsers(
|
||||
@ApiParam(
|
||||
name = "jitEnrollmentInvitation",
|
||||
value = "List of email address of recipients",
|
||||
required = true)
|
||||
@Valid JITEnrollmentInvitation jitEnrollmentInvitation);
|
||||
|
||||
@POST
|
||||
@Path("/validate")
|
||||
Response validateUser(Credential credential);
|
||||
|
||||
@ -19,7 +19,6 @@ package io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import io.entgra.device.mgt.core.device.mgt.common.Device;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@ -28,7 +27,6 @@ import org.eclipse.wst.common.uriresolver.internal.util.URIEncoder;
|
||||
import org.wso2.carbon.context.CarbonContext;
|
||||
import org.wso2.carbon.context.PrivilegedCarbonContext;
|
||||
import io.entgra.device.mgt.core.device.mgt.common.exceptions.DeviceManagementException;
|
||||
import io.entgra.device.mgt.core.device.mgt.common.EnrolmentInfo;
|
||||
import io.entgra.device.mgt.core.device.mgt.common.configuration.mgt.ConfigurationManagementException;
|
||||
import io.entgra.device.mgt.core.device.mgt.common.exceptions.OTPManagementException;
|
||||
import io.entgra.device.mgt.core.device.mgt.common.invitation.mgt.DeviceEnrollmentInvitation;
|
||||
@ -45,6 +43,8 @@ import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.BasicUserInfoWrapper
|
||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.Credential;
|
||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.EnrollmentInvitation;
|
||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.ErrorResponse;
|
||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.InvitationMailProfile;
|
||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.JITEnrollmentInvitation;
|
||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.OldPasswordResetWrapper;
|
||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.PermissionList;
|
||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.RoleList;
|
||||
@ -83,7 +83,6 @@ import javax.ws.rs.HeaderParam;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
@ -92,6 +91,7 @@ import java.io.File;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.security.SecureRandom;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
@ -757,6 +757,54 @@ public class UserManagementServiceImpl implements UserManagementService {
|
||||
return Response.status(Response.Status.OK).entity("Invitation mails have been sent.").build();
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("jit-enrollment-invite")
|
||||
@Override
|
||||
public Response inviteExternalUsers(JITEnrollmentInvitation jitEnrollmentInvitation) {
|
||||
if (jitEnrollmentInvitation.getMailProfiles() == null || jitEnrollmentInvitation.getMailProfiles().isEmpty()) {
|
||||
String msg = "Error occurred while validating mail profiles. Mail profiles cannot be empty";
|
||||
log.error(msg);
|
||||
throw new BadRequestException(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).setCode(HttpStatus.SC_BAD_REQUEST).
|
||||
build());
|
||||
}
|
||||
String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
|
||||
String inviteBy = DeviceMgtAPIUtils.getAuthenticatedUser();
|
||||
try {
|
||||
DeviceManagementProviderService dms = DeviceMgtAPIUtils.getDeviceManagementService();
|
||||
for (InvitationMailProfile mailProfile : jitEnrollmentInvitation.getMailProfiles()) {
|
||||
Properties props = new Properties();
|
||||
props.setProperty("username", mailProfile.getUsername());
|
||||
props.setProperty("tenant-domain", tenantDomain);
|
||||
props.setProperty("sp", jitEnrollmentInvitation.getSp());
|
||||
props.setProperty("ownership-type", jitEnrollmentInvitation.getOwnershipType());
|
||||
props.setProperty("device-type", jitEnrollmentInvitation.getDeviceType());
|
||||
props.setProperty("invite-by", inviteBy);
|
||||
Set<String> recipients = new HashSet<>();
|
||||
recipients.add(mailProfile.getMail());
|
||||
EmailMetaInfo metaInfo = new EmailMetaInfo(recipients, props);
|
||||
dms.sendEnrolmentInvitation(getTemplateName(jitEnrollmentInvitation.getDeviceType(),
|
||||
"jit-enrollment-invitation", "-"), metaInfo);
|
||||
}
|
||||
} catch (DeviceManagementException ex) {
|
||||
String msg = "Error occurred while inviting user to enroll their device";
|
||||
log.error(msg, ex);
|
||||
return Response.serverError().entity(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
|
||||
} catch (ConfigurationManagementException ex) {
|
||||
String msg = "Error occurred while sending the email invitations. Mail server not configured.";
|
||||
log.error(msg, ex);
|
||||
return Response.serverError().entity(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
|
||||
} catch (NoSuchFileException ex) {
|
||||
String msg = "Error occurred while retrieving email template";
|
||||
log.error(msg, ex);
|
||||
return Response.serverError().entity(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
|
||||
}
|
||||
return Response.status(Response.Status.OK).entity("Invitation mails have been sent.").build();
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/validate")
|
||||
@Override
|
||||
@ -1179,6 +1227,30 @@ public class UserManagementServiceImpl implements UserManagementService {
|
||||
return DeviceManagementConstants.EmailAttributes.DEFAULT_ENROLLMENT_TEMPLATE;
|
||||
}
|
||||
|
||||
private String getTemplateName(String deviceType, String prefix, String separator) throws NoSuchFileException {
|
||||
String templateName = deviceType + separator + prefix + ".vm";
|
||||
List<String> templatePathSegments =
|
||||
Arrays.asList(CarbonUtils.getCarbonHome(), "repository", "resources", "email-templates", templateName);
|
||||
File template = new File(String.join(File.separator, templatePathSegments));
|
||||
if (template.exists()) {
|
||||
return templateName;
|
||||
}
|
||||
|
||||
String defaultTemplateName = "default" + separator + prefix + ".vm";
|
||||
List<String> defaultTemplatePathSegments =
|
||||
Arrays.asList(CarbonUtils.getCarbonHome(), "repository", "resources", "email-templates", defaultTemplateName);
|
||||
File defaultTemplate = new File(String.join(File.separator, defaultTemplatePathSegments));
|
||||
|
||||
if (defaultTemplate.exists()) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("The template that is expected to use is not available. Therefore, using default template.");
|
||||
}
|
||||
return defaultTemplateName;
|
||||
}
|
||||
|
||||
throw new NoSuchFileException("Didn't found template file for " + templateName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches users which matches a given filter based on a claim
|
||||
*
|
||||
|
||||
@ -0,0 +1,277 @@
|
||||
/*
|
||||
* Copyright (c) 2018 - 2023, 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.device.mgt.core.ui.request.interceptor;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import io.entgra.device.mgt.core.ui.request.interceptor.beans.AuthData;
|
||||
import io.entgra.device.mgt.core.ui.request.interceptor.beans.JITData;
|
||||
import io.entgra.device.mgt.core.ui.request.interceptor.beans.JITEnrollmentData;
|
||||
import io.entgra.device.mgt.core.ui.request.interceptor.beans.ProxyResponse;
|
||||
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.httpclient.HttpStatus;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
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",
|
||||
description = "Call token endpoint and retrieve token",
|
||||
urlPatterns = {
|
||||
"/jit-enrollment-callback"
|
||||
}
|
||||
)
|
||||
public class JITEnrollmentCallbackHandler extends HttpServlet {
|
||||
private static final Log log = LogFactory.getLog(JITEnrollmentCallbackHandler.class);
|
||||
private String gatewayUrl;
|
||||
private String keyManagerUrl;
|
||||
private JITData JITInfo;
|
||||
private String encodedClientCredentials;
|
||||
private String applicationName;
|
||||
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
|
||||
+ System.getProperty(HandlerConstants.IOT_GW_HOST_ENV_VAR)
|
||||
+ HandlerConstants.COLON + HandlerUtil.getGatewayPort(request.getScheme());
|
||||
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) {
|
||||
response.sendError(HttpStatus.SC_UNAUTHORIZED);
|
||||
return;
|
||||
}
|
||||
|
||||
JITInfo = (JITData) session.getAttribute(HandlerConstants.SESSION_JIT_DATA_KEY);
|
||||
if (JITInfo == null) {
|
||||
response.sendError(HttpStatus.SC_UNAUTHORIZED);
|
||||
return;
|
||||
}
|
||||
|
||||
JITEnrollmentInfo = (JITEnrollmentData)
|
||||
session.getAttribute(HandlerConstants.SESSION_JIT_ENROLLMENT_DATA_KEY);
|
||||
if (JITEnrollmentInfo == null) {
|
||||
response.sendError(HttpStatus.SC_UNAUTHORIZED);
|
||||
return;
|
||||
}
|
||||
applicationName = request.getContextPath().substring(1,
|
||||
request.getContextPath().indexOf("-ui-request-handler"));
|
||||
initializeJITEnrollmentConfigurations();
|
||||
populateApplicationData(registerApplication());
|
||||
persistAuthData(session, getToken());
|
||||
response.sendRedirect(JITEnrollmentInfo.getRedirectUrl() + "?ownershipType=" +
|
||||
JITEnrollmentInfo.getOwnershipType() + "&os=" + JITEnrollmentInfo.getOs() + "&username=" +
|
||||
JITEnrollmentInfo.getUsername() + "&tenantDomain=" + JITEnrollmentInfo.getTenantDomain());
|
||||
} catch (JITEnrollmentException | IOException ex) {
|
||||
log.error("Error occurred while processing JIT provisioning callback request", ex);
|
||||
}
|
||||
}
|
||||
|
||||
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(), HandlerConstants.OS_ANDROID)) {
|
||||
enrollmentScopes = (Element) JITConfigurationDoc.
|
||||
getElementsByTagName(HandlerConstants.TAG_ANDROID_ENROLLMENT_SCOPES).item(0);
|
||||
} else if (Objects.equals(JITEnrollmentInfo.getOs(), HandlerConstants.OS_IOS)) {
|
||||
enrollmentScopes = (Element) JITConfigurationDoc.
|
||||
getElementsByTagName(HandlerConstants.TAG_IOS_ENROLLMENT_SCOPES).item(0);
|
||||
} else if (Objects.equals(JITEnrollmentInfo.getOs(), HandlerConstants.OS_WINDOWS)) {
|
||||
enrollmentScopes = (Element) JITConfigurationDoc.
|
||||
getElementsByTagName(HandlerConstants.TAG_WINDOWS_ENROLLMENT_SCOPES).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
|
||||
* @return {@link JsonObject} Json object corresponding to provided json string
|
||||
* @throws JITEnrollmentException throws when error occurred while parsing
|
||||
*/
|
||||
private JsonObject parseResponseData(String data) throws JITEnrollmentException {
|
||||
JsonParser parser = new JsonParser();
|
||||
JsonElement responseData = parser.parse(data);
|
||||
if (responseData.isJsonObject()) {
|
||||
return responseData.getAsJsonObject();
|
||||
}
|
||||
throw new JITEnrollmentException("Unexpected response body return");
|
||||
}
|
||||
|
||||
/***
|
||||
* Build application registration request
|
||||
* @return {@link HttpPost} Application registration request
|
||||
*/
|
||||
private HttpPost buildApplicationRegistrationRequest() {
|
||||
HttpPost applicationRegistrationRequest = new HttpPost(gatewayUrl + HandlerConstants.APP_REG_ENDPOINT);
|
||||
applicationRegistrationRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BASIC
|
||||
+ JITInfo.getEncodedClientCredentials());
|
||||
applicationRegistrationRequest.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString());
|
||||
JsonArray tags = new JsonArray();
|
||||
tags.add("device_management");
|
||||
JsonObject payload = new JsonObject();
|
||||
payload.addProperty("applicationName", applicationName);
|
||||
payload.add("tags", tags);
|
||||
payload.addProperty("allowedToAllDomains", false);
|
||||
payload.addProperty("mappingAnExistingOAuthApp", false);
|
||||
applicationRegistrationRequest.setEntity(new StringEntity(payload.toString(), ContentType.APPLICATION_JSON));
|
||||
return applicationRegistrationRequest;
|
||||
}
|
||||
|
||||
/***
|
||||
* Populate dynamic client's data
|
||||
* @param application - application data receiving from dcr request
|
||||
*/
|
||||
private void populateApplicationData(JsonObject application) {
|
||||
clientId = application.get("client_id").getAsString();
|
||||
clientSecret = application.get("client_secret").getAsString();
|
||||
String headerValue = clientId+ ':' + clientSecret;
|
||||
encodedClientCredentials = Base64.getEncoder().encodeToString(headerValue.getBytes());
|
||||
}
|
||||
|
||||
/***
|
||||
* Register client application
|
||||
* @return {@link JsonObject} Json object contain registered application data
|
||||
* @throws JITEnrollmentException throws when error occurred while application registration
|
||||
*/
|
||||
private JsonObject registerApplication() throws JITEnrollmentException {
|
||||
try {
|
||||
ProxyResponse proxyResponse = HandlerUtil.execute(buildApplicationRegistrationRequest());
|
||||
if (proxyResponse.getCode() == HttpStatus.SC_CREATED ||
|
||||
proxyResponse.getCode() == HttpStatus.SC_OK) {
|
||||
return parseResponseData(proxyResponse.getData());
|
||||
}
|
||||
throw new JITEnrollmentException("Unexpected response status return for application registration request");
|
||||
} catch (IOException ex) {
|
||||
throw new JITEnrollmentException("Error occurred while executing application registration request", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* Acquire token
|
||||
* @return {@link JsonObject} Json object containing token data
|
||||
* @throws JITEnrollmentException throws when error occurred while acquiring token
|
||||
*/
|
||||
private JsonObject getToken() throws JITEnrollmentException {
|
||||
try {
|
||||
ProxyResponse proxyResponse = HandlerUtil.execute(buildTokenAcquireRequest());
|
||||
if (proxyResponse.getCode() == org.apache.http.HttpStatus.SC_CREATED ||
|
||||
proxyResponse.getCode() == org.apache.http.HttpStatus.SC_OK) {
|
||||
return parseResponseData(proxyResponse.getData());
|
||||
}
|
||||
throw new JITEnrollmentException("Unexpected response status return for token acquiring request");
|
||||
} catch (IOException ex) {
|
||||
throw new JITEnrollmentException("Error occurred while executing token acquiring request", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* Build token acquire request
|
||||
* @return {@link HttpPost} Token acquire request
|
||||
*/
|
||||
private HttpPost buildTokenAcquireRequest() {
|
||||
HttpPost tokenAcquiringRequest = new HttpPost(keyManagerUrl + HandlerConstants.OAUTH2_TOKEN_ENDPOINT);
|
||||
tokenAcquiringRequest.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.toString());
|
||||
tokenAcquiringRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BASIC
|
||||
+ encodedClientCredentials);
|
||||
StringEntity payload = new StringEntity(
|
||||
"grant_type=" + HandlerConstants.CLIENT_CREDENTIAL_GRANT_TYPE + "&scope=" + scope,
|
||||
ContentType.APPLICATION_FORM_URLENCODED);
|
||||
tokenAcquiringRequest.setEntity(payload);
|
||||
return tokenAcquiringRequest;
|
||||
}
|
||||
|
||||
/***
|
||||
* Persists auth data in session
|
||||
* @param session - {@link HttpSession}
|
||||
* @param token - Json object containing token data
|
||||
*/
|
||||
private void persistAuthData(HttpSession session, JsonObject token) {
|
||||
AuthData authData = new AuthData();
|
||||
authData.setAccessToken(token.get("access_token").getAsString());
|
||||
authData.setClientId(clientId);
|
||||
authData.setClientSecret(clientSecret);
|
||||
authData.setEncodedClientApp(encodedClientCredentials);
|
||||
authData.setScope(token.get("scope").getAsString());
|
||||
session.setAttribute(HandlerConstants.SESSION_AUTH_DATA_KEY, authData);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2018 - 2023, 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.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;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.IOException;
|
||||
|
||||
@WebServlet(
|
||||
name = "JIT enrollment handler",
|
||||
description = "Handle jit enrollment request",
|
||||
urlPatterns = {
|
||||
"/jit-enrollment"
|
||||
}
|
||||
)
|
||||
public class JITEnrollmentHandler extends HttpServlet {
|
||||
private static final Log log = LogFactory.getLog(JITEnrollmentHandler.class);
|
||||
private String username;
|
||||
private String ownershipType;
|
||||
private String os;
|
||||
private String redirectUrl;
|
||||
private String tenantDomain;
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
|
||||
try {
|
||||
HttpSession session = request.getSession(true);
|
||||
String JITProvisionHandlerUrl = request.getScheme() + HandlerConstants.SCHEME_SEPARATOR
|
||||
+ System.getProperty(HandlerConstants.IOT_CORE_HOST_ENV_VAR)
|
||||
+ HandlerConstants.COLON + HandlerUtil.getCorePort(request.getScheme())
|
||||
+ request.getContextPath()
|
||||
+ HandlerConstants.JIT_PROVISION_HANDLER;
|
||||
String onCompletionUrl = request.getScheme() + HandlerConstants.SCHEME_SEPARATOR
|
||||
+ System.getProperty(HandlerConstants.IOT_CORE_HOST_ENV_VAR)
|
||||
+ HandlerConstants.COLON + HandlerUtil.getCorePort(request.getScheme())
|
||||
+ request.getContextPath()
|
||||
+ "/jit-enrollment-callback";
|
||||
username = request.getParameter("username");
|
||||
ownershipType = request.getParameter("ownershipType");
|
||||
os = request.getParameter("os");
|
||||
redirectUrl = request.getParameter("redirectUrl");
|
||||
tenantDomain = request.getParameter("tenantDomain");
|
||||
String sp = request.getParameter("sp");
|
||||
persistJITData(session);
|
||||
response.sendRedirect(JITProvisionHandlerUrl + "?tenantDomain=" + tenantDomain
|
||||
+ "&sp=" + sp + "&redirectUrl=" + onCompletionUrl);
|
||||
} catch (IOException ex) {
|
||||
log.error("Error occurred while handling JIT enrollment request");
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* Persists JIT data in session
|
||||
* @param session - {@link HttpSession}
|
||||
*/
|
||||
private void persistJITData(HttpSession session) {
|
||||
JITEnrollmentData JITEnrollmentInfo = new JITEnrollmentData();
|
||||
JITEnrollmentInfo.setOwnershipType(ownershipType);
|
||||
JITEnrollmentInfo.setOs(os);
|
||||
JITEnrollmentInfo.setUsername(username);
|
||||
JITEnrollmentInfo.setRedirectUrl(redirectUrl);
|
||||
JITEnrollmentInfo.setTenantDomain(tenantDomain);
|
||||
session.setAttribute(HandlerConstants.SESSION_JIT_ENROLLMENT_DATA_KEY, JITEnrollmentInfo);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2018 - 2023, 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.device.mgt.core.ui.request.interceptor;
|
||||
|
||||
import io.entgra.device.mgt.core.ui.request.interceptor.beans.JITData;
|
||||
import io.entgra.device.mgt.core.ui.request.interceptor.beans.JITEnrollmentData;
|
||||
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.httpclient.HttpStatus;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
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.Objects;
|
||||
|
||||
@WebServlet(
|
||||
name = "JIT callback handler",
|
||||
description = "Call token endpoint and retrieve token",
|
||||
urlPatterns = {
|
||||
"/jit-provision-callback"
|
||||
}
|
||||
)
|
||||
public class JITProvisionCallbackHandler extends HttpServlet {
|
||||
private static final Log log = LogFactory.getLog(JITProvisionCallbackHandler.class);
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
|
||||
String state = request.getParameter("state");
|
||||
HttpSession session = request.getSession(false);
|
||||
String JITProvisionCallbackURL = 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;
|
||||
try {
|
||||
if (session == null) {
|
||||
response.sendError(HttpStatus.SC_UNAUTHORIZED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == null || !Objects.equals(state, session.getAttribute("state").toString())) {
|
||||
response.sendError(org.apache.http.HttpStatus.SC_BAD_REQUEST, "MismatchingStateError: CSRF Warning! " +
|
||||
"State not equal in request and response");
|
||||
return;
|
||||
}
|
||||
|
||||
JITData JITInfo = (JITData) session.getAttribute(HandlerConstants.SESSION_JIT_DATA_KEY);
|
||||
if (JITInfo == null) {
|
||||
response.sendError(HttpStatus.SC_UNAUTHORIZED);
|
||||
return;
|
||||
}
|
||||
|
||||
response.sendRedirect(JITInfo.getRedirectUrl() + "?code=" + request.getParameter("code")
|
||||
+ "&redirectUrl=" + JITProvisionCallbackURL);
|
||||
} catch (IOException ex) {
|
||||
log.error("Error occurred while processing JIT provisioning callback request", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright (c) 2018 - 2023, 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.device.mgt.core.ui.request.interceptor;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import io.entgra.device.mgt.core.ui.request.interceptor.beans.JITData;
|
||||
import io.entgra.device.mgt.core.ui.request.interceptor.beans.ProxyResponse;
|
||||
import io.entgra.device.mgt.core.ui.request.interceptor.exceptions.JITEnrollmentException;
|
||||
import io.entgra.device.mgt.core.ui.request.interceptor.exceptions.JITProvisionException;
|
||||
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.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpStatus;
|
||||
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.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
@WebServlet(
|
||||
name = "JITProvisionRequestHandlerServlet",
|
||||
description = "Handle Just In Time Provisioning requests",
|
||||
urlPatterns = {
|
||||
"/jit-provision"
|
||||
}
|
||||
)
|
||||
public class JITProvisionHandler extends HttpServlet {
|
||||
private static final Log log = LogFactory.getLog(JITProvisionHandler.class);
|
||||
private String tenantDomain;
|
||||
private String clientId;
|
||||
private String JITServiceProviderName;
|
||||
private String encodedClientCredentials;
|
||||
private String JITConfigurationPath;
|
||||
private String redirectUrl;
|
||||
private String state;
|
||||
private static final Map<String, Element> tenantConfigs = new HashMap<>();
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
|
||||
String keyManagerUrl = request.getScheme() + HandlerConstants.SCHEME_SEPARATOR
|
||||
+ System.getProperty(HandlerConstants.IOT_KM_HOST_ENV_VAR)
|
||||
+ HandlerConstants.COLON + HandlerUtil.getKeyManagerPort(request.getScheme());
|
||||
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;
|
||||
JITConfigurationPath = CarbonUtils.getCarbonConfigDirPath() + File.separator + "jit-config.xml";
|
||||
String scope = "openid";
|
||||
state = HandlerUtil.generateStateToken();
|
||||
tenantDomain = request.getParameter("tenantDomain");
|
||||
redirectUrl = request.getParameter("redirectUrl");
|
||||
JITServiceProviderName = request.getParameter("sp");
|
||||
try {
|
||||
if (tenantDomain == null || JITServiceProviderName == null) {
|
||||
HandlerUtil.handleError(response, HttpStatus.SC_BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
if (!initializeJITConfigurations()) {
|
||||
HandlerUtil.handleError(response, HttpStatus.SC_SERVICE_UNAVAILABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
persistJITData(request.getSession(true));
|
||||
response.sendRedirect(keyManagerUrl + HandlerConstants.AUTHORIZATION_ENDPOINT +
|
||||
"?response_type=code" +
|
||||
"&client_id=" + clientId +
|
||||
"&state=" + state +
|
||||
"&scope=" + scope +
|
||||
"&redirect_uri=" + JITCallbackUrl);
|
||||
} catch (JITProvisionException | IOException ex) {
|
||||
log.error("Error occurred while processing JIT provisioning request", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* Retrieve JIT data from current session if session exists, otherwise build and return
|
||||
* @param session - {@link HttpSession}
|
||||
* @return {@link JITData}
|
||||
*/
|
||||
private JITData getJITData(HttpSession session) {
|
||||
return (session.getAttribute(HandlerConstants.SESSION_JIT_DATA_KEY) != null) ?
|
||||
(JITData) session.getAttribute(HandlerConstants.SESSION_JIT_DATA_KEY) : new JITData();
|
||||
}
|
||||
|
||||
/***
|
||||
* Persists JIT data in session
|
||||
* @param session {@link HttpSession}
|
||||
*/
|
||||
private void persistJITData(HttpSession session) {
|
||||
JITData JITInfo = getJITData(session);
|
||||
JITInfo.setEncodedClientCredentials(encodedClientCredentials);
|
||||
JITInfo.setTenantDomain(tenantDomain);
|
||||
JITInfo.setRedirectUrl(redirectUrl);
|
||||
JITInfo.setSp(JITServiceProviderName);
|
||||
session.setMaxInactiveInterval(3600);
|
||||
session.setAttribute("state", state);
|
||||
session.setAttribute(HandlerConstants.SESSION_JIT_DATA_KEY, JITInfo);
|
||||
}
|
||||
|
||||
/***
|
||||
* 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 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) &&
|
||||
Objects.equals(configElement.getAttributes().getNamedItem("name").getNodeValue(),
|
||||
JITServiceProviderName)) {
|
||||
return configElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/***
|
||||
* Initialize JIT configurations
|
||||
* @return boolean true when successful initialization, otherwise false
|
||||
* @throws JITProvisionException throws when error occurred
|
||||
*/
|
||||
private boolean initializeJITConfigurations() throws JITProvisionException {
|
||||
try {
|
||||
Element serviceProvider = tenantConfigs.get(tenantDomain);
|
||||
if (serviceProvider == null) {
|
||||
File JITConfigurationFile = new File(JITConfigurationPath);
|
||||
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
|
||||
Document JITConfigurationDoc = documentBuilder.parse(JITConfigurationFile);
|
||||
JITConfigurationDoc.getDocumentElement().normalize();
|
||||
serviceProvider = findServiceProvider(tenantDomain, JITConfigurationDoc);
|
||||
if (serviceProvider == null) return false;
|
||||
tenantConfigs.put(tenantDomain, serviceProvider);
|
||||
}
|
||||
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";
|
||||
throw new JITProvisionException(msg, ex);
|
||||
} catch (IOException ex) {
|
||||
String msg = "IO error occurred while parsing the JIT config file";
|
||||
throw new JITProvisionException(msg, ex);
|
||||
} catch (SAXException ex) {
|
||||
String msg = "Parse error occurred while parsing the JIT config document";
|
||||
throw new JITProvisionException(msg, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2018 - 2023 Entgra (Pvt) Ltd, Inc - All Rights Reserved.
|
||||
*
|
||||
* Unauthorised copying/redistribution of this file, via any medium is strictly prohibited.
|
||||
*
|
||||
* Licensed under the Entgra Commercial License, Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://entgra.io/licenses/entgra-commercial/1.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.device.mgt.core.ui.request.interceptor.beans;
|
||||
|
||||
public class JITData {
|
||||
private String username;
|
||||
private String tenantDomain;
|
||||
private String redirectUrl;
|
||||
private String sp;
|
||||
private String encodedClientCredentials;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getTenantDomain() {
|
||||
return tenantDomain;
|
||||
}
|
||||
|
||||
public void setTenantDomain(String tenantDomain) {
|
||||
this.tenantDomain = tenantDomain;
|
||||
}
|
||||
|
||||
public String getRedirectUrl() {
|
||||
return redirectUrl;
|
||||
}
|
||||
|
||||
public void setRedirectUrl(String redirectUrl) {
|
||||
this.redirectUrl = redirectUrl;
|
||||
}
|
||||
|
||||
public String getSp() {
|
||||
return sp;
|
||||
}
|
||||
|
||||
public void setSp(String sp) {
|
||||
this.sp = sp;
|
||||
}
|
||||
|
||||
public String getEncodedClientCredentials() {
|
||||
return encodedClientCredentials;
|
||||
}
|
||||
|
||||
public void setEncodedClientCredentials(String encodedClientCredentials) {
|
||||
this.encodedClientCredentials = encodedClientCredentials;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2018 - 2023 Entgra (Pvt) Ltd, Inc - All Rights Reserved.
|
||||
*
|
||||
* Unauthorised copying/redistribution of this file, via any medium is strictly prohibited.
|
||||
*
|
||||
* Licensed under the Entgra Commercial License, Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://entgra.io/licenses/entgra-commercial/1.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.device.mgt.core.ui.request.interceptor.beans;
|
||||
|
||||
public class JITEnrollmentData {
|
||||
private String username;
|
||||
private String tenantDomain;
|
||||
private String ownershipType;
|
||||
private String os;
|
||||
private String redirectUrl;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getTenantDomain() {
|
||||
return tenantDomain;
|
||||
}
|
||||
|
||||
public void setTenantDomain(String tenantDomain) {
|
||||
this.tenantDomain = tenantDomain;
|
||||
}
|
||||
|
||||
public String getOwnershipType() {
|
||||
return ownershipType;
|
||||
}
|
||||
|
||||
public void setOwnershipType(String ownershipType) {
|
||||
this.ownershipType = ownershipType;
|
||||
}
|
||||
|
||||
public String getOs() {
|
||||
return os;
|
||||
}
|
||||
|
||||
public void setOs(String os) {
|
||||
this.os = os;
|
||||
}
|
||||
|
||||
public String getRedirectUrl() {
|
||||
return redirectUrl;
|
||||
}
|
||||
|
||||
public void setRedirectUrl(String redirectUrl) {
|
||||
this.redirectUrl = redirectUrl;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2018 - 2023 Entgra (Pvt) Ltd, Inc - All Rights Reserved.
|
||||
*
|
||||
* Unauthorised copying/redistribution of this file, via any medium is strictly prohibited.
|
||||
*
|
||||
* Licensed under the Entgra Commercial License, Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://entgra.io/licenses/entgra-commercial/1.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.device.mgt.core.ui.request.interceptor.exceptions;
|
||||
|
||||
public class JITEnrollmentException extends Exception {
|
||||
public JITEnrollmentException(String msg, Throwable t) {
|
||||
super(msg, t);
|
||||
}
|
||||
public JITEnrollmentException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2018 - 2023 Entgra (Pvt) Ltd, Inc - All Rights Reserved.
|
||||
*
|
||||
* Unauthorised copying/redistribution of this file, via any medium is strictly prohibited.
|
||||
*
|
||||
* Licensed under the Entgra Commercial License, Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://entgra.io/licenses/entgra-commercial/1.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.device.mgt.core.ui.request.interceptor.exceptions;
|
||||
|
||||
public class JITProvisionException extends Exception {
|
||||
public JITProvisionException(String msg, Throwable t) {
|
||||
super(msg, t);
|
||||
}
|
||||
public JITProvisionException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@ -107,4 +107,18 @@ public class HandlerConstants {
|
||||
public static final String USER_SCOPES = "userScopes";
|
||||
public static final String HUBSPOT_CHAT_URL = "api.hubapi.com";
|
||||
public static final String USERNAME_WITH_DOMAIN = "usernameWithDomain";
|
||||
public static final String JIT_PROVISION_CALLBACK_URL = "/jit-provision-callback";
|
||||
public static final String JIT_ENROLLMENT_HANDLER_CALLBACK_URL = "/jit-enrollment-callback";
|
||||
public static final String DCR_URL = "/client-registration/v0.17/register";
|
||||
public static final String SESSION_JIT_DATA_KEY = "JITInfo";
|
||||
public static final String SESSION_JIT_ENROLLMENT_DATA_KEY = "JITEnrollmentInfo";
|
||||
public static final String JIT_PROVISION_HANDLER = "/jit-provision";
|
||||
public static final String JIT_ENROLLMENT_AUTH_APP_KEY = "JIT_ENROLLMENT_AUTH_APP";
|
||||
public static final String CLIENT_CREDENTIAL_GRANT_TYPE = "client_credentials";
|
||||
public static final String OS_ANDROID = "android";
|
||||
public static final String OS_WINDOWS = "windows";
|
||||
public static final String OS_IOS = "ios";
|
||||
public static final String TAG_ANDROID_ENROLLMENT_SCOPES = "AndroidEnrollmentScopes";
|
||||
public static final String TAG_WINDOWS_ENROLLMENT_SCOPES = "WindowsEnrollmentScopes";
|
||||
public static final String TAG_IOS_ENROLLMENT_SCOPES = "IOSEnrollmentScopes";
|
||||
}
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
|
||||
<!--
|
||||
~ Copyright (c) 2018 - 2023, 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.
|
||||
-->
|
||||
|
||||
<JITConfiguration>
|
||||
<EnrollmentConfiguration>
|
||||
<AndroidEnrollmentScopes>
|
||||
<Scope>dm:metadata:view</Scope>
|
||||
<Scope>dm:metadata:create</Scope>
|
||||
<Scope>dm:metadata:update</Scope>
|
||||
<Scope>and:devices:enroll</Scope>
|
||||
<Scope>dm:device:enroll</Scope>
|
||||
<Scope>and:conf:view</Scope>
|
||||
</AndroidEnrollmentScopes>
|
||||
<IOSEnrollmentScopes>
|
||||
<!-- <Scope></Scope> -->
|
||||
</IOSEnrollmentScopes>
|
||||
<WindowsEnrollmentScopes>
|
||||
<!-- <Scope></Scope> -->
|
||||
</WindowsEnrollmentScopes>
|
||||
</EnrollmentConfiguration>
|
||||
<ServiceProviderConfiguration>
|
||||
<!--<ServiceProvider tenantDomain="" name="">
|
||||
<ClientId></ClientId>
|
||||
<ClientSecret></ClientSecret>
|
||||
</ServiceProvider>-->
|
||||
</ServiceProviderConfiguration>
|
||||
</JITConfiguration>
|
||||
@ -0,0 +1,61 @@
|
||||
#*
|
||||
Copyright (C) 2018 - 2023 Entgra (Pvt) Ltd, Inc - All Rights Reserved.
|
||||
|
||||
Unauthorised copying/redistribution of this file, via any medium is strictly prohibited.
|
||||
|
||||
Licensed under the Entgra Commercial License, Version 1.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://entgra.io/licenses/entgra-commercial/1.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.
|
||||
*#
|
||||
<EmailConfig>
|
||||
<Subject>You have been invited to enroll your $device-type device in Entgra IoT</Subject>
|
||||
<Body>
|
||||
<![CDATA[
|
||||
<html>
|
||||
<head>
|
||||
<title>Entgra IoT Server</title>
|
||||
</head>
|
||||
<body style="color: #666666; background-color:#cdcdcd; padding: 0px; margin: 0px;">
|
||||
<div style="background-color:#cdcdcd; font-length: 1em; font-family: Arial, Helvetica; line-height: 170%; color: #666666; padding: 20px 0px; margin: 0px;">
|
||||
<div style="width: 86%; max-width: 650px; padding: 2%; background-color: #ffffff; margin: auto; border-radius: 14px;">
|
||||
<div style="line-height: 0px; border-top-left-radius: 10px; border-top-right-radius: 10px; padding: 10px;">
|
||||
<div style="display: inline-block; line-height: 0px;">
|
||||
<img alt="entgra" src="https://storage.googleapis.com/cdn-entgra/logo.png" height="50px" width="143px" />
|
||||
</div>
|
||||
</div>
|
||||
<div style="background-color: #ffffff; line-height: 170%; color: #666666; padding: 20px 25px;">
|
||||
<p style="font-length: 1em; font-family: Arial, Helvetica; line-height: 170%; color: #666666; margin: 5px 0px 20px;">
|
||||
Hi $username,
|
||||
</p>
|
||||
<p style="font-size: 1em; font-family: Arial, Helvetica; line-height: 170%; color: #666666; margin: 5px 0px;">
|
||||
You have been invited by $invite-by to enrol your $device-type device in Entgra IoT Server.
|
||||
Click <a href="$base-url-https/enroll-web-agent/$device-type/provision?username=$username&sp=$sp&tenantDomain=$tenant-domain&ownershipType=$ownership-type&os=$device-type">here</a> to begin device
|
||||
enrolment.</p>
|
||||
|
||||
<p style="font-length: 1em; font-family: Arial, Helvetica; line-height: 170%; color: #666666; margin: 5px 0px;">
|
||||
Should you need assistance, please contact your administrator.
|
||||
</p>
|
||||
|
||||
<p style="font-length: 1em; font-family: Arial, Helvetica; line-height: 170%; color: #666666; margin: 20px 0px 5px;">
|
||||
Regards,
|
||||
</p>
|
||||
<p style="font-size: 1em; font-family: Arial, Helvetica; line-height: 170%; color: #666666; margin: 5px 0px;">
|
||||
Entgra IoT Administrator
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
]]>
|
||||
</Body>
|
||||
</EmailConfig>
|
||||
@ -13,3 +13,4 @@ org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../../r
|
||||
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/io.entgra.device.mgt.core.device.mgt.basics_${feature.version}/email/templates,target:${installFolder}/../../../repository/resources/email-templates,overwrite:true);\
|
||||
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/io.entgra.device.mgt.core.device.mgt.basics_${feature.version}/conf_templates/,target:${installFolder}/../../resources/conf/,overwrite:true);\
|
||||
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/io.entgra.device.mgt.core.device.mgt.basics_${feature.version}/conf/traccar-config.xml,target:${installFolder}/../../conf/traccar-config.xml,overwrite:true);\
|
||||
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/io.entgra.device.mgt.core.device.mgt.basics_${feature.version}/conf/jit-config.xml,target:${installFolder}/../../conf/jit-config.xml,overwrite:true);\
|
||||
|
||||
@ -4,4 +4,5 @@ org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../featur
|
||||
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/io.entgra.device.mgt.core.ui.request.interceptor_${feature.version}/webapps/ui-request-handler.war,target:${installFolder}/../../deployment/server/webapps/store-ui-request-handler.war,overwrite:true);\
|
||||
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/io.entgra.device.mgt.core.ui.request.interceptor_${feature.version}/webapps/ui-request-handler.war,target:${installFolder}/../../deployment/server/webapps/entgra-ui-request-handler.war,overwrite:true);\
|
||||
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/io.entgra.device.mgt.core.ui.request.interceptor_${feature.version}/webapps/ui-request-handler.war,target:${installFolder}/../../deployment/server/webapps/mdm-reports-ui-request-handler.war,overwrite:true);\
|
||||
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/io.entgra.device.mgt.core.ui.request.interceptor_${feature.version}/webapps/ui-request-handler.war,target:${installFolder}/../../deployment/server/webapps/enroll-web-agent-ui-request-handler.war,overwrite:true);\
|
||||
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/io.entgra.device.mgt.core.ui.request.interceptor_${feature.version}/payloads/,target:${installFolder}/../../resources/payloads/,overwrite:true);\
|
||||
|
||||
Loading…
Reference in New Issue
Block a user