def is_ip_whitelisted_machine(): """Returns True if the call is made from IP whitelisted machine.""" # TODO(vadimsh): Get rid of this. It's blocked on fixing /bot_code calls in # bootstrap code everywhere to use service accounts and switching all Swarming # Tasks API calls made from bots to use proper authentication. return auth.is_in_ip_whitelist(auth.bots_ip_whitelist(), auth.get_peer_ip(), False)
def validate_bot_id_and_fetch_config(bot_id): """Verifies ID reported by a bot matches the credentials being used. Expected to be called in a context of some bot API request handler. Uses bots.cfg config to look up what credentials are expected to be used by the bot with given ID. Raises auth.AuthorizationError if bot_id is unknown or bot is using invalid credentials. On success returns the configuration for this bot (BotGroupConfig tuple), as defined in bots.cfg """ cfg = bot_groups_config.get_bot_group_config(bot_id) if not cfg: logging.error( 'bot_auth: unknown bot_id, not in the config\nbot_id: "%s"', bot_id) raise auth.AuthorizationError('Unknown bot ID, not in config') peer_ident = auth.get_peer_identity() if cfg.require_luci_machine_token: if not _is_valid_ident_for_bot(peer_ident, bot_id): logging.error( 'bot_auth: bot ID doesn\'t match the machine token used\n' 'bot_id: "%s", peer_ident: "%s"', bot_id, peer_ident.to_bytes()) raise auth.AuthorizationError( 'Bot ID doesn\'t match the token used') elif cfg.require_service_account: expected_id = auth.Identity(auth.IDENTITY_USER, cfg.require_service_account) if peer_ident != expected_id: logging.error( 'bot_auth: bot is not using expected service account\n' 'bot_id: "%s", expected_id: "%s", peer_ident: "%s"', bot_id, expected_id.to_bytes(), peer_ident.to_bytes()) raise auth.AuthorizationError( 'bot is not using expected service account') elif not cfg.ip_whitelist: # This branch should not be hit for validated configs. logging.error( 'bot_auth: invalid bot group config, no auth method defined\n' 'bot_id: "%s"', bot_id) raise auth.AuthorizationError('Invalid bot group config') # Check that IP whitelist applies (in addition to credentials). if cfg.ip_whitelist: ip = auth.get_peer_ip() if not auth.is_in_ip_whitelist(cfg.ip_whitelist, ip): logging.error( 'bot_auth: bot IP is not whitelisted\n' 'bot_id: "%s", peer_ip: "%s", ip_whitelist: "%s"', bot_id, ipaddr.ip_to_string(ip), cfg.ip_whitelist) raise auth.AuthorizationError('Not IP whitelisted') return cfg
def post(self): # Forbid usage of delegation tokens for this particular call. Using # delegation when creating delegation tokens is too deep. Redelegation will # be done as separate explicit API call that accept existing delegation # token via request body, not via headers. if auth.get_current_identity() != auth.get_peer_identity(): raise auth.AuthorizationError( 'This API call must not be used with active delegation token') # Convert request body to proto (with validation). Verify IP format. try: body = self.parse_body() subtoken = subtoken_from_jsonish(body) intent = body.get('intent') or '' if not isinstance(intent, basestring): raise TypeError('"intent" must be string') except (TypeError, ValueError) as exc: self.abort_with_error(400, text=str(exc)) # Fill in defaults. assert not subtoken.requestor_identity user_id = auth.get_current_identity().to_bytes() subtoken.requestor_identity = user_id if not subtoken.delegated_identity: subtoken.delegated_identity = user_id subtoken.creation_time = int(utils.time_time()) if not subtoken.validity_duration: subtoken.validity_duration = DEF_VALIDITY_DURATION_SEC if '*' in subtoken.services: subtoken.services[:] = get_default_allowed_services(user_id) # Check ACL (raises auth.AuthorizationError on errors). rule = check_can_create_token(user_id, subtoken) # Register the token in the datastore, generate its ID. subtoken.subtoken_id = register_subtoken(subtoken, rule, intent, auth.get_peer_ip()) # Create and sign the token. try: token = delegation.serialize_token(delegation.seal_token(subtoken)) except delegation.BadTokenError as exc: # This happens if resulting token is too large. self.abort_with_error(400, text=str(exc)) self.send_response(response={ 'delegation_token': token, 'subtoken_id': str(subtoken.subtoken_id), 'validity_duration': subtoken.validity_duration, }, http_code=201)
def file_size(size): """Reports the size of a file fetched from GCS by whitelisted clients. If the client's requests are not whitelisted for monitoring, does nothing. Args: size: Size of the file in bytes. """ ip = auth.get_peer_ip() for cfg in config.settings().client_monitoring_config: if auth.is_in_ip_whitelist(cfg.ip_whitelist, ip): _bytes_requested.increment_by( size, fields={ 'client_name': cfg.label, 'client_email': auth.get_peer_identity().to_bytes(), 'download_source': 'GCS' }) return
def who(self, _request): return WhoResponse( host=auth.get_peer_host(), identity=auth.get_current_identity().to_bytes(), ip=auth.ip_to_string(auth.get_peer_ip()))
def who(self, _request): return WhoResponse(host=auth.get_peer_host(), identity=auth.get_current_identity().to_bytes(), ip=auth.ip_to_string(auth.get_peer_ip()))
def validate_bot_id_and_fetch_config(bot_id): """Verifies ID reported by a bot matches the credentials being used. Expected to be called in a context of some bot API request handler. Uses bots.cfg config to look up what credentials are expected to be used by the bot with given ID. Raises auth.AuthorizationError if bot_id is unknown or bot is using invalid credentials. On success returns the configuration for this bot (BotGroupConfig tuple), as defined in bots.cfg. """ bot_id = _extract_primary_hostname(bot_id) cfg = bot_groups_config.get_bot_group_config(bot_id) if not cfg: logging.error( 'bot_auth: unknown bot_id, not in the config\nbot_id: "%s"', bot_id) raise auth.AuthorizationError('Unknown bot ID, not in config') # This should not really happen for validated configs. if not cfg.auth: logging.error('bot_auth: no auth configured in bots.cfg') raise auth.AuthorizationError('No auth configured in bots.cfg') ip = auth.get_peer_ip() peer_ident = auth.get_peer_identity() # Errors from all auth methods. auth_errs = [] # Logs to emit if all methods fail. Omitted if some method succeeds. delayed_logs = [] # Try all auth methods sequentially until a first success. When migrating # between different methods it may be important to know when a method is # skipped. Logs from such methods are always emitted at 'error' level. Other # logs are buffered and emitted only if all methods fail. for bot_auth in cfg.auth: err, details = _check_bot_auth(bot_auth, bot_id, peer_ident, ip) if not err: logging.debug('Using auth method: %s', bot_auth) return cfg auth_errs.append(err) if bot_auth.log_if_failed: logging.error('Preferred auth method failed: %s', err) logging.error('Failed auth method: %s', bot_auth) for msg in details: logging.error('%s', msg) else: delayed_logs.append('Auth method failed: %s' % (err, )) delayed_logs.append('Failed auth method: %s' % (bot_auth, )) delayed_logs.extend(details) # All fallback methods failed. Need their logs to investigate. for msg in delayed_logs: logging.error('%s', msg) # In most cases there's only one auth method used, so we can simplify the # error message to be less confusing. if len(auth_errs) == 1: raise auth.AuthorizationError(auth_errs[0]) raise auth.AuthorizationError('All auth methods failed: %s' % '; '.join(auth_errs))
def is_ip_whitelisted_machine(): """Returns True if the call is made from IP whitelisted machine.""" return auth.is_in_ip_whitelist(auth.bots_ip_whitelist(), auth.get_peer_ip(), False)