diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/device/mgt/mobile/android/api/AndroidEnterpriseAPI.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/device/mgt/mobile/android/api/AndroidEnterpriseAPI.java index 3ffd40654..19ad49afb 100644 --- a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/device/mgt/mobile/android/api/AndroidEnterpriseAPI.java +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/device/mgt/mobile/android/api/AndroidEnterpriseAPI.java @@ -1322,59 +1322,56 @@ public interface AndroidEnterpriseAPI { //###################################################################################################################### //###################################################################################################################### - @PUT - @Path("/unenroll") + @GET + @Path("/wipe-device") @ApiOperation( produces = MediaType.APPLICATION_JSON, - consumes = MediaType.APPLICATION_JSON, - httpMethod = "PUT", - value = "Unenroll an enterprise from EMM", - notes = "Unenroll an enterprise from EMM.", - tags = "Android Enterprise Service", + httpMethod = "GET", + value = "Getting managed configs", + notes = "Getting managed configs.", + tags = "Device Type Management Administrative Service", extensions = { @Extension(properties = { @ExtensionProperty(name = AndroidConstants.SCOPE, value = "perm:enterprise:modify") }) } ) - @ApiResponses( - value = { - @ApiResponse(code = 201, message = "Created. \n Successfully removed", - responseHeaders = { - @ResponseHeader( - name = "Content-Location", - description = "The URL of the added policy."), - @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 = 303, - message = "See Other. \n The source can be retrieved from the URL specified in the location header.", - responseHeaders = { - @ResponseHeader( - name = "Content-Location", - description = "The Source URL of the document.")}), - @ApiResponse( - code = 400, - message = "Bad Request. \n Invalid request or validation error."), - @ApiResponse( - code = 415, - message = "Unsupported media type. \n The format of the requested entity was not supported."), - @ApiResponse( - code = 500, - message = "Internal Server Error. \n " + - "Server error occurred while unenrolling.") - }) - - Response unenroll(); + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Created. \n Successfully fetched managed configs", + responseHeaders = { + @ResponseHeader( + name = "Content-Location", + description = "The URL of the added policy."), + @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 = 303, + message = "See Other. \n The source can be retrieved from the URL specified in the location header.", + responseHeaders = { + @ResponseHeader( + name = "Content-Location", + description = "The Source URL of the document.")}), + @ApiResponse( + code = 400, + message = "Bad Request. \n Invalid request or validation error."), + @ApiResponse( + code = 415, + message = "Unsupported media type. \n The format of the requested entity was not supported."), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n " + + "Server error occurred while getting managed configs.") + }) + Response wipeEnterprise(); } diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/device/mgt/mobile/android/api/impl/AndroidEnterpriseAPIImpl.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/device/mgt/mobile/android/api/impl/AndroidEnterpriseAPIImpl.java index e4b541506..1ea0effe3 100644 --- a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/device/mgt/mobile/android/api/impl/AndroidEnterpriseAPIImpl.java +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/device/mgt/mobile/android/api/impl/AndroidEnterpriseAPIImpl.java @@ -30,8 +30,16 @@ import org.wso2.carbon.device.application.mgt.common.dto.ApplicationPolicyDTO; import org.wso2.carbon.device.application.mgt.common.dto.ApplicationReleaseDTO; import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException; import org.wso2.carbon.device.application.mgt.common.services.ApplicationManager; +import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; +import org.wso2.carbon.device.mgt.common.EnrolmentInfo; +import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.exceptions.InvalidDeviceException; +import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; +import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException; import org.wso2.carbon.device.mgt.common.policy.mgt.ProfileFeature; +import org.wso2.carbon.device.mgt.core.operation.mgt.CommandOperation; import org.wso2.carbon.device.mgt.mobile.android.api.AndroidEnterpriseAPI; import org.wso2.carbon.device.mgt.mobile.android.common.AndroidConstants; import org.wso2.carbon.device.mgt.mobile.android.common.GoogleAPIInvoker; @@ -795,28 +803,75 @@ public class AndroidEnterpriseAPIImpl implements AndroidEnterpriseAPI { } } - @PUT - @Path("/{id}/unenroll") @Override - public Response unenroll() { + @Produces(MediaType.APPLICATION_JSON) + @GET + @Path("/wipe-device") + public Response wipeEnterprise() { + log.warn("Wiping all devices!!!"); EnterpriseConfigs enterpriseConfigs = AndroidEnterpriseUtils.getEnterpriseConfigs(); - GoogleAPIInvoker googleAPIInvoker = new GoogleAPIInvoker(enterpriseConfigs.getEsa()); try { - googleAPIInvoker.unenroll(enterpriseConfigs.getEnterpriseId()); - } catch (IOException e) { - String errorMessage = "Could not unenroll the enterprise " + enterpriseConfigs.getEnterpriseId(); - log.error(errorMessage); - throw new NotFoundException( - new ErrorResponse.ErrorResponseBuilder().setCode(Response.Status.INTERNAL_SERVER_ERROR - .getStatusCode()).setMessage(errorMessage).build()); + // Take all enterprise devices in the DB. + List androidEnterpriseUsers = AndroidAPIUtils.getAndroidPluginService() + .getAllEnterpriseDevices(enterpriseConfigs.getEnterpriseId()); + + // Extract the device identifiers of enterprise devices. + List deviceID = new ArrayList<>(); + if (androidEnterpriseUsers != null && !androidEnterpriseUsers.isEmpty()) { + for (AndroidEnterpriseUser userDevice: androidEnterpriseUsers) { + deviceID.add(userDevice.getEmmDeviceId()); + } + } + + List byodDevices = new ArrayList<>(); + List copeDevices = new ArrayList<>(); + // Get all registered device + List devices = AndroidAPIUtils.getDeviceManagementService(). + getAllDevices(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID, false); + for (Device device : devices) { // Go through all enrolled devices + if (deviceID.contains(device.getDeviceIdentifier())) { // Filter out only enterprise enrolled devices. + if (device.getEnrolmentInfo().getOwnership().equals(EnrolmentInfo.OwnerShip.BYOD)) { + byodDevices.add(device.getDeviceIdentifier()); + } else { + copeDevices.add(device.getDeviceIdentifier()); + } + } + } + + CommandOperation operation = new CommandOperation(); + operation.setType(Operation.Type.COMMAND);//TODO: Check if this should be profile + // type when implementing COPE/COSU + if (byodDevices != null && !byodDevices.isEmpty()) { // BYOD devices only needs a data wipe(work profile) + log.warn("Wiping " + byodDevices.size() + " BYOD devices"); + operation.setCode(AndroidConstants.OperationCodes.ENTERPRISE_WIPE); + } else if (copeDevices != null && !copeDevices.isEmpty()) { + log.warn("Wiping " + copeDevices.size() + " COPE/COSU devices"); + operation.setCode(AndroidConstants.OperationCodes.WIPE_DATA); + } + AndroidDeviceUtils.getOperationResponse(deviceID, operation); + log.warn("Added wipe to all devices"); + return Response.status(Response.Status.OK).build(); } catch (EnterpriseServiceException e) { - String errorMessage = "Could not get client to call Google to unenroll enterprise " + enterpriseConfigs.getEnterpriseId(); + return Response.serverError().entity( + new ErrorResponse.ErrorResponseBuilder().setMessage("Error when saving configs").build()).build(); + } catch (OperationManagementException e) { + String errorMessage = "Could not add wipe command to enterprise " + enterpriseConfigs.getEnterpriseId(); log.error(errorMessage); - throw new NotFoundException( - new ErrorResponse.ErrorResponseBuilder().setCode(Response.Status.INTERNAL_SERVER_ERROR - .getStatusCode()).setMessage(errorMessage).build()); + return Response.serverError().entity( + new ErrorResponse.ErrorResponseBuilder().setMessage(errorMessage).build()).build(); + } catch (DeviceManagementException e) { + String errorMessage = "Could not add wipe command to enterprise " + enterpriseConfigs.getEnterpriseId() + + " due to an error in device management"; + log.error(errorMessage); + return Response.serverError().entity( + new ErrorResponse.ErrorResponseBuilder().setMessage(errorMessage).build()).build(); + } catch (InvalidDeviceException e) { + String errorMessage = "Could not add wipe command to enterprise due to invalid device ids"; + log.error(errorMessage); + return Response.serverError().entity( + new ErrorResponse.ErrorResponseBuilder().setMessage(errorMessage).build()).build(); } - return Response.status(Response.Status.OK).build(); + } } diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.common/src/main/java/org/wso2/carbon/device/mgt/mobile/android/common/spi/AndroidGoogleEnterpriseService.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.common/src/main/java/org/wso2/carbon/device/mgt/mobile/android/common/spi/AndroidGoogleEnterpriseService.java index a10fc418e..d964ab6bd 100644 --- a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.common/src/main/java/org/wso2/carbon/device/mgt/mobile/android/common/spi/AndroidGoogleEnterpriseService.java +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.common/src/main/java/org/wso2/carbon/device/mgt/mobile/android/common/spi/AndroidGoogleEnterpriseService.java @@ -39,4 +39,7 @@ public interface AndroidGoogleEnterpriseService { boolean updateMobileDevice(AndroidEnterpriseManagedConfig managedConfig) throws EnterpriseServiceException; boolean deleteMobileDevice(String id) throws EnterpriseServiceException; + + List getAllEnterpriseDevices(String enterpriseId) + throws EnterpriseServiceException ; } diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.core/src/main/java/org/wso2/carbon/device/mgt/mobile/android/core/dao/EnterpriseDAO.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.core/src/main/java/org/wso2/carbon/device/mgt/mobile/android/core/dao/EnterpriseDAO.java index 79c91e3e5..931f184f8 100644 --- a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.core/src/main/java/org/wso2/carbon/device/mgt/mobile/android/core/dao/EnterpriseDAO.java +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.core/src/main/java/org/wso2/carbon/device/mgt/mobile/android/core/dao/EnterpriseDAO.java @@ -50,4 +50,7 @@ public interface EnterpriseDAO { boolean updateConfig(AndroidEnterpriseManagedConfig managedConfig) throws EnterpriseManagementDAOException; boolean deleteConfig(String id, int tenantId) throws EnterpriseManagementDAOException; + + List getAllEnterpriseDevices(int tenantId, String enterpriseId) throws + EnterpriseManagementDAOException; } diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.core/src/main/java/org/wso2/carbon/device/mgt/mobile/android/core/dao/impl/EnterpriseDAOImpl.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.core/src/main/java/org/wso2/carbon/device/mgt/mobile/android/core/dao/impl/EnterpriseDAOImpl.java index 0abfa811c..4e4f47e03 100644 --- a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.core/src/main/java/org/wso2/carbon/device/mgt/mobile/android/core/dao/impl/EnterpriseDAOImpl.java +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.core/src/main/java/org/wso2/carbon/device/mgt/mobile/android/core/dao/impl/EnterpriseDAOImpl.java @@ -286,4 +286,42 @@ public class EnterpriseDAOImpl implements EnterpriseDAO { return status; } + public List getAllEnterpriseDevices(int tenantId, String enterpriseId) + throws EnterpriseManagementDAOException { + Connection conn; + PreparedStatement stmt = null; + List enterpriseUsers = new ArrayList<>(); + ResultSet rs = null; + try { + conn = AndroidDAOFactory.getConnection(); + String selectDBQuery = + "SELECT * FROM AD_ENTERPRISE_USER_DEVICE WHERE ENTERPRISE_ID = ? AND TENANT_ID = ?"; + stmt = conn.prepareStatement(selectDBQuery); + stmt.setString(1, enterpriseId); + stmt.setInt(2, tenantId); + + rs = stmt.executeQuery(); + + while (rs.next()) { + AndroidEnterpriseUser enterpriseUser = new AndroidEnterpriseUser(); + enterpriseUser.setEmmUsername(rs.getString("EMM_USERNAME")); + enterpriseUser.setTenantId(rs.getInt("TENANT_ID")); + enterpriseUser.setLastUpdatedTime(rs.getString("LAST_UPDATED_TIMESTAMP")); + enterpriseUser.setAndroidPlayDeviceId(rs.getString("ANDROID_PLAY_DEVICE_ID")); + enterpriseUser.setEnterpriseId(rs.getString("ENTERPRISE_ID")); + enterpriseUser.setGoogleUserId(rs.getString("GOOGLE_USER_ID")); + enterpriseUser.setEmmDeviceId(rs.getString("EMM_DEVICE_ID")); + enterpriseUsers.add(enterpriseUser); + } + } catch (SQLException e) { + String msg = "Error occurred while fetching user of enterprise: '" + enterpriseId + "'"; + log.error(msg, e); + throw new EnterpriseManagementDAOException(msg, e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, rs); + AndroidDAOFactory.closeConnection(); + } + + return enterpriseUsers; + } } diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.core/src/main/java/org/wso2/carbon/device/mgt/mobile/android/core/impl/AndroidGoogleEnterpriseServiceImpl.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.core/src/main/java/org/wso2/carbon/device/mgt/mobile/android/core/impl/AndroidGoogleEnterpriseServiceImpl.java index 67d79b8f4..ae59c266c 100644 --- a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.core/src/main/java/org/wso2/carbon/device/mgt/mobile/android/core/impl/AndroidGoogleEnterpriseServiceImpl.java +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.core/src/main/java/org/wso2/carbon/device/mgt/mobile/android/core/impl/AndroidGoogleEnterpriseServiceImpl.java @@ -216,4 +216,30 @@ public class AndroidGoogleEnterpriseServiceImpl implements AndroidGoogleEnterpri } return status; } + + @Override + public List getAllEnterpriseDevices(String enterpriseId) + throws EnterpriseServiceException { + + List androidEnterpriseUsers; + if (log.isDebugEnabled()) { + log.debug("Calling get enterprise device service by enterprise identifier: " + enterpriseId); + } + try { + AndroidDAOFactory.openConnection(); + androidEnterpriseUsers = this.enterpriseDAO.getAllEnterpriseDevices(CarbonContext + .getThreadLocalCarbonContext() + .getTenantId(), enterpriseId); + + } catch (EnterpriseManagementDAOException e) { + String msg = "Error occurred while adding the user " + + CarbonContext.getThreadLocalCarbonContext().getUsername(); + log.error(msg, e); + throw new EnterpriseServiceException(msg, e); + } finally { + AndroidDAOFactory.closeConnection(); + } + return androidEnterpriseUsers; + } + } diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.core/src/main/java/org/wso2/carbon/device/mgt/mobile/android/core/util/AndroidDeviceUtils.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.core/src/main/java/org/wso2/carbon/device/mgt/mobile/android/core/util/AndroidDeviceUtils.java index 51edcb75d..035bfd2d2 100644 --- a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.core/src/main/java/org/wso2/carbon/device/mgt/mobile/android/core/util/AndroidDeviceUtils.java +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.core/src/main/java/org/wso2/carbon/device/mgt/mobile/android/core/util/AndroidDeviceUtils.java @@ -323,6 +323,7 @@ public class AndroidDeviceUtils { JsonArray appListArray = appListElement.getAsJsonArray(); // Find if there are Apps with Work profile configurations + boolean alreadySendToGoogle = false; for (JsonElement appElement : appListArray) { JsonElement googlePolicyPayload = appElement.getAsJsonObject(). get(AndroidConstants.ApplicationInstall.GOOGLE_POLICY_PAYLOAD); @@ -332,12 +333,16 @@ public class AndroidDeviceUtils { containsGoogleAppPolicy = true;// breaking out of outer for loop try { uuid = uuid.replace("\"", ""); - sendPayloadToGoogle(uuid, payload, deviceIdentifier); + if (alreadySendToGoogle) { + sendPayloadToGoogle(uuid, payload, deviceIdentifier, false); + } else { + sendPayloadToGoogle(uuid, payload, deviceIdentifier, true); + alreadySendToGoogle = true; + } } catch (org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException e) { String errorMessage = "App install failed for device " + deviceIdentifier.getId(); log.error(errorMessage, e); } - break; } } @@ -352,8 +357,8 @@ public class AndroidDeviceUtils { * @param payload policy profile * @param deviceIdentifier device to apply policy */ - private static void sendPayloadToGoogle(String uuid, String payload, DeviceIdentifier deviceIdentifier) - throws ApplicationManagementException { + private static void sendPayloadToGoogle(String uuid, String payload, DeviceIdentifier deviceIdentifier, + boolean requireSendingToGoogle) throws ApplicationManagementException { try { EnterpriseConfigs enterpriseConfigs = AndroidEnterpriseUtils.getEnterpriseConfigsFromGoogle(); if (enterpriseConfigs.getErrorResponse() == null) { @@ -369,12 +374,12 @@ public class AndroidDeviceUtils { for (EnterpriseApp enterpriseApp : enterpriseInstallPolicy.getApps()) { apps.add(enterpriseApp.getProductId()); } - googleAPIInvoker - .approveAppsForUser(enterpriseConfigs.getEnterpriseId(), userDetail.getGoogleUserId(), apps, - enterpriseInstallPolicy.getProductSetBehavior()); - googleAPIInvoker - .updateAppsForUser(enterpriseConfigs.getEnterpriseId(), userDetail.getGoogleUserId(), - AndroidEnterpriseUtils.convertToDeviceInstance(enterpriseInstallPolicy)); + if (requireSendingToGoogle) { + googleAPIInvoker.approveAppsForUser(enterpriseConfigs.getEnterpriseId(), userDetail + .getGoogleUserId(), apps, enterpriseInstallPolicy.getProductSetBehavior()); + googleAPIInvoker.updateAppsForUser(enterpriseConfigs.getEnterpriseId(), userDetail.getGoogleUserId(), + AndroidEnterpriseUtils.convertToDeviceInstance(enterpriseInstallPolicy)); + } AndroidEnterpriseUtils.getAppSubscriptionService().performEntAppSubscription(uuid, Arrays.asList(CarbonContext.getThreadLocalCarbonContext().getUsername()), SubscriptionType.USER.toString(), SubAction.INSTALL.toString(), false); @@ -697,15 +702,21 @@ public class AndroidDeviceUtils { StringEntity requestEntity = new StringEntity(payload.toString(), ContentType.APPLICATION_JSON); JsonArray appListArray = appListElement.getAsJsonArray(); for (JsonElement appElement : appListArray) { - uuid = appElement.getAsJsonObject(). - get(AndroidConstants.ApplicationInstall.ENROLLMENT_APP_INSTALL_UUID).getAsString(); - try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - HttpPost postRequest = new HttpPost(requestUrl.replace("{uuid}", uuid)); - postRequest.setHeader(AndroidConstants.ApplicationInstall.AUTHORIZATION, - AndroidConstants.ApplicationInstall.AUTHORIZATION_HEADER_VALUE + tokenInfo - .getAccessToken()); - postRequest.setEntity(requestEntity); - httpClient.execute(postRequest); + JsonElement googlePolicyPayload = appElement.getAsJsonObject(). + get(AndroidConstants.ApplicationInstall.GOOGLE_POLICY_PAYLOAD); + + if (googlePolicyPayload == null) { + uuid = appElement.getAsJsonObject(). + get(AndroidConstants.ApplicationInstall.ENROLLMENT_APP_INSTALL_UUID).getAsString(); + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + HttpPost postRequest = new HttpPost(requestUrl.replace("{uuid}", uuid)); + postRequest.setHeader(AndroidConstants.ApplicationInstall.AUTHORIZATION, + AndroidConstants.ApplicationInstall.AUTHORIZATION_HEADER_VALUE + tokenInfo + .getAccessToken()); + postRequest.setEntity(requestEntity); + httpClient.execute(postRequest); + } + } } } catch (UserStoreException e) {