Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2015 The Swarming Authors. All rights reserved. | 1 # Copyright 2015 The Swarming Authors. All rights reserved. |
| 2 # Use of this source code is governed by the Apache v2.0 license that can be | 2 # Use of this source code is governed by the Apache v2.0 license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import re | 5 import re |
| 6 | 6 |
| 7 from components import auth | 7 from components import auth |
| 8 from components import config | 8 from components import config |
| 9 from components import utils | 9 from components import utils |
| 10 | 10 |
| 11 from proto import service_config_pb2 | 11 from proto import service_config_pb2 |
| 12 import common | 12 import common |
| 13 import projects | |
| 13 import storage | 14 import storage |
| 14 | 15 |
| 15 | 16 |
| 16 @utils.memcache('acl.cfg', time=60) | 17 @utils.memcache('acl.cfg', time=60) |
| 17 def read_acl_cfg(): | 18 def read_acl_cfg(): |
| 18 return storage.get_self_config_async( | 19 return storage.get_self_config_async( |
| 19 common.ACL_FILENAME, service_config_pb2.AclCfg).get_result() | 20 common.ACL_FILENAME, service_config_pb2.AclCfg).get_result() |
| 20 | 21 |
| 21 | 22 |
| 22 def can_read_config_set(config_set, headers=None): | 23 def can_read_config_set(config_set): |
| 23 """Returns True if current requester has access to the |config_set|. | 24 """Returns True if current requester has access to the |config_set|. |
| 24 | 25 |
| 25 Raise: | 26 Raise: |
| 26 ValueError if config_set is malformed. | 27 ValueError if config_set is malformed. |
| 27 """ | 28 """ |
| 28 try: | 29 try: |
| 29 service_match = config.SERVICE_CONFIG_SET_RGX.match(config_set) | 30 service_match = config.SERVICE_CONFIG_SET_RGX.match(config_set) |
| 30 if service_match: | 31 if service_match: |
| 31 service_name = service_match.group(1) | 32 service_name = service_match.group(1) |
| 32 return can_read_service_config(service_name, headers=headers) | 33 return can_read_service_config(service_name) |
| 33 | 34 |
| 34 project_match = config.PROJECT_CONFIG_SET_RGX.match(config_set) | 35 project_match = config.PROJECT_CONFIG_SET_RGX.match(config_set) |
| 35 if project_match: | 36 if project_match: |
| 36 project_id = project_match.group(1) | 37 project_id = project_match.group(1) |
| 37 return can_read_project_config(project_id) | 38 return has_project_access(project_id) |
| 38 | 39 |
| 39 ref_match = config.REF_CONFIG_SET_RGX.match(config_set) | 40 ref_match = config.REF_CONFIG_SET_RGX.match(config_set) |
| 40 if ref_match: | 41 if ref_match: |
| 41 project_id = ref_match.group(1) | 42 project_id = ref_match.group(1) |
| 42 return can_read_project_config(project_id) | 43 return has_project_access(project_id) |
| 43 | 44 |
| 44 except ValueError: # pragma: no cover | 45 except ValueError: # pragma: no cover |
| 45 # Make sure we don't let ValueError raise for a reason different than | 46 # Make sure we don't let ValueError raise for a reason different than |
| 46 # malformed config_set. | 47 # malformed config_set. |
| 47 logging.exception('Unexpected ValueError in can_read_config_set()') | 48 logging.exception('Unexpected ValueError in can_read_config_set()') |
| 48 return False | 49 return False |
| 49 raise ValueError() | 50 raise ValueError() |
| 50 | 51 |
| 51 | 52 |
| 52 def can_read_service_config(service_id, headers=None): | 53 def can_read_service_config(service_id): |
| 53 """Returns True if current requester can read service configs. | 54 """Returns True if current requester can read service configs. |
| 54 | 55 |
| 55 If X-Appengine-Inbound-Appid header matches service_id, the permission is | 56 An app <app-id> has access to configs of service with id <app-id>. |
| 56 granted. | |
| 57 """ | 57 """ |
| 58 assert isinstance(service_id, basestring) | 58 assert isinstance(service_id, basestring) |
| 59 assert service_id | 59 assert service_id |
| 60 | 60 |
| 61 group = read_acl_cfg().service_access_group | 61 group = read_acl_cfg().service_access_group |
| 62 trusted_identities = [ | |
|
Vadim Sh.
2015/07/08 14:20:34
as I said in another CL, I don't like implicitly b
nodir
2015/07/08 16:35:58
Implemented fine-grained acls for service configs
| |
| 63 'user:%s@%s.gserviceaccount.com' % (service_id, subdomain) | |
| 64 for subdomain in ('appspot', 'googleplex')] | |
| 62 return ( | 65 return ( |
| 63 auth.is_admin() or | 66 auth.is_admin() or |
| 64 group and auth.is_group_member(group) or | 67 group and auth.is_group_member(group) or |
| 65 (headers or {}).get('X-Appengine-Inbound-Appid') == service_id | 68 auth.get_current_identity().to_bytes() in trusted_identities |
|
Vadim Sh.
2015/07/08 14:20:34
it should have worked
does caller use follow_redi
nodir
2015/07/08 16:35:58
yes, the caller is chrome-infra-auth-dev.appspot.c
| |
| 66 ) | 69 ) |
| 67 | 70 |
| 68 | 71 |
| 69 # pylint: disable=W0613 | 72 def has_project_access(project_id): |
| 70 def can_read_project_config(project_id): # pragma: no cover | 73 metadata = projects.get_metadata(project_id) |
| 71 return has_project_access() | 74 super_group = read_acl_cfg().project_access_group |
| 72 | 75 return ( |
| 73 | 76 auth.is_admin() or |
| 74 def can_read_project_list(): # pragma: no cover | 77 super_group and auth.is_group_member(super_group) or |
| 75 return has_project_access() | 78 metadata and metadata.access and auth.is_group_member(metadata.access) |
| 76 | 79 ) |
| 77 | |
| 78 def has_project_access(): | |
| 79 group = read_acl_cfg().project_access_group | |
| 80 return auth.is_admin() or (group and auth.is_group_member(group)) | |
| OLD | NEW |