@@ -803,16 +803,16 @@ def _try_authenticate_gssapi_gss_implementation(self, future):
803
803
804
804
def _try_authenticate_gssapi_sspi_implementation (self , future ):
805
805
global log_sspi
806
- log_sspi = logging .getLogger ("kafka.client .sspi" )
806
+ log_sspi = logging .getLogger ("kafka.conn .sspi" )
807
807
kerberos_host_name = self .config ['sasl_kerberos_domain_name' ] or self .host
808
808
service_principal_name = self .config ['sasl_kerberos_service_name' ] + '/' + kerberos_host_name
809
- scheme = "Kerberos" # Do not try with Negotiate that comes with a different protocol than SASL
809
+ scheme = "Kerberos" # Do not try with Negotiate for SASL authentication. Tokens are different.
810
810
# https://docs.microsoft.com/en-us/windows/win32/secauthn/context-requirements
811
811
flags = (
812
- sspicon .ISC_REQ_MUTUAL_AUTH | # mutual authentication
813
- sspicon .ISC_REQ_INTEGRITY | # check for integrity
814
- sspicon .ISC_REQ_SEQUENCE_DETECT | # enable out-of-order messages
815
- sspicon .ISC_REQ_CONFIDENTIALITY # request confidentiality
812
+ sspicon .ISC_REQ_MUTUAL_AUTH | # mutual authentication
813
+ sspicon .ISC_REQ_INTEGRITY | # check for integrity
814
+ sspicon .ISC_REQ_SEQUENCE_DETECT | # enable out-of-order messages
815
+ sspicon .ISC_REQ_CONFIDENTIALITY # request confidentiality
816
816
)
817
817
818
818
err = None
@@ -836,7 +836,7 @@ def _try_authenticate_gssapi_sspi_implementation(self, future):
836
836
log_sspi .info ("Using %s SSPI Security Package (%s)" , client_ctx .pkg_info ["Name" ], client_ctx .pkg_info ["Comment" ])
837
837
838
838
# Exchange tokens until authentication either succeeds or fails
839
- log_sspi .debug ("Begining rounds..." )
839
+ log_sspi .debug ("Beginning rounds..." )
840
840
received_token = None # no token to pass when initiating the first round
841
841
while not client_ctx .authenticated :
842
842
# calculate an output token from kafka token (or None on first iteration)
@@ -874,10 +874,15 @@ def _try_authenticate_gssapi_sspi_implementation(self, future):
874
874
received_token = self ._recv_bytes_blocking (token_size )
875
875
log_sspi .debug ("Received token from server (size %s)" , token_size )
876
876
877
+ # Add some extra attributes to the context
877
878
sspi_amend_ctx_metadata (client_ctx )
879
+
878
880
# Process the security layer negotiation token, sent by the server
879
881
# once the security context is established.
880
882
883
+ # The following part is required by SASL, but not by classic Kerberos.
884
+ # See RFC 4752
885
+
881
886
# unwraps message containing supported protection levels and msg size
882
887
msg = sspi_gss_unwrap_step (client_ctx , received_token )
883
888
@@ -1674,16 +1679,17 @@ def sspi_gss_unwrap_step(sec_ctx, token):
1674
1679
GSSAPI's unwrap with SSPI.
1675
1680
"""
1676
1681
buffer = win32security .PySecBufferDescType ()
1677
- # Stream is a token coming from the other side
1682
+ # This buffer contains a stream, which is a token coming from the other side
1678
1683
buffer .append (win32security .PySecBufferType (len (token ), sspicon .SECBUFFER_STREAM ))
1679
1684
buffer [0 ].Buffer = token
1680
- # Will receive the clear, or just unwrapped text if no encryption was used.
1685
+
1686
+ # This buffer will receive the clear, or just unwrapped text if no encryption was used.
1681
1687
# Will be resized.
1682
1688
buffer .append (win32security .PySecBufferType (0 , sspicon .SECBUFFER_DATA ))
1683
1689
1684
1690
pfQOP = sec_ctx .ctxt .DecryptMessage (buffer , sec_ctx ._get_next_seq_num ())
1685
1691
if pfQOP == sspicon .SECQOP_WRAP_NO_ENCRYPT :
1686
- log .debug ("Received token was not encrypted" )
1692
+ log_sspi .debug ("Received token was not encrypted" )
1687
1693
r = buffer [1 ].Buffer
1688
1694
return r
1689
1695
@@ -1699,12 +1705,14 @@ def sspi_gss_wrap_step(sec_ctx, msg, encrypt=False):
1699
1705
1700
1706
buffer = win32security .PySecBufferDescType ()
1701
1707
1708
+ # This buffer will contain unencrypted data to wrap, and maybe encrypt.
1702
1709
buffer .append (win32security .PySecBufferType (len (msg ), sspicon .SECBUFFER_DATA ))
1703
1710
buffer [0 ].Buffer = msg
1704
1711
1705
1712
# Will receive the token that forms the beginning of the msg
1706
1713
buffer .append (win32security .PySecBufferType (trailer_size , sspicon .SECBUFFER_TOKEN ))
1707
1714
1715
+ # The trailer is needed in case of block encryption
1708
1716
buffer .append (win32security .PySecBufferType (block_size , sspicon .SECBUFFER_PADDING ))
1709
1717
1710
1718
fQOP = 0 if encrypt else sspicon .SECQOP_WRAP_NO_ENCRYPT
@@ -1717,7 +1725,7 @@ def sspi_gss_wrap_step(sec_ctx, msg, encrypt=False):
1717
1725
def sspi_amend_ctx_metadata (sec_ctx ):
1718
1726
"""Adds initiator and service names in the security context for ease of use"""
1719
1727
if not sec_ctx .authenticated :
1720
- raise ValueError ("Sec context is not completly authenticated" )
1728
+ raise ValueError ("Sec context is not completely authenticated" )
1721
1729
1722
1730
names = sec_ctx .ctxt .QueryContextAttributes (sspicon .SECPKG_ATTR_NATIVE_NAMES )
1723
1731
sec_ctx .initiator_name , sec_ctx .service_name = names
0 commit comments