Commit a63c0394 authored by knn's avatar knn Committed by Commit bot

Expose chrome policies using Android's App Restrictions Schema

BUG=446795

Review URL: https://codereview.chromium.org/823273007

Cr-Commit-Position: refs/heads/master@{#310796}
parent 74893f0b
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/chrome', 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/chrome',
'policy_out_dir': '<(SHARED_INTERMEDIATE_DIR)/policy', 'policy_out_dir': '<(SHARED_INTERMEDIATE_DIR)/policy',
'protoc_out_dir': '<(SHARED_INTERMEDIATE_DIR)/protoc_out', 'protoc_out_dir': '<(SHARED_INTERMEDIATE_DIR)/protoc_out',
'android_resources_out_dir': '<(policy_out_dir)/android_resources',
'generate_policy_source_script_path': 'generate_policy_source_script_path':
'policy/tools/generate_policy_source.py', 'policy/tools/generate_policy_source.py',
'policy_constant_header_path': 'policy_constant_header_path':
...@@ -20,6 +21,10 @@ ...@@ -20,6 +21,10 @@
'<(policy_out_dir)/policy/policy_constants.cc', '<(policy_out_dir)/policy/policy_constants.cc',
'protobuf_decoder_path': 'protobuf_decoder_path':
'<(policy_out_dir)/policy/cloud_policy_generated.cc', '<(policy_out_dir)/policy/cloud_policy_generated.cc',
'app_restrictions_path':
'<(android_resources_out_dir)/xml/app_restrictions.xml',
'app_resources_path':
'<(android_resources_out_dir)/values/restriction_values.xml',
# This is the "full" protobuf, which defines one protobuf message per # This is the "full" protobuf, which defines one protobuf message per
# policy. It is also the format currently used by the server. # policy. It is also the format currently used by the server.
'chrome_settings_proto_path': 'chrome_settings_proto_path':
...@@ -109,6 +114,8 @@ ...@@ -109,6 +114,8 @@
'<(protobuf_decoder_path)', '<(protobuf_decoder_path)',
'<(chrome_settings_proto_path)', '<(chrome_settings_proto_path)',
'<(cloud_policy_proto_path)', '<(cloud_policy_proto_path)',
'<(app_restrictions_path)',
'<(app_resources_path)',
], ],
'action_name': 'generate_policy_source', 'action_name': 'generate_policy_source',
'action': [ 'action': [
...@@ -119,11 +126,21 @@ ...@@ -119,11 +126,21 @@
'--chrome-settings-protobuf=<(chrome_settings_proto_path)', '--chrome-settings-protobuf=<(chrome_settings_proto_path)',
'--cloud-policy-protobuf=<(cloud_policy_proto_path)', '--cloud-policy-protobuf=<(cloud_policy_proto_path)',
'--cloud-policy-decoder=<(protobuf_decoder_path)', '--cloud-policy-decoder=<(protobuf_decoder_path)',
'--app-restrictions-definition=<(app_restrictions_path)',
'--app-restrictions-resources=<(app_resources_path)',
'<(OS)', '<(OS)',
'<(chromeos)', '<(chromeos)',
'policy/resources/policy_templates.json', 'policy/resources/policy_templates.json',
], ],
'message': 'Generating policy source', 'message': 'Generating policy source',
'conditions': [
['OS!="android"', {
'outputs!': [
'<(app_restrictions_path)',
'<(app_resources_path)',
],
}],
],
}, },
], ],
'direct_dependent_settings': { 'direct_dependent_settings': {
......
...@@ -47,6 +47,9 @@ if (enable_configuration_policy) { ...@@ -47,6 +47,9 @@ if (enable_configuration_policy) {
# build puts everything into the following directory. We do the same for now. # build puts everything into the following directory. We do the same for now.
policy_gen_dir = "$root_gen_dir/policy" policy_gen_dir = "$root_gen_dir/policy"
# Directory for generating Android App Restrictions resources
android_resources_gen_dir = "$policy_gen_dir/android_resources"
# This protobuf is equivalent to chrome_settings.proto but shares messages # This protobuf is equivalent to chrome_settings.proto but shares messages
# for policies of the same type, so that less classes have to be generated # for policies of the same type, so that less classes have to be generated
# and compiled. # and compiled.
...@@ -59,6 +62,9 @@ if (enable_configuration_policy) { ...@@ -59,6 +62,9 @@ if (enable_configuration_policy) {
constants_header_path = "$policy_gen_dir/policy_constants.h" constants_header_path = "$policy_gen_dir/policy_constants.h"
constants_source_path = "$policy_gen_dir/policy_constants.cc" constants_source_path = "$policy_gen_dir/policy_constants.cc"
protobuf_decoder_path = "$policy_gen_dir/cloud_policy_generated.cc" protobuf_decoder_path = "$policy_gen_dir/cloud_policy_generated.cc"
app_restrictions_path = "$android_resources_gen_dir/xml/app_restrictions.xml"
app_resources_path =
"$android_resources_gen_dir/values/restriction_values.xml"
action("cloud_policy_code_generate") { action("cloud_policy_code_generate") {
script = "tools/generate_policy_source.py" script = "tools/generate_policy_source.py"
...@@ -78,8 +84,17 @@ if (enable_configuration_policy) { ...@@ -78,8 +84,17 @@ if (enable_configuration_policy) {
protobuf_decoder_path, protobuf_decoder_path,
chrome_settings_proto_path, chrome_settings_proto_path,
cloud_policy_proto_path, cloud_policy_proto_path,
app_restrictions_path,
app_resources_path,
] ]
if (os != "android") {
outputs -= [
app_restrictions_path,
app_resources_path,
]
}
args = [ args = [
"--policy-constants-header=" + "--policy-constants-header=" +
rebase_path(constants_header_path, root_build_dir), rebase_path(constants_header_path, root_build_dir),
...@@ -91,6 +106,10 @@ if (enable_configuration_policy) { ...@@ -91,6 +106,10 @@ if (enable_configuration_policy) {
rebase_path(cloud_policy_proto_path, root_build_dir), rebase_path(cloud_policy_proto_path, root_build_dir),
"--cloud-policy-decoder=" + "--cloud-policy-decoder=" +
rebase_path(protobuf_decoder_path, root_build_dir), rebase_path(protobuf_decoder_path, root_build_dir),
"--app-restrictions-definition=" +
rebase_path(app_restrictions_path, root_build_dir),
"--app-restrictions-resources=" +
rebase_path(app_resources_path, root_build_dir),
os, os,
chromeos_flag, chromeos_flag,
rebase_path("resources/policy_templates.json", root_build_dir), rebase_path("resources/policy_templates.json", root_build_dir),
......
...@@ -18,6 +18,7 @@ import re ...@@ -18,6 +18,7 @@ import re
import sys import sys
import textwrap import textwrap
import types import types
from xml.sax.saxutils import escape as xml_escape
CHROME_POLICY_KEY = 'SOFTWARE\\\\Policies\\\\Google\\\\Chrome' CHROME_POLICY_KEY = 'SOFTWARE\\\\Policies\\\\Google\\\\Chrome'
...@@ -27,23 +28,34 @@ CHROMIUM_POLICY_KEY = 'SOFTWARE\\\\Policies\\\\Chromium' ...@@ -27,23 +28,34 @@ CHROMIUM_POLICY_KEY = 'SOFTWARE\\\\Policies\\\\Chromium'
class PolicyDetails: class PolicyDetails:
"""Parses a policy template and caches all its details.""" """Parses a policy template and caches all its details."""
# Maps policy types to a tuple with 3 other types: # Maps policy types to a tuple with 5 other types:
# - the equivalent base::Value::Type or 'TYPE_EXTERNAL' if the policy # - the equivalent base::Value::Type or 'TYPE_EXTERNAL' if the policy
# references external data # references external data
# - the equivalent Protobuf field type # - the equivalent Protobuf field type
# - the name of one of the protobufs for shared policy types # - the name of one of the protobufs for shared policy types
# - the equivalent type in Android's App Restriction Schema
# - whether the equivalent app restriction type needs supporting resources
# TODO(joaodasilva): refactor the 'dict' type into a more generic 'json' type # TODO(joaodasilva): refactor the 'dict' type into a more generic 'json' type
# that can also be used to represent lists of other JSON objects. # that can also be used to represent lists of other JSON objects.
TYPE_MAP = { TYPE_MAP = {
'dict': ('TYPE_DICTIONARY', 'string', 'String'), 'dict': ('TYPE_DICTIONARY', 'string', 'String',
'external': ('TYPE_EXTERNAL', 'string', 'String'), 'string', False),
'int': ('TYPE_INTEGER', 'int64', 'Integer'), 'external': ('TYPE_EXTERNAL', 'string', 'String',
'int-enum': ('TYPE_INTEGER', 'int64', 'Integer'), 'invalid', False),
'list': ('TYPE_LIST', 'StringList', 'StringList'), 'int': ('TYPE_INTEGER', 'int64', 'Integer',
'main': ('TYPE_BOOLEAN', 'bool', 'Boolean'), 'integer', False),
'string': ('TYPE_STRING', 'string', 'String'), 'int-enum': ('TYPE_INTEGER', 'int64', 'Integer',
'string-enum': ('TYPE_STRING', 'string', 'String'), 'choice', True),
'string-enum-list': ('TYPE_LIST', 'StringList', 'StringList'), 'list': ('TYPE_LIST', 'StringList', 'StringList',
'string', False),
'main': ('TYPE_BOOLEAN', 'bool', 'Boolean',
'bool', False),
'string': ('TYPE_STRING', 'string', 'String',
'string', False),
'string-enum': ('TYPE_STRING', 'string', 'String',
'choice', True),
'string-enum-list': ('TYPE_LIST', 'StringList', 'StringList',
'multi-select', True),
} }
class EnumItem: class EnumItem:
...@@ -85,8 +97,9 @@ class PolicyDetails: ...@@ -85,8 +97,9 @@ class PolicyDetails:
if not PolicyDetails.TYPE_MAP.has_key(policy['type']): if not PolicyDetails.TYPE_MAP.has_key(policy['type']):
raise NotImplementedError('Unknown policy type for %s: %s' % raise NotImplementedError('Unknown policy type for %s: %s' %
(policy['name'], policy['type'])) (policy['name'], policy['type']))
self.policy_type, self.protobuf_type, self.policy_protobuf_type = \ self.policy_type, self.protobuf_type, self.policy_protobuf_type, \
PolicyDetails.TYPE_MAP[policy['type']] self.restriction_type, self.has_restriction_resources = \
PolicyDetails.TYPE_MAP[policy['type']]
self.schema = policy['schema'] self.schema = policy['schema']
self.desc = '\n'.join( self.desc = '\n'.join(
...@@ -136,6 +149,17 @@ def main(): ...@@ -136,6 +149,17 @@ def main():
dest='cloud_policy_decoder_path', dest='cloud_policy_decoder_path',
help='generate C++ code decoding the cloud policy protobuf', help='generate C++ code decoding the cloud policy protobuf',
metavar='FILE') metavar='FILE')
parser.add_option('--ard', '--app-restrictions-definition',
dest='app_restrictions_path',
help='generate an XML file as specified by '
'Android\'s App Restriction Schema',
metavar='FILE')
parser.add_option('--arr', '--app-restrictions-resources',
dest='app_resources_path',
help='generate an XML file with resources supporting the '
'restrictions defined in --app-restrictions-definition '
'parameter',
metavar='FILE')
(opts, args) = parser.parse_args() (opts, args) = parser.parse_args()
...@@ -153,10 +177,10 @@ def main(): ...@@ -153,10 +177,10 @@ def main():
for policy in _Flatten(template_file_contents) ] for policy in _Flatten(template_file_contents) ]
sorted_policy_details = sorted(policy_details, key=lambda policy: policy.name) sorted_policy_details = sorted(policy_details, key=lambda policy: policy.name)
def GenerateFile(path, writer, sorted=False): def GenerateFile(path, writer, sorted=False, xml=False):
if path: if path:
with open(path, 'w') as f: with open(path, 'w') as f:
_OutputGeneratedWarningHeader(f, template_file_name) _OutputGeneratedWarningHeader(f, template_file_name, xml)
writer(sorted and sorted_policy_details or policy_details, os, f) writer(sorted and sorted_policy_details or policy_details, os, f)
GenerateFile(opts.header_path, _WritePolicyConstantHeader, sorted=True) GenerateFile(opts.header_path, _WritePolicyConstantHeader, sorted=True)
...@@ -165,17 +189,32 @@ def main(): ...@@ -165,17 +189,32 @@ def main():
GenerateFile(opts.chrome_settings_proto_path, _WriteChromeSettingsProtobuf) GenerateFile(opts.chrome_settings_proto_path, _WriteChromeSettingsProtobuf)
GenerateFile(opts.cloud_policy_decoder_path, _WriteCloudPolicyDecoder) GenerateFile(opts.cloud_policy_decoder_path, _WriteCloudPolicyDecoder)
if os == 'android':
GenerateFile(opts.app_restrictions_path, _WriteAppRestrictions, xml=True)
GenerateFile(opts.app_resources_path, _WriteResourcesForPolicies, xml=True)
return 0 return 0
#------------------ shared helpers ---------------------------------# #------------------ shared helpers ---------------------------------#
def _OutputGeneratedWarningHeader(f, template_file_path): def _OutputGeneratedWarningHeader(f, template_file_path, xml_style):
f.write('//\n' left_margin = '//'
'// DO NOT MODIFY THIS FILE DIRECTLY!\n' if xml_style:
'// IT IS GENERATED BY generate_policy_source.py\n' left_margin = ' '
'// FROM ' + template_file_path + '\n' f.write('<?xml version="1.0" encoding="utf-8"?>\n'
'//\n\n') '<!--\n')
else:
f.write('//\n')
f.write(left_margin + ' DO NOT MODIFY THIS FILE DIRECTLY!\n')
f.write(left_margin + ' IT IS GENERATED BY generate_policy_source.py\n')
f.write(left_margin + ' FROM ' + template_file_path + '\n')
if xml_style:
f.write('-->\n\n')
else:
f.write(left_margin + '\n\n')
COMMENT_WRAPPER = textwrap.TextWrapper() COMMENT_WRAPPER = textwrap.TextWrapper()
...@@ -561,7 +600,7 @@ class SchemaNodesGenerator: ...@@ -561,7 +600,7 @@ class SchemaNodesGenerator:
return self.id_map[id_str] return self.id_map[id_str]
def ResolveID(self, index, params): def ResolveID(self, index, params):
return params[:index] + (self.GetByID(params[index]),) + params[index+1:] return params[:index] + (self.GetByID(params[index]),) + params[index + 1:]
def ResolveReferences(self): def ResolveReferences(self):
"""Resolve reference mapping, required to be called after Generate() """Resolve reference mapping, required to be called after Generate()
...@@ -968,5 +1007,82 @@ def _WriteCloudPolicyDecoder(policies, os, f): ...@@ -968,5 +1007,82 @@ def _WriteCloudPolicyDecoder(policies, os, f):
f.write(CPP_FOOT) f.write(CPP_FOOT)
def _EscapeResourceString(raw_resource):
if type(raw_resource) == int:
return raw_resource
return xml_escape(raw_resource)\
.replace('\\', '\\\\')\
.replace('\"','\\\"')\
.replace('\'','\\\'')
def _WriteAppRestrictions(policies, os, f):
def WriteRestrictionCommon(key):
f.write(' <restriction\n'
' android:key="%s"\n' % key)
f.write(' android:title="@string/%sTitle"\n' % key)
f.write(' android:description="@string/%sDesc"\n' % key)
def WriteItemsDefinition(key):
f.write(' android:entries="@array/%sEntries"\n' % key)
f.write(' android:entryValues="@array/%sValues"\n' % key)
def WriteAppRestriction(policy):
policy_name = policy.name
WriteRestrictionCommon(policy_name)
if policy.has_restriction_resources:
WriteItemsDefinition(policy_name)
f.write(' android:restrictionType="%s"/>' % policy.restriction_type)
f.write('\n\n')
# _WriteAppRestrictions body
f.write('<restrictions xmlns:android="'
'http://schemas.android.com/apk/res/android">\n\n')
for policy in policies:
if policy.is_supported and policy.restriction_type != 'invalid':
WriteAppRestriction(policy)
f.write('</restrictions>')
def _WriteResourcesForPolicies(policies, os, f):
# TODO(knn): Update this to support i18n.
def WriteString(key, value):
f.write(' <string name="%s">%s</string>\n'
% (key, _EscapeResourceString(value)))
def WriteItems(key, items):
if items:
f.write(' <string-array name="%sEntries">\n' % key)
for item in items:
f.write(' <item>%s</item>\n' %
_EscapeResourceString(item.caption))
f.write(' </string-array>\n')
f.write(' <string-array name="%sValues">\n' % key)
for item in items:
f.write(' <item>%s</item>\n' % _EscapeResourceString(item.value))
f.write(' </string-array>\n')
def WriteResourceForPolicy(policy):
policy_name = policy.name
WriteString(policy_name + 'Title', policy.caption)
# Get the first line of the policy description.
description = policy.desc.split('\n', 1)[0]
WriteString(policy_name + 'Desc', description)
if policy.has_restriction_resources:
WriteItems(policy_name, policy.items)
# _WriteResourcesForPolicies body
f.write('<resources>\n\n')
for policy in policies:
if policy.is_supported and policy.restriction_type != 'invalid':
WriteResourceForPolicy(policy)
f.write('</resources>')
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(main()) sys.exit(main())
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment