Merge branch 'master' of ssh://repository.entgra.net:222/community/device-mgt-core

fix-ws
osh 11 months ago
commit a95d9438e5

@ -456,17 +456,19 @@ public class APIPublisherServiceImpl implements APIPublisherService {
Scope scope = new Scope();
for (DefaultPermission defaultPermission: defaultPermissions.getDefaultPermissions()) {
//todo check whether scope is available or not
ScopeMapping scopeMapping = defaultPermission.getScopeMapping();
List<String> bindings = new ArrayList<>(
Arrays.asList(scopeMapping.getDefaultRoles().split(",")));
bindings.add(ADMIN_ROLE_KEY);
scope.setName(scopeMapping.getKey());
scope.setDescription(scopeMapping.getName());
scope.setDisplayName(scopeMapping.getName());
scope.setBindings(bindings);
publisherRESTAPIServices.addNewSharedScope(apiApplicationKey, accessTokenInfo, scope);
if (!publisherRESTAPIServices.isSharedScopeNameExists(apiApplicationKey, accessTokenInfo,
defaultPermission.getScopeMapping().getKey())) {
ScopeMapping scopeMapping = defaultPermission.getScopeMapping();
List<String> bindings = new ArrayList<>(
Arrays.asList(scopeMapping.getDefaultRoles().split(",")));
bindings.add(ADMIN_ROLE_KEY);
scope.setName(scopeMapping.getKey());
scope.setDescription(scopeMapping.getName());
scope.setDisplayName(scopeMapping.getName());
scope.setBindings(bindings);
publisherRESTAPIServices.addNewSharedScope(apiApplicationKey, accessTokenInfo, scope);
}
}
} catch (BadRequestException | UnexpectedResponseException | APIServicesException e) {
log.error("Error occurred while adding default scopes");

@ -1333,7 +1333,7 @@ public class ApplicationManagerImpl implements ApplicationManager {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
String iconPath = APIUtil.createAppIconPath(applicationReleaseDTO, tenantId);
DataHolder.getInstance().getDeviceManagementService().saveApplicationIcon(iconPath,
String.valueOf(applicationReleaseDTO.getPackageName()), applicationReleaseDTO.getVersion(), tenantId);
String.valueOf(applicationReleaseDTO.getPackageName()), applicationReleaseDTO.getVersion());
} catch (ApplicationManagementException e) {
String msg = "Error occurred while creating iconPath. Application package name : " + applicationReleaseDTO.getPackageName();
log.error(msg, e);

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

@ -0,0 +1,252 @@
/*
* 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.device.mgt.api.jaxrs.service.api;
import io.entgra.device.mgt.core.apimgt.annotations.Scope;
import io.entgra.device.mgt.core.apimgt.annotations.Scopes;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.ErrorResponse;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.util.Constants;
import io.swagger.annotations.*;
import org.apache.axis2.transport.http.HTTPConstants;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
/**
* Metadata related REST-API implementation.
*/
@SwaggerDefinition(
info = @Info(
version = "1.0.0",
title = "Device Status Filter Service",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = "name", value = "DeviceStatusManagement"),
@ExtensionProperty(name = "context", value = "/api/device-mgt/v1.0/device-status-filters"),
})
}
),
tags = {
@Tag(name = "device_management")
}
)
@Scopes(
scopes = {
@Scope(
name = "View Device Status Filter",
description = "View device status details",
key = "dm:devicestatusfilter:view",
roles = {"Internal/devicemgt-user"},
permissions = {"/device-mgt/device-status-filters/view"}
),
@Scope(
name = "Update Device status filter",
description = "Updating Device status filter",
key = "dm:devicestatusfilter:update",
roles = {"Internal/devicemgt-user"},
permissions = {"/device-mgt/device-status-filters/update"}
),
}
)
@Api(value = "Device Status Management")
@Path("/device-status-filters")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public interface DeviceStatusFilterService {
@GET
@Path("/{device-type}")
@ApiOperation(
httpMethod = HTTPConstants.HEADER_GET,
value = "Get device status filters",
notes = "Get device status filters for the tenant of the logged in user",
tags = "Tenant Metadata Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "dm:devicestatusfilter:view")
})
}
)
@ApiResponses(
value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully retrieved device status filters.",
responseHeaders = {
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body"),
@ResponseHeader(
name = "ETag",
description = "Entity Tag of the response resource.\n" +
"Used by caches, or in conditional requests."),
@ResponseHeader(
name = "Last-Modified",
description = "Date and time the resource was last modified.\n" +
"Used by caches, or in conditional requests."),
}),
@ApiResponse(
code = 500,
message = "Internal Server Error. " +
"\n Server error occurred while getting device status filters.",
response = ErrorResponse.class)
})
Response getDeviceStatusFilters( @ApiParam(
name = "deviceType",
value = "The device type.",
required = true) @PathParam ("device-type") String deviceType);
@GET
@Path("/is-enabled")
@ApiOperation(
httpMethod = HTTPConstants.HEADER_GET,
value = "Get device status filter",
notes = "Get device status filter enable or not for the tenant of the logged in user",
tags = "Tenant Metadata Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "dm:devicestatusfilter:view")
})
}
)
@ApiResponses(
value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully retrieved device status filter.",
response = Response.class,
responseHeaders = {
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body"),
@ResponseHeader(
name = "ETag",
description = "Entity Tag of the response resource.\n" +
"Used by caches, or in conditional requests."),
@ResponseHeader(
name = "Last-Modified",
description = "Date and time the resource was last modified.\n" +
"Used by caches, or in conditional requests."),
}),
@ApiResponse(
code = 500,
message = "Internal Server Error. " +
"\n Server error occurred while getting device status check.",
response = ErrorResponse.class)
})
Response getDeviceStatusCheck();
@PUT
@Path("/toggle-device-status")
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = HTTPConstants.HEADER_POST,
value = "Update Device status check for tenant",
notes = "Update Device status check for the tenant of the logged in user",
tags = "Tenant Metadata Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "dm:devicestatusfilter:update")
})
}
)
@ApiResponses(
value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully updated device status check.",
response = Response.class,
responseHeaders = {
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body"),
@ResponseHeader(
name = "ETag",
description = "Entity Tag of the response resource.\n" +
"Used by caches, or in conditional requests."),
@ResponseHeader(
name = "Last-Modified",
description = "Date and time the resource was last modified.\n" +
"Used by caches, or in conditional requests."),
}),
@ApiResponse(
code = 500,
message = "Internal Server Error. " +
"\n Server error occurred while updating device status check.",
response = ErrorResponse.class)
})
Response updateDeviceStatusCheck(
@ApiParam(
name = "Device status check",
value = "The device status filtering is enable or not.",
required = true)
@QueryParam("isEnabled") boolean isEnabled);
@PUT
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = HTTPConstants.HEADER_POST,
value = "Update Device status filters for given device type for tenant",
notes = "Update Device status filters for given device type for the tenant of the logged in user",
tags = "Tenant Metadata Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "dm:devicestatusfilter:update")
})
}
)
@ApiResponses(
value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully updated device status filters for given device type..",
response = Response.class,
responseHeaders = {
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body"),
@ResponseHeader(
name = "ETag",
description = "Entity Tag of the response resource.\n" +
"Used by caches, or in conditional requests."),
@ResponseHeader(
name = "Last-Modified",
description = "Date and time the resource was last modified.\n" +
"Used by caches, or in conditional requests."),
}),
@ApiResponse(
code = 500,
message = "Internal Server Error. " +
"\n Server error occurred while updating device status filters for given device type.",
response = ErrorResponse.class)
})
Response updateDeviceStatusFilters(
@ApiParam(
name = "deviceType",
value = "The device type for which you want to update device status filters.",
required = true)
@QueryParam("deviceType") String deviceType,
@ApiParam(
name = "deviceStatus",
value = "A list of device status values to update for the given device type.",
required = true)
@QueryParam("deviceStatus") List<String> deviceStatus);
}

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

@ -0,0 +1,120 @@
/*
* 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.device.mgt.api.jaxrs.service.impl;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.api.DeviceStatusFilterService;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.util.DeviceMgtAPIUtils;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.MetadataManagementException;
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.DeviceStatusManagementService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.CarbonContext;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
@Path("/device-status-filters")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class DeviceStatusFilterServiceImpl implements DeviceStatusFilterService {
private static final Log log = LogFactory.getLog(DeviceStatusFilterServiceImpl.class);
@Override
@GET
@Path("/{deviceType}")
public Response getDeviceStatusFilters(@PathParam("deviceType") String deviceType) {
List<String> result;
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
try {
DeviceStatusManagementService deviceManagementProviderService = DeviceMgtAPIUtils.getDeviceStatusManagmentService();
result = deviceManagementProviderService.getDeviceStatusFilters(deviceType, tenantId);
if (result != null) {
return Response.status(Response.Status.OK).entity(result).build();
}
return Response.status(Response.Status.NO_CONTENT).entity(false).build();
} catch (MetadataManagementException e) {
String msg = "Error occurred while getting device status filter of the tenant.";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
@GET
@Path("/is-enabled")
@Override
public Response getDeviceStatusCheck() {
boolean result;
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
try {
DeviceStatusManagementService deviceManagementProviderService = DeviceMgtAPIUtils.getDeviceStatusManagmentService();
result = deviceManagementProviderService.getDeviceStatusCheck(tenantId);
return Response.status(Response.Status.OK).entity(result).build();
} catch (MetadataManagementException e) {
String msg = "Error occurred while getting device status filter of the tenant.";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
@Override
@PUT
@Path("/toggle-device-status")
public Response updateDeviceStatusCheck(
@QueryParam("isEnabled")
boolean isEnabled) {
boolean result;
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
try {
DeviceStatusManagementService deviceManagementProviderService = DeviceMgtAPIUtils.getDeviceStatusManagmentService();
result = deviceManagementProviderService.updateDefaultDeviceStatusCheck(tenantId, isEnabled);
if (result) {
return Response.status(Response.Status.OK).entity("Successfully updated device status check.").build();
} else {
return Response.status(Response.Status.NO_CONTENT).entity(false).build();
}
} catch (MetadataManagementException e) {
String msg = "Error occurred while updating device status check.";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
@Override
@PUT
public Response updateDeviceStatusFilters(
@QueryParam("deviceType")
String deviceType,
@QueryParam("deviceStatus")
List<String> deviceStatus
) {
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
try {
DeviceStatusManagementService deviceManagementProviderService = DeviceMgtAPIUtils.getDeviceStatusManagmentService();
deviceManagementProviderService.updateDefaultDeviceStatusFilters(tenantId, deviceType, deviceStatus);
return Response.status(Response.Status.OK).entity("Successfully updated device status filters for " + deviceType).build();
} catch (MetadataManagementException e) {
String msg = "Error occurred while updating device status for " + deviceType;
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
}

@ -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;
@ -349,9 +349,9 @@ public class UserManagementServiceImpl implements UserManagementService {
}
return Response.status(Response.Status.OK).build();
} else {
String msg = "There are enrolled devices for user: " + username + ". Please remove them before deleting the user.";
String msg = "Before deleting this user, ensure there are no devices assigned to the user. You can either remove the devices or change their owner through an update enrollment operation.";
log.error(msg);
return Response.status(400).entity(msg).build();
return Response.status(409).entity(msg).build();
}
} catch (DeviceManagementException | UserStoreException e) {
String msg = "Exception in trying to remove user by user: " + username;
@ -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
*

@ -21,6 +21,7 @@ package io.entgra.device.mgt.core.device.mgt.api.jaxrs.util;
import io.entgra.device.mgt.core.apimgt.webapp.publisher.APIPublisherService;
import io.entgra.device.mgt.core.application.mgt.common.services.ApplicationManager;
import io.entgra.device.mgt.core.application.mgt.common.services.SubscriptionManager;
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.DeviceStatusManagementService;
import org.apache.axis2.AxisFault;
import org.apache.axis2.client.Options;
import org.apache.axis2.java.security.SSLProtocolSocketFactory;
@ -153,6 +154,8 @@ public class DeviceMgtAPIUtils {
// private static IntegrationClientService integrationClientService;
private static MetadataManagementService metadataManagementService;
private static WhiteLabelManagementService whiteLabelManagementService;
private static DeviceStatusManagementService deviceStatusManagementService;
private static OTPManagementService otpManagementService;
private static volatile SubscriptionManager subscriptionManager;
@ -532,6 +535,28 @@ public class DeviceMgtAPIUtils {
return whiteLabelManagementService;
}
/**
* Initializing and accessing method for DeviceStatusManagementService.
*
* @return WhiteLabelManagementService instance
* @throws IllegalStateException if DeviceStatusManagementService cannot be initialized
*/
public static DeviceStatusManagementService getDeviceStatusManagmentService() {
if (deviceStatusManagementService == null) {
synchronized (DeviceMgtAPIUtils.class) {
if (deviceStatusManagementService == null) {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
deviceStatusManagementService = (DeviceStatusManagementService) ctx.getOSGiService(
DeviceStatusManagementService.class, null);
if (deviceStatusManagementService == null) {
throw new IllegalStateException("DeviceStatusManagementService Management service not initialized.");
}
}
}
}
return deviceStatusManagementService;
}
/**
* Initializing and accessing method for MetadataManagementService.
*

@ -50,6 +50,7 @@
<ref bean="analyticsArtifactsManagementService"/>
<ref bean="metadataService"/>
<ref bean="whitelabelService"/>
<ref bean="deviceStatusFilterService"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="jsonProvider"/>
@ -101,6 +102,7 @@
<bean id="analyticsArtifactsManagementService" class="io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl.AnalyticsArtifactsManagementServiceImpl"/>
<bean id="metadataService" class="io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl.MetadataServiceImpl"/>
<bean id="whitelabelService" class="io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl.WhiteLabelServiceImpl"/>
<bean id="deviceStatusFilterService" class="io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl.DeviceStatusFilterServiceImpl"/>
<!--<bean id="errorHandler" class="io.entgra.device.mgt.core.device.mgt.api.jaxrs.common.ErrorHandler"/>-->
<cxf:bus>

@ -0,0 +1,43 @@
/*
* 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.device.mgt.common.metadata.mgt;
import java.util.List;
public class AllowedDeviceStatus {
private String type;
private List<String> status;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<String> getStatus() {
return status;
}
public void setStatus(List<String> status) {
this.status = status;
}
}

@ -0,0 +1,85 @@
/*
* 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.device.mgt.common.metadata.mgt;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.MetadataManagementException;
import java.util.List;
public interface DeviceStatusManagementService {
/**
* This method is useful to create & persist default device status filter for provided tenant if
* it doesn't exist already
*
* @throws MetadataManagementException if error while adding default device status
*/
void addDefaultDeviceStatusFilterIfNotExist(int tenantId) throws MetadataManagementException;
/**
* This method is useful to reset existing device status to default values in xml
*
* @throws MetadataManagementException if error while resetting default device status
*/
void resetToDefaultDeviceStausFilter() throws MetadataManagementException;
/**
* This method is useful to update existing allowed device status
*
* @throws MetadataManagementException if error while updating existing device status
*/
void updateDefaultDeviceStatusFilters(int tenantId, String deviceType, List<String> deviceStatus)
throws MetadataManagementException;
/**
* This method is useful to update existing device status check
*
* @throws MetadataManagementException if error while updating existing device status
*/
boolean updateDefaultDeviceStatusCheck(int tenantId, boolean isChecked)
throws MetadataManagementException;
/**
* This method is useful to get existing device status filters
*
* @throws MetadataManagementException if error while getting existing device status
*/
List<AllowedDeviceStatus> getDeviceStatusFilters(int tenantId) throws MetadataManagementException;
/**
* This method is useful to get existing device status filters by device type and tenant id
*
* @throws MetadataManagementException if error while getting existing device status
*/
List<String> getDeviceStatusFilters(String deviceType, int tenantId) throws MetadataManagementException;
/**
* This method is useful to get existing device status filters
*
* @throws MetadataManagementException if error while getting existing device status check
*/
boolean getDeviceStatusCheck(int tenantId) throws MetadataManagementException;
/**
* This method is useful to check status is valid for device type
*
* @throws MetadataManagementException if error while getting existing device status check
*/
boolean isDeviceStatusValid(String deviceType, String deviceStatus, int tenantId) throws MetadataManagementException;
}

@ -0,0 +1,46 @@
/*
* 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.device.mgt.core.config.ui;
import javax.xml.bind.annotation.XmlElement;
import java.util.List;
public class DeviceStatusConfigurations {
private List<DeviceStatusItem> deviceStatusItems;
private boolean deviceStatusCheck;
@XmlElement(name = "DeviceStatusItem")
public List<DeviceStatusItem> getDeviceStatusItems() {
return deviceStatusItems;
}
@XmlElement(name = "EnableDeviceStatusCheck")
public boolean isDeviceStatusCheck() {
return deviceStatusCheck;
}
public void setDeviceStatusCheck(boolean deviceStatusCheck) {
this.deviceStatusCheck = deviceStatusCheck;
}
public void setDeviceStatusItems(List<DeviceStatusItem> deviceStatusItems) {
this.deviceStatusItems = deviceStatusItems;
}
}

@ -0,0 +1,48 @@
/*
* 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.device.mgt.core.config.ui;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import java.util.List;
public class DeviceStatusItem {
private List<String> status;
private String type;
@XmlElement(name = "Type")
public String getType() {
return type;
}
@XmlElementWrapper(name = "AllowedStatus")
@XmlElement(name = "Status")
public List<String> getStatus() {
return status;
}
public void setType(String type) {
this.type = type;
}
public void setStatus(List<String> status) {
this.status = status;
}
}

@ -38,7 +38,9 @@ public class UIConfiguration {
private DeviceInfoConfigurations deviceInfoConfigurations;
@XmlElement(name = "AppRegistration", required=true)
private DeviceStatusConfigurations deviceStatusConfigurations;
@XmlElement(name = "AppRegistration", required = true)
public AppRegistration getAppRegistration() {
return appRegistration;
}
@ -74,7 +76,8 @@ public class UIConfiguration {
public void setHubspotChat(HubspotChat hubspotChat) {
this.hubspotChat = hubspotChat;
}
@XmlElement(name = "Billing", required=true)
@XmlElement(name = "Billing", required = true)
public Billing getBilling() {
return billing;
}
@ -109,4 +112,13 @@ public class UIConfiguration {
public void setDeviceInfoConfigurations(DeviceInfoConfigurations deviceInfoConfigurations) {
this.deviceInfoConfigurations = deviceInfoConfigurations;
}
@XmlElement(name = "DeviceStatusConfigurations", required = true)
public DeviceStatusConfigurations getDeviceStatusConfigurations() {
return deviceStatusConfigurations;
}
public void setDeviceStatusConfigurations(DeviceStatusConfigurations deviceStatusConfigurations) {
this.deviceStatusConfigurations = deviceStatusConfigurations;
}
}

@ -114,4 +114,14 @@ public interface ApplicationDAO {
* @throws DeviceManagementDAOException
*/
String getIconPath(String applicationIdentifier) throws DeviceManagementDAOException;
/**
* This method is used to get the installed application list of a specific device
* @param deviceId ID of the device
* @param enrolmentId Enrolment ID of the device
* @param tenantId tenant ID
* @throws DeviceManagementDAOException If any database error occurred
*/
List<Application> getInstalledApplicationListOnDevice(int deviceId, int enrolmentId, int tenantId)
throws DeviceManagementDAOException;
}

@ -62,4 +62,35 @@ public interface EnrollmentDAO {
boolean updateOwnerOfEnrollment(List<Device> devices, String owner, int tenantId)
throws DeviceManagementDAOException;
/***
*This method is used to add the device status of the enrollment for given set of devices to given user.
*
* @param currentOwner of device.
* @param status going to add
* @param tenantId tenant id.
* @return either (1) true, if device status is succeeded or false.
* @throws DeviceManagementDAOException if an error occurs when updating device owner.
*/
boolean addDeviceStatus(String currentOwner, EnrolmentInfo.Status status, int tenantId) throws DeviceManagementDAOException;
/***
*This method is used to add the device status of the enrollment for given set of devices to given user.
*
* @param config of Enrollment.
* @return either (1) true, if device status is succeeded or false.
* @throws DeviceManagementDAOException if an error occurs when updating device owner.
*/
boolean addDeviceStatus(EnrolmentInfo config) throws DeviceManagementDAOException;
/***
*This method is used to add the device status of the enrollment for given set of devices to given user.
*
* @param enrolmentId of device.
* @param status going to add
* @return either (1) true, if device status is succeeded or false.
* @throws DeviceManagementDAOException if an error occurs when updating device owner.
*/
boolean addDeviceStatus(int enrolmentId, EnrolmentInfo.Status status) throws DeviceManagementDAOException;
}

