def get(self): params = { 'is_admin': auth.is_admin(), 'is_user': acl.isolate_readable(), 'user_type': acl.get_user_type(), } if auth.is_admin(): params['xsrf_token'] = self.generate_xsrf_token() self.response.write(template.render('isolate/root.html', params))
def get(self): params = { 'is_admin': auth.is_admin(), 'is_user': acl.isolate_readable(), 'mapreduce_jobs': [], 'user_type': acl.get_user_type(), } if auth.is_admin(): params['mapreduce_jobs'] = [{ 'id': job_id, 'name': job_def['job_name'] } for job_id, job_def in mapreduce_jobs.MAPREDUCE_JOBS.iteritems()] params['xsrf_token'] = self.generate_xsrf_token() self.response.write(template.render('isolate/root.html', params))
def get(self): params = { 'is_admin': auth.is_admin(), 'is_user': acl.isolate_readable(), 'mapreduce_jobs': [], 'user_type': acl.get_user_type(), } if auth.is_admin(): params['mapreduce_jobs'] = [ {'id': job_id, 'name': job_def['job_name']} for job_id, job_def in mapreduce_jobs.MAPREDUCE_JOBS.iteritems() ] params['xsrf_token'] = self.generate_xsrf_token() self.response.write(template.render('isolate/root.html', params))
def get_available_buckets(): """Returns buckets available to the current identity. Results are memcached for 10 minutes per identity. Returns: Set of bucket names or None if all buckets are available. """ if auth.is_admin(): return None identity = auth.get_current_identity().to_bytes() cache_key = 'available_buckets/%s' % identity available_buckets = memcache.get(cache_key) if available_buckets is not None: return available_buckets logging.info( 'Computing a list of available buckets for %s' % identity) group_buckets_map = collections.defaultdict(set) available_buckets = set() all_buckets = config.get_buckets_async().get_result() for bucket in all_buckets: for rule in bucket.acls: if rule.identity == identity: available_buckets.add(bucket.name) if rule.group: group_buckets_map[rule.group].add(bucket.name) for group, buckets in group_buckets_map.iteritems(): if available_buckets.issuperset(buckets): continue if auth.is_group_member(group): available_buckets.update(buckets) # Cache for 10 min memcache.set(cache_key, available_buckets, 10 * 60) return available_buckets
def get(self): params = { 'is_admin': auth.is_admin(), } self.response.write( template.render('templates/root.html', params=params))
class AuthDBRevisionsHandler(auth.ApiHandler): """Serves deflated AuthDB proto message with snapshot of all groups. Args: rev: version of the snapshot to get ('latest' or concrete revision number). Not all versions may be available (i.e. there may be gaps in revision numbers). skip_body: if '1' will not return actual snapshot, just its SHA256 hash, revision number and timestamp. """ @auth.require(lambda: (auth.is_admin() or acl.is_trusted_service( ) or replication.is_replica(auth.get_current_identity()))) def get(self, rev): skip_body = self.request.get('skip_body') == '1' if rev == 'latest': snapshot = replication.get_latest_auth_db_snapshot(skip_body) else: try: rev = int(rev) except ValueError: self.abort_with_error( 400, text='Bad revision number, not an integer') snapshot = replication.get_auth_db_snapshot(rev, skip_body) if not snapshot: self.abort_with_error(404, text='No such snapshot: %s' % rev) resp = { 'auth_db_rev': snapshot.key.integer_id(), 'created_ts': utils.datetime_to_timestamp(snapshot.created_ts), 'sha256': snapshot.auth_db_sha256, } if not skip_body: assert snapshot.auth_db_deflated resp['deflated_body'] = base64.b64encode(snapshot.auth_db_deflated) self.send_response({'snapshot': resp})
def get_user_type(): """Returns a string describing the current access control for the user.""" if auth.is_admin(): return 'admin' if isolate_readable(): return 'user' return 'unknown user'
def impl(): if auth.is_admin(): raise ndb.Return(None) identity = auth.get_current_identity().to_bytes() cache_key = 'accessible_buckets_v2/%s' % identity ctx = ndb.get_context() available_buckets = yield ctx.memcache_get(cache_key) if available_buckets is not None: raise ndb.Return(available_buckets) logging.info('Computing a list of available buckets for %s' % identity) group_buckets_map = collections.defaultdict(set) available_buckets = set() all_buckets = yield config.get_buckets_async() for bucket_id, cfg in all_buckets.iteritems(): for rule in cfg.acls: if rule.identity == identity: available_buckets.add(bucket_id) elif rule.group: # pragma: no branch group_buckets_map[rule.group].add(bucket_id) for group, buckets in group_buckets_map.iteritems(): if available_buckets.issuperset(buckets): continue if auth.is_group_member(group): available_buckets.update(buckets) # Cache for 10 min yield ctx.memcache_set(cache_key, available_buckets, 10 * 60) raise ndb.Return(available_buckets)
def impl(): ctx = ndb.get_context() cache_key = 'role/%s/%s' % (identity_str, bucket_id) cache = yield ctx.memcache_get(cache_key) if cache is not None: raise ndb.Return(cache[0]) _, bucket_cfg = yield config.get_bucket_async(bucket_id) if not bucket_cfg: raise ndb.Return(None) if auth.is_admin(identity): raise ndb.Return(project_config_pb2.Acl.WRITER) # A LUCI service calling us in the context of some project is allowed to # do anything it wants in that project. We trust all LUCI services to do # authorization on their own for this case. A cross-project request must be # explicitly authorized in Buildbucket ACLs though (so we proceed to the # bucket_cfg check below). if identity.is_project: project_id, _ = config.parse_bucket_id(bucket_id) if project_id == identity.name: raise ndb.Return(project_config_pb2.Acl.WRITER) # Roles are just numbers. The higher the number, the more permissions # the identity has. We exploit this here to get the single maximally # permissive role for the current identity. role = None for rule in bucket_cfg.acls: if rule.role <= role: continue if (rule.identity == identity_str or (rule.group and auth.is_group_member(rule.group, identity))): role = rule.role yield ctx.memcache_set(cache_key, (role, ), time=60) raise ndb.Return(role)
def get_available_buckets(): """Returns buckets available to the current identity. Results are memcached for 10 minutes per identity. Returns: Set of bucket names or None if all buckets are available. """ if auth.is_admin(): return None identity = auth.get_current_identity().to_bytes() cache_key = 'available_buckets/%s' % identity available_buckets = memcache.get(cache_key) if available_buckets is not None: return available_buckets logging.info('Computing a list of available buckets for %s' % identity) group_buckets_map = collections.defaultdict(set) available_buckets = set() all_buckets = config.get_buckets_async().get_result() for bucket in all_buckets: for rule in bucket.acls: if rule.identity == identity: available_buckets.add(bucket.name) if rule.group: group_buckets_map[rule.group].add(bucket.name) for group, buckets in group_buckets_map.iteritems(): if available_buckets.issuperset(buckets): continue if auth.is_group_member(group): available_buckets.update(buckets) # Cache for 10 min memcache.set(cache_key, available_buckets, 10 * 60) return available_buckets
def has_project_access(project_id): metadata = projects.get_metadata(project_id) super_group = read_acl_cfg().project_access_group return ( auth.is_admin() or super_group and auth.is_group_member(super_group) or metadata and config.api._has_access(metadata.access) )
def set_greeting(_): """ Sets the username and adds admin distinction is user is admin. :returns: username and if admin admin distrinction (string) """ username = auth.get_username() addition = '' if not auth.is_admin() else " (admin)" return "Hello {0}{1}".format(username, addition)
def render_admin_area(_): """ Renders the admin area containing new user and admin creation. :returns: html.Div or None if not admin """ if not auth.is_admin(): return admin_area = html.Div(children=[ html.Br(), dcc.Input( id='new_user_name_input', placeholder="Enter new user\'s username", type='text', value='', autoFocus=True ), html.Span(style={'margin-right': '25px'}), dcc.Input( id='new_user_password_input', placeholder="Enter new user\'s password", type='password', value='' ), html.Span(style={'margin-right': '25px'}), html.Button( 'Add new user!', id='new_user_button' ), html.Span(style={'margin-right': '25px'}), html.Span(id='new_user_message'), html.Div(), html.Br(), dcc.Input( id='new_admin_name_input', placeholder="Enter new admin\'s username", type='text', value='' ), html.Span(style={'margin-right': '25px'}), dcc.Input( id='new_admin_password_input', placeholder="Enter new admin\'s password", type='password', value='' ), html.Span(style={'margin-right': '25px'}), html.Button( 'Add new admin!', id='new_admin_button' ), html.Span(style={'margin-right': '25px'}), html.Span(id='new_admin_message') ]) return admin_area
def toggle_schedule_button(_, __, ___): """ Toggles the test scheduling button's visibility depending on whether user is logged in and an admin. :returns: html style """ if auth.is_authorized() and auth.is_admin(): return {} else: return {'display': 'none'}
def can_read_service_config(service_id, headers=None): """Returns True if current requester can read service configs. If X-Appengine-Inbound-Appid header matches service_id, the permission is granted. """ assert isinstance(service_id, basestring) assert service_id group = read_acl_cfg().service_access_group return (auth.is_admin() or group and auth.is_group_member(group) or (headers or {}).get('X-Appengine-Inbound-Appid') == service_id)
def add_bug_label(self, request): """Add a new bug label to a tree.""" if not auth.is_admin(): raise endpoints.NotFoundException() tree = Tree.get_by_id(request.tree) if not tree: raise endpoints.NotFoundException("Tree '%s' not found." % request.tree) tree.bug_labels.append(request.label) tree.bug_labels = list(set(tree.bug_labels)) tree.put() return tree.to_proto()
def has_role(package_path, role, identity): """True if |identity| has |role| in some |package_path|.""" assert impl.is_valid_package_path(package_path), package_path assert is_valid_role(role), role if auth.is_admin(identity): return True for acl in get_package_acls(package_path, role): if identity in acl.users: return True for group in acl.groups: if auth.is_group_member(group, identity): return True return False
def has_service_access(service_id): """Returns True if current requester can read service configs. An app <app-id> has access to configs of service with id <app-id>. """ assert isinstance(service_id, basestring) assert service_id if auth.is_admin(): return True service_cfg = services.get_service_async(service_id).get_result() return service_cfg and config.api._has_access(service_cfg.access)
def reimport(self, request): """Reimports a config set.""" if not auth.is_admin(): raise endpoints.ForbiddenException('Only admins are allowed to do this') # Assume it is Gitiles. try: gitiles_import.import_config_set(request.config_set) return message_types.VoidMessage() except gitiles_import.NotFoundError as e: raise endpoints.NotFoundException(e.message) except ValueError as e: raise endpoints.BadRequestException(e.message) except gitiles_import.Error as e: raise endpoints.InternalServerErrorException(e.message)
def reimport(self, request): """Reimports a config set.""" if not auth.is_admin(): raise endpoints.ForbiddenException( 'Only admins are allowed to do this') # Assume it is Gitiles. try: gitiles_import.import_config_set(request.config_set) return message_types.VoidMessage() except gitiles_import.NotFoundError as e: raise endpoints.NotFoundException(e.message) except ValueError as e: raise endpoints.BadRequestException(e.message) except gitiles_import.Error as e: raise endpoints.InternalServerErrorException(e.message)
def new(self, request): """Add a new tree.""" if not auth.is_admin(): raise endpoints.NotFoundException() if Tree.get_by_id(request.name): raise endpoints.ForbiddenException( "Duplicate tree with name '%s' found." % (request.name)) tree = Tree( id=request.name, display_name=request.display_name, bug_labels=request.bug_labels, group=request.group) tree.put() return tree.to_proto()
def is_trusted_requester(): """Returns True if the requester can see the service metadata. Used in metadata endpoint. Returns: True if the current identity is an admin or the config service. """ if auth.is_admin(): return True settings = common.ConfigSettings.cached() if settings and settings.trusted_config_account: identity = auth.get_current_identity() if identity == settings.trusted_config_account: return True return False
def insert_schedule_tests_button(n): """ Inserts the button for scheduling a new test and inserts test scheduling when button is clicked. :param n: number of clicks of button :returns: html.Button if authorized, None otherwise """ # Catch non authorized requests if not auth.is_authorized() or not auth.is_admin(): return # None means page load if n is None: return html.Button('Schedule now', className='topbar-button') # n=1 means first click on button if n == 1: by = auth.get_username() add_test_scheduling(by) return html.Button('Scheduled', className='topbar-button')
def has_any_of_roles_async(bucket, roles): """True if current identity has any of |roles| in |bucket|.""" assert bucket assert roles errors.validate_bucket_name(bucket) roles = set(roles) assert roles.issubset(project_config_pb2.Acl.Role.values()) if auth.is_admin(): raise ndb.Return(True) _, bucket_cfg = yield config.get_bucket_async(bucket) identity_str = auth.get_current_identity().to_bytes() if bucket_cfg: for rule in bucket_cfg.acls: if rule.role not in roles: continue if rule.identity == identity_str: raise ndb.Return(True) if rule.group and auth.is_group_member(rule.group): raise ndb.Return(True) raise ndb.Return(False)
def has_any_of_roles_async(bucket, roles): """True if current identity has any of |roles| in |bucket|.""" assert bucket assert roles errors.validate_bucket_name(bucket) roles = set(roles) assert roles.issubset(project_config_pb2.Acl.Role.values()) if auth.is_admin(): raise ndb.Return(True) bucket_cfg = yield config.get_bucket_async(bucket) identity_str = auth.get_current_identity().to_bytes() if bucket_cfg: for rule in bucket_cfg.acls: if rule.role not in roles: continue if rule.identity == identity_str: raise ndb.Return(True) if rule.group and auth.is_group_member(rule.group): raise ndb.Return(True) raise ndb.Return(False)
def isolate_writable(): """Returns True if current user can write to isolate.""" full_access = auth.is_group_member(config.settings().auth.full_access_group) return full_access or auth.is_admin()
def isolate_writable(): """Returns True if current user can write to isolate.""" return auth.is_group_member(FULL_ACCESS_GROUP) or auth.is_admin()
def is_admin(): return auth.is_group_member(ADMINS_GROUP) or auth.is_admin()
def has_project_access(project_id): metadata = projects.get_metadata(project_id) super_group = read_acl_cfg().project_access_group return (auth.is_admin() or super_group and auth.is_group_member(super_group) or metadata and config.api._has_access(metadata.access))
def has_project_access(): group = read_acl_cfg().project_access_group return auth.is_admin() or (group and auth.is_group_member(group))
class ConfigApi(remote.Service): """Configuration service.""" @auth.endpoints_method(ConfigSettingsMessage, ConfigSettingsMessage, http_method='POST') @auth.require(lambda: auth.is_superuser() or auth.is_admin()) def settings(self, request): """Reads/writes config service location. Accessible only by admins.""" settings = common.ConfigSettings.fetch() or common.ConfigSettings() delta = {} if request.service_hostname is not None: delta['service_hostname'] = request.service_hostname if request.trusted_config_account is not None: try: delta['trusted_config_account'] = auth.Identity.from_bytes( request.trusted_config_account) except ValueError as ex: raise endpoints.BadRequestException( 'Invalid trusted_config_account %s: %s' % (request.trusted_config_account, ex.message)) changed = settings.modify( updated_by=auth.get_current_identity().to_bytes(), **delta) if changed: logging.warning('Updated config settings') settings = common.ConfigSettings.fetch() or settings return ConfigSettingsMessage( service_hostname=settings.service_hostname, trusted_config_account=(settings.trusted_config_account.to_bytes() if settings.trusted_config_account else None)) @auth.endpoints_method(ValidateRequestMessage, ValidateResponseMessage, http_method='POST') @auth.require(is_trusted_requester) def validate(self, request): """Validates a config. Compatible with validation protocol described in ValidationCfg message of /appengine/config_service/proto/service_config.proto. """ ctx = validation.Context() validation.validate(request.config_set, request.path, request.content, ctx) res = ValidateResponseMessage() for m in ctx.result().messages: res.messages.append( ValidationMessage( severity=common.Severity.lookup_by_number(m.severity), text=m.text, )) return res @auth.endpoints_method(message_types.VoidMessage, ServiceDynamicMetadata, http_method='GET', path='metadata') @auth.require(is_trusted_requester) def get_metadata(self, _request): """Describes a service. Used by config service to discover other services. """ meta = ServiceDynamicMetadata(version=METADATA_FORMAT_VERSION) http_headers = dict(self.request_state.headers) assert 'host' in http_headers, http_headers meta.validation = meta.Validator( url='https://{hostname}/_ah/api/{name}/{version}/{path}validate'. format( hostname=http_headers['host'], name=self.api_info.name, version=self.api_info.version, path=self.api_info.path or '', )) for p in sorted(get_default_rule_set().patterns()): meta.validation.patterns.append(ConfigPattern(**p._asdict())) return meta
def is_admin(self): return auth.is_admin(self.identity)
def is_ereporter2_editor(): """Only auth admins or recipients can edit the silencing filters.""" return auth.is_admin() or auth.is_group_member(RECIPIENTS_AUTH_GROUP)
def is_ereporter2_viewer(): """True if current user is in recipients list, viewer list or is an admin.""" if auth.is_admin() or auth.is_group_member(VIEWERS_AUTH_GROUP): return True ident = auth.get_current_identity() return ident.is_user and ident.name in get_ereporter2_recipients()
def _is_admin(): """Full administrative access.""" group = config.settings().auth.admins_group return auth.is_group_member(group) or auth.is_admin()