diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/mdm/services/android/services/AndroidEnterpriseService.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/mdm/services/android/services/AndroidEnterpriseService.java index a76a57ada9..76a77febd2 100644 --- a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/mdm/services/android/services/AndroidEnterpriseService.java +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/mdm/services/android/services/AndroidEnterpriseService.java @@ -1332,64 +1332,60 @@ public interface AndroidEnterpriseService { name = "applicationPolicyDTO", value = "Enterprise managed conf.") ApplicationPolicyDTO applicationPolicyDTO); - //###################################################################################################################### //###################################################################################################################### //###################################################################################################################### - @PUT - @Path("/unenroll") + @GET + @Path("/wipe-enterprise") @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") + @ExtensionProperty(name = AndroidConstants.SCOPE, value = "perm:enterprise:view") }) } ) - @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/mdm/services/android/services/impl/AndroidEnterpriseServiceImpl.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/mdm/services/android/services/impl/AndroidEnterpriseServiceImpl.java index 26805efd7b..85ee941e68 100644 --- a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/mdm/services/android/services/impl/AndroidEnterpriseServiceImpl.java +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/mdm/services/android/services/impl/AndroidEnterpriseServiceImpl.java @@ -31,8 +31,17 @@ 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.Activity; +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.impl.EnterpriseServiceException; import org.wso2.carbon.device.mgt.mobile.android.impl.dto.AndroidEnterpriseManagedConfig; import org.wso2.carbon.device.mgt.mobile.android.impl.dto.AndroidEnterpriseUser; @@ -798,28 +807,73 @@ public class AndroidEnterpriseServiceImpl implements AndroidEnterpriseService { } } - @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.size() > 0) { + 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); + if (byodDevices != null && byodDevices.size() > 0) { // 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.size() > 0) { + log.warn("Wiping " + copeDevices.size() + " BYOD devices"); + operation.setCode(AndroidConstants.OperationCodes.ENTERPRISE_WIPE);//TODO: fix + } + 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.api/src/main/java/org/wso2/carbon/mdm/services/android/util/AndroidDeviceUtils.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/mdm/services/android/util/AndroidDeviceUtils.java index a66e3a07f9..4f43c332eb 100644 --- a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/mdm/services/android/util/AndroidDeviceUtils.java +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/mdm/services/android/util/AndroidDeviceUtils.java @@ -321,21 +321,27 @@ 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); + if (googlePolicyPayload != null) { String uuid = appElement.getAsJsonObject().get("uuid").toString(); 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; } } @@ -349,8 +355,10 @@ public class AndroidDeviceUtils { * Sends the app install policy to Google * @param payload policy profile * @param deviceIdentifier device to apply policy + * @param requireSendingToGoogle */ - private static void sendPayloadToGoogle(String uuid, String payload, DeviceIdentifier deviceIdentifier) + private static void sendPayloadToGoogle(String uuid, String payload, DeviceIdentifier deviceIdentifier, + boolean requireSendingToGoogle) throws org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException { try { EnterpriseConfigs enterpriseConfigs = AndroidEnterpriseUtils.getEnterpriseConfigsFromGoogle(); @@ -370,10 +378,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()), @@ -698,15 +708,20 @@ 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) { diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/AndroidPluginService.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/AndroidPluginService.java index 7bc4ad3be6..371eecaa90 100644 --- a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/AndroidPluginService.java +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/AndroidPluginService.java @@ -39,4 +39,7 @@ public interface AndroidPluginService { 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/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidPluginServiceImpl.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidPluginServiceImpl.java index 1fc0754f90..58d819f975 100644 --- a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidPluginServiceImpl.java +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidPluginServiceImpl.java @@ -215,4 +215,29 @@ public class AndroidPluginServiceImpl implements AndroidPluginService { } 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/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/EnterpriseDAO.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/EnterpriseDAO.java index 87aafb814d..284e64cf80 100644 --- a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/EnterpriseDAO.java +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/EnterpriseDAO.java @@ -49,4 +49,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/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/impl/EnterpriseDAOImpl.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/impl/EnterpriseDAOImpl.java index 8dbdb6e29a..9b767a6bca 100644 --- a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/impl/EnterpriseDAOImpl.java +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/impl/EnterpriseDAOImpl.java @@ -291,4 +291,44 @@ 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; + } + }