GSSAPI Authentication Handler for Requests
requests-gssapi is an HTTP library that extends `python-requests` to provide optional GSSAPI authentication support, including mutual authentication. It acts as a fully backward-compatible shim for the older `requests-kerberos` library, allowing for a seamless transition. The current version is 1.4.0 and requires Python >=3.8. It is actively maintained with releases occurring as needed.
Common errors
-
No Kerberos credentials available (Mechanism: 'krb5_gss_mech')
cause The Python environment or the user running the script does not have an active Kerberos Ticket-Granting Ticket (TGT) in a credential cache.fixRun `kinit` in your shell to obtain a TGT before executing the Python script. Verify with `klist`. -
Cannot authenticate with requests-gssapi on SPNEGO server, wrong OID selected (KRB5 instead of SPNEGO).
cause The GSSAPI negotiation mechanism defaults to Kerberos 5 (KRB5) when the server expects SPNEGO (Simple Protected Negotiation).fixExplicitly specify the SPNEGO mechanism: ```python import gssapi from requests_gssapi import HTTPSPNEGOAuth try: spnego_mech = gssapi.mechs.Mechanism.from_sasl_name("GS2-SPNEGO") except AttributeError: # Fallback for older gssapi versions or specific environments spnego_mech = gssapi.OID.from_int_seq("1.3.6.1.5.5.2") auth = HTTPSPNEGOAuth(mech=spnego_mech) response = requests.get("http://your-spnego-server.com", auth=auth) ``` -
requests.exceptions.ConnectionError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response')) OR MutualAuthenticationErrorcause The server closed the connection prematurely, often related to mutual authentication issues where the server does not correctly handle the multiple round-trip authentication handshake, or `requests-gssapi` was configured to require mutual authentication which the server failed to provide.fixIf mutual authentication is not strictly required for your security model, disable it: `auth=HTTPSPNEGOAuth(mutual_authentication=requests_gssapi.DISABLED)`. Ensure your server is correctly configured for GSSAPI/SPNEGO without requiring additional mutual authentication rounds if that's the desired behavior.
Warnings
- gotcha Mutual Authentication can cause handshake failures with some servers. While historically defaulted to REQUIRED in `requests-kerberos`, `requests-gssapi` has evolved to handle it more flexibly (often `OPTIONAL` or implicitly not required). If you encounter `MutualAuthenticationError`, the server might not be prepared for the extra round-trip, or `REQUIRED` was inadvertently set.
- breaking Sharing `HTTPSPNEGOAuth` objects across multiple threads can lead to concurrency issues and authentication failures. The library caches `gssapi.SecurityContext` objects per hostname, which can be overwritten by concurrent requests to the same host.
- gotcha Requests with a body (e.g., POST requests) might fail with a 401 Unauthorized on the initial attempt due to `httplib` not supporting the `Expect-Continue` header. This can lead to additional overhead for request retransmission and failure for non-repeatable bodies.
- gotcha Using channel bindings (e.g., `tls-server-end-point`) requires the `cryptography` Python package to be installed, as `requests-gssapi` attempts to import its `x509` module to process peer certificates.
Install
-
pip install requests-gssapi -
conda install requests-gssapi -c conda-forge
Imports
- HTTPSPNEGOAuth
from requests_gssapi import HTTPSPNEGOAuth
- HTTPKerberosAuth
from requests_kerberos import HTTPKerberosAuth
from requests_gssapi import HTTPKerberosAuth
Quickstart
import requests
from requests_gssapi import HTTPSPNEGOAuth
# Ensure a Kerberos TGT is available (e.g., by running 'kinit' in your shell)
# For example purposes, hitting a generic domain, replace with your GSSAPI-enabled service
try:
response = requests.get("http://example.org/protected", auth=HTTPSPNEGOAuth())
response.raise_for_status()
print(f"Success: {response.status_code}")
print(response.text)
except requests.exceptions.RequestException as e:
print(f"An error occurred: {e}")
# Example with opportunistic authentication and target name override
# response_opportunistic = requests.get(
# "https://your-service.example.com/api",
# auth=HTTPSPNEGOAuth(opportunistic_auth=True, target_name="service-principal@REALM")
# )
# print(response_opportunistic.status_code)