Merge branch 'remoteConf' into 'master'

Add remote configuration feature to android device mgt plugin

See merge request entgra/carbon-device-mgt-plugins!37
merge-requests/41/head
Charitha Goonetilleke 6 years ago
commit db2f49274c

@ -0,0 +1,54 @@
/*
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* WSO2 Inc. 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.mdm.services.android.bean;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
/**
* This class represents the information of sending application config operation.
*/
@ApiModel(value = "ApplicationRestriction",
description = "Details related to application config passed to device.")
public class ApplicationRestriction extends AndroidOperation implements Serializable {
private static final long serialVersionUID = 1995401458L;
@ApiModelProperty(name = "appIdentifier", value = "The application identifier to be sent.", required = true)
private String appIdentifier;
@ApiModelProperty(name = "restrictionPayload", value = "The restriction payload to be sent.", required = true)
private String restrictionPayload;
public String getAppIdentifier() {
return appIdentifier;
}
public void setAppIdentifier(String appIdentifier) {
this.appIdentifier = appIdentifier;
}
public String getRestrictionPayload() {
return restrictionPayload;
}
public void setRestrictionPayload(String restrictionPayload) {
this.restrictionPayload = restrictionPayload;
}
}

@ -0,0 +1,55 @@
/*
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* WSO2 Inc. 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.mdm.services.android.bean.wrapper;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.wso2.carbon.mdm.services.android.bean.ApplicationRestriction;
import java.util.List;
/**
* This class is used to wrap the Notification bean with devices.
*/
@ApiModel(value = "ApplicationRestrictionBeanWrapper",
description = "Mapping between application restriction operation and device list to be applied.")
public class ApplicationRestrictionBeanWrapper {
@ApiModelProperty(name = "deviceIDs", value = "List of device Ids", required = true)
private List<String> deviceIDs;
@ApiModelProperty(name = "operation", value = "The information of application restriction operation",
required = true)
private ApplicationRestriction operation;
public List<String> getDeviceIDs() {
return deviceIDs;
}
public void setDeviceIDs(List<String> deviceIDs) {
this.deviceIDs = deviceIDs;
}
public ApplicationRestriction getOperation() {
return operation;
}
public void setOperation(ApplicationRestriction operation) {
this.operation = operation;
}
}

