예제 #1
0
    def login_kerberos(self):
        """
        Login to FreeIPA server using existing Kerberos credentials.

        In order to use this method, the package ```requests_kerberos`` <https://pypi.org/project/requests-kerberos/>`_
        must be installed. There must already be a Kerberos Ticket-Granting Ticket (TGT) cached in a Kerberos credential
        cache. Whether a TGT is available can be easily determined by running the klist command. If no TGT is available,
        then it first must be obtained by running the kinit command, or pointing the ``$KRB5CCNAME`` environment
        variable to a credential cache with a valid TGT.

        :raises Unauthorized: raised if credentials are invalid.
        :raises ImportError: raised if the ``requests_kerberos`` module is unavailable.
        """
        if isinstance(requests_kerberos, ImportError):
            raise requests_kerberos

        login_url = '{0}/session/login_kerberos'.format(self._base_url)
        headers = {'Referer': self._base_url}
        response = self._session.post(
            login_url,
            headers=headers,
            verify=self._verify_ssl,
            auth=requests_kerberos.HTTPKerberosAuth())

        if not response.ok:
            raise Unauthorized(response.text)

        self.log.info('Successfully logged using Kerberos credentials.')

        return AuthenticatedSession(self, logged_in=True)
예제 #2
0
def create_kerberos_auth(config):
    global requests_kerberos
    if requests_kerberos is None:
        import requests_kerberos

        KERBEROS_STRATEGIES['required'] = requests_kerberos.REQUIRED
        KERBEROS_STRATEGIES['optional'] = requests_kerberos.OPTIONAL
        KERBEROS_STRATEGIES['disabled'] = requests_kerberos.DISABLED

    # For convenience
    if config['kerberos_auth'] is None or is_affirmative(
            config['kerberos_auth']):
        config['kerberos_auth'] = 'required'

    if config['kerberos_auth'] not in KERBEROS_STRATEGIES:
        raise ConfigurationError(
            'Invalid Kerberos strategy `{}`, must be one of: {}'.format(
                config['kerberos_auth'], ' | '.join(KERBEROS_STRATEGIES)))

    return requests_kerberos.HTTPKerberosAuth(
        mutual_authentication=KERBEROS_STRATEGIES[config['kerberos_auth']],
        delegate=is_affirmative(config['kerberos_delegate']),
        force_preemptive=is_affirmative(config['kerberos_force_initiate']),
        hostname_override=config['kerberos_hostname'],
        principal=config['kerberos_principal'],
    )
예제 #3
0
    def __init__(
        self,
        server_url: str,
        use_tls: bool = False,
        headers: dict = None,
        auth=None,
        verify: bool = True,
    ):
        """
        Parameters
        ----------
        server_url: The URL of the livy server. Should include protocol (http/https) and port
        headers, optional: A dictionary for the API request to Livy.
        auth, optional: An object for `requests` to use in its `auth` keyword.
        verify, optional: (True) Use TLS / SSL. (False) Ignore TLS / SSL errors
        """
        self._verify = verify

        if auth is None:
            auth = requests_kerberos.HTTPKerberosAuth(
                mutual_authentication=requests_kerberos.REQUIRED,
                force_preemptive=True)

        self._auth = auth

        self._base_url = "%s/batches" % server_url

        if headers is None:
            headers = {"Content-Type": "application/json"}

        self._headers = headers
예제 #4
0
def get_raz_client(raz_url,
                   username,
                   auth='kerberos',
                   service='s3',
                   service_name='cm_s3',
                   cluster_name='myCluster'):
    if not username:
        from crequest.middleware import CrequestMiddleware
        request = CrequestMiddleware.get_request()
        username = request.user.username if request and hasattr(
            request, 'user') and request.user.is_authenticated else None

    if not username:
        raise PopupException('No username set.')

    if auth == 'kerberos' or True:  # True until JWT option
        auth_handler = requests_kerberos.HTTPKerberosAuth(
            mutual_authentication=requests_kerberos.OPTIONAL)

    raz = RazToken(raz_url, auth_handler)
    raz_token = raz.get_delegation_token(user=username)

    return RazClient(raz_url,
                     raz_token,
                     username,
                     service=service,
                     service_name=service_name,
                     cluster_name=cluster_name)
