예제 #1
0
    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)
예제 #2
0
 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
예제 #3
0
 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
예제 #4
0
 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
예제 #5
0
 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')
예제 #6
0
    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)