Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trying to use HTTPKerberosAuthentication fails using principal #188

Closed
9y2070m opened this issue May 31, 2024 · 7 comments
Closed

Trying to use HTTPKerberosAuthentication fails using principal #188

9y2070m opened this issue May 31, 2024 · 7 comments

Comments

@9y2070m
Copy link

9y2070m commented May 31, 2024

On a non-domain joined machine, I try to fetch something from an API where I need Kerberos authentication.

OS Name: Microsoft Windows 10 Enterprise
Version: 10.0.19045 Build 19045
PS C:\_workspace_\key_infrastructure> poetry run pip freeze
asttokens==2.4.1
astunparse==1.6.3
backcall==0.2.0
bcrypt==4.1.3
certifi==2024.2.2
cffi==1.16.0
charset-normalizer==3.3.2
colorama==0.4.6
coverage==7.5.1
cryptography==42.0.7
decorator==5.1.1
exceptiongroup==1.2.1
executing==2.0.1
idna==3.7
iniconfig==2.0.0
ipython==8.12.3
jedi==0.19.1
Jinja2==3.1.4
MarkupSafe==2.1.5
matplotlib-inline==0.1.7
packaging==24.0
paramiko==3.4.0
parso==0.8.4
pdoc==14.4.0
pickleshare==0.7.5
pluggy==1.5.0
prompt_toolkit==3.0.45
pure-eval==0.2.2
pycparser==2.22
Pygments==2.18.0
PyNaCl==1.5.0
pyspnego==0.10.2
pytest==7.4.4
pytest-mock==3.14.0
requests==2.31.0
requests-kerberos==0.14.0
requests-mock==1.12.1
six==1.16.0
sspilib==0.1.0
stack-data==0.6.3
tomli==2.0.1
traitlets==5.14.3
typing_extensions==4.12.0
urllib3==2.2.1
wcwidth==0.2.13

The authentication is set as follows:

_kerberos_authentication = requests_kerberos.HTTPKerberosAuth(
    mutual_authentication=requests_kerberos.DISABLED,
    principal=f"UserName@DOMAIN.AT:secret-password",
)

Using the correct username and password does not work on the non-domain joined machine.

>>> client.fetch_private_key_certificate_pair_for_device(id="100001211", environment=definition.Environment.DEV)
2024-05-31 13:38:35,027 - key_infrastructure.client - Fetch private key and certificate for id='100001211' valid -12h:20240614133835 (environment=<Environment.DEV: 'dev'>.).
2024-05-31 13:38:35,027 - key_infrastructure.client - Fetch a fresh key infrastructure access token (environment=<Environment.DEV: 'dev'>, role='debug').
2024-05-31 13:38:35,027 - key_infrastructure.client - GET url='https://key.infrastructure.at/api/v1/dev/token/roles/debug'
2024-05-31 13:38:35,037 - urllib3.connectionpool - Starting new HTTPS connection (1): key.infrastructure.at:443
2024-05-31 13:38:35,057 - urllib3.connectionpool - https://key.infrastructure.at:443 "GET /api/v1/dev/token/roles/debug HTTP/1.1" 401 381
2024-05-31 13:38:35,057 - requests_kerberos.kerberos_ - handle_401(): Handling: 401
2024-05-31 13:38:35,057 - spnego._sspi - SSPI step input:
2024-05-31 13:38:35,057 - requests_kerberos.kerberos_ - generate_request_header(): ctx step failed:
Traceback (most recent call last):
  File "C:\Users\DemoUser\AppData\Local\pypoetry\Cache\virtualenvs\key-infrastructure-FYt_TK8o-py3.8\lib\site-packages\spnego\_context.py", line 68, in wrapper
    return func(*args, **kwargs)
  File "C:\Users\DemoUser\AppData\Local\pypoetry\Cache\virtualenvs\key-infrastructure-FYt_TK8o-py3.8\lib\site-packages\spnego\_sspi.py", line 263, in step
    res = sspilib.raw.initialize_security_context(
  File "src\\sspilib\\raw\\_security_context.pyx", line 438, in sspilib.raw._security_context.initialize_security_context
OSError: [WinError -2146893042] No credentials are available in the security package

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\DemoUser\AppData\Local\pypoetry\Cache\virtualenvs\key-infrastructure-FYt_TK8o-py3.8\lib\site-packages\requests_kerberos\kerberos_.py", line 227, in generate_request_header
    gss_response = ctx.step(in_token=negotiate_resp_value)
  File "C:\Users\DemoUser\AppData\Local\pypoetry\Cache\virtualenvs\key-infrastructure-FYt_TK8o-py3.8\lib\site-packages\spnego\_context.py", line 71, in wrapper
    raise SpnegoError(base_error=native_err, context_msg=context) from native_err
spnego.exceptions.NoCredentialError: SpnegoError (7): [WinError -2146893042] No credentials are available in the security package, Context: Processing security token
2024-05-31 13:38:35,067 - requests_kerberos.kerberos_ - SpnegoError (7): [WinError -2146893042] No credentials are available in the security package, Context: Processing security token
Traceback (most recent call last):
  File "C:\Users\DemoUser\AppData\Local\pypoetry\Cache\virtualenvs\key-infrastructure-FYt_TK8o-py3.8\lib\site-packages\spnego\_context.py", line 68, in wrapper
    return func(*args, **kwargs)
  File "C:\Users\DemoUser\AppData\Local\pypoetry\Cache\virtualenvs\key-infrastructure-FYt_TK8o-py3.8\lib\site-packages\spnego\_sspi.py", line 263, in step
    res = sspilib.raw.initialize_security_context(
  File "src\\sspilib\\raw\\_security_context.pyx", line 438, in sspilib.raw._security_context.initialize_security_context
OSError: [WinError -2146893042] No credentials are available in the security package

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\DemoUser\AppData\Local\pypoetry\Cache\virtualenvs\key-infrastructure-FYt_TK8o-py3.8\lib\site-packages\requests_kerberos\kerberos_.py", line 227, in generate_request_header
    gss_response = ctx.step(in_token=negotiate_resp_value)
  File "C:\Users\DemoUser\AppData\Local\pypoetry\Cache\virtualenvs\key-infrastructure-FYt_TK8o-py3.8\lib\site-packages\spnego\_context.py", line 71, in wrapper
    raise SpnegoError(base_error=native_err, context_msg=context) from native_err
spnego.exceptions.NoCredentialError: SpnegoError (7): [WinError -2146893042] No credentials are available in the security package, Context: Processing security token
2024-05-31 13:38:35,067 - requests_kerberos.kerberos_ - handle_401(): returning <Response [401]>
2024-05-31 13:38:35,067 - requests_kerberos.kerberos_ - handle_response(): returning <Response [401]>
2024-05-31 13:38:35,067 - requests_kerberos.kerberos_ - handle_response() has seen 0 401 responses
2024-05-31 13:38:35,077 - requests_kerberos.kerberos_ - handle_401(): Handling: 401
2024-05-31 13:38:35,077 - spnego._sspi - SSPI step input:
2024-05-31 13:38:35,077 - requests_kerberos.kerberos_ - generate_request_header(): ctx step failed:
Traceback (most recent call last):
  File "C:\Users\DemoUser\AppData\Local\pypoetry\Cache\virtualenvs\key-infrastructure-FYt_TK8o-py3.8\lib\site-packages\spnego\_context.py", line 68, in wrapper
    return func(*args, **kwargs)
  File "C:\Users\DemoUser\AppData\Local\pypoetry\Cache\virtualenvs\key-infrastructure-FYt_TK8o-py3.8\lib\site-packages\spnego\_sspi.py", line 263, in step
    res = sspilib.raw.initialize_security_context(
  File "src\\sspilib\\raw\\_security_context.pyx", line 438, in sspilib.raw._security_context.initialize_security_context
OSError: [WinError -2146893042] No credentials are available in the security package

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\DemoUser\AppData\Local\pypoetry\Cache\virtualenvs\key-infrastructure-FYt_TK8o-py3.8\lib\site-packages\requests_kerberos\kerberos_.py", line 227, in generate_request_header
    gss_response = ctx.step(in_token=negotiate_resp_value)
  File "C:\Users\DemoUser\AppData\Local\pypoetry\Cache\virtualenvs\key-infrastructure-FYt_TK8o-py3.8\lib\site-packages\spnego\_context.py", line 71, in wrapper
    raise SpnegoError(base_error=native_err, context_msg=context) from native_err
spnego.exceptions.NoCredentialError: SpnegoError (7): [WinError -2146893042] No credentials are available in the security package, Context: Processing security token
2024-05-31 13:38:35,077 - requests_kerberos.kerberos_ - SpnegoError (7): [WinError -2146893042] No credentials are available in the security package, Context: Processing security token
Traceback (most recent call last):
  File "C:\Users\DemoUser\AppData\Local\pypoetry\Cache\virtualenvs\key-infrastructure-FYt_TK8o-py3.8\lib\site-packages\spnego\_context.py", line 68, in wrapper
    return func(*args, **kwargs)
  File "C:\Users\DemoUser\AppData\Local\pypoetry\Cache\virtualenvs\key-infrastructure-FYt_TK8o-py3.8\lib\site-packages\spnego\_sspi.py", line 263, in step
    res = sspilib.raw.initialize_security_context(
  File "src\\sspilib\\raw\\_security_context.pyx", line 438, in sspilib.raw._security_context.initialize_security_context
OSError: [WinError -2146893042] No credentials are available in the security package

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\DemoUser\AppData\Local\pypoetry\Cache\virtualenvs\key-infrastructure-FYt_TK8o-py3.8\lib\site-packages\requests_kerberos\kerberos_.py", line 227, in generate_request_header
    gss_response = ctx.step(in_token=negotiate_resp_value)
  File "C:\Users\DemoUser\AppData\Local\pypoetry\Cache\virtualenvs\key-infrastructure-FYt_TK8o-py3.8\lib\site-packages\spnego\_context.py", line 71, in wrapper
    raise SpnegoError(base_error=native_err, context_msg=context) from native_err
spnego.exceptions.NoCredentialError: SpnegoError (7): [WinError -2146893042] No credentials are available in the security package, Context: Processing security token
2024-05-31 13:38:35,077 - requests_kerberos.kerberos_ - handle_401(): returning <Response [401]>
2024-05-31 13:38:35,077 - requests_kerberos.kerberos_ - handle_response(): returning <Response [401]>
2024-05-31 13:38:35,077 - requests_kerberos.kerberos_ - handle_response() has seen 1 401 responses
2024-05-31 13:38:35,077 - requests_kerberos.kerberos_ - handle_response(): returning 401 <Response [401]>
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\_workspace_\key_infrastructure\src\key_infrastructure\client.py", line 145, in fetch_private_key_certificate_pair_for_device
    with _oki_session(environment, role) as oki_session:
  File "C:\Python38\lib\contextlib.py", line 113, in __enter__
    return next(self.gen)
  File "C:\_workspace_\key_infrastructure\src\key_infrastructure\client.py", line 80, in _oki_session
    header = _fetch_fresh_oki_access_token_for_header(environment, role, authentication)
  File "C:\_workspace_\key_infrastructure\src\key_infrastructure\client.py", line 62, in _fetch_fresh_oki_access_token_for_header
    access_token = _unpack_requests_response(response)["accessToken"]
  File "C:\_workspace_\key_infrastructure\src\key_infrastructure\client.py", line 38, in _unpack_requests_response
    response.raise_for_status()
  File "C:\Users\DemoUser\AppData\Local\pypoetry\Cache\virtualenvs\key-infrastructure-FYt_TK8o-py3.8\lib\site-packages\requests\models.py", line 1021, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 401 Client Error: Unauthorized for url: https://key.infrastructure.at/api/v1/dev/token/roles/debug
>>>

I don't understand why this is not working. I assume that requests_kerberos is always using the credentials from Windows and the Kerberos ticket?

My implementation works if the machine is domain-joined and a Kerberos ticket is available
or if I use the wrong username and password on the domain-joined machine.

@jborean93
Copy link
Contributor

I’m not aware of this library, or any of its dependencies, ever supporting a username and password in the principal kwarg. The code just passes the principal as is to the underlying libraries and they in turn use that to lookup the username. We do have a separate kwarg specifically for a password which you should be using. As for the non-domain joined Wjndows host, I’ve only ever got that to work with Kerberos auth by adding a realm mapping so SSPI knows how to contact a KDC for the requested realm. I’ve seen claims it works if DNS SRV lookups can work but I have never been able to see that happening.

@behackett
Copy link

behackett commented May 31, 2024

WinKerberos, which requests-kerberos used to rely on, supports username and password, allowing you to authenticate as a user different from the Windows logon user.

@jborean93
Copy link
Contributor

In that case the password kwarg can do the same thing. It creates the SEC_WINNT_AUTH_IDENTITY structure to authenticate with custom credentials just like winkerberos.

@9y2070m
Copy link
Author

9y2070m commented Jun 3, 2024

In the current readme, and in the latest released version on pypi, no password argument is supported yet.

On Windows, WinKerberos is used instead of PyKerberos. WinKerberos allows the use of arbitrary principals instead of a credential cache. Passwords can be specified by following the form user@realm:password for principal.
https://github.com/requests/requests-kerberos/blob/master/README.rst?plain=1#L152-L154

For testing I installed requests-kerberos from master now and used the password kwarg.
It didn't work out, but when I additionally use the hostname_override argument at least I get
an authenticated user.
But the communication with the server still doesn't work out, as it still tells me I am unauthorized.

>>> client.fetch_private_key_certificate_pair_for_device(id="100001211", environment=definition.Environment.DEV)
INFO:key_infrastructure.client:Fetch private key and certificate for device with id='100001211' valid -12h:20240617103655 (environment=<Environment.DEV: 'dev'>).
INFO:key_infrastructure.client:Fetch a fresh key infrastructure access token (environment=<Environment.DEV: 'dev'>, role='debug').
DEBUG:key_infrastructure.client:GET url='https://key.infrastructure.at/api/v1/dev/token/roles/debug'
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): key.infrastructure.at:443
DEBUG:urllib3.connectionpool:https://key.infrastructure.at:443 "GET /api/v1/dev/token/roles/debug HTTP/1.1" 401 381
DEBUG:requests_kerberos.kerberos_:handle_401(): Handling: 401
DEBUG:spnego._sspi:SSPI step input:
DEBUG:spnego._sspi:SSPI step output: <..hidden..>
DEBUG:requests_kerberos.kerberos_:authenticate_user(): Authorization header: Negotiate <..hidden..>
DEBUG:urllib3.connectionpool:https://key.infrastructure.at:443 "GET /api/v1/dev/token/roles/debug HTTP/1.1" 401 381
DEBUG:requests_kerberos.kerberos_:authenticate_user(): returning <Response [401]>
DEBUG:requests_kerberos.kerberos_:handle_401(): returning <Response [401]>
DEBUG:requests_kerberos.kerberos_:handle_response(): returning <Response [401]>
DEBUG:requests_kerberos.kerberos_:handle_response() has seen 0 401 responses
DEBUG:requests_kerberos.kerberos_:handle_401(): Handling: 401
DEBUG:requests_kerberos.kerberos_:handle_401(): Kerberos is not supported
DEBUG:requests_kerberos.kerberos_:handle_401(): returning <Response [401]>
DEBUG:requests_kerberos.kerberos_:handle_response(): returning <Response [401]>
DEBUG:requests_kerberos.kerberos_:handle_response() has seen 1 401 responses
DEBUG:requests_kerberos.kerberos_:handle_response(): returning 401 <Response [401]>
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\_workspace_\key_infrastructure\src\key_infrastructure\client.py", line 147, in fetch_private_key_certificate_pair_for_device
    with _oki_session(environment, role) as oki_session:
  File "C:\Python38\lib\contextlib.py", line 113, in __enter__
    return next(self.gen)
  File "C:\_workspace_\key_infrastructure\src\key_infrastructure\client.py", line 82, in _oki_session
    header = _fetch_fresh_oki_access_token_for_header(environment, role, authentication)
  File "C:\_workspace_\key_infrastructure\src\key_infrastructure\client.py", line 64, in _fetch_fresh_oki_access_token_for_header
    access_token = _unpack_requests_response(response)["accessToken"]
  File "C:\_workspace_\key_infrastructure\src\key_infrastructure\client.py", line 40, in _unpack_requests_response
    response.raise_for_status()
  File "C:\Users\HW0Mes00Local\AppData\Local\pypoetry\Cache\virtualenvs\key-infrastructure-FYt_TK8o-py3.8\lib\site-packages\requests\models.py", line 1024, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 401 Client Error: Unauthorized for url: https://key.infrastructure.at/api/v1/dev/token/roles/debug
>>>

@jborean93
Copy link
Contributor

In the current readme, and in the latest released version on pypi, no password argument is supported yet.

Looks like it's due for a new release and for the readme to be updated. The username:password was the original approach in #182 but was updated to use a separate kwarg.

It didn't work out, but when I additionally use the hostname_override argument at least I get
an authenticated user.

The hostname_override kwarg should only be needed if you are connecting using an IP or a hostname that doesn't form a valid SPN. SPNs are critical for Kerberos as it's needed when requesting the service ticket from the KDC. If it doesn't exist or doesn't match up with the target service you are authenticating with then it will fail.

But the communication with the server still doesn't work out, as it still tells me I am unauthorized.

Unfortunately you'll have to look into the logs of the service there. If we build a ticket and send it to the proper server then you'll have to find out why it rejected the ticket.

@jborean93
Copy link
Contributor

#189 updates the README to fix up the incorrect password documentation.

@9y2070m
Copy link
Author

9y2070m commented Jun 6, 2024

Thanks a lot, I got everything to run! 👍 🥳

@9y2070m 9y2070m closed this as completed Jun 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants