From 4b4ed5793a1934a8f3389262d546386f853c85ac Mon Sep 17 00:00:00 2001 From: pramilaniroshan Date: Fri, 15 Dec 2023 10:01:52 +0530 Subject: [PATCH 01/10] Add method for get installed applications using device ID --- .../device/mgt/core/dao/ApplicationDAO.java | 10 ++++ .../mgt/core/dao/impl/ApplicationDAOImpl.java | 46 +++++++++++++++++++ .../DeviceManagementProviderService.java | 11 ++++- .../DeviceManagementProviderServiceImpl.java | 38 ++++++++++++++- 4 files changed, 102 insertions(+), 3 deletions(-) diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/ApplicationDAO.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/ApplicationDAO.java index 0c1899e9af..826c5a07e7 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/ApplicationDAO.java +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/ApplicationDAO.java @@ -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 getInstalledApplicationListOnDevice(int deviceId, int enrolmentId, int tenantId) + throws DeviceManagementDAOException; } diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/impl/ApplicationDAOImpl.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/impl/ApplicationDAOImpl.java index 1f48c3dc92..fb3ad85549 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/impl/ApplicationDAOImpl.java +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/impl/ApplicationDAOImpl.java @@ -575,4 +575,50 @@ public class ApplicationDAOImpl implements ApplicationDAO { } return applicationList; } + + public List getInstalledApplicationListOnDevice(int deviceId, int enrolmentId, int tenantId) + throws DeviceManagementDAOException { + Connection conn; + List 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; + } } diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/service/DeviceManagementProviderService.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/service/DeviceManagementProviderService.java index d3b12e9816..2e35b5a254 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/service/DeviceManagementProviderService.java +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/service/DeviceManagementProviderService.java @@ -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 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 getInstalledApplicationsOnDevice(Device device) throws DeviceManagementException; } diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/service/DeviceManagementProviderServiceImpl.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/service/DeviceManagementProviderServiceImpl.java index 60750b454f..aea7c5873a 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/service/DeviceManagementProviderServiceImpl.java +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/service/DeviceManagementProviderServiceImpl.java @@ -4953,9 +4953,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 +5079,38 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } return newApplicationList; } + + public List getInstalledApplicationsOnDevice(Device device) throws DeviceManagementException { + List 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 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; + } } From a7ae791f9d67f13425a673e7870ecbb7292d919d Mon Sep 17 00:00:00 2001 From: prathabanKavin Date: Mon, 18 Dec 2023 09:15:04 +0530 Subject: [PATCH 02/10] Change deletion warning for users with device --- .../mgt/api/jaxrs/service/impl/UserManagementServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/service/impl/UserManagementServiceImpl.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/service/impl/UserManagementServiceImpl.java index 6d34b2bc6d..cd8063fdca 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/service/impl/UserManagementServiceImpl.java +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/service/impl/UserManagementServiceImpl.java @@ -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; From 946431905f7bcd80bccfd5499275c4bbb64066a0 Mon Sep 17 00:00:00 2001 From: pramilaniroshan Date: Tue, 19 Dec 2023 11:31:48 +0530 Subject: [PATCH 03/10] Remove Tenant id from saveApplicationIcon method --- .../core/application/mgt/core/impl/ApplicationManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/application-mgt/io.entgra.device.mgt.core.application.mgt.core/src/main/java/io/entgra/device/mgt/core/application/mgt/core/impl/ApplicationManagerImpl.java b/components/application-mgt/io.entgra.device.mgt.core.application.mgt.core/src/main/java/io/entgra/device/mgt/core/application/mgt/core/impl/ApplicationManagerImpl.java index 22f5688b07..c897fcf65c 100644 --- a/components/application-mgt/io.entgra.device.mgt.core.application.mgt.core/src/main/java/io/entgra/device/mgt/core/application/mgt/core/impl/ApplicationManagerImpl.java +++ b/components/application-mgt/io.entgra.device.mgt.core.application.mgt.core/src/main/java/io/entgra/device/mgt/core/application/mgt/core/impl/ApplicationManagerImpl.java @@ -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); From c2a9b6a0738293d87b355082680070af0aa849a4 Mon Sep 17 00:00:00 2001 From: Pramila Niroshan Date: Tue, 19 Dec 2023 18:56:49 +0000 Subject: [PATCH 04/10] Add a config to decide which device statuses to persist in the database (#250) Co-authored-by: pramilaniroshan Reviewed-on: https://repository.entgra.net/community/device-mgt-core/pulls/250 Co-authored-by: Pramila Niroshan Co-committed-by: Pramila Niroshan --- .../api/DeviceStatusFilterService.java | 252 +++++++++++ .../impl/DeviceStatusFilterServiceImpl.java | 120 +++++ .../mgt/api/jaxrs/util/DeviceMgtAPIUtils.java | 25 ++ .../src/main/webapp/WEB-INF/cxf-servlet.xml | 2 + .../metadata/mgt/AllowedDeviceStatus.java | 43 ++ .../mgt/DeviceStatusManagementService.java | 85 ++++ .../config/ui/DeviceStatusConfigurations.java | 46 ++ .../mgt/core/config/ui/DeviceStatusItem.java | 48 ++ .../mgt/core/config/ui/UIConfiguration.java | 16 +- .../device/mgt/core/dao/EnrollmentDAO.java | 31 ++ .../dao/impl/AbstractEnrollmentDAOImpl.java | 14 +- .../enrolment/GenericEnrollmentDAOImpl.java | 12 +- .../enrolment/SQLServerEnrollmentDAOImpl.java | 12 +- .../internal/DeviceManagementDataHolder.java | 11 + .../DeviceManagementServiceComponent.java | 13 + .../DeviceStatusManagementServiceImpl.java | 322 ++++++++++++++ .../mgt/dao/util/MetadataConstants.java | 3 + .../DeviceManagementProviderServiceImpl.java | 52 ++- .../task/impl/DeviceStatusMonitoringTask.java | 21 +- .../device/mgt/core/search/DeviceDetails.java | 8 +- .../DeviceManagementProviderServiceTest.java | 12 +- .../mgt/core/task/DeviceTaskManagerTest.java | 3 +- .../config/operation/mdm-ui-config.xml | 410 ++++++++++++++++++ .../src/test/resources/sql/h2.sql | 12 + .../mgt/common/spi/TenantManagerService.java | 2 + .../core/tenant/mgt/core/TenantManager.java | 7 + .../mgt/core/impl/TenantManagerImpl.java | 15 + .../core/impl/TenantManagerServiceImpl.java | 5 + .../core/internal/TenantMgtDataHolder.java | 11 + .../internal/TenantMgtServiceComponent.java | 6 + .../listener/DeviceMgtTenantListener.java | 1 + .../src/main/resources/conf/mdm-ui-config.xml | 50 +++ 32 files changed, 1630 insertions(+), 40 deletions(-) create mode 100644 components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/service/api/DeviceStatusFilterService.java create mode 100644 components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/service/impl/DeviceStatusFilterServiceImpl.java create mode 100644 components/device-mgt/io.entgra.device.mgt.core.device.mgt.common/src/main/java/io/entgra/device/mgt/core/device/mgt/common/metadata/mgt/AllowedDeviceStatus.java create mode 100644 components/device-mgt/io.entgra.device.mgt.core.device.mgt.common/src/main/java/io/entgra/device/mgt/core/device/mgt/common/metadata/mgt/DeviceStatusManagementService.java create mode 100644 components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/config/ui/DeviceStatusConfigurations.java create mode 100644 components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/config/ui/DeviceStatusItem.java create mode 100644 components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/metadata/mgt/DeviceStatusManagementServiceImpl.java create mode 100644 components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/test/resources/config/operation/mdm-ui-config.xml diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/service/api/DeviceStatusFilterService.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/service/api/DeviceStatusFilterService.java new file mode 100644 index 0000000000..7c0d84de1d --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/service/api/DeviceStatusFilterService.java @@ -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 deviceStatus); +} diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/service/impl/DeviceStatusFilterServiceImpl.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/service/impl/DeviceStatusFilterServiceImpl.java new file mode 100644 index 0000000000..7e5fd01437 --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/service/impl/DeviceStatusFilterServiceImpl.java @@ -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 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 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(); + } + } +} diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/util/DeviceMgtAPIUtils.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/util/DeviceMgtAPIUtils.java index 1c3be6a797..a39cdba7b2 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/util/DeviceMgtAPIUtils.java +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/util/DeviceMgtAPIUtils.java @@ -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. * diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/webapp/WEB-INF/cxf-servlet.xml index bb05b0b2e3..7cdb4ffa0e 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/webapp/WEB-INF/cxf-servlet.xml +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -50,6 +50,7 @@ + @@ -101,6 +102,7 @@ + diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.common/src/main/java/io/entgra/device/mgt/core/device/mgt/common/metadata/mgt/AllowedDeviceStatus.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.common/src/main/java/io/entgra/device/mgt/core/device/mgt/common/metadata/mgt/AllowedDeviceStatus.java new file mode 100644 index 0000000000..6824315b0d --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.common/src/main/java/io/entgra/device/mgt/core/device/mgt/common/metadata/mgt/AllowedDeviceStatus.java @@ -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 status; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public List getStatus() { + return status; + } + + public void setStatus(List status) { + this.status = status; + } +} diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.common/src/main/java/io/entgra/device/mgt/core/device/mgt/common/metadata/mgt/DeviceStatusManagementService.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.common/src/main/java/io/entgra/device/mgt/core/device/mgt/common/metadata/mgt/DeviceStatusManagementService.java new file mode 100644 index 0000000000..5ee7c8fce0 --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.common/src/main/java/io/entgra/device/mgt/core/device/mgt/common/metadata/mgt/DeviceStatusManagementService.java @@ -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 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 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 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; +} diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/config/ui/DeviceStatusConfigurations.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/config/ui/DeviceStatusConfigurations.java new file mode 100644 index 0000000000..9cdbacf399 --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/config/ui/DeviceStatusConfigurations.java @@ -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 deviceStatusItems; + private boolean deviceStatusCheck; + + @XmlElement(name = "DeviceStatusItem") + public List getDeviceStatusItems() { + return deviceStatusItems; + } + + @XmlElement(name = "EnableDeviceStatusCheck") + public boolean isDeviceStatusCheck() { + return deviceStatusCheck; + } + + public void setDeviceStatusCheck(boolean deviceStatusCheck) { + this.deviceStatusCheck = deviceStatusCheck; + } + + public void setDeviceStatusItems(List deviceStatusItems) { + this.deviceStatusItems = deviceStatusItems; + } +} diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/config/ui/DeviceStatusItem.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/config/ui/DeviceStatusItem.java new file mode 100644 index 0000000000..43a5cc018a --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/config/ui/DeviceStatusItem.java @@ -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 status; + private String type; + + @XmlElement(name = "Type") + public String getType() { + return type; + } + + @XmlElementWrapper(name = "AllowedStatus") + @XmlElement(name = "Status") + public List getStatus() { + return status; + } + + public void setType(String type) { + this.type = type; + } + + public void setStatus(List status) { + this.status = status; + } +} diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/config/ui/UIConfiguration.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/config/ui/UIConfiguration.java index 6e71d17072..4dd9cbfe4a 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/config/ui/UIConfiguration.java +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/config/ui/UIConfiguration.java @@ -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; + } } diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/EnrollmentDAO.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/EnrollmentDAO.java index c6fd1828bc..1bce2627d9 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/EnrollmentDAO.java +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/EnrollmentDAO.java @@ -62,4 +62,35 @@ public interface EnrollmentDAO { boolean updateOwnerOfEnrollment(List 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; + + } diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/impl/AbstractEnrollmentDAOImpl.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/impl/AbstractEnrollmentDAOImpl.java index 456dca9c8a..98050fe318 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/impl/AbstractEnrollmentDAOImpl.java +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/impl/AbstractEnrollmentDAOImpl.java @@ -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 = ?"; diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/impl/enrolment/GenericEnrollmentDAOImpl.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/impl/enrolment/GenericEnrollmentDAOImpl.java index 452e1a1b30..188af00f88 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/impl/enrolment/GenericEnrollmentDAOImpl.java +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/impl/enrolment/GenericEnrollmentDAOImpl.java @@ -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){ diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/impl/enrolment/SQLServerEnrollmentDAOImpl.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/impl/enrolment/SQLServerEnrollmentDAOImpl.java index cd5d846df9..18074e0841 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/impl/enrolment/SQLServerEnrollmentDAOImpl.java +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/dao/impl/enrolment/SQLServerEnrollmentDAOImpl.java @@ -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){ diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/internal/DeviceManagementDataHolder.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/internal/DeviceManagementDataHolder.java index a1dbe98c2a..5cdc29da25 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/internal/DeviceManagementDataHolder.java +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/internal/DeviceManagementDataHolder.java @@ -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 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(); diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/internal/DeviceManagementServiceComponent.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/internal/DeviceManagementServiceComponent.java index d7b459d4b7..b3bc1f2f0d 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/internal/DeviceManagementServiceComponent.java +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/internal/DeviceManagementServiceComponent.java @@ -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); diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/metadata/mgt/DeviceStatusManagementServiceImpl.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/metadata/mgt/DeviceStatusManagementServiceImpl.java new file mode 100644 index 0000000000..1daea9fd24 --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/metadata/mgt/DeviceStatusManagementServiceImpl.java @@ -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 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>() { + }.getType(); + List 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 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>() {}.getType(); + List 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 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>() {}.getType(); + List 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>() { + }.getType(); + List statusList = gson.fromJson(metadata.getMetaValue(), listType); + + for (AllowedDeviceStatus status : statusList) { + if (status.getType().equalsIgnoreCase(deviceType)) { + List 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 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 getDefaultDeviceStatus() { + DeviceStatusConfigurations deviceStatusConfigurations = UIConfigurationManager.getInstance().getUIConfig().getDeviceStatusConfigurations(); + List 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; + } +} diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/metadata/mgt/dao/util/MetadataConstants.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/metadata/mgt/dao/util/MetadataConstants.java index 644875efdb..5d2c44af42 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/metadata/mgt/dao/util/MetadataConstants.java +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/metadata/mgt/dao/util/MetadataConstants.java @@ -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"; } diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/service/DeviceManagementProviderServiceImpl.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/service/DeviceManagementProviderServiceImpl.java index 60750b454f..278912c25a 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/service/DeviceManagementProviderServiceImpl.java +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/service/DeviceManagementProviderServiceImpl.java @@ -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); diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/status/task/impl/DeviceStatusMonitoringTask.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/status/task/impl/DeviceStatusMonitoringTask.java index 6f078619ee..fd9958782b 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/status/task/impl/DeviceStatusMonitoringTask.java +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/main/java/io/entgra/device/mgt/core/device/mgt/core/status/task/impl/DeviceStatusMonitoringTask.java @@ -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 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); diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/test/java/io/entgra/device/mgt/core/device/mgt/core/search/DeviceDetails.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/test/java/io/entgra/device/mgt/core/device/mgt/core/search/DeviceDetails.java index 3c7365936e..8d6a4a5673 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/test/java/io/entgra/device/mgt/core/device/mgt/core/search/DeviceDetails.java +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/test/java/io/entgra/device/mgt/core/device/mgt/core/search/DeviceDetails.java @@ -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 diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/test/java/io/entgra/device/mgt/core/device/mgt/core/service/DeviceManagementProviderServiceTest.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/test/java/io/entgra/device/mgt/core/device/mgt/core/service/DeviceManagementProviderServiceTest.java index e1bbe3ee76..942cb2c8b0 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/test/java/io/entgra/device/mgt/core/device/mgt/core/service/DeviceManagementProviderServiceTest.java +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/test/java/io/entgra/device/mgt/core/device/mgt/core/service/DeviceManagementProviderServiceTest.java @@ -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); diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/test/java/io/entgra/device/mgt/core/device/mgt/core/task/DeviceTaskManagerTest.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/test/java/io/entgra/device/mgt/core/device/mgt/core/task/DeviceTaskManagerTest.java index 335ba0dc25..e232bffe44 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/test/java/io/entgra/device/mgt/core/device/mgt/core/task/DeviceTaskManagerTest.java +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/test/java/io/entgra/device/mgt/core/device/mgt/core/task/DeviceTaskManagerTest.java @@ -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++) { diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/test/resources/config/operation/mdm-ui-config.xml b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/test/resources/config/operation/mdm-ui-config.xml new file mode 100644 index 0000000000..8b5eba6efa --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/test/resources/config/operation/mdm-ui-config.xml @@ -0,0 +1,410 @@ + + + + + true + true + + 3600 + + 10000 + + + false + tracking_url + + access_token + sender_actorId + + + false + true + false + true + false + true + + + + name + label_device + default + + + type + label_type + default + + + owner + label_owner + default + + + serial + label_serialNumber + default + + + ownership + label_ownership + default + + + status + label_status + default + + + dateOfLastUpdate + label_last_updated + default + + + actions + label_actions + default + + + batteryLevel + label_battery_leve + deviceInfo + + + deviceModel + label_deviceModel + deviceInfo + + + osVersion + label_os_version + deviceInfo + + + vendor + label_vendor + deviceInfo + + + availableRAMMemory + label_available_ram_memory + deviceInfo + + + connectionType + label_connection_type + deviceInfo + + + cpuUsage + label_cpu_usage + deviceInfo + + + externalAvailableMemory + label_external_available_memory + deviceInfo + + + externalTotalMemory + label_external_tot_memory + deviceInfo + + + internalAvailableMemory + label_internal_available_memory + deviceInfo + + + internalTotalMemory + label_internal_tot_memory + deviceInfo + + + osBuildDate + label_os_build_date + deviceInfo + + + pluggedIn + label_plugged_in + deviceInfo + + + ssid + label_ssid + deviceInfo + + + totalRAMMemory + label_tot_ram_memory + deviceInfo + + + updatedTime + label_updated_time + deviceInfo + + + + true + + android + + ACTIVE + CREATED + INACTIVE + UNREACHABLE + UNCLAIMED + SUSPENDED + BLOCKED + REMOVED + SUSPENDED + DISENROLLMENT_REQUESTED + + + + ios + + ACTIVE + CREATED + INACTIVE + UNREACHABLE + UNCLAIMED + SUSPENDED + BLOCKED + REMOVED + SUSPENDED + DISENROLLMENT_REQUESTED + + + + windows + + ACTIVE + CREATED + INACTIVE + UNREACHABLE + UNCLAIMED + SUSPENDED + BLOCKED + REMOVED + SUSPENDED + DISENROLLMENT_REQUESTED + + + + + + analytics_management + application_management + device_management + subscription_management + review_management + + true + + + grafana:api:view + am:store:app:review:view + am:store:app:review:update + am:pub:sp:app:view + am:pub:sp:create + am:pub:sp:attach + am:pub:sp:detach + am:pub:sp:connect + am:pub:app:view + am:pub:app:update + am:store:app:view + am:store:app:modify + am:store:app:sub:install + am:store:app:sub:uninstall + am:admin:pub:app:review:view + am:admin:pub:app:update + am:admin:store:app:review:update + am:admin:store:app:sub:view + am:admin:store:app:sub:modify + dm:device-type:view + and:enterprise:modify + and:enterprise:view + dm:sign-csr + dm:admin:devices:view + dm:devices:status:change + rm:roles:add + rm:users:add + rm:roles:update + rm:roles:permissions:view + rm:roles:details:view + rm:roles:view + rm:roles:combined:add + rm:roles:delete + dm:activity:get + dm:devices:delete + dm:devices:app:view + dm:devices:policy:view + dm:devices:compliance:view + dm:devices:features:view + dm:devices:ops:view + dm:devices:search + dm:devices:details + dm:devices:update + dm:devices:view + dm:devices:enrollment-guide:view + dm:conf:view + dm:conf:manage + pm:policies:remove + pm:policies:priorities:update + pm:policies:deactivate + pm:policies:details:view + pm:policies:add + pm:policies:activate + pm:policies:update + pm:policies:change + dm:policies:view + um:users:add + um:users:details:view + um:users:count + um:users:delete + um:roles:view + um:users:user-details:view + um:users:cred:change + um:users:search + um:users:is-exist + um:users:update + um:users:invite + um:admin:users:view + dm:admin:enrollment:update + gm:devices:view + gm:groups:update + gm:groups:add + gm:groups:device:view + gm:devices:count + gm:devices-types:view + gm:groups:remove + gm:groups:view + gm:groups:groups-view + gm:roles:share + gm:groups:count + gm:roles:view + gm:devices:remove + gm:devices:add + gm:devices:assign + dm:device-type:conf:view + dm:device-type:features:view + dm:device-type:view + am:admin:app:install + am:admin:app:uninstall + gm:admin:groups:count + gm:admin:groups:view + gm:admin:groups:add + dm:notif:mark-checked + dm:notifications:view + cm:cert:delete + cm:cert:details:get + cm:cert:view + cm:cert:add + cm:cert:verify + dm:admin + dm:device-type:deploy + dm:device-type:event:modify + dm:device-type:event:view + dm:admin:device-type:modify + dm:admin:device-type:view + dm:admin:device-type:conf:add + dm:device:enroll + dm:geo:an:view + dm:geo:alerts:manage + dm:admin:devices:permanent-delete + and:conf:manage + and:conf:view + um:users:permission:view + ios:conf:view + ios:conf:manage + ios:dep:view + ios:dep:add + win:conf:view + win:conf:manage + and:ops:lock-devices + and:ops:unlock-devices + and:ops:location + and:ops:clear-password + and:ops:control-camera + and:ops:enterprise-wipe + and:ops:wipe + and:ops:ring + and:ops:app-list + and:ops:reboot + and:ops:change-LockTask + and:ops:mute + and:ops:conf-display-msg + and:ops:send-app-restrictions + and:ops:file-transfer + and:ops:set-webclip + and:ops:password-policy + and:ops:change-lock-code + and:ops:upgrade-firmware + and:ops:send-notif + dm:geo:geo-fence:manage + dm:whitelable:view + dm:whitelable:update + dm:metadata:view + dm:metadata:create + dm:metadata:update + and:ops:add-google-acc + and:ops:authenticate-acc + and:ops:update-default-sim + and:ops:add-google-acc + and:ops:device-info + win:ops:lock-devices + win:devices:enroll + win:ops:disenroll + win:ops:wipe + win:ops:ring + win:ops:lock-reset + win:ops:reboot + win:ops:location + admin:tenant:view + dm:admin:devices:usage:view + and:ops:clear-app + and:ops:suspend-package + and:ops:alternate-install + ios:ops:lock + ios:ops:location + ios:ops:ring + ios:ops:clear-passcode + ios:ops:enterprise-wipe + ios:ops:notif + ios:ops:wipe + ios:ops:boolean-setting + ios:ops:wallpaper + ios:ops:app-attributes + ios:ops:app-conf + mac:ops:restart + mac:ops:shutdown + am:store:vpp:user:modify + am:store:vpp:user:view + am:store:vpp:assets:modify + am:store:vpp:assets:view + and:devices:enroll + ios:devices:enroll + + + device-mgt + + \ No newline at end of file diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/test/resources/sql/h2.sql b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/test/resources/sql/h2.sql index b4d2bde228..94c94106b5 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/test/resources/sql/h2.sql +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.core/src/test/resources/sql/h2.sql @@ -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 -- diff --git a/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.common/src/main/java/io/entgra/device/mgt/core/tenant/mgt/common/spi/TenantManagerService.java b/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.common/src/main/java/io/entgra/device/mgt/core/tenant/mgt/common/spi/TenantManagerService.java index c8af337243..a43f20f24c 100644 --- a/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.common/src/main/java/io/entgra/device/mgt/core/tenant/mgt/common/spi/TenantManagerService.java +++ b/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.common/src/main/java/io/entgra/device/mgt/core/tenant/mgt/common/spi/TenantManagerService.java @@ -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; } \ No newline at end of file diff --git a/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/TenantManager.java b/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/TenantManager.java index 1a6eeff68a..97eb706be7 100644 --- a/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/TenantManager.java +++ b/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/TenantManager.java @@ -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; } diff --git a/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/impl/TenantManagerImpl.java b/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/impl/TenantManagerImpl.java index edfb95360b..5dc2eb7f08 100644 --- a/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/impl/TenantManagerImpl.java +++ b/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/impl/TenantManagerImpl.java @@ -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(); diff --git a/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/impl/TenantManagerServiceImpl.java b/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/impl/TenantManagerServiceImpl.java index 79de1b0000..da21a52100 100644 --- a/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/impl/TenantManagerServiceImpl.java +++ b/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/impl/TenantManagerServiceImpl.java @@ -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); + } } diff --git a/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/internal/TenantMgtDataHolder.java b/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/internal/TenantMgtDataHolder.java index 7c34b3c177..9658d68848 100644 --- a/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/internal/TenantMgtDataHolder.java +++ b/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/internal/TenantMgtDataHolder.java @@ -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; + } } diff --git a/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/internal/TenantMgtServiceComponent.java b/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/internal/TenantMgtServiceComponent.java index 7c7210213c..fa2f26c972 100644 --- a/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/internal/TenantMgtServiceComponent.java +++ b/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/internal/TenantMgtServiceComponent.java @@ -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"); diff --git a/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/listener/DeviceMgtTenantListener.java b/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/listener/DeviceMgtTenantListener.java index 40b58efe7e..978e69b0e4 100644 --- a/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/listener/DeviceMgtTenantListener.java +++ b/components/tenant-mgt/io.entgra.device.mgt.core.tenant.mgt.core/src/main/java/io/entgra/device/mgt/core/tenant/mgt/core/listener/DeviceMgtTenantListener.java @@ -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); diff --git a/features/device-mgt/io.entgra.device.mgt.core.device.mgt.basics.feature/src/main/resources/conf/mdm-ui-config.xml b/features/device-mgt/io.entgra.device.mgt.core.device.mgt.basics.feature/src/main/resources/conf/mdm-ui-config.xml index 416c0711f3..50e75857bd 100644 --- a/features/device-mgt/io.entgra.device.mgt.core.device.mgt.basics.feature/src/main/resources/conf/mdm-ui-config.xml +++ b/features/device-mgt/io.entgra.device.mgt.core.device.mgt.basics.feature/src/main/resources/conf/mdm-ui-config.xml @@ -162,6 +162,54 @@ deviceInfo + + false + + android + + ACTIVE + CREATED + INACTIVE + UNREACHABLE + UNCLAIMED + SUSPENDED + BLOCKED + REMOVED + SUSPENDED + DISENROLLMENT_REQUESTED + + + + ios + + ACTIVE + CREATED + INACTIVE + UNREACHABLE + UNCLAIMED + SUSPENDED + BLOCKED + REMOVED + SUSPENDED + DISENROLLMENT_REQUESTED + + + + windows + + ACTIVE + CREATED + INACTIVE + UNREACHABLE + UNCLAIMED + SUSPENDED + BLOCKED + REMOVED + SUSPENDED + DISENROLLMENT_REQUESTED + + + analytics_management @@ -315,6 +363,8 @@ dm:geo:geo-fence:manage dm:whitelable:view dm:whitelable:update + dm:devicestatusfilter:view + dm:devicestatusfilter:update dm:metadata:view dm:metadata:create dm:metadata:update From 041c84a45f76e00b180c41a653ed67ebb88935ea Mon Sep 17 00:00:00 2001 From: Rajitha Kumara Date: Wed, 20 Dec 2023 14:40:05 +0530 Subject: [PATCH 05/10] Fix duplicate scope publishing issue --- .../publisher/APIPublisherServiceImpl.java | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/components/apimgt-extensions/io.entgra.device.mgt.core.apimgt.webapp.publisher/src/main/java/io/entgra/device/mgt/core/apimgt/webapp/publisher/APIPublisherServiceImpl.java b/components/apimgt-extensions/io.entgra.device.mgt.core.apimgt.webapp.publisher/src/main/java/io/entgra/device/mgt/core/apimgt/webapp/publisher/APIPublisherServiceImpl.java index db7e58a32b..d748e1cee9 100644 --- a/components/apimgt-extensions/io.entgra.device.mgt.core.apimgt.webapp.publisher/src/main/java/io/entgra/device/mgt/core/apimgt/webapp/publisher/APIPublisherServiceImpl.java +++ b/components/apimgt-extensions/io.entgra.device.mgt.core.apimgt.webapp.publisher/src/main/java/io/entgra/device/mgt/core/apimgt/webapp/publisher/APIPublisherServiceImpl.java @@ -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 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 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"); From aa4b62328367f8af68d6752d10cc4a65afc8f282 Mon Sep 17 00:00:00 2001 From: rajitha Date: Fri, 11 Aug 2023 09:50:33 +0530 Subject: [PATCH 06/10] Add JIT base provision and enrollment handlers --- .../jaxrs/beans/InvitationMailProfile.java | 28 ++ .../jaxrs/beans/JITEnrollmentInvitation.java | 50 ++++ .../service/api/UserManagementService.java | 73 ++++-- .../impl/UserManagementServiceImpl.java | 76 +++++- .../JITEnrollmentCallbackHandler.java | 219 ++++++++++++++++ .../interceptor/JITEnrollmentHandler.java | 90 +++++++ .../JITProvisionCallbackHandler.java | 72 +++++ .../interceptor/JITProvisionHandler.java | 248 ++++++++++++++++++ .../ui/request/interceptor/beans/JITData.java | 68 +++++ .../interceptor/beans/JITEnrollmentData.java | 68 +++++ .../exceptions/JITEnrollmentException.java | 30 +++ .../exceptions/JITProvisionException.java | 29 ++ .../interceptor/util/HandlerConstants.java | 8 + .../src/main/resources/conf/jit-config.xml | 28 ++ .../default-jit-enrollment-invitation.vm | 61 +++++ .../src/main/resources/p2.inf | 1 + .../src/main/resources/p2.inf | 1 + 17 files changed, 1132 insertions(+), 18 deletions(-) create mode 100644 components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/beans/InvitationMailProfile.java create mode 100644 components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/beans/JITEnrollmentInvitation.java create mode 100644 components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITEnrollmentCallbackHandler.java create mode 100644 components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITEnrollmentHandler.java create mode 100644 components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITProvisionCallbackHandler.java create mode 100644 components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITProvisionHandler.java create mode 100644 components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/beans/JITData.java create mode 100644 components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/beans/JITEnrollmentData.java create mode 100644 components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/exceptions/JITEnrollmentException.java create mode 100644 components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/exceptions/JITProvisionException.java create mode 100644 features/device-mgt/io.entgra.device.mgt.core.device.mgt.basics.feature/src/main/resources/conf/jit-config.xml create mode 100644 features/device-mgt/io.entgra.device.mgt.core.device.mgt.basics.feature/src/main/resources/email/templates/default-jit-enrollment-invitation.vm diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/beans/InvitationMailProfile.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/beans/InvitationMailProfile.java new file mode 100644 index 0000000000..4133d3f25e --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/beans/InvitationMailProfile.java @@ -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; + } +} diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/beans/JITEnrollmentInvitation.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/beans/JITEnrollmentInvitation.java new file mode 100644 index 0000000000..32e4bfbe9d --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/beans/JITEnrollmentInvitation.java @@ -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 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 getMailProfiles() { + return mailProfiles; + } + + public void setMailProfiles(List 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; + } +} diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/service/api/UserManagementService.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/service/api/UserManagementService.java index 2b7b81b72f..2f824ef34b 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/service/api/UserManagementService.java +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/service/api/UserManagementService.java @@ -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); diff --git a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/service/impl/UserManagementServiceImpl.java b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/service/impl/UserManagementServiceImpl.java index cd8063fdca..2ed0d17bee 100644 --- a/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/service/impl/UserManagementServiceImpl.java +++ b/components/device-mgt/io.entgra.device.mgt.core.device.mgt.api/src/main/java/io/entgra/device/mgt/core/device/mgt/api/jaxrs/service/impl/UserManagementServiceImpl.java @@ -19,7 +19,6 @@ package io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl; import com.google.gson.JsonArray; import com.google.gson.JsonObject; -import io.entgra.device.mgt.core.device.mgt.common.Device; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -28,7 +27,6 @@ import org.eclipse.wst.common.uriresolver.internal.util.URIEncoder; import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.context.PrivilegedCarbonContext; import io.entgra.device.mgt.core.device.mgt.common.exceptions.DeviceManagementException; -import io.entgra.device.mgt.core.device.mgt.common.EnrolmentInfo; import io.entgra.device.mgt.core.device.mgt.common.configuration.mgt.ConfigurationManagementException; import io.entgra.device.mgt.core.device.mgt.common.exceptions.OTPManagementException; import io.entgra.device.mgt.core.device.mgt.common.invitation.mgt.DeviceEnrollmentInvitation; @@ -45,6 +43,8 @@ import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.BasicUserInfoWrapper import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.Credential; import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.EnrollmentInvitation; import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.ErrorResponse; +import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.InvitationMailProfile; +import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.JITEnrollmentInvitation; import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.OldPasswordResetWrapper; import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.PermissionList; import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.RoleList; @@ -83,7 +83,6 @@ import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; -import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; @@ -92,6 +91,7 @@ import java.io.File; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; +import java.nio.file.NoSuchFileException; import java.security.SecureRandom; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -757,6 +757,54 @@ public class UserManagementServiceImpl implements UserManagementService { return Response.status(Response.Status.OK).entity("Invitation mails have been sent.").build(); } + @POST + @Path("jit-enrollment-invite") + @Override + public Response inviteExternalUsers(JITEnrollmentInvitation jitEnrollmentInvitation) { + if (jitEnrollmentInvitation.getMailProfiles() == null || jitEnrollmentInvitation.getMailProfiles().isEmpty()) { + String msg = "Error occurred while validating mail profiles. Mail profiles cannot be empty"; + log.error(msg); + throw new BadRequestException( + new ErrorResponse.ErrorResponseBuilder().setMessage(msg).setCode(HttpStatus.SC_BAD_REQUEST). + build()); + } + String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String inviteBy = DeviceMgtAPIUtils.getAuthenticatedUser(); + try { + DeviceManagementProviderService dms = DeviceMgtAPIUtils.getDeviceManagementService(); + for (InvitationMailProfile mailProfile : jitEnrollmentInvitation.getMailProfiles()) { + Properties props = new Properties(); + props.setProperty("username", mailProfile.getUsername()); + props.setProperty("tenant-domain", tenantDomain); + props.setProperty("sp", jitEnrollmentInvitation.getSp()); + props.setProperty("ownership-type", jitEnrollmentInvitation.getOwnershipType()); + props.setProperty("device-type", jitEnrollmentInvitation.getDeviceType()); + props.setProperty("invite-by", inviteBy); + Set 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,28 @@ 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; + File template = new File(CarbonUtils.getCarbonHome() + File.separator + "repository" + File.separator + + "resources" + File.separator + "email-templates" + File.separator + templateName + ".vm"); + if (template.exists()) { + return templateName; + } + String defaultTemplateName = "default" + separator + prefix; + File defaultTemplate = new File(CarbonUtils.getCarbonHome() + File.separator + "repository" + File.separator + + "resources" + File.separator + "email-templates" + File.separator + defaultTemplateName + ".vm"); + + if (defaultTemplate.exists()) { + if (log.isDebugEnabled()) { + log.debug("The template that is expected to use is not available. Therefore, using default template."); + } + return defaultTemplateName; + } + + String msg = "Didn't found template file for " + templateName; + throw new NoSuchFileException(msg); + } + /** * Searches users which matches a given filter based on a claim * diff --git a/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITEnrollmentCallbackHandler.java b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITEnrollmentCallbackHandler.java new file mode 100644 index 0000000000..3d314bf79d --- /dev/null +++ b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITEnrollmentCallbackHandler.java @@ -0,0 +1,219 @@ +/* + * 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 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.Base64; + +@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; + + @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()); + 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; + } + + JITEnrollmentData 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")); + scope = "perm:metadata:view perm:metadata:create perm:metadata:update perm:android:enroll " + + "perm:device:enroll perm:android:view-configuration"; + 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); + } + } + + /*** + * 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); + } +} diff --git a/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITEnrollmentHandler.java b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITEnrollmentHandler.java new file mode 100644 index 0000000000..b13d4d904a --- /dev/null +++ b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITEnrollmentHandler.java @@ -0,0 +1,90 @@ +/* + * 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.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 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); + } +} diff --git a/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITProvisionCallbackHandler.java b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITProvisionCallbackHandler.java new file mode 100644 index 0000000000..0214069df0 --- /dev/null +++ b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITProvisionCallbackHandler.java @@ -0,0 +1,72 @@ +/* + * 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; + +@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) { + 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; + } + + 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); + } + } +} diff --git a/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITProvisionHandler.java b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITProvisionHandler.java new file mode 100644 index 0000000000..61f6614cc9 --- /dev/null +++ b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/JITProvisionHandler.java @@ -0,0 +1,248 @@ +/* + * 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.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 adminUsername; + private String clientId; + private String JITServiceProviderName; + private String apiManagerUrl; + private String encodedAdminCredentials; + private String encodedClientCredentials; + private String JITConfigurationPath; + private String JITCallbackUrl; + private String redirectUrl; + + @Override + 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()); + JITCallbackUrl = request.getScheme() + HandlerConstants.SCHEME_SEPARATOR + + System.getProperty(HandlerConstants.IOT_CORE_HOST_ENV_VAR) + + HandlerConstants.COLON + HandlerUtil.getCorePort(request.getScheme()) + + request.getContextPath() + + HandlerConstants.JIT_PROVISION_CALLBACK_URL; + apiManagerUrl = request.getScheme() + HandlerConstants.SCHEME_SEPARATOR + + System.getProperty(HandlerConstants.IOT_APIM_HOST_ENV_VAR) + + HandlerConstants.COLON + HandlerUtil.getAPIManagerPort(request.getScheme()); + JITConfigurationPath = CarbonUtils.getCarbonConfigDirPath() + File.separator + "jit-config.xml"; + String scope = "openid"; + tenantDomain = request.getParameter("tenantDomain"); + 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; + } + + populateServiceProvider(); + persistJITData(request.getSession(true)); + response.sendRedirect(keyManagerUrl + HandlerConstants.AUTHORIZATION_ENDPOINT + + "?response_type=code" + + "&client_id=" + clientId + + "&state=" + + "&scope=" + scope + + "&redirect_uri=" + JITCallbackUrl); + } catch (JITProvisionException | IOException ex) { + log.error("Error occurred while processing JIT provisioning request", ex); + } + } + + /*** + * Construct dynamic client registration request + * @return {@link HttpPost} DCR request + */ + private HttpPost buildDCRRequest() { + HttpPost DCRRequest = new HttpPost(apiManagerUrl + HandlerConstants.DCR_URL); + DCRRequest.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()); + DCRRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BASIC + encodedAdminCredentials); + JsonObject payload = new JsonObject(); + payload.addProperty("clientName", JITServiceProviderName); + payload.addProperty("owner", adminUsername); + payload.addProperty("saasApp", true); + payload.addProperty("grantType", HandlerConstants.CODE_GRANT_TYPE); + payload.addProperty("callbackUrl", JITCallbackUrl); + DCRRequest.setEntity(new StringEntity(payload.toString(), ContentType.APPLICATION_JSON)); + return DCRRequest; + } + + /*** + * Retrieve JIT data from current session if session exists, otherwise build and return + * @param session - {@link HttpSession} + * @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(HandlerConstants.SESSION_JIT_DATA_KEY, JITInfo); + } + + /*** + * Populate service provider details + * @throws JITProvisionException throws when dcr request fails due to IO exception + */ + private void populateServiceProvider() throws JITProvisionException { + try { + HttpPost DCRRequest = buildDCRRequest(); + ProxyResponse proxyResponse = HandlerUtil.execute(DCRRequest); + if (proxyResponse.getCode() == HttpStatus.SC_OK) { + JsonObject serviceProvider = parseResponseData(proxyResponse.getData()); + clientId = serviceProvider.get("clientId").getAsString(); + String clientSecret = serviceProvider.get("clientSecret").getAsString(); + String headerValue = clientId + ':' + clientSecret; + encodedClientCredentials = Base64.getEncoder().encodeToString(headerValue.getBytes()); + } + } catch (IOException ex) { + String msg = "Error exception occurred while executing proxy request"; + throw new JITProvisionException(msg, ex); + } + } + + /*** + * Parse string data and build json object + * @param data - Json string + * @return {@link JsonObject} Json object corresponding to provided json string + * @throws JITProvisionException throws when error occurred while parsing + */ + private JsonObject parseResponseData(String data) throws JITProvisionException { + JsonParser parser = new JsonParser(); + JsonElement responseData = parser.parse(data); + if (responseData.isJsonObject()) { + return responseData.getAsJsonObject(); + } + throw new JITProvisionException("Unexpected response body return"); + } + + /*** + * Find the tenant based configurations and return + * @param tenantDomain - Domain of the tenant + * @param document - Config doc + * @return {@link Element} If config found return configuration element, otherwise null + */ + private Element findTenantConfigs(String tenantDomain, Document document) { + NodeList tenantConfigurations = document.getElementsByTagName("TenantConfiguration"); + for (int idx = 0; idx < tenantConfigurations.getLength(); idx++) { + Node configNode = tenantConfigurations.item(idx); + if (configNode.getNodeType() == Node.ELEMENT_NODE) { + Element configElement = (Element) configNode; + if (Objects.equals(configElement.getAttributes(). + getNamedItem("tenantDomain").getNodeValue(), tenantDomain)) { + 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 { + File JITConfigurationFile = new File(JITConfigurationPath); + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + Document JITConfigurationDoc = documentBuilder.parse(JITConfigurationFile); + JITConfigurationDoc.getDocumentElement().normalize(); + Element tenantConfig = findTenantConfigs(tenantDomain, JITConfigurationDoc); + if (tenantConfig == null) return false; + adminUsername = tenantConfig.getElementsByTagName("AdminUsername").item(0).getTextContent(); + String adminPassword = tenantConfig.getElementsByTagName("AdminPassword").item(0).getTextContent(); + String headerValue = adminUsername + ":" + adminPassword; + encodedAdminCredentials = Base64.getEncoder().encodeToString(headerValue.getBytes()); + 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); + } + } +} diff --git a/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/beans/JITData.java b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/beans/JITData.java new file mode 100644 index 0000000000..0e5f1769e7 --- /dev/null +++ b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/beans/JITData.java @@ -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; + } +} diff --git a/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/beans/JITEnrollmentData.java b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/beans/JITEnrollmentData.java new file mode 100644 index 0000000000..225d31cc91 --- /dev/null +++ b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/beans/JITEnrollmentData.java @@ -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; + } +} diff --git a/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/exceptions/JITEnrollmentException.java b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/exceptions/JITEnrollmentException.java new file mode 100644 index 0000000000..c845f8b5c8 --- /dev/null +++ b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/exceptions/JITEnrollmentException.java @@ -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); + } +} + diff --git a/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/exceptions/JITProvisionException.java b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/exceptions/JITProvisionException.java new file mode 100644 index 0000000000..fc3018890d --- /dev/null +++ b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/exceptions/JITProvisionException.java @@ -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); + } +} diff --git a/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/util/HandlerConstants.java b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/util/HandlerConstants.java index 9aa9cb9fe6..f7f4399a77 100644 --- a/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/util/HandlerConstants.java +++ b/components/ui-request-interceptor/io.entgra.device.mgt.core.ui.request.interceptor/src/main/java/io/entgra/device/mgt/core/ui/request/interceptor/util/HandlerConstants.java @@ -107,4 +107,12 @@ 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"; } diff --git a/features/device-mgt/io.entgra.device.mgt.core.device.mgt.basics.feature/src/main/resources/conf/jit-config.xml b/features/device-mgt/io.entgra.device.mgt.core.device.mgt.basics.feature/src/main/resources/conf/jit-config.xml new file mode 100644 index 0000000000..ae22e570ab --- /dev/null +++ b/features/device-mgt/io.entgra.device.mgt.core.device.mgt.basics.feature/src/main/resources/conf/jit-config.xml @@ -0,0 +1,28 @@ + + + + + + + \ No newline at end of file diff --git a/features/device-mgt/io.entgra.device.mgt.core.device.mgt.basics.feature/src/main/resources/email/templates/default-jit-enrollment-invitation.vm b/features/device-mgt/io.entgra.device.mgt.core.device.mgt.basics.feature/src/main/resources/email/templates/default-jit-enrollment-invitation.vm new file mode 100644 index 0000000000..4487662397 --- /dev/null +++ b/features/device-mgt/io.entgra.device.mgt.core.device.mgt.basics.feature/src/main/resources/email/templates/default-jit-enrollment-invitation.vm @@ -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. +*# + + You have been invited to enroll your $device-type device in Entgra IoT + + + + Entgra IoT Server + + +
+
+
+
+ entgra +
+
+
+

+ Hi $username, +

+

+ You have been invited by $invite-by to enrol your $device-type device in Entgra IoT Server. + Click here to begin device + enrolment.

+ +

+ Should you need assistance, please contact your administrator. +

+ +

+ Regards, +

+

+ Entgra IoT Administrator +

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