def local_auth_server(token_cb, **overrides): class MockedProvider(object): def generate_token(self, scopes): return token_cb(scopes) s = auth_server.LocalAuthServer() try: local_auth = s.start(MockedProvider()) local_auth.update(overrides) with luci_context.write(local_auth=local_auth): yield finally: s.stop()
def local_auth_server(token_cb, default_account_id, **overrides): class MockedProvider(object): def generate_token(self, account_id, scopes): return token_cb(account_id, scopes) s = auth_server.LocalAuthServer() try: local_auth = s.start(token_provider=MockedProvider(), accounts=('acc_1', 'acc_2', 'acc_3'), default_account_id=default_account_id) local_auth.update(overrides) with luci_context.write(local_auth=local_auth): yield finally: s.stop()
def local_auth_server(token_cb, default_account_id, **overrides): class MockedProvider(object): def generate_token(self, account_id, scopes): return token_cb(account_id, scopes) acc = lambda aid: auth_server.Account(id=aid, email=aid + '@example.com') s = auth_server.LocalAuthServer() try: local_auth = s.start(token_provider=MockedProvider(), accounts=(acc('acc_1'), acc('acc_2'), acc('acc_3')), default_account_id=default_account_id) local_auth.update(overrides) with luci_context.write(local_auth=local_auth): yield finally: s.stop()
def start(self): """Grabs initial bot auth headers and starts all auth related threads. Raises: AuthSystemError on fatal errors. """ assert not self._auth_params_reader, 'already running' try: # Read headers more often than bot_main writes them (which is 60 sec), to # reduce maximum possible latency between header updates and reads. Use # interval that isn't a divisor of 60 to avoid reads and writes happening # at the same moment in time. reader = file_reader.FileReaderThread(self._auth_params_file, interval_sec=53) reader.start() except file_reader.FatalReadError as e: raise AuthSystemError('Cannot start FileReaderThread: %s' % e) # Initial validation. try: params = process_auth_params_json(reader.last_value) except ValueError as e: reader.stop() raise AuthSystemError('Cannot parse bot_auth_params.json: %s' % e) # If using task auth, launch local HTTP server that serves tokens (let OS # assign the port). server = None local_auth_context = None if params.task_service_account != 'none': try: server = auth_server.LocalAuthServer() local_auth_context = server.start(token_provider=self) except Exception as exc: reader.stop() # cleanup raise AuthSystemError( 'Failed to start local auth server - %s' % exc) # Good to go. with self._lock: self._auth_params_reader = reader self._local_server = server self._local_auth_context = local_auth_context
def start(self): """Grabs initial bot auth headers and starts all auth related threads. If the task is configured to use service accounts (based on data in 'auth_params_file'), launches the local auth service and returns a dict that contains its parameters. It can be placed into LUCI_CONTEXT['local_auth'] slot. Sets default service account (to be used by Swarming internal processes, like run_isolated.py) to 'system' (or unsets it if the bot has no associated service account). run_isolated.py eventually switches the default account to 'task' before launching the actual user-supplied code. If task is not using service accounts, returns None (meaning, there's no need to setup LUCI_CONTEXT['local_auth'] at all). Format of the returned dict: { 'rpc_port': <int with port number>, 'secret': <str with a random string to send with RPCs>, 'accounts': [{'id': <str>}, ...], 'default_account_id': <str> or None } Raises: AuthSystemError on fatal errors. """ assert not self._auth_params_reader, 'already running' try: # Read headers more often than bot_main writes them (which is 15 sec), to # reduce maximum possible latency between header updates and reads. # # TODO(vadimsh): Replace this with real IPC, like local sockets. reader = file_reader.FileReaderThread( self._auth_params_file, interval_sec=10) reader.start() except file_reader.FatalReadError as e: raise AuthSystemError('Cannot start FileReaderThread: %s' % e) # Initial validation. try: params = process_auth_params_json(reader.last_value) except ValueError as e: reader.stop() raise AuthSystemError('Cannot parse bot_auth_params.json: %s' % e) logging.info('Using following service accounts:') logging.info(' system: %s', params.system_service_account) logging.info(' task: %s', params.task_service_account) bot_email = '-' if params.bot_service_account != 'none': logging.info('The bot itself runs as %s', params.bot_service_account) bot_email = params.bot_service_account available_accounts = [] def add_account(account_id, email): if email == 'bot': email = bot_email available_accounts.append(auth_server.Account(id=account_id, email=email)) # Expose all defined accounts (if any) to subprocesses via LUCI_CONTEXT. # # Use 'system' logical account as default for internal Swarming processes. # It is specified by 'system_service_account' field in bots.cfg. Swarming # will eventually switch to 'task' logical account before launching # user-supplied code. 'task' account is specified in the task definition. # This happens in run_isolated.py. # # If 'system_service_account' is not defined, then do not set default # account at all! It means internal Swarming processes will use # non-authenticated calls (which is precisely the meaning of un-set # system account). default_account_id = None if params.system_service_account != 'none': default_account_id = 'system' add_account('system', params.system_service_account) if params.task_service_account != 'none': add_account('task', params.task_service_account) # If using service accounts, launch local HTTP server that serves tokens # (let OS assign the port). server = None local_auth_context = None if available_accounts: server = auth_server.LocalAuthServer() local_auth_context = server.start( token_provider=self, accounts=available_accounts, default_account_id=default_account_id) # Good to go. with self._lock: self._auth_params_reader = reader self._local_server = server return local_auth_context