| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/net/proxy_policy_handler.h" |
| |
| #include "base/logging.h" |
| #include "base/prefs/pref_value_map.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/values.h" |
| #include "chrome/browser/prefs/proxy_config_dictionary.h" |
| #include "chrome/browser/prefs/proxy_prefs.h" |
| #include "chrome/common/pref_names.h" |
| #include "components/policy/core/browser/configuration_policy_handler.h" |
| #include "components/policy/core/browser/policy_error_map.h" |
| #include "components/policy/core/common/policy_map.h" |
| #include "grit/components_strings.h" |
| #include "policy/policy_constants.h" |
| |
| namespace { |
| |
| // This is used to check whether for a given ProxyMode value, the ProxyPacUrl, |
| // the ProxyBypassList and the ProxyServer policies are allowed to be specified. |
| // |error_message_id| is the message id of the localized error message to show |
| // when the policies are not specified as allowed. Each value of ProxyMode |
| // has a ProxyModeValidationEntry in the |kProxyModeValidationMap| below. |
| struct ProxyModeValidationEntry { |
| const char* mode_value; |
| bool pac_url_allowed; |
| bool bypass_list_allowed; |
| bool server_allowed; |
| int error_message_id; |
| }; |
| |
| // List of entries determining which proxy policies can be specified, depending |
| // on the ProxyMode. |
| const ProxyModeValidationEntry kProxyModeValidationMap[] = { |
| { ProxyPrefs::kDirectProxyModeName, |
| false, false, false, IDS_POLICY_PROXY_MODE_DISABLED_ERROR }, |
| { ProxyPrefs::kAutoDetectProxyModeName, |
| false, false, false, IDS_POLICY_PROXY_MODE_AUTO_DETECT_ERROR }, |
| { ProxyPrefs::kPacScriptProxyModeName, |
| true, false, false, IDS_POLICY_PROXY_MODE_PAC_URL_ERROR }, |
| { ProxyPrefs::kFixedServersProxyModeName, |
| false, true, true, IDS_POLICY_PROXY_MODE_FIXED_SERVERS_ERROR }, |
| { ProxyPrefs::kSystemProxyModeName, |
| false, false, false, IDS_POLICY_PROXY_MODE_SYSTEM_ERROR }, |
| }; |
| |
| } // namespace |
| |
| namespace policy { |
| |
| // The proxy policies have the peculiarity that they are loaded from individual |
| // policies, but the providers then expose them through a unified |
| // DictionaryValue. Once Dictionary policies are fully supported, the individual |
| // proxy policies will be deprecated. http://crbug.com/108996 |
| |
| ProxyPolicyHandler::ProxyPolicyHandler() {} |
| |
| ProxyPolicyHandler::~ProxyPolicyHandler() { |
| } |
| |
| bool ProxyPolicyHandler::CheckPolicySettings(const PolicyMap& policies, |
| PolicyErrorMap* errors) { |
| const base::Value* mode = GetProxyPolicyValue(policies, key::kProxyMode); |
| const base::Value* server = GetProxyPolicyValue(policies, key::kProxyServer); |
| const base::Value* server_mode = |
| GetProxyPolicyValue(policies, key::kProxyServerMode); |
| const base::Value* pac_url = GetProxyPolicyValue(policies, key::kProxyPacUrl); |
| const base::Value* bypass_list = |
| GetProxyPolicyValue(policies, key::kProxyBypassList); |
| |
| if ((server || pac_url || bypass_list) && !(mode || server_mode)) { |
| errors->AddError(key::kProxySettings, |
| key::kProxyMode, |
| IDS_POLICY_NOT_SPECIFIED_ERROR); |
| return false; |
| } |
| |
| std::string mode_value; |
| if (!CheckProxyModeAndServerMode(policies, errors, &mode_value)) |
| return false; |
| |
| // If neither ProxyMode nor ProxyServerMode are specified, mode_value will be |
| // empty and the proxy shouldn't be configured at all. |
| if (mode_value.empty()) |
| return true; |
| |
| bool is_valid_mode = false; |
| for (size_t i = 0; i != arraysize(kProxyModeValidationMap); ++i) { |
| const ProxyModeValidationEntry& entry = kProxyModeValidationMap[i]; |
| if (entry.mode_value != mode_value) |
| continue; |
| |
| is_valid_mode = true; |
| |
| if (!entry.pac_url_allowed && pac_url) { |
| errors->AddError(key::kProxySettings, |
| key::kProxyPacUrl, |
| entry.error_message_id); |
| } |
| if (!entry.bypass_list_allowed && bypass_list) { |
| errors->AddError(key::kProxySettings, |
| key::kProxyBypassList, |
| entry.error_message_id); |
| } |
| if (!entry.server_allowed && server) { |
| errors->AddError(key::kProxySettings, |
| key::kProxyServer, |
| entry.error_message_id); |
| } |
| |
| if ((!entry.pac_url_allowed && pac_url) || |
| (!entry.bypass_list_allowed && bypass_list) || |
| (!entry.server_allowed && server)) { |
| return false; |
| } |
| } |
| |
| if (!is_valid_mode) { |
| errors->AddError(key::kProxySettings, |
| mode ? key::kProxyMode : key::kProxyServerMode, |
| IDS_POLICY_OUT_OF_RANGE_ERROR, |
| mode_value); |
| return false; |
| } |
| return true; |
| } |
| |
| void ProxyPolicyHandler::ApplyPolicySettings(const PolicyMap& policies, |
| PrefValueMap* prefs) { |
| const base::Value* mode = GetProxyPolicyValue(policies, key::kProxyMode); |
| const base::Value* server = GetProxyPolicyValue(policies, key::kProxyServer); |
| const base::Value* server_mode = |
| GetProxyPolicyValue(policies, key::kProxyServerMode); |
| const base::Value* pac_url = GetProxyPolicyValue(policies, key::kProxyPacUrl); |
| const base::Value* bypass_list = |
| GetProxyPolicyValue(policies, key::kProxyBypassList); |
| |
| ProxyPrefs::ProxyMode proxy_mode; |
| if (mode) { |
| std::string string_mode; |
| CHECK(mode->GetAsString(&string_mode)); |
| CHECK(ProxyPrefs::StringToProxyMode(string_mode, &proxy_mode)); |
| } else if (server_mode) { |
| int int_mode = 0; |
| CHECK(server_mode->GetAsInteger(&int_mode)); |
| |
| switch (int_mode) { |
| case PROXY_SERVER_MODE: |
| proxy_mode = ProxyPrefs::MODE_DIRECT; |
| break; |
| case PROXY_AUTO_DETECT_PROXY_SERVER_MODE: |
| proxy_mode = ProxyPrefs::MODE_AUTO_DETECT; |
| break; |
| case PROXY_MANUALLY_CONFIGURED_PROXY_SERVER_MODE: |
| proxy_mode = ProxyPrefs::MODE_FIXED_SERVERS; |
| if (pac_url) |
| proxy_mode = ProxyPrefs::MODE_PAC_SCRIPT; |
| break; |
| case PROXY_USE_SYSTEM_PROXY_SERVER_MODE: |
| proxy_mode = ProxyPrefs::MODE_SYSTEM; |
| break; |
| default: |
| proxy_mode = ProxyPrefs::MODE_DIRECT; |
| NOTREACHED(); |
| } |
| } else { |
| return; |
| } |
| |
| switch (proxy_mode) { |
| case ProxyPrefs::MODE_DIRECT: |
| prefs->SetValue(prefs::kProxy, ProxyConfigDictionary::CreateDirect()); |
| break; |
| case ProxyPrefs::MODE_AUTO_DETECT: |
| prefs->SetValue(prefs::kProxy, ProxyConfigDictionary::CreateAutoDetect()); |
| break; |
| case ProxyPrefs::MODE_PAC_SCRIPT: { |
| std::string pac_url_string; |
| if (pac_url && pac_url->GetAsString(&pac_url_string)) { |
| prefs->SetValue( |
| prefs::kProxy, |
| ProxyConfigDictionary::CreatePacScript(pac_url_string, false)); |
| } else { |
| NOTREACHED(); |
| } |
| break; |
| } |
| case ProxyPrefs::MODE_FIXED_SERVERS: { |
| std::string proxy_server; |
| std::string bypass_list_string; |
| if (server->GetAsString(&proxy_server)) { |
| if (bypass_list) |
| bypass_list->GetAsString(&bypass_list_string); |
| prefs->SetValue(prefs::kProxy, |
| ProxyConfigDictionary::CreateFixedServers( |
| proxy_server, bypass_list_string)); |
| } |
| break; |
| } |
| case ProxyPrefs::MODE_SYSTEM: |
| prefs->SetValue(prefs::kProxy, ProxyConfigDictionary::CreateSystem()); |
| break; |
| case ProxyPrefs::kModeCount: |
| NOTREACHED(); |
| } |
| } |
| |
| const base::Value* ProxyPolicyHandler::GetProxyPolicyValue( |
| const PolicyMap& policies, const char* policy_name) { |
| // See note on the ProxyPolicyHandler implementation above. |
| const base::Value* value = policies.GetValue(key::kProxySettings); |
| const base::DictionaryValue* settings; |
| if (!value || !value->GetAsDictionary(&settings)) |
| return NULL; |
| |
| const base::Value* policy_value = NULL; |
| std::string tmp; |
| if (!settings->Get(policy_name, &policy_value) || |
| policy_value->IsType(base::Value::TYPE_NULL) || |
| (policy_value->IsType(base::Value::TYPE_STRING) && |
| policy_value->GetAsString(&tmp) && |
| tmp.empty())) { |
| return NULL; |
| } |
| return policy_value; |
| } |
| |
| bool ProxyPolicyHandler::CheckProxyModeAndServerMode(const PolicyMap& policies, |
| PolicyErrorMap* errors, |
| std::string* mode_value) { |
| const base::Value* mode = GetProxyPolicyValue(policies, key::kProxyMode); |
| const base::Value* server = GetProxyPolicyValue(policies, key::kProxyServer); |
| const base::Value* server_mode = |
| GetProxyPolicyValue(policies, key::kProxyServerMode); |
| const base::Value* pac_url = GetProxyPolicyValue(policies, key::kProxyPacUrl); |
| |
| // If there's a server mode, convert it into a mode. |
| // When both are specified, the mode takes precedence. |
| if (mode) { |
| if (server_mode) { |
| errors->AddError(key::kProxySettings, |
| key::kProxyServerMode, |
| IDS_POLICY_OVERRIDDEN, |
| key::kProxyMode); |
| } |
| if (!mode->GetAsString(mode_value)) { |
| errors->AddError(key::kProxySettings, |
| key::kProxyMode, |
| IDS_POLICY_TYPE_ERROR, |
| ValueTypeToString(base::Value::TYPE_BOOLEAN)); |
| return false; |
| } |
| |
| ProxyPrefs::ProxyMode mode; |
| if (!ProxyPrefs::StringToProxyMode(*mode_value, &mode)) { |
| errors->AddError(key::kProxySettings, |
| key::kProxyMode, |
| IDS_POLICY_INVALID_PROXY_MODE_ERROR); |
| return false; |
| } |
| |
| if (mode == ProxyPrefs::MODE_PAC_SCRIPT && !pac_url) { |
| errors->AddError(key::kProxySettings, |
| key::kProxyPacUrl, |
| IDS_POLICY_NOT_SPECIFIED_ERROR); |
| return false; |
| } else if (mode == ProxyPrefs::MODE_FIXED_SERVERS && !server) { |
| errors->AddError(key::kProxySettings, |
| key::kProxyServer, |
| IDS_POLICY_NOT_SPECIFIED_ERROR); |
| return false; |
| } |
| } else if (server_mode) { |
| int server_mode_value; |
| if (!server_mode->GetAsInteger(&server_mode_value)) { |
| errors->AddError(key::kProxySettings, |
| key::kProxyServerMode, |
| IDS_POLICY_TYPE_ERROR, |
| ValueTypeToString(base::Value::TYPE_INTEGER)); |
| return false; |
| } |
| |
| switch (server_mode_value) { |
| case PROXY_SERVER_MODE: |
| *mode_value = ProxyPrefs::kDirectProxyModeName; |
| break; |
| case PROXY_AUTO_DETECT_PROXY_SERVER_MODE: |
| *mode_value = ProxyPrefs::kAutoDetectProxyModeName; |
| break; |
| case PROXY_MANUALLY_CONFIGURED_PROXY_SERVER_MODE: |
| if (server && pac_url) { |
| int message_id = IDS_POLICY_PROXY_BOTH_SPECIFIED_ERROR; |
| errors->AddError(key::kProxySettings, |
| key::kProxyServer, |
| message_id); |
| errors->AddError(key::kProxySettings, |
| key::kProxyPacUrl, |
| message_id); |
| return false; |
| } |
| if (!server && !pac_url) { |
| int message_id = IDS_POLICY_PROXY_NEITHER_SPECIFIED_ERROR; |
| errors->AddError(key::kProxySettings, |
| key::kProxyServer, |
| message_id); |
| errors->AddError(key::kProxySettings, |
| key::kProxyPacUrl, |
| message_id); |
| return false; |
| } |
| if (pac_url) |
| *mode_value = ProxyPrefs::kPacScriptProxyModeName; |
| else |
| *mode_value = ProxyPrefs::kFixedServersProxyModeName; |
| break; |
| case PROXY_USE_SYSTEM_PROXY_SERVER_MODE: |
| *mode_value = ProxyPrefs::kSystemProxyModeName; |
| break; |
| default: |
| errors->AddError(key::kProxySettings, |
| key::kProxyServerMode, |
| IDS_POLICY_OUT_OF_RANGE_ERROR, |
| base::IntToString(server_mode_value)); |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| } // namespace policy |