Merge branch 'uninstall' into 'master'

Uninstall applications via Apps Tab - (For Android devices only)

See merge request entgra/carbon-device-mgt!700
revert-70ac1926
Dharmakeerthi Lasantha 4 years ago
commit d627bfc6c3

@ -65,6 +65,15 @@ public interface SubscriptionManager {
*/
List<ScheduledSubscriptionDTO> cleanScheduledSubscriptions() throws SubscriptionManagementException;
/**
* Check app is subscribed in entgra store or not
*
* @param id id of the device
* @param packageName package name of the application
* @throws SubscriptionManagementException if error occurred while cleaning up subscriptions.
*/
String checkAppSubscription(int id, String packageName) throws SubscriptionManagementException;
/**
* Retrieves the subscription entry which is pending by task name. At a given time, there should be only a single
* entry in the status {@code PENDING} and not marked as deleted.

@ -21,6 +21,7 @@ import org.wso2.carbon.device.application.mgt.common.ExecutionStatus;
import org.wso2.carbon.device.application.mgt.common.dto.ApplicationReleaseDTO;
import org.wso2.carbon.device.application.mgt.common.dto.DeviceSubscriptionDTO;
import org.wso2.carbon.device.application.mgt.common.dto.ScheduledSubscriptionDTO;
import org.wso2.carbon.device.application.mgt.common.exception.SubscriptionManagementException;
import org.wso2.carbon.device.application.mgt.core.exception.ApplicationManagementDAOException;
import java.time.LocalDateTime;
@ -154,6 +155,16 @@ public interface SubscriptionDAO {
List<ScheduledSubscriptionDTO> getScheduledSubscriptionByStatus(ExecutionStatus status, boolean deleted)
throws ApplicationManagementDAOException;
/**
* Gets the UUID of an application if the app is subscribed in entgra store
*
* @param id id of the device
* @param packageName package name of the application
* @throws SubscriptionManagementException if error
* occurred while cleaning up subscriptions.
*/
String getUUID(int id, String packageName) throws ApplicationManagementDAOException;
/**
* Retrieves a list of subscriptions that are not executed on the scheduled time.
*

@ -930,6 +930,42 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
}
}
@Override
public String getUUID(int id, String packageName) throws ApplicationManagementDAOException {
try {
Connection conn = this.getDBConnection();
String sql = "SELECT " +
"AP_APP_RELEASE.UUID " +
"FROM AP_DEVICE_SUBSCRIPTION " +
"JOIN AP_APP_RELEASE " +
"ON " +
"AP_DEVICE_SUBSCRIPTION.AP_APP_RELEASE_ID = AP_APP_RELEASE.AP_APP_ID " +
"WHERE PACKAGE_NAME = ? " +
"AND DM_DEVICE_ID = ?" +
"AND UNSUBSCRIBED = 'FALSE' " +
"AND STATUS = 'COMPLETED';";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, packageName);
stmt.setInt(2, id);
try (ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
return rs.getString("UUID");
}
return null;
}
}
} catch (DBConnectionException e) {
String msg =
"Error occurred while obtaining the DB connection to check an application is subscribed ";
log.error(msg, e);
throw new ApplicationManagementDAOException(msg, e);
} catch (SQLException e) {
String msg = "Error occurred when processing SQL to check an application is subscribed";
log.error(msg, e);
throw new ApplicationManagementDAOException(msg, e);
}
}
@Override
public List<ScheduledSubscriptionDTO> getScheduledSubscriptionByStatus(ExecutionStatus status, boolean deleted)
throws ApplicationManagementDAOException {

@ -169,6 +169,26 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
}
}
@Override
public String checkAppSubscription(int id, String packageName) throws SubscriptionManagementException {
try {
ConnectionManagerUtil.openDBConnection();
return subscriptionDAO.getUUID(id, packageName);
} catch (ApplicationManagementDAOException e) {
String msg = "Error occurred while checking the application is " +
"subscribed one or not";
log.error(msg, e);
throw new SubscriptionManagementException(msg, e);
} catch (DBConnectionException e) {
String msg = "Error occurred while observing the database connection while checking the application is " +
"subscribed one or not";
log.error(msg, e);
throw new SubscriptionManagementException(msg, e);
} finally {
ConnectionManagerUtil.closeDBConnection();
}
}
@Override
public List<ScheduledSubscriptionDTO> cleanScheduledSubscriptions() throws SubscriptionManagementException {
try {

@ -176,6 +176,10 @@
<Name>Install App</Name>
<Description>Install App</Description>
</Feature>
<Feature code="UNMANAGED_APP_UNINSTALL">
<Name>Uninstall App</Name>
<Description>Uninstall user installed App</Description>
</Feature>
<Feature code="UNINSTALL_APPLICATION">
<Name>Uninstall App</Name>
<Description>Uninstall App</Description>

@ -180,6 +180,10 @@
<Name>Uninstall App</Name>
<Description>Uninstall App</Description>
</Feature>
<Feature code="UNMANAGED_APP_UNINSTALL">
<Name>Uninstall App</Name>
<Description>Uninstall user installed App</Description>
</Feature>
<Feature code="BLACKLIST_APPLICATIONS">
<Name>Blacklist app</Name>
<Description>Blacklist applications</Description>

@ -423,5 +423,15 @@
<version>${carbon.identity.framework.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.application.mgt.common</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.application.mgt.core</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

@ -0,0 +1,67 @@
/*
* Copyright (c) 2020, 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 org.wso2.carbon.device.mgt.jaxrs.beans;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
/**
* This class represents the information of uninstall application operation.
*/
@ApiModel(value = "ApplicationUninstallation",
description = "This class carries all information related to application uninstallation.")
public class ApplicationUninstallation {
@ApiModelProperty(name = "appIdentifier", value = "The package name of the application to be uninstalled.", required = true)
@Size(min = 2, max = 45)
@Pattern(regexp = "^[A-Za-z0-9]*$")
String appIdentifier;
@ApiModelProperty(name = "type", value = "The type of the application. The following types of applications " +
"are supported: enterprise, public", required = true)
@Size(min = 2, max = 12)
@Pattern(regexp = "^[A-Za-z]*$")
String type;
public ApplicationUninstallation() {
}
public ApplicationUninstallation(String appIdentifier, String type) {
this.appIdentifier = appIdentifier;
this.type = type;
}
public String getAppIdentifier() {
return appIdentifier;
}
public void setAppIdentifier(String appIdentifier) {
this.appIdentifier = appIdentifier;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}

@ -1480,6 +1480,48 @@ public interface DeviceManagementService {
int limit);
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Path("/{type}/{id}/uninstallation")
@ApiOperation(
consumes = MediaType.APPLICATION_JSON,
produces = MediaType.APPLICATION_JSON,
httpMethod = "POST",
value = "Uninstall apps in device using apps tab",
notes = "Check app is subscribed in store or not and then do uninstallation accordingly",
tags = "Device Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:applications")
})
})
@ApiResponses(
value = {
})
Response uninstallation(
@ApiParam(
name = "type",
value = "The device type name, such as ios, android, windows",
required = true)
@PathParam("type")
@Size(max = 45)
String type,
@ApiParam(
name = "id",
value = "The device identifier of the device.",
required = true)
@PathParam("id")
@Size(max = 45)
String id,
@ApiParam(
name = "packageName",
value = "The package name of the app user want to uninstall",
required = true)
@QueryParam("packageName")
String packageName);
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/{type}/{id}/operations")

@ -36,21 +36,29 @@
package org.wso2.carbon.device.mgt.jaxrs.service.impl;
import com.google.gson.Gson;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.PaginationResult;
import org.wso2.carbon.device.application.mgt.common.ApplicationInstallResponse;
import org.wso2.carbon.device.application.mgt.common.SubscriptionType;
import org.wso2.carbon.device.application.mgt.common.exception.SubscriptionManagementException;
import org.wso2.carbon.device.application.mgt.common.services.SubscriptionManager;
import org.wso2.carbon.device.application.mgt.core.util.HelperUtil;
import org.wso2.carbon.device.mgt.common.DeviceFilters;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
import org.wso2.carbon.device.mgt.common.OperationLogFilters;
import org.wso2.carbon.device.mgt.common.MDMAppConstants;
import org.wso2.carbon.device.mgt.common.DeviceManagementConstants;
import org.wso2.carbon.device.mgt.common.Feature;
import org.wso2.carbon.device.mgt.common.FeatureManager;
import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.OperationLogFilters;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
import org.wso2.carbon.device.mgt.common.DeviceFilters;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.PaginationResult;
import org.wso2.carbon.device.mgt.common.app.mgt.Application;
import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManagementException;
import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationException;
@ -88,17 +96,19 @@ import org.wso2.carbon.device.mgt.core.search.mgt.SearchMgtException;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.device.mgt.core.service.GroupManagementProviderService;
import org.wso2.carbon.device.mgt.core.util.DeviceManagerUtil;
import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceCompliance;
import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceList;
import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse;
import org.wso2.carbon.device.mgt.jaxrs.beans.OperationList;
import org.wso2.carbon.device.mgt.jaxrs.beans.OperationRequest;
import org.wso2.carbon.device.mgt.jaxrs.beans.ComplianceDeviceList;
import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceCompliance;
import org.wso2.carbon.device.mgt.jaxrs.beans.ApplicationList;
import org.wso2.carbon.device.mgt.jaxrs.beans.OperationStatusBean;
import org.wso2.carbon.device.mgt.jaxrs.beans.ComplianceDeviceList;
import org.wso2.carbon.device.mgt.jaxrs.beans.OperationRequest;
import org.wso2.carbon.device.mgt.jaxrs.beans.OperationList;
import org.wso2.carbon.device.mgt.jaxrs.beans.ApplicationUninstallation;
import org.wso2.carbon.device.mgt.jaxrs.service.api.DeviceManagementService;
import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.InputValidationException;
import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.RequestValidationUtil;
import org.wso2.carbon.device.mgt.jaxrs.util.Constants;
import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils;
import org.wso2.carbon.identity.jwt.client.extension.JWTClient;
import org.wso2.carbon.identity.jwt.client.extension.dto.AccessTokenInfo;
@ -877,6 +887,82 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
}
}
@POST
@Path("/{type}/{id}/uninstallation")
@Override
public Response uninstallation(
@PathParam("type") @Size(max = 45) String type,
@PathParam("id") @Size(max = 45) String id,
@QueryParam("packageName") String packageName) {
List<DeviceIdentifier> deviceIdentifiers = new ArrayList<>();
Operation operation = new Operation();
try {
RequestValidationUtil.validateDeviceIdentifier(type, id);
Device device = DeviceMgtAPIUtils.getDeviceManagementService().getDevice(id, false);
ApplicationManagementProviderService amc = DeviceMgtAPIUtils.getAppManagementService();
List<Application> applications = amc.getApplicationListForDevice(device);
//checking requested package names are valid or not
RequestValidationUtil.validateApplicationIdentifier(packageName, applications);
DeviceIdentifier deviceIdentifier = new DeviceIdentifier(device.getDeviceIdentifier(), device.getType());
deviceIdentifiers.add(deviceIdentifier);
SubscriptionManager subscriptionManager = DeviceMgtAPIUtils.getSubscriptionManager();
String UUID = subscriptionManager.checkAppSubscription(device.getId(), packageName);
// UUID is available means app is subscribed in the entgra store
if (UUID != null) {
ApplicationInstallResponse response = subscriptionManager
.performBulkAppOperation(UUID, deviceIdentifiers, SubscriptionType.DEVICE.toString(),
"uninstall");
return Response.status(Response.Status.OK).entity(response).build();
//if the applications not installed via entgra store
} else {
if (Constants.ANDROID.equals(type)) {
ApplicationUninstallation applicationUninstallation = new ApplicationUninstallation(packageName, "PUBLIC");
Gson gson = new Gson();
operation.setCode(MDMAppConstants.AndroidConstants.UNMANAGED_APP_UNINSTALL);
operation.setType(Operation.Type.PROFILE);
operation.setPayLoad(gson.toJson(applicationUninstallation));
DeviceManagementProviderService deviceManagementProviderService = HelperUtil
.getDeviceManagementProviderService();
Activity activity = deviceManagementProviderService.addOperation(
DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID, operation, deviceIdentifiers);
return Response.status(Response.Status.CREATED).entity(activity).build();
} else {
String msg = "Not implemented for other device types";
log.error(msg);
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
}
}
} catch (DeviceManagementException e) {
String msg = "Error occurred while getting '" + type + "' device, which carries " +
"the id '" + id + "'";
log.error(msg, e);
return Response.serverError().entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
} catch (SubscriptionManagementException |
org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException
e) {
String msg = "Error occurred while getting the " + type + "application is of device " + id + "subscribed " +
"at entgra store";
log.error(msg, e);
return Response.serverError().entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
} catch (ApplicationManagementException e) {
String msg = "Error occurred while fetching the apps of the '" + type + "' device, which carries " +
"the id '" + id + "'";
log.error(msg, e);
return Response.serverError().entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
} catch (OperationManagementException e) {
String msg = "Issue in retrieving operation management service instance";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
} catch (InvalidDeviceException e) {
String msg = "The list of device identifiers are invalid";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
@GET
@Path("/{type}/{id}/operations")
@Override

@ -26,6 +26,7 @@ import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.Feature;
import org.wso2.carbon.device.mgt.common.FeatureManager;
import org.wso2.carbon.device.mgt.common.OperationLogFilters;
import org.wso2.carbon.device.mgt.common.app.mgt.Application;
import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceTypeNotFoundException;
@ -42,16 +43,11 @@ import org.wso2.carbon.device.mgt.jaxrs.beans.PolicyWrapper;
import org.wso2.carbon.device.mgt.jaxrs.beans.ProfileFeature;
import org.wso2.carbon.device.mgt.jaxrs.beans.RoleInfo;
import org.wso2.carbon.device.mgt.jaxrs.beans.Scope;
import org.wso2.carbon.device.mgt.jaxrs.service.api.DeviceTypeManagementService;
import org.wso2.carbon.device.mgt.jaxrs.util.Constants;
import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils;
import org.wso2.carbon.policy.mgt.common.PolicyPayloadValidator;
import javax.ws.rs.core.Response;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.ArrayList;
import java.util.Calendar;
@ -125,6 +121,26 @@ public class RequestValidationUtil {
}
}
/**
* validating the package name requested by user
*
* @param applications All the applications in the device
* @param packageName Package name sen by the user
*/
public static void validateApplicationIdentifier(String packageName, List<Application> applications) {
List<String> packageNames = new ArrayList<>();
for (Application application : applications) {
packageNames.add(application.getApplicationIdentifier());
}
if (!packageNames.contains(packageName)) {
String msg = "Invalid package name";
log.error(msg);
throw new InputValidationException(new ErrorResponse.ErrorResponseBuilder()
.setCode(HttpStatus.SC_BAD_REQUEST)
.setMessage(msg).build());
}
}
public static void validateStatus(List<String> statusList) {
for (String status : statusList) {
switch (status) {

@ -52,6 +52,7 @@ import org.wso2.carbon.analytics.api.AnalyticsDataAPI;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.core.util.Utils;
import org.wso2.carbon.device.application.mgt.common.services.SubscriptionManager;
import org.wso2.carbon.device.mgt.analytics.data.publisher.service.EventsPublisherService;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.Device;
@ -174,6 +175,8 @@ public class DeviceMgtAPIUtils {
private static MetadataManagementService metadataManagementService;
private static OTPManagementService otpManagementService;
private static volatile SubscriptionManager subscriptionManager;
static {
String keyStorePassword = ServerConfiguration.getInstance().getFirstProperty("Security.KeyStore.Password");
String trustStorePassword = ServerConfiguration.getInstance().getFirstProperty(
@ -216,6 +219,25 @@ public class DeviceMgtAPIUtils {
return 0;
}
public static SubscriptionManager getSubscriptionManager() {
if (subscriptionManager == null) {
synchronized (DeviceMgtAPIUtils.class) {
if (subscriptionManager == null) {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
subscriptionManager =
(SubscriptionManager) ctx.getOSGiService(SubscriptionManager.class, null);
if (subscriptionManager == null) {
String msg = "Subscription Manager service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
}
}
}
return subscriptionManager;
}
public static void scheduleTaskService(int notifierFrequency) {
TaskScheduleService taskScheduleService;
try {

@ -47,6 +47,7 @@ public class MDMAppConstants {
}
public static final String OPCODE_INSTALL_APPLICATION = "INSTALL_APPLICATION";
public static final String OPCODE_UNINSTALL_APPLICATION = "UNINSTALL_APPLICATION";
public static final String UNMANAGED_APP_UNINSTALL= "UNMANAGED_APP_UNINSTALL";
}
public class WindowsConstants {

@ -407,6 +407,10 @@
<Name>Uninstall App</Name>
<Description>Uninstall App</Description>
</Feature>
<Feature type="operation" code="UNMANAGED_APP_UNINSTALL">
<Name>Uninstall App</Name>
<Description>Uninstall user installed App</Description>
</Feature>
<Feature type="policy" code="BLACKLIST_APPLICATIONS">
<Name>Blacklist app</Name>
<Description>Blacklist applications</Description>

Loading…
Cancel
Save