예제 #5
0
    def __init__(self,
                 url,
                 mode='r',
                 buffer_size=DEFAULT_BUFFER_SIZE,
                 kerberos=False,
                 user=None,
                 password=None):
        if kerberos:
            import requests_kerberos
            auth = requests_kerberos.HTTPKerberosAuth()
        elif user is not None and password is not None:
            auth = (user, password)
        else:
            auth = None

        self.buffer_size = buffer_size
        self.mode = mode

        self.response = requests.get(url,
                                     auth=auth,
                                     stream=True,
                                     headers=_HEADERS)

        if not self.response.ok:
            self.response.raise_for_status()

        self._read_iter = self.response.iter_content(self.buffer_size)
        self._read_buffer = b''
        self._current_pos = 0

        #
        # This member is part of the io.BufferedIOBase interface.
        #
        self.raw = None
예제 #6
0
    def __init__(self, user, timeout=100, kerberized=False, principal=None,
                 keytab=None, krb_conf=None,
                 host = "localhost", protocol = "http",
                 proxy_port = 50070, data_port = 50075, hdfs_ip = None, kdc_ip = None):
        self.host = host
        self.protocol = protocol
        self.proxy_port = proxy_port
        self.data_port = data_port
        self.user = user
        self.kerberized = kerberized
        self.principal = principal
        self.keytab = keytab
        self.timeout = timeout
        self.hdfs_ip = hdfs_ip
        self.kdc_ip = kdc_ip
        self.krb_conf = krb_conf

        # logging.basicConfig(level=logging.DEBUG)
        # logging.getLogger().setLevel(logging.DEBUG)
        # requests_log = logging.getLogger("requests.packages.urllib3")
        # requests_log.setLevel(logging.DEBUG)
        # requests_log.propagate = True

        if kerberized:
            self._run_kinit()
            self.kerberos_auth = reqkerb.HTTPKerberosAuth(mutual_authentication=reqkerb.DISABLED, hostname_override=self.host, principal=self.principal)
            if self.kerberos_auth is None:
                print("failed to obtain kerberos_auth")
        else:
            self.kerberos_auth = None
예제 #7
0
def get_requests_session(auth=False):
    """
    Create a requests session with authentication (when enabled).

    :param bool auth: configure authentication on the session
    :return: the configured requests session
    :rtype: requests.Session
    """
    config = get_worker_config()
    session = requests.Session()
    if auth:
        if config.cachito_auth_type == "kerberos":
            session.auth = requests_kerberos.HTTPKerberosAuth(
                mutual_authentication=requests_kerberos.OPTIONAL)
        elif config.cachito_auth_type == "cert":
            session.cert = config.cachito_auth_cert

    retry = Retry(total=5,
                  read=5,
                  connect=5,
                  backoff_factor=1.3,
                  status_forcelist=(500, 502, 503, 504))
    adapter = requests.adapters.HTTPAdapter(max_retries=retry)
    session.mount("http://", adapter)
    session.mount("https://", adapter)
    return session
예제 #8
0
def pdc_client(url, token, insecure, develop):
    """
    Because pdc_client is in upstream version and maybe change according to
    its own requirement, use some code here
    """
    session = requests.Session()

    if not develop:
        # For local environment, we don't need to require a token,
        # just access API directly.
        # REQUIRED, OPTIONAL, DISABLED
        session.auth = requests_kerberos.HTTPKerberosAuth(
            mutual_authentication=requests_kerberos.DISABLED)

    if insecure:
        # turn off for servers with insecure certificates
        session.verify = False

        # turn off warnings about making insecure calls
        if requests.__version__ < '2.4.0':
            print("Requests version is too old, please upgrade to 2.4.0 or latest.")
            # disable all warnings, it had better to upgrade requests.
            warnings.filterwarnings("ignore")
        else:
            requests.packages.urllib3.disable_warnings()

    pdc = beanbag.BeanBag(url, session=session)

    if not develop:
        # For develop environment, we don't need to require a token
        if not token:
            token = obtain_token(pdc)
        session.headers["Authorization"] = "Token %s" % token

    return pdc, session
