diff options
37 files changed, 2158 insertions, 1339 deletions
diff --git a/chrome/app/policy/cloud_policy_codegen.gyp b/chrome/app/policy/cloud_policy_codegen.gyp new file mode 100644 index 0000000..2c7e3b1 --- /dev/null +++ b/chrome/app/policy/cloud_policy_codegen.gyp @@ -0,0 +1,202 @@ +# Copyright (c) 2011 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. + +{ + 'variables': { + 'chromium_code': 1, + 'policy_out_dir': '<(SHARED_INTERMEDIATE_DIR)/policy', + 'protoc_out_dir': '<(SHARED_INTERMEDIATE_DIR)/protoc_out', + 'generate_policy_source_script_path': + '../../tools/build/generate_policy_source.py', + 'policy_constant_header_path': + '<(policy_out_dir)/policy/policy_constants.h', + 'policy_constant_source_path': + '<(policy_out_dir)/policy/policy_constants.cc', + 'configuration_policy_type_header_path': + '<(policy_out_dir)/policy/configuration_policy_type.h', + 'protobuf_decoder_path': + '<(policy_out_dir)/policy/cloud_policy_generated.cc', + 'cloud_policy_proto_path': '<(policy_out_dir)/policy/cloud_policy.proto', + 'proto_path_substr': 'chrome/browser/policy/proto', + 'proto_rel_path': '../../../<(proto_path_substr)', + }, + 'targets': [ + { + 'target_name': 'cloud_policy_code_generate', + 'type': 'none', + 'actions': [ + { + 'inputs': [ + 'policy_templates.json', + '<(generate_policy_source_script_path)', + ], + 'outputs': [ + '<(policy_constant_header_path)', + '<(policy_constant_source_path)', + '<(configuration_policy_type_header_path)', + '<(protobuf_decoder_path)', + '<(cloud_policy_proto_path)', + ], + 'action_name': 'generate_policy_source', + 'action': [ + 'python', + '<@(generate_policy_source_script_path)', + '--policy-constants-header=<(policy_constant_header_path)', + '--policy-constants-source=<(policy_constant_source_path)', + '--policy-type-header=<(configuration_policy_type_header_path)', + '--policy-protobuf=<(cloud_policy_proto_path)', + '--protobuf-decoder=<(protobuf_decoder_path)', + '<(OS)', + 'policy_templates.json', + ], + 'message': 'Generating policy source', + }, + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '<(policy_out_dir)', + '<(protoc_out_dir)', + ], + }, + }, + { + 'target_name': 'cloud_policy_proto_compile', + 'type': 'none', + 'actions': [ + { + 'action_name': 'compile_generated_proto', + 'inputs': [ + '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)protoc<(EXECUTABLE_SUFFIX)', + '<(policy_out_dir)/policy/cloud_policy.proto', + ], + 'outputs': [ + '<(PRODUCT_DIR)/pyproto/device_management_pb/cloud_policy_pb2.py', + '<(protoc_out_dir)/<(proto_path_substr)/cloud_policy.pb.h', + '<(protoc_out_dir)/<(proto_path_substr)/cloud_policy.pb.cc', + ], + 'action': [ + '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)protoc<(EXECUTABLE_SUFFIX)', + '--proto_path=<(policy_out_dir)/policy', + '<(policy_out_dir)/policy/cloud_policy.proto', + '--cpp_out=<(protoc_out_dir)/<(proto_path_substr)', + '--python_out=<(PRODUCT_DIR)/pyproto/device_management_pb', + ], + 'message': 'Compiling generated cloud policy protobuf', + }, + ], + 'dependencies': [ + '../../../third_party/protobuf/protobuf.gyp:protoc#host', + 'cloud_policy_code_generate', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '<(protoc_out_dir)', + ] + }, + }, + { + 'target_name': 'cloud_policy_backend_header_compile', + 'type': 'none', + 'sources': [ + '<(proto_rel_path)/device_management_backend.proto', + '<(proto_rel_path)/device_management_local.proto', + ], + 'rules': [ + { + 'rule_name': 'gen_proto', + 'extension': 'proto', + 'inputs': [ + '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)protoc<(EXECUTABLE_SUFFIX)', + ], + 'outputs': [ + '<(PRODUCT_DIR)/pyproto/device_management_pb/<(RULE_INPUT_ROOT)_pb2.py', + '<(protoc_out_dir)/<(proto_path_substr)/<(RULE_INPUT_ROOT).pb.h', + '<(protoc_out_dir)/<(proto_path_substr)/<(RULE_INPUT_ROOT).pb.cc', + ], + 'action': [ + '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)protoc<(EXECUTABLE_SUFFIX)', + '--proto_path=<(policy_out_dir)/policy', + '--proto_path=<(proto_rel_path)', + '<(proto_rel_path)/<(RULE_INPUT_NAME)', + '--cpp_out=<(protoc_out_dir)/<(proto_path_substr)', + '--python_out=<(PRODUCT_DIR)/pyproto/device_management_pb', + ], + 'message': 'Generating C++ and Python code from <(RULE_INPUT_PATH)', + } + ], + 'dependencies': [ + '../../../third_party/protobuf/protobuf.gyp:protoc#host', + 'cloud_policy_proto_compile', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '<(protoc_out_dir)', + ] + }, + }, + { + 'target_name': 'policy', + 'type': '<(library)', + 'hard_dependency': 1, + 'direct_dependent_settings': { + 'include_dirs': [ + '<(policy_out_dir)', + '<(protoc_out_dir)', + ], + }, + 'sources': [ + '<(policy_constant_header_path)', + '<(policy_constant_source_path)', + '<(configuration_policy_type_header_path)', + '<(protobuf_decoder_path)', + '<(protoc_out_dir)/<(proto_path_substr)/cloud_policy.pb.h', + '<(protoc_out_dir)/<(proto_path_substr)/cloud_policy.pb.cc', + ], + 'include_dirs': [ + '../../..', + ], + 'dependencies': [ + 'cloud_policy_code_generate', + 'cloud_policy_proto_compile', + 'cloud_policy_backend_header_compile', + '../../../third_party/protobuf/protobuf.gyp:protobuf_lite', + ], + }, + ], + 'conditions': [ + ['OS=="win"', { + 'targets': [ + { + 'target_name': 'policy_win64', + 'type': '<(library)', + 'hard_dependency': 1, + 'sources': [ + '<(policy_constant_header_path)', + '<(policy_constant_source_path)', + '<(configuration_policy_type_header_path)', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '<(policy_out_dir)' + ], + }, + 'dependencies': [ + 'cloud_policy_code_generate', + ], + 'configurations': { + 'Common_Base': { + 'msvs_target_platform': 'x64', + }, + }, + }, + ], + }], + ], # 'conditions' +} + +# Local Variables: +# tab-width:2 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=2 shiftwidth=2: diff --git a/chrome/app/policy/policy_templates.gypi b/chrome/app/policy/policy_templates.gypi index 7233a93..084334a 100644 --- a/chrome/app/policy/policy_templates.gypi +++ b/chrome/app/policy/policy_templates.gypi @@ -1,99 +1,9 @@ -# Copyright (c) 2010 The Chromium Authors. All rights reserved. +# Copyright (c) 2011 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. { - 'variables': { - 'policy_out_dir': '<(SHARED_INTERMEDIATE_DIR)/policy', - 'generate_policy_source_script': - ['python', 'tools/build/generate_policy_source.py'], - }, - 'target_defaults': { - 'variables': { - 'policy_target': 0, - }, - 'target_conditions': [ - [ 'policy_target==1', { - 'include_dirs': [ - '<(policy_out_dir)', - ], - 'actions': [ - { - 'variables': - { - 'policy_constant_header': - '<(policy_out_dir)/policy/policy_constants.h', - 'policy_constant_source': - '<(policy_out_dir)/policy/policy_constants.cc', - 'configuration_policy_type_header': - '<(policy_out_dir)/policy/configuration_policy_type.h', - }, - 'inputs': [ - 'policy_templates.json', - '../../tools/build/generate_policy_source.py' - ], - 'outputs': [ - '<(policy_constant_header)', - '<(policy_constant_source)', - '<(configuration_policy_type_header)', - ], - 'action_name': 'generate_policy_source', - 'action': [ - '<@(generate_policy_source_script)', - '--policy-constants-header=<(policy_constant_header)', - '--policy-constants-source=<(policy_constant_source)', - '--policy-type-header=<(configuration_policy_type_header)', - '<(OS)', - '<@(_inputs)', - ], - 'message': 'Generating policy source', - 'process_outputs_as_sources': 1, - }, - ], - }, ], - ], - }, - 'targets': [ - { - 'target_name': 'policy', - 'type': '<(library)', - 'hard_dependency': 1, - 'include_dirs': [ - '<(policy_out_dir)', - ], - 'direct_dependent_settings': { - 'include_dirs': [ - '<(SHARED_INTERMEDIATE_DIR)/policy' - ], - }, - 'variables': { - 'policy_target': 1, - }, - }, - ], 'conditions': [ - ['OS=="win"', { - 'targets': [ - { - 'target_name': 'policy_win64', - 'type': '<(library)', - 'hard_dependency': 1, - 'variables': { - 'policy_target': 1, - }, - 'direct_dependent_settings': { - 'include_dirs': [ - '<(SHARED_INTERMEDIATE_DIR)/policy' - ], - }, - 'configurations': { - 'Common_Base': { - 'msvs_target_platform': 'x64', - }, - }, - }, - ], - }], ['OS=="win" or OS=="mac" or OS=="linux"', { 'targets': [ { diff --git a/chrome/app/policy/policy_templates.json b/chrome/app/policy/policy_templates.json index c971bea..c566d2b 100644 --- a/chrome/app/policy/policy_templates.json +++ b/chrome/app/policy/policy_templates.json @@ -86,6 +86,13 @@ # 'example_value'. These are used in the generated documentation and example # policy configuration files. # +# IDs: +# Since a Protocol Buffer definition is generated from this file, unique and +# persistent IDs for all fields (but not for groups!) are needed. These are +# specified by the 'id' keys of each policy. NEVER CHANGE EXISTING IDs, +# because doing so would break the deployed wire format! +# For your editing convenience: highest ID currently used: 63 +# 'policy_definitions': [ { 'name': 'Homepage', @@ -101,6 +108,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': 'http://chromium.org', + 'id': 1, 'caption': '''Configure the home page URL''', 'desc': '''Configures the default home page URL in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> and prevents users from changing it. @@ -117,6 +125,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': True, + 'id': 2, 'caption': '''Use New Tab Page as homepage''', 'desc': '''Configures the type of the default home page in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> and prevents users from changing home page preferences. The home page can either be set to a URL you specify or set to the New Tab Page. @@ -134,6 +143,7 @@ 'supported_on': ['chrome.*:11-'], 'features': {'dynamic_refresh': 1}, 'example_value': True, + 'id': 3, 'caption': '''Set Chrome as Default Browser''', 'desc': '''Configures the default browser checks in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> and prevents users from changing them. @@ -150,6 +160,7 @@ 'supported_on': ['chrome.win:8-'], 'features': {'dynamic_refresh': 0}, 'example_value': 'en', + 'id': 4, 'caption': '''Application locale''', 'desc': '''Configures the application locale in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> and prevents users from changing the locale. @@ -164,6 +175,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': True, + 'id': 5, 'caption': '''Enable alternate error pages''', 'desc': '''Enables the use of alternate error pages that are built into <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> (such as 'page not found') and prevents users from changing this setting. @@ -179,6 +191,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': True, + 'id': 6, 'caption': '''Enable search suggestions''', 'desc': '''Enables search suggestions in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>'s Omnibox and prevents users from changing this setting. @@ -194,6 +207,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': True, + 'id': 7, 'caption': '''Enable DNS prefetching''', 'desc': '''Enables DNS prefetching in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> and prevents users from changing this setting. @@ -205,6 +219,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': True, + 'id': 8, 'caption': '''Disable SPDY protocol''', 'desc': '''Disables use of the SPDY protocol in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>.''', }, @@ -214,6 +229,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 0}, 'example_value': True, + 'id': 9, 'caption': '''Enable JavaScript''', 'desc': '''Enables JavaScript in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> and prevents users from changing this setting. @@ -227,6 +243,7 @@ 'supported_on': ['chrome.*:11-'], 'features': {'dynamic_refresh': 1}, 'example_value': False, + 'id': 10, 'caption': '''Enable Incognito mode''', 'desc': '''Enables Incognito mode in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>. @@ -240,6 +257,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': True, + 'id': 11, 'caption': '''Disable saving browser history''', 'desc': '''Disables saving browser history in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> and prevents users from changing this setting. @@ -253,6 +271,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': True, + 'id': 12, 'caption': '''Enable printing''', 'desc': '''Enables printing in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> and prevents users from changing this setting. @@ -267,6 +286,7 @@ 'features': {'dynamic_refresh': 1}, 'future': True, 'example_value': True, + 'id': 13, 'caption': '''Enable <ph name="CLOUD_PRINT_NAME">Google Cloud Print</ph> proxy''', 'desc': ''' Enables <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> to act as a proxy between <ph name="CLOUD_PRINT_NAME">Google Cloud Print</ph> and legacy printers connected to the machine. @@ -280,6 +300,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 0}, 'example_value': True, + 'id': 14, 'caption': '''Enable Safe Browsing''', 'desc': '''Enables <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>'s Safe Browsing feature and prevents users from changing this setting. @@ -295,6 +316,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 0}, 'example_value': True, + 'id': 15, 'caption': '''Enable reporting of usage and crash-related data''', 'desc': '''Enables anonymous reporting of usage and crash-related data about <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> to Google and prevents users from changing this setting. @@ -316,6 +338,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': True, + 'id': 16, 'caption': '''Enable the password manager''', 'desc': '''Enables saving passwords and using saved passwords in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>. @@ -331,6 +354,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': False, + 'id': 17, 'caption': '''Allow users to show passwords in Password Manager''', 'desc': '''Controls whether the user may show passwords in clear text in the password manager. @@ -346,6 +370,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': False, + 'id': 18, 'caption': '''Enable AutoFill''', 'desc': '''Enables <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>'s AutoFill feature and allows users to auto complete web forms using previously stored information such as address or credit card information. @@ -359,6 +384,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': ['Java', 'Shockwave Flash', 'Chrome PDF Viewer'], + 'id': 19, 'caption': '''Specify a list of disabled plugins''', 'desc': '''Specifies a list of plugins that are disabled in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> and prevents users from changing this setting. @@ -373,6 +399,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': True, + 'id': 20, 'caption': '''Disable synchronization of data with Google''', 'desc': '''Disables data synchronization in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> using Google-hosted synchronization services and prevents users from changing this setting. @@ -384,6 +411,7 @@ 'supported_on': ['chrome.win:11-', 'chrome.mac:11-'], 'features': {'dynamic_refresh': 0}, 'example_value': '${user_home}\Chrome', + 'id': 63, 'caption': '''Set user data directory''', 'desc': '''Configures the directory that <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will use for storing user data. @@ -438,6 +466,7 @@ 'supported_on': ['chrome.*:10-'], 'features': {'dynamic_refresh': 1}, 'example_value': 'direct', + 'id': 21, 'caption': '''Choose how to specify proxy server settings''', 'desc': '''Allows you to specify the proxy server used by <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> and prevents users from changing proxy settings. @@ -481,7 +510,9 @@ ], 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, + 'deprecated': True, 'example_value': 2, + 'id': 22, 'caption': '''Choose how to specify proxy server settings''', 'desc': '''This policy is deprecated, use ProxyMode instead. @@ -504,6 +535,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': '123.123.123.123:8080', + 'id': 23, 'caption': '''Address or URL of proxy server''', 'desc': '''You can specify the URL of the proxy server here. @@ -518,6 +550,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': 'http://internal.site/example.pac', + 'id': 24, 'caption': '''URL to a proxy .pac file''', 'desc': '''You can specify a URL to a proxy .pac file here. @@ -532,6 +565,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': 'http://www.example1.com,http://www.example2.com,http://internalsite/', + 'id': 25, 'caption': '''Proxy bypass rules''', 'desc': '''<ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will bypass any proxy for the list of hosts given here. @@ -555,6 +589,7 @@ 'supported_on': ['chrome.*:9-'], 'features': {'dynamic_refresh': 0}, 'example_value': 'basic,digest,ntlm,negotiate', + 'id': 26, 'caption': '''Supported authentication schemes''', 'desc': '''Specifies which HTTP Authentication schemes are supported by <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>. @@ -566,6 +601,7 @@ 'supported_on': ['chrome.*:9-'], 'features': {'dynamic_refresh': 0}, 'example_value': False, + 'id': 27, 'caption': '''Disable CNAME lookup when negotiating Kerberos authentication''', 'desc': '''Specifies whether the generated Kerberos SPN is based on the canonical DNS name or the original name entered. @@ -579,6 +615,7 @@ 'supported_on': ['chrome.*:9-'], 'features': {'dynamic_refresh': 0}, 'example_value': False, + 'id': 28, 'caption': '''Include non-standard port in Kerberos SPN''', 'desc': '''Specifies whether the generated Kerberos SPN should include a non-standard port. @@ -592,6 +629,7 @@ 'supported_on': ['chrome.*:9-'], 'features': {'dynamic_refresh': 0}, 'example_value': '*example.com,foobar.com,*baz', + 'id': 29, 'caption': '''Authentication server whitelist''', 'desc': '''Specifies which servers should be whitelisted for integrated authentication. Integrated authentication is only enabled when <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> receives an authentication challenge from a proxy or from a server which is in this permitted list. @@ -603,6 +641,7 @@ 'supported_on': ['chrome.*:9-'], 'features': {'dynamic_refresh': 0}, 'example_value': 'foobar.example.com', + 'id': 30, 'caption': '''Kerberos delegation server whitelist''', 'desc': '''Servers that <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> may delegate to.''', }, @@ -612,6 +651,7 @@ 'supported_on': ['chrome.linux:9-', 'chrome.mac:9-'], 'features': {'dynamic_refresh': 0}, 'example_value': 'libgssapi_krb5.so.2', + 'id': 31, 'caption': '''GSSAPI library name''', 'desc': '''Specifies which GSSAPI library to use for HTTP Authentication. You can set either just a library name, or a full path. If no setting is provided, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will fall back to using a default library name.''', }, @@ -629,6 +669,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': ['extension_id1', 'extension_id2'], + 'id': 32, 'caption': '''Configure extension installation blacklist''', 'desc': '''Allows you to specify which extensions the users can NOT install. Extensions already installed will be removed if blacklisted. @@ -641,6 +682,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': ['extension_id1', 'extension_id2'], + 'id': 33, 'caption': '''Configure extension installation whitelist''', 'desc': '''Allows you to specify which extensions are not subject to the blacklist. @@ -655,6 +697,7 @@ 'supported_on': ['chrome.*:9-'], 'features': {'dynamic_refresh': 1}, 'example_value': ['lcncmkcnkcdbbanbjakcencbaoegdjlp;https://clients2.google.com/service/update2/crx'], + 'id': 34, 'caption': '''Configure the list of force-installed extensions''', 'desc': '''Allows you to specify a list of extensions that will be installed silently, without user interaction. @@ -671,6 +714,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': True, + 'id': 35, 'caption': '''Show Home button on toolbar''', 'desc': '''Shows the Home button on <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>'s toolbar. @@ -686,6 +730,7 @@ 'supported_on': ['chrome.*:9-'], 'features': {'dynamic_refresh': 1}, 'example_value': False, + 'id': 36, 'caption': '''Disable Developer Tools''', 'desc': '''Disables the Developer Tools and the JavaScript console. @@ -722,6 +767,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': 4, + 'id': 37, 'caption': '''Action on startup''', 'desc': '''Allows you to specify the behavior on startup. @@ -739,12 +785,27 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': ['http://example.com', 'http://chromium.org'], + 'id': 38, 'caption': '''URLs to open on startup''', 'desc': '''If 'Open a list of URLs' is selected as the startup action, this allows you to specify the list of URLs that are opened.''', }, ], }, { + 'name': 'BlockThirdPartyCookies', + 'type': 'main', + 'supported_on': ['chrome.*:10-'], + 'features': {'dynamic_refresh': 1}, + 'example_value': False, + 'id': 39, + 'caption': '''Block third party cookies''', + 'desc': '''Blocks third party cookies. + + Enabling this setting prevents cookies from being set by web page elements that are not from the domain that is in the browser's address bar. + + Disabling this setting allows cookies to be set by web page elements that are not from the domain that is in the browser's address bar and prevents users from changing this setting.''', + }, + { 'name': 'DefaultSearchProvider', 'type': 'group', 'caption': '''Default search provider''', @@ -756,6 +817,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': True, + 'id': 40, 'caption': '''Enable the default search provider''', 'desc': '''Enables the use of a default search provider. @@ -770,24 +832,12 @@ </ph>.''', }, { - 'name': 'BlockThirdPartyCookies', - 'type': 'main', - 'supported_on': ['chrome.*:10-'], - 'features': {'dynamic_refresh': 1}, - 'example_value': False, - 'caption': '''Block third party cookies''', - 'desc': '''Blocks third party cookies. - - Enabling this setting prevents cookies from being set by web page elements that are not from the domain that is in the browser's address bar. - - Disabling this setting allows cookies to be set by web page elements that are not from the domain that is in the browser's address bar and prevents users from changing this setting.''', - }, - { 'name': 'DefaultSearchProviderName', 'type': 'string', 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': 'My Intranet Search', + 'id': 41, 'caption': '''Default search provider name''', 'desc': '''Specifies the name of the default search provider. If left empty, the host name specified by the search URL will be used.''', }, @@ -797,6 +847,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': 'mis', + 'id': 42, 'caption': '''Default search provider keyword''', 'desc': '''Specifies the keyword, which is the shortcut used in the omnibox to trigger the search for this provider. Optional.''', }, @@ -806,6 +857,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': 'http://search.my.company/search?q={searchTerms}', + 'id': 43, 'caption': '''Default search provider search URL''', 'desc': '''Specifies the URL of the search engine used when doing a default search. The URL should contain the string '<ph name="SEARCH_TERM_MARKER">{searchTerms}</ph>', which will be replaced at query time by the terms the user is searching for.''', }, @@ -815,6 +867,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': 'http://search.my.company/suggest?q={searchTerms}', + 'id': 44, 'caption': '''Default search provider suggest URL''', 'desc': '''Specifies the URL of the search engine used to provide search suggestions. The URL should contain the string '<ph name="SEARCH_TERM_MARKER">{searchTerms}</ph>', which will be replaced at query time by the text the user has entered so far. Optional.''', }, @@ -824,6 +877,7 @@ 'supported_on': ['chrome.*:10-'], 'features': {'dynamic_refresh': 1}, 'example_value': 'http://search.my.company/suggest?q={searchTerms}', + 'id': 45, 'caption': '''Default search provider instant URL''', 'desc': '''Specifies the URL of the search engine used to provide instant results. The URL should contain the string <ph name="SEARCH_TERM_MARKER">'{searchTerms}'</ph>, which will be replaced at query time by the text the user has entered so far. Optional.''', }, @@ -833,6 +887,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': 'http://search.my.company/favicon.ico', + 'id': 46, 'caption': '''Default search provider icon''', 'desc': '''Specifies the favorite icon URL of the default search provider. Optional.''', }, @@ -842,6 +897,7 @@ 'supported_on': ['chrome.*:8-'], 'features': {'dynamic_refresh': 1}, 'example_value': ['UTF-8', 'UTF-16', 'GB2312', 'ISO-8859-1'], + 'id': 47, 'caption': '''Default search provider encodings''', 'desc': '''Specifies the character encodings supported by the search provider. Encodings are code page names like UTF-8, GB2312, and ISO-8859-1. They are tried in the order provided. The default is UTF-8.''', }, @@ -871,6 +927,7 @@ 'supported_on': ['chrome.*:10-'], 'features': {'dynamic_refresh': 1}, 'example_value': 0, + 'id': 48, 'caption': '''Default cookies setting''', 'desc': '''Allows you to set whether websites are allowed to set local data. Setting local data can be either allowed for all websites or denied for all websites.''', }, @@ -892,6 +949,7 @@ 'supported_on': ['chrome.*:10-'], 'features': {'dynamic_refresh': 1}, 'example_value': 0, + 'id': 49, 'caption': '''Default images setting''', 'desc': '''Allows you to set whether websites are allowed to display images. Displaying images can be either allowed for all websites or denied for all websites.''', }, @@ -913,6 +971,7 @@ 'supported_on': ['chrome.*:10-'], 'features': {'dynamic_refresh': 1}, 'example_value': 0, + 'id': 50, 'caption': '''Default JavaScript setting''', 'desc': '''Allows you to set whether websites are allowed to run JavaScript. Running JavaScript can be either allowed for all websites or denied for all websites.''', }, @@ -934,6 +993,7 @@ 'supported_on': ['chrome.*:10-'], 'features': {'dynamic_refresh': 1}, 'example_value': 0, + 'id': 51, 'caption': '''Default plugins setting''', 'desc': '''Allows you to set whether websites are allowed to automatically run plugins. Automatically running plugins can be either allowed for all websites or denied for all websites.''', }, @@ -955,6 +1015,7 @@ 'supported_on': ['chrome.*:10-'], 'features': {'dynamic_refresh': 1}, 'example_value': 1, + 'id': 52, 'caption': '''Default popups setting''', 'desc': '''Allows you to set whether websites are allowed to show pop-ups. Showing popups can be either allowed for all websites or denied for all websites.''', }, @@ -981,6 +1042,7 @@ 'supported_on': ['chrome.*:10-'], 'features': {'dynamic_refresh': 1}, 'example_value': 2, + 'id': 53, 'caption': '''Default notification setting''', 'desc': '''Allows you to set whether websites are allowed to display desktop notifications. Displaying desktop notifications can be allowed by default, denied by default or the user can be asked everytime a website wants to show desktop notifications.''', }, @@ -1007,6 +1069,7 @@ 'supported_on': ['chrome.*:10-'], 'features': {'dynamic_refresh': 1}, 'example_value': 0, + 'id': 54, 'caption': '''Default geolocation setting''', 'desc': '''Allows you to set whether websites are allowed to track the users' physical location. Tracking the users' physical location can be allowed by default, denied by default or the user can be asked everytime a website requests the pysical location.''', }, @@ -1018,6 +1081,7 @@ 'supported_on': ['chrome.*:9-'], 'features': {'dynamic_refresh': 0}, 'example_value': False, + 'id': 55, 'caption': '''Disable support for 3D graphics APIs''', 'desc': '''Disable support for 3D graphics APIs. @@ -1031,6 +1095,7 @@ 'supported_on': ['chrome_os:1.0.0.0-'], 'features': {'dynamic_refresh': 1}, 'example_value': 3600000, + 'id': 56, 'caption': '''Policy refresh rate''', 'desc': '''Specifies the period in milliseconds at which the device management service is queried for policy information. @@ -1064,6 +1129,7 @@ 'supported_on': ['chrome_frame:8-'], 'features': {'dynamic_refresh': 0}, 'example_value': 1, + 'id': 57, 'caption': '''Default HTML renderer for <ph name="PRODUCT_FRAME_NAME">$3<ex>Google Chrome Frame</ex></ph>''', 'desc': '''Allows you to configure the default HTML renderer when <ph name="PRODUCT_FRAME_NAME">$3<ex>Google Chrome Frame</ex> </ph> is installed. @@ -1077,6 +1143,7 @@ 'supported_on': ['chrome_frame:8-'], 'features': {'dynamic_refresh': 0}, 'example_value': ['http://www.example.com', 'http://www.example.edu'], + 'id': 58, 'caption': '''Always render the following URL patterns in <ph name="PRODUCT_FRAME_NAME">$3<ex>Google Chrome Frame</ex></ph>''', 'desc': '''Customize the list of URL patterns that should always be rendered by <ph name="PRODUCT_FRAME_NAME">$3<ex>Google Chrome Frame</ex></ph>. @@ -1088,6 +1155,7 @@ 'supported_on': ['chrome_frame:8-'], 'features': {'dynamic_refresh': 0}, 'example_value': ['http://www.example.com', 'http://www.example.edu'], + 'id': 59, 'caption': '''Always render the following URL patterns in the host browser''', 'desc': '''Customize the list of URL patterns that should always be rendered by the host browser. For example patterns see http://www.chromium.org/developers/how-tos/chrome-frame-getting-started.''', @@ -1106,6 +1174,7 @@ 'supported_on': ['chrome_frame:8-'], 'features': {'dynamic_refresh': 0}, 'example_value': ['text/xml', 'application/xml'], + 'id': 60, 'caption': '''Allow <ph name="PRODUCT_FRAME_NAME">$3<ex>Google Chrome Frame</ex></ph> to handle the following content types.''', 'desc': '''Allow <ph name="PRODUCT_FRAME_NAME">$3<ex>Google Chrome Frame</ex></ph> to handle the following content types.''', }, @@ -1117,6 +1186,7 @@ 'supported_on': ['chrome_os:0.9.79.0-'], 'features': {'dynamic_refresh': 1}, 'example_value': True, + 'id': 61, 'caption': '''Enable lock when ChromeOS devices become idle or suspended.''', 'desc': '''Enable lock when ChromeOS devices become idle or suspended. @@ -1132,6 +1202,7 @@ 'supported_on': ['chrome.*:11-'], 'features': {'dynamic_refresh': 1}, 'example_value': True, + 'id': 62, 'caption': '''Enable Instant''', 'desc': '''Enables <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>'s Instant feature and prevents users from changing this setting. diff --git a/chrome/app/policy/syntax_check_policy_template_json.py b/chrome/app/policy/syntax_check_policy_template_json.py index d332254..3cc36cb 100644 --- a/chrome/app/policy/syntax_check_policy_template_json.py +++ b/chrome/app/policy/syntax_check_policy_template_json.py @@ -81,7 +81,29 @@ class PolicyTemplateChecker(object): container_name, identifier, value) return value - def _CheckPolicy(self, policy, may_contain_groups): + def _AddPolicyID(self, id, policy_ids, policy): + ''' + Adds |id| to |policy_ids|. Generates an error message if the + |id| exists already; |policy| is needed for this message. + ''' + if id in policy_ids: + self._Error('Duplicate id', 'policy', policy.get('name'), + id) + else: + policy_ids.add(id) + + def _CheckPolicyIDs(self, policy_ids): + ''' + Checks a set of policy_ids to make sure it contains a continuous range + of entries (i.e. no holes). + Holes would not be a technical problem, but we want to ensure that nobody + accidentally omits IDs. + ''' + for i in range(len(policy_ids)): + if (i + 1) not in policy_ids: + self._Error('No policy with id: %s' % (i + 1)) + + def _CheckPolicy(self, policy, is_in_group, policy_ids): if not isinstance(policy, dict): self._Error('Each policy must be a dictionary.', 'policy', None, policy) return @@ -90,7 +112,7 @@ class PolicyTemplateChecker(object): for key in policy: if key not in ('name', 'type', 'caption', 'desc', 'supported_on', 'label', 'policies', 'items', 'example_value', 'features', - 'deprecated', 'future'): + 'deprecated', 'future', 'id'): self.warning_count += 1 print ('In policy %s: Warning: Unknown key: %s' % (policy.get('name'), key)) @@ -124,26 +146,37 @@ class PolicyTemplateChecker(object): if policy_type == 'group': # Groups must not be nested. - if not may_contain_groups: + if is_in_group: self._Error('Policy groups must not be nested.', 'policy', policy) # Each policy group must have a list of policies. policies = self._CheckContains(policy, 'policies', list) + + # Check sub-policies. if policies is not None: for nested_policy in policies: - self._CheckPolicy(nested_policy, False) + self._CheckPolicy(nested_policy, True, policy_ids) + + # Groups must not have an |id|. + if 'id' in policy: + self._Error('Policies of type "group" must not have an "id" field.', + 'policy', policy) # Statistics. self.num_groups += 1 else: # policy_type != group + # Each policy must have a protobuf ID. + id = self._CheckContains(policy, 'id', int) + self._AddPolicyID(id, policy_ids, policy) + # Each policy must have a supported_on list. supported_on = self._CheckContains(policy, 'supported_on', list) if supported_on is not None: for s in supported_on: if not isinstance(s, str): self._Error('Entries in "supported_on" must be strings.', 'policy', - policy, supported_on) + policy, supported_on) # Each policy must have a 'features' dict. self._CheckContains(policy, 'features', dict) @@ -163,7 +196,7 @@ class PolicyTemplateChecker(object): # Statistics. self.num_policies += 1 - if not may_contain_groups: + if is_in_group: self.num_policies_in_groups += 1 if policy_type in ('int-enum', 'string-enum'): @@ -336,8 +369,10 @@ class PolicyTemplateChecker(object): container_name='The root element', offending=None) if policy_definitions is not None: + policy_ids = set() for policy in policy_definitions: - self._CheckPolicy(policy, True) + self._CheckPolicy(policy, False, policy_ids) + self._CheckPolicyIDs(policy_ids) # Check (non-policy-specific) message definitions. messages = self._CheckContains(data, 'messages', dict, @@ -361,8 +396,8 @@ class PolicyTemplateChecker(object): self._CheckFormat(filename) # Third part: summary and exit. - print ('Finished. %d errors, %d warnings.' % - (self.error_count, self.warning_count)) + print ('Finished checking %s. %d errors, %d warnings.' % + (filename, self.error_count, self.warning_count)) if self.options.stats: if self.num_groups > 0: print ('%d policies, %d of those in %d groups (containing on ' diff --git a/chrome/browser/policy/asynchronous_policy_provider.cc b/chrome/browser/policy/asynchronous_policy_provider.cc index e697b05..9b050ad 100644 --- a/chrome/browser/policy/asynchronous_policy_provider.cc +++ b/chrome/browser/policy/asynchronous_policy_provider.cc @@ -25,7 +25,7 @@ bool AsynchronousPolicyProvider::Provide( ConfigurationPolicyStoreInterface* store) { DCHECK(CalledOnValidThread()); DCHECK(loader_->policy()); - DecodePolicyValueTree(loader_->policy(), store); + ApplyPolicyValueTree(loader_->policy(), store); return true; } diff --git a/chrome/browser/policy/cloud_policy_cache.cc b/chrome/browser/policy/cloud_policy_cache.cc new file mode 100644 index 0000000..3bf69fb --- /dev/null +++ b/chrome/browser/policy/cloud_policy_cache.cc @@ -0,0 +1,429 @@ +// Copyright (c) 2011 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/policy/cloud_policy_cache.h" + +#include <limits> + +#include "base/file_util.h" +#include "base/logging.h" +#include "base/task.h" +#include "base/values.h" +#include "chrome/browser/browser_thread.h" +#include "chrome/browser/policy/proto/cloud_policy.pb.h" +#include "chrome/browser/policy/proto/device_management_backend.pb.h" +#include "chrome/browser/policy/proto/device_management_constants.h" +#include "chrome/browser/policy/proto/device_management_local.pb.h" + +using google::protobuf::RepeatedField; +using google::protobuf::RepeatedPtrField; + +// This CloudPolicyCache currently supports two protocols for the interaction +// with DMServer: the old "DevicePolicy" format, which is being used in the +// CrOS Pilot Program and will be deprecated afterwards, and the new +// "CloudPolicy" format, which will be used exclusively after the public launch +// of ChromeOS. + +namespace policy { + +// Decodes a CloudPolicySettings object into two maps with mandatory and +// recommended settings, respectively. The implementation is generated code +// in policy/cloud_policy_generated.cc. +void DecodePolicy(const em::CloudPolicySettings& policy, + ConfigurationPolicyProvider::PolicyMapType* mandatory, + ConfigurationPolicyProvider::PolicyMapType* recommended); + +// Saves policy information to a file. +class PersistPolicyTask : public Task { + public: + PersistPolicyTask(const FilePath& path, + const em::CloudPolicyResponse* cloud_policy_response, + const em::DevicePolicyResponse* device_policy_response, + const bool is_unmanaged) + : path_(path), + cloud_policy_response_(cloud_policy_response), + device_policy_response_(device_policy_response), + is_unmanaged_(is_unmanaged) {} + + private: + // Task override. + virtual void Run(); + + const FilePath path_; + scoped_ptr<const em::CloudPolicyResponse> cloud_policy_response_; + scoped_ptr<const em::DevicePolicyResponse> device_policy_response_; + const bool is_unmanaged_; +}; + +void PersistPolicyTask::Run() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + std::string data; + em::CachedCloudPolicyResponse cached_policy; + if (cloud_policy_response_.get()) { + cached_policy.mutable_cloud_policy()->CopyFrom(*cloud_policy_response_); + } else if (device_policy_response_.get()) { + cached_policy.mutable_device_policy()->CopyFrom(*device_policy_response_); + cached_policy.set_timestamp(base::Time::NowFromSystemTime().ToTimeT()); + } + if (is_unmanaged_) { + cached_policy.set_unmanaged(true); + cached_policy.set_timestamp(base::Time::NowFromSystemTime().ToTimeT()); + } + if (!cached_policy.SerializeToString(&data)) { + LOG(WARNING) << "Failed to serialize policy data"; + return; + } + + int size = data.size(); + if (file_util::WriteFile(path_, data.c_str(), size) != size) { + LOG(WARNING) << "Failed to write " << path_.value(); + return; + } +} + +CloudPolicyCache::CloudPolicyCache( + const FilePath& backing_file_path) + : backing_file_path_(backing_file_path), + device_policy_(new DictionaryValue), + fresh_policy_(false), + is_unmanaged_(false), + has_device_policy_(false) { +} + +CloudPolicyCache::~CloudPolicyCache() {} + +void CloudPolicyCache::LoadPolicyFromFile() { + // TODO(jkummerow): This method is doing file IO during browser startup. In + // the long run it would be better to delay this until the FILE thread exists. + if (!file_util::PathExists(backing_file_path_) || fresh_policy_) { + return; + } + + // Read the protobuf from the file. + std::string data; + if (!file_util::ReadFileToString(backing_file_path_, &data)) { + LOG(WARNING) << "Failed to read policy data from " + << backing_file_path_.value(); + return; + } + + em::CachedCloudPolicyResponse cached_response; + if (!cached_response.ParseFromArray(data.c_str(), data.size())) { + LOG(WARNING) << "Failed to parse policy data read from " + << backing_file_path_.value(); + return; + } + base::Time timestamp; + PolicyMapType mandatory_policy; + PolicyMapType recommended_policy; + is_unmanaged_ = cached_response.unmanaged(); + if (is_unmanaged_ || cached_response.has_device_policy()) + timestamp = base::Time::FromTimeT(cached_response.timestamp()); + if (cached_response.has_cloud_policy()) { + DCHECK(!is_unmanaged_); + bool ok = DecodePolicyResponse(cached_response.cloud_policy(), + &mandatory_policy, + &recommended_policy, + ×tamp); + if (!ok) { + LOG(WARNING) << "Decoding policy data failed."; + return; + } + } + if (timestamp > base::Time::NowFromSystemTime()) { + LOG(WARNING) << "Rejected policy data from " << backing_file_path_.value() + << ", file is from the future."; + return; + } + // Swap in the new policy information. + if (is_unmanaged_) { + base::AutoLock lock(lock_); + last_policy_refresh_time_ = timestamp; + return; + } else if (cached_response.has_cloud_policy()) { + if (!fresh_policy_) { + base::AutoLock lock(lock_); + mandatory_policy_.swap(mandatory_policy); + recommended_policy_.swap(recommended_policy); + last_policy_refresh_time_ = timestamp; + has_device_policy_ = false; + } + } else if (cached_response.has_device_policy()) { + scoped_ptr<DictionaryValue> value( + DecodeDevicePolicy(cached_response.device_policy())); + if (!fresh_policy_) { + base::AutoLock lock(lock_); + device_policy_.reset(value.release()); + last_policy_refresh_time_ = timestamp; + has_device_policy_ = true; + } + } +} + +bool CloudPolicyCache::SetPolicy(const em::CloudPolicyResponse& policy) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + is_unmanaged_ = false; + base::Time timestamp; + PolicyMapType mandatory_policy; + PolicyMapType recommended_policy; + bool ok = DecodePolicyResponse(policy, &mandatory_policy, &recommended_policy, + ×tamp); + if (!ok) { + // TODO(jkummerow): Signal error to PolicyProvider. + return false; + } + const bool new_policy_differs = + !Equals(mandatory_policy, mandatory_policy_) || + !Equals(recommended_policy, recommended_policy_); + { + base::AutoLock lock(lock_); + mandatory_policy_.swap(mandatory_policy); + recommended_policy_.swap(recommended_policy); + fresh_policy_ = true; + last_policy_refresh_time_ = timestamp; + has_device_policy_ = false; + } + + if (timestamp > base::Time::NowFromSystemTime() + + base::TimeDelta::FromMinutes(1)) { + LOG(WARNING) << "Server returned policy with timestamp from the future, " + "not persisting to disk."; + } else { + em::CloudPolicyResponse* policy_copy = new em::CloudPolicyResponse; + policy_copy->CopyFrom(policy); + BrowserThread::PostTask( + BrowserThread::FILE, + FROM_HERE, + new PersistPolicyTask(backing_file_path_, policy_copy, NULL, false)); + } + return new_policy_differs; +} + +bool CloudPolicyCache::SetDevicePolicy(const em::DevicePolicyResponse& policy) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + is_unmanaged_ = false; + DictionaryValue* value = DecodeDevicePolicy(policy); + const bool new_policy_differs = !(value->Equals(device_policy_.get())); + base::Time now(base::Time::NowFromSystemTime()); + { + base::AutoLock lock(lock_); + device_policy_.reset(value); + fresh_policy_ = true; + last_policy_refresh_time_ = now; + has_device_policy_ = true; + } + + em::DevicePolicyResponse* policy_copy = new em::DevicePolicyResponse; + policy_copy->CopyFrom(policy); + BrowserThread::PostTask( + BrowserThread::FILE, + FROM_HERE, + new PersistPolicyTask(backing_file_path_, NULL, policy_copy, false)); + return new_policy_differs; +} + +DictionaryValue* CloudPolicyCache::GetDevicePolicy() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + base::AutoLock lock(lock_); + return device_policy_->DeepCopy(); +} + +const CloudPolicyCache::PolicyMapType* + CloudPolicyCache::GetMandatoryPolicy() const { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + return &mandatory_policy_; +} + +const CloudPolicyCache::PolicyMapType* + CloudPolicyCache::GetRecommendedPolicy() const { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + return &recommended_policy_; +} + +void CloudPolicyCache::SetUnmanaged() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + is_unmanaged_ = true; + { + base::AutoLock lock(lock_); + mandatory_policy_.clear(); + recommended_policy_.clear(); + device_policy_.reset(new DictionaryValue); + last_policy_refresh_time_ = base::Time::NowFromSystemTime(); + } + BrowserThread::PostTask( + BrowserThread::FILE, + FROM_HERE, + new PersistPolicyTask(backing_file_path_, NULL, NULL, true)); +} + +// static +bool CloudPolicyCache::DecodePolicyResponse( + const em::CloudPolicyResponse& policy_response, + PolicyMapType* mandatory, + PolicyMapType* recommended, + base::Time* timestamp) { + std::string data = policy_response.signed_response(); + + if (!VerifySignature(policy_response.signature(), data, + policy_response.certificate_chain())) { + LOG(WARNING) << "Failed to verify signature."; + return false; + } + + em::SignedCloudPolicyResponse response; + if (!response.ParseFromArray(data.c_str(), data.size())) { + LOG(WARNING) << "Failed to parse SignedCloudPolicyResponse protobuf."; + return false; + } + + // TODO(jkummerow): Verify response.device_token(). Needs final specification + // which token we're actually sending / expecting to get back. + + // TODO(jkummerow): Store response.device_name(), if we decide to transfer + // it from the server to the client. + + DCHECK(timestamp); + *timestamp = base::Time::FromTimeT(response.timestamp()); + DecodePolicy(response.settings(), mandatory, recommended); + return true; +} + +// static +bool CloudPolicyCache::VerifySignature( + const std::string& signature, + const std::string& data, + const RepeatedPtrField<std::string>& certificate_chain) { + // TODO(jkummerow): Implement this. Non-trivial because we want to do it + // for all platforms -> it's enough work to deserve its own CL. + // Don't forget to also verify the hostname of the server against the cert. + return true; +} + +// static +bool CloudPolicyCache::MapEntryEquals(const PolicyMapType::value_type& a, + const PolicyMapType::value_type& b) { + return a.first == b.first && Value::Equals(a.second, b.second); +} + +// static +bool CloudPolicyCache::Equals(const PolicyMapType& a, const PolicyMapType& b) { + return a.size() == b.size() && + std::equal(a.begin(), a.end(), b.begin(), MapEntryEquals); +} + +// static +Value* CloudPolicyCache::DecodeIntegerValue(google::protobuf::int64 value) { + if (value < std::numeric_limits<int>::min() || + value > std::numeric_limits<int>::max()) { + LOG(WARNING) << "Integer value " << value + << " out of numeric limits, ignoring."; + return NULL; + } + + return Value::CreateIntegerValue(static_cast<int>(value)); +} + +// static +Value* CloudPolicyCache::DecodeValue(const em::GenericValue& value) { + if (!value.has_value_type()) + return NULL; + + switch (value.value_type()) { + case em::GenericValue::VALUE_TYPE_BOOL: + if (value.has_bool_value()) + return Value::CreateBooleanValue(value.bool_value()); + return NULL; + case em::GenericValue::VALUE_TYPE_INT64: + if (value.has_int64_value()) + return DecodeIntegerValue(value.int64_value()); + return NULL; + case em::GenericValue::VALUE_TYPE_STRING: + if (value.has_string_value()) + return Value::CreateStringValue(value.string_value()); + return NULL; + case em::GenericValue::VALUE_TYPE_DOUBLE: + if (value.has_double_value()) + return Value::CreateDoubleValue(value.double_value()); + return NULL; + case em::GenericValue::VALUE_TYPE_BYTES: + if (value.has_bytes_value()) { + std::string bytes = value.bytes_value(); + return BinaryValue::CreateWithCopiedBuffer(bytes.c_str(), bytes.size()); + } + return NULL; + case em::GenericValue::VALUE_TYPE_BOOL_ARRAY: { + ListValue* list = new ListValue; + RepeatedField<bool>::const_iterator i; + for (i = value.bool_array().begin(); i != value.bool_array().end(); ++i) + list->Append(Value::CreateBooleanValue(*i)); + return list; + } + case em::GenericValue::VALUE_TYPE_INT64_ARRAY: { + ListValue* list = new ListValue; + RepeatedField<google::protobuf::int64>::const_iterator i; + for (i = value.int64_array().begin(); + i != value.int64_array().end(); ++i) { + Value* int_value = DecodeIntegerValue(*i); + if (int_value) + list->Append(int_value); + } + return list; + } + case em::GenericValue::VALUE_TYPE_STRING_ARRAY: { + ListValue* list = new ListValue; + RepeatedPtrField<std::string>::const_iterator i; + for (i = value.string_array().begin(); + i != value.string_array().end(); ++i) + list->Append(Value::CreateStringValue(*i)); + return list; + } + case em::GenericValue::VALUE_TYPE_DOUBLE_ARRAY: { + ListValue* list = new ListValue; + RepeatedField<double>::const_iterator i; + for (i = value.double_array().begin(); + i != value.double_array().end(); ++i) + list->Append(Value::CreateDoubleValue(*i)); + return list; + } + default: + NOTREACHED() << "Unhandled value type"; + } + + return NULL; +} + +// static +DictionaryValue* CloudPolicyCache::DecodeDevicePolicy( + const em::DevicePolicyResponse& policy) { + DictionaryValue* result = new DictionaryValue; + RepeatedPtrField<em::DevicePolicySetting>::const_iterator setting; + for (setting = policy.setting().begin(); + setting != policy.setting().end(); + ++setting) { + // Wrong policy key? Skip. + if (setting->policy_key().compare(kChromeDevicePolicySettingKey) != 0) + continue; + + // No policy value? Skip. + if (!setting->has_policy_value()) + continue; + + // Iterate through all the name-value pairs wrapped in |setting|. + const em::GenericSetting& policy_value(setting->policy_value()); + RepeatedPtrField<em::GenericNamedValue>::const_iterator named_value; + for (named_value = policy_value.named_value().begin(); + named_value != policy_value.named_value().end(); + ++named_value) { + if (named_value->has_value()) { + Value* decoded_value = + CloudPolicyCache::DecodeValue(named_value->value()); + if (decoded_value) + result->Set(named_value->name(), decoded_value); + } + } + } + return result; +} + +} // namespace policy diff --git a/chrome/browser/policy/cloud_policy_cache.h b/chrome/browser/policy/cloud_policy_cache.h new file mode 100644 index 0000000..20352ac --- /dev/null +++ b/chrome/browser/policy/cloud_policy_cache.h @@ -0,0 +1,141 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_POLICY_CLOUD_POLICY_CACHE_H_ +#define CHROME_BROWSER_POLICY_CLOUD_POLICY_CACHE_H_ + +#include <string> + +#include "base/file_path.h" +#include "base/gtest_prod_util.h" +#include "base/ref_counted.h" +#include "base/scoped_ptr.h" +#include "base/synchronization/lock.h" +#include "base/time.h" +#include "chrome/browser/policy/configuration_policy_provider.h" +#include "chrome/browser/policy/proto/device_management_backend.pb.h" +#include "policy/configuration_policy_type.h" + +class DictionaryValue; +class ListValue; +class Value; + +using google::protobuf::RepeatedPtrField; + +namespace policy { + +namespace em = enterprise_management; + +// Keeps the authoritative copy of cloud policy information as read from the +// persistence file or determined by the policy backend. The cache doesn't talk +// to the service directly, but receives updated policy information through +// SetPolicy() calls, which is then persisted and decoded into the internal +// Value representation chrome uses. +class CloudPolicyCache { + public: + typedef ConfigurationPolicyProvider::PolicyMapType PolicyMapType; + + explicit CloudPolicyCache(const FilePath& backing_file_path); + ~CloudPolicyCache(); + + // Loads policy information from the backing file. Non-existing or erroneous + // cache files are ignored. + void LoadPolicyFromFile(); + + // Resets the policy information. Returns true if the new policy is different + // from the previously stored policy. + bool SetPolicy(const em::CloudPolicyResponse& policy); + bool SetDevicePolicy(const em::DevicePolicyResponse& policy); + + // Gets the policy information. Ownership of the return value is transferred + // to the caller. + DictionaryValue* GetDevicePolicy(); + const PolicyMapType* GetMandatoryPolicy() const; + const PolicyMapType* GetRecommendedPolicy() const; + + void SetUnmanaged(); + bool is_unmanaged() const { + return is_unmanaged_; + } + + // Returns the time at which the policy was last fetched. + base::Time last_policy_refresh_time() const { + return last_policy_refresh_time_; + } + + // Returns true if this cache holds (old-style) device policy that should be + // given preference over (new-style) mandatory/recommended policy. + bool has_device_policy() const { + return has_device_policy_; + } + + private: + friend class CloudPolicyCacheTest; + friend class DeviceManagementPolicyCacheDecodeTest; + + // Decodes a CloudPolicyResponse into two (ConfigurationPolicyType -> Value*) + // maps and a timestamp. Also performs verification, returns NULL if any + // check fails. + static bool DecodePolicyResponse( + const em::CloudPolicyResponse& policy_response, + PolicyMapType* mandatory, + PolicyMapType* recommended, + base::Time* timestamp); + + // Returns true if |certificate_chain| is trusted and a |signature| created + // from it matches |data|. + static bool VerifySignature( + const std::string& signature, + const std::string& data, + const RepeatedPtrField<std::string>& certificate_chain); + + // Returns true if |a| equals |b|. + static bool Equals(const PolicyMapType& a, const PolicyMapType& b); + // Helper function for the above. + static bool MapEntryEquals(const PolicyMapType::value_type& a, + const PolicyMapType::value_type& b); + + // Decodes an int64 value. Checks whether the passed value fits the numeric + // limits of the value representation. Returns a value (ownership is + // transferred to the caller) on success, NULL on failure. + static Value* DecodeIntegerValue(google::protobuf::int64 value); + + // Decode a GenericValue message to the Value representation used internally. + // Returns NULL if |value| is invalid (i.e. contains no actual value). + static Value* DecodeValue(const em::GenericValue& value); + + // Decodes a policy message and returns it in Value representation. Ownership + // of the returned dictionary is transferred to the caller. + static DictionaryValue* DecodeDevicePolicy( + const em::DevicePolicyResponse& response); + + // The file in which we store a cached version of the policy information. + const FilePath backing_file_path_; + + // Protects both |mandatory_policy_| and |recommended_policy_| as well as + // |device_policy_|. + base::Lock lock_; + + // Policy key-value information. + PolicyMapType mandatory_policy_; + PolicyMapType recommended_policy_; + scoped_ptr<DictionaryValue> device_policy_; + + // Tracks whether the store received a SetPolicy() call, which overrides any + // information loaded from the file. + bool fresh_policy_; + + bool is_unmanaged_; + + // Tracks whether the cache currently stores |device_policy_| that should be + // given preference over |mandatory_policy_| and |recommended_policy_|. + bool has_device_policy_; + + // The time at which the policy was last refreshed. + base::Time last_policy_refresh_time_; +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_CLOUD_POLICY_CACHE_H_ diff --git a/chrome/browser/policy/cloud_policy_cache_unittest.cc b/chrome/browser/policy/cloud_policy_cache_unittest.cc new file mode 100644 index 0000000..554ff48 --- /dev/null +++ b/chrome/browser/policy/cloud_policy_cache_unittest.cc @@ -0,0 +1,660 @@ +// Copyright (c) 2011 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/policy/cloud_policy_cache.h" + +#include <limits> +#include <string> + +#include "base/file_util.h" +#include "base/message_loop.h" +#include "base/scoped_temp_dir.h" +#include "base/values.h" +#include "chrome/browser/browser_thread.h" +#include "chrome/browser/policy/proto/cloud_policy.pb.h" +#include "chrome/browser/policy/proto/device_management_backend.pb.h" +// TODO(jkummerow): remove this import when removing old DMPC test cases. +#include "chrome/browser/policy/proto/device_management_constants.h" +#include "chrome/browser/policy/proto/device_management_local.pb.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace policy { + +// Decodes a CloudPolicySettings object into two maps with mandatory and +// recommended settings, respectively. The implementation is generated code +// in policy/cloud_policy_generated.cc. +void DecodePolicy(const em::CloudPolicySettings& policy, + ConfigurationPolicyProvider::PolicyMapType* mandatory, + ConfigurationPolicyProvider::PolicyMapType* recommended); + +// The implementations of these methods are in cloud_policy_generated.cc. +Value* DecodeIntegerValue(google::protobuf::int64 value); +ListValue* DecodeStringList(const em::StringList& string_list); + +// Tests the device management policy cache. +class CloudPolicyCacheTest : public testing::Test { + protected: + typedef ConfigurationPolicyProvider::PolicyMapType PolicyMapType; + + CloudPolicyCacheTest() + : loop_(MessageLoop::TYPE_UI), + ui_thread_(BrowserThread::UI, &loop_), + file_thread_(BrowserThread::FILE, &loop_) {} + + void SetUp() { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + } + + void TearDown() { + loop_.RunAllPending(); + } + + // Creates a (signed) CloudPolicyResponse setting the given |homepage| and + // featuring the given |timestamp| (as issued by the server). + // Mildly hacky special feature: pass an empty string as |homepage| to get + // a completely empty policy. + em::CloudPolicyResponse* CreateHomepagePolicy( + const std::string& homepage, + const base::Time& timestamp, + const em::PolicyOptions::PolicyMode policy_mode) { + em::SignedCloudPolicyResponse signed_response; + if (homepage != "") { + em::CloudPolicySettings* settings = signed_response.mutable_settings(); + em::HomepageLocationProto* homepagelocation_proto = + settings->mutable_homepagelocation(); + homepagelocation_proto->set_homepagelocation(homepage); + homepagelocation_proto->mutable_policy_options()->set_mode(policy_mode); + } + signed_response.set_timestamp(timestamp.ToTimeT()); + std::string serialized_signed_response; + EXPECT_TRUE(signed_response.SerializeToString(&serialized_signed_response)); + + em::CloudPolicyResponse* response = new em::CloudPolicyResponse; + response->set_signed_response(serialized_signed_response); + // TODO(jkummerow): Set proper certificate_chain and signature (when + // implementing support for signature verification). + response->set_signature("TODO"); + response->add_certificate_chain("TODO"); + return response; + } + + void WritePolicy(const em::CloudPolicyResponse& policy) { + std::string data; + em::CachedCloudPolicyResponse cached_policy; + cached_policy.mutable_cloud_policy()->CopyFrom(policy); + EXPECT_TRUE(cached_policy.SerializeToString(&data)); + int size = static_cast<int>(data.size()); + EXPECT_EQ(size, file_util::WriteFile(test_file(), data.c_str(), size)); + } + + FilePath test_file() { + return temp_dir_.path().AppendASCII("CloudPolicyCacheTest"); + } + + bool Equals(const PolicyMapType& a, const PolicyMapType& b) const { + return CloudPolicyCache::Equals(a, b); + } + + MessageLoop loop_; + + private: + ScopedTempDir temp_dir_; + BrowserThread ui_thread_; + BrowserThread file_thread_; +}; + +TEST_F(CloudPolicyCacheTest, Equals) { + PolicyMapType a; + a.insert(std::make_pair(kPolicyHomepageLocation, + Value::CreateStringValue("aaa"))); + PolicyMapType a2; + a2.insert(std::make_pair(kPolicyHomepageLocation, + Value::CreateStringValue("aaa"))); + PolicyMapType b; + b.insert(std::make_pair(kPolicyHomepageLocation, + Value::CreateStringValue("bbb"))); + PolicyMapType c; + c.insert(std::make_pair(kPolicyHomepageLocation, + Value::CreateStringValue("aaa"))); + c.insert(std::make_pair(kPolicyHomepageIsNewTabPage, + Value::CreateBooleanValue(true))); + EXPECT_FALSE(Equals(a, b)); + EXPECT_FALSE(Equals(b, a)); + EXPECT_FALSE(Equals(a, c)); + EXPECT_FALSE(Equals(c, a)); + EXPECT_TRUE(Equals(a, a2)); + EXPECT_TRUE(Equals(a2, a)); + PolicyMapType empty1; + PolicyMapType empty2; + EXPECT_TRUE(Equals(empty1, empty2)); + EXPECT_TRUE(Equals(empty2, empty1)); + EXPECT_FALSE(Equals(empty1, a)); + EXPECT_FALSE(Equals(a, empty1)); +} + +TEST_F(CloudPolicyCacheTest, DecodePolicy) { + em::CloudPolicySettings settings; + settings.mutable_homepagelocation()->set_homepagelocation("chromium.org"); + settings.mutable_javascriptenabled()->set_javascriptenabled(true); + settings.mutable_javascriptenabled()->mutable_policy_options()->set_mode( + em::PolicyOptions::MANDATORY); + settings.mutable_policyrefreshrate()->set_policyrefreshrate(5); + settings.mutable_policyrefreshrate()->mutable_policy_options()->set_mode( + em::PolicyOptions::RECOMMENDED); + PolicyMapType mandatory_policy; + PolicyMapType recommended_policy; + DecodePolicy(settings, &mandatory_policy, &recommended_policy); + PolicyMapType mandatory; + mandatory.insert(std::make_pair(kPolicyHomepageLocation, + Value::CreateStringValue("chromium.org"))); + mandatory.insert(std::make_pair(kPolicyJavascriptEnabled, + Value::CreateBooleanValue(true))); + PolicyMapType recommended; + recommended.insert(std::make_pair(kPolicyPolicyRefreshRate, + Value::CreateIntegerValue(5))); + EXPECT_TRUE(Equals(mandatory, mandatory_policy)); + EXPECT_TRUE(Equals(recommended, recommended_policy)); +} + +TEST_F(CloudPolicyCacheTest, DecodeIntegerValue) { + const int min = std::numeric_limits<int>::min(); + const int max = std::numeric_limits<int>::max(); + scoped_ptr<Value> value( + DecodeIntegerValue(static_cast<google::protobuf::int64>(42))); + ASSERT_TRUE(value.get()); + EXPECT_TRUE(value->Equals(Value::CreateIntegerValue(42))); + value.reset( + DecodeIntegerValue(static_cast<google::protobuf::int64>(min - 1LL))); + EXPECT_EQ(NULL, value.get()); + value.reset(DecodeIntegerValue(static_cast<google::protobuf::int64>(min))); + ASSERT_TRUE(value.get()); + EXPECT_TRUE(value->Equals(Value::CreateIntegerValue(min))); + value.reset( + DecodeIntegerValue(static_cast<google::protobuf::int64>(max + 1LL))); + EXPECT_EQ(NULL, value.get()); + value.reset(DecodeIntegerValue(static_cast<google::protobuf::int64>(max))); + ASSERT_TRUE(value.get()); + EXPECT_TRUE(value->Equals(Value::CreateIntegerValue(max))); +} + +TEST_F(CloudPolicyCacheTest, DecodeStringList) { + em::StringList string_list; + string_list.add_entries("ponies"); + string_list.add_entries("more ponies"); + scoped_ptr<ListValue> decoded(DecodeStringList(string_list)); + ListValue expected; + expected.Append(Value::CreateStringValue("ponies")); + expected.Append(Value::CreateStringValue("more ponies")); + EXPECT_TRUE(decoded->Equals(&expected)); +} + +TEST_F(CloudPolicyCacheTest, Empty) { + CloudPolicyCache cache(test_file()); + PolicyMapType empty; + EXPECT_TRUE(Equals(empty, *cache.GetMandatoryPolicy())); + EXPECT_TRUE(Equals(empty, *cache.GetRecommendedPolicy())); + EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); +} + +TEST_F(CloudPolicyCacheTest, LoadNoFile) { + CloudPolicyCache cache(test_file()); + cache.LoadPolicyFromFile(); + PolicyMapType empty; + EXPECT_TRUE(Equals(empty, *cache.GetMandatoryPolicy())); + EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); +} + +TEST_F(CloudPolicyCacheTest, RejectFuture) { + scoped_ptr<em::CloudPolicyResponse> policy_response( + CreateHomepagePolicy("", base::Time::NowFromSystemTime() + + base::TimeDelta::FromMinutes(5), + em::PolicyOptions::MANDATORY)); + WritePolicy(*policy_response); + CloudPolicyCache cache(test_file()); + cache.LoadPolicyFromFile(); + PolicyMapType empty; + EXPECT_TRUE(Equals(empty, *cache.GetMandatoryPolicy())); + EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); +} + +TEST_F(CloudPolicyCacheTest, LoadWithFile) { + scoped_ptr<em::CloudPolicyResponse> policy_response( + CreateHomepagePolicy("", base::Time::NowFromSystemTime(), + em::PolicyOptions::MANDATORY)); + WritePolicy(*policy_response); + CloudPolicyCache cache(test_file()); + cache.LoadPolicyFromFile(); + PolicyMapType empty; + EXPECT_TRUE(Equals(empty, *cache.GetMandatoryPolicy())); + EXPECT_NE(base::Time(), cache.last_policy_refresh_time()); + EXPECT_GE(base::Time::Now(), cache.last_policy_refresh_time()); +} + +TEST_F(CloudPolicyCacheTest, LoadWithData) { + scoped_ptr<em::CloudPolicyResponse> policy( + CreateHomepagePolicy("http://www.example.com", + base::Time::NowFromSystemTime(), + em::PolicyOptions::MANDATORY)); + WritePolicy(*policy); + CloudPolicyCache cache(test_file()); + cache.LoadPolicyFromFile(); + PolicyMapType expected; + expected.insert( + std::make_pair(kPolicyHomepageLocation, + Value::CreateStringValue("http://www.example.com"))); + EXPECT_TRUE(Equals(expected, *cache.GetMandatoryPolicy())); +} + +TEST_F(CloudPolicyCacheTest, SetPolicy) { + CloudPolicyCache cache(test_file()); + scoped_ptr<em::CloudPolicyResponse> policy( + CreateHomepagePolicy("http://www.example.com", + base::Time::NowFromSystemTime(), + em::PolicyOptions::MANDATORY)); + EXPECT_TRUE(cache.SetPolicy(*policy)); + scoped_ptr<em::CloudPolicyResponse> policy2( + CreateHomepagePolicy("http://www.example.com", + base::Time::NowFromSystemTime(), + em::PolicyOptions::MANDATORY)); + EXPECT_FALSE(cache.SetPolicy(*policy2)); + PolicyMapType expected; + expected.insert( + std::make_pair(kPolicyHomepageLocation, + Value::CreateStringValue("http://www.example.com"))); + PolicyMapType empty; + EXPECT_TRUE(Equals(expected, *cache.GetMandatoryPolicy())); + EXPECT_TRUE(Equals(empty, *cache.GetRecommendedPolicy())); + policy.reset(CreateHomepagePolicy("http://www.example.com", + base::Time::NowFromSystemTime(), + em::PolicyOptions::RECOMMENDED)); + EXPECT_TRUE(cache.SetPolicy(*policy)); + EXPECT_TRUE(Equals(expected, *cache.GetRecommendedPolicy())); + EXPECT_TRUE(Equals(empty, *cache.GetMandatoryPolicy())); +} + +TEST_F(CloudPolicyCacheTest, ResetPolicy) { + CloudPolicyCache cache(test_file()); + + scoped_ptr<em::CloudPolicyResponse> policy( + CreateHomepagePolicy("http://www.example.com", + base::Time::NowFromSystemTime(), + em::PolicyOptions::MANDATORY)); + EXPECT_TRUE(cache.SetPolicy(*policy)); + PolicyMapType expected; + expected.insert( + std::make_pair(kPolicyHomepageLocation, + Value::CreateStringValue("http://www.example.com"))); + EXPECT_TRUE(Equals(expected, *cache.GetMandatoryPolicy())); + + scoped_ptr<em::CloudPolicyResponse> empty_policy( + CreateHomepagePolicy("", base::Time::NowFromSystemTime(), + em::PolicyOptions::MANDATORY)); + EXPECT_TRUE(cache.SetPolicy(*empty_policy)); + PolicyMapType empty; + EXPECT_TRUE(Equals(empty, *cache.GetMandatoryPolicy())); +} + +TEST_F(CloudPolicyCacheTest, PersistPolicy) { + { + CloudPolicyCache cache(test_file()); + scoped_ptr<em::CloudPolicyResponse> policy( + CreateHomepagePolicy("http://www.example.com", + base::Time::NowFromSystemTime(), + em::PolicyOptions::MANDATORY)); + cache.SetPolicy(*policy); + } + + loop_.RunAllPending(); + + EXPECT_TRUE(file_util::PathExists(test_file())); + CloudPolicyCache cache(test_file()); + cache.LoadPolicyFromFile(); + PolicyMapType expected; + expected.insert( + std::make_pair(kPolicyHomepageLocation, + Value::CreateStringValue("http://www.example.com"))); + EXPECT_TRUE(Equals(expected, *cache.GetMandatoryPolicy())); +} + +TEST_F(CloudPolicyCacheTest, FreshPolicyOverride) { + scoped_ptr<em::CloudPolicyResponse> policy( + CreateHomepagePolicy("http://www.example.com", + base::Time::NowFromSystemTime(), + em::PolicyOptions::MANDATORY)); + WritePolicy(*policy); + + CloudPolicyCache cache(test_file()); + scoped_ptr<em::CloudPolicyResponse> updated_policy( + CreateHomepagePolicy("http://www.chromium.org", + base::Time::NowFromSystemTime(), + em::PolicyOptions::MANDATORY)); + EXPECT_TRUE(cache.SetPolicy(*updated_policy)); + + cache.LoadPolicyFromFile(); + PolicyMapType expected; + expected.insert( + std::make_pair(kPolicyHomepageLocation, + Value::CreateStringValue("http://www.chromium.org"))); + EXPECT_TRUE(Equals(expected, *cache.GetMandatoryPolicy())); +} + +} // namespace policy + +// ================================================================== +// Everything below this line can go when we phase out support for +// the old (trusted testing/pilot program) policy format. + +// This is a (slightly updated) copy of the old +// device_management_policy_cache_unittest.cc. The new CloudPolicyCache +// supports the old DMPC's interface for now (until it is phased out), so for +// this transitional period, we keep these old test cases but apply them to the +// new implementation (CPC). + +namespace policy { + +// Wraps base functionaly for the test cases. +class DeviceManagementPolicyCacheTestBase : public testing::Test { + protected: + // Add a string policy setting to a policy response message. + void AddStringPolicy(em::DevicePolicyResponse* policy, + const std::string& name, + const std::string& value) { + em::DevicePolicySetting* setting = policy->add_setting(); + setting->set_policy_key(kChromeDevicePolicySettingKey); + em::GenericSetting* policy_value = setting->mutable_policy_value(); + em::GenericNamedValue* named_value = policy_value->add_named_value(); + named_value->set_name(name); + em::GenericValue* value_container = named_value->mutable_value(); + value_container->set_value_type(em::GenericValue::VALUE_TYPE_STRING); + value_container->set_string_value(value); + } +}; + +// Tests the device management policy cache. +class DeviceManagementPolicyCacheTest + : public DeviceManagementPolicyCacheTestBase { + protected: + DeviceManagementPolicyCacheTest() + : loop_(MessageLoop::TYPE_UI), + ui_thread_(BrowserThread::UI, &loop_), + file_thread_(BrowserThread::FILE, &loop_) {} + + void SetUp() { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + } + + void TearDown() { + loop_.RunAllPending(); + } + + void WritePolicy(const em::DevicePolicyResponse& policy, + const base::Time& timestamp) { + std::string data; + em::CachedCloudPolicyResponse cached_policy; + cached_policy.mutable_device_policy()->CopyFrom(policy); + cached_policy.set_timestamp(timestamp.ToTimeT()); + EXPECT_TRUE(cached_policy.SerializeToString(&data)); + int size = static_cast<int>(data.size()); + EXPECT_EQ(size, file_util::WriteFile(test_file(), data.c_str(), size)); + } + + FilePath test_file() { + return temp_dir_.path().AppendASCII("DeviceManagementPolicyCacheTest"); + } + + protected: + MessageLoop loop_; + + private: + ScopedTempDir temp_dir_; + BrowserThread ui_thread_; + BrowserThread file_thread_; +}; + +TEST_F(DeviceManagementPolicyCacheTest, Empty) { + CloudPolicyCache cache(test_file()); + DictionaryValue empty; + scoped_ptr<Value> policy(cache.GetDevicePolicy()); + EXPECT_TRUE(empty.Equals(policy.get())); + EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); +} + +TEST_F(DeviceManagementPolicyCacheTest, LoadNoFile) { + CloudPolicyCache cache(test_file()); + cache.LoadPolicyFromFile(); + DictionaryValue empty; + scoped_ptr<Value> policy(cache.GetDevicePolicy()); + EXPECT_TRUE(empty.Equals(policy.get())); + EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); +} + +TEST_F(DeviceManagementPolicyCacheTest, RejectFuture) { + em::DevicePolicyResponse policy_response; + WritePolicy(policy_response, base::Time::NowFromSystemTime() + + base::TimeDelta::FromMinutes(5)); + CloudPolicyCache cache(test_file()); + cache.LoadPolicyFromFile(); + DictionaryValue empty; + scoped_ptr<Value> policy(cache.GetDevicePolicy()); + EXPECT_TRUE(empty.Equals(policy.get())); + EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); +} + +TEST_F(DeviceManagementPolicyCacheTest, LoadWithFile) { + em::DevicePolicyResponse policy_response; + WritePolicy(policy_response, base::Time::NowFromSystemTime()); + CloudPolicyCache cache(test_file()); + cache.LoadPolicyFromFile(); + DictionaryValue empty; + scoped_ptr<Value> policy(cache.GetDevicePolicy()); + EXPECT_TRUE(empty.Equals(policy.get())); + EXPECT_NE(base::Time(), cache.last_policy_refresh_time()); + EXPECT_GE(base::Time::Now(), cache.last_policy_refresh_time()); +} + +TEST_F(DeviceManagementPolicyCacheTest, LoadWithData) { + em::DevicePolicyResponse policy; + AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); + WritePolicy(policy, base::Time::NowFromSystemTime()); + CloudPolicyCache cache(test_file()); + cache.LoadPolicyFromFile(); + DictionaryValue expected; + expected.Set("HomepageLocation", + Value::CreateStringValue("http://www.example.com")); + scoped_ptr<Value> policy_value(cache.GetDevicePolicy()); + EXPECT_TRUE(expected.Equals(policy_value.get())); +} + +TEST_F(DeviceManagementPolicyCacheTest, SetDevicePolicy) { + CloudPolicyCache cache(test_file()); + em::DevicePolicyResponse policy; + AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); + EXPECT_TRUE(cache.SetDevicePolicy(policy)); + em::DevicePolicyResponse policy2; + AddStringPolicy(&policy2, "HomepageLocation", "http://www.example.com"); + EXPECT_FALSE(cache.SetDevicePolicy(policy2)); + DictionaryValue expected; + expected.Set("HomepageLocation", + Value::CreateStringValue("http://www.example.com")); + scoped_ptr<Value> policy_value(cache.GetDevicePolicy()); + EXPECT_TRUE(expected.Equals(policy_value.get())); +} + +TEST_F(DeviceManagementPolicyCacheTest, ResetPolicy) { + CloudPolicyCache cache(test_file()); + + em::DevicePolicyResponse policy; + AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); + EXPECT_TRUE(cache.SetDevicePolicy(policy)); + DictionaryValue expected; + expected.Set("HomepageLocation", + Value::CreateStringValue("http://www.example.com")); + scoped_ptr<Value> policy_value(cache.GetDevicePolicy()); + EXPECT_TRUE(expected.Equals(policy_value.get())); + + EXPECT_TRUE(cache.SetDevicePolicy(em::DevicePolicyResponse())); + policy_value.reset(cache.GetDevicePolicy()); + DictionaryValue empty; + EXPECT_TRUE(empty.Equals(policy_value.get())); +} + +TEST_F(DeviceManagementPolicyCacheTest, PersistPolicy) { + { + CloudPolicyCache cache(test_file()); + em::DevicePolicyResponse policy; + AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); + cache.SetDevicePolicy(policy); + } + + loop_.RunAllPending(); + + EXPECT_TRUE(file_util::PathExists(test_file())); + CloudPolicyCache cache(test_file()); + cache.LoadPolicyFromFile(); + DictionaryValue expected; + expected.Set("HomepageLocation", + Value::CreateStringValue("http://www.example.com")); + scoped_ptr<Value> policy_value(cache.GetDevicePolicy()); + EXPECT_TRUE(expected.Equals(policy_value.get())); +} + +TEST_F(DeviceManagementPolicyCacheTest, FreshPolicyOverride) { + em::DevicePolicyResponse policy; + AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); + WritePolicy(policy, base::Time::NowFromSystemTime()); + + CloudPolicyCache cache(test_file()); + em::DevicePolicyResponse updated_policy; + AddStringPolicy(&updated_policy, "HomepageLocation", + "http://www.chromium.org"); + EXPECT_TRUE(cache.SetDevicePolicy(updated_policy)); + + cache.LoadPolicyFromFile(); + DictionaryValue expected; + expected.Set("HomepageLocation", + Value::CreateStringValue("http://www.chromium.org")); + scoped_ptr<Value> policy_value(cache.GetDevicePolicy()); + EXPECT_TRUE(expected.Equals(policy_value.get())); +} + +// Tests proper decoding of policy values. +class DeviceManagementPolicyCacheDecodeTest + : public DeviceManagementPolicyCacheTestBase { + protected: + void DecodeAndCheck(Value* expected_value_ptr) { + scoped_ptr<Value> expected_value(expected_value_ptr); + scoped_ptr<Value> decoded_value( + CloudPolicyCache::DecodeValue(value_)); + if (expected_value_ptr) { + ASSERT_TRUE(decoded_value.get()); + EXPECT_TRUE(decoded_value->Equals(expected_value.get())); + } else { + ASSERT_FALSE(decoded_value.get()); + } + } + + DictionaryValue* DecodeDevicePolicy(const em::DevicePolicyResponse policy) { + return CloudPolicyCache::DecodeDevicePolicy(policy); + } + + em::GenericValue value_; +}; + +TEST_F(DeviceManagementPolicyCacheDecodeTest, Bool) { + value_.set_value_type(em::GenericValue::VALUE_TYPE_BOOL); + value_.set_bool_value(true); + DecodeAndCheck(Value::CreateBooleanValue(true)); +} + +TEST_F(DeviceManagementPolicyCacheDecodeTest, Int64) { + value_.set_value_type(em::GenericValue::VALUE_TYPE_INT64); + value_.set_int64_value(42); + DecodeAndCheck(Value::CreateIntegerValue(42)); +} + +TEST_F(DeviceManagementPolicyCacheDecodeTest, Int64Overflow) { + const int min = std::numeric_limits<int>::min(); + const int max = std::numeric_limits<int>::max(); + value_.set_value_type(em::GenericValue::VALUE_TYPE_INT64); + value_.set_int64_value(min - 1LL); + DecodeAndCheck(NULL); + value_.set_int64_value(max + 1LL); + DecodeAndCheck(NULL); + value_.set_int64_value(min); + DecodeAndCheck(Value::CreateIntegerValue(min)); + value_.set_int64_value(max); + DecodeAndCheck(Value::CreateIntegerValue(max)); +} + +TEST_F(DeviceManagementPolicyCacheDecodeTest, String) { + value_.set_value_type(em::GenericValue::VALUE_TYPE_STRING); + value_.set_string_value("ponies!"); + DecodeAndCheck(Value::CreateStringValue("ponies!")); +} + +TEST_F(DeviceManagementPolicyCacheDecodeTest, Double) { + value_.set_value_type(em::GenericValue::VALUE_TYPE_DOUBLE); + value_.set_double_value(0.42L); + DecodeAndCheck(Value::CreateDoubleValue(0.42L)); +} + +TEST_F(DeviceManagementPolicyCacheDecodeTest, Bytes) { + std::string data("binary ponies."); + value_.set_value_type(em::GenericValue::VALUE_TYPE_BYTES); + value_.set_bytes_value(data); + DecodeAndCheck( + BinaryValue::CreateWithCopiedBuffer(data.c_str(), data.size())); +} + +TEST_F(DeviceManagementPolicyCacheDecodeTest, BoolArray) { + value_.set_value_type(em::GenericValue::VALUE_TYPE_BOOL_ARRAY); + value_.add_bool_array(false); + value_.add_bool_array(true); + ListValue* list = new ListValue; + list->Append(Value::CreateBooleanValue(false)); + list->Append(Value::CreateBooleanValue(true)); + DecodeAndCheck(list); +} + +TEST_F(DeviceManagementPolicyCacheDecodeTest, Int64Array) { + value_.set_value_type(em::GenericValue::VALUE_TYPE_INT64_ARRAY); + value_.add_int64_array(42); + value_.add_int64_array(17); + ListValue* list = new ListValue; + list->Append(Value::CreateIntegerValue(42)); + list->Append(Value::CreateIntegerValue(17)); + DecodeAndCheck(list); +} + +TEST_F(DeviceManagementPolicyCacheDecodeTest, StringArray) { + value_.set_value_type(em::GenericValue::VALUE_TYPE_STRING_ARRAY); + value_.add_string_array("ponies"); + value_.add_string_array("more ponies"); + ListValue* list = new ListValue; + list->Append(Value::CreateStringValue("ponies")); + list->Append(Value::CreateStringValue("more ponies")); + DecodeAndCheck(list); +} + +TEST_F(DeviceManagementPolicyCacheDecodeTest, DoubleArray) { + value_.set_value_type(em::GenericValue::VALUE_TYPE_DOUBLE_ARRAY); + value_.add_double_array(0.42L); + value_.add_double_array(0.17L); + ListValue* list = new ListValue; + list->Append(Value::CreateDoubleValue(0.42L)); + list->Append(Value::CreateDoubleValue(0.17L)); + DecodeAndCheck(list); +} + +TEST_F(DeviceManagementPolicyCacheDecodeTest, DecodePolicy) { + em::DevicePolicyResponse policy; + AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); + scoped_ptr<Value> decoded(DecodeDevicePolicy(policy)); + DictionaryValue expected; + expected.Set("HomepageLocation", + Value::CreateStringValue("http://www.example.com")); + EXPECT_TRUE(expected.Equals(decoded.get())); +} + +} // namespace policy diff --git a/chrome/browser/policy/configuration_policy_provider.cc b/chrome/browser/policy/configuration_policy_provider.cc index 82ca864..21190ee9 100644 --- a/chrome/browser/policy/configuration_policy_provider.cc +++ b/chrome/browser/policy/configuration_policy_provider.cc @@ -21,7 +21,7 @@ bool ConfigurationPolicyProvider::IsInitializationComplete() const { return true; } -void ConfigurationPolicyProvider::DecodePolicyValueTree( +void ConfigurationPolicyProvider::ApplyPolicyValueTree( const DictionaryValue* policies, ConfigurationPolicyStoreInterface* store) { const PolicyDefinitionList* policy_list(policy_definition_list()); @@ -36,6 +36,19 @@ void ConfigurationPolicyProvider::DecodePolicyValueTree( // supports it. } +void ConfigurationPolicyProvider::ApplyPolicyMap( + const PolicyMapType* policies, + ConfigurationPolicyStoreInterface* store) { + const PolicyDefinitionList* policy_list(policy_definition_list()); + for (const PolicyDefinitionList::Entry* i = policy_list->begin; + i != policy_list->end; ++i) { + PolicyMapType::const_iterator it = + policies->find(i->policy_type); + if (it != policies->end() && it->second->IsType(i->value_type)) + store->Apply(i->policy_type, it->second->DeepCopy()); + } +} + // Class ConfigurationPolicyObserverRegistrar. ConfigurationPolicyObserverRegistrar::ConfigurationPolicyObserverRegistrar() diff --git a/chrome/browser/policy/configuration_policy_provider.h b/chrome/browser/policy/configuration_policy_provider.h index af2cddf..4eedab6 100644 --- a/chrome/browser/policy/configuration_policy_provider.h +++ b/chrome/browser/policy/configuration_policy_provider.h @@ -6,12 +6,14 @@ #define CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_H_ #pragma once +#include <map> #include <string> #include "base/basictypes.h" #include "base/scoped_ptr.h" #include "base/values.h" #include "chrome/browser/policy/configuration_policy_store_interface.h" +#include "policy/configuration_policy_type.h" namespace policy { @@ -20,6 +22,8 @@ namespace policy { // etc.) should implement a subclass of this class. class ConfigurationPolicyProvider { public: + typedef std::map<ConfigurationPolicyType, Value*> PolicyMapType; + class Observer { public: virtual ~Observer() {} @@ -59,9 +63,14 @@ class ConfigurationPolicyProvider { protected: // Decodes the value tree and writes the configuration to the given |store|. - void DecodePolicyValueTree(const DictionaryValue* policies, + void ApplyPolicyValueTree(const DictionaryValue* policies, ConfigurationPolicyStoreInterface* store); + // Writes the configuration found in the already-decoded map |policies| to + // the given |store|. + void ApplyPolicyMap(const PolicyMapType* policies, + ConfigurationPolicyStoreInterface* store); + const PolicyDefinitionList* policy_definition_list() const { return policy_definition_list_; } diff --git a/chrome/browser/policy/configuration_policy_store_interface.h b/chrome/browser/policy/configuration_policy_store_interface.h index d3261a3..1d3bf43 100644 --- a/chrome/browser/policy/configuration_policy_store_interface.h +++ b/chrome/browser/policy/configuration_policy_store_interface.h @@ -7,8 +7,6 @@ #pragma once #include "base/basictypes.h" -// configuration_policy_type.h is generated. See policy_template.json for -// policy definitions. #include "policy/configuration_policy_type.h" class Value; diff --git a/chrome/browser/policy/device_management_backend.h b/chrome/browser/policy/device_management_backend.h index 114c7b7..f2fec0d 100644 --- a/chrome/browser/policy/device_management_backend.h +++ b/chrome/browser/policy/device_management_backend.h @@ -75,8 +75,12 @@ class DeviceManagementBackend : base::NonThreadSafe { public: virtual ~DevicePolicyResponseDelegate() {} + // Deprecated in favor of HandleCloudPolicyResponse. To be removed once + // DMServer supports the new protocol. virtual void HandlePolicyResponse( const em::DevicePolicyResponse& response) = 0; + virtual void HandleCloudPolicyResponse( + const em::CloudPolicyResponse& response) = 0; virtual void OnError(ErrorCode code) = 0; protected: @@ -106,6 +110,12 @@ class DeviceManagementBackend : base::NonThreadSafe { const em::DevicePolicyRequest& request, DevicePolicyResponseDelegate* delegate) = 0; + virtual void ProcessCloudPolicyRequest( + const std::string& device_management_token, + const std::string& device_id, + const em::CloudPolicyRequest& request, + DevicePolicyResponseDelegate* delegate) = 0; + protected: DeviceManagementBackend() {} diff --git a/chrome/browser/policy/device_management_backend_impl.cc b/chrome/browser/policy/device_management_backend_impl.cc index ed75f3f..b01cbf8 100644 --- a/chrome/browser/policy/device_management_backend_impl.cc +++ b/chrome/browser/policy/device_management_backend_impl.cc @@ -27,6 +27,8 @@ const char DeviceManagementBackendImpl::kValueRequestRegister[] = "register"; const char DeviceManagementBackendImpl::kValueRequestUnregister[] = "unregister"; const char DeviceManagementBackendImpl::kValueRequestPolicy[] = "policy"; +const char DeviceManagementBackendImpl::kValueRequestCloudPolicy[] = + "cloud_policy"; const char DeviceManagementBackendImpl::kValueDeviceType[] = "Chrome OS"; const char DeviceManagementBackendImpl::kValueAppType[] = "Chrome"; @@ -170,7 +172,10 @@ void DeviceManagementJobBase::HandleResponse( } if (response_code != 200) { - OnError(DeviceManagementBackend::kErrorHttpStatus); + if (response_code == 400) + OnError(DeviceManagementBackend::kErrorRequestInvalid); + else + OnError(DeviceManagementBackend::kErrorHttpStatus); return; } @@ -230,7 +235,17 @@ class DeviceManagementRegisterJob : public DeviceManagementJobBase { const std::string& auth_token, const std::string& device_id, const em::DeviceRegisterRequest& request, - DeviceManagementBackend::DeviceRegisterResponseDelegate* delegate); + DeviceManagementBackend::DeviceRegisterResponseDelegate* delegate) + : DeviceManagementJobBase( + backend_impl, + DeviceManagementBackendImpl::kValueRequestRegister, + device_id), + delegate_(delegate) { + SetAuthToken(auth_token); + em::DeviceManagementRequest request_wrapper; + request_wrapper.mutable_register_request()->CopyFrom(request); + SetPayload(request_wrapper); + } virtual ~DeviceManagementRegisterJob() {} private: @@ -247,32 +262,25 @@ class DeviceManagementRegisterJob : public DeviceManagementJobBase { DISALLOW_COPY_AND_ASSIGN(DeviceManagementRegisterJob); }; -DeviceManagementRegisterJob::DeviceManagementRegisterJob( - DeviceManagementBackendImpl* backend_impl, - const std::string& auth_token, - const std::string& device_id, - const em::DeviceRegisterRequest& request, - DeviceManagementBackend::DeviceRegisterResponseDelegate* delegate) - : DeviceManagementJobBase( - backend_impl, - DeviceManagementBackendImpl::kValueRequestRegister, - device_id), - delegate_(delegate) { - SetAuthToken(auth_token); - em::DeviceManagementRequest request_wrapper; - request_wrapper.mutable_register_request()->CopyFrom(request); - SetPayload(request_wrapper); -} - // Handles device unregistration jobs. class DeviceManagementUnregisterJob : public DeviceManagementJobBase { public: DeviceManagementUnregisterJob( DeviceManagementBackendImpl* backend_impl, - const std::string& device_id, const std::string& device_management_token, + const std::string& device_id, const em::DeviceUnregisterRequest& request, - DeviceManagementBackend::DeviceUnregisterResponseDelegate* delegate); + DeviceManagementBackend::DeviceUnregisterResponseDelegate* delegate) + : DeviceManagementJobBase( + backend_impl, + DeviceManagementBackendImpl::kValueRequestUnregister, + device_id), + delegate_(delegate) { + SetDeviceManagementToken(device_management_token); + em::DeviceManagementRequest request_wrapper; + request_wrapper.mutable_unregister_request()->CopyFrom(request); + SetPayload(request_wrapper); + } virtual ~DeviceManagementUnregisterJob() {} private: @@ -289,23 +297,6 @@ class DeviceManagementUnregisterJob : public DeviceManagementJobBase { DISALLOW_COPY_AND_ASSIGN(DeviceManagementUnregisterJob); }; -DeviceManagementUnregisterJob::DeviceManagementUnregisterJob( - DeviceManagementBackendImpl* backend_impl, - const std::string& device_management_token, - const std::string& device_id, - const em::DeviceUnregisterRequest& request, - DeviceManagementBackend::DeviceUnregisterResponseDelegate* delegate) - : DeviceManagementJobBase( - backend_impl, - DeviceManagementBackendImpl::kValueRequestUnregister, - device_id), - delegate_(delegate) { - SetDeviceManagementToken(device_management_token); - em::DeviceManagementRequest request_wrapper; - request_wrapper.mutable_unregister_request()->CopyFrom(request); - SetPayload(request_wrapper); -} - // Handles policy request jobs. class DeviceManagementPolicyJob : public DeviceManagementJobBase { public: @@ -314,7 +305,17 @@ class DeviceManagementPolicyJob : public DeviceManagementJobBase { const std::string& device_management_token, const std::string& device_id, const em::DevicePolicyRequest& request, - DeviceManagementBackend::DevicePolicyResponseDelegate* delegate); + DeviceManagementBackend::DevicePolicyResponseDelegate* delegate) + : DeviceManagementJobBase( + backend_impl, + DeviceManagementBackendImpl::kValueRequestPolicy, + device_id), + delegate_(delegate) { + SetDeviceManagementToken(device_management_token); + em::DeviceManagementRequest request_wrapper; + request_wrapper.mutable_policy_request()->CopyFrom(request); + SetPayload(request_wrapper); + } virtual ~DeviceManagementPolicyJob() {} private: @@ -331,22 +332,40 @@ class DeviceManagementPolicyJob : public DeviceManagementJobBase { DISALLOW_COPY_AND_ASSIGN(DeviceManagementPolicyJob); }; -DeviceManagementPolicyJob::DeviceManagementPolicyJob( - DeviceManagementBackendImpl* backend_impl, - const std::string& device_management_token, - const std::string& device_id, - const em::DevicePolicyRequest& request, - DeviceManagementBackend::DevicePolicyResponseDelegate* delegate) - : DeviceManagementJobBase( +// Handles cloud policy request jobs. +class CloudPolicyJob : public DeviceManagementJobBase { + public: + CloudPolicyJob( + DeviceManagementBackendImpl* backend_impl, + const std::string& device_management_token, + const std::string& device_id, + const em::CloudPolicyRequest& request, + DeviceManagementBackend::DevicePolicyResponseDelegate* delegate) + : DeviceManagementJobBase( backend_impl, - DeviceManagementBackendImpl::kValueRequestPolicy, + DeviceManagementBackendImpl::kValueRequestCloudPolicy, device_id), - delegate_(delegate) { - SetDeviceManagementToken(device_management_token); - em::DeviceManagementRequest request_wrapper; - request_wrapper.mutable_policy_request()->CopyFrom(request); - SetPayload(request_wrapper); -} + delegate_(delegate) { + SetDeviceManagementToken(device_management_token); + em::DeviceManagementRequest request_wrapper; + request_wrapper.mutable_cloud_policy_request()->CopyFrom(request); + SetPayload(request_wrapper); + } + virtual ~CloudPolicyJob() {} + + private: + // DeviceManagementJobBase overrides. + virtual void OnError(DeviceManagementBackend::ErrorCode error) { + delegate_->OnError(error); + } + virtual void OnResponse(const em::DeviceManagementResponse& response) { + delegate_->HandleCloudPolicyResponse(response.cloud_policy_response()); + } + + DeviceManagementBackend::DevicePolicyResponseDelegate* delegate_; + + DISALLOW_COPY_AND_ASSIGN(CloudPolicyJob); +}; DeviceManagementBackendImpl::DeviceManagementBackendImpl( DeviceManagementService* service) @@ -409,4 +428,13 @@ void DeviceManagementBackendImpl::ProcessPolicyRequest( request, delegate)); } +void DeviceManagementBackendImpl::ProcessCloudPolicyRequest( + const std::string& device_management_token, + const std::string& device_id, + const em::CloudPolicyRequest& request, + DevicePolicyResponseDelegate* delegate) { + AddJob(new CloudPolicyJob(this, device_management_token, device_id, + request, delegate)); +} + } // namespace policy diff --git a/chrome/browser/policy/device_management_backend_impl.h b/chrome/browser/policy/device_management_backend_impl.h index d818b4d..40c7e11 100644 --- a/chrome/browser/policy/device_management_backend_impl.h +++ b/chrome/browser/policy/device_management_backend_impl.h @@ -36,7 +36,10 @@ class DeviceManagementBackendImpl : public DeviceManagementBackend { // String constants for the device and app type we report to the server. static const char kValueRequestRegister[]; static const char kValueRequestUnregister[]; + // Deprecated in favor of kValueRequestCloudPolicy. + // See DevicePolicyResponseDelegate::HandlePolicyResponse. static const char kValueRequestPolicy[]; + static const char kValueRequestCloudPolicy[]; static const char kValueDeviceType[]; static const char kValueAppType[]; @@ -63,11 +66,18 @@ class DeviceManagementBackendImpl : public DeviceManagementBackend { const std::string& device_id, const em::DeviceUnregisterRequest& request, DeviceUnregisterResponseDelegate* response_delegate); + // Deprecated in favor of ProcessCloudPolicyRequest. + // See DevicePolicyResponseDelegate::HandlePolicyResponse. virtual void ProcessPolicyRequest( const std::string& device_management_token, const std::string& device_id, const em::DevicePolicyRequest& request, DevicePolicyResponseDelegate* response_delegate); + virtual void ProcessCloudPolicyRequest( + const std::string& device_management_token, + const std::string& device_id, + const em::CloudPolicyRequest& request, + DevicePolicyResponseDelegate* delegate); // Keeps track of the jobs currently in flight. JobSet pending_jobs_; diff --git a/chrome/browser/policy/device_management_backend_mock.h b/chrome/browser/policy/device_management_backend_mock.h index 0533efc..01ac14d 100644 --- a/chrome/browser/policy/device_management_backend_mock.h +++ b/chrome/browser/policy/device_management_backend_mock.h @@ -40,6 +40,7 @@ class DevicePolicyResponseDelegateMock virtual ~DevicePolicyResponseDelegateMock(); MOCK_METHOD1(HandlePolicyResponse, void(const em::DevicePolicyResponse&)); + MOCK_METHOD1(HandleCloudPolicyResponse, void(const em::CloudPolicyResponse&)); MOCK_METHOD1(OnError, void(DeviceManagementBackend::ErrorCode error)); }; diff --git a/chrome/browser/policy/device_management_policy_cache.cc b/chrome/browser/policy/device_management_policy_cache.cc deleted file mode 100644 index ef8e6e1..0000000 --- a/chrome/browser/policy/device_management_policy_cache.cc +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright (c) 2010 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/policy/device_management_policy_cache.h" - -#include <limits> -#include <string> - -#include "base/file_util.h" -#include "base/logging.h" -#include "base/task.h" -#include "base/values.h" -#include "chrome/browser/browser_thread.h" -#include "chrome/browser/policy/proto/device_management_constants.h" -#include "chrome/browser/policy/proto/device_management_local.pb.h" - -using google::protobuf::RepeatedField; -using google::protobuf::RepeatedPtrField; - -namespace policy { - -// Saves policy information to a file. -class PersistPolicyTask : public Task { - public: - PersistPolicyTask(const FilePath& path, - const em::DevicePolicyResponse* policy, - const base::Time& timestamp, - const bool is_device_unmanaged) - : path_(path), - policy_(policy), - timestamp_(timestamp), - is_device_unmanaged_(is_device_unmanaged) {} - - private: - // Task override. - virtual void Run(); - - const FilePath path_; - scoped_ptr<const em::DevicePolicyResponse> policy_; - const base::Time timestamp_; - const bool is_device_unmanaged_; -}; - -void PersistPolicyTask::Run() { - std::string data; - em::CachedDevicePolicyResponse cached_policy; - if (policy_.get()) - cached_policy.mutable_policy()->CopyFrom(*policy_); - if (is_device_unmanaged_) - cached_policy.set_unmanaged(true); - cached_policy.set_timestamp(timestamp_.ToInternalValue()); - if (!cached_policy.SerializeToString(&data)) { - LOG(WARNING) << "Failed to serialize policy data"; - return; - } - - int size = data.size(); - if (file_util::WriteFile(path_, data.c_str(), size) != size) { - LOG(WARNING) << "Failed to write " << path_.value(); - return; - } -} - -DeviceManagementPolicyCache::DeviceManagementPolicyCache( - const FilePath& backing_file_path) - : backing_file_path_(backing_file_path), - policy_(new DictionaryValue), - fresh_policy_(false), - is_device_unmanaged_(false) { -} - -DeviceManagementPolicyCache::~DeviceManagementPolicyCache() {} - -void DeviceManagementPolicyCache::LoadPolicyFromFile() { - if (!file_util::PathExists(backing_file_path_) || fresh_policy_) - return; - - // Read the protobuf from the file. - std::string data; - if (!file_util::ReadFileToString(backing_file_path_, &data)) { - LOG(WARNING) << "Failed to read policy data from " - << backing_file_path_.value(); - return; - } - - em::CachedDevicePolicyResponse cached_policy; - if (!cached_policy.ParseFromArray(data.c_str(), data.size())) { - LOG(WARNING) << "Failed to parse policy data read from " - << backing_file_path_.value(); - return; - } - - // Reject files that claim to be from the future. - base::Time timestamp = base::Time::FromInternalValue( - cached_policy.timestamp()); - if (timestamp > base::Time::NowFromSystemTime()) { - LOG(WARNING) << "Rejected policy data from " << backing_file_path_.value() - << ", file is from the future."; - return; - } - is_device_unmanaged_ = cached_policy.unmanaged(); - - // Decode and swap in the new policy information. - scoped_ptr<DictionaryValue> value(DecodePolicy(cached_policy.policy())); - { - base::AutoLock lock(lock_); - if (!fresh_policy_) - policy_.reset(value.release()); - last_policy_refresh_time_ = timestamp; - } -} - -bool DeviceManagementPolicyCache::SetPolicy( - const em::DevicePolicyResponse& policy) { - is_device_unmanaged_ = false; - DictionaryValue* value = DeviceManagementPolicyCache::DecodePolicy(policy); - const bool new_policy_differs = !(value->Equals(policy_.get())); - base::Time now(base::Time::NowFromSystemTime()); - { - base::AutoLock lock(lock_); - policy_.reset(value); - fresh_policy_ = true; - last_policy_refresh_time_ = now; - } - - em::DevicePolicyResponse* policy_copy = new em::DevicePolicyResponse; - policy_copy->CopyFrom(policy); - BrowserThread::PostTask( - BrowserThread::FILE, - FROM_HERE, - new PersistPolicyTask(backing_file_path_, policy_copy, now, false)); - return new_policy_differs; -} - -DictionaryValue* DeviceManagementPolicyCache::GetPolicy() { - base::AutoLock lock(lock_); - return policy_->DeepCopy(); -} - -void DeviceManagementPolicyCache::SetDeviceUnmanaged() { - is_device_unmanaged_ = true; - base::Time now(base::Time::NowFromSystemTime()); - { - base::AutoLock lock(lock_); - policy_.reset(new DictionaryValue); - last_policy_refresh_time_ = now; - } - BrowserThread::PostTask( - BrowserThread::FILE, - FROM_HERE, - new PersistPolicyTask(backing_file_path_, NULL, now, true)); -} - -// static -Value* DeviceManagementPolicyCache::DecodeIntegerValue( - google::protobuf::int64 value) { - if (value < std::numeric_limits<int>::min() || - value > std::numeric_limits<int>::max()) { - LOG(WARNING) << "Integer value " << value - << " out of numeric limits, ignoring."; - return NULL; - } - - return Value::CreateIntegerValue(static_cast<int>(value)); -} - -// static -Value* DeviceManagementPolicyCache::DecodeValue(const em::GenericValue& value) { - if (!value.has_value_type()) - return NULL; - - switch (value.value_type()) { - case em::GenericValue::VALUE_TYPE_BOOL: - if (value.has_bool_value()) - return Value::CreateBooleanValue(value.bool_value()); - return NULL; - case em::GenericValue::VALUE_TYPE_INT64: - if (value.has_int64_value()) - return DecodeIntegerValue(value.int64_value()); - return NULL; - case em::GenericValue::VALUE_TYPE_STRING: - if (value.has_string_value()) - return Value::CreateStringValue(value.string_value()); - return NULL; - case em::GenericValue::VALUE_TYPE_DOUBLE: - if (value.has_double_value()) - return Value::CreateDoubleValue(value.double_value()); - return NULL; - case em::GenericValue::VALUE_TYPE_BYTES: - if (value.has_bytes_value()) { - std::string bytes = value.bytes_value(); - return BinaryValue::CreateWithCopiedBuffer(bytes.c_str(), bytes.size()); - } - return NULL; - case em::GenericValue::VALUE_TYPE_BOOL_ARRAY: { - ListValue* list = new ListValue; - RepeatedField<bool>::const_iterator i; - for (i = value.bool_array().begin(); i != value.bool_array().end(); ++i) - list->Append(Value::CreateBooleanValue(*i)); - return list; - } - case em::GenericValue::VALUE_TYPE_INT64_ARRAY: { - ListValue* list = new ListValue; - RepeatedField<google::protobuf::int64>::const_iterator i; - for (i = value.int64_array().begin(); - i != value.int64_array().end(); ++i) { - Value* int_value = DecodeIntegerValue(*i); - if (int_value) - list->Append(int_value); - } - return list; - } - case em::GenericValue::VALUE_TYPE_STRING_ARRAY: { - ListValue* list = new ListValue; - RepeatedPtrField<std::string>::const_iterator i; - for (i = value.string_array().begin(); - i != value.string_array().end(); ++i) - list->Append(Value::CreateStringValue(*i)); - return list; - } - case em::GenericValue::VALUE_TYPE_DOUBLE_ARRAY: { - ListValue* list = new ListValue; - RepeatedField<double>::const_iterator i; - for (i = value.double_array().begin(); - i != value.double_array().end(); ++i) - list->Append(Value::CreateDoubleValue(*i)); - return list; - } - default: - NOTREACHED() << "Unhandled value type"; - } - - return NULL; -} - -// static -DictionaryValue* DeviceManagementPolicyCache::DecodePolicy( - const em::DevicePolicyResponse& policy) { - DictionaryValue* result = new DictionaryValue; - RepeatedPtrField<em::DevicePolicySetting>::const_iterator setting; - for (setting = policy.setting().begin(); - setting != policy.setting().end(); - ++setting) { - // Wrong policy key? Skip. - if (setting->policy_key().compare(kChromeDevicePolicySettingKey) != 0) - continue; - - // No policy value? Skip. - if (!setting->has_policy_value()) - continue; - - // Iterate through all the name-value pairs wrapped in |setting|. - const em::GenericSetting& policy_value(setting->policy_value()); - RepeatedPtrField<em::GenericNamedValue>::const_iterator named_value; - for (named_value = policy_value.named_value().begin(); - named_value != policy_value.named_value().end(); - ++named_value) { - if (named_value->has_value()) { - Value* decoded_value = - DeviceManagementPolicyCache::DecodeValue(named_value->value()); - if (decoded_value) - result->Set(named_value->name(), decoded_value); - } - } - } - return result; -} - -} // namespace policy diff --git a/chrome/browser/policy/device_management_policy_cache.h b/chrome/browser/policy/device_management_policy_cache.h deleted file mode 100644 index 50441eb..0000000 --- a/chrome/browser/policy/device_management_policy_cache.h +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2010 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. - -#ifndef CHROME_BROWSER_POLICY_DEVICE_MANAGEMENT_POLICY_CACHE_H_ -#define CHROME_BROWSER_POLICY_DEVICE_MANAGEMENT_POLICY_CACHE_H_ - -#include "base/file_path.h" -#include "base/gtest_prod_util.h" -#include "base/ref_counted.h" -#include "base/scoped_ptr.h" -#include "base/synchronization/lock.h" -#include "base/time.h" -#include "chrome/browser/policy/proto/device_management_backend.pb.h" - -class DictionaryValue; -class Value; - -namespace policy { - -namespace em = enterprise_management; - -// Keeps the authoritative copy of cloud policy information as read from the -// persistence file or determined by the policy backend. The cache doesn't talk -// to the service directly, but receives updated policy information through -// SetPolicy() calls, which is then persisted and decoded into the internal -// Value representation chrome uses. -class DeviceManagementPolicyCache { - public: - explicit DeviceManagementPolicyCache(const FilePath& backing_file_path); - ~DeviceManagementPolicyCache(); - - // Loads policy information from the backing file. Non-existing or erroneous - // cache files are ignored. - void LoadPolicyFromFile(); - - // Resets the policy information. Returns true if the new policy is different - // from the previously stored policy. - bool SetPolicy(const em::DevicePolicyResponse& policy); - - // Gets the policy information. Ownership of the return value is transferred - // to the caller. - DictionaryValue* GetPolicy(); - - void SetDeviceUnmanaged(); - bool is_device_unmanaged() const { - return is_device_unmanaged_; - } - - // Returns the time as which the policy was last fetched. - base::Time last_policy_refresh_time() const { - return last_policy_refresh_time_; - } - - private: - friend class DeviceManagementPolicyCacheDecodeTest; - FRIEND_TEST_ALL_PREFIXES(DeviceManagementPolicyCacheDecodeTest, DecodePolicy); - - // Decodes an int64 value. Checks whether the passed value fits the numeric - // limits of the value representation. Returns a value (ownership is - // transferred to the caller) on success, NULL on failure. - static Value* DecodeIntegerValue(google::protobuf::int64 value); - - // Decode a GenericValue message to the Value representation used internally. - // Returns NULL if |value| is invalid (i.e. contains no actual value). - static Value* DecodeValue(const em::GenericValue& value); - - // Decodes a policy message and returns it in Value representation. Ownership - // of the returned dictionary is transferred to the caller. - static DictionaryValue* DecodePolicy( - const em::DevicePolicyResponse& response); - - // The file in which we store a cached version of the policy information. - const FilePath backing_file_path_; - - // Protects |policy_|. - base::Lock lock_; - - // Policy key-value information. - scoped_ptr<DictionaryValue> policy_; - - // Tracks whether the store received a SetPolicy() call, which overrides any - // information loaded from the file. - bool fresh_policy_; - - bool is_device_unmanaged_; - - // The time at which the policy was last refreshed. - base::Time last_policy_refresh_time_; -}; - -} // namespace policy - -#endif // CHROME_BROWSER_POLICY_DEVICE_MANAGEMENT_POLICY_CACHE_H_ diff --git a/chrome/browser/policy/device_management_policy_cache_unittest.cc b/chrome/browser/policy/device_management_policy_cache_unittest.cc deleted file mode 100644 index 1fe98c8..0000000 --- a/chrome/browser/policy/device_management_policy_cache_unittest.cc +++ /dev/null @@ -1,321 +0,0 @@ -// Copyright (c) 2010 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/policy/device_management_policy_cache.h" - -#include <limits> -#include <string> - -#include "base/file_util.h" -#include "base/message_loop.h" -#include "base/scoped_temp_dir.h" -#include "base/values.h" -#include "chrome/browser/browser_thread.h" -#include "chrome/browser/policy/proto/device_management_constants.h" -#include "chrome/browser/policy/proto/device_management_local.pb.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace policy { - -// Wraps base functionaly for the test cases. -class DeviceManagementPolicyCacheTestBase : public testing::Test { - protected: - // Add a string policy setting to a policy response message. - void AddStringPolicy(em::DevicePolicyResponse* policy, - const std::string& name, - const std::string& value) { - em::DevicePolicySetting* setting = policy->add_setting(); - setting->set_policy_key(kChromeDevicePolicySettingKey); - em::GenericSetting* policy_value = setting->mutable_policy_value(); - em::GenericNamedValue* named_value = policy_value->add_named_value(); - named_value->set_name(name); - em::GenericValue* value_container = named_value->mutable_value(); - value_container->set_value_type(em::GenericValue::VALUE_TYPE_STRING); - value_container->set_string_value(value); - } -}; - -// Tests the device management policy cache. -class DeviceManagementPolicyCacheTest - : public DeviceManagementPolicyCacheTestBase { - protected: - DeviceManagementPolicyCacheTest() - : loop_(MessageLoop::TYPE_UI), - ui_thread_(BrowserThread::UI, &loop_), - file_thread_(BrowserThread::FILE, &loop_) {} - - void SetUp() { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - } - - void TearDown() { - loop_.RunAllPending(); - } - - void WritePolicy(const em::DevicePolicyResponse& policy, - const base::Time& timestamp) { - std::string data; - em::CachedDevicePolicyResponse cached_policy; - cached_policy.mutable_policy()->CopyFrom(policy); - cached_policy.set_timestamp(timestamp.ToInternalValue()); - EXPECT_TRUE(cached_policy.SerializeToString(&data)); - int size = static_cast<int>(data.size()); - EXPECT_EQ(size, file_util::WriteFile(test_file(), data.c_str(), size)); - } - - FilePath test_file() { - return temp_dir_.path().AppendASCII("DeviceManagementPolicyCacheTest"); - } - - protected: - MessageLoop loop_; - - private: - ScopedTempDir temp_dir_; - BrowserThread ui_thread_; - BrowserThread file_thread_; -}; - -TEST_F(DeviceManagementPolicyCacheTest, Empty) { - DeviceManagementPolicyCache cache(test_file()); - DictionaryValue empty; - scoped_ptr<Value> policy(cache.GetPolicy()); - EXPECT_TRUE(empty.Equals(policy.get())); - EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); -} - -TEST_F(DeviceManagementPolicyCacheTest, LoadNoFile) { - DeviceManagementPolicyCache cache(test_file()); - cache.LoadPolicyFromFile(); - DictionaryValue empty; - scoped_ptr<Value> policy(cache.GetPolicy()); - EXPECT_TRUE(empty.Equals(policy.get())); - EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); -} - -TEST_F(DeviceManagementPolicyCacheTest, RejectFuture) { - em::DevicePolicyResponse policy_response; - WritePolicy(policy_response, base::Time::NowFromSystemTime() + - base::TimeDelta::FromMinutes(5)); - DeviceManagementPolicyCache cache(test_file()); - cache.LoadPolicyFromFile(); - DictionaryValue empty; - scoped_ptr<Value> policy(cache.GetPolicy()); - EXPECT_TRUE(empty.Equals(policy.get())); - EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); -} - -TEST_F(DeviceManagementPolicyCacheTest, LoadWithFile) { - em::DevicePolicyResponse policy_response; - WritePolicy(policy_response, base::Time::NowFromSystemTime()); - DeviceManagementPolicyCache cache(test_file()); - cache.LoadPolicyFromFile(); - DictionaryValue empty; - scoped_ptr<Value> policy(cache.GetPolicy()); - EXPECT_TRUE(empty.Equals(policy.get())); - EXPECT_NE(base::Time(), cache.last_policy_refresh_time()); - EXPECT_GE(base::Time::Now(), cache.last_policy_refresh_time()); -} - -TEST_F(DeviceManagementPolicyCacheTest, LoadWithData) { - em::DevicePolicyResponse policy; - AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); - WritePolicy(policy, base::Time::NowFromSystemTime()); - DeviceManagementPolicyCache cache(test_file()); - cache.LoadPolicyFromFile(); - DictionaryValue expected; - expected.Set("HomepageLocation", - Value::CreateStringValue("http://www.example.com")); - scoped_ptr<Value> policy_value(cache.GetPolicy()); - EXPECT_TRUE(expected.Equals(policy_value.get())); -} - -TEST_F(DeviceManagementPolicyCacheTest, SetPolicy) { - DeviceManagementPolicyCache cache(test_file()); - em::DevicePolicyResponse policy; - AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); - EXPECT_TRUE(cache.SetPolicy(policy)); - em::DevicePolicyResponse policy2; - AddStringPolicy(&policy2, "HomepageLocation", "http://www.example.com"); - EXPECT_FALSE(cache.SetPolicy(policy2)); - DictionaryValue expected; - expected.Set("HomepageLocation", - Value::CreateStringValue("http://www.example.com")); - scoped_ptr<Value> policy_value(cache.GetPolicy()); - EXPECT_TRUE(expected.Equals(policy_value.get())); -} - -TEST_F(DeviceManagementPolicyCacheTest, ResetPolicy) { - DeviceManagementPolicyCache cache(test_file()); - - em::DevicePolicyResponse policy; - AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); - EXPECT_TRUE(cache.SetPolicy(policy)); - DictionaryValue expected; - expected.Set("HomepageLocation", - Value::CreateStringValue("http://www.example.com")); - scoped_ptr<Value> policy_value(cache.GetPolicy()); - EXPECT_TRUE(expected.Equals(policy_value.get())); - - EXPECT_TRUE(cache.SetPolicy(em::DevicePolicyResponse())); - policy_value.reset(cache.GetPolicy()); - DictionaryValue empty; - EXPECT_TRUE(empty.Equals(policy_value.get())); -} - -TEST_F(DeviceManagementPolicyCacheTest, PersistPolicy) { - { - DeviceManagementPolicyCache cache(test_file()); - em::DevicePolicyResponse policy; - AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); - cache.SetPolicy(policy); - } - - loop_.RunAllPending(); - - EXPECT_TRUE(file_util::PathExists(test_file())); - DeviceManagementPolicyCache cache(test_file()); - cache.LoadPolicyFromFile(); - DictionaryValue expected; - expected.Set("HomepageLocation", - Value::CreateStringValue("http://www.example.com")); - scoped_ptr<Value> policy_value(cache.GetPolicy()); - EXPECT_TRUE(expected.Equals(policy_value.get())); -} - -TEST_F(DeviceManagementPolicyCacheTest, FreshPolicyOverride) { - em::DevicePolicyResponse policy; - AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); - WritePolicy(policy, base::Time::NowFromSystemTime()); - - DeviceManagementPolicyCache cache(test_file()); - em::DevicePolicyResponse updated_policy; - AddStringPolicy(&updated_policy, "HomepageLocation", - "http://www.chromium.org"); - EXPECT_TRUE(cache.SetPolicy(updated_policy)); - - cache.LoadPolicyFromFile(); - DictionaryValue expected; - expected.Set("HomepageLocation", - Value::CreateStringValue("http://www.chromium.org")); - scoped_ptr<Value> policy_value(cache.GetPolicy()); - EXPECT_TRUE(expected.Equals(policy_value.get())); -} - -// Tests proper decoding of policy values. -class DeviceManagementPolicyCacheDecodeTest - : public DeviceManagementPolicyCacheTestBase { - protected: - void DecodeAndCheck(Value* expected_value_ptr) { - scoped_ptr<Value> expected_value(expected_value_ptr); - scoped_ptr<Value> decoded_value( - DeviceManagementPolicyCache::DecodeValue(value_)); - if (expected_value_ptr) { - ASSERT_TRUE(decoded_value.get()); - EXPECT_TRUE(decoded_value->Equals(expected_value.get())); - } else { - ASSERT_FALSE(decoded_value.get()); - } - } - - em::GenericValue value_; -}; - -TEST_F(DeviceManagementPolicyCacheDecodeTest, Bool) { - value_.set_value_type(em::GenericValue::VALUE_TYPE_BOOL); - value_.set_bool_value(true); - DecodeAndCheck(Value::CreateBooleanValue(true)); -} - -TEST_F(DeviceManagementPolicyCacheDecodeTest, Int64) { - value_.set_value_type(em::GenericValue::VALUE_TYPE_INT64); - value_.set_int64_value(42); - DecodeAndCheck(Value::CreateIntegerValue(42)); -} - -TEST_F(DeviceManagementPolicyCacheDecodeTest, Int64Overflow) { - const int min = std::numeric_limits<int>::min(); - const int max = std::numeric_limits<int>::max(); - value_.set_value_type(em::GenericValue::VALUE_TYPE_INT64); - value_.set_int64_value(min - 1LL); - DecodeAndCheck(NULL); - value_.set_int64_value(max + 1LL); - DecodeAndCheck(NULL); - value_.set_int64_value(min); - DecodeAndCheck(Value::CreateIntegerValue(min)); - value_.set_int64_value(max); - DecodeAndCheck(Value::CreateIntegerValue(max)); -} - -TEST_F(DeviceManagementPolicyCacheDecodeTest, String) { - value_.set_value_type(em::GenericValue::VALUE_TYPE_STRING); - value_.set_string_value("ponies!"); - DecodeAndCheck(Value::CreateStringValue("ponies!")); -} - -TEST_F(DeviceManagementPolicyCacheDecodeTest, Double) { - value_.set_value_type(em::GenericValue::VALUE_TYPE_DOUBLE); - value_.set_double_value(0.42L); - DecodeAndCheck(Value::CreateDoubleValue(0.42L)); -} - -TEST_F(DeviceManagementPolicyCacheDecodeTest, Bytes) { - std::string data("binary ponies."); - value_.set_value_type(em::GenericValue::VALUE_TYPE_BYTES); - value_.set_bytes_value(data); - DecodeAndCheck( - BinaryValue::CreateWithCopiedBuffer(data.c_str(), data.size())); -} - -TEST_F(DeviceManagementPolicyCacheDecodeTest, BoolArray) { - value_.set_value_type(em::GenericValue::VALUE_TYPE_BOOL_ARRAY); - value_.add_bool_array(false); - value_.add_bool_array(true); - ListValue* list = new ListValue; - list->Append(Value::CreateBooleanValue(false)); - list->Append(Value::CreateBooleanValue(true)); - DecodeAndCheck(list); -} - -TEST_F(DeviceManagementPolicyCacheDecodeTest, Int64Array) { - value_.set_value_type(em::GenericValue::VALUE_TYPE_INT64_ARRAY); - value_.add_int64_array(42); - value_.add_int64_array(17); - ListValue* list = new ListValue; - list->Append(Value::CreateIntegerValue(42)); - list->Append(Value::CreateIntegerValue(17)); - DecodeAndCheck(list); -} - -TEST_F(DeviceManagementPolicyCacheDecodeTest, StringArray) { - value_.set_value_type(em::GenericValue::VALUE_TYPE_STRING_ARRAY); - value_.add_string_array("ponies"); - value_.add_string_array("more ponies"); - ListValue* list = new ListValue; - list->Append(Value::CreateStringValue("ponies")); - list->Append(Value::CreateStringValue("more ponies")); - DecodeAndCheck(list); -} - -TEST_F(DeviceManagementPolicyCacheDecodeTest, DoubleArray) { - value_.set_value_type(em::GenericValue::VALUE_TYPE_DOUBLE_ARRAY); - value_.add_double_array(0.42L); - value_.add_double_array(0.17L); - ListValue* list = new ListValue; - list->Append(Value::CreateDoubleValue(0.42L)); - list->Append(Value::CreateDoubleValue(0.17L)); - DecodeAndCheck(list); -} - -TEST_F(DeviceManagementPolicyCacheDecodeTest, DecodePolicy) { - em::DevicePolicyResponse policy; - AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); - scoped_ptr<Value> decoded(DeviceManagementPolicyCache::DecodePolicy(policy)); - DictionaryValue expected; - expected.Set("HomepageLocation", - Value::CreateStringValue("http://www.example.com")); - EXPECT_TRUE(expected.Equals(decoded.get())); -} - -} // namespace policy diff --git a/chrome/browser/policy/device_management_policy_provider.cc b/chrome/browser/policy/device_management_policy_provider.cc index 315a6d2..eaaf4d4 100644 --- a/chrome/browser/policy/device_management_policy_provider.cc +++ b/chrome/browser/policy/device_management_policy_provider.cc @@ -4,14 +4,16 @@ #include "chrome/browser/policy/device_management_policy_provider.h" +#include <algorithm> + #include "base/command_line.h" #include "base/file_util.h" #include "base/path_service.h" #include "base/rand_util.h" #include "base/task.h" #include "chrome/browser/browser_thread.h" +#include "chrome/browser/policy/cloud_policy_cache.h" #include "chrome/browser/policy/device_management_backend.h" -#include "chrome/browser/policy/device_management_policy_cache.h" #include "chrome/browser/policy/profile_policy_context.h" #include "chrome/browser/policy/proto/device_management_constants.h" #include "chrome/browser/profiles/profile.h" @@ -86,8 +88,13 @@ DeviceManagementPolicyProvider::~DeviceManagementPolicyProvider() { bool DeviceManagementPolicyProvider::Provide( ConfigurationPolicyStoreInterface* policy_store) { - scoped_ptr<DictionaryValue> policies(cache_->GetPolicy()); - DecodePolicyValueTree(policies.get(), policy_store); + if (cache_->has_device_policy()) { + scoped_ptr<DictionaryValue> policies(cache_->GetDevicePolicy()); + ApplyPolicyValueTree(policies.get(), policy_store); + } else { + ApplyPolicyMap(cache_->GetMandatoryPolicy(), policy_store); + // TODO(jkummerow, mnissler): provide recommended policy. + } return true; } @@ -98,13 +105,23 @@ bool DeviceManagementPolicyProvider::IsInitializationComplete() const { void DeviceManagementPolicyProvider::HandlePolicyResponse( const em::DevicePolicyResponse& response) { DCHECK(TokenAvailable()); - if (cache_->SetPolicy(response)) { + if (cache_->SetDevicePolicy(response)) { initial_fetch_done_ = true; NotifyCloudPolicyUpdate(); } SetState(STATE_POLICY_VALID); } +void DeviceManagementPolicyProvider::HandleCloudPolicyResponse( + const em::CloudPolicyResponse& response) { + DCHECK(TokenAvailable()); + if (cache_->SetPolicy(response)) { + initial_fetch_done_ = true; + NotifyCloudPolicyUpdate(); + } + SetState(STATE_POLICY_VALID); +} + void DeviceManagementPolicyProvider::OnError( DeviceManagementBackend::ErrorCode code) { DCHECK(TokenAvailable()); @@ -117,6 +134,12 @@ void DeviceManagementPolicyProvider::OnError( DeviceManagementBackend::kErrorServiceManagementNotSupported) { VLOG(1) << "The device is no longer managed, resetting device token."; SetState(STATE_TOKEN_RESET); + } else if (!fallback_to_old_protocol_ && + code == DeviceManagementBackend::kErrorRequestInvalid) { + LOG(WARNING) << "Device management server doesn't understand new protocol," + << " falling back to old request."; + fallback_to_old_protocol_ = true; + SetState(STATE_TOKEN_VALID); // Triggers SendPolicyRequest() immediately. } else { LOG(WARNING) << "Could not provide policy from the device manager (error = " << code << "), will retry in " @@ -140,7 +163,7 @@ void DeviceManagementPolicyProvider::OnTokenError() { void DeviceManagementPolicyProvider::OnNotManaged() { DCHECK(!TokenAvailable()); VLOG(1) << "This device is not managed."; - cache_->SetDeviceUnmanaged(); + cache_->SetUnmanaged(); SetState(STATE_UNMANAGED); } @@ -186,6 +209,7 @@ void DeviceManagementPolicyProvider::Initialize( DCHECK(profile); backend_.reset(backend); profile_ = profile; + fallback_to_old_protocol_ = false; storage_dir_ = GetOrCreateDeviceManagementDir(profile_->GetPath()); state_ = STATE_INITIALIZING; initial_fetch_done_ = false; @@ -201,13 +225,13 @@ void DeviceManagementPolicyProvider::Initialize( unmanaged_device_refresh_rate_ms_ = unmanaged_device_refresh_rate_ms; const FilePath policy_path = storage_dir_.Append(kPolicyFilename); - cache_.reset(new DeviceManagementPolicyCache(policy_path)); + cache_.reset(new CloudPolicyCache(policy_path)); cache_->LoadPolicyFromFile(); SetDeviceTokenFetcher(new DeviceTokenFetcher(backend_.get(), profile, GetTokenPath())); - if (cache_->is_device_unmanaged()) { + if (cache_->is_unmanaged()) { // This is a non-first login on an unmanaged device. SetState(STATE_UNMANAGED); } else { @@ -226,15 +250,23 @@ void DeviceManagementPolicyProvider::RemoveObserver( } void DeviceManagementPolicyProvider::SendPolicyRequest() { - em::DevicePolicyRequest policy_request; - policy_request.set_policy_scope(kChromePolicyScope); - em::DevicePolicySettingRequest* setting = - policy_request.add_setting_request(); - setting->set_key(kChromeDevicePolicySettingKey); - setting->set_watermark(""); - backend_->ProcessPolicyRequest(token_fetcher_->GetDeviceToken(), - token_fetcher_->GetDeviceID(), - policy_request, this); + if (!fallback_to_old_protocol_) { + em::CloudPolicyRequest policy_request; + policy_request.set_policy_scope(kChromePolicyScope); + backend_->ProcessCloudPolicyRequest(token_fetcher_->GetDeviceToken(), + token_fetcher_->GetDeviceID(), + policy_request, this); + } else { + em::DevicePolicyRequest policy_request; + policy_request.set_policy_scope(kChromePolicyScope); + em::DevicePolicySettingRequest* setting = + policy_request.add_setting_request(); + setting->set_key(kChromeDevicePolicySettingKey); + setting->set_watermark(""); + backend_->ProcessPolicyRequest(token_fetcher_->GetDeviceToken(), + token_fetcher_->GetDeviceID(), + policy_request, this); + } } void DeviceManagementPolicyProvider::RefreshTaskExecute() { diff --git a/chrome/browser/policy/device_management_policy_provider.h b/chrome/browser/policy/device_management_policy_provider.h index 592df9b..dd09628 100644 --- a/chrome/browser/policy/device_management_policy_provider.h +++ b/chrome/browser/policy/device_management_policy_provider.h @@ -21,8 +21,8 @@ class TokenService; namespace policy { +class CloudPolicyCache; class DeviceManagementBackend; -class DeviceManagementPolicyCache; // Provides policy fetched from the device management server. With the exception // of the Provide method, which can be called on the FILE thread, all public @@ -44,7 +44,9 @@ class DeviceManagementPolicyProvider // DevicePolicyResponseDelegate implementation: virtual void HandlePolicyResponse( - const em::DevicePolicyResponse& response); + const em::DevicePolicyResponse& response); // deprecated. + virtual void HandleCloudPolicyResponse( + const em::CloudPolicyResponse& response); virtual void OnError(DeviceManagementBackend::ErrorCode code); // DeviceTokenFetcher::Observer implementation: @@ -146,7 +148,8 @@ class DeviceManagementPolicyProvider scoped_ptr<DeviceManagementBackend> backend_; Profile* profile_; // weak - scoped_ptr<DeviceManagementPolicyCache> cache_; + scoped_ptr<CloudPolicyCache> cache_; + bool fallback_to_old_protocol_; scoped_refptr<DeviceTokenFetcher> token_fetcher_; DeviceTokenFetcher::ObserverRegistrar registrar_; ObserverList<ConfigurationPolicyProvider::Observer, true> observer_list_; diff --git a/chrome/browser/policy/device_management_policy_provider_unittest.cc b/chrome/browser/policy/device_management_policy_provider_unittest.cc index d0a0eaa..8dc3bf4 100644 --- a/chrome/browser/policy/device_management_policy_provider_unittest.cc +++ b/chrome/browser/policy/device_management_policy_provider_unittest.cc @@ -7,9 +7,9 @@ #include "base/scoped_temp_dir.h" #include "chrome/browser/browser_thread.h" #include "chrome/browser/net/gaia/token_service.h" +#include "chrome/browser/policy/cloud_policy_cache.h" #include "chrome/browser/policy/configuration_policy_pref_store.h" #include "chrome/browser/policy/configuration_policy_provider.h" -#include "chrome/browser/policy/device_management_policy_cache.h" #include "chrome/browser/policy/device_management_policy_provider.h" #include "chrome/browser/policy/mock_configuration_policy_store.h" #include "chrome/browser/policy/mock_device_management_backend.h" @@ -113,9 +113,8 @@ class DeviceManagementPolicyProviderTest : public testing::Test { MockConfigurationPolicyStore store; EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy( - key::kDisableSpdy, true)); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); SimulateSuccessfulLoginAndRunPending(); EXPECT_FALSE(waiting_for_initial_policies()); EXPECT_CALL(store, Apply(kPolicyDisableSpdy, _)).Times(1); @@ -138,7 +137,7 @@ class DeviceManagementPolicyProviderTest : public testing::Test { scoped_ptr<DeviceManagementPolicyProvider> provider_; protected: - DeviceManagementPolicyCache* cache(DeviceManagementPolicyProvider* provider) { + CloudPolicyCache* cache(DeviceManagementPolicyProvider* provider) { return provider->cache_.get(); } @@ -193,9 +192,8 @@ TEST_F(DeviceManagementPolicyProviderTest, SecondProvide) { // Simulate a app relaunch by constructing a new provider. Policy should be // refreshed (since that might be the purpose of the app relaunch). CreateNewProvider(); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy( - key::kDisableSpdy, true)); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); loop_.RunAllPending(); Mock::VerifyAndClearExpectations(backend_); @@ -203,7 +201,7 @@ TEST_F(DeviceManagementPolicyProviderTest, SecondProvide) { // Cached policy should still be available. MockConfigurationPolicyStore store; CreateNewProvider(); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendFailPolicy( DeviceManagementBackend::kErrorRequestFailed)); SimulateSuccessfulLoginAndRunPending(); @@ -231,15 +229,14 @@ TEST_F(DeviceManagementPolicyProviderTest, ErrorCausesNewRequest) { DeviceManagementBackend::kErrorRequestFailed)); EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendFailPolicy( DeviceManagementBackend::kErrorRequestFailed)); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendFailPolicy( DeviceManagementBackend::kErrorRequestFailed)); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, - true)); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); } SimulateSuccessfulLoginAndRunPending(); } @@ -250,16 +247,13 @@ TEST_F(DeviceManagementPolicyProviderTest, RefreshPolicies) { CreateNewProvider(0, 0, 0, 1000 * 1000, 1000, 0); EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, - true)); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, - true)); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, - true)); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendFailPolicy( DeviceManagementBackend::kErrorRequestFailed)); } @@ -273,14 +267,13 @@ TEST_F(DeviceManagementPolicyProviderTest, DeviceNotFound) { InSequence s; EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendFailPolicy( DeviceManagementBackend::kErrorServiceDeviceNotFound)); EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, - true)); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); } SimulateSuccessfulLoginAndRunPending(); } @@ -292,14 +285,13 @@ TEST_F(DeviceManagementPolicyProviderTest, InvalidTokenOnPolicyRequest) { InSequence s; EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendFailPolicy( DeviceManagementBackend::kErrorServiceManagementTokenInvalid)); EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, - true)); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); } SimulateSuccessfulLoginAndRunPending(); } @@ -312,13 +304,11 @@ TEST_F(DeviceManagementPolicyProviderTest, DeviceNoLongerManaged) { CreateNewProvider(0, 0, 0, 0, 0, 1000 * 1000); EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, - true)); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, - true)); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendFailPolicy( DeviceManagementBackend::kErrorServiceManagementNotSupported)); EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( @@ -341,7 +331,7 @@ TEST_F(DeviceManagementPolicyProviderTest, UnmanagedDevice) { SimulateSuccessfulLoginAndRunPending(); // (1) The provider's DMPolicyCache should know that the device is not // managed. - EXPECT_TRUE(cache(provider_.get())->is_device_unmanaged()); + EXPECT_TRUE(cache(provider_.get())->is_unmanaged()); // (2) On restart, the provider should detect that this is not the first // login. CreateNewProvider(1000 * 1000, 0, 0, 0, 0, 0); @@ -350,14 +340,43 @@ TEST_F(DeviceManagementPolicyProviderTest, UnmanagedDevice) { InSequence s; EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, - true)); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); } SimulateSuccessfulLoginAndRunPending(); // (3) Since the backend call this time returned a device id, the "unmanaged" // marker should have been deleted. - EXPECT_FALSE(cache(provider_.get())->is_device_unmanaged()); + EXPECT_FALSE(cache(provider_.get())->is_unmanaged()); +} + +TEST_F(DeviceManagementPolicyProviderTest, FallbackToOldProtocol) { + { // Scoping so SimulateSuccessfulLoginAndRunPending doesn't see the sequence. + InSequence s; + CreateNewProvider(0, 0, 0, 0, 0, 1000 * 1000); + EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedRegister()); + // If the CloudPolicyRequest fails with kErrorRequestInvalid... + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendFailPolicy( + DeviceManagementBackend::kErrorRequestInvalid)); + // ...the client should fall back to a classic PolicyRequest... + EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedBooleanPolicy( + key::kDisableSpdy, true)); + // ...and remember this fallback for any future request, ... + EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendFailPolicy( + DeviceManagementBackend::kErrorHttpStatus)); + // ...both after successful fetches and after errors. + EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendFailPolicy( + DeviceManagementBackend::kErrorServiceManagementNotSupported)); + // Finally, we set the client to 'unmanaged' to stop its request stream. + EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendFailRegister( + DeviceManagementBackend::kErrorServiceManagementNotSupported)); + } + SimulateSuccessfulLoginAndRunPending(); } } // namespace policy diff --git a/chrome/browser/policy/mock_device_management_backend.h b/chrome/browser/policy/mock_device_management_backend.h index a684e4f..54c8c8f 100644 --- a/chrome/browser/policy/mock_device_management_backend.h +++ b/chrome/browser/policy/mock_device_management_backend.h @@ -9,6 +9,7 @@ #include <map> #include <string> +#include "base/time.h" #include "base/values.h" #include "chrome/browser/policy/device_management_backend.h" #include "chrome/browser/policy/proto/device_management_constants.h" @@ -46,6 +47,12 @@ class MockDeviceManagementBackend : public DeviceManagementBackend { const em::DevicePolicyRequest& request, DevicePolicyResponseDelegate* delegate)); + MOCK_METHOD4(ProcessCloudPolicyRequest, void( + const std::string& device_management_token, + const std::string& device_id, + const em::CloudPolicyRequest& request, + DevicePolicyResponseDelegate* delegate)); + private: DISALLOW_COPY_AND_ASSIGN(MockDeviceManagementBackend); }; @@ -73,6 +80,24 @@ ACTION_P2(MockDeviceManagementBackendSucceedBooleanPolicy, name, value) { arg3->HandlePolicyResponse(response); } +ACTION(MockDeviceManagementBackendSucceedSpdyCloudPolicy) { + em::SignedCloudPolicyResponse signed_response; + em::CloudPolicySettings* settings = signed_response.mutable_settings(); + em::DisableSpdyProto* spdy_proto = settings->mutable_disablespdy(); + spdy_proto->set_disablespdy(true); + spdy_proto->mutable_policy_options()->set_mode(em::PolicyOptions::MANDATORY); + signed_response.set_timestamp(base::Time::NowFromSystemTime().ToTimeT()); + std::string serialized_signed_response; + EXPECT_TRUE(signed_response.SerializeToString(&serialized_signed_response)); + em::CloudPolicyResponse response; + response.set_signed_response(serialized_signed_response); + // TODO(jkummerow): Set proper certificate_chain and signature (when + // implementing support for signature verification). + response.set_signature("TODO"); + response.add_certificate_chain("TODO"); + arg3->HandleCloudPolicyResponse(response); +} + ACTION_P(MockDeviceManagementBackendFailRegister, error) { arg3->OnError(error); } diff --git a/chrome/browser/policy/profile_policy_context.cc b/chrome/browser/policy/profile_policy_context.cc index 7adffd3..b8e3151a 100644 --- a/chrome/browser/policy/profile_policy_context.cc +++ b/chrome/browser/policy/profile_policy_context.cc @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <algorithm> +#include <string> + #include "base/command_line.h" #include "chrome/browser/policy/configuration_policy_pref_store.h" #include "chrome/browser/policy/device_management_policy_provider.h" @@ -20,7 +23,7 @@ namespace { const int64 kPolicyRefreshRateMinMs = 30 * 60 * 1000; // 30 minutes const int64 kPolicyRefreshRateMaxMs = 24 * 60 * 60 * 1000; // 1 day -} +} // namespace namespace policy { diff --git a/chrome/browser/policy/proto/cloud_policy.proto b/chrome/browser/policy/proto/cloud_policy.proto deleted file mode 100644 index 82a1135..0000000 --- a/chrome/browser/policy/proto/cloud_policy.proto +++ /dev/null @@ -1,221 +0,0 @@ -// -// DO NOT MODIFY THIS FILE DIRECTLY! -// ITS IS GENERATED BY generate_policy_source.py -// FROM policy_templates.json -// - -syntax = "proto2"; - -option optimize_for = LITE_RUNTIME; - -package enterprise_management; - -// PBs for individual settings. - -message PolicyOptions { - enum PolicyMode { - // The user may choose to override the given settings. - RECOMMENDED = 1; - // The given settings are applied regardless of user choice. - MANDATORY = 2; - } - optional PolicyMode mode = 1; -} - -message HomepageProto { - optional PolicyOptions policy_options = 1; - optional string HomepageLocation = 2; - optional bool HomepageIsNewTabPage = 3; -} - -message ApplicationLocaleValueProto { - optional PolicyOptions policy_options = 1; - optional string ApplicationLocaleValue = 2; -} - -message AlternateErrorPagesEnabledProto { - optional PolicyOptions policy_options = 1; - optional bool AlternateErrorPagesEnabled = 2; -} - -message SearchSuggestEnabledProto { - optional PolicyOptions policy_options = 1; - optional bool SearchSuggestEnabled = 2; -} - -message DnsPrefetchingEnabledProto { - optional PolicyOptions policy_options = 1; - optional bool DnsPrefetchingEnabled = 2; -} - -message DisableSpdyProto { - optional PolicyOptions policy_options = 1; - optional bool DisableSpdy = 2; -} - -message JavascriptEnabledProto { - optional PolicyOptions policy_options = 1; - optional bool JavascriptEnabled = 2; -} - -message SavingBrowserHistoryDisabledProto { - optional PolicyOptions policy_options = 1; - optional bool SavingBrowserHistoryDisabled = 2; -} - -message PrintingEnabledProto { - optional PolicyOptions policy_options = 1; - optional bool PrintingEnabled = 2; -} - -message SafeBrowsingEnabledProto { - optional PolicyOptions policy_options = 1; - optional bool SafeBrowsingEnabled = 2; -} - -message MetricsReportingEnabledProto { - optional PolicyOptions policy_options = 1; - optional bool MetricsReportingEnabled = 2; -} - -message PasswordManagerProto { - optional PolicyOptions policy_options = 1; - optional bool PasswordManagerEnabled = 2; - optional bool PasswordManagerAllowShowPasswords = 3; -} - -message AutoFillEnabledProto { - optional PolicyOptions policy_options = 1; - optional bool AutoFillEnabled = 2; -} - -message DisabledPluginsProto { - optional PolicyOptions policy_options = 1; - repeated string DisabledPlugins = 2; -} - -message SyncDisabledProto { - optional PolicyOptions policy_options = 1; - optional bool SyncDisabled = 2; -} - -message ProxyProto { - optional PolicyOptions policy_options = 1; - optional string ProxyMode = 2; - optional int64 ProxyServerMode = 3; - optional string ProxyServer = 4; - optional string ProxyPacUrl = 5; - optional string ProxyBypassList = 6; -} - -message HTTPAuthenticationProto { - optional PolicyOptions policy_options = 1; - optional string AuthSchemes = 2; - optional bool DisableAuthNegotiateCnameLookup = 3; - optional bool EnableAuthNegotiatePort = 4; - optional string AuthServerWhitelist = 5; - optional string AuthNegotiateDelegateWhitelist = 6; - optional string GSSAPILibraryName = 7; -} - -message ExtensionsProto { - optional PolicyOptions policy_options = 1; - repeated string ExtensionInstallBlacklist = 2; - repeated string ExtensionInstallWhitelist = 3; - repeated string ExtensionInstallForcelist = 4; -} - -message ShowHomeButtonProto { - optional PolicyOptions policy_options = 1; - optional bool ShowHomeButton = 2; -} - -message DeveloperToolsDisabledProto { - optional PolicyOptions policy_options = 1; - optional bool DeveloperToolsDisabled = 2; -} - -message RestoreOnStartupGroupProto { - optional PolicyOptions policy_options = 1; - optional int64 RestoreOnStartup = 2; - repeated string RestoreOnStartupURLs = 3; -} - -message DefaultSearchProviderProto { - optional PolicyOptions policy_options = 1; - optional bool DefaultSearchProviderEnabled = 2; - optional string DefaultSearchProviderName = 3; - optional string DefaultSearchProviderKeyword = 4; - optional string DefaultSearchProviderSearchURL = 5; - optional string DefaultSearchProviderSuggestURL = 6; - optional string DefaultSearchProviderInstantURL = 7; - optional string DefaultSearchProviderIconURL = 8; - repeated string DefaultSearchProviderEncodings = 9; -} - -message ContentSettingsProto { - optional PolicyOptions policy_options = 1; - optional int64 DefaultCookiesSetting = 2; - optional int64 DefaultImagesSetting = 3; - optional int64 DefaultJavaScriptSetting = 4; - optional int64 DefaultPluginsSetting = 5; - optional int64 DefaultPopupsSetting = 6; - optional int64 DefaultNotificationSetting = 7; - optional int64 DefaultGeolocationSetting = 8; -} - -message Disable3DAPIsProto { - optional PolicyOptions policy_options = 1; - optional bool Disable3DAPIs = 2; -} - -message ChromeFrameRendererSettingsProto { - optional PolicyOptions policy_options = 1; - optional int64 ChromeFrameRendererSettings = 2; - repeated string RenderInChromeFrameList = 3; - repeated string RenderInHostList = 4; -} - -message ChromeFrameContentTypesProto { - optional PolicyOptions policy_options = 1; - repeated string ChromeFrameContentTypes = 2; -} - -message ChromeOsLockOnIdleSuspendProto { - optional PolicyOptions policy_options = 1; - optional bool ChromeOsLockOnIdleSuspend = 2; -} - - -// -------------------------------------------------- -// Wrapper PB for DMServer -> ChromeOS communication. - -message CloudPolicySettings { - optional HomepageProto Homepage = 1; - optional ApplicationLocaleValueProto ApplicationLocaleValue = 2; - optional AlternateErrorPagesEnabledProto AlternateErrorPagesEnabled = 3; - optional SearchSuggestEnabledProto SearchSuggestEnabled = 4; - optional DnsPrefetchingEnabledProto DnsPrefetchingEnabled = 5; - optional DisableSpdyProto DisableSpdy = 6; - optional JavascriptEnabledProto JavascriptEnabled = 7; - optional SavingBrowserHistoryDisabledProto SavingBrowserHistoryDisabled = 8; - optional PrintingEnabledProto PrintingEnabled = 9; - optional SafeBrowsingEnabledProto SafeBrowsingEnabled = 10; - optional MetricsReportingEnabledProto MetricsReportingEnabled = 11; - optional PasswordManagerProto PasswordManager = 12; - optional AutoFillEnabledProto AutoFillEnabled = 13; - optional DisabledPluginsProto DisabledPlugins = 14; - optional SyncDisabledProto SyncDisabled = 15; - optional ProxyProto Proxy = 16; - optional HTTPAuthenticationProto HTTPAuthentication = 17; - optional ExtensionsProto Extensions = 18; - optional ShowHomeButtonProto ShowHomeButton = 19; - optional DeveloperToolsDisabledProto DeveloperToolsDisabled = 20; - optional RestoreOnStartupGroupProto RestoreOnStartupGroup = 21; - optional DefaultSearchProviderProto DefaultSearchProvider = 22; - optional ContentSettingsProto ContentSettings = 23; - optional Disable3DAPIsProto Disable3DAPIs = 24; - optional ChromeFrameRendererSettingsProto ChromeFrameRendererSettings = 25; - optional ChromeFrameContentTypesProto ChromeFrameContentTypes = 26; - optional ChromeOsLockOnIdleSuspendProto ChromeOsLockOnIdleSuspend = 27; -} diff --git a/chrome/browser/policy/proto/device_management_backend.proto b/chrome/browser/policy/proto/device_management_backend.proto index 3187f6b..1a857b6 100644 --- a/chrome/browser/policy/proto/device_management_backend.proto +++ b/chrome/browser/policy/proto/device_management_backend.proto @@ -88,62 +88,94 @@ message DevicePolicyResponse { repeated DevicePolicySetting setting = 1; } +// Request from device to server to register device. The response will include +// a device token that can be used to query policies. +message DeviceRegisterRequest { + // reregister device without erasing server state. + // it can be used to refresh dmtoken etc. + optional bool reregister = 1; +} + +// Response from server to device register request. +message DeviceRegisterResponse { + // device mangement toke for this registration. + required string device_management_token = 1; +} + // Protocol buffers for the new protocol: // -------------------------------------- -// Request from device to server to query if the authenticated user is in a -// managed domain. -message ManagedCheckRequest { +// Request from device to server to get policies for an unregistered user. +// These are actually "meta-policies", that control the rules for the user +// about enrolling for real policies. +message InitialPolicyRequest { } -// Response from server to device indicating if the authenticated user is in a -// managed domain. -message ManagedCheckResponse { - enum Mode { - // The device must be enrolled for policies. +message InitialPolicySettings { + enum EnrollmentRule { + // The user must enroll its device for policies. MANAGED = 1; - // The device is not automatically enrolled for policies, but the user - // may choose to try to enroll it. + // The users's device is not automatically enrolled for policies, but the + // user may choose to try to enroll it. UNMANAGED = 2; } - optional Mode mode = 1; + optional EnrollmentRule enrollment_rule = 1; } -// Request from device to server to register device. -message DeviceRegisterRequest { - // reregister device without erasing server state. - // it can be used to refresh dmtoken etc. - optional bool reregister = 1; +// Response from server to device containing the policies available before +// registration. +message InitialPolicyResponse { + optional InitialPolicySettings settings = 1; } -// Response from server to device register request. -message DeviceRegisterResponse { - // device mangement toke for this registration. - required string device_management_token = 1; +// Request from device to server to unregister device management token. +message DeviceUnregisterRequest { +} - // The name of the device, assigned by the server. - optional string device_name = 2; +// Response from server to unregister request. +message DeviceUnregisterResponse { } -// Request from device to server to unregister device. -message DeviceUnregisterRequest { +// Request from device to server to register device. The response will include +// a device token that can be used to query policies. +message CloudRegisterRequest { + enum Type { + // Requesting token for user policies. + USER = 1; + // Requesting token for device policies. + DEVICE = 2; + } + optional Type type = 1; + // Unique identifier of the machine. Only set if type == DEVICE. + // This won't be sent in later requests, the machine can be identified + // by its device token. + optional string machine_id = 2; } -// Response from server to device unregister request. -message DeviceUnregisterResponse { +// Response from server to device register request. +message CloudRegisterResponse { + // Token for this registration. + required string device_management_token = 1; + + // The name of the requesting device, assigned by the server. + optional string machine_name = 2; } message CloudPolicyRequest { // Identify request scope: chromeos/device for device policies, chromeos/user - // for user policies. + // for user policies. Only those policy scopes will be served, that are + // allowed by the type choice in CloudRegisterRequest. optional string policy_scope = 1; - // The device token of the owner of the device sending the request. In cases - // the request was sent by the device owner or device policies were - // requested, this is the same as the token used for authentication. - // Otherwise (if the user policy is requested for someone else than the device - // owner) this token is different from the token used for authentication. - optional string device_token = 2; + + // The token used to query device policies on the device sending the request. + // Note, that the token used for actual authentication is sent in an HTTP + // header. These two tokens are the same if this request is for querying + // device policies and they differ if this request is for querying user + // policies. In the second case, the server can use device_policy_token to + // identify the device and determine if the user is allowed to get policies + // on the given device. + optional string device_policy_token = 2; } // Response from server to device for reading policies. @@ -176,20 +208,20 @@ message SignedCloudPolicyResponse { // // Http Query parameters: // Query parameters contain the following information in each request: -// request: register/unregister/policy/cloud_policy/managed_check etc. +// request: register/unregister/policy/cloud_policy/cloud_register/ +// initial_policy // devicetype: CrOS/Android/Iphone etc. // apptype: CrOS/AndroidDM etc. -// deviceid: unique id that identify the device. // agent: identify agent on device. // // Authorization: -// 1. If request is managed_check, client must pass in GoogleLogin auth -// cookie in Authorization header: +// 1. If request is initial_policy, client must pass in GoogleLogin +// auth cookie in Authorization header: // Authorization: GoogleLogin auth=<auth cookie> -// This is the only case when the deviceid query parameter is set to empty. -// The response will contain a flag indicating if the user is in a managed -// domain or not. (We don't want to expose device ids of users not in -// managed domains.) +// The response will contain settings that a user can get without +// registration. Currently the only such setting is a flag indicating if the +// user is in a managed domain or not. (We don't want to expose device ids of +// users not in managed domains.) // 2. If request is register_request, client must pass in GoogleLogin auth // cookie in Authorization header: // Authorization: GoogleLogin auth=<auth cookie> @@ -200,7 +232,7 @@ message SignedCloudPolicyResponse { // Authorization: GoogleDMToken token=<google dm token> // message DeviceManagementRequest { - // Register request. + // Register request (old protocol). optional DeviceRegisterRequest register_request = 1; // Unregister request. @@ -212,8 +244,11 @@ message DeviceManagementRequest { // Data request (new protocol). optional CloudPolicyRequest cloud_policy_request = 4; - // Request to check if a user is managed or not. - optional ManagedCheckRequest managed_check_request = 5; + // Request for initial (before registration) policies. + optional InitialPolicyRequest initial_policy_request = 5; + + // Register request (new protocol). + optional CloudRegisterRequest cloud_register_request = 6; } // Response from server to device. @@ -241,7 +276,7 @@ message DeviceManagementResponse { // Error message. optional string error_message = 2; - // Register response + // Register response (old protocol). optional DeviceRegisterResponse register_response = 3; // Unregister response @@ -253,6 +288,9 @@ message DeviceManagementResponse { // Policy response (new protocol). optional CloudPolicyResponse cloud_policy_response = 6; - // Response to managed check request. - optional ManagedCheckResponse managed_check_response = 7; + // Response to initial (before registration) policy request. + optional InitialPolicyResponse initial_policy_response = 7; + + // Register response (new protocol). + optional CloudRegisterResponse cloud_register_response = 8; }
\ No newline at end of file diff --git a/chrome/browser/policy/proto/device_management_local.proto b/chrome/browser/policy/proto/device_management_local.proto index a991551..45c2994 100644 --- a/chrome/browser/policy/proto/device_management_local.proto +++ b/chrome/browser/policy/proto/device_management_local.proto @@ -10,14 +10,18 @@ package enterprise_management; import "device_management_backend.proto"; -// Wrapper around DevicePolicyResponse for caching on disk. -message CachedDevicePolicyResponse { +// Wrapper around CloudPolicyResponse/DevicePolicyResponse for caching on disk. +message CachedCloudPolicyResponse { // The DevicePolicyResponse wrapped by this message. - optional DevicePolicyResponse policy = 1; - // Timestamp noting when this policy was cached. + optional DevicePolicyResponse device_policy = 1; + // Timestamp noting when the |unmanaged| flag was set. The data format is + // a unix timestamp. When caching (deprecated) DevicePolicyResponses, this + // timestamp also notes when the response was cached. optional uint64 timestamp = 2; // Flag that is set to true if this device is not managed. optional bool unmanaged = 3; + // The CloudPolicyResponse wrapped by this message. + optional CloudPolicyResponse cloud_policy = 4; } // Encapsulates a device ID and the associated device token. diff --git a/chrome/browser/policy/proto/device_management_proto.gyp b/chrome/browser/policy/proto/device_management_proto.gyp deleted file mode 100644 index ede0251..0000000 --- a/chrome/browser/policy/proto/device_management_proto.gyp +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright (c) 2010 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. - -{ - 'variables': { - 'chromium_code': 1, - 'protoc_out_dir': '<(SHARED_INTERMEDIATE_DIR)/protoc_out', - }, - 'targets': [ - { - # Protobuf compiler / generate rule for the device management protocol. - 'target_name': 'device_management_proto', - 'type': 'none', - 'sources': [ - 'cloud_policy.proto', - 'device_management_backend.proto', - 'device_management_local.proto', - ], - 'rules': [ - { - 'rule_name': 'genproto', - 'extension': 'proto', - 'inputs': [ - '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)protoc<(EXECUTABLE_SUFFIX)', - ], - 'variables': { - # The protoc compiler requires a proto_path argument with the - # directory containing the .proto file. There's no generator - # variable that corresponds to this, so fake it. - 'rule_input_relpath': 'chrome/browser/policy/proto', - }, - 'outputs': [ - '<(PRODUCT_DIR)/pyproto/device_management_pb/<(RULE_INPUT_ROOT)_pb2.py', - '<(protoc_out_dir)/<(rule_input_relpath)/<(RULE_INPUT_ROOT).pb.h', - '<(protoc_out_dir)/<(rule_input_relpath)/<(RULE_INPUT_ROOT).pb.cc', - ], - 'action': [ - '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)protoc<(EXECUTABLE_SUFFIX)', - '--proto_path=.', - './<(RULE_INPUT_ROOT)<(RULE_INPUT_EXT)', - '--cpp_out=<(protoc_out_dir)/<(rule_input_relpath)', - '--python_out=<(PRODUCT_DIR)/pyproto/device_management_pb', - ], - 'message': 'Generating C++ and Python code from <(RULE_INPUT_PATH)', - }, - ], - 'dependencies': [ - '../../../../third_party/protobuf/protobuf.gyp:protoc#host', - ], - 'direct_dependent_settings': { - 'include_dirs': [ - '<(protoc_out_dir)', - ] - }, - }, - { - 'target_name': 'device_management_proto_cpp', - 'type': 'none', - 'export_dependent_settings': [ - '../../../../third_party/protobuf/protobuf.gyp:protobuf_lite', - 'device_management_proto', - ], - 'dependencies': [ - '../../../../third_party/protobuf/protobuf.gyp:protobuf_lite', - 'device_management_proto', - ], - 'direct_dependent_settings': { - 'include_dirs': [ - '<(protoc_out_dir)', - ] - }, - }, - ], -} - -# Local Variables: -# tab-width:2 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=2 shiftwidth=2: diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 80caf95..6b78cae 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -38,7 +38,6 @@ 'common_nacl_win64', 'common_constants_win64', 'installer_util_nacl_win64', - 'policy_win64', ], 'allocator_target': '../base/allocator/allocator.gyp:allocator', 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/chrome', @@ -849,10 +848,10 @@ '../third_party/icu/icu.gyp:icuuc', '../third_party/libjingle/libjingle.gyp:libjingle', '../third_party/sqlite/sqlite.gyp:sqlite', + 'app/policy/cloud_policy_codegen.gyp:policy', 'browser/sync/protocol/sync_proto.gyp:sync_proto_cpp', 'common_constants', 'common_net', - 'policy', 'sync', 'sync_notifier', ], @@ -1810,9 +1809,9 @@ 'type': 'executable', 'msvs_guid': '89C1C190-A5D1-4EC4-BD6A-67FF2195C7CC', 'dependencies': [ + 'app/policy/cloud_policy_codegen.gyp:policy', 'common_constants', 'installer_util', - 'policy', '../base/base.gyp:base', '../breakpad/breakpad.gyp:breakpad_handler', '../breakpad/breakpad.gyp:breakpad_sender', diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 7e853d6..85e4c01 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -9,7 +9,7 @@ 'type': '<(library)', 'msvs_guid': '5BF908A7-68FB-4A4B-99E3-8C749F1FE4EA', 'dependencies': [ - 'browser/policy/proto/device_management_proto.gyp:device_management_proto_cpp', + 'app/policy/cloud_policy_codegen.gyp:policy', 'browser/sync/protocol/sync_proto.gyp:sync_proto_cpp', 'chrome_extra_resources', 'chrome_resources', @@ -19,7 +19,6 @@ 'debugger', 'installer_util', 'platform_locale_settings', - 'policy', 'profile_import', 'safe_browsing_csd_proto', 'safe_browsing_report_proto', @@ -1763,6 +1762,8 @@ 'browser/policy/asynchronous_policy_loader.h', 'browser/policy/asynchronous_policy_provider.cc', 'browser/policy/asynchronous_policy_provider.h', + 'browser/policy/cloud_policy_cache.cc', + 'browser/policy/cloud_policy_cache.h', 'browser/policy/config_dir_policy_provider.cc', 'browser/policy/config_dir_policy_provider.h', 'browser/policy/configuration_policy_loader_win.cc', @@ -1783,8 +1784,6 @@ 'browser/policy/device_management_backend.h', 'browser/policy/device_management_backend_impl.cc', 'browser/policy/device_management_backend_impl.h', - 'browser/policy/device_management_policy_cache.cc', - 'browser/policy/device_management_policy_cache.h', 'browser/policy/device_management_policy_provider.cc', 'browser/policy/device_management_policy_provider.h', 'browser/policy/device_management_service.cc', @@ -1802,8 +1801,6 @@ 'browser/policy/profile_policy_context.cc', 'browser/policy/profile_policy_context.h', # TODO(danno): Find a better way to include these files - '<(protoc_out_dir)/chrome/browser/policy/proto/cloud_policy.pb.cc', - '<(protoc_out_dir)/chrome/browser/policy/proto/cloud_policy.pb.h', '<(protoc_out_dir)/chrome/browser/policy/proto/device_management_backend.pb.cc', '<(protoc_out_dir)/chrome/browser/policy/proto/device_management_backend.pb.h', 'browser/policy/proto/device_management_constants.cc', diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi index 01e28c8..1ee077a 100644 --- a/chrome/chrome_common.gypi +++ b/chrome/chrome_common.gypi @@ -202,12 +202,12 @@ # TODO(gregoryd): chrome_resources and chrome_strings could be # shared with the 64-bit target, but it does not work due to a gyp # issue. + 'app/policy/cloud_policy_codegen.gyp:policy', 'chrome_resources', 'chrome_strings', 'common_constants', 'common_net', 'default_plugin/default_plugin.gyp:default_plugin', - 'policy', 'theme_resources', '../app/app.gyp:app_base', '../app/app.gyp:app_resources', @@ -593,7 +593,7 @@ 'chrome_resources', 'chrome_strings', 'common_constants_win64', - 'policy_win64', + 'app/policy/cloud_policy_codegen.gyp:policy_win64', '../app/app.gyp:app_base_nacl_win64', '../app/app.gyp:app_resources', '../base/base.gyp:base_nacl_win64', @@ -625,6 +625,7 @@ ], 'export_dependent_settings': [ '../app/app.gyp:app_base_nacl_win64', + 'app/policy/cloud_policy_codegen.gyp:policy_win64', ], # TODO(gregoryd): This could be shared with the 32-bit target, but # it does not work due to a gyp issue. diff --git a/chrome/chrome_dll.gypi b/chrome/chrome_dll.gypi index 47aeb77..1f2bb58 100644 --- a/chrome/chrome_dll.gypi +++ b/chrome/chrome_dll.gypi @@ -69,7 +69,7 @@ }, 'dependencies': [ '<@(chromium_dependencies)', - 'policy' + 'app/policy/cloud_policy_codegen.gyp:policy', ], 'conditions': [ ['OS=="win"', { diff --git a/chrome/chrome_exe.gypi b/chrome/chrome_exe.gypi index 90c53f5..bf6fcf4 100644 --- a/chrome/chrome_exe.gypi +++ b/chrome/chrome_exe.gypi @@ -443,11 +443,11 @@ 'dependencies': [ 'installer_util', 'installer_util_strings', - 'policy', '../breakpad/breakpad.gyp:breakpad_handler', '../breakpad/breakpad.gyp:breakpad_sender', '../sandbox/sandbox.gyp:sandbox', 'app/locales/locales.gyp:*', + 'app/policy/cloud_policy_codegen.gyp:policy', ], 'msvs_settings': { 'VCLinkerTool': { @@ -490,10 +490,10 @@ # On Windows make sure we've built Win64 version of chrome_dll, # which contains all of the library code with Chromium # functionality. - 'installer_util_nacl_win64', - 'common_constants_win64', 'chrome_dll_nacl_win64', - 'policy_win64', + 'common_constants_win64', + 'installer_util_nacl_win64', + 'app/policy/cloud_policy_codegen.gyp:policy_win64', '../breakpad/breakpad.gyp:breakpad_handler_win64', '../breakpad/breakpad.gyp:breakpad_sender_win64', '../base/base.gyp:base_nacl_win64', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index f9ca358..b906609 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -29,9 +29,8 @@ 'chrome_gpu', 'chrome_resources', 'chrome_strings', + 'app/policy/cloud_policy_codegen.gyp:policy', 'browser/sync/protocol/sync_proto.gyp:sync_proto_cpp', - 'browser/policy/proto/device_management_proto.gyp:device_management_proto_cpp', - 'policy', 'theme_resources', '../base/base.gyp:test_support_base', '../ipc/ipc.gyp:test_support_ipc', @@ -44,6 +43,7 @@ ], 'export_dependent_settings': [ 'renderer', + 'app/policy/cloud_policy_codegen.gyp:policy', ], 'include_dirs': [ '..', @@ -204,7 +204,6 @@ 'test_support_common', 'chrome_resources', 'chrome_strings', - 'policy', 'theme_resources', '../skia/skia.gyp:skia', '../testing/gtest.gyp:gtest', @@ -269,7 +268,6 @@ 'test_support_common', 'chrome_resources', 'chrome_strings', - 'policy', '../skia/skia.gyp:skia', '../testing/gtest.gyp:gtest', ], @@ -297,7 +295,6 @@ 'msvs_guid': 'D2250C20-3A94-4FB9-AF73-11BC5B73884B', 'dependencies': [ 'browser', - 'policy', 'renderer', 'test_support_common', 'test_support_ui', @@ -356,7 +353,6 @@ 'chrome_resources', 'chrome_strings', 'debugger', - 'policy', 'syncapi', 'test_support_common', 'test_support_ui', @@ -1022,7 +1018,6 @@ 'common', 'chrome_resources', 'chrome_strings', - 'policy', 'test_support_ui', '../base/base.gyp:base', '../build/temp_gyp/googleurl.gyp:googleurl', @@ -1090,7 +1085,6 @@ 'chrome_resources', 'chrome_strings', 'common', - 'policy', 'profile_import', 'renderer', 'service', @@ -1408,6 +1402,7 @@ 'browser/policy/asynchronous_policy_provider_unittest.cc', 'browser/policy/asynchronous_policy_test_base.cc', 'browser/policy/asynchronous_policy_test_base.h', + 'browser/policy/cloud_policy_cache_unittest.cc', 'browser/policy/config_dir_policy_provider_unittest.cc', 'browser/policy/configuration_policy_pref_store_unittest.cc', 'browser/policy/configuration_policy_provider_mac_unittest.cc', @@ -1417,7 +1412,6 @@ 'browser/policy/device_management_backend_mock.cc', 'browser/policy/device_management_backend_mock.h', 'browser/policy/device_management_service_unittest.cc', - 'browser/policy/device_management_policy_cache_unittest.cc', 'browser/policy/device_management_policy_provider_unittest.cc', 'browser/policy/managed_prefs_banner_base_unittest.cc', 'browser/policy/mock_configuration_policy_provider.cc', @@ -2091,7 +2085,6 @@ 'chrome', 'chrome_resources', 'chrome_strings', - 'policy', 'profile_import', 'renderer', 'test_support_common', @@ -2472,7 +2465,6 @@ 'msvs_guid': 'BBF2BC2F-7CD8-463E-BE88-CB81AAD92BFE', 'dependencies': [ 'chrome', - 'policy', 'test_support_common', '../app/app.gyp:app_resources', '../base/base.gyp:base', @@ -2725,7 +2717,6 @@ 'dependencies': [ 'chrome', 'debugger', - 'policy', 'test_support_common', 'test_support_ui', 'theme_resources', @@ -2760,7 +2751,6 @@ 'dependencies': [ 'chrome', 'debugger', - 'policy', 'test_support_common', 'test_support_ui', 'theme_resources', @@ -2790,7 +2780,6 @@ 'dependencies': [ 'chrome', 'debugger', - 'policy', 'test_support_common', 'test_support_ui', 'theme_resources', @@ -2975,7 +2964,6 @@ 'chrome', 'chrome_resources', 'common', - 'policy', 'profile_import', 'renderer', 'chrome_strings', @@ -3134,7 +3122,6 @@ 'chrome', 'chrome_resources', 'chrome_strings', - 'policy', 'renderer', 'test_support_common', '../app/app.gyp:app_base', @@ -3228,7 +3215,6 @@ 'chrome', 'chrome_resources', 'chrome_strings', - 'policy', 'test_support_common', 'test_support_ui', '../skia/skia.gyp:skia', @@ -3337,7 +3323,6 @@ 'dependencies': [ 'test_support_common', 'browser', - 'policy', 'renderer', 'syncapi', '../base/base.gyp:base', @@ -3415,7 +3400,6 @@ 'dependencies': [ 'chrome_resources', 'chrome_strings', - 'policy', 'test_support_common', 'test_support_ui', '../skia/skia.gyp:skia', @@ -3471,7 +3455,6 @@ 'product_prefix': '_', 'dependencies': [ 'chrome', - 'policy', 'debugger', 'syncapi', 'test_support_common', diff --git a/chrome/tools/build/generate_policy_source.py b/chrome/tools/build/generate_policy_source.py index 1051092..6b2ee46 100644 --- a/chrome/tools/build/generate_policy_source.py +++ b/chrome/tools/build/generate_policy_source.py @@ -29,6 +29,12 @@ def main(): parser.add_option("--pth", "--policy-type-header", dest="type_path", help="generate header file for policy type enumeration", metavar="FILE"); + parser.add_option("--ppb", "--policy-protobuf", dest="proto_path", + help="generate cloud policy protobuf file", + metavar="FILE"); + parser.add_option("--ppd", "--protobuf-decoder", dest="decoder_path", + help="generate C++ code decoding the policy protobuf", + metavar="FILE"); (opts, args) = parser.parse_args(); @@ -38,27 +44,45 @@ def main(): sys.exit(2) template_file_contents = _LoadJSONFile(args[1]); if opts.header_path is not None: - _WritePolicyConstantHeader(template_file_contents, - args, - opts); + _WritePolicyConstantHeader(template_file_contents, args, opts); if opts.source_path is not None: - _WritePolicyConstantSource(template_file_contents, - args, - opts); + _WritePolicyConstantSource(template_file_contents, args, opts); if opts.type_path is not None: - _WritePolicyTypeEnumerationHeader(template_file_contents, - args, - opts); + _WritePolicyTypeEnumerationHeader(template_file_contents, args, opts); + if opts.proto_path is not None: + _WriteProtobuf(template_file_contents, args, opts.proto_path) + if opts.decoder_path is not None: + _WriteProtobufParser(template_file_contents, args, opts.decoder_path) +#------------------ shared helpers ---------------------------------# def _OutputGeneratedWarningForC(f, template_file_path): f.write('//\n' '// DO NOT MODIFY THIS FILE DIRECTLY!\n' '// IT IS GENERATED BY generate_policy_source.py\n' - '// FROM ' + template_file_path + ' \n' + '// FROM ' + template_file_path + '\n' '//\n\n') +def _GetPolicyNameList(template_file_contents): + policy_names = []; + for policy in template_file_contents['policy_definitions']: + if policy['type'] == 'group': + for sub_policy in policy['policies']: + policy_names.append(sub_policy['name']) + else: + policy_names.append(policy['name']) + policy_names.sort() + return policy_names + + +def _LoadJSONFile(json_file): + with open(json_file, "r") as f: + text = f.read() + return eval(text) + + +#------------------ policy constants header ------------------------# def _WritePolicyConstantHeader(template_file_contents, args, opts): platform = args[0]; with open(opts.header_path, "w") as f: @@ -80,6 +104,7 @@ def _WritePolicyConstantHeader(template_file_contents, args, opts): '#endif // CHROME_COMMON_POLICY_CONSTANTS_H_\n') +#------------------ policy constants source ------------------------# def _WritePolicyConstantSource(template_file_contents, args, opts): platform = args[0]; with open(opts.source_path, "w") as f: @@ -103,6 +128,7 @@ def _WritePolicyConstantSource(template_file_contents, args, opts): '} // namespace policy\n') +#------------------ policy type enumeration header -----------------# def _WritePolicyTypeEnumerationHeader(template_file_contents, args, opts): with open(opts.type_path, "w") as f: _OutputGeneratedWarningForC(f, args[1]) @@ -120,23 +146,183 @@ def _WritePolicyTypeEnumerationHeader(template_file_contents, args, opts): '#endif // CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_TYPE_H_\n') -def _GetPolicyNameList(template_file_contents): - policy_names = []; - for policy in template_file_contents['policy_definitions']: - if policy['type'] == 'group': - for sub_policy in policy['policies']: - policy_names.append(sub_policy['name']) - else: - policy_names.append(policy['name']) - policy_names.sort() - return policy_names +#------------------ policy protobuf --------------------------------# +PROTO_HEAD = ''' +syntax = "proto2"; +option optimize_for = LITE_RUNTIME; -def _LoadJSONFile(json_file): - with open(json_file, "r") as f: - text = f.read() - return eval(text) +package enterprise_management; + +message StringList { + repeated string entries = 1; +} + +message PolicyOptions { + enum PolicyMode { + // The given settings are applied regardless of user choice. + MANDATORY = 0; + // The user may choose to override the given settings. + RECOMMENDED = 1; + } + optional PolicyMode mode = 1 [default = MANDATORY]; +} + +''' + + +PROTOBUF_TYPE = { + 'main': 'bool', + 'string': 'string', + 'string-enum': 'string', + 'int': 'int64', + 'int-enum': 'int64', + 'list': 'StringList', +} + + +# Field IDs [1..RESERVED_IDS] will not be used in the wrapping protobuf. +RESERVED_IDS = 2 + + +def _WritePolicyProto(file, policy, fields): + file.write('message %sProto {\n' % policy['name']) + file.write(' optional PolicyOptions policy_options = 1;\n') + file.write(' optional %s %s = 2;\n' % + (PROTOBUF_TYPE[policy['type']], policy['name'])) + file.write('}\n\n') + fields += [' optional %sProto %s = %s;\n' % + (policy['name'], policy['name'], policy['id'] + RESERVED_IDS)] + + +def _WriteProtobuf(template_file_contents, args, outfilepath): + with open(outfilepath, 'w') as f: + _OutputGeneratedWarningForC(f, args[1]) + f.write(PROTO_HEAD) + + fields = [] + f.write('// PBs for individual settings.\n\n') + for policy in template_file_contents['policy_definitions']: + if policy['type'] == 'group': + for sub_policy in policy['policies']: + _WritePolicyProto(f, sub_policy, fields) + else: + _WritePolicyProto(f, policy, fields) + + f.write('// --------------------------------------------------\n' + '// Big wrapper PB containing the above groups.\n\n' + 'message CloudPolicySettings {\n') + f.write(''.join(fields)) + f.write('}\n\n') + + +#------------------ protobuf decoder -------------------------------# +CPP_HEAD = ''' +#include <limits> +#include <map> +#include <string> + +#include "base/logging.h" +#include "base/values.h" +#include "chrome/browser/policy/configuration_policy_provider.h" +#include "chrome/browser/policy/proto/device_management_backend.pb.h" +#include "policy/configuration_policy_type.h" + +using google::protobuf::RepeatedPtrField; + +namespace policy { + +namespace em = enterprise_management; + +Value* DecodeIntegerValue(google::protobuf::int64 value) { + if (value < std::numeric_limits<int>::min() || + value > std::numeric_limits<int>::max()) { + LOG(WARNING) << "Integer value " << value + << " out of numeric limits, ignoring."; + return NULL; + } + + return Value::CreateIntegerValue(static_cast<int>(value)); +} + +ListValue* DecodeStringList(const em::StringList& string_list) { + ListValue* list_value = new ListValue; + RepeatedPtrField<std::string>::const_iterator entry; + for (entry = string_list.entries().begin(); + entry != string_list.entries().end(); ++entry) { + list_value->Append(Value::CreateStringValue(*entry)); + } + return list_value; +} + +void DecodePolicy(const em::CloudPolicySettings& policy, + ConfigurationPolicyProvider::PolicyMapType* mandatory, + ConfigurationPolicyProvider::PolicyMapType* recommended) { + DCHECK(mandatory); + DCHECK(recommended); +''' + + +CPP_FOOT = '''} + +} // namespace policy +''' + + +def _CreateValue(type): + if type == 'main': + return "Value::CreateBooleanValue" + elif type in ('int', 'int-enum'): + return "DecodeIntegerValue" + elif type in ('string', 'string-enum'): + return "Value::CreateStringValue" + elif type == 'list': + return "DecodeStringList" + else: + raise NotImplementedError() + + +def _WritePolicyCode(file, policy): + membername = policy['name'].lower() + proto_type = "%sProto" % policy['name'] + proto_name = "%s_proto" % membername + file.write(' if (policy.has_%s()) {\n' % membername) + file.write(' const em::%s& %s = policy.%s();\n' % + (proto_type, proto_name, membername)) + file.write(' if (%s.has_%s()) {\n' % (proto_name, membername)) + file.write(' Value* value = %s(%s.%s());\n' % + (_CreateValue(policy['type']), proto_name, membername)) + file.write(' ConfigurationPolicyProvider::PolicyMapType* destination =' + ' mandatory;\n' + ' if (%s.has_policy_options()) {\n' + ' switch(%s.policy_options().mode()) {\n' % + (proto_name, proto_name)) + file.write(' case em::PolicyOptions::RECOMMENDED:\n' + ' destination = recommended;\n' + ' break;\n' + ' case em::PolicyOptions::MANDATORY:\n' + ' break;\n' + ' }\n' + ' }\n' + ' destination->insert(std::make_pair(kPolicy%s, value));\n' % + policy['name']) + file.write(' }\n' + ' }\n') + + +def _WriteProtobufParser(template_file_contents, args, outfilepath): + with open(outfilepath, 'w') as f: + _OutputGeneratedWarningForC(f, args[1]) + f.write(CPP_HEAD) + for policy in template_file_contents['policy_definitions']: + if policy['type'] == 'group': + for sub_policy in policy['policies']: + _WritePolicyCode(f, sub_policy) + else: + _WritePolicyCode(f, policy) + f.write(CPP_FOOT) +#------------------ main() -----------------------------------------# if __name__ == '__main__': main(); diff --git a/chrome_frame/chrome_frame.gyp b/chrome_frame/chrome_frame.gyp index 4bde4aa..00662af4 100644 --- a/chrome_frame/chrome_frame.gyp +++ b/chrome_frame/chrome_frame.gyp @@ -109,7 +109,7 @@ 'type': 'executable', 'dependencies': [ '../base/base.gyp:test_support_base', - '../chrome/chrome.gyp:policy', + '../chrome/app/policy/cloud_policy_codegen.gyp:policy', '../testing/gmock.gyp:gmock', '../testing/gtest.gyp:gtest', 'chrome_frame_ie', @@ -757,7 +757,7 @@ 'chrome_frame_utils', 'chrome_tab_idl', '../chrome/chrome.gyp:common', - '../chrome/chrome.gyp:policy', + '../chrome/app/policy/cloud_policy_codegen.gyp:policy', '../chrome/chrome.gyp:utility', '../build/temp_gyp/googleurl.gyp:googleurl', '../third_party/libxml/libxml.gyp:libxml', diff --git a/net/net.gyp b/net/net.gyp index 9035094..5266f74a 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -1182,8 +1182,8 @@ 'conditions': [ ['inside_chromium_build==1', { 'dependencies': [ + '../chrome/app/policy/cloud_policy_codegen.gyp:cloud_policy_proto_compile', '../chrome/browser/sync/protocol/sync_proto.gyp:sync_proto', - '../chrome/browser/policy/proto/device_management_proto.gyp:device_management_proto', '../third_party/protobuf/protobuf.gyp:py_proto', ], }], diff --git a/net/tools/testserver/device_management.py b/net/tools/testserver/device_management.py index 00254c1..ccf1ac8 100644 --- a/net/tools/testserver/device_management.py +++ b/net/tools/testserver/device_management.py @@ -95,7 +95,7 @@ class RequestHandler(object): unique. """ if not self._params: - self._params = cgi.parse_qs(self._path[self._path.find('?')+1:]) + self._params = cgi.parse_qs(self._path[self._path.find('?') + 1:]) param_list = self._params.get(name, []) if len(param_list) == 1: @@ -173,7 +173,6 @@ class RequestHandler(object): response = dm.DeviceManagementResponse() response.error = dm.DeviceManagementResponse.SUCCESS response.register_response.device_management_token = dmtoken - response.register_response.device_name = self.GetDeviceName() self.DumpMessage('Response', response) @@ -498,7 +497,7 @@ class TestServer(object): dmtoken_chars = [] while len(dmtoken_chars) < 32: dmtoken_chars.append(random.choice('0123456789abcdef')) - dmtoken= ''.join(dmtoken_chars) + dmtoken = ''.join(dmtoken_chars) self._registered_devices[dmtoken] = device_id return dmtoken |