You're configuring the SecurityContext with usage "initiate", therefore its tokens are meant to be sent to a server (acceptor) – it makes no sense to give them to a spnego.client which is a second initiator and expects to be given a token received from a server.
Basically, initiator=client and acceptor=server. Two initiators cannot talk to each otherother; spnego.client will not convert a client token to a different type of client token.
Overall, it doesn't make sense to use both gssapi.SecurityContext and spnego.client (except in loopback tests) – either use one or the other.
The advantage of spnego.client is that it is cross-platform (automatically using SSPI on Windows or GSSAPI on Linux). But in your case, you are already hard-depending on the gssapi module, therefore it's more appropriate to directly use gssapi.SecurityContext for the final token too.
SPNEGO is not a native part of Kerberos; it is a Microsoft extension. So although SPNEGO may be the default for Microsoft SSPI, plain Kerberos is the default for standard GSSAPI.
The MIT Krb5 implementation of GSSAPI does support SPNEGO, but you have to explicitly request it like this:
spnego_oid = gssapi.Mechanism.from_sasl_name("SPNEGO") # -or- # spnego_oid = gssapi.Mechanism.from_int_seq("1.3.6.1.5.5.2") # -or- # spnego_oid = gssapi.OID.from_int_seq("1.3.6.1.5.5.2") ctx = gssapi.SecurityContext(..., mech=spnego_oid, ...)If you're using
requestsfor the actual HTTP request, I'd recommend using the requests_gssapi module to handle the final bits (it will automatically create a context and obtain a token for each HTTP request):spnego_oid = gssapi.Mechanism.from_sasl_name("SPNEGO") auth_handler = requests_gssapi.HTTPSPNEGOAuth(mech=spnego_oid, creds=impersonated_creds, opportunistic_auth=True) http_client = requests.Session(auth=auth_handler)Recent versions of requests_gssapi already default to requesting SPNEGO, though in older versions it was necessary to specify it manually.
The same recommendation goes for httpx_gssapi if you use httpx.
One additional note is that Kerberos principals should be treated as if they're case-sensitive (both the service name and the host name).
Active Directory domain controllers are case-insensitive and treat "HOST/foo" identically to "host/FOO" and so on, but that doesn't apply to other Kerberos implementations, so it would be best practice to use the standard spelling of service names.
HTTPis always upper-case, buthostshould be lower-case. (Of course, if your keytab contains "HOST/", then you might have no choice but to use "HOST/" yourself, but that would mean the keytab was generated incorrectly.)Most other "generic" Kerberos service names such as
imap,smtp,cifsare lower-case as well (HTTPbeing the exception, not the rule).Realm names are always upper-case (
REGION.INTRA.NETis correct).Domain names are usually lower-case (
'HTTP/sap3.' + realm.lower()is correct).