@ -245,6 +245,12 @@ import java.util.List;
description = "Transferring a file to android devices", description = "Transferring a file to android devices",
key = "perm:android:file-transfer", key = "perm:android:file-transfer",
permissions = {"/device-mgt/devices/owning-device/operations/android/file-transfer"} permissions = {"/device-mgt/devices/owning-device/operations/android/file-transfer"}
),
@Scope(
name = "Send app restrictions",
description = "Send app restrictions to an application in the device",
key = "perm:android:send-app-restrictions",
permissions = {"/device-mgt/devices/owning-device/operations/android/send-app-conf"}
) )
} }
) )
@ -1856,6 +1862,68 @@ public interface DeviceManagementAdminService {
value = "The properties to set the web clip.", value = "The properties to set the web clip.",
required = true) required = true)
WebClipBeanWrapper webClipBeanWrapper); WebClipBeanWrapper webClipBeanWrapper);
@POST
@Path("/send-app-conf")
@ApiOperation(
consumes = MediaType.APPLICATION_JSON,
httpMethod = "POST",
value = "Sending an app restrictions to Android Devices",
notes = "Send application restrictions to Android devices.",
response = Activity.class,
tags = "Android Device Management Administrative Service",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = AndroidConstants.SCOPE,
value = "perm:android:send-app-restrictions")
})
}
)
@ApiResponses(value = {
@ApiResponse(
code = 201,
message = "Created. \n Successfully sent the application configuration.",
response = Activity.class,
responseHeaders = {
@ResponseHeader(
name = "Content-Location",
description = "URL of the activity instance that refers to the scheduled operation."),
@ResponseHeader(
name = "Content-Type",
description = "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 adding a new send application config operation.")
})
Response sendApplicationConfiguration(
@ApiParam(
name = "notification",
value = "The properties required to send application restrictions. Provide the restriction you " +
"wish to send and the ID of the Android device. Multiple device IDs can be added by using" +
" comma separated values.",
required = true)
ApplicationRestrictionBeanWrapper applicationRestrictionBeanWrapper);
@POST @POST
@Path("/configure-global-proxy") @Path("/configure-global-proxy")

@ -37,7 +37,7 @@ package org.wso2.carbon.mdm.services.android.services.impl;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.json.JSONException; import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.InvalidDeviceException; import org.wso2.carbon.device.mgt.common.InvalidDeviceException;
import org.wso2.carbon.device.mgt.common.operation.mgt.Activity; 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.Operation;
@ -45,6 +45,7 @@ import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementExcept
import org.wso2.carbon.device.mgt.core.operation.mgt.CommandOperation; import org.wso2.carbon.device.mgt.core.operation.mgt.CommandOperation;
import org.wso2.carbon.device.mgt.core.operation.mgt.ProfileOperation; import org.wso2.carbon.device.mgt.core.operation.mgt.ProfileOperation;
import org.wso2.carbon.mdm.services.android.bean.ApplicationInstallation; import org.wso2.carbon.mdm.services.android.bean.ApplicationInstallation;
import org.wso2.carbon.mdm.services.android.bean.ApplicationRestriction;
import org.wso2.carbon.mdm.services.android.bean.ApplicationUninstallation; import org.wso2.carbon.mdm.services.android.bean.ApplicationUninstallation;
import org.wso2.carbon.mdm.services.android.bean.ApplicationUpdate; import org.wso2.carbon.mdm.services.android.bean.ApplicationUpdate;
import org.wso2.carbon.mdm.services.android.bean.BlacklistApplications; import org.wso2.carbon.mdm.services.android.bean.BlacklistApplications;
@ -63,6 +64,7 @@ import org.wso2.carbon.mdm.services.android.bean.WebClip;
import org.wso2.carbon.mdm.services.android.bean.Wifi; import org.wso2.carbon.mdm.services.android.bean.Wifi;
import org.wso2.carbon.mdm.services.android.bean.WipeData; import org.wso2.carbon.mdm.services.android.bean.WipeData;
import org.wso2.carbon.mdm.services.android.bean.wrapper.ApplicationInstallationBeanWrapper; import org.wso2.carbon.mdm.services.android.bean.wrapper.ApplicationInstallationBeanWrapper;
import org.wso2.carbon.mdm.services.android.bean.wrapper.ApplicationRestrictionBeanWrapper;
import org.wso2.carbon.mdm.services.android.bean.wrapper.ApplicationUninstallationBeanWrapper; import org.wso2.carbon.mdm.services.android.bean.wrapper.ApplicationUninstallationBeanWrapper;
import org.wso2.carbon.mdm.services.android.bean.wrapper.ApplicationUpdateBeanWrapper; import org.wso2.carbon.mdm.services.android.bean.wrapper.ApplicationUpdateBeanWrapper;
import org.wso2.carbon.mdm.services.android.bean.wrapper.BlacklistApplicationsBeanWrapper; import org.wso2.carbon.mdm.services.android.bean.wrapper.BlacklistApplicationsBeanWrapper;
@ -82,6 +84,7 @@ import org.wso2.carbon.mdm.services.android.bean.wrapper.WipeDataBeanWrapper;
import org.wso2.carbon.mdm.services.android.exception.BadRequestException; import org.wso2.carbon.mdm.services.android.exception.BadRequestException;
import org.wso2.carbon.mdm.services.android.exception.UnexpectedServerErrorException; import org.wso2.carbon.mdm.services.android.exception.UnexpectedServerErrorException;
import org.wso2.carbon.mdm.services.android.services.DeviceManagementAdminService; import org.wso2.carbon.mdm.services.android.services.DeviceManagementAdminService;
import org.wso2.carbon.mdm.services.android.util.AndroidAPIUtils;
import org.wso2.carbon.mdm.services.android.util.AndroidConstants; import org.wso2.carbon.mdm.services.android.util.AndroidConstants;
import org.wso2.carbon.mdm.services.android.util.AndroidDeviceUtils; import org.wso2.carbon.mdm.services.android.util.AndroidDeviceUtils;
@ -528,7 +531,8 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe
@POST @POST
@Path("/install-application") @Path("/install-application")
@Override @Override
public Response installApplication(ApplicationInstallationBeanWrapper applicationInstallationBeanWrapper) { public Response installApplication(
ApplicationInstallationBeanWrapper applicationInstallationBeanWrapper) {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Invoking 'InstallApplication' operation"); log.debug("Invoking 'InstallApplication' operation");
} }
@ -554,11 +558,6 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe
Activity activity = AndroidDeviceUtils Activity activity = AndroidDeviceUtils
.getOperationResponse(applicationInstallationBeanWrapper.getDeviceIDs(), operation); .getOperationResponse(applicationInstallationBeanWrapper.getDeviceIDs(), operation);
return Response.status(Response.Status.CREATED).entity(activity).build(); return Response.status(Response.Status.CREATED).entity(activity).build();
} catch (JSONException e) {
String errorMessage = "Invalid payload for the operation.";
log.error(errorMessage);
throw new BadRequestException(
new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(errorMessage).build());
} catch (InvalidDeviceException e) { } catch (InvalidDeviceException e) {
String errorMessage = "Invalid Device Identifiers found."; String errorMessage = "Invalid Device Identifiers found.";
log.error(errorMessage, e); log.error(errorMessage, e);
@ -616,7 +615,8 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe
@POST @POST
@Path("/uninstall-application") @Path("/uninstall-application")
@Override @Override
public Response uninstallApplication(ApplicationUninstallationBeanWrapper applicationUninstallationBeanWrapper) { public Response uninstallApplication(
ApplicationUninstallationBeanWrapper applicationUninstallationBeanWrapper) {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Invoking 'UninstallApplication' operation"); log.debug("Invoking 'UninstallApplication' operation");
} }
@ -1022,6 +1022,46 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe
new ErrorResponse.ErrorResponseBuilder().setCode(500L).setMessage(errorMessage).build()); new ErrorResponse.ErrorResponseBuilder().setCode(500L).setMessage(errorMessage).build());
} }
} }
@POST
@Path("/send-app-conf")
@Override
public Response sendApplicationConfiguration(
ApplicationRestrictionBeanWrapper applicationRestrictionBeanWrapper) {
if (log.isDebugEnabled()) {
log.debug("Invoking 'send application configuration' operation");
}
try {
if (applicationRestrictionBeanWrapper == null || applicationRestrictionBeanWrapper.getOperation() == null) {
String errorMessage = "The payload of the application configuration operation is incorrect";
log.error(errorMessage);
throw new BadRequestException(
new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(errorMessage).build());
}
ApplicationRestriction applicationRestriction = applicationRestrictionBeanWrapper.getOperation();
ProfileOperation operation = new ProfileOperation();
operation.setCode(AndroidConstants.OperationCodes.REMOTE_APP_CONFIG);
operation.setType(Operation.Type.PROFILE);
operation.setPayLoad(applicationRestriction.toJSON());
return (Response) AndroidAPIUtils.getOperationResponse(applicationRestrictionBeanWrapper.getDeviceIDs(),
operation);
} catch (InvalidDeviceException e) {
String errorMessage = "Invalid Device Identifiers found.";
log.error(errorMessage, e);
throw new BadRequestException(
new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(errorMessage).build());
} catch (OperationManagementException e) {
String errorMessage = "Issue in retrieving operation management service instance";
log.error(errorMessage, e);
throw new UnexpectedServerErrorException(
new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(errorMessage).build());
} catch (DeviceManagementException e) {
String errorMessage = "Issue in retrieving device management service instance";
log.error(errorMessage, e);
throw new UnexpectedServerErrorException(
new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(errorMessage).build());
}
}
private static void validateApplicationUrl(String apkUrl) { private static void validateApplicationUrl(String apkUrl) {
try { try {

@ -23,12 +23,26 @@ import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.analytics.api.AnalyticsDataAPI; import org.wso2.carbon.analytics.api.AnalyticsDataAPI;
import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.analytics.data.publisher.service.EventsPublisherService; 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.DeviceManagementConstants;
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.InvalidDeviceException;
import org.wso2.carbon.device.mgt.common.notification.mgt.NotificationManagementService; import org.wso2.carbon.device.mgt.common.notification.mgt.NotificationManagementService;
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.core.app.mgt.ApplicationManagementProviderService; import org.wso2.carbon.device.mgt.core.app.mgt.ApplicationManagementProviderService;
import org.wso2.carbon.device.mgt.core.device.details.mgt.DeviceInformationManager; import org.wso2.carbon.device.mgt.core.device.details.mgt.DeviceInformationManager;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.mdm.services.android.bean.ErrorResponse;
import org.wso2.carbon.mdm.services.android.exception.BadRequestException;
import org.wso2.carbon.policy.mgt.core.PolicyManagerService; import org.wso2.carbon.policy.mgt.core.PolicyManagerService;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.List;
/** /**
* AndroidAPIUtil class provides utility functions used by Android REST-API classes. * AndroidAPIUtil class provides utility functions used by Android REST-API classes.
*/ */
@ -135,4 +149,25 @@ public class AndroidAPIUtils {
return analyticsDataAPI; return analyticsDataAPI;
} }
public static Response getOperationResponse(List<String> deviceIDs, Operation operation)
throws DeviceManagementException, OperationManagementException, InvalidDeviceException {
if (deviceIDs == null || deviceIDs.size() == 0) {
String errorMessage = "Device identifier list is empty";
log.error(errorMessage);
throw new BadRequestException(
new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(errorMessage).build());
}
DeviceIdentifier deviceIdentifier;
List<DeviceIdentifier> deviceIdentifiers = new ArrayList<>();
for (String deviceId : deviceIDs) {
deviceIdentifier = new DeviceIdentifier();
deviceIdentifier.setId(deviceId);
deviceIdentifier.setType(AndroidConstants.DEVICE_TYPE_ANDROID);
deviceIdentifiers.add(deviceIdentifier);
}
Activity activity = getDeviceManagementService().addOperation(
DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID, operation, deviceIdentifiers);
return Response.status(Response.Status.CREATED).entity(activity).build();
}
} }

@ -140,6 +140,7 @@ public final class AndroidConstants {
public static final String WORK_PROFILE = "WORK_PROFILE"; public static final String WORK_PROFILE = "WORK_PROFILE";
public static final String NOTIFIER_FREQUENCY = "NOTIFIER_FREQUENCY"; public static final String NOTIFIER_FREQUENCY = "NOTIFIER_FREQUENCY";
public static final String GLOBAL_PROXY = "SET_GLOBAL_PROXY"; public static final String GLOBAL_PROXY = "SET_GLOBAL_PROXY";
public static final String REMOTE_APP_CONFIG = "REMOTE_APP_CONFIG";
} }
public final class StatusCodes { public final class StatusCodes {

@ -491,6 +491,15 @@ var generatePayload = function (operationCode, operationData, deviceList) {
} }
}; };
break; break;
case androidOperationConstants["APP_RESTRICTION_OPERATION_CODE"]:
operationType = operationTypeConstants["PROFILE"];
payload = {
"operation": {
"appIdentifier": operationData["app-id"],
"restrictionPayload": operationData["payload"]
}
};
break;
default: default:
// If the operation is neither of above, it is a command operation // If the operation is neither of above, it is a command operation
operationType = operationTypeConstants["COMMAND"]; operationType = operationTypeConstants["COMMAND"];
@ -554,5 +563,6 @@ var androidOperationConstants = {
"APPLICATION_OPERATION_CODE": "APP-RESTRICTION", "APPLICATION_OPERATION_CODE": "APP-RESTRICTION",
"SYSTEM_UPDATE_POLICY_CODE": "SYSTEM_UPDATE_POLICY", "SYSTEM_UPDATE_POLICY_CODE": "SYSTEM_UPDATE_POLICY",
"KIOSK_APPS_CODE": "KIOSK_APPS", "KIOSK_APPS_CODE": "KIOSK_APPS",
"FILE_TRANSFER": "FILE_TRANSFER" "FILE_TRANSFER": "FILE_TRANSFER",
"APP_RESTRICTION_OPERATION_CODE": "REMOTE_APP_CONFIG"
}; };

@ -36,7 +36,8 @@
"perm:android:unlock-devices", "perm:android:unlock-devices",
"perm:android:control-camera", "perm:android:control-camera",
"perm:android:reboot", "perm:android:reboot",
"perm:android:logcat" "perm:android:logcat",
"perm:android:send-app-restrictions"
], ],
"features": { "features": {
"DEVICE_RING": { "DEVICE_RING": {
@ -214,6 +215,24 @@
} }
], ],
"permission": "/device-mgt/devices/owning-device/operations/android/wipe" "permission": "/device-mgt/devices/owning-device/operations/android/wipe"
},
"REMOTE_APP_CONFIG": {
"icon": "fw-lock",
"formParams": [
{
"type": "text",
"id": "app-id",
"optional": false,
"label": "Application identifier"
},
{
"type": "text",
"id": "payload",
"optional": false,
"label": "Application restriction payload"
}
],
"permission": "/device-mgt/devices/owning-device/operations/android/send-app-conf"
} }
} }
} }

@ -347,6 +347,13 @@
<Name>Unlock the device</Name> <Name>Unlock the device</Name>
<Description>Unlock the device</Description> <Description>Unlock the device</Description>
</Feature> </Feature>
<Feature code="REMOTE_APP_CONFIG">
<Name>Send app restriction</Name>
<Description>Send remote configurations to app</Description>
<Operation context="/api/device-mgt/android/v1.0/admin/devices/send-app-conf" method="POST"
type="application/json">
</Operation>
</Feature>
</Features> </Features>
<TaskConfiguration> <TaskConfiguration>
<Enable>true</Enable> <Enable>true</Enable>

Loading…
Cancel
Save