def process(self, challenge=None): if not self._have_negotiated_details: kerberos.authGSSClientStep(self.context, '') _negotiated_details = kerberos.authGSSClientResponse(self.context) self._have_negotiated_details = True return base64.b64decode(_negotiated_details) challenge = base64.b64encode(challenge).decode( 'ascii') # kerberos methods expect strings, not bytes if self.user is None: ret = kerberos.authGSSClientStep(self.context, challenge) if ret == kerberos.AUTH_GSS_COMPLETE: self.user = kerberos.authGSSClientUserName(self.context) return b'' else: response = kerberos.authGSSClientResponse(self.context) if response: response = base64.b64decode(response) else: response = b'' return response kerberos.authGSSClientUnwrap(self.context, challenge) data = kerberos.authGSSClientResponse(self.context) plaintext_data = base64.b64decode(data) if len(plaintext_data) != 4: raise SASLProtocolException( "Bad response from server") # todo: better message word, = struct.unpack('!I', plaintext_data) qop_bits = word >> 24 max_length = word & 0xffffff server_offered_qops = QOP.names_from_bitmask(qop_bits) self._pick_qop(server_offered_qops) self.max_buffer = min(self.sasl.max_buffer, max_length) """ byte 0: the selected qop. 1==auth, 2==auth-int, 4==auth-conf byte 1-3: the max length for any buffer sent back and forth on this connection. (big endian) the rest of the buffer: the authorization user name in UTF-8 - not null terminated. """ auth_id = self.sasl.authorization_id or self.user l = len(auth_id) fmt = '!I' + str(l) + 's' word = QOP.flag_from_name(self.qop) << 24 | self.max_buffer out = struct.pack( fmt, word, _b(auth_id), ) encoded = base64.b64encode(out).decode('ascii') kerberos.authGSSClientWrap(self.context, encoded) response = kerberos.authGSSClientResponse(self.context) self.complete = True return base64.b64decode(response)
def _pick_qop(self, server_offered_qops): """ Choose a quality of protection based on the user's requirements and what the server supports. """ available_qops = set(self.sasl.qops) & set(server_offered_qops) if not available_qops: raise SASLProtocolException( "Your requested quality of " "protection is one of (%s), but the server is only " "offering (%s)" % (', '.join(self.sasl.qops), ', '.join(server_offered_qops))) else: self.qops = available_qops for qop in ('auth-conf', 'auth-int', 'auth'): if qop in self.qops: self.qop = qop break
def _pick_qop(self, server_qop_set): """ Choose a quality of protection based on the user's requirements, what the server supports, and what the mechanism supports. """ user_qops = set(_b(qop) if isinstance(qop, str) else qop for qop in self.sasl.qops) # normalize user-defined config supported_qops = set(self.qops) available_qops = user_qops & supported_qops & server_qop_set if not available_qops: user = b', '.join(user_qops).decode('ascii') supported = b', '.join(supported_qops).decode('ascii') offered = b', '.join(server_qop_set).decode('ascii') raise SASLProtocolException("Your requested quality of " "protection is one of (%s), the server is " "offering (%s), and %s supports (%s)" % (user, offered, self.name, supported)) else: for qop in (QOP.AUTH_CONF, QOP.AUTH_INT, QOP.AUTH): if qop in available_qops: self.qop = qop break
def _pick_qop(self, server_qop_set): """ Choose a quality of protection based on the user's requirements and what the server supports. """ configured_qops = set( _b(qop) if isinstance(qop, str) else qop for qop in self.sasl.qops) # normalize user-defined config available_qops = configured_qops & server_qop_set if not available_qops: configured = b', '.join(configured_qops).decode('ascii') offered = b', '.join(server_qop_set).decode('ascii') raise SASLProtocolException( "Your requested quality of " "protection is one of (%s), but the server is only " "offering (%s)" % (configured, offered)) else: self.qops = available_qops for qop in (QOP.AUTH_CONF, QOP.AUTH_INT, QOP.AUTH): if qop in self.qops: self.qop = qop break
def authenticate_server(self, cmp_hash): a2 = b':' + self._digest_uri if self.qop != QOP.AUTH: a2 += b':00000000000000000000000000000000' if self.gen_hash(a2) != cmp_hash: raise SASLProtocolException('Invalid server auth response')
def process(self, challenge=None): if not self._have_negotiated_details: kerberos.authGSSClientStep(self.context, '') _negotiated_details = kerberos.authGSSClientResponse(self.context) self._have_negotiated_details = True return base64.b64decode(_negotiated_details) challenge = base64.b64encode(challenge) if self.user is None: ret = kerberos.authGSSClientStep(self.context, challenge) if ret == kerberos.AUTH_GSS_COMPLETE: self.user = kerberos.authGSSClientUserName(self.context) return '' else: response = kerberos.authGSSClientResponse(self.context) if response: response = base64.b64decode(response) else: response = '' return response kerberos.authGSSClientUnwrap(self.context, challenge) data = kerberos.authGSSClientResponse(self.context) plaintext_data = base64.b64decode(data) if len(plaintext_data) != 4: raise SASLProtocolException( "Bad response from server") # todo: better message layers_supported, = struct.unpack('B', plaintext_data[0]) server_offered_qops = [] if 0x01 & layers_supported: server_offered_qops.append('auth') if 0x02 & layers_supported: server_offered_qops.append('auth-int') if 0x04 & layers_supported: server_offered_qops.append('auth-conf') self._pick_qop(server_offered_qops) max_length, = struct.unpack('!i', '\x00' + plaintext_data[1:]) self.max_buffer = min(self.sasl.max_buffer, max_length) """ Construct the reply. byte 0: the selected qop. 1==auth, 2==auth-int, 4==auth-conf byte 1-3: the max length for any buffer sent back and forth on this connection. (big endian) the rest of the buffer: the authorization user name in UTF-8 - not null terminated. So, we write the max length and authorization user name first, then overwrite the first byte of the buffer with the qop. This is ok since the max length is writen out in big endian. """ i = len(self.user) fmt = '!I' + str(i) + 's' outdata = create_string_buffer(4 + i) struct.pack_into(fmt, outdata, 0, self.max_buffer, self.user) qop = 1 if self.qop == 'auth-int': qop = 2 elif self.qop == 'auth-conf': qop = 4 struct.pack_into('!B', outdata, 0, qop) encodeddata = base64.b64encode(outdata) kerberos.authGSSClientWrap(self.context, encodeddata) response = kerberos.authGSSClientResponse(self.context) self.complete = True return base64.b64decode(response)