Merge branch 'global-proxy' into 'master'

Set Network Independent HTTP Proxy for Android Device

See merge request entgra/carbon-device-mgt-plugins!9
revert-dabc3590
Inosh Perara 6 years ago
commit 7cbaed3947

@ -0,0 +1,125 @@
/*
* Copyright (c) 2019, 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.mdm.services.android.bean;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.apache.commons.lang.StringUtils;
import java.io.Serializable;
/**
* This class represents the information of setting up global proxy
*/
@ApiModel(
value = "GlobalProxy",
description = "This class represents the information of setting up global proxy"
)
public class GlobalProxy extends AndroidOperation implements Serializable {
@ApiModelProperty(
name = "proxyConfigType",
value = "Type of the proxy",
required = true
)
private ProxyType proxyConfigType;
@ApiModelProperty(
name = "proxyHost",
value = "The hostname of the proxy server"
)
private String proxyHost;
@ApiModelProperty(
name = "proxyPort",
value = "The port which the proxy server is running"
)
private int proxyPort;
@ApiModelProperty(
name = "proxyExclList",
value = "Hosts to exclude using the proxy on connections for. These hosts can use wildcards such as " +
"*.example.com"
)
private String proxyExclList;
@ApiModelProperty(
name = "proxyPacUrl",
value = "PAC file URL to auto config proxy"
)
private String proxyPacUrl;
public boolean validateRequest() {
if (ProxyType.MANUAL.equals(this.proxyConfigType)) {
if (StringUtils.isEmpty(this.proxyHost)) {
return false;
}
if (this.proxyPort < 0 || this.proxyPort > 65535) {
return false;
}
} else if (ProxyType.AUTO.equals(this.proxyConfigType)) {
if (StringUtils.isEmpty(proxyPacUrl)) {
return false;
}
}
return false;
}
public ProxyType getProxyConfigType() {
return proxyConfigType;
}
public void setProxyConfigType(ProxyType proxyConfigType) {
this.proxyConfigType = proxyConfigType;
}
public String getProxyHost() {
return proxyHost;
}
public void setProxyHost(String proxyHost) {
this.proxyHost = proxyHost;
}
public int getProxyPort() {
return proxyPort;
}
public void setProxyPort(int proxyPort) {
this.proxyPort = proxyPort;
}
public String getProxyExclList() {
return proxyExclList;
}
public void setProxyExclList(String proxyExclList) {
this.proxyExclList = proxyExclList;
}
public String getProxyPacUrl() {
return proxyPacUrl;
}
public void setProxyPacUrl(String proxyPacUrl) {
this.proxyPacUrl = proxyPacUrl;
}
}

@ -0,0 +1,66 @@
/*
* Copyright (c) 2019, 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.mdm.services.android.bean.wrapper;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.wso2.carbon.mdm.services.android.bean.GlobalProxy;
import java.util.List;
/**
* This class is used to wrap the GlobalProxyPolicy bean with devices.
*/
@ApiModel(
value = "GlobalProxyBeanWrapper",
description = "Mapping between global proxy settings and devices"
)
public class GlobalProxyBeanWrapper {
@ApiModelProperty(
name = "operation",
value = "Information of setting up global proxy",
required = true
)
private GlobalProxy operation;
@ApiModelProperty(
name = "deviceIDs",
value = "List of device Ids",
required = true)
private List<String> deviceIDs;
public GlobalProxy getOperation() {
return operation;
}
public void setOperation(GlobalProxy operation) {
this.operation = operation;
}
public List<String> getDeviceIDs() {
return deviceIDs;
}
public void setDeviceIDs(List<String> deviceIDs) {
this.deviceIDs = deviceIDs;
}
}

@ -15,6 +15,23 @@
* specific language governing permissions and limitations
* under the License.
*
*
* 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.services;
@ -193,6 +210,12 @@ import java.util.List;
key = "perm:android:configure-wifi",
permissions = {"/device-mgt/devices/owning-device/operations/android/wifi"}
),
@Scope(
name = "Configure Global Proxy",
description = "Configure Global Proxy on Android Device",
key = "perm:android:configure-global-proxy",
permissions = {"/device-mgt/devices/owning-device/operations/android/global-proxy"}
),
@Scope(
name = "Encrypt Storage",
description = "Encrypting storage on Android Device",
@ -1834,5 +1857,65 @@ public interface DeviceManagementAdminService {
required = true)
WebClipBeanWrapper webClipBeanWrapper);
@POST
@Path("/configure-global-proxy")
@ApiOperation(
consumes = MediaType.APPLICATION_JSON,
httpMethod = "POST",
value = "Setting a network independent proxy recommendation on Android Devices",
notes = "Set global proxy on Android devices. All the network traffic will be routed through the proxy " +
"server regardless of the network the device is connected to.",
response = Activity.class,
tags = "Android Device Management Administrative Service",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = AndroidConstants.SCOPE,
value = "perm:android:configure-global-proxy")
})
}
)
@ApiResponses(value = {
@ApiResponse(
code = 201,
message = "Created. \n Successfully scheduled the global proxy operation.",
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.\n",
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 the set global proxy operation.")
})
Response setRecommendedGlobalProxy(
@ApiParam(
name = "globalProxyInfo",
value = "The properties to set the global proxy settings.",
required = true)
GlobalProxyBeanWrapper globalProxyBeanWrapper);
}

@ -15,13 +15,29 @@
* specific language governing permissions and limitations
* under the License.
*
*
* 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.services.impl;
import org.apache.commons.logging.Log;
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.operation.mgt.Activity;
import org.wso2.carbon.device.mgt.common.operation.mgt.Operation;
@ -37,6 +53,7 @@ import org.wso2.carbon.mdm.services.android.bean.DeviceEncryption;
import org.wso2.carbon.mdm.services.android.bean.DeviceLock;
import org.wso2.carbon.mdm.services.android.bean.ErrorResponse;
import org.wso2.carbon.mdm.services.android.bean.FileTransfer;
import org.wso2.carbon.mdm.services.android.bean.GlobalProxy;
import org.wso2.carbon.mdm.services.android.bean.LockCode;
import org.wso2.carbon.mdm.services.android.bean.Notification;
import org.wso2.carbon.mdm.services.android.bean.PasscodePolicy;
@ -53,6 +70,7 @@ import org.wso2.carbon.mdm.services.android.bean.wrapper.CameraBeanWrapper;
import org.wso2.carbon.mdm.services.android.bean.wrapper.DeviceLockBeanWrapper;
import org.wso2.carbon.mdm.services.android.bean.wrapper.EncryptionBeanWrapper;
import org.wso2.carbon.mdm.services.android.bean.wrapper.FileTransferBeanWrapper;
import org.wso2.carbon.mdm.services.android.bean.wrapper.GlobalProxyBeanWrapper;
import org.wso2.carbon.mdm.services.android.bean.wrapper.LockCodeBeanWrapper;
import org.wso2.carbon.mdm.services.android.bean.wrapper.NotificationBeanWrapper;
import org.wso2.carbon.mdm.services.android.bean.wrapper.PasswordPolicyBeanWrapper;
@ -958,6 +976,53 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe
}
}
@POST
@Path("/configure-global-proxy")
@Override
public Response setRecommendedGlobalProxy(GlobalProxyBeanWrapper globalProxyBeanWrapper) {
if (log.isDebugEnabled()) {
log.debug("Applying 'configure-global-proxy' operation: " +
globalProxyBeanWrapper.getOperation().toJSON() + " for Devices: ["
+ String.join(",", globalProxyBeanWrapper.getDeviceIDs()) + "]");
}
try {
if (globalProxyBeanWrapper == null || globalProxyBeanWrapper.getOperation() == null) {
String errorMessage = "The payload of the global proxy operation is incorrect";
log.error(errorMessage);
throw new BadRequestException(
new ErrorResponse.ErrorResponseBuilder().setCode(400L).setMessage(errorMessage).build());
}
GlobalProxy globalProxy = globalProxyBeanWrapper.getOperation();
if (globalProxy.validateRequest()) {
ProfileOperation operation = new ProfileOperation();
operation.setCode(AndroidConstants.OperationCodes.GLOBAL_PROXY);
operation.setType(Operation.Type.PROFILE);
operation.setPayLoad(globalProxy.toJSON());
Activity activity = AndroidDeviceUtils
.getOperationResponse(globalProxyBeanWrapper.getDeviceIDs(), operation);
return Response.status(Response.Status.CREATED).entity(activity).build();
} else {
String errorMessage = "The payload of the global proxy operation is incorrect";
log.error(errorMessage);
throw new BadRequestException(
new ErrorResponse.ErrorResponseBuilder().setCode(400L).setMessage(errorMessage).build());
}
} 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());
}
}
private static void validateApplicationUrl(String apkUrl) {
try {
URL url = new URL(apkUrl);

@ -16,6 +16,23 @@
* under the License.
*
*
* 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.
*
*
* Copyright (c) 2018, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
@ -122,6 +139,7 @@ public final class AndroidConstants {
public static final String APP_RESTRICTION = "APP-RESTRICTION";
public static final String WORK_PROFILE = "WORK_PROFILE";
public static final String NOTIFIER_FREQUENCY = "NOTIFIER_FREQUENCY";
public static final String GLOBAL_PROXY = "SET_GLOBAL_PROXY";
}
public final class StatusCodes {

@ -27,10 +27,11 @@
*
* 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
* "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.
*
*/
var androidOperationModule = function () {
@ -51,6 +52,7 @@ var androidOperationModule = function () {
"CAMERA_OPERATION_CODE": "CAMERA",
"ENCRYPT_STORAGE_OPERATION_CODE": "ENCRYPT_STORAGE",
"WIFI_OPERATION_CODE": "WIFI",
"GLOBAL_PROXY_OPERATION_CODE": "GLOBAL_PROXY",
"WIPE_OPERATION_CODE": "WIPE_DATA",
"NOTIFICATION_OPERATION_CODE": "NOTIFICATION",
"WORK_PROFILE_CODE": "WORK_PROFILE",
@ -153,6 +155,15 @@ var androidOperationModule = function () {
"wifiCaCertName": operationPayload["cacertName"]
};
break;
case androidOperationConstants["GLOBAL_PROXY_OPERATION_CODE"]:
payload = {
"proxyConfigType": operationPayload["proxyConfigType"],
"proxyHost": operationPayload["proxyHost"],
"proxyPort": operationPayload["proxyPort"],
"proxyExclList": operationPayload["proxyExclList"],
"proxyPacUrl": operationPayload["proxyPacUrl"]
};
break;
case androidOperationConstants["VPN_OPERATION_CODE"]:
payload = {
"serverAddress": operationPayload["serverAddress"],
@ -310,6 +321,18 @@ var androidOperationModule = function () {
}
};
break;
case androidOperationConstants["GLOBAL_PROXY_OPERATION_CODE"]:
operationType = operationTypeConstants["PROFILE"];
payload = {
"operation": {
"proxyConfigType": operationData["proxyConfigType"],
"proxyHost": operationData["proxyHost"],
"proxyPort": operationData["proxyPort"],
"proxyExclList": operationData["proxyExclList"],
"proxyPacUrl": operationData["proxyPacUrl"]
}
};
break;
case androidOperationConstants["VPN_OPERATION_CODE"]:
operationType = operationTypeConstants["PROFILE"];
payload = {
@ -433,6 +456,7 @@ var androidOperationModule = function () {
publicMethods.getAndroidServiceEndpoint = function (operationCode) {
var featureMap = {
"WIFI": "configure-wifi",
"GLOBAL_PROXY": "configure-global-proxy",
"CAMERA": "control-camera",
"VPN": "configure-vpn",
"DEVICE_LOCK": "lock-devices",
@ -455,7 +479,6 @@ var androidOperationModule = function () {
"ENTERPRISE_WIPE": "enterprise-wipe",
"WIPE_DATA": "wipe"
};
//return "/mdm-android-agent/operation/" + featureMap[operationCode];
return "/api/device-mgt/android/v1.0/admin/devices/" + featureMap[operationCode];
};

@ -45,6 +45,8 @@ var androidOperationConstants = {
"ENCRYPT_STORAGE_OPERATION_CODE": "ENCRYPT_STORAGE",
"WIFI_OPERATION": "wifi",
"WIFI_OPERATION_CODE": "WIFI",
"GLOBAL_PROXY_OPERATION": "global-proxy",
"GLOBAL_PROXY_OPERATION_CODE": "GLOBAL_PROXY",
"VPN_OPERATION": "vpn",
"VPN_OPERATION_CODE": "VPN",
"APPLICATION_OPERATION": "app-restriction",
@ -323,6 +325,69 @@ var validatePolicyProfile = function () {
validationStatusArray.push(validationStatus);
}
// Validating PROXY
if ($.inArray(androidOperationConstants["GLOBAL_PROXY_OPERATION_CODE"], configuredOperations) !== -1) {
// if PROXY is configured
operation = androidOperationConstants["GLOBAL_PROXY_OPERATION"];
// initializing continueToCheckNextInputs to true
continueToCheckNextInputs = true;
if ($("input#manual-proxy-configuration-radio-button").is(":checked")) {
var proxyHost = $("input#proxy-host").val();
var proxyPort = $("input#proxy-port").val();
if (!proxyHost) {
validationStatus = {
"error": true,
"subErrorMsg": "Proxy server host name is required.",
"erroneousFeature": operation
};
continueToCheckNextInputs = false;
}
if (!proxyPort) {
validationStatus = {
"error": true,
"subErrorMsg": "Proxy server port is required.",
"erroneousFeature": operation
};
continueToCheckNextInputs = false;
} else if (!$.isNumeric(proxyPort)) {
validationStatus = {
"error": true,
"subErrorMsg": "Proxy server port requires a number input.",
"erroneousFeature": operation
};
continueToCheckNextInputs = false;
} else if (!inputIsValidAgainstRange(proxyPort, 0, 65535)) {
validationStatus = {
"error": true,
"subErrorMsg": "Proxy server port is not within the range of valid port numbers.",
"erroneousFeature": operation
};
continueToCheckNextInputs = false;
}
} else if ($("input#auto-proxy-configuration-radio-button").is(":checked")) {
var pacFileUrl = $("input#proxy-pac-url").val();
if (!pacFileUrl) {
validationStatus = {
"error": true,
"subErrorMsg": "Proxy pac file URL is required for proxy auto config.",
"erroneousFeature": operation
};
continueToCheckNextInputs = false;
}
}
// at-last, if the value of continueToCheckNextInputs is still true
// this means that no error is found
if (continueToCheckNextInputs) {
validationStatus = {
"error": false,
"okFeature": operation
};
}
}
if ($.inArray(androidOperationConstants["VPN_OPERATION_CODE"], configuredOperations) != -1) {
// if WIFI is configured
operation = androidOperationConstants["VPN_OPERATION"];
@ -777,6 +842,36 @@ var slideDownPaneAgainstValueSetForRadioButtons = function (selectElement, paneI
$(paneSelector).addClass("hidden");
}
};
/**
* Method to switch panes based on the selected radio button.
*
* The method will un hide the element with the id (paneIdPrefix + selectElement.value)
*
* @param selectElement selected HTML element
* @param paneIdPrefix prefix of the id of the pane to un hide.
* @param valueSet applicable value set
*/
var switchPaneAgainstValueSetForRadioButtons = function (selectElement, paneIdPrefix, valueSet) {
var selectedValueOnChange = selectElement.value;
var paneSelector = "#" + paneIdPrefix;
var pane;
for (var i = 0; i < valueSet.length; ++i) {
if (selectedValueOnChange !== valueSet[i]) {
pane = paneSelector + valueSet[i].toLowerCase();
if ($(pane).hasClass("expanded")) {
$(pane).removeClass("expanded");
}
$(pane).slideUp();
} else {
pane = paneSelector + selectedValueOnChange.toLowerCase();
if (!$(pane).hasClass("expanded")) {
$(pane).addClass("expanded");
}
$(pane).slideDown();
}
}
};
// End of HTML embedded invoke methods

@ -56,6 +56,17 @@
<span id="wifi-ok" class="has-success status-icon hidden"><i class="fw fw-success"></i></span>
<span id="wifi-error" class="has-error status-icon hidden"><i class="fw fw-error"></i></span>
</a>
<a href="javascript:void(0)" onclick="showAdvanceOperation('global-proxy', this)">
<span class="wr-hidden-operations-icon fw-stack">
<i class="fw fw-proxy fw-stack-2x"></i>
</span>
Global Proxy Settings
<span id="global-proxy-configured" class="has-configured status-icon hidden">
<i class="fw fw-success"></i>
</span>
<span id="global-proxy-ok" class="has-success status-icon hidden"><i class="fw fw-success"></i></span>
<span id="global-proxy-error" class="has-error status-icon hidden"><i class="fw fw-error"></i></span>
</a>
<a href="javascript:void(0)" onclick="showAdvanceOperation('vpn', this)">
<span class="wr-hidden-operations-icon fw-stack">
<i class="fw fw-vpn fw-stack-2x"></i>
@ -950,6 +961,132 @@
</div>
<!-- /wi-fi -->
<!-- global-proxy -->
<div class="wr-hidden-operation" data-operation="global-proxy">
<div class="panel panel-default operation-data" data-operation="global-proxy" data-operation-code="GLOBAL_PROXY">
<div id="global-proxy-heading" class="panel-heading" role="tab">
<h2 class="sub-title panel-title">
Global Proxy Settings
<label class="wr-input-control switch" data-toggle="collapse" data-target="#global-proxy-body">
<input type="checkbox"/>
<span class="helper"></span>
<span class="text"></span>
</label>
</h2>
<div class="panel-title-description">
<p>
This configurations can be used to set a network-independent global HTTP proxy on an Android
device. Once this configuration profile is installed on a device, all the network traffic
will be routed through the proxy server.
</p>
</div>
</div>
<div id="global-proxy-body" class="panel-collapse panel-body collapse" role="tabpanel"
aria-labelledby="global-proxy-body">
<hr/>
<ul class="message message-info">
<i class="icon fw fw-info"></i>
<a id="global-proxy-info-message">
This profile requires the agent application to be the device owner.
</a>
</ul>
<br>
<ul class="message message-warning">
<i class="icon fw fw-warning"></i>
<a id="global-proxy-warning-message">
This proxy is only a recommendation and it is possible that some apps will ignore it.
</a>
</ul>
<br>
Please note that * sign represents required fields of data.
<br>
<br>
<div id="global-proxy-feature-error-msg" class="alert alert-danger hidden" role="alert">
<i class="icon fw fw-error"></i><span></span>
</div>
<label class="wr-input-label" for="proxy-config-type-container">
Proxy Configuration Type
<span class="helper" title="Select the configuration type.">
<span class="wr-help-tip glyphicon glyphicon-question-sign"></span>
</span>
</label>
<div class="wr-input-control" id="proxy-config-type-container">
<label class="wr-input-control radio light">
<input id="manual-proxy-configuration-radio-button" type="radio" name="global-proxy-config-type"
class="form-control operationDataKeys" data-key="proxyConfigType"
value="MANUAL"
onclick="switchPaneAgainstValueSetForRadioButtons(this,
'global-proxy-configuration-type-', ['MANUAL','AUTO'])"/>
<span class="helper" title="Manually enter proxy configurations.">
Manual
</span>
</label>
<label class="wr-input-control radio light">
<input id="auto-proxy-configuration-radio-button" type="radio" name="global-proxy-config-type"
class="form-control operationDataKeys" data-key="proxyConfigType"
value="AUTO"
onclick="switchPaneAgainstValueSetForRadioButtons(this,
'global-proxy-configuration-type-', ['AUTO','MANUAL'])"/>
<span class="helper"
title="Proxy configurations will be automatically fetched from Proxy PAC file.">
Auto
</span>
</label>
</div>
<div id="global-proxy-configuration-type-manual" class="wr-input-control" style="display:block">
<div class="wr-input-control">
<label class="wr-input-label" for="proxy-host">
Proxy Host
<span class="helper required" title="Host name/IP address of the proxy server.">
<span class="wr-help-tip glyphicon glyphicon-question-sign"></span>
</span>
</label>
<input id="proxy-host" class="form-control operationDataKeys" data-key="proxyHost"
placeholder="[ 192.168.8.1 ]"/>
</div>
<div class="wr-input-control">
<label class="wr-input-label" for="proxy-port">
Proxy Port
<span class="helper required" title="Target port for the proxy server">
<span class="wr-help-tip glyphicon glyphicon-question-sign"></span>
</span>
</label>
<label id="proxyPortValidationText" class="wr-input-label hidden">
Target port should be between 0 - 65535
</label>
<input id="proxy-port" class="form-control operationDataKeys" data-key="proxyPort"
placeholder="[ Target port 0-65535 ]"/>
</div>
<div class="wr-input-control">
<label class="wr-input-label" for="proxy-excl">
Proxy Exclusion List
<span class="helper"
title="Add hostnames to this separated by commas to prevent them from routing through the proxy server.
The hostname entries can be wildcards such as *.example.com">
<span class="wr-help-tip glyphicon glyphicon-question-sign"></span>
</span>
</label>
<input id="proxy-excl" class="form-control operationDataKeys" data-key="proxyExclList"
placeholder="[ Example: localhost, *.example.com ]"/>
</div>
</div>
<div id="global-proxy-configuration-type-auto" class="wr-input-control" style="display:none">
<div class="wr-input-control">
<label class="wr-input-label" for="proxy-host">
Proxy PAC File URL
<span class="helper required" title="URL for the proxy auto config PAC script">
<span class="wr-help-tip glyphicon glyphicon-question-sign"></span>
</span>
</label>
<input id="proxy-pac-url" class="form-control operationDataKeys" data-key="proxyPacUrl"
placeholder="[ http://exampleproxy.com/proxy.pac ]"/>
</div>
</div>
</div>
</div>
</div>
<!-- /global-proxy -->
<!--app-restriction-->
<div class="wr-hidden-operation" data-operation="app-restriction">
<div class="panel panel-default operation-data" data-operation="app-restriction"

@ -166,6 +166,36 @@ var slideDownPaneAgainstValueSetForRadioButtons = function (selectElement, paneI
$(paneSelector).addClass("hidden");
}
};
/**
* Method to switch panes based on the selected radio button.
*
* The method will un hide the element with the id (paneIdPrefix + selectElement.value)
*
* @param selectElement selected HTML element
* @param paneIdPrefix prefix of the id of the pane to un hide.
* @param valueSet applicable value set
*/
var switchPaneAgainstValueSetForRadioButtons = function (selectElement, paneIdPrefix, valueSet) {
var selectedValueOnChange = selectElement.value;
var paneSelector = "#" + paneIdPrefix;
var pane;
for (var i = 0; i < valueSet.length; ++i) {
if (selectedValueOnChange !== valueSet[i]) {
pane = paneSelector + valueSet[i].toLowerCase();
if ($(pane).hasClass("expanded")) {
$(pane).removeClass("expanded");
}
$(pane).slideUp();
} else {
pane = paneSelector + selectedValueOnChange.toLowerCase();
if (!$(pane).hasClass("expanded")) {
$(pane).addClass("expanded");
}
$(pane).slideDown();
}
}
};
// End of HTML embedded invoke methods
/**

@ -39,6 +39,17 @@
<span id="wifi-ok" class="has-success status-icon hidden"><i class="fw fw-success"></i></span>
<span id="wifi-error" class="has-error status-icon hidden"><i class="fw fw-error"></i></span>
</a>
<a href="javascript:void(0)" onclick="showAdvanceOperation('global-proxy', this)">
<span class="wr-hidden-operations-icon fw-stack">
<i class="fw fw-proxy fw-stack-2x"></i>
</span>
Global Proxy Settings
<span id="global-proxy-configured" class="has-configured status-icon hidden">
<i class="fw fw-success"></i>
</span>
<span id="global-proxy-ok" class="has-success status-icon hidden"><i class="fw fw-success"></i></span>
<span id="global-proxy-error" class="has-error status-icon hidden"><i class="fw fw-error"></i></span>
</a>
<a href="javascript:void(0)" onclick="showAdvanceOperation('vpn', this)">
<span class="wr-hidden-operations-icon fw-stack">
<i class="fw fw-vpn fw-stack-2x"></i>
@ -955,6 +966,136 @@
</div>
<!-- /wi-fi -->
<!-- global-proxy -->
<div class="wr-hidden-operation" data-operation="global-proxy">
<div class="panel panel-default operation-data" data-operation="global-proxy"
data-operation-code="GLOBAL_PROXY">
<div id="global-proxy-heading" class="panel-heading" role="tab">
<h2 class="sub-title panel-title">
Global Proxy Settings
<label class="wr-input-control switch" data-toggle="collapse" data-target="#global-proxy-body">
<input type="checkbox"/>
<span class="helper"></span>
<span class="text"></span>
</label>
</h2>
<div class="panel-title-description">
<p>
This configurations can be used to set a network-independent global HTTP proxy on an Android
device. Once this configuration profile is installed on a device, all the network traffic
will be routed through the proxy server.
</p>
</div>
</div>
<div id="global-proxy-body" class="panel-collapse panel-body collapse" role="tabpanel"
aria-labelledby="global-proxy-body">
<hr/>
<ul class="message message-info">
<i class="icon fw fw-info"></i>
<a id="global-proxy-info-message">
This profile requires the agent application to be the device owner.
</a>
</ul>
<br>
<ul class="message message-warning">
<i class="icon fw fw-warning"></i>
<a id="global-proxy-warning-message">
This proxy is only a recommendation and it is possible that some apps will ignore it.
</a>
</ul>
<br>
Please note that * sign represents required fields of data.
<br>
<br>
<div id="global-proxy-feature-error-msg" class="alert alert-danger hidden" role="alert">
<i class="icon fw fw-error"></i><span></span>
</div>
<label class="wr-input-label" for="proxy-config-type-container">
Proxy Configuration Type
<span class="helper" title="Select the configuration type.">
<span class="wr-help-tip glyphicon glyphicon-question-sign"></span>
</span>
</label>
<div class="wr-input-control" id="proxy-config-type-container">
<label class="wr-input-control radio light">
<input id="manual-proxy-configuration-radio-button" type="radio"
name="global-proxy-config-type"
onclick="switchPaneAgainstValueSetForRadioButtons(this,
'global-proxy-configuration-type-', ['MANUAL','AUTO'])"
class="form-control operationDataKeys" data-key="proxyConfigType"
value="MANUAL" disabled/>
<span class="helper" title="Manually enter proxy configurations.">
Manual
</span>
</label>
<label class="wr-input-control radio light">
<input id="auto-proxy-configuration-radio-button" type="radio"
name="global-proxy-config-type"
onclick="switchPaneAgainstValueSetForRadioButtons(this,
'global-proxy-configuration-type-', ['AUTO','MANUAL'])"
class="form-control operationDataKeys" data-key="proxyConfigType"
value="AUTO" disabled/>
<span class="helper"
title="Proxy configurations will be automatically fetched from Proxy PAC file.">
Auto
</span>
</label>
</div>
<div id="global-proxy-configuration-type-manual" class="wr-input-control expanded">
<div class="wr-input-control">
<label class="wr-input-label" for="proxy-host">
Proxy Host
<span class="helper required" title="Host name/IP address of the proxy server.">
<span class="wr-help-tip glyphicon glyphicon-question-sign"></span>
</span>
</label>
<input id="proxy-host" class="form-control operationDataKeys" data-key="proxyHost"
placeholder="[ 192.168.8.1 ]" disabled/>
</div>
<div class="wr-input-control">
<label class="wr-input-label" for="proxy-port">
Proxy Port
<span class="helper required" title="Target port for the proxy server">
<span class="wr-help-tip glyphicon glyphicon-question-sign"></span>
</span>
</label>
<label id="proxyPortValidationText" class="wr-input-label hidden">
Target port should be between 0 - 65535
</label>
<input id="proxy-port" class="form-control operationDataKeys" data-key="proxyPort"
placeholder="[ Target port 0-65535 ]" disabled/>
</div>
<div class="wr-input-control">
<label class="wr-input-label" for="proxy-excl">
Proxy Exclusion List
<span class="helper"
title="Add hostnames to this separated by commas to prevent them from routing
through the proxy server. The hostname entries can be wildcards such as
*.example.com">
<span class="wr-help-tip glyphicon glyphicon-question-sign"></span>
</span>
</label>
<input id="proxy-excl" class="form-control operationDataKeys" data-key="proxyExclList"
placeholder="[ Example: localhost, *.example.com ]" disabled/>
</div>
</div>
<div id="global-proxy-configuration-type-auto" class="wr-input-control">
<div class="wr-input-control">
<label class="wr-input-label" for="proxy-host">
Proxy PAC File URL
<span class="helper required" title="URL for the proxy auto config PAC script">
<span class="wr-help-tip glyphicon glyphicon-question-sign"></span>
</span>
</label>
<input id="proxy-pac-url" class="form-control operationDataKeys" data-key="proxyPacUrl"
placeholder="[ http://exampleproxy.com/proxy.pac ]" disabled/>
</div>
</div>
</div>
</div>
</div>
<!-- /global-proxy -->
<!--COSU profile configuration-->
<div class="wr-hidden-operation" data-operation="cosu-profile-configuration">
<div class="panel panel-default operation-data" data-operation="cosu-profile-configuration"

@ -44,6 +44,8 @@ var androidOperationConstants = {
"ENCRYPT_STORAGE_OPERATION_CODE": "ENCRYPT_STORAGE",
"WIFI_OPERATION": "wifi",
"WIFI_OPERATION_CODE": "WIFI",
"GLOBAL_PROXY_OPERATION": "global-proxy",
"GLOBAL_PROXY_OPERATION_CODE": "GLOBAL_PROXY",
"VPN_OPERATION": "vpn",
"VPN_OPERATION_CODE": "VPN",
"APPLICATION_OPERATION": "app-restriction",
@ -242,6 +244,72 @@ var validatePolicyProfile = function () {
validationStatusArray.push(validationStatus);
}
// Validating PROXY
if ($.inArray(androidOperationConstants["GLOBAL_PROXY_OPERATION_CODE"], configuredOperations) !== -1) {
// if PROXY is configured
operation = androidOperationConstants["GLOBAL_PROXY_OPERATION"];
// initializing continueToCheckNextInputs to true
continueToCheckNextInputs = true;
if ($("input#manual-proxy-configuration-radio-button").is(":checked")) {
var proxyHost = $("input#proxy-host").val();
var proxyPort = $("input#proxy-port").val();
if (!proxyHost) {
validationStatus = {
"error": true,
"subErrorMsg": "Proxy server host name is required.",
"erroneousFeature": operation
};
continueToCheckNextInputs = false;
}
if (!proxyPort) {
validationStatus = {
"error": true,
"subErrorMsg": "Proxy server port is required.",
"erroneousFeature": operation
};
continueToCheckNextInputs = false;
} else if (!$.isNumeric(proxyPort)) {
validationStatus = {
"error": true,
"subErrorMsg": "Proxy server port requires a number input.",
"erroneousFeature": operation
};
continueToCheckNextInputs = false;
} else if (!inputIsValidAgainstRange(proxyPort, 0, 65535)) {
validationStatus = {
"error": true,
"subErrorMsg": "Proxy server port is not within the range of valid port numbers.",
"erroneousFeature": operation
};
continueToCheckNextInputs = false;
}
} else if ($("input#auto-proxy-configuration-radio-button").is(":checked")) {
var pacFileUrl = $("input#proxy-pac-url").val();
if (!pacFileUrl) {
validationStatus = {
"error": true,
"subErrorMsg": "Proxy pac file URL is required for proxy auto config.",
"erroneousFeature": operation
};
continueToCheckNextInputs = false;
}
}
// at-last, if the value of continueToCheckNextInputs is still true
// this means that no error is found
if (continueToCheckNextInputs) {
validationStatus = {
"error": false,
"okFeature": operation
};
}
// updating validationStatusArray with validationStatus
validationStatusArray.push(validationStatus);
}
if ($.inArray(androidOperationConstants["VPN_OPERATION_CODE"], configuredOperations) != -1) {
// if WIFI is configured
operation = androidOperationConstants["VPN_OPERATION"];
@ -739,6 +807,36 @@ var slideDownPaneAgainstValueSetForRadioButtons = function (selectElement, paneI
}
};
/**
* Method to switch panes based on the selected radio button.
*
* The method will un hide the element with the id (paneIdPrefix + selectElement.value)
*
* @param selectElement selected HTML element
* @param paneIdPrefix prefix of the id of the pane to un hide.
* @param valueSet applicable value set
*/
var switchPaneAgainstValueSetForRadioButtons = function (selectElement, paneIdPrefix, valueSet) {
var selectedValueOnChange = selectElement.value;
var paneSelector = "#" + paneIdPrefix;
var pane;
for (var i = 0; i < valueSet.length; ++i) {
if (selectedValueOnChange !== valueSet[i]) {
pane = paneSelector + valueSet[i].toLowerCase();
if ($(pane).hasClass("expanded")) {
$(pane).removeClass("expanded");
}
$(pane).slideUp();
} else {
pane = paneSelector + selectedValueOnChange.toLowerCase();
if (!$(pane).hasClass("expanded")) {
$(pane).addClass("expanded");
}
$(pane).slideDown();
}
}
};
// End of HTML embedded invoke methods

@ -56,6 +56,17 @@
<span id="wifi-ok" class="has-success status-icon hidden"><i class="fw fw-success"></i></span>
<span id="wifi-error" class="has-error status-icon hidden"><i class="fw fw-error"></i></span>
</a>
<a href="javascript:void(0)" onclick="showAdvanceOperation('global-proxy', this)">
<span class="wr-hidden-operations-icon fw-stack">
<i class="fw fw-proxy fw-stack-2x"></i>
</span>
Global Proxy Settings
<span id="global-proxy-configured" class="has-configured status-icon hidden">
<i class="fw fw-success"></i>
</span>
<span id="global-proxy-ok" class="has-success status-icon hidden"><i class="fw fw-success"></i></span>
<span id="global-proxy-error" class="has-error status-icon hidden"><i class="fw fw-error"></i></span>
</a>
<a href="javascript:void(0)" onclick="showAdvanceOperation('vpn', this)">
<span class="wr-hidden-operations-icon fw-stack">
<i class="fw fw-vpn fw-stack-2x"></i>
@ -974,6 +985,132 @@
</div>
<!-- /wi-fi -->
<!-- global-proxy -->
<div class="wr-hidden-operation" data-operation="global-proxy">
<div class="panel panel-default operation-data" data-operation="global-proxy" data-operation-code="GLOBAL_PROXY">
<div id="global-proxy-heading" class="panel-heading" role="tab">
<h2 class="sub-title panel-title">
Global Proxy Settings
<label class="wr-input-control switch" data-toggle="collapse" data-target="#global-proxy-body">
<input type="checkbox"/>
<span class="helper"></span>
<span class="text"></span>
</label>
</h2>
<div class="panel-title-description">
<p>
This configurations can be used to set a network-independent global HTTP proxy on an Android
device. Once this configuration profile is installed on a device, all the network traffic
will be routed through the proxy server.
</p>
</div>
</div>
<div id="global-proxy-body" class="panel-collapse panel-body collapse" role="tabpanel"
aria-labelledby="global-proxy-body">
<hr/>
<ul class="message message-info">
<i class="icon fw fw-info"></i>
<a id="global-proxy-info-message">
This profile requires the agent application to be the device owner.
</a>
</ul>
<br>
<ul class="message message-warning">
<i class="icon fw fw-warning"></i>
<a id="global-proxy-warning-message">
This proxy is only a recommendation and it is possible that some apps will ignore it.
</a>
</ul>
<br>
Please note that * sign represents required fields of data.
<br>
<br>
<div id="global-proxy-feature-error-msg" class="alert alert-danger hidden" role="alert">
<i class="icon fw fw-error"></i><span></span>
</div>
<label class="wr-input-label" for="proxy-config-type-container">
Proxy Configuration Type
<span class="helper" title="Select the configuration type.">
<span class="wr-help-tip glyphicon glyphicon-question-sign"></span>
</span>
</label>
<div class="wr-input-control" id="proxy-config-type-container">
<label class="wr-input-control radio light">
<input id="manual-proxy-configuration-radio-button" type="radio" name="global-proxy-config-type"
class="form-control operationDataKeys" data-key="proxyConfigType"
value="MANUAL"
onclick="switchPaneAgainstValueSetForRadioButtons(this,
'global-proxy-configuration-type-', ['MANUAL','AUTO'])" checked/>
<span class="helper" title="Manually enter proxy configurations.">
Manual
</span>
</label>
<label class="wr-input-control radio light">
<input id="auto-proxy-configuration-radio-button" type="radio" name="global-proxy-config-type"
class="form-control operationDataKeys" data-key="proxyConfigType"
value="AUTO"
onclick="switchPaneAgainstValueSetForRadioButtons(this,
'global-proxy-configuration-type-', ['AUTO','MANUAL'])"/>
<span class="helper"
title="Proxy configurations will be automatically fetched from Proxy PAC file.">
Auto
</span>
</label>
</div>
<div id="global-proxy-configuration-type-manual" class="wr-input-control" style="display:block">
<div class="wr-input-control">
<label class="wr-input-label" for="proxy-host">
Proxy Host
<span class="helper required" title="Host name/IP address of the proxy server.">
<span class="wr-help-tip glyphicon glyphicon-question-sign"></span>
</span>
</label>
<input id="proxy-host" class="form-control operationDataKeys" data-key="proxyHost"
placeholder="[ 192.168.8.1 ]"/>
</div>
<div class="wr-input-control">
<label class="wr-input-label" for="proxy-port">
Proxy Port
<span class="helper required" title="Target port for the proxy server">
<span class="wr-help-tip glyphicon glyphicon-question-sign"></span>
</span>
</label>
<label id="proxyPortValidationText" class="wr-input-label hidden">
Target port should be between 0 - 65535
</label>
<input id="proxy-port" class="form-control operationDataKeys" data-key="proxyPort"
placeholder="[ Target port 0-65535 ]"/>
</div>
<div class="wr-input-control">
<label class="wr-input-label" for="proxy-excl">
Proxy Exclusion List
<span class="helper"
title="Add hostnames to this separated by commas to prevent them from routing through the proxy server.
The hostname entries can be wildcards such as *.example.com">
<span class="wr-help-tip glyphicon glyphicon-question-sign"></span>
</span>
</label>
<input id="proxy-excl" class="form-control operationDataKeys" data-key="proxyExclList"
placeholder="[ Example: localhost, *.example.com ]"/>
</div>
</div>
<div id="global-proxy-configuration-type-auto" class="wr-input-control" style="display:none">
<div class="wr-input-control">
<label class="wr-input-label" for="proxy-host">
Proxy PAC File URL
<span class="helper required" title="URL for the proxy auto config PAC script">
<span class="wr-help-tip glyphicon glyphicon-question-sign"></span>
</span>
</label>
<input id="proxy-pac-url" class="form-control operationDataKeys" data-key="proxyPacUrl"
placeholder="[ http://exampleproxy.com/proxy.pac ]"/>
</div>
</div>
</div>
</div>
</div>
<!-- /global-proxy -->
<!--app-restriction-->
<div class="wr-hidden-operation" data-operation="app-restriction">
<div class="panel panel-default operation-data" data-operation="app-restriction"

@ -13,6 +13,7 @@
"perm:android:lock-devices",
"perm:android:configure-vpn",
"perm:android:configure-wifi",
"perm:android:configure-global-proxy",
"perm:android:enroll",
"perm:android:uninstall-application",
"perm:android:manage-configuration",

@ -163,6 +163,10 @@
<Name>Wifi</Name>
<Description>Setting up wifi configuration</Description>
</Feature>
<Feature code="GLOBAL_PROXY">
<Name>Global Proxy</Name>
<Description>Setting up a network-independent global HTTP proxy on a device.</Description>
</Feature>
<Feature code="CAMERA">
<Name>Camera</Name>
<Description>Enable or disable camera</Description>

Loading…
Cancel
Save