Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(421)

Side by Side Diff: appengine/config_service/acl.py

Issue 1224913002: luci-config: fine-grained acls (Closed) Base URL: git@github.com:luci/luci-py.git@master
Patch Set: identities in configs Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « appengine/config_service/README.md ('k') | appengine/config_service/acl_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
14 import services
13 import storage 15 import storage
14 16
15 17
16 @utils.memcache('acl.cfg', time=60) 18 @utils.memcache('acl.cfg', time=60)
17 def read_acl_cfg(): 19 def read_acl_cfg():
18 return storage.get_self_config_async( 20 return storage.get_self_config_async(
19 common.ACL_FILENAME, service_config_pb2.AclCfg).get_result() 21 common.ACL_FILENAME, service_config_pb2.AclCfg).get_result()
20 22
23 def _has_access(access_list):
24 cur_ident = auth.get_current_identity().to_bytes()
25 for ac in access_list:
26 if ac.startswith('group:'):
27 if auth.is_group_member(ac.split(':', 2)[1]):
28 return True
29 else:
30 identity_str = ac
31 if ':' not in identity_str:
32 identity_str = 'user:%s' % identity_str
33 if cur_ident == identity_str:
34 return True
35 return False
21 36
22 def can_read_config_set(config_set, headers=None): 37
38 def can_read_config_set(config_set):
23 """Returns True if current requester has access to the |config_set|. 39 """Returns True if current requester has access to the |config_set|.
24 40
25 Raise: 41 Raise:
26 ValueError if config_set is malformed. 42 ValueError if config_set is malformed.
27 """ 43 """
28 try: 44 try:
29 service_match = config.SERVICE_CONFIG_SET_RGX.match(config_set) 45 service_match = config.SERVICE_CONFIG_SET_RGX.match(config_set)
30 if service_match: 46 if service_match:
31 service_name = service_match.group(1) 47 service_name = service_match.group(1)
32 return can_read_service_config(service_name, headers=headers) 48 return has_service_access(service_name)
33 49
34 project_match = config.PROJECT_CONFIG_SET_RGX.match(config_set) 50 project_match = config.PROJECT_CONFIG_SET_RGX.match(config_set)
35 if project_match: 51 if project_match:
36 project_id = project_match.group(1) 52 project_id = project_match.group(1)
37 return can_read_project_config(project_id) 53 return has_project_access(project_id)
38 54
39 ref_match = config.REF_CONFIG_SET_RGX.match(config_set) 55 ref_match = config.REF_CONFIG_SET_RGX.match(config_set)
40 if ref_match: 56 if ref_match:
41 project_id = ref_match.group(1) 57 project_id = ref_match.group(1)
42 return can_read_project_config(project_id) 58 return has_project_access(project_id)
43 59
44 except ValueError: # pragma: no cover 60 except ValueError: # pragma: no cover
45 # Make sure we don't let ValueError raise for a reason different than 61 # Make sure we don't let ValueError raise for a reason different than
46 # malformed config_set. 62 # malformed config_set.
47 logging.exception('Unexpected ValueError in can_read_config_set()') 63 logging.exception('Unexpected ValueError in can_read_config_set()')
48 return False 64 return False
49 raise ValueError() 65 raise ValueError()
50 66
51 67
52 def can_read_service_config(service_id, headers=None): 68 def has_service_access(service_id):
53 """Returns True if current requester can read service configs. 69 """Returns True if current requester can read service configs.
54 70
55 If X-Appengine-Inbound-Appid header matches service_id, the permission is 71 An app <app-id> has access to configs of service with id <app-id>.
56 granted.
57 """ 72 """
58 assert isinstance(service_id, basestring) 73 assert isinstance(service_id, basestring)
59 assert service_id 74 assert service_id
60 75
61 group = read_acl_cfg().service_access_group 76 if auth.is_admin():
77 return True
78
79 service_cfg = services.get_service_async(service_id).get_result()
80 return service_cfg and _has_access(service_cfg.access)
81
82
83 def has_project_access(project_id):
84 metadata = projects.get_metadata(project_id)
85 super_group = read_acl_cfg().project_access_group
62 return ( 86 return (
63 auth.is_admin() or 87 auth.is_admin() or
64 group and auth.is_group_member(group) or 88 super_group and auth.is_group_member(super_group) or
65 (headers or {}).get('X-Appengine-Inbound-Appid') == service_id 89 metadata and _has_access(metadata.access)
66 ) 90 )
67
68
69 # pylint: disable=W0613
70 def can_read_project_config(project_id): # pragma: no cover
71 return has_project_access()
72
73
74 def can_read_project_list(): # pragma: no cover
75 return has_project_access()
76
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))
OLDNEW
« no previous file with comments | « appengine/config_service/README.md ('k') | appengine/config_service/acl_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698