Bug 1429177 - Policy: Set network proxy settings. r=mixedpuppy
This commit is contained in:
@@ -12,6 +12,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "gXulStore",
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
BookmarksPolicies: "resource:///modules/policies/BookmarksPolicies.jsm",
|
||||
ProxyPolicies: "resource:///modules/policies/ProxyPolicies.jsm",
|
||||
});
|
||||
|
||||
const PREF_LOGLEVEL = "browser.policies.loglevel";
|
||||
@@ -325,6 +326,17 @@ var Policies = {
|
||||
}
|
||||
},
|
||||
|
||||
"Proxy": {
|
||||
onBeforeAddons(manager, param) {
|
||||
if (param.Locked) {
|
||||
manager.disallowFeature("changeProxySettings");
|
||||
ProxyPolicies.configureProxySettings(param, setAndLockPref);
|
||||
} else {
|
||||
ProxyPolicies.configureProxySettings(param, setDefaultPref);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"RememberPasswords": {
|
||||
onBeforeUIStartup(manager, param) {
|
||||
setAndLockPref("signon.rememberSignons", param);
|
||||
|
||||
110
browser/components/enterprisepolicies/helpers/ProxyPolicies.jsm
Normal file
110
browser/components/enterprisepolicies/helpers/ProxyPolicies.jsm
Normal file
@@ -0,0 +1,110 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
|
||||
const PREF_LOGLEVEL = "browser.policies.loglevel";
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "log", () => {
|
||||
let { ConsoleAPI } = ChromeUtils.import("resource://gre/modules/Console.jsm", {});
|
||||
return new ConsoleAPI({
|
||||
prefix: "ProxyPolicies.jsm",
|
||||
// tip: set maxLogLevel to "debug" and use log.debug() to create detailed
|
||||
// messages during development. See LOG_LEVELS in Console.jsm for details.
|
||||
maxLogLevel: "error",
|
||||
maxLogLevelPref: PREF_LOGLEVEL,
|
||||
});
|
||||
});
|
||||
|
||||
// Don't use const here because this is acessed by
|
||||
// tests through the BackstagePass object.
|
||||
var PROXY_TYPES_MAP = new Map([
|
||||
["none", Ci.nsIProtocolProxyService.PROXYCONFIG_DIRECT],
|
||||
["system", Ci.nsIProtocolProxyService.PROXYCONFIG_SYSTEM],
|
||||
["manual", Ci.nsIProtocolProxyService.PROXYCONFIG_MANUAL],
|
||||
["autoDetect", Ci.nsIProtocolProxyService.PROXYCONFIG_WPAD],
|
||||
["autoConfig", Ci.nsIProtocolProxyService.PROXYCONFIG_PAC],
|
||||
]);
|
||||
|
||||
var EXPORTED_SYMBOLS = [ "ProxyPolicies" ];
|
||||
|
||||
var ProxyPolicies = {
|
||||
configureProxySettings(param, setPref) {
|
||||
if (param.Mode) {
|
||||
setPref("network.proxy.type", PROXY_TYPES_MAP.get(param.Mode));
|
||||
}
|
||||
|
||||
if (param.AutoConfigURL) {
|
||||
setPref("network.proxy.autoconfig_url", param.AutoConfigURL.spec);
|
||||
}
|
||||
|
||||
if (param.UseProxyForDNS !== undefined) {
|
||||
setPref("network.proxy.socks_remote_dns", param.UseProxyForDNS);
|
||||
}
|
||||
|
||||
if (param.AutoLogin !== undefined) {
|
||||
setPref("signon.autologin.proxy", param.AutoLogin);
|
||||
}
|
||||
|
||||
if (param.SOCKSVersion !== undefined) {
|
||||
if (param.SOCKSVersion != 4 && param.SOCKSVersion != 5) {
|
||||
log.error("Invalid SOCKS version");
|
||||
} else {
|
||||
setPref("network.proxy.socks_version", param.SOCKSVersion);
|
||||
}
|
||||
}
|
||||
|
||||
if (param.Passthrough !== undefined) {
|
||||
setPref("network.proxy.no_proxies_on", param.Passthrough);
|
||||
}
|
||||
|
||||
if (param.UseHTTPProxyForAllProtocols !== undefined) {
|
||||
setPref("network.proxy.share_proxy_settings", param.UseHTTPProxyForAllProtocols);
|
||||
}
|
||||
|
||||
function setProxyHostAndPort(type, address) {
|
||||
let url;
|
||||
try {
|
||||
// Prepend https just so we can use the URL parser
|
||||
// instead of parsing manually.
|
||||
url = new URL(`https://${address}`);
|
||||
} catch (e) {
|
||||
log.error(`Invalid address for ${type} proxy: ${address}`);
|
||||
return;
|
||||
}
|
||||
|
||||
setPref(`network.proxy.${type}`, url.hostname);
|
||||
if (url.port) {
|
||||
setPref(`network.proxy.${type}_port`, Number(url.port));
|
||||
}
|
||||
}
|
||||
|
||||
if (param.HTTPProxy) {
|
||||
setProxyHostAndPort("http", param.HTTPProxy);
|
||||
|
||||
// network.proxy.share_proxy_settings is a UI feature, not handled by the
|
||||
// network code. That pref only controls if the checkbox is checked, and
|
||||
// then we must manually set the other values.
|
||||
if (param.UseHTTPProxyForAllProtocols) {
|
||||
param.FTPProxy = param.SSLProxy = param.SOCKSProxy = param.HTTPProxy;
|
||||
}
|
||||
}
|
||||
|
||||
if (param.FTPProxy) {
|
||||
setProxyHostAndPort("ftp", param.FTPProxy);
|
||||
}
|
||||
|
||||
if (param.SSLProxy) {
|
||||
setProxyHostAndPort("ssl", param.SSLProxy);
|
||||
}
|
||||
|
||||
if (param.SOCKSProxy) {
|
||||
setProxyHostAndPort("socks", param.SOCKSProxy);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -9,4 +9,5 @@ with Files("**"):
|
||||
|
||||
EXTRA_JS_MODULES.policies += [
|
||||
'BookmarksPolicies.jsm',
|
||||
'ProxyPolicies.jsm',
|
||||
]
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"policies": {
|
||||
"Proxy": {
|
||||
"Mode": "manual",
|
||||
"Locked": true,
|
||||
"HTTPProxy": "www.example.com:42",
|
||||
"UseHTTPProxyForAllProtocols": true,
|
||||
"Passthrough": "foo, bar, baz",
|
||||
"SOCKSVersion": 4,
|
||||
"UseProxyForDNS": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -306,6 +306,64 @@
|
||||
}
|
||||
},
|
||||
|
||||
"Proxy": {
|
||||
"description": "Configure Proxy settings.",
|
||||
"first_available": "60.0",
|
||||
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Mode": {
|
||||
"type": "string",
|
||||
"enum": ["none", "system", "manual", "autoDetect", "autoConfig"]
|
||||
},
|
||||
|
||||
"Locked": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
"AutoConfigURL": {
|
||||
"type": "URLorEmpty"
|
||||
},
|
||||
|
||||
"FTPProxy": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"HTTPProxy": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"SSLProxy": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"SOCKSProxy": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"SOCKSVersion": {
|
||||
"type": "number",
|
||||
"enum": [4, 5]
|
||||
},
|
||||
|
||||
"UseHTTPProxyForAllProtocols": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
"Passthrough": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"UseProxyForDNS": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
"AutoLogin": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"RememberPasswords": {
|
||||
"description": "Enforces the setting to allow Firefox to remember saved logins and passwords. Both true and false values are accepted.",
|
||||
"first_available": "60.0",
|
||||
|
||||
@@ -37,5 +37,6 @@ support-files =
|
||||
[browser_policy_display_bookmarks.js]
|
||||
[browser_policy_display_menu.js]
|
||||
[browser_policy_enable_tracking_protection.js]
|
||||
[browser_policy_proxy.js]
|
||||
[browser_policy_remember_passwords.js]
|
||||
[browser_policy_set_homepage.js]
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
function checkPref(prefName, expectedValue, expectedLockedness) {
|
||||
let prefType, prefValue;
|
||||
switch (typeof(expectedValue)) {
|
||||
case "boolean":
|
||||
prefType = Services.prefs.PREF_BOOL;
|
||||
prefValue = Services.prefs.getBoolPref(prefName);
|
||||
break;
|
||||
|
||||
case "number":
|
||||
prefType = Services.prefs.PREF_INT;
|
||||
prefValue = Services.prefs.getIntPref(prefName);
|
||||
break;
|
||||
|
||||
case "string":
|
||||
prefType = Services.prefs.PREF_STRING;
|
||||
prefValue = Services.prefs.getStringPref(prefName);
|
||||
break;
|
||||
}
|
||||
|
||||
if (expectedLockedness !== undefined) {
|
||||
is(Services.prefs.prefIsLocked(prefName), expectedLockedness, `Pref ${prefName} is correctly locked`);
|
||||
}
|
||||
is(Services.prefs.getPrefType(prefName), prefType, `Pref ${prefName} has the correct type`);
|
||||
is(prefValue, expectedValue, `Pref ${prefName} has the correct value`);
|
||||
}
|
||||
|
||||
add_task(async function test_proxy_modes_and_autoconfig() {
|
||||
// Directly test the proxy Mode and AutoconfigURL parameters through
|
||||
// the API instead of the policy engine, because the test harness
|
||||
// uses these prefs, and changing them interfere with the harness.
|
||||
|
||||
// Checks that every Mode value translates correctly to the expected pref value
|
||||
let { ProxyPolicies, PROXY_TYPES_MAP } = ChromeUtils.import("resource:///modules/policies/ProxyPolicies.jsm", {});
|
||||
|
||||
for (let [mode, expectedValue] of PROXY_TYPES_MAP) {
|
||||
ProxyPolicies.configureProxySettings({Mode: mode}, (_, value) => {
|
||||
is(value, expectedValue, "Correct proxy mode");
|
||||
});
|
||||
}
|
||||
|
||||
let autoconfigURL = Services.io.newURI("data:text/plain,test");
|
||||
ProxyPolicies.configureProxySettings({AutoConfigURL: autoconfigURL}, (_, value) => {
|
||||
is(value, autoconfigURL.spec, "AutoconfigURL correctly set");
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_proxy_boolean_settings() {
|
||||
// Tests that both false and true values are correctly set and locked
|
||||
await setupPolicyEngineWithJson({
|
||||
"policies": {
|
||||
"Proxy": {
|
||||
"UseProxyForDNS": false,
|
||||
"AutoLogin": false,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
checkPref("network.proxy.socks_remote_dns", false);
|
||||
checkPref("signon.autologin.proxy", false);
|
||||
|
||||
await setupPolicyEngineWithJson({
|
||||
"policies": {
|
||||
"Proxy": {
|
||||
"UseProxyForDNS": true,
|
||||
"AutoLogin": true,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
checkPref("network.proxy.socks_remote_dns", true);
|
||||
checkPref("signon.autologin.proxy", true);
|
||||
});
|
||||
|
||||
add_task(async function test_proxy_socks_and_passthrough() {
|
||||
await setupPolicyEngineWithJson({
|
||||
"policies": {
|
||||
"Proxy": {
|
||||
"SOCKSVersion": 4,
|
||||
"Passthrough": "a, b, c"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
checkPref("network.proxy.socks_version", 4);
|
||||
checkPref("network.proxy.no_proxies_on", "a, b, c");
|
||||
});
|
||||
|
||||
add_task(async function test_proxy_addresses() {
|
||||
function checkProxyPref(proxytype, address, port) {
|
||||
checkPref(`network.proxy.${proxytype}`, address);
|
||||
checkPref(`network.proxy.${proxytype}_port`, port);
|
||||
}
|
||||
|
||||
await setupPolicyEngineWithJson({
|
||||
"policies": {
|
||||
"Proxy": {
|
||||
"HTTPProxy": "http.proxy.example.com:10",
|
||||
"FTPProxy": "ftp.proxy.example.com:20",
|
||||
"SSLProxy": "ssl.proxy.example.com:30",
|
||||
"SOCKSProxy": "socks.proxy.example.com:40",
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
checkProxyPref("http", "http.proxy.example.com", 10);
|
||||
checkProxyPref("ftp", "ftp.proxy.example.com", 20);
|
||||
checkProxyPref("ssl", "ssl.proxy.example.com", 30);
|
||||
checkProxyPref("socks", "socks.proxy.example.com", 40);
|
||||
|
||||
// Do the same, but now use the UseHTTPProxyForAllProtocols option
|
||||
// and check that it takes effect.
|
||||
await setupPolicyEngineWithJson({
|
||||
"policies": {
|
||||
"Proxy": {
|
||||
"HTTPProxy": "http.proxy.example.com:10",
|
||||
"FTPProxy": "ftp.proxy.example.com:20",
|
||||
"SSLProxy": "ssl.proxy.example.com:30",
|
||||
"SOCKSProxy": "socks.proxy.example.com:40",
|
||||
"UseHTTPProxyForAllProtocols": true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
checkProxyPref("http", "http.proxy.example.com", 10);
|
||||
checkProxyPref("ftp", "http.proxy.example.com", 10);
|
||||
checkProxyPref("ssl", "http.proxy.example.com", 10);
|
||||
checkProxyPref("socks", "http.proxy.example.com", 10);
|
||||
});
|
||||
@@ -264,7 +264,7 @@ var gConnectionsDialog = {
|
||||
for (let element of gConnectionsDialog.getProxyControls()) {
|
||||
element.disabled = disabled;
|
||||
}
|
||||
if (!isControlled) {
|
||||
if (!isLocked) {
|
||||
gConnectionsDialog.proxyTypeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,6 +310,11 @@ this.browserSettings = class extends ExtensionAPI {
|
||||
"proxyConfig is not supported on android.");
|
||||
}
|
||||
|
||||
if (!Services.policies.isAllowed("changeProxySettings")) {
|
||||
throw new ExtensionError(
|
||||
"Proxy settings are being managed by the Policies manager.");
|
||||
}
|
||||
|
||||
let value = details.value;
|
||||
|
||||
if (!PROXY_TYPES_MAP.has(value.proxyType)) {
|
||||
|
||||
Reference in New Issue
Block a user