@ -93,9 +93,6 @@ public abstract class AbstractEnrollmentDAOImpl implements EnrollmentDAO {
stmt.setInt(4, enrolmentInfo.getId());
stmt.setInt(5, tenantId);
int updatedCount = stmt.executeUpdate();
if (updatedCount == 1){
addDeviceStatus(enrolmentInfo.getId(), enrolmentInfo.getStatus());
}
return updatedCount;
} catch (SQLException e) {
throw new DeviceManagementDAOException("Error occurred while updating enrolment configuration", e);
@ -131,9 +128,6 @@ public abstract class AbstractEnrollmentDAOImpl implements EnrollmentDAO {
}
if (updateStatus > 0) {
status = true;
for (EnrolmentInfo enrolmentInfo : enrolmentInfos) {
addDeviceStatus(enrolmentInfo);
}
}
} catch (SQLException e) {
throw new DeviceManagementDAOException("Error occurred while updating enrolment status of given device-list.", e);
@ -256,11 +250,11 @@ public abstract class AbstractEnrollmentDAOImpl implements EnrollmentDAO {
return true;
}
private boolean addDeviceStatus(EnrolmentInfo config) throws DeviceManagementDAOException {
public boolean addDeviceStatus(EnrolmentInfo config) throws DeviceManagementDAOException {
return addDeviceStatus(config.getId(), config.getStatus());
}
private boolean addDeviceStatus(String currentOwner, EnrolmentInfo.Status status, int tenantId) throws DeviceManagementDAOException {
public boolean addDeviceStatus(String currentOwner, EnrolmentInfo.Status status, int tenantId) throws DeviceManagementDAOException {
Connection conn;
String changedBy = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
if (changedBy == null){
@ -323,7 +317,7 @@ public abstract class AbstractEnrollmentDAOImpl implements EnrollmentDAO {
return true;
}
private boolean addDeviceStatus(int enrolmentId, EnrolmentInfo.Status status) throws DeviceManagementDAOException {
public boolean addDeviceStatus(int enrolmentId, EnrolmentInfo.Status status) throws DeviceManagementDAOException {
Connection conn;
String changedBy = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
if (changedBy == null){
@ -347,7 +341,7 @@ public abstract class AbstractEnrollmentDAOImpl implements EnrollmentDAO {
DeviceManagementDAOUtil.cleanupResources(stmt, null);
// if there was no record for the enrolment or the previous status is not the same as the current status
// we'll add a record
if (previousStatus == null || previousStatus != status){
if (previousStatus == null || previousStatus != status) {
if (deviceId == -1) {
// we need the device id in order to add a new record, therefore we get it from the enrolment table
sql = "SELECT DEVICE_ID FROM DM_ENROLMENT WHERE ID = ?";

@ -575,4 +575,50 @@ public class ApplicationDAOImpl implements ApplicationDAO {
}
return applicationList;
}
public List<Application> getInstalledApplicationListOnDevice(int deviceId, int enrolmentId, int tenantId)
throws DeviceManagementDAOException {
Connection conn;
List<Application> applicationList = new ArrayList<>();
Application application;
String sql = "SELECT " +
"ID, " +
"NAME, " +
"APP_IDENTIFIER, " +
"PLATFORM, " +
"CATEGORY, " +
"VERSION, " +
"TYPE, " +
"LOCATION_URL, " +
"IMAGE_URL, " +
"APP_PROPERTIES, " +
"MEMORY_USAGE, " +
"IS_ACTIVE, " +
"TENANT_ID " +
"FROM DM_APPLICATION " +
"WHERE DEVICE_ID = ? AND " +
"ENROLMENT_ID = ? AND " +
"TENANT_ID = ? ";
try {
conn = this.getConnection();
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, deviceId);
stmt.setInt(2, enrolmentId);
stmt.setInt(3, tenantId);
try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
application = loadApplication(rs);
applicationList.add(application);
}
}
}
} catch (SQLException e) {
String msg = "SQL Error occurred while retrieving the list of Applications " +
"installed in device id '" + deviceId;
log.error(msg, e);
throw new DeviceManagementDAOException(msg, e);
}
return applicationList;
}
}

@ -88,9 +88,6 @@ public class GenericEnrollmentDAOImpl extends AbstractEnrollmentDAOImpl {
stmt.setInt(4, enrolmentInfo.getId());
stmt.setInt(5, tenantId);
int updatedCount = stmt.executeUpdate();
if (updatedCount == 1){
addDeviceStatus(enrolmentInfo.getId(), enrolmentInfo.getStatus());
}
return updatedCount;
} catch (SQLException e) {
throw new DeviceManagementDAOException("Error occurred while updating enrolment configuration", e);
@ -126,9 +123,6 @@ public class GenericEnrollmentDAOImpl extends AbstractEnrollmentDAOImpl {
}
if (updateStatus > 0) {
status = true;
for (EnrolmentInfo enrolmentInfo : enrolmentInfos) {
addDeviceStatus(enrolmentInfo);
}
}
} catch (SQLException e) {
throw new DeviceManagementDAOException("Error occurred while updating enrolment status of given device-list.", e);
@ -251,11 +245,11 @@ public class GenericEnrollmentDAOImpl extends AbstractEnrollmentDAOImpl {
return true;
}
private boolean addDeviceStatus(EnrolmentInfo config) throws DeviceManagementDAOException {
public boolean addDeviceStatus(EnrolmentInfo config) throws DeviceManagementDAOException {
return addDeviceStatus(config.getId(), config.getStatus());
}
private boolean addDeviceStatus(String currentOwner, EnrolmentInfo.Status status, int tenantId) throws DeviceManagementDAOException {
public boolean addDeviceStatus(String currentOwner, EnrolmentInfo.Status status, int tenantId) throws DeviceManagementDAOException {
Connection conn;
String changedBy = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
if (changedBy == null){
@ -318,7 +312,7 @@ public class GenericEnrollmentDAOImpl extends AbstractEnrollmentDAOImpl {
return true;
}
private boolean addDeviceStatus(int enrolmentId, EnrolmentInfo.Status status) throws DeviceManagementDAOException {
public boolean addDeviceStatus(int enrolmentId, EnrolmentInfo.Status status) throws DeviceManagementDAOException {
Connection conn;
String changedBy = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
if (changedBy == null){

@ -87,9 +87,6 @@ public class SQLServerEnrollmentDAOImpl extends AbstractEnrollmentDAOImpl {
stmt.setInt(4, enrolmentInfo.getId());
stmt.setInt(5, tenantId);
int updatedCount = stmt.executeUpdate();
if (updatedCount == 1){
addDeviceStatus(enrolmentInfo.getId(), enrolmentInfo.getStatus());
}
return updatedCount;
} catch (SQLException e) {
throw new DeviceManagementDAOException("Error occurred while updating enrolment configuration", e);
@ -125,9 +122,6 @@ public class SQLServerEnrollmentDAOImpl extends AbstractEnrollmentDAOImpl {
}
if (updateStatus > 0) {
status = true;
for (EnrolmentInfo enrolmentInfo : enrolmentInfos) {
addDeviceStatus(enrolmentInfo);
}
}
} catch (SQLException e) {
throw new DeviceManagementDAOException("Error occurred while updating enrolment status of given device-list.", e);
@ -250,11 +244,11 @@ public class SQLServerEnrollmentDAOImpl extends AbstractEnrollmentDAOImpl {
return true;
}
private boolean addDeviceStatus(EnrolmentInfo config) throws DeviceManagementDAOException {
public boolean addDeviceStatus(EnrolmentInfo config) throws DeviceManagementDAOException {
return addDeviceStatus(config.getId(), config.getStatus());
}
private boolean addDeviceStatus(String currentOwner, EnrolmentInfo.Status status, int tenantId) throws DeviceManagementDAOException {
public boolean addDeviceStatus(String currentOwner, EnrolmentInfo.Status status, int tenantId) throws DeviceManagementDAOException {
Connection conn;
String changedBy = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
if (changedBy == null){
@ -317,7 +311,7 @@ public class SQLServerEnrollmentDAOImpl extends AbstractEnrollmentDAOImpl {
return true;
}
private boolean addDeviceStatus(int enrolmentId, EnrolmentInfo.Status status) throws DeviceManagementDAOException {
public boolean addDeviceStatus(int enrolmentId, EnrolmentInfo.Status status) throws DeviceManagementDAOException {
Connection conn;
String changedBy = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
if (changedBy == null){

@ -18,6 +18,7 @@
package io.entgra.device.mgt.core.device.mgt.core.internal;
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.DeviceStatusManagementService;
import io.entgra.device.mgt.core.server.bootup.heartbeat.beacon.service.HeartBeatManagementService;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import io.entgra.device.mgt.core.device.mgt.common.DeviceStatusTaskPluginConfig;
@ -93,6 +94,8 @@ public class DeviceManagementDataHolder {
private WhiteLabelManagementService whiteLabelManagementService;
private TraccarManagementService traccarManagementService;
private DeviceStatusManagementService deviceStatusManagementService;
private final Map<DeviceType, DeviceStatusTaskPluginConfig> deviceStatusTaskPluginConfigs = Collections.synchronizedMap(
new HashMap<>());
@ -384,6 +387,14 @@ public class DeviceManagementDataHolder {
this.whiteLabelManagementService = whiteLabelManagementService;
}
public DeviceStatusManagementService getDeviceStatusManagementService() {
return deviceStatusManagementService;
}
public void setDeviceStatusManagementService(DeviceStatusManagementService deviceStatusManagementService) {
this.deviceStatusManagementService = deviceStatusManagementService;
}
public TraccarManagementService getTraccarManagementService() {
TraccarManagementService traccarManagementService;
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();

@ -17,6 +17,8 @@
*/
package io.entgra.device.mgt.core.device.mgt.core.internal;
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.DeviceStatusManagementService;
import io.entgra.device.mgt.core.device.mgt.core.metadata.mgt.DeviceStatusManagementServiceImpl;
import io.entgra.device.mgt.core.server.bootup.heartbeat.beacon.service.HeartBeatManagementService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@ -372,6 +374,17 @@ public class DeviceManagementServiceComponent {
}
bundleContext.registerService(WhiteLabelManagementService.class.getName(), whiteLabelManagementService, null);
/* Registering DeviceState Filter Service */
DeviceStatusManagementService deviceStatusManagemntService = new DeviceStatusManagementServiceImpl();
DeviceManagementDataHolder.getInstance().setDeviceStatusManagementService(deviceStatusManagemntService);
try {
deviceStatusManagemntService.addDefaultDeviceStatusFilterIfNotExist(tenantId);
} catch (Throwable e) {
log.error("Error occurred while adding default tenant device status", e);
}
bundleContext.registerService(DeviceStatusManagementService.class.getName(), deviceStatusManagemntService, null);
/* Registering Event Configuration Service */
EventConfigurationProviderService eventConfigurationService = new EventConfigurationProviderServiceImpl();
DeviceManagementDataHolder.getInstance().setEventConfigurationProviderService(eventConfigurationService);

@ -0,0 +1,322 @@
/*
* 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.device.mgt.core.metadata.mgt;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.MetadataManagementException;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.TransactionManagementException;
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.AllowedDeviceStatus;
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.DeviceStatusManagementService;
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.Metadata;
import io.entgra.device.mgt.core.device.mgt.core.config.ui.DeviceStatusConfigurations;
import io.entgra.device.mgt.core.device.mgt.core.config.ui.DeviceStatusItem;
import io.entgra.device.mgt.core.device.mgt.core.config.ui.UIConfigurationManager;
import io.entgra.device.mgt.core.device.mgt.core.metadata.mgt.dao.MetadataDAO;
import io.entgra.device.mgt.core.device.mgt.core.metadata.mgt.dao.MetadataManagementDAOException;
import io.entgra.device.mgt.core.device.mgt.core.metadata.mgt.dao.MetadataManagementDAOFactory;
import io.entgra.device.mgt.core.device.mgt.core.metadata.mgt.dao.util.MetadataConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.lang.reflect.Type;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class DeviceStatusManagementServiceImpl implements DeviceStatusManagementService {
private static final Log log = LogFactory.getLog(DeviceStatusManagementServiceImpl.class);
private final MetadataDAO metadataDAO;
public DeviceStatusManagementServiceImpl() {
this.metadataDAO = MetadataManagementDAOFactory.getMetadataDAO();
}
@Override
public void addDefaultDeviceStatusFilterIfNotExist(int tenantId) throws MetadataManagementException {
try {
MetadataManagementDAOFactory.beginTransaction();
if (!metadataDAO.isExist(tenantId, MetadataConstants.ALLOWED_DEVICE_STATUS_META_KEY) && !metadataDAO.isExist(tenantId, MetadataConstants.IS_DEVICE_STATUS_CHECK_META_KEY)) {
Metadata defaultDeviceStatusMetadata = constructDeviceStatusMetadata(getDefaultDeviceStatus());
Metadata defaultDeviceStatusCheckMetadata = constructDeviceStatusCheckMetadata(getDefaultDeviceStatusCheck());
// Add default device status and device status check metadata entries
addMetadataEntry(tenantId, defaultDeviceStatusMetadata, MetadataConstants.ALLOWED_DEVICE_STATUS_META_KEY);
addMetadataEntry(tenantId, defaultDeviceStatusCheckMetadata, MetadataConstants.IS_DEVICE_STATUS_CHECK_META_KEY);
}
MetadataManagementDAOFactory.commitTransaction();
} catch (MetadataManagementDAOException e) {
MetadataManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while inserting default device status metadata entry.";
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} catch (TransactionManagementException e) {
String msg = "Error occurred while opening a connection to the data source";
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} finally {
MetadataManagementDAOFactory.closeConnection();
}
}
@Override
public void resetToDefaultDeviceStausFilter() throws MetadataManagementException {
}
@Override
public void updateDefaultDeviceStatusFilters(int tenantId, String deviceType, List<String> deviceStatus) throws MetadataManagementException {
try {
MetadataManagementDAOFactory.beginTransaction();
// Retrieve the current device status metadata
Metadata metadata = metadataDAO.getMetadata(tenantId, MetadataConstants.ALLOWED_DEVICE_STATUS_META_KEY);
if (metadata != null) {
Gson gson = new Gson();
Type listType = new TypeToken<List<AllowedDeviceStatus>>() {
}.getType();
List<AllowedDeviceStatus> currentStatusList = gson.fromJson(metadata.getMetaValue(), listType);
// Find the status for the specified deviceType
for (AllowedDeviceStatus status : currentStatusList) {
if (status.getType().equalsIgnoreCase(deviceType)) {
// Update the status list for the specified deviceType
status.setStatus(deviceStatus);
break;
}
}
metadata.setMetaValue(gson.toJson(currentStatusList));
updateMetadataEntry(tenantId, metadata, MetadataConstants.ALLOWED_DEVICE_STATUS_META_KEY);
}
MetadataManagementDAOFactory.commitTransaction();
} catch (MetadataManagementDAOException e) {
MetadataManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while updating device status metadata entry.";
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} catch (TransactionManagementException e) {
String msg = "Error occurred while opening a connection to the data source";
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} finally {
MetadataManagementDAOFactory.closeConnection();
}
}
@Override
public boolean updateDefaultDeviceStatusCheck(int tenantId, boolean isChecked) throws MetadataManagementException {
boolean success = false;
try {
MetadataManagementDAOFactory.beginTransaction();
if (metadataDAO.isExist(tenantId, MetadataConstants.IS_DEVICE_STATUS_CHECK_META_KEY)) {
Metadata isDeviceStatusChecked = constructDeviceStatusCheckMetadata(isChecked);
// Add default device status check metadata entries
updateMetadataEntry(tenantId, isDeviceStatusChecked, MetadataConstants.IS_DEVICE_STATUS_CHECK_META_KEY);
success = true;
}
MetadataManagementDAOFactory.commitTransaction();
} catch (MetadataManagementDAOException e) {
MetadataManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while updating device status check metadata entry.";
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} catch (TransactionManagementException e) {
String msg = "Error occurred while opening a connection to the data source";
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} finally {
MetadataManagementDAOFactory.closeConnection();
}
return success;
}
@Override
public List<AllowedDeviceStatus> getDeviceStatusFilters(int tenantId) throws MetadataManagementException {
try {
MetadataManagementDAOFactory.openConnection();
Metadata metadata = metadataDAO.getMetadata(tenantId, MetadataConstants.ALLOWED_DEVICE_STATUS_META_KEY);
Gson gson = new Gson();
Type listType = new TypeToken<List<AllowedDeviceStatus>>() {}.getType();
List<AllowedDeviceStatus> statusList = gson.fromJson(metadata.getMetaValue(), listType);
return statusList;
} catch (MetadataManagementDAOException e) {
String msg = "Error occurred while retrieving device status meta data for tenant:" + tenantId;
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} catch (SQLException e) {
String msg = "Error occurred while opening a connection to the data source";
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} finally {
MetadataManagementDAOFactory.closeConnection();
}
}
public List<String> getDeviceStatusFilters(String deviceType, int tenantId) throws MetadataManagementException {
try {
MetadataManagementDAOFactory.openConnection();
Metadata metadata = metadataDAO.getMetadata(tenantId, MetadataConstants.ALLOWED_DEVICE_STATUS_META_KEY);
Gson gson = new Gson();
Type listType = new TypeToken<List<AllowedDeviceStatus>>() {}.getType();
List<AllowedDeviceStatus> statusList = gson.fromJson(metadata.getMetaValue(), listType);
for (AllowedDeviceStatus status : statusList) {
if (status.getType().equalsIgnoreCase(deviceType)) {
return status.getStatus();
}
}
// Device type not found in metadata
return Collections.emptyList();
} catch (MetadataManagementDAOException e) {
String msg = "Error occurred while retrieving device status meta data for tenant: " + tenantId;
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} catch (SQLException e) {
String msg = "Error occurred while opening a connection to the data source";
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} finally {
MetadataManagementDAOFactory.closeConnection();
}
}
@Override
public boolean getDeviceStatusCheck(int tenantId) throws MetadataManagementException {
try {
MetadataManagementDAOFactory.openConnection();
Metadata metadata = metadataDAO.getMetadata(tenantId, MetadataConstants.IS_DEVICE_STATUS_CHECK_META_KEY);
String metaValue = metadata.getMetaValue();
return Boolean.parseBoolean(metaValue);
} catch (MetadataManagementDAOException e) {
String msg = "Error occurred while retrieving device status check meta data for tenant:" + tenantId;
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} catch (SQLException e) {
String msg = "Error occurred while opening a connection to the data source";
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} finally {
MetadataManagementDAOFactory.closeConnection();
}
}
@Override
public boolean isDeviceStatusValid(String deviceType, String deviceStatus, int tenantId) throws MetadataManagementException {
try {
MetadataManagementDAOFactory.openConnection();
Metadata metadata = metadataDAO.getMetadata(tenantId, MetadataConstants.ALLOWED_DEVICE_STATUS_META_KEY);
Gson gson = new Gson();
Type listType = new TypeToken<List<AllowedDeviceStatus>>() {
}.getType();
List<AllowedDeviceStatus> statusList = gson.fromJson(metadata.getMetaValue(), listType);
for (AllowedDeviceStatus status : statusList) {
if (status.getType().equalsIgnoreCase(deviceType)) {
List<String> allowedStatus = status.getStatus();
return allowedStatus.contains(deviceStatus);
}
}
return false; // Device type not found in metadata
} catch (MetadataManagementDAOException e) {
String msg = "Error occurred while retrieving device status meta data for tenant: " + tenantId;
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} catch (SQLException e) {
String msg = "Error occurred while opening a connection to the data source";
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} finally {
MetadataManagementDAOFactory.closeConnection();
}
}
private void addMetadataEntry(int tenantId, Metadata metadata, String key) throws MetadataManagementDAOException {
metadataDAO.addMetadata(tenantId, metadata);
if (log.isDebugEnabled()) {
log.debug(key + " metadata entry has been inserted successfully");
}
}
private void updateMetadataEntry(int tenantId, Metadata metadata, String key) throws MetadataManagementDAOException {
metadataDAO.updateMetadata(tenantId, metadata);
if (log.isDebugEnabled()) {
log.debug(key + " metadata entry has been updated successfully");
}
}
private Metadata constructDeviceStatusMetadata(List<DeviceStatusItem> deviceStatusItems) {
Gson gson = new Gson();
String deviceStatusItemsJsonString = gson.toJson(deviceStatusItems);
Metadata metadata = new Metadata();
metadata.setMetaKey(MetadataConstants.ALLOWED_DEVICE_STATUS_META_KEY);
metadata.setMetaValue(deviceStatusItemsJsonString);
return metadata;
}
private Metadata constructDeviceStatusCheckMetadata(boolean deviceStatusCheck) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("deviceStatusCheck", String.valueOf(deviceStatusCheck));
Metadata metadata = new Metadata();
metadata.setMetaKey(MetadataConstants.IS_DEVICE_STATUS_CHECK_META_KEY);
metadata.setMetaValue(String.valueOf(deviceStatusCheck));
return metadata;
}
private List<DeviceStatusItem> getDefaultDeviceStatus() {
DeviceStatusConfigurations deviceStatusConfigurations = UIConfigurationManager.getInstance().getUIConfig().getDeviceStatusConfigurations();
List<DeviceStatusItem> deviceStatusItems = new ArrayList<>();
if (deviceStatusConfigurations != null) {
// Access the list of DeviceStatusItem objects
deviceStatusItems = deviceStatusConfigurations.getDeviceStatusItems();
} else {
if (log.isDebugEnabled()) {
log.debug("DeviceStatusConfigurations is null.");
}
}
return deviceStatusItems;
}
private boolean getDefaultDeviceStatusCheck() {
DeviceStatusConfigurations deviceStatusConfigurations = UIConfigurationManager.getInstance().getUIConfig().getDeviceStatusConfigurations();
boolean deviceStatusCheck = false;
if (deviceStatusConfigurations != null) {
// Access the deviceStatusCheck
deviceStatusCheck = deviceStatusConfigurations.isDeviceStatusCheck();
} else {
if (log.isDebugEnabled()) {
log.debug("DeviceStatusConfigurations is null.");
}
}
return deviceStatusCheck;
}
}

@ -20,4 +20,7 @@ package io.entgra.device.mgt.core.device.mgt.core.metadata.mgt.dao.util;
public class MetadataConstants {
public static final String WHITELABEL_META_KEY = "whitelabel";
public static final String ALLOWED_DEVICE_STATUS_META_KEY = "allowed_device_status";
public static final String IS_DEVICE_STATUS_CHECK_META_KEY = "device-status-check";
}

@ -1030,10 +1030,9 @@ public interface DeviceManagementProviderService {
* @param iconPath Icon path of the application
* @param packageName Package name of the application
* @param version Version of the application
* @param tenantId Tenant ID of the application created user
* @throws DeviceManagementException if any service level or DAO level error occurs
*/
void saveApplicationIcon(String iconPath, String packageName, String version, int tenantId)
void saveApplicationIcon(String iconPath, String packageName, String version)
throws DeviceManagementException;
/**
@ -1062,4 +1061,12 @@ public interface DeviceManagementProviderService {
*/
List<Application> getInstalledApplicationsOnDevice(Device device, int offset, int limit)
throws DeviceManagementException;
/**
* This method is for getting the installed application list of a device
* @param device {@link Device}
* @return list of applications {@link Application}
* @throws DeviceManagementException if any service level or DAO level error occurs
*/
List<Application> getInstalledApplicationsOnDevice(Device device) throws DeviceManagementException;
}

@ -20,6 +20,7 @@ package io.entgra.device.mgt.core.device.mgt.core.service;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.DeviceStatusManagementService;
import io.entgra.device.mgt.core.device.mgt.extensions.logger.spi.EntgraLogger;
import io.entgra.device.mgt.core.notification.logger.DeviceEnrolmentLogContext;
import io.entgra.device.mgt.core.notification.logger.impl.EntgraDeviceEnrolmentLoggerImpl;
@ -485,6 +486,8 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
Device currentDevice = this.getDevice(deviceIdentifier, false);
DeviceManagementDAOFactory.beginTransaction();
device.setId(currentDevice.getId());
DeviceStatusManagementService deviceStatusManagementService = DeviceManagementDataHolder
.getInstance().getDeviceStatusManagementService();
if (device.getEnrolmentInfo().getId() == 0) {
device.getEnrolmentInfo().setId(currentDevice.getEnrolmentInfo().getId());
}
@ -495,7 +498,14 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
device.setName(currentDevice.getName());
}
deviceDAO.updateDevice(device, tenantId);
enrollmentDAO.updateEnrollment(device.getEnrolmentInfo(), tenantId);
int updatedRows = enrollmentDAO.updateEnrollment(device.getEnrolmentInfo(), tenantId);
boolean isEnableDeviceStatusCheck = deviceStatusManagementService.getDeviceStatusCheck(tenantId);
boolean isValidState = deviceStatusManagementService.isDeviceStatusValid(device.getType(),device.getEnrolmentInfo().getStatus().name(),tenantId);
if (updatedRows == 1 && !deviceStatusManagementService.getDeviceStatusCheck(tenantId)){
enrollmentDAO.addDeviceStatus(device.getEnrolmentInfo().getId(), device.getEnrolmentInfo().getStatus());
} else if (updatedRows ==1 && isEnableDeviceStatusCheck && isValidState ) {
enrollmentDAO.addDeviceStatus(device.getEnrolmentInfo().getId(), device.getEnrolmentInfo().getStatus());
}
DeviceManagementDAOFactory.commitTransaction();
log.info("Device enrolled successfully", deviceEnrolmentLogContextBuilder.setDeviceId(String.valueOf(currentDevice.getId())).setDeviceType(String.valueOf(currentDevice.getType())).setOwner(currentDevice.getEnrolmentInfo().getOwner()).setOwnership(String.valueOf(currentDevice.getEnrolmentInfo().getOwnership())).setTenantID(String.valueOf(tenantId)).setTenantDomain(tenantDomain).setUserName(userName).build());
@ -603,7 +613,16 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
device.getEnrolmentInfo().setDateOfLastUpdate(new Date().getTime());
device.getEnrolmentInfo().setStatus(EnrolmentInfo.Status.REMOVED);
DeviceManagementDAOFactory.beginTransaction();
enrollmentDAO.updateEnrollment(device.getEnrolmentInfo(), tenantId);
DeviceStatusManagementService deviceStatusManagementService = DeviceManagementDataHolder
.getInstance().getDeviceStatusManagementService();
int updatedRows = enrollmentDAO.updateEnrollment(device.getEnrolmentInfo(), tenantId);
boolean isEnableDeviceStatusCheck = deviceStatusManagementService.getDeviceStatusCheck(tenantId);
boolean isValidState = deviceStatusManagementService.isDeviceStatusValid(device.getType(),device.getEnrolmentInfo().getStatus().name(),tenantId);
if (updatedRows == 1 && !deviceStatusManagementService.getDeviceStatusCheck(tenantId)){
enrollmentDAO.addDeviceStatus(device.getEnrolmentInfo().getId(), device.getEnrolmentInfo().getStatus());
} else if (updatedRows ==1 && isEnableDeviceStatusCheck && isValidState ) {
enrollmentDAO.addDeviceStatus(device.getEnrolmentInfo().getId(), device.getEnrolmentInfo().getStatus());
}
deviceDAO.updateDevice(device, tenantId);
DeviceManagementDAOFactory.commitTransaction();
this.removeDeviceFromCache(deviceId);
@ -3339,7 +3358,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
isDeviceUpdated = disenrollDevice(deviceIdentifier);
} else {
enrolmentInfo.setStatus(newStatus);
isDeviceUpdated = updateEnrollment(deviceId, enrolmentInfo, tenantId);
isDeviceUpdated = updateEnrollment(deviceId, enrolmentInfo, tenantId, deviceIdentifier);
}
this.removeDeviceFromCache(deviceIdentifier);
return isDeviceUpdated;
@ -3370,7 +3389,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
}
}
private boolean updateEnrollment(int deviceId, EnrolmentInfo enrolmentInfo, int tenantId)
private boolean updateEnrollment(int deviceId, EnrolmentInfo enrolmentInfo, int tenantId, DeviceIdentifier deviceIdentifier)
throws DeviceManagementException {
if (log.isDebugEnabled()) {
log.debug("Update enrollment of device: " + deviceId);
@ -3379,10 +3398,21 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
try {
DeviceManagementDAOFactory.beginTransaction();
int updatedRows = enrollmentDAO.updateEnrollment(enrolmentInfo, tenantId);
String type = deviceIdentifier.getType();
DeviceStatusManagementService deviceStatusManagementService = DeviceManagementDataHolder
.getInstance().getDeviceStatusManagementService();
DeviceManagementDAOFactory.commitTransaction();
if (updatedRows > 0) {
isUpdatedEnrollment = true;
}
boolean isEnableDeviceStatusCheck = deviceStatusManagementService.getDeviceStatusCheck(tenantId);
boolean isValidState = deviceStatusManagementService.isDeviceStatusValid(type, enrolmentInfo.getStatus().name(), tenantId);
if (updatedRows == 1 && !deviceStatusManagementService.getDeviceStatusCheck(tenantId)) {
enrollmentDAO.addDeviceStatus(enrolmentInfo.getId(), enrolmentInfo.getStatus());
} else if (updatedRows == 1 && isEnableDeviceStatusCheck && isValidState) {
enrollmentDAO.addDeviceStatus(enrolmentInfo.getId(), enrolmentInfo.getStatus());
}
} catch (DeviceManagementDAOException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while updating the enrollment information device for" +
@ -4411,13 +4441,25 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
device.getEnrolmentInfo().setStatus(EnrolmentInfo.Status.REMOVED);
// different try blocks are used to isolate transactions
try {
enrollmentDAO.updateEnrollment(device.getEnrolmentInfo(), tenantId);
String type = device.getType();
DeviceStatusManagementService deviceStatusManagementService = DeviceManagementDataHolder
.getInstance().getDeviceStatusManagementService();
int updatedRows = enrollmentDAO.updateEnrollment(device.getEnrolmentInfo(), tenantId);
boolean isEnableDeviceStatusCheck = deviceStatusManagementService.getDeviceStatusCheck(tenantId);
boolean isValidState = deviceStatusManagementService.isDeviceStatusValid(type, String.valueOf(EnrolmentInfo.Status.REMOVED),tenantId);
if (updatedRows == 1 && !deviceStatusManagementService.getDeviceStatusCheck(tenantId)){
enrollmentDAO.addDeviceStatus(device.getEnrolmentInfo().getId(), device.getEnrolmentInfo().getStatus());
} else if (updatedRows ==1 && isEnableDeviceStatusCheck && isValidState ) {
enrollmentDAO.addDeviceStatus(device.getEnrolmentInfo().getId(), device.getEnrolmentInfo().getStatus());
}
} catch (DeviceManagementDAOException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while dis-enrolling device: " +
device.getName();
log.error(msg, e);
throw new DeviceManagementException(msg, e);
} catch (MetadataManagementException e) {
throw new RuntimeException(e);
}
try {
deviceDAO.updateDevice(device, tenantId);
@ -4953,9 +4995,11 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
}
@Override
public void saveApplicationIcon(String iconPath, String packageName, String version, int tenantId) throws DeviceManagementException{
public void saveApplicationIcon(String iconPath, String packageName, String version) throws DeviceManagementException{
int tenantId = 0;
try{
DeviceManagementDAOFactory.beginTransaction();
tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
if(applicationDAO.getApplicationPackageCount(packageName) == 0){
applicationDAO.saveApplicationIcon(iconPath, packageName, version, tenantId);
}
@ -5077,4 +5121,38 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
}
return newApplicationList;
}
public List<Application> getInstalledApplicationsOnDevice(Device device) throws DeviceManagementException {
List<Application> applications;
try {
DeviceManagementDAOFactory.openConnection();
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
applications = applicationDAO.getInstalledApplicationListOnDevice(device.getId(),
device.getEnrolmentInfo().getId(), tenantId);
if (applications == null) {
String msg = "Couldn't found applications for device identifier '" + device.getId() + "'";
log.error(msg);
throw new DeviceManagementException(msg);
}
} catch (DeviceManagementDAOException e) {
String msg = "Error occurred while retrieving the application list of android device, " +
"which carries the id '" + device.getId() + "'";
log.error(msg, e);
throw new DeviceManagementException(msg, e);
} catch (SQLException e) {
String msg = "Error occurred while opening a connection to the data source";
log.error(msg, e);
throw new DeviceManagementException(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
List<Application> newApplicationList;
newApplicationList = this.getInstalledAppIconInfo(applications);
if (newApplicationList == null) {
String msg = "Error occurred while getting app icon info for device identifier '" + device.getId() + "'";
log.error(msg);
throw new DeviceManagementException(msg);
}
return newApplicationList;
}
}

@ -19,6 +19,9 @@
package io.entgra.device.mgt.core.device.mgt.core.status.task.impl;
import com.google.gson.Gson;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.MetadataManagementException;
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.DeviceStatusManagementService;
import io.entgra.device.mgt.core.device.mgt.core.internal.DeviceManagementDataHolder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import io.entgra.device.mgt.core.device.mgt.common.DeviceIdentifier;
@ -33,6 +36,7 @@ import io.entgra.device.mgt.core.device.mgt.core.dao.DeviceManagementDAOExceptio
import io.entgra.device.mgt.core.device.mgt.core.dao.DeviceManagementDAOFactory;
import io.entgra.device.mgt.core.device.mgt.core.status.task.DeviceStatusTaskException;
import io.entgra.device.mgt.core.device.mgt.core.task.impl.DynamicPartitionedScheduleTask;
import org.wso2.carbon.context.CarbonContext;
import java.sql.SQLException;
import java.util.ArrayList;
@ -135,11 +139,26 @@ public class DeviceStatusMonitoringTask extends DynamicPartitionedScheduleTask {
private boolean updateDeviceStatus(List<EnrolmentInfo> enrolmentInfos) throws
DeviceStatusTaskException {
boolean updateStatus;
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
DeviceStatusManagementService deviceStatusManagementService = DeviceManagementDataHolder
.getInstance().getDeviceStatusManagementService();
try {
DeviceManagementDAOFactory.beginTransaction();
updateStatus = DeviceManagementDAOFactory.getEnrollmentDAO().updateEnrollmentStatus(enrolmentInfos);
boolean isEnableDeviceStatusCheck = deviceStatusManagementService.getDeviceStatusCheck(tenantId);
if (updateStatus) {
for (EnrolmentInfo enrolmentInfo : enrolmentInfos) {
if (isEnableDeviceStatusCheck) {
if (deviceStatusManagementService.isDeviceStatusValid(this.deviceType, enrolmentInfo.getStatus().name(), tenantId)) {
DeviceManagementDAOFactory.getEnrollmentDAO().addDeviceStatus(enrolmentInfo);
}
} else {
DeviceManagementDAOFactory.getEnrollmentDAO().addDeviceStatus(enrolmentInfo);
}
}
}
DeviceManagementDAOFactory.commitTransaction();
} catch (DeviceManagementDAOException e) {
} catch (DeviceManagementDAOException | MetadataManagementException e) {
DeviceManagementDAOFactory.rollbackTransaction();
throw new DeviceStatusTaskException("Error occurred while updating enrollment status of devices of type '"
+ deviceType + "'", e);

@ -19,6 +19,8 @@
package io.entgra.device.mgt.core.device.mgt.core.search;
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.DeviceStatusManagementService;
import io.entgra.device.mgt.core.device.mgt.core.metadata.mgt.DeviceStatusManagementServiceImpl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.testng.annotations.BeforeClass;
@ -38,9 +40,11 @@ public class DeviceDetails extends BaseDeviceManagementTest {
@Override
public void init() throws Exception {
DeviceManagementProviderService deviceManagementProviderService = new DeviceManagementProviderServiceImpl();
DeviceManagementDataHolder.getInstance().setDeviceManagementProvider(deviceManagementProviderService);
DeviceManagementProviderService deviceManagementProviderService = new DeviceManagementProviderServiceImpl();
DeviceManagementDataHolder.getInstance().setDeviceManagementProvider(deviceManagementProviderService);
DeviceStatusManagementService deviceStatusManagementService = new DeviceStatusManagementServiceImpl();
DeviceManagementDataHolder.getInstance().setDeviceStatusManagementService(deviceStatusManagementService);
}
@Test

@ -18,6 +18,9 @@
package io.entgra.device.mgt.core.device.mgt.core.service;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.MetadataManagementException;
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.DeviceStatusManagementService;
import io.entgra.device.mgt.core.device.mgt.core.config.ui.UIConfigurationManager;
import org.apache.commons.collections.map.SingletonMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@ -61,6 +64,7 @@ import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.core.service.RealmService;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.sql.Timestamp;
@ -78,6 +82,8 @@ public class DeviceManagementProviderServiceTest extends BaseDeviceManagementTes
private static final String ALTERNATE_DEVICE_ID = "1128";
private static final String DEVICE_TYPE = "RANDOM_DEVICE_TYPE";
private final DeviceDetailsDAO deviceDetailsDAO = DeviceManagementDAOFactory.getDeviceDetailsDAO();
private static final String MDM_CONFIG_LOCATION = "src" + File.separator + "test" + File.separator + "resources" +
File.separator + "config" + File.separator + "operation" + File.separator + "mdm-ui-config.xml";
DeviceManagementProviderService deviceMgtService;
@ -96,6 +102,7 @@ public class DeviceManagementProviderServiceTest extends BaseDeviceManagementTes
DeviceManagementDataHolder.getInstance().setDeviceTaskManagerService(null);
deviceMgtService.registerDeviceType(new TestDeviceManagementService(DEVICE_TYPE,
MultitenantConstants.SUPER_TENANT_DOMAIN_NAME));
UIConfigurationManager.getInstance().initConfig(MDM_CONFIG_LOCATION);
}
private RegistryService getRegistryService() throws RegistryException {
@ -204,8 +211,11 @@ public class DeviceManagementProviderServiceTest extends BaseDeviceManagementTes
@Test(dependsOnMethods = {"testSuccessfulDeviceEnrollment"})
public void testReEnrollmentofSameDeviceUnderSameUser() throws DeviceManagementException {
public void testReEnrollmentofSameDeviceUnderSameUser() throws DeviceManagementException, MetadataManagementException {
if (!isMock()) {
DeviceStatusManagementService deviceStatusManagementService = DeviceManagementDataHolder
.getInstance().getDeviceStatusManagementService();
deviceStatusManagementService.addDefaultDeviceStatusFilterIfNotExist(MultitenantConstants.SUPER_TENANT_ID);
Device device = TestDataHolder.generateDummyDeviceData(new DeviceIdentifier(DEVICE_ID, DEVICE_TYPE));
boolean enrollment = deviceMgtService.enrollDevice(device);
Assert.assertTrue(enrollment);

@ -17,6 +17,7 @@
*/
package io.entgra.device.mgt.core.device.mgt.core.task;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.MetadataManagementException;
import io.entgra.device.mgt.core.server.bootup.heartbeat.beacon.service.HeartBeatManagementService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@ -68,7 +69,7 @@ public class DeviceTaskManagerTest extends BaseDeviceManagementTest {
private OperationManager operationManager;
@BeforeClass
public void init() throws DeviceManagementException, RegistryException {
public void init() throws DeviceManagementException, RegistryException, MetadataManagementException {
log.info("Initializing Device Task Manager Test Suite");
this.deviceIds = new ArrayList<>();
for (int i = 0; i < 5; i++) {

@ -0,0 +1,410 @@
<?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.
-->
<UIConfiguration>
<EnableOAuth>true</EnableOAuth>
<EnableSSO>true</EnableSSO>
<!-- session time out in seconds -->
<SessionTimeOut>3600</SessionTimeOut>
<!-- maximum number of login cache entries -->
<LoginCacheCapacity>10000</LoginCacheCapacity>
<!-- hubspot account info for live chat -->
<HubspotChat>
<EnableHubspot>false</EnableHubspot>
<TrackingUrl>tracking_url</TrackingUrl>
<!-- access token - whenever the access token will be rotated, needs to be changed this with the new token -->
<AccessToken>access_token</AccessToken>
<SenderActorId>sender_actorId</SenderActorId>
</HubspotChat>
<Billing>
<HideBillGenerationInSuperTenant>false</HideBillGenerationInSuperTenant>
<HideBillGenerationInSubTenant>true</HideBillGenerationInSubTenant>
<HideTotalCalculationInSuperTenant>false</HideTotalCalculationInSuperTenant>
<HideTotalCalculationInSubTenant>true</HideTotalCalculationInSubTenant>
<HideDomainSelectionInSuperTenant>false</HideDomainSelectionInSuperTenant>
<HideDomainSelectionInSubTenant>true</HideDomainSelectionInSubTenant>
</Billing>
<DeviceInfoConfigurations>
<DeviceInfoItem>
<DefinedValue>name</DefinedValue>
<DisplayValue>label_device</DisplayValue>
<Type>default</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>type</DefinedValue>
<DisplayValue>label_type</DisplayValue>
<Type>default</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>owner</DefinedValue>
<DisplayValue>label_owner</DisplayValue>
<Type>default</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>serial</DefinedValue>
<DisplayValue>label_serialNumber</DisplayValue>
<Type>default</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>ownership</DefinedValue>
<DisplayValue>label_ownership</DisplayValue>
<Type>default</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>status</DefinedValue>
<DisplayValue>label_status</DisplayValue>
<Type>default</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>dateOfLastUpdate</DefinedValue>
<DisplayValue>label_last_updated</DisplayValue>
<Type>default</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>actions</DefinedValue>
<DisplayValue>label_actions</DisplayValue>
<Type>default</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>batteryLevel</DefinedValue>
<DisplayValue>label_battery_leve</DisplayValue>
<Type>deviceInfo</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>deviceModel</DefinedValue>
<DisplayValue>label_deviceModel</DisplayValue>
<Type>deviceInfo</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>osVersion</DefinedValue>
<DisplayValue>label_os_version</DisplayValue>
<Type>deviceInfo</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>vendor</DefinedValue>
<DisplayValue>label_vendor</DisplayValue>
<Type>deviceInfo</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>availableRAMMemory</DefinedValue>
<DisplayValue>label_available_ram_memory</DisplayValue>
<Type>deviceInfo</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>connectionType</DefinedValue>
<DisplayValue>label_connection_type</DisplayValue>
<Type>deviceInfo</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>cpuUsage</DefinedValue>
<DisplayValue>label_cpu_usage</DisplayValue>
<Type>deviceInfo</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>externalAvailableMemory</DefinedValue>
<DisplayValue>label_external_available_memory</DisplayValue>
<Type>deviceInfo</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>externalTotalMemory</DefinedValue>
<DisplayValue>label_external_tot_memory</DisplayValue>
<Type>deviceInfo</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>internalAvailableMemory</DefinedValue>
<DisplayValue>label_internal_available_memory</DisplayValue>
<Type>deviceInfo</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>internalTotalMemory</DefinedValue>
<DisplayValue>label_internal_tot_memory</DisplayValue>
<Type>deviceInfo</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>osBuildDate</DefinedValue>
<DisplayValue>label_os_build_date</DisplayValue>
<Type>deviceInfo</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>pluggedIn</DefinedValue>
<DisplayValue>label_plugged_in</DisplayValue>
<Type>deviceInfo</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>ssid</DefinedValue>
<DisplayValue>label_ssid</DisplayValue>
<Type>deviceInfo</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>totalRAMMemory</DefinedValue>
<DisplayValue>label_tot_ram_memory</DisplayValue>
<Type>deviceInfo</Type>
</DeviceInfoItem>
<DeviceInfoItem>
<DefinedValue>updatedTime</DefinedValue>
<DisplayValue>label_updated_time</DisplayValue>
<Type>deviceInfo</Type>
</DeviceInfoItem>
</DeviceInfoConfigurations>
<DeviceStatusConfigurations>
<EnableDeviceStatusCheck>true</EnableDeviceStatusCheck>
<DeviceStatusItem>
<Type>android</Type>
<AllowedStatus>
<Status>ACTIVE</Status>
<Status>CREATED</Status>
<Status>INACTIVE</Status>
<Status>UNREACHABLE</Status>
<Status>UNCLAIMED</Status>
<Status>SUSPENDED</Status>
<Status>BLOCKED</Status>
<Status>REMOVED</Status>
<Status>SUSPENDED</Status>
<Status>DISENROLLMENT_REQUESTED</Status>
</AllowedStatus>
</DeviceStatusItem>
<DeviceStatusItem>
<Type>ios</Type>
<AllowedStatus>
<Status>ACTIVE</Status>
<Status>CREATED</Status>
<Status>INACTIVE</Status>
<Status>UNREACHABLE</Status>
<Status>UNCLAIMED</Status>
<Status>SUSPENDED</Status>
<Status>BLOCKED</Status>
<Status>REMOVED</Status>
<Status>SUSPENDED</Status>
<Status>DISENROLLMENT_REQUESTED</Status>
</AllowedStatus>
</DeviceStatusItem>
<DeviceStatusItem>
<Type>windows</Type>
<AllowedStatus>
<Status>ACTIVE</Status>
<Status>CREATED</Status>
<Status>INACTIVE</Status>
<Status>UNREACHABLE</Status>
<Status>UNCLAIMED</Status>
<Status>SUSPENDED</Status>
<Status>BLOCKED</Status>
<Status>REMOVED</Status>
<Status>SUSPENDED</Status>
<Status>DISENROLLMENT_REQUESTED</Status>
</AllowedStatus>
</DeviceStatusItem>
</DeviceStatusConfigurations>
<AppRegistration>
<Tags>
<Tag>analytics_management</Tag>
<Tag>application_management</Tag>
<Tag>device_management</Tag>
<Tag>subscription_management</Tag>
<Tag>review_management</Tag>
</Tags>
<AllowToAllDomains>true</AllowToAllDomains>
</AppRegistration>
<Scopes>
<Scope>grafana:api:view</Scope>
<Scope>am:store:app:review:view</Scope>
<Scope>am:store:app:review:update</Scope>
<Scope>am:pub:sp:app:view</Scope>
<Scope>am:pub:sp:create</Scope>
<Scope>am:pub:sp:attach</Scope>
<Scope>am:pub:sp:detach</Scope>
<Scope>am:pub:sp:connect</Scope>
<Scope>am:pub:app:view</Scope>
<Scope>am:pub:app:update</Scope>
<Scope>am:store:app:view</Scope>
<Scope>am:store:app:modify</Scope>
<Scope>am:store:app:sub:install</Scope>
<Scope>am:store:app:sub:uninstall</Scope>
<Scope>am:admin:pub:app:review:view</Scope>
<Scope>am:admin:pub:app:update</Scope>
<Scope>am:admin:store:app:review:update</Scope>
<Scope>am:admin:store:app:sub:view</Scope>
<Scope>am:admin:store:app:sub:modify</Scope>
<Scope>dm:device-type:view</Scope>
<Scope>and:enterprise:modify</Scope>
<Scope>and:enterprise:view</Scope>
<Scope>dm:sign-csr</Scope>
<Scope>dm:admin:devices:view</Scope>
<Scope>dm:devices:status:change</Scope>
<Scope>rm:roles:add</Scope>
<Scope>rm:users:add</Scope>
<Scope>rm:roles:update</Scope>
<Scope>rm:roles:permissions:view</Scope>
<Scope>rm:roles:details:view</Scope>
<Scope>rm:roles:view</Scope>
<Scope>rm:roles:combined:add</Scope>
<Scope>rm:roles:delete</Scope>
<Scope>dm:activity:get</Scope>
<Scope>dm:devices:delete</Scope>
<Scope>dm:devices:app:view</Scope>
<Scope>dm:devices:policy:view</Scope>
<Scope>dm:devices:compliance:view</Scope>
<Scope>dm:devices:features:view</Scope>
<Scope>dm:devices:ops:view</Scope>
<Scope>dm:devices:search</Scope>
<Scope>dm:devices:details</Scope>
<Scope>dm:devices:update</Scope>
<Scope>dm:devices:view</Scope>
<Scope>dm:devices:enrollment-guide:view</Scope>
<Scope>dm:conf:view</Scope>
<Scope>dm:conf:manage</Scope>
<Scope>pm:policies:remove</Scope>
<Scope>pm:policies:priorities:update</Scope>
<Scope>pm:policies:deactivate</Scope>
<Scope>pm:policies:details:view</Scope>
<Scope>pm:policies:add</Scope>
<Scope>pm:policies:activate</Scope>
<Scope>pm:policies:update</Scope>
<Scope>pm:policies:change</Scope>
<Scope>dm:policies:view</Scope>
<Scope>um:users:add</Scope>
<Scope>um:users:details:view</Scope>
<Scope>um:users:count</Scope>
<Scope>um:users:delete</Scope>
<Scope>um:roles:view</Scope>
<Scope>um:users:user-details:view</Scope>
<Scope>um:users:cred:change</Scope>
<Scope>um:users:search</Scope>
<Scope>um:users:is-exist</Scope>
<Scope>um:users:update</Scope>
<Scope>um:users:invite</Scope>
<Scope>um:admin:users:view</Scope>
<Scope>dm:admin:enrollment:update</Scope>
<Scope>gm:devices:view</Scope>
<Scope>gm:groups:update</Scope>
<Scope>gm:groups:add</Scope>
<Scope>gm:groups:device:view</Scope>
<Scope>gm:devices:count</Scope>
<Scope>gm:devices-types:view</Scope>
<Scope>gm:groups:remove</Scope>
<Scope>gm:groups:view</Scope>
<Scope>gm:groups:groups-view</Scope>
<Scope>gm:roles:share</Scope>
<Scope>gm:groups:count</Scope>
<Scope>gm:roles:view</Scope>
<Scope>gm:devices:remove</Scope>
<Scope>gm:devices:add</Scope>
<Scope>gm:devices:assign</Scope>
<Scope>dm:device-type:conf:view</Scope>
<Scope>dm:device-type:features:view</Scope>
<Scope>dm:device-type:view</Scope>
<Scope>am:admin:app:install</Scope>
<Scope>am:admin:app:uninstall</Scope>
<Scope>gm:admin:groups:count</Scope>
<Scope>gm:admin:groups:view</Scope>
<Scope>gm:admin:groups:add</Scope>
<Scope>dm:notif:mark-checked</Scope>
<Scope>dm:notifications:view</Scope>
<Scope>cm:cert:delete</Scope>
<Scope>cm:cert:details:get</Scope>
<Scope>cm:cert:view</Scope>
<Scope>cm:cert:add</Scope>
<Scope>cm:cert:verify</Scope>
<Scope>dm:admin</Scope>
<Scope>dm:device-type:deploy</Scope>
<Scope>dm:device-type:event:modify</Scope>
<Scope>dm:device-type:event:view</Scope>
<Scope>dm:admin:device-type:modify</Scope>
<Scope>dm:admin:device-type:view</Scope>
<Scope>dm:admin:device-type:conf:add</Scope>
<Scope>dm:device:enroll</Scope>
<Scope>dm:geo:an:view</Scope>
<Scope>dm:geo:alerts:manage</Scope>
<Scope>dm:admin:devices:permanent-delete</Scope>
<Scope>and:conf:manage</Scope>
<Scope>and:conf:view</Scope>
<Scope>um:users:permission:view</Scope>
<Scope>ios:conf:view</Scope>
<Scope>ios:conf:manage</Scope>
<Scope>ios:dep:view</Scope>
<Scope>ios:dep:add</Scope>
<Scope>win:conf:view</Scope>
<Scope>win:conf:manage</Scope>
<Scope>and:ops:lock-devices</Scope>
<Scope>and:ops:unlock-devices</Scope>
<Scope>and:ops:location</Scope>
<Scope>and:ops:clear-password</Scope>
<Scope>and:ops:control-camera</Scope>
<Scope>and:ops:enterprise-wipe</Scope>
<Scope>and:ops:wipe</Scope>
<Scope>and:ops:ring</Scope>
<Scope>and:ops:app-list</Scope>
<Scope>and:ops:reboot</Scope>
<Scope>and:ops:change-LockTask</Scope>
<Scope>and:ops:mute</Scope>
<Scope>and:ops:conf-display-msg</Scope>
<Scope>and:ops:send-app-restrictions</Scope>
<Scope>and:ops:file-transfer</Scope>
<Scope>and:ops:set-webclip</Scope>
<Scope>and:ops:password-policy</Scope>
<Scope>and:ops:change-lock-code</Scope>
<Scope>and:ops:upgrade-firmware</Scope>
<Scope>and:ops:send-notif</Scope>
<Scope>dm:geo:geo-fence:manage</Scope>
<Scope>dm:whitelable:view</Scope>
<Scope>dm:whitelable:update</Scope>
<Scope>dm:metadata:view</Scope>
<Scope>dm:metadata:create</Scope>
<Scope>dm:metadata:update</Scope>
<Scope>and:ops:add-google-acc</Scope>
<Scope>and:ops:authenticate-acc</Scope>
<Scope>and:ops:update-default-sim</Scope>
<Scope>and:ops:add-google-acc</Scope>
<Scope>and:ops:device-info</Scope>
<Scope>win:ops:lock-devices</Scope>
<Scope>win:devices:enroll</Scope>
<Scope>win:ops:disenroll</Scope>
<Scope>win:ops:wipe</Scope>
<Scope>win:ops:ring</Scope>
<Scope>win:ops:lock-reset</Scope>
<Scope>win:ops:reboot</Scope>
<Scope>win:ops:location</Scope>
<Scope>admin:tenant:view</Scope>
<Scope>dm:admin:devices:usage:view</Scope>
<Scope>and:ops:clear-app</Scope>
<Scope>and:ops:suspend-package</Scope>
<Scope>and:ops:alternate-install</Scope>
<Scope>ios:ops:lock</Scope>
<Scope>ios:ops:location</Scope>
<Scope>ios:ops:ring</Scope>
<Scope>ios:ops:clear-passcode</Scope>
<Scope>ios:ops:enterprise-wipe</Scope>
<Scope>ios:ops:notif</Scope>
<Scope>ios:ops:wipe</Scope>
<Scope>ios:ops:boolean-setting</Scope>
<Scope>ios:ops:wallpaper</Scope>
<Scope>ios:ops:app-attributes</Scope>
<Scope>ios:ops:app-conf</Scope>
<Scope>mac:ops:restart</Scope>
<Scope>mac:ops:shutdown</Scope>
<Scope>am:store:vpp:user:modify</Scope>
<Scope>am:store:vpp:user:view</Scope>
<Scope>am:store:vpp:assets:modify</Scope>
<Scope>am:store:vpp:assets:view</Scope>
<Scope>and:devices:enroll</Scope>
<Scope>ios:devices:enroll</Scope>
</Scopes>
<SSOConfiguration>
<Issuer>device-mgt</Issuer>
</SSOConfiguration>
</UIConfiguration>

@ -670,3 +670,15 @@ CREATE TABLE IF NOT EXISTS DM_EXT_PERMISSION_MAPPING (
TRACCAR_USER_ID INT DEFAULT 0
);
-- END OF DM_EXT_PERMISSION_MAPPING TABLE--
-- METADATA TABLE --
CREATE TABLE IF NOT EXISTS DM_METADATA (
METADATA_ID INT AUTO_INCREMENT NOT NULL,
DATA_TYPE VARCHAR(16) NOT NULL,
METADATA_KEY VARCHAR(128) NOT NULL,
METADATA_VALUE TEXT NOT NULL,
TENANT_ID INTEGER NOT NULL,
PRIMARY KEY (METADATA_ID),
CONSTRAINT METADATA_KEY_TENANT_ID UNIQUE (METADATA_KEY, TENANT_ID)
);
-- END OF METADATA TABLE --

@ -24,4 +24,6 @@ public interface TenantManagerService {
void addDefaultRoles(TenantInfoBean tenantInfoBean) throws TenantMgtException;
void addDefaultAppCategories(TenantInfoBean tenantInfoBean) throws TenantMgtException;
void addDefaultDeviceStatusFilters(TenantInfoBean tenantInfoBean) throws TenantMgtException;
}

@ -36,4 +36,11 @@ public interface TenantManager {
* @throws TenantMgtException Throws when error occurred while adding default application categories
*/
void addDefaultAppCategories(TenantInfoBean tenantInfoBean) throws TenantMgtException;
/**
* Add default device status filters to a tenant described by the tenant info bean
* @param tenantInfoBean The info bean that provides tenant info
* @throws TenantMgtException Throws when error occurred while adding default application categories
*/
void addDefaultDeviceStatusFilters(TenantInfoBean tenantInfoBean) throws TenantMgtException;
}

@ -98,6 +98,21 @@ public class TenantManagerImpl implements TenantManager {
}
}
@Override
public void addDefaultDeviceStatusFilters(TenantInfoBean tenantInfoBean) throws TenantMgtException {
initTenantFlow(tenantInfoBean);
try {
TenantMgtDataHolder.getInstance().getDeviceStatusManagementService().
addDefaultDeviceStatusFilterIfNotExist(tenantInfoBean.getTenantId());
} catch (MetadataManagementException e) {
String msg = "Error occurred while adding default device status filter";
log.error(msg, e);
throw new TenantMgtException(msg, e);
} finally {
endTenantFlow();
}
}
private void initTenantFlow(TenantInfoBean tenantInfoBean) {
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext privilegedCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();

@ -33,4 +33,9 @@ public class TenantManagerServiceImpl implements TenantManagerService {
public void addDefaultAppCategories(TenantInfoBean tenantInfoBean) throws TenantMgtException {
TenantMgtDataHolder.getInstance().getTenantManager().addDefaultAppCategories(tenantInfoBean);
}
@Override
public void addDefaultDeviceStatusFilters(TenantInfoBean tenantInfoBean) throws TenantMgtException {
TenantMgtDataHolder.getInstance().getTenantManager().addDefaultDeviceStatusFilters(tenantInfoBean);
}
}

@ -18,6 +18,7 @@
package io.entgra.device.mgt.core.tenant.mgt.core.internal;
import io.entgra.device.mgt.core.application.mgt.common.services.ApplicationManager;
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.DeviceStatusManagementService;
import io.entgra.device.mgt.core.tenant.mgt.core.TenantManager;
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.WhiteLabelManagementService;
import org.wso2.carbon.user.core.service.RealmService;
@ -32,6 +33,8 @@ public class TenantMgtDataHolder {
private RealmService realmService;
private DeviceStatusManagementService deviceStatusManagementService;
public RealmService getRealmService() {
return realmService;
}
@ -67,4 +70,12 @@ public class TenantMgtDataHolder {
public static TenantMgtDataHolder getInstance() {
return instance;
}
public DeviceStatusManagementService getDeviceStatusManagementService() {
return deviceStatusManagementService;
}
public void setDeviceStatusManagementService(DeviceStatusManagementService deviceStatusManagementService) {
this.deviceStatusManagementService = deviceStatusManagementService;
}
}

@ -18,6 +18,8 @@
package io.entgra.device.mgt.core.tenant.mgt.core.internal;
import io.entgra.device.mgt.core.application.mgt.common.services.ApplicationManager;
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.DeviceStatusManagementService;
import io.entgra.device.mgt.core.device.mgt.core.metadata.mgt.DeviceStatusManagementServiceImpl;
import io.entgra.device.mgt.core.tenant.mgt.common.spi.TenantManagerService;
import io.entgra.device.mgt.core.tenant.mgt.core.TenantManager;
import io.entgra.device.mgt.core.tenant.mgt.core.impl.TenantManagerImpl;
@ -64,6 +66,10 @@ public class TenantMgtServiceComponent {
componentContext.getBundleContext().registerService(WhiteLabelManagementServiceImpl.class.getName(),
whiteLabelManagementService, null);
TenantMgtDataHolder.getInstance().setWhiteLabelManagementService(whiteLabelManagementService);
DeviceStatusManagementService deviceStatusManagementService = new DeviceStatusManagementServiceImpl();
componentContext.getBundleContext().registerService(DeviceStatusManagementService.class.getName(),
deviceStatusManagementService, null);
TenantMgtDataHolder.getInstance().setDeviceStatusManagementService(deviceStatusManagementService);
DeviceMgtTenantListener deviceMgtTenantListener = new DeviceMgtTenantListener();
if(log.isDebugEnabled()) {
log.info("Tenant management listener is registering");

@ -38,6 +38,7 @@ public class DeviceMgtTenantListener implements TenantMgtListener {
try {
tenantManager.addDefaultRoles(tenantInfoBean);
tenantManager.addDefaultAppCategories(tenantInfoBean);
tenantManager.addDefaultDeviceStatusFilters(tenantInfoBean);
} catch (TenantMgtException e) {
String msg = "Error occurred while executing tenant creation flow";
log.error(msg, e);

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

@ -162,6 +162,54 @@
<Type>deviceInfo</Type>
</DeviceInfoItem>
</DeviceInfoConfigurations>
<DeviceStatusConfigurations>
<EnableDeviceStatusCheck>false</EnableDeviceStatusCheck>
<DeviceStatusItem>
<Type>android</Type>
<AllowedStatus>
<Status>ACTIVE</Status>
<Status>CREATED</Status>
<Status>INACTIVE</Status>
<Status>UNREACHABLE</Status>
<Status>UNCLAIMED</Status>
<Status>SUSPENDED</Status>
<Status>BLOCKED</Status>
<Status>REMOVED</Status>
<Status>SUSPENDED</Status>
<Status>DISENROLLMENT_REQUESTED</Status>
</AllowedStatus>
</DeviceStatusItem>
<DeviceStatusItem>
<Type>ios</Type>
<AllowedStatus>
<Status>ACTIVE</Status>
<Status>CREATED</Status>
<Status>INACTIVE</Status>
<Status>UNREACHABLE</Status>
<Status>UNCLAIMED</Status>
<Status>SUSPENDED</Status>
<Status>BLOCKED</Status>
<Status>REMOVED</Status>
<Status>SUSPENDED</Status>
<Status>DISENROLLMENT_REQUESTED</Status>
</AllowedStatus>
</DeviceStatusItem>
<DeviceStatusItem>
<Type>windows</Type>
<AllowedStatus>
<Status>ACTIVE</Status>
<Status>CREATED</Status>
<Status>INACTIVE</Status>
<Status>UNREACHABLE</Status>
<Status>UNCLAIMED</Status>
<Status>SUSPENDED</Status>
<Status>BLOCKED</Status>
<Status>REMOVED</Status>
<Status>SUSPENDED</Status>
<Status>DISENROLLMENT_REQUESTED</Status>
</AllowedStatus>
</DeviceStatusItem>
</DeviceStatusConfigurations>
<AppRegistration>
<Tags>
<Tag>analytics_management</Tag>
@ -315,6 +363,8 @@
<Scope>dm:geo:geo-fence:manage</Scope>
<Scope>dm:whitelable:view</Scope>
<Scope>dm:whitelable:update</Scope>
<Scope>dm:devicestatusfilter:view</Scope>
<Scope>dm:devicestatusfilter:update</Scope>
<Scope>dm:metadata:view</Scope>
<Scope>dm:metadata:create</Scope>
<Scope>dm:metadata:update</Scope>

@ -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&amp;sp=$sp&amp;tenantDomain=$tenant-domain&amp;ownershipType=$ownership-type&amp;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…
Cancel
Save