예제 #9
0
def test_generate_request_header_step_error(mock_client):
    response = requests.Response()
    response.url = "http://www.example.org/"
    response.headers = {'www-authenticate': 'negotiate dG9rZW4='}
    host = urlparse(response.url).hostname
    auth = requests_kerberos.HTTPKerberosAuth()

    mock_client.return_value.step.side_effect = spnego.exceptions.InvalidTokenError(
    )
    with pytest.raises(requests_kerberos.exceptions.KerberosExchangeError,
                       match="ctx step failed"):
        auth.generate_request_header(response, host)

    assert mock_client.call_count == 1
    assert mock_client.call_args[1] == {
        "username": None,
        "hostname": "www.example.org",
        "service": "HTTP",
        "channel_bindings": None,
        "context_req":
        spnego.ContextReq.sequence_detect | spnego.ContextReq.mutual_auth,
        "protocol": "kerberos",
    }

    assert mock_client.return_value.step.call_count == 1
    assert mock_client.return_value.step.call_args[1] == {
        "in_token": b"token",
    }
예제 #10
0
    def _get_requests_config(cls, instance):
        auth = None

        # Authenticate our connection to JMX endpoint if required
        kerberos = instance.get('kerberos')
        username = instance.get('username')
        password = instance.get('password')
        if username is not None and password is not None:
            auth = (username, password)
        elif kerberos is not None:
            if kerberos not in KERBEROS_STRATEGIES:
                raise Exception(
                    'Invalid Kerberos strategy `{}`'.format(kerberos))

            auth = requests_kerberos.HTTPKerberosAuth(
                mutual_authentication=KERBEROS_STRATEGIES[kerberos],
                delegate=is_affirmative(
                    instance.get('kerberos_delegate', False)),
                force_preemptive=is_affirmative(
                    instance.get('kerberos_force_initiate', False)),
                hostname_override=instance.get('kerberos_hostname'),
                principal=instance.get('kerberos_principal'),
            )

        return RequestsConfig(
            auth=auth,
            ssl_verify=instance.get('ssl_verify'),
            ssl_cert=instance.get('ssl_cert'),
            ssl_key=instance.get('ssl_key'),
            kerberos_keytab=instance.get('kerberos_keytab'),
        )
    def test_handle_response_500_mutual_auth_required_failure(self):
        with patch('kerberos.authGSSClientStep', clientStep_error):

            response_500 = requests.Response()
            response_500.url = "http://www.example.org/"
            response_500.status_code = 500
            response_500.headers = {}
            response_500.request = "REQUEST"
            response_500.connection = "CONNECTION"
            response_500._content = "CONTENT"
            response_500.encoding = "ENCODING"
            response_500.raw = "RAW"
            response_500.cookies = "COOKIES"

            auth = requests_kerberos.HTTPKerberosAuth()
            auth.context = {"www.example.org": "CTX"}

            r = auth.handle_response(response_500)

            self.assertNotEqual(r, response_500)
            self.assertNotEqual(r.headers, response_500.headers)
            self.assertEqual(r.status_code, response_500.status_code)
            self.assertEqual(r.encoding, response_500.encoding)
            self.assertEqual(r.raw, response_500.raw)
            self.assertEqual(r.url, response_500.url)
            self.assertEqual(r.reason, response_500.reason)
            self.assertEqual(r.connection, response_500.connection)
            self.assertEqual(r.content, b'')
            self.assertNotEqual(r.cookies, response_500.cookies)

            self.assertFalse(clientStep_error.called)
예제 #12
0
    def __init__(self,
                 url,
                 mode='r',
                 kerberos=False,
                 user=None,
                 password=None):
        """
        If Kerberos is True, will attempt to use the local Kerberos credentials.
        Otherwise, will try to use "basic" HTTP authentication via username/password.

        If none of those are set, will connect unauthenticated.
        """
        if kerberos:
            import requests_kerberos
            auth = requests_kerberos.HTTPKerberosAuth()
        elif user is not None and password is not None:
            auth = (user, password)
        else:
            auth = None

        self.response = requests.get(url, auth=auth, stream=True)

        if not self.response.ok:
            self.response.raise_for_status()

        self.mode = mode
        self._read_buffer = None
        self._read_iter = None
        self._readline_iter = None
예제 #13
0
    def __init__(self,
                 url,
                 mode='r',
                 buffer_size=DEFAULT_BUFFER_SIZE,
                 kerberos=False,
                 user=None,
                 password=None,
                 headers=None,
                 timeout=None):
        """
        If Kerberos is True, will attempt to use the local Kerberos credentials.
        Otherwise, will try to use "basic" HTTP authentication via username/password.

        If none of those are set, will connect unauthenticated.
        """
        self.url = url

        if kerberos:
            import requests_kerberos
            self.auth = requests_kerberos.HTTPKerberosAuth()
        elif user is not None and password is not None:
            self.auth = (user, password)
        else:
            self.auth = None

        if headers is None:
            self.headers = _HEADERS.copy()
        else:
            self.headers = headers

        self.timeout = timeout

        self.buffer_size = buffer_size
        self.mode = mode
        self.response = self._partial_request()

        if not self.response.ok:
            self.response.raise_for_status()

        logger.debug('self.response: %r, raw: %r', self.response,
                     self.response.raw)

        self._seekable = True

        self.content_length = int(
            self.response.headers.get("Content-Length", -1))
        if self.content_length < 0:
            self._seekable = False
        if self.response.headers.get("Accept-Ranges",
                                     "none").lower() != "bytes":
            self._seekable = False

        self._read_iter = self.response.iter_content(self.buffer_size)
        self._read_buffer = bytebuffer.ByteBuffer(buffer_size)
        self._current_pos = 0

        #
        # This member is part of the io.BufferedIOBase interface.
        #
        self.raw = None
예제 #14
0
def test_no_force_preemptive():
    auth = requests_kerberos.HTTPKerberosAuth()

    request = requests.Request(url="http://www.example.org")

    auth.__call__(request)

    assert 'Authorization' not in request.headers
예제 #15
0
파일: raz_client.py 프로젝트: daleyjh/hue
def get_raz_client(raz_url, username, auth='kerberos', service='s3', service_name='cm_s3', cluster_name='myCluster'):
  if auth == 'kerberos' or True:  # True until ABFS option
    auth_handler = requests_kerberos.HTTPKerberosAuth(mutual_authentication=requests_kerberos.OPTIONAL)

  raz = RazToken(raz_url, auth_handler)
  raz_token = raz.get_delegation_token(user=username)

  return RazClient(raz_url, raz_token, username, service=service, service_name=service_name, cluster_name=cluster_name)
예제 #16
0
def login(args):
    kerb = requests_kerberos.HTTPKerberosAuth(
        mutual_authentication=requests_kerberos.DISABLED)
    s = requests.session()
    s.get('{base}{authpath}'.format(base=args.server, authpath=args.auth_path),
          auth=kerb,
          verify=args.cacert)
    return s
예제 #17
0
def _download(url, temp):
    """Downloads the image."""
    _LOGGER.debug('Downloading tar file from %r to %r.', url, temp)

    krb_auth = requests_kerberos.HTTPKerberosAuth(
        mutual_authentication=requests_kerberos.DISABLED)

    request = requests.get(url, stream=True, auth=krb_auth)
    shutil.copyfileobj(request.raw, temp)
예제 #18
0
def test_force_preemptive(mock_client):
    auth = requests_kerberos.HTTPKerberosAuth(force_preemptive=True)

    request = requests.Request(url="http://www.example.org")

    auth.__call__(request)

    assert 'Authorization' in request.headers
    assert request.headers.get('Authorization') == 'Negotiate R1NTUkVTUE9OU0U='
예제 #19
0
def _krb_auth():
    """Returns kerberos auth object."""
    auth_principle = None
    if os.name == 'posix':
        # kerberos 1.2.5 doesn't accept None principal. Remove this once fixed.
        auth_principle = ''

    return requests_kerberos.HTTPKerberosAuth(
        mutual_authentication=requests_kerberos.DISABLED,
        principal=auth_principle,
        service=restclientopts.AUTH_PRINCIPAL)
예제 #20
0
파일: tar.py 프로젝트: GrammaB/treadmill
def _download(url, temp):
    """Downloads the image."""
    _LOGGER.debug('Downloading tar file from %r to %r.', url, temp)

    krb_auth = requests_kerberos.HTTPKerberosAuth(
        mutual_authentication=requests_kerberos.DISABLED,
        # kerberos 1.2.5 doesn't accept None principal. Remove this once fixed.
        principal='')

    request = requests.get(url, stream=True, auth=krb_auth)
    shutil.copyfileobj(request.raw, temp)
 def test_generate_request_header_custom_service(self):
     with patch.multiple('kerberos',
                         authGSSClientInit=clientInit_error,
                         authGSSClientResponse=clientResponse,
                         authGSSClientStep=clientStep_continue):
         response = requests.Response()
         response.url = "http://www.example.org/"
         response.headers = {'www-authenticate': 'negotiate token'}
         auth = requests_kerberos.HTTPKerberosAuth(service="barfoo")
         auth.generate_request_header(response),
         clientInit_error.assert_called_with("*****@*****.**")
예제 #22
0
    def test_kerberos_sspi_reject_principal(self):
        with patch.multiple(kerberos_module_name,
                            authGSSClientInit=clientInit_complete,
                            authGSSClientResponse=clientResponse,
                            authGSSClientStep=clientStep_continue):
            response = requests.Response()
            response.url = "http://www.example.org/"
            host = urlparse(response.url).hostname

            auth = requests_kerberos.HTTPKerberosAuth(principal="user@REALM")
            auth._using_kerberos_sspi = True
            self.assertRaises(NotImplementedError,
                              auth.generate_request_header, response, host)

            auth = requests_kerberos.HTTPKerberosAuth(principal=None)
            auth._using_kerberos_sspi = True
            auth.generate_request_header(response, host)
            clientInit_complete.assert_called_with(
                "*****@*****.**",
                gssflags=(kerberos.GSS_C_MUTUAL_FLAG
                          | kerberos.GSS_C_SEQUENCE_FLAG))
    def test_no_force_preemptive(self):
        with patch.multiple(kerberos_module_name,
                            authGSSClientInit=clientInit_complete,
                            authGSSClientResponse=clientResponse,
                            authGSSClientStep=clientStep_continue):
            auth = requests_kerberos.HTTPKerberosAuth()

            request = requests.Request(url="http://www.example.org")

            auth.__call__(request)

            self.assertTrue('Authorization' not in request.headers)
예제 #24
0
def test_handle_response_200_mutual_auth_optional_soft_failure(mock_client):
    response_ok = requests.Response()
    response_ok.url = "http://www.example.org/"
    response_ok.status_code = 200

    auth = requests_kerberos.HTTPKerberosAuth(requests_kerberos.OPTIONAL)
    auth._context = {"www.example.org": mock_client.return_value}

    r = auth.handle_response(response_ok)

    assert r == response_ok
    assert mock_client.return_value.step.call_count == 0
예제 #25
0
    def _setup_tunnel(self, host_port):
        """Use HTTPConnection to HTTP CONNECT to our proxy, connect to the backend and return socket for this tunnel.

    host_port: tuple (host, port) from thrift.transport.TSocket._resolveAddr.
    """
        conn = httplib.HTTPConnection(self.proxy_host, self.proxy_port)
        auth_header = requests_kerberos.HTTPKerberosAuth(
        ).generate_request_header(None, self.proxy_host, is_preemptive=True)
        conn.set_tunnel(*host_port,
                        headers={'Proxy-Authorization': auth_header})
        conn.connect()
        return conn.sock
예제 #26
0
 def test_generate_request_header_step_error(self):
     with patch.multiple('kerberos',
                         authGSSClientInit=clientInit_complete,
                         authGSSClientResponse=clientResponse,
                         authGSSClientStep=clientStep_error):
         response = requests.Response()
         response.url = "http://www.example.org/"
         response.headers = {'www-authenticate': 'negotiate token'}
         auth = requests_kerberos.HTTPKerberosAuth()
         self.assertEqual(auth.generate_request_header(response), None)
         clientInit_complete.assert_called_with("*****@*****.**")
         clientStep_error.assert_called_with("CTX", "token")
         self.assertFalse(clientResponse.called)
예제 #27
0
def test_handle_response_200_mutual_auth_required_failure(mock_client):
    response_ok = requests.Response()
    response_ok.url = "http://www.example.org/"
    response_ok.status_code = 200
    response_ok.headers = {}

    auth = requests_kerberos.HTTPKerberosAuth()
    auth._context = {"www.example.org": mock_client.return_value}

    with pytest.raises(requests_kerberos.MutualAuthenticationError):
        auth.handle_response(response_ok)

    assert mock_client.return_value.step.call_count == 0
예제 #28
0
def test_handle_response_500_mutual_auth_required_failure(mock_client):
    response_500 = requests.Response()
    response_500.url = "http://www.example.org/"
    response_500.status_code = 500
    response_500.headers = {}
    response_500.request = "REQUEST"
    response_500.connection = "CONNECTION"
    response_500._content = "CONTENT"
    response_500.encoding = "ENCODING"
    response_500.raw = "RAW"
    response_500.cookies = "COOKIES"

    auth = requests_kerberos.HTTPKerberosAuth()
    auth._context = {"www.example.org": mock_client.return_value}

    r = auth.handle_response(response_500)

    assert isinstance(r, requests_kerberos.kerberos_.SanitizedResponse)
    assert r != response_500
    assert r.headers != response_500.headers
    assert r.status_code == response_500.status_code
    assert r.encoding == response_500.encoding
    assert r.raw == response_500.raw
    assert r.url == response_500.url
    assert r.reason == response_500.reason
    assert r.connection == response_500.connection
    assert r.content == ''
    assert r.cookies != response_500.cookies

    assert mock_client.return_value.step.call_count == 0

    # re-test with error response sanitizing disabled
    auth = requests_kerberos.HTTPKerberosAuth(
        sanitize_mutual_error_response=False)
    auth._context = {"www.example.org": mock_client.return_value}

    r = auth.handle_response(response_500)

    assert not isinstance(r, requests_kerberos.kerberos_.SanitizedResponse)
예제 #29
0
def test_handle_response_401_rejected(mock_client, mocker):
    # Get a 401 from server, authenticate, and get another 401 back.
    # Ensure there is no infinite recursion.
    connection = mocker.MagicMock()

    def connection_send(self, *args, **kwargs):
        reject = requests.Response()
        reject.url = "http://www.example.org/"
        reject.status_code = 401
        reject.connection = connection
        return reject

    connection.send.side_effect = connection_send

    request = requests.Request()
    response = requests.Response()
    response.request = request
    response.url = "http://www.example.org/"
    response.headers = {'www-authenticate': 'negotiate dG9rZW4='}
    response.status_code = 401
    response.connection = connection
    response._content = ""
    response.raw = mocker.MagicMock(return_value=None)

    auth = requests_kerberos.HTTPKerberosAuth()

    r = auth.handle_response(response)

    assert r.status_code == 401
    assert request.headers["Authorization"] == "Negotiate R1NTUkVTUE9OU0U="

    assert connection.send.call_count == 1
    assert connection.send.call_args[0] == (request, )
    assert response.raw.release_conn.call_count == 1
    assert response.raw.release_conn.call_args[0] == ()

    assert mock_client.call_count == 1
    assert mock_client.call_args[1] == {
        "username": None,
        "hostname": "www.example.org",
        "service": "HTTP",
        "channel_bindings": None,
        "context_req":
        spnego.ContextReq.sequence_detect | spnego.ContextReq.mutual_auth,
        "protocol": "kerberos",
    }

    assert mock_client.return_value.step.call_count == 1
    assert mock_client.return_value.step.call_args[1] == {
        "in_token": b"token",
    }
예제 #30
0
def test_delegation(mock_client, mocker):
    response_ok = requests.Response()
    response_ok.url = "http://www.example.org/"
    response_ok.status_code = 200
    response_ok.headers = {'www-authenticate': 'negotiate c2VydmVydG9rZW4='}

    connection = mocker.MagicMock()
    connection.send.return_value = response_ok

    request = requests.Request()
    response = requests.Response()
    response.request = request
    response.url = "http://www.example.org/"
    response.headers = {'www-authenticate': 'negotiate dG9rZW4='}
    response.status_code = 401
    response.connection = connection
    response._content = ""
    response.raw = mocker.MagicMock(return_value=None)
    auth = requests_kerberos.HTTPKerberosAuth(1, "HTTP", True)
    r = auth.authenticate_user(response)

    assert response in r.history
    assert r == response_ok
    assert request.headers["Authorization"] == "Negotiate R1NTUkVTUE9OU0U="

    assert connection.send.call_count == 1
    assert connection.send.call_args[0] == (request, )

    assert mock_client.call_count == 1
    assert mock_client.call_args[1] == {
        "username":
        None,
        "hostname":
        "www.example.org",
        "service":
        "HTTP",
        "channel_bindings":
        None,
        "context_req":
        spnego.ContextReq.sequence_detect | spnego.ContextReq.mutual_auth
        | spnego.ContextReq.delegate,
        "protocol":
        "kerberos",
    }

    assert mock_client.return_value.step.call_count == 1
    assert mock_client.return_value.step.call_args[1] == {
        "in_token": b"token",
    }