Merge branch 'application-mgt-new' into 'application-mgt-new'

Merge with upstream master

See merge request entgra/carbon-device-mgt-plugins!43
revert-dabc3590
Saad Sahibjan 6 years ago
commit 03cf82642a

@ -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 {

@ -21,6 +21,7 @@ package org.wso2.carbon.mdm.services.android.mocks;
import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.DeviceManagementException; import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.DeviceTypeNotFoundException;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo; import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
import org.wso2.carbon.device.mgt.common.FeatureManager; import org.wso2.carbon.device.mgt.common.FeatureManager;
import org.wso2.carbon.device.mgt.common.InvalidDeviceException; import org.wso2.carbon.device.mgt.common.InvalidDeviceException;
@ -289,7 +290,7 @@ public class DeviceManagementProviderServiceMock implements DeviceManagementProv
} }
@Override @Override
public FeatureManager getFeatureManager(String s) throws DeviceManagementException { public FeatureManager getFeatureManager(String s) throws DeviceTypeNotFoundException {
return null; return null;
} }

@ -418,7 +418,8 @@ var generatePayload = function (operationCode, operationData, deviceList) {
payload = { payload = {
"operation": { "operation": {
"type": operationData["type"], "type": operationData["type"],
"openvpn_config": operationData["openvpn_config"] "openvpn_config": operationData["openvpn_config"],
"packageName": operationData["packageName"]
} }
}; };
break; break;
@ -491,6 +492,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 +564,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"
}; };

@ -167,7 +167,8 @@ var androidOperationModule = function () {
case androidOperationConstants["VPN_OPERATION_CODE"]: case androidOperationConstants["VPN_OPERATION_CODE"]:
payload = { payload = {
"type": operationPayload["type"], "type": operationPayload["type"],
"openvpn_config": operationPayload["openvpn_config"] "openvpn_config": operationPayload["openvpn_config"],
"packageName": operationPayload["packageName"]
}; };
break; break;
case androidOperationConstants["APPLICATION_OPERATION_CODE"]: case androidOperationConstants["APPLICATION_OPERATION_CODE"]:
@ -425,7 +426,8 @@ var androidOperationModule = function () {
payload = { payload = {
"operation": { "operation": {
"type": operationData["type"], "type": operationData["type"],
"openvpn_config": operationData["openvpn_config"] "openvpn_config": operationData["openvpn_config"],
"packageName": operationData["packageName"]
} }
}; };
break; break;

@ -17,6 +17,11 @@
}} }}
<!-- android --> <!-- android -->
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading" role="tab">
<h2 class="sub-title panel-title">
Platform Configuration - Windows
</h2>
</div>
<div id="android-config-body" class="panel-collapse panel-body" role="tabpanel"> <div id="android-config-body" class="panel-collapse panel-body" role="tabpanel">
<div id="android-config-error-msg" class="alert alert-danger hidden" role="alert"> <div id="android-config-error-msg" class="alert alert-danger hidden" role="alert">
<i class="icon fw fw-error"></i><span></span> <i class="icon fw fw-error"></i><span></span>

@ -92,7 +92,7 @@ var kioskConfigs = {
$(document).ready(function () { $(document).ready(function () {
$("#fcm-inputs").hide(); $("#fcm-inputs").hide();
tinymce.init({ tinymce.init({
selector: "textarea", selector: "#android-eula",
height:500, height:500,
theme: "modern", theme: "modern",
plugins: [ plugins: [

@ -590,14 +590,34 @@ var validatePolicyProfile = function () {
// initializing continueToCheckNextInputs to true // initializing continueToCheckNextInputs to true
continueToCheckNextInputs = true; continueToCheckNextInputs = true;
var openvpnConfig = $("#openvpn-config").val(); let openVpnConfigEnabled = document.getElementById('vpn-body').classList.contains('in');
if (!openvpnConfig || openvpnConfig === '') { if (openVpnConfigEnabled) {
validationStatus = { var openvpnConfig = $("textarea#openvpn-config").val();
"error": true, if (!openvpnConfig || openvpnConfig === '') {
"subErrorMsg": "ovpn config required. You cannot proceed.", validationStatus = {
"erroneousFeature": operation "error": true,
}; "subErrorMsg": "ovpn config file is required. You cannot proceed.",
continueToCheckNextInputs = false; "erroneousFeature": operation
};
continueToCheckNextInputs = false;
}
}
if (validationStatus) {
validationStatusArray.push(validationStatus);
}
let alwaysOnVpnEnabled = document.getElementById('always-on-vpn-body').classList.contains('in');
if (alwaysOnVpnEnabled) {
var alwaysOnConfig = $("input#vpn-client-app").val();
if (!alwaysOnConfig || alwaysOnConfig === '') {
validationStatus = {
"error": true,
"subErrorMsg": "Add a valid package name for the VPN client",
"erroneousFeature": "always-on-vpn"
};
continueToCheckNextInputs = false;
}
} }
// at-last, if the value of continueToCheckNextInputs is still true // at-last, if the value of continueToCheckNextInputs is still true

@ -1246,6 +1246,62 @@
<input id="vpn-type" class="form-control operationDataKeys" type="hidden" data-key="type" value="OpenVPN" /> <input id="vpn-type" class="form-control operationDataKeys" type="hidden" data-key="type" value="OpenVPN" />
</div> </div>
</div> </div>
<!-- Always on VPN connection settings -->
<div id="always-on-vpn-heading" class="panel-heading" role="tab">
<h2 class="sub-title panel-title">
Always On VPN Settings
<label class="wr-input-control switch" data-toggle="collapse" data-target="#always-on-vpn-body">
<input type="checkbox"/>
<span class="helper"></span>
<span class="text"></span>
</label>
</h2>
<div class="panel-title-description">
Configure an always-on VPN connection through a specific VPN client application
</div>
</div>
<div id="always-on-vpn-body" class="panel-collapse panel-body collapse" role="tabpanel"
aria-labelledby="vpn-body">
<hr/>
<div class="always-on-vpn-message">
<ul class="message message-info">
<i class="icon fw fw-info"></i>
<a id="always-on-vpn-status-msg"> Below configurations are valid only when the Agent is
<b>work-profile owner</b> or <b>device owner</b>.</a>
</ul>
</div>
<br/>
<div class="wr-input-control">
<label class="wr-input-label" for="vpn-client-app">
VPN Client Application Package Name*
<span class="helper" title="Package name of the VPN client application to be configured.">
<span class="wr-help-tip glyphicon glyphicon-question-sign"></span>
</span>
</label>
<input id="vpn-client-app" type="text" class="form-control operationDataKeys"
data-key="packageName" maxlength="200" placeholder="[ Should be a valid package name ]"/>
</div>
<!--<div class="wr-input-control">-->
<!--<label class="wr-input-control checkbox">-->
<!--<input id="vpn-lock-down" type="checkbox" class="operationDataKeys"-->
<!--data-key="lockDownEnable" checked="checked"/>-->
<!--<span class="helper"-->
<!--title="True to disallow networking when the VPN is not connected or false otherwise">-->
<!--Lock Down VPN-->
<!--<span class="wr-help-tip glyphicon glyphicon-question-sign"></span>-->
<!--</span>-->
<!--</label>-->
<!--</div>-->
</div>
<!-- Always on VPN connection settings -->
</div> </div>
</div> </div>
<!-- /VPN --> <!-- /VPN -->

@ -2142,6 +2142,62 @@
data-key="openvpn_config" style="height: 400px;" disabled></textarea> data-key="openvpn_config" style="height: 400px;" disabled></textarea>
</div> </div>
</div> </div>
<!-- Always on VPN connection settings -->
<div id="always-on-vpn-heading" class="panel-heading" role="tab">
<h2 class="sub-title panel-title">
Always On VPN Settings
<label class="wr-input-control switch" data-toggle="collapse" data-target="#always-on-vpn-body">
<input type="checkbox"/>
<span class="helper"></span>
<span class="text"></span>
</label>
</h2>
<div class="panel-title-description">
Configure an always-on VPN connection through a specific VPN client application
</div>
</div>
<div id="always-on-vpn-body" class="panel-collapse panel-body collapse" role="tabpanel"
aria-labelledby="vpn-body">
<hr/>
<div class="always-on-vpn-message">
<ul class="message message-info">
<i class="icon fw fw-info"></i>
<a id="always-on-vpn-status-msg"> Below configurations are valid only when the Agent is
<b>work-profile owner</b> or <b>device owner</b>.</a>
</ul>
</div>
<br/>
<div class="wr-input-control">
<label class="wr-input-label" for="vpn-client-app">
VPN Client Application Package Name
<span class="helper" title="Package name of the VPN client application to be configured.">
<span class="wr-help-tip glyphicon glyphicon-question-sign"></span>
</span>
</label>
<input id="vpn-client-app" type="text" class="form-control operationDataKeys"
data-key="packageName" maxlength="200" placeholder="[ Should be a valid package name ]"/>
</div>
<!--<div class="wr-input-control">-->
<!--<label class="wr-input-control checkbox">-->
<!--<input id="vpn-lock-down" type="checkbox" class="operationDataKeys"-->
<!--data-key="lockDownEnable" checked="checked"/>-->
<!--<span class="helper"-->
<!--title="True to disallow networking when the VPN is not connected or false otherwise">-->
<!--Lock Down VPN-->
<!--<span class="wr-help-tip glyphicon glyphicon-question-sign"></span>-->
<!--</span>-->
<!--</label>-->
<!--</div>-->
</div>
<!-- Always on VPN connection settings -->
</div> </div>
</div> </div>
<!-- /VPN --> <!-- /VPN -->

@ -524,17 +524,35 @@ var validatePolicyProfile = function () {
operation = androidOperationConstants["VPN_OPERATION"]; operation = androidOperationConstants["VPN_OPERATION"];
// initializing continueToCheckNextInputs to true // initializing continueToCheckNextInputs to true
continueToCheckNextInputs = true; continueToCheckNextInputs = true;
let openVpnConfigEnabled = document.getElementById('vpn-body').classList.contains('in');
if (openVpnConfigEnabled) {
var openvpnConfig = $("input#openvpn-config").val();
if (!openvpnConfig || openvpnConfig === '') {
validationStatus = {
"error": true,
"subErrorMsg": "ovpn config file is required. You cannot proceed.",
"erroneousFeature": operation
};
continueToCheckNextInputs = false;
}
}
var openvpnConfig = $("input#openvpn-config").val(); if (validationStatus) {
if (!openvpnConfig || openvpnConfig === '') { validationStatusArray.push(validationStatus);
validationStatus = {
"error": true,
"subErrorMsg": "ovpn config file is required. You cannot proceed.",
"erroneousFeature": operation
};
continueToCheckNextInputs = false;
} }
let alwaysOnVpnEnabled = document.getElementById('always-on-vpn-body').classList.contains('in');
if (alwaysOnVpnEnabled) {
var alwaysOnConfig = $("input#vpn-client-app").val();
if (!alwaysOnConfig || alwaysOnConfig === '') {
validationStatus = {
"error": true,
"subErrorMsg": "Add a valid package name for the VPN client",
"erroneousFeature": "always-on-vpn"
};
continueToCheckNextInputs = false;
}
}
// at-last, if the value of continueToCheckNextInputs is still true // at-last, if the value of continueToCheckNextInputs is still true
// this means that no error is found // this means that no error is found
if (continueToCheckNextInputs) { if (continueToCheckNextInputs) {

@ -2160,7 +2160,67 @@
<input id="openvpn-config" class="form-control operationDataKeys" type="hidden" data-key="openvpn_config" /> <input id="openvpn-config" class="form-control operationDataKeys" type="hidden" data-key="openvpn_config" />
<input id="vpn-type" class="form-control operationDataKeys" type="hidden" data-key="type" value="OpenVPN" /> <input id="vpn-type" class="form-control operationDataKeys" type="hidden" data-key="type" value="OpenVPN" />
</div> </div>
<br/>
</div>
<!-- Always on VPN connection settings -->
<div id="always-on-vpn-heading" class="panel-heading" role="tab">
<h2 class="sub-title panel-title">
Always On VPN Settings
<label class="wr-input-control switch" data-toggle="collapse" data-target="#always-on-vpn-body">
<input type="checkbox"/>
<span class="helper"></span>
<span class="text"></span>
</label>
</h2>
<div class="panel-title-description">
Configure an always-on VPN connection through a specific VPN client application
</div>
</div>
<div id="always-on-vpn-body" class="panel-collapse panel-body collapse" role="tabpanel"
aria-labelledby="vpn-body">
<hr/>
<div class="always-on-vpn-message">
<ul class="message message-info">
<i class="icon fw fw-info"></i>
<a id="always-on-vpn-status-msg"> Below configurations are valid only when the Agent is
<b>work-profile owner</b> or <b>device owner</b>.</a>
</ul>
</div>
<br/>
<div id="always-on-vpn-feature-error-msg" class="alert alert-danger hidden" role="alert">
<i class="icon fw fw-error"></i><span></span>
</div>
<div class="wr-input-control">
<label class="wr-input-label" for="vpn-client-app">
VPN Client Application Package Name
<span class="helper" title="Package name of the VPN client application to be configured.">
<span class="wr-help-tip glyphicon glyphicon-question-sign"></span>
</span>
</label>
<input id="vpn-client-app" type="text" class="form-control operationDataKeys"
data-key="packageName" maxlength="200" placeholder="[ Should be a valid package name ]"/>
</div>
<!--<div class="wr-input-control">-->
<!--<label class="wr-input-control checkbox">-->
<!--<input id="vpn-lock-down" type="checkbox" class="operationDataKeys"-->
<!--data-key="lockDownEnable" checked="checked"/>-->
<!--<span class="helper"-->
<!--title="True to disallow networking when the VPN is not connected or false otherwise">-->
<!--Lock Down VPN-->
<!--<span class="wr-help-tip glyphicon glyphicon-question-sign"></span>-->
<!--</span>-->
<!--</label>-->
<!--</div>-->
</div> </div>
<!-- Always on VPN connection settings -->
</div> </div>
</div> </div>
<!-- /VPN --> <!-- /VPN -->

@ -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"
} }
} }
} }

@ -17,6 +17,11 @@
}} }}
<!-- windows --> <!-- windows -->
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading" role="tab">
<h2 class="sub-title panel-title">
Platform Configuration - Windows
</h2>
</div>
<div id="windows-config-body" class="panel-collapse panel-body" role="tabpanel"> <div id="windows-config-body" class="panel-collapse panel-body" role="tabpanel">
<div id="windows-config-error-msg" class="alert alert-danger hidden" role="alert"> <div id="windows-config-error-msg" class="alert alert-danger hidden" role="alert">
<i class="icon fw fw-error"></i><span></span> <i class="icon fw fw-error"></i><span></span>

@ -72,7 +72,7 @@ function promptErrorPolicyPlatform(errorMsg) {
$(document).ready(function () { $(document).ready(function () {
tinymce.init({ tinymce.init({
selector: "textarea", selector: "#windows-eula",
height:500, height:500,
theme: "modern", theme: "modern",
plugins: [ plugins: [

@ -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