| OLD | NEW |
| 1 # Copyright 2015 The LUCI Authors. All rights reserved. | 1 # Copyright 2015 The LUCI Authors. All rights reserved. |
| 2 # Use of this source code is governed under the Apache License, Version 2.0 | 2 # Use of this source code is governed under the Apache License, Version 2.0 |
| 3 # that can be found in the LICENSE file. | 3 # that can be found in the LICENSE file. |
| 4 | 4 |
| 5 """Adapter between config service client and the rest of auth_service. | 5 """Adapter between config service client and the rest of auth_service. |
| 6 | 6 |
| 7 Basically a cron job that each minute refetches config files from config service | 7 Basically a cron job that each minute refetches config files from config service |
| 8 and modifies auth service datastore state if anything changed. | 8 and modifies auth service datastore state if anything changed. |
| 9 | 9 |
| 10 Following files are fetched: | 10 Following files are fetched: |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 136 # update generates single AuthDB replication task instead of a bunch of them. | 136 # update generates single AuthDB replication task instead of a bunch of them. |
| 137 if dirty_in_authdb: | 137 if dirty_in_authdb: |
| 138 _update_authdb_configs(dirty_in_authdb) | 138 _update_authdb_configs(dirty_in_authdb) |
| 139 | 139 |
| 140 | 140 |
| 141 ### Integration with config validation framework. | 141 ### Integration with config validation framework. |
| 142 | 142 |
| 143 | 143 |
| 144 @validation.self_rule('delegation.cfg', config_pb2.DelegationConfig) | 144 @validation.self_rule('delegation.cfg', config_pb2.DelegationConfig) |
| 145 def validate_delegation_config(conf, ctx): | 145 def validate_delegation_config(conf, ctx): |
| 146 # Helper to valid a required list of identifies (or '*'). | 146 def validate_service_list(name, lst): |
| 147 def validate_ident_list(name, lst): | |
| 148 if not lst: | 147 if not lst: |
| 149 ctx.error('missing %s field', name) | 148 ctx.error('missing %s field', name) |
| 150 return | 149 return |
| 151 for uid in lst: | 150 for uid in lst: |
| 152 if uid != '*': | 151 if uid == '*': |
| 153 try: | 152 continue |
| 154 model.Identity.from_bytes(uid) | 153 try: |
| 155 except ValueError as exc: | 154 ident = model.Identity.from_bytes(uid) |
| 156 ctx.error('bad identity string "%s" in %s: %s', uid, name, exc) | 155 if ident.kind != 'service': |
| 156 ctx.error('%s: expecting "service:" identity, got "%s"', name, uid) |
| 157 except ValueError as exc: |
| 158 ctx.error('%s: bad identity string "%s": %s', name, uid, exc) |
| 157 if '*' in lst and len(lst) != 1: | 159 if '*' in lst and len(lst) != 1: |
| 158 ctx.warning('redundant entries in %s, it has "*"" already', name) | 160 ctx.warning('redundant entries in %s, it has "*"" already', name) |
| 159 | 161 |
| 162 def validate_principal_list(name, lst, required=False): |
| 163 if required and not lst: |
| 164 ctx.error('missing %s field', name) |
| 165 return |
| 166 for p in lst: |
| 167 if p == '*': |
| 168 continue |
| 169 if p.startswith('group:'): |
| 170 group = p[len('group:'):] |
| 171 if not model.is_valid_group_name(group): |
| 172 ctx.error('%s: not a valid group name: %s', name, group) |
| 173 continue |
| 174 if '*' in p: |
| 175 try: |
| 176 model.IdentityGlob.from_bytes(p) |
| 177 except ValueError as exc: |
| 178 ctx.error('%s: not a valid identity glob "%s": %s', name, p, exc) |
| 179 continue |
| 180 try: |
| 181 model.Identity.from_bytes(p) |
| 182 except ValueError as exc: |
| 183 ctx.error('%s: not a valid identity "%s": %s', name, p, exc) |
| 184 |
| 160 for idx, r in enumerate(conf.rules): | 185 for idx, r in enumerate(conf.rules): |
| 161 with ctx.prefix('rules #%d: ', idx): | 186 with ctx.prefix('rules #%d: ', idx): |
| 162 validate_ident_list('user_id', r.user_id) | 187 validate_service_list('target_service', r.target_service) |
| 163 validate_ident_list('target_service', r.target_service) | 188 validate_principal_list('user_id', r.user_id, required=True) |
| 189 validate_principal_list( |
| 190 'allowed_to_impersonate', r.allowed_to_impersonate) |
| 164 if r.max_validity_duration <= 0: | 191 if r.max_validity_duration <= 0: |
| 165 ctx.error('max_validity_duration must be a positive integer') | 192 ctx.error('max_validity_duration must be a positive integer') |
| 166 for s in r.allowed_to_impersonate: | |
| 167 if s.startswith('group:'): | |
| 168 name = s[len('group:'):] | |
| 169 if not model.is_valid_group_name(name): | |
| 170 ctx.error('not a valid group name: %s', name) | |
| 171 continue | |
| 172 if '*' in s: | |
| 173 try: | |
| 174 model.IdentityGlob.from_bytes(s) | |
| 175 except ValueError as exc: | |
| 176 ctx.error('not a valid identity glob "%s": %s', s, exc) | |
| 177 continue | |
| 178 try: | |
| 179 model.Identity.from_bytes(s) | |
| 180 except ValueError as exc: | |
| 181 ctx.error('not a valid identity "%s": %s', s, exc) | |
| 182 | 193 |
| 183 | 194 |
| 184 # TODO(vadimsh): Below use validation context for real (e.g. emit multiple | 195 # TODO(vadimsh): Below use validation context for real (e.g. emit multiple |
| 185 # errors at once instead of aborting on the first one). | 196 # errors at once instead of aborting on the first one). |
| 186 | 197 |
| 187 | 198 |
| 188 @validation.self_rule('imports.cfg') | 199 @validation.self_rule('imports.cfg') |
| 189 def validate_imports_config(conf, ctx): | 200 def validate_imports_config(conf, ctx): |
| 190 try: | 201 try: |
| 191 importer.validate_config(conf) | 202 importer.validate_config(conf) |
| (...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 553 try: | 564 try: |
| 554 location = gitiles.Location.parse(configs_url) | 565 location = gitiles.Location.parse(configs_url) |
| 555 return str(gitiles.Location( | 566 return str(gitiles.Location( |
| 556 hostname=location.hostname, | 567 hostname=location.hostname, |
| 557 project=location.project, | 568 project=location.project, |
| 558 treeish=rev, | 569 treeish=rev, |
| 559 path=posixpath.join(location.path, path))) | 570 path=posixpath.join(location.path, path))) |
| 560 except ValueError: | 571 except ValueError: |
| 561 # Not a gitiles URL, return as is. | 572 # Not a gitiles URL, return as is. |
| 562 return configs_url | 573 return configs_url |
| OLD | NEW |