Exemplo n.º 1
0
  def _grab_bot_token(self, auth_params):
    """Extracts OAuth token from 'Authorization' header used by the bot itself.

    This works only for bots that use OAuth for authentication (e.g. GCE bots).
    Also it totally ignores scopes. It relies on bot_main to keep the bot OAuth
    token sufficiently fresh. See remote_client.AUTH_HEADERS_EXPIRATION_SEC.

    Args:
      auth_params: AuthParams tuple with configuration.

    Returns:
      auth_server.AccessToken.
    """
    bot_auth_hdr = auth_params.swarming_http_headers.get('Authorization') or ''
    if not bot_auth_hdr.startswith('Bearer '):
      raise auth_server.TokenError(2, 'The bot is not using OAuth')
    tok = bot_auth_hdr[len('Bearer '):]

    # Default to some safe small expiration in case bot_main doesn't report it
    # to us. This may happen if get_authentication_header bot hook is not
    # reporting expiration time.
    exp = auth_params.swarming_http_headers_exp or (time.time() + 4*60)

    # TODO(vadimsh): For GCE bots specifically we can pass a list of OAuth
    # scopes granted to the GCE token and verify it contains all the requested
    # scopes.
    return auth_server.AccessToken(tok, exp)
Exemplo n.º 2
0
    def _grab_token_via_rpc(self, auth_params, rpc_client, account_id, scopes):
        """Makes RPC to Swarming to mint a token.

    Args:
      auth_params: AuthParams tuple with configuration.
      rpc_client: instance of remote_client.RemoteClient to use for RPC.
      account_id: logical account name (e.g 'system' or 'task').
      scopes: list of OAuth scopes.

    Returns:
      (auth_server.AccessToken, <service account email>).
    """
        # Clients of AuthSystem can bombard it with parallel requests for the exact
        # same OAuth token (imagine a task launching N subprocesses in parallel,
        # each one requesting a token). We stop this concurrency here with a battery
        # of locks keyed by (account_id, sorted(scopes)). So the Swarming will see
        # only one request at a time.
        with self._rpc_locks.lock(key=(account_id, tuple(sorted(scopes)))):
            try:
                # WARNING: This call may indirectly call 'get_bot_headers', so we have
                # to use a different lock here (not self._lock).
                resp = rpc_client.mint_oauth_token(task_id=auth_params.task_id,
                                                   bot_id=auth_params.bot_id,
                                                   account_id=account_id,
                                                   scopes=scopes)
            except remote_client.InternalError as exc:
                # Raising RPCError propagates transient error status to clients, so that
                # they can decide to retry later.
                raise auth_server.RPCError(500, str(exc))
            except remote_client.MintOAuthTokenError as exc:
                # Raising fatal TokenError makes LocalAuthServer cache the error, so
                # that retrying clients get the error reply right away, without hitting
                # Swarming server.
                raise auth_server.TokenError(4, str(exc))

        # This is <email>, 'bot' or 'none'. We should handle all cases, since
        # the configuration on the server can change while the bot is running
        # the task. This is bad, but possible.
        service_account = resp.get('service_account') or 'unknown'
        if service_account == 'none':
            raise auth_server.TokenError(
                1,
                'The task has no %r account associated with it' % account_id)
        if service_account == 'bot':
            return self._grab_bot_token(auth_params), 'bot'

        # Should have a real token here now. Double check and return. It will be
        # cached by LocalAuthServer until it expires.
        access_token = resp.get('access_token')
        expiry = resp.get('expiry')
        if not access_token or not isinstance(access_token, basestring):
            raise auth_server.RPCError(
                500, 'Bad server reply, no valid token given')
        if not expiry or not isinstance(expiry, (int, long)):
            raise auth_server.RPCError(
                500, 'Bad server reply, no token expiry given')

        # Normalize types (unicode -> str, long -> int).
        tok = auth_server.AccessToken(str(access_token), int(expiry))
        return tok, str(service_account)
Exemplo n.º 3
0
    def _grab_bot_oauth_token(self, auth_params):
        # Piggyback on the bot own credentials for now. This works only for bots
        # that use OAuth for authentication (e.g. GCE bots). Also it totally ignores
        # scopes or expiration time. It relies on bot_main to keep the bot OAuth
        # token sufficiently fresh. See remote_client.AUTH_HEADERS_EXPIRATION_SEC.
        bot_auth_hdr = auth_params.swarming_http_headers.get(
            'Authorization') or ''
        if not bot_auth_hdr.startswith('Bearer '):
            raise auth_server.TokenError(2,
                                         'The bot is not using OAuth',
                                         fatal=True)
        tok = bot_auth_hdr[len('Bearer '):]

        # bot_main guarantees swarming_http_headers are usable for at least 6 min.
        # (see AUTH_HEADERS_EXPIRATION_SEC). task_runner grabs these headers from
        # bot_main asynchronously with some delay. To account for that delay make
        # expiration time shorter (4 min instead of 6 min).
        #
        # TODO(vadimsh): The real token expiration time can be passed from
        # bot_main.py via --auth-params-file mechanism (same way as
        # 'swarming_http_headers' are passed).
        #
        # TODO(vadimsh): For GCE bots specifically we can pass a list of OAuth
        # scopes granted to the GCE token and verify it contains all the requested
        # scopes.
        return auth_server.AccessToken(tok, int(time.time()) + 4 * 60)
Exemplo n.º 4
0
 def token_gen(account_id, scopes):
     calls.append((account_id, scopes))
     return auth_server.AccessToken('tok_%s' % account_id,
                                    time.time() + 300)
Exemplo n.º 5
0
 def token_gen(account_id, scopes):
     self.assertEqual('acc_1', account_id)
     self.assertEqual(1, len(scopes))
     self.assertEqual(oauth.OAUTH_SCOPES, scopes[0])
     return auth_server.AccessToken(token, time.time())
Exemplo n.º 6
0
 def token_gen(scopes):
     calls.append(scopes)
     return auth_server.AccessToken('tok', time.time() + 300)
Exemplo n.º 7
0
 def token_gen(scopes):
     self.assertEqual(1, len(scopes))
     self.assertEqual(oauth.OAUTH_SCOPES, scopes[0])
     return auth_server.AccessToken(token, time.time() + 300)