def process(self, challenge=b''): b64_challenge = b64encode(challenge) try: if self.step == 0: result = kerberos.authGSSClientStep( self.gss, b64_challenge) if result != kerberos.AUTH_GSS_CONTINUE: self.step = 1 elif not challenge: kerberos.authGSSClientClean(self.gss) return b'' elif self.step == 1: username = self.credentials['username'] kerberos.authGSSClientUnwrap(self.gss, b64_challenge) resp = kerberos.authGSSClientResponse(self.gss) kerberos.authGSSClientWrap(self.gss, resp, username) resp = kerberos.authGSSClientResponse(self.gss) except kerberos.GSSError as e: raise SASLCancelled('Kerberos error: %s' % e) if not resp: return b'' else: return b64decode(resp)
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 unwrap(self, incoming): if self.qop != QOP.AUTH: incoming = base64.b64encode(incoming).decode('ascii') kerberos.authGSSClientUnwrap(self.context, incoming) conf = kerberos.authGSSClientResponseConf(self.context) if 0 == conf and self.qop == QOP.AUTH_CONF: raise Exception("Error: confidentiality requested, but not honored by the server.") return base64.b64decode(kerberos.authGSSClientResponse(self.context)) else: return incoming
def unwrap(self, incoming): if self.qop != 'auth': incoming = base64.b64encode(incoming) kerberos.authGSSClientUnwrap(self.context, incoming) conf = kerberos.authGSSClientResponseConf(self.context) if 0 == conf and self.qop == 'auth-conf': raise StandardError("Error: confidentiality requested, but not honored by the server.") return base64.b64decode(kerberos.authGSSClientResponse(self.context)) else: return incoming
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 _kerberos_received(self, message): # Inspired by: https://github.com/thobbs/pure-sasl/blob/0.6.2/puresasl/mechanisms.py # https://github.com/thobbs/pure-sasl/blob/0.6.2/LICENSE try: import kerberos except ImportError: raise ImportError('Please install gremlinpython[kerberos].') # First pass: get service granting ticket and return it to gremlin-server if not self._kerberos_context: try: _, kerberos_context = kerberos.authGSSClientInit( self._kerberized_service, gssflags=kerberos.GSS_C_MUTUAL_FLAG) kerberos.authGSSClientStep(kerberos_context, '') auth = kerberos.authGSSClientResponse(kerberos_context) self._kerberos_context = kerberos_context except kerberos.KrbError as e: raise ConfigurationError( 'Kerberos authentication requires a valid service name in DriverRemoteConnection, ' 'as well as a valid tgt (export KRB5CCNAME) or keytab (export KRB5_KTNAME): ' + str(e)) return request.RequestMessage('', 'authentication', {'sasl': auth}) # Second pass: completion of authentication sasl_response = message['status']['attributes']['sasl'] if not self._username: result_code = kerberos.authGSSClientStep(self._kerberos_context, sasl_response) if result_code == kerberos.AUTH_GSS_COMPLETE: self._username = kerberos.authGSSClientUserName(self._kerberos_context) return request.RequestMessage('', 'authentication', {'sasl': ''}) # Third pass: sasl quality of protection (qop) handshake # Gremlin-server Krb5Authenticator only supports qop=QOP_AUTH; use ssl for confidentiality. # Handshake content format: # 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. kerberos.authGSSClientUnwrap(self._kerberos_context, sasl_response) data = kerberos.authGSSClientResponse(self._kerberos_context) plaintext_data = base64.b64decode(data) assert len(plaintext_data) == 4, "Unexpected response from gremlin server sasl handshake" word, = struct.unpack('!I', plaintext_data) qop_bits = word >> 24 assert self.QOP_AUTH_BIT & qop_bits, "Unexpected sasl qop level received from gremlin server" name_length = len(self._username) fmt = '!I' + str(name_length) + 's' word = self.QOP_AUTH_BIT << 24 | self.MAX_CONTENT_LENGTH out = struct.pack(fmt, word, self._username.encode("utf-8"),) encoded = base64.b64encode(out).decode('ascii') kerberos.authGSSClientWrap(self._kerberos_context, encoded) auth = kerberos.authGSSClientResponse(self._kerberos_context) return request.RequestMessage('', 'authentication', {'sasl': auth})
def unwrap(self, incoming): if self.qop != 'auth': incoming = base64.b64encode(incoming) kerberos.authGSSClientUnwrap(self.context, incoming) conf = kerberos.authGSSClientResponseConf(self.context) if 0 == conf and self.qop == 'auth-conf': raise StandardError( "Error: confidentiality requested, but not honored by the server." ) return base64.b64decode( kerberos.authGSSClientResponse(self.context)) else: return incoming
def mic_getline(self): resp = ftplib.FTP.getline(self) if resp[:4] != '631 ': raise AssertionError rc = kerberos.authGSSClientUnwrap(self.vc, resp[4:].strip("\r\n")) response = base64.b64decode(kerberos.authGSSClientResponse(self.vc)) return response
def __gssauth(self, response): data = base64.b64encode(response) try: if self.gss_step == self.GSS_STATE_STEP: if not self.gss_vc: rc, self.gss_vc = kerberos.authGSSClientInit( 'imap@' + self.hostname) response = kerberos.authGSSClientResponse(self.gss_vc) rc = kerberos.authGSSClientStep(self.gss_vc, data) if rc != kerberos.AUTH_GSS_CONTINUE: self.gss_step = self.GSS_STATE_WRAP elif self.gss_step == self.GSS_STATE_WRAP: rc = kerberos.authGSSClientUnwrap(self.gss_vc, data) response = kerberos.authGSSClientResponse(self.gss_vc) rc = kerberos.authGSSClientWrap( self.gss_vc, response, self.username) response = kerberos.authGSSClientResponse(self.gss_vc) except kerberos.GSSError as err: # Kerberos errored out on us, respond with None to cancel the # authentication self.ui.debug('imap', '%s: %s'% (err[0][0], err[1][0])) return None if not response: response = '' return base64.b64decode(response)
def __gssauth(self, response): data = base64.b64encode(response) try: if self.gss_step == self.GSS_STATE_STEP: if not self.gss_vc: rc, self.gss_vc = kerberos.authGSSClientInit('imap@' + self.hostname) response = kerberos.authGSSClientResponse(self.gss_vc) rc = kerberos.authGSSClientStep(self.gss_vc, data) if rc != kerberos.AUTH_GSS_CONTINUE: self.gss_step = self.GSS_STATE_WRAP elif self.gss_step == self.GSS_STATE_WRAP: rc = kerberos.authGSSClientUnwrap(self.gss_vc, data) response = kerberos.authGSSClientResponse(self.gss_vc) rc = kerberos.authGSSClientWrap(self.gss_vc, response, self.username) response = kerberos.authGSSClientResponse(self.gss_vc) except kerberos.GSSError as err: # Kerberos errored out on us, respond with None to cancel the # authentication self.ui.debug('imap', '%s: %s' % (err[0][0], err[1][0])) return None if not response: response = '' return base64.b64decode(response)
def process(self, challenge=b""): b64_challenge = b64encode(challenge) try: if self.step == 0: result = kerberos.authGSSClientStep(self.gss, b64_challenge) if result != kerberos.AUTH_GSS_CONTINUE: self.step = 1 elif self.step == 1: username = self.credentials["username"] kerberos.authGSSClientUnwrap(self.gss, b64_challenge) resp = kerberos.authGSSClientResponse(self.gss) kerberos.authGSSClientWrap(self.gss, resp, username) resp = kerberos.authGSSClientResponse(self.gss) except kerberos.GSSError as e: raise SASLCancelled("Kerberos error: %s" % e.message) if not resp: return b"" else: return b64decode(resp)
def challenge(self, challenge): if self.step == 0: rc = kerberos.authGSSClientStep(self._gss, base64.b64encode(challenge)) if rc != kerberos.AUTH_GSS_CONTINUE: self.step = 1 elif self.step == 1: rc = kerberos.authGSSClientUnwrap(self._gss, base64.b64encode(challenge)) response = kerberos.authGSSClientResponse(self._gss) rc = kerberos.authGSSClientWrap(self._gss, response, self.username) response = kerberos.authGSSClientResponse(self._gss) if response is None: return Response("") else: return Response(base64.b64decode(response))
def process(self, challenge=b''): b64_challenge = b64encode(challenge).decode('ascii') try: if self.step == 0: result = kerberos.authGSSClientStep(self.gss, b64_challenge) if result != kerberos.AUTH_GSS_CONTINUE: self.step = 1 elif not challenge: kerberos.authGSSClientClean(self.gss) return b'' elif self.step == 1: username = self.credentials['username'] kerberos.authGSSClientUnwrap(self.gss, b64_challenge) resp = kerberos.authGSSClientResponse(self.gss) kerberos.authGSSClientWrap(self.gss, resp, username.decode()) resp = kerberos.authGSSClientResponse(self.gss) except kerberos.GSSError as e: raise SASLCancelled('Kerberos error: %s' % e) if not resp: return b'' else: return b64decode(resp)
def challenge(self, challenge): if self.step == 0: ret = kerberos.authGSSClientStep(self._gss, base64.b64encode(challenge)) if ret != kerberos.AUTH_GSS_CONTINUE: self.step = 1 elif self.step == 1: ret = kerberos.authGSSClientUnwrap(self._gss, base64.b64encode(challenge)) response = kerberos.authGSSClientResponse(self._gss) ret = kerberos.authGSSClientWrap(self._gss, response, self.username) response = kerberos.authGSSClientResponse(self._gss) if response is None: return Response(b"") else: return Response(base64.b64decode(response))
def step (rcv): #DEBUG# print 'New Call with Complete:', self.complete #DEBUG# print 'Received:', '"' + b64encode (rcv) + '"' if not self.complete: # Initiate the GSSAPI Client #ALT# rc, self.ctx = kerberos.authGSSClientInit ('imap@' + hostname, gssflags=kerberos.GSS_C_SEQUENCE_FLAG) #STD# rc, self.ctx = kerberos.authGSSClientInit ('imap@' + hostname) if not self.ctx: rc, self.ctx = kerberos.authGSSClientInit ('imap@' + hostname) rc = kerberos.authGSSClientStep (self.ctx, b64encode (rcv)) #DEBUG# print 'ClientStep Result Code:', ['CONTINUE', 'COMPLETE'] [rc] if rc == kerberos.AUTH_GSS_COMPLETE: self.complete = True # if rc != 0: # print 'Error making a step' # return None snd = kerberos.authGSSClientResponse (self.ctx) return (b64decode (snd) if snd else "") else: # Unwrap and interpret the information token rc = kerberos.authGSSClientUnwrap (self.ctx, b64encode (rcv)) # if rc != 0: # print 'Error unwrapping' # return None token = b64decode (kerberos.authGSSClientResponse (self.ctx)) if len (token) != 4: #DEBUG# print 'Error unwrapping token after GSSAPI handshake' return None flags = ord (token [0]) #DEBUG# print 'Flags:', '0x%02x' % flags if flags & kerberos.GSS_C_INTEG_FLAG: pass #DEBUG# print 'Integrity Supported' if flags & kerberos.GSS_C_CONF_FLAG: pass #DEBUG# print 'Confidentialtiy Supported' maxlen = (ord (token [1]) << 16) | (ord (token [2]) << 8) | (ord (token [3])) #DEBUG# print 'Maxlen:', maxlen rettok = (chr (0) * 4) + 'ofo' return self.wrap (rettok)
def gssauth(self, response): if not HAVE_KERBEROS_GSS: # shouldn't get here raise ValueError('kerberos GSS support not available') data = ''.join(str(response).encode('base64').splitlines()) if self.gss_step == GSS_STATE_STEP: if not self.gss_vc: (rc, self.gss_vc) = kerberos.authGSSClientInit( 'imap@%s' % self.conf['server'] ) response = kerberos.authGSSClientResponse(self.gss_vc) rc = kerberos.authGSSClientStep(self.gss_vc, data) if rc != kerberos.AUTH_GSS_CONTINUE: self.gss_step = GSS_STATE_WRAP elif self.gss_step == GSS_STATE_WRAP: rc = kerberos.authGSSClientUnwrap(self.gss_vc, data) response = kerberos.authGSSClientResponse(self.gss_vc) rc = kerberos.authGSSClientWrap(self.gss_vc, response, self.conf['username']) response = kerberos.authGSSClientResponse(self.gss_vc) if not response: response = '' return response.decode('base64')
def SASLHandler(self, conn, challenge): ''' Perform next SASL auth step. Used internally. ''' if challenge.getNamespace() != NS_SASL: return if challenge.getName() == 'failure': self.startsasl = 'failure' try: reason = challenge.getChildren()[0] except Exception: reason = challenge self.DEBUG('Failed SASL authentification: %s' % reason, 'error') if self.on_sasl : self.on_sasl () raise NodeProcessed elif challenge.getName() == 'success': self.startsasl='success' self.DEBUG('Successfully authenticated with remote server.', 'ok') handlers=self._owner.Dispatcher.dumpHandlers() self._owner.Dispatcher.PlugOut() dispatcher_nb.Dispatcher().PlugIn(self._owner) self._owner.Dispatcher.restoreHandlers(handlers) self._owner.User = self.username if self.on_sasl : self.on_sasl () raise NodeProcessed ########################################3333 incoming_data = challenge.getData() data=base64.decodestring(incoming_data) self.DEBUG('Got challenge:'+data,'ok') if self.mechanism == "GSSAPI": if self.gss_step == GSS_STATE_STEP: rc = kerberos.authGSSClientStep(self.gss_vc, incoming_data) if rc != kerberos.AUTH_GSS_CONTINUE: self.gss_step = GSS_STATE_WRAP elif self.gss_step == GSS_STATE_WRAP: rc = kerberos.authGSSClientUnwrap(self.gss_vc, incoming_data) response = kerberos.authGSSClientResponse(self.gss_vc) rc = kerberos.authGSSClientWrap(self.gss_vc, response, self.username) response = kerberos.authGSSClientResponse(self.gss_vc) if not response: response = '' self._owner.send(Node('response', attrs={'xmlns':NS_SASL}, payload=response).__str__()) raise NodeProcessed chal = challenge_splitter(data) if not self.realm and 'realm' in chal: self.realm = chal['realm'] if 'qop' in chal and ((isinstance(chal['qop'], str) and \ chal['qop'] =='auth') or (isinstance(chal['qop'], list) and 'auth' in \ chal['qop'])): resp={} resp['username'] = self.username if self.realm: resp['realm'] = self.realm else: resp['realm'] = self._owner.Server resp['nonce']=chal['nonce'] cnonce='' for i in range(7): cnonce += hex(int(random.random() * 65536 * 4096))[2:] resp['cnonce'] = cnonce resp['nc'] = ('00000001') resp['qop'] = 'auth' resp['digest-uri'] = 'xmpp/'+self._owner.Server A1=C([H(C([resp['username'], resp['realm'], self.password])), resp['nonce'], resp['cnonce']]) A2=C(['AUTHENTICATE',resp['digest-uri']]) response= HH(C([HH(A1), resp['nonce'], resp['nc'], resp['cnonce'], resp['qop'], HH(A2)])) resp['response'] = response resp['charset'] = 'utf-8' sasl_data='' for key in ('charset', 'username', 'realm', 'nonce', 'nc', 'cnonce', 'digest-uri', 'response', 'qop'): if key in ['nc','qop','response','charset']: sasl_data += "%s=%s," % (key,resp[key]) else: sasl_data += '%s="%s",' % (key,resp[key]) ########################################3333 node=Node('response', attrs={'xmlns':NS_SASL}, payload=[base64.encodestring(sasl_data[:-1]).replace('\r','').replace('\n','')]) self._owner.send(node.__str__()) elif 'rspauth' in chal: self._owner.send(Node('response', attrs={'xmlns':NS_SASL}).__str__()) else: self.startsasl='failure' self.DEBUG('Failed SASL authentification: unknown challenge', 'error') if self.on_sasl : self.on_sasl () raise NodeProcessed
def callback(self,response): '''Callback for use with imaplib.authenticate(mech,callback) Will be repeatedly called with data from server, and its return data passed back to server. ''' response = "".join(str(response).encode('base64').splitlines()) ## print "Entering callback with response={}".format(response) ctx = self.context if ctx is None: raise Exception("GSS context is None.") # GSSAPI SASL: two states # First negotiate GSS security context # Then negotiate security protection layer if (self.state == STATE_ONE): # Negotiating security context rc = kerberos.authGSSClientStep(ctx, response) if (rc != AUTH_GSS_CONTINUE and rc != AUTH_GSS_COMPLETE): raise Exception("Bad GSSAPI return code: {}".format(rc)) elif (rc == AUTH_GSS_COMPLETE): # -> State transition self.state = STATE_TWO payload = kerberos.authGSSClientResponse(ctx) elif (self.state == STATE_TWO): # Negotiating protection layer rc = kerberos.authGSSClientUnwrap(ctx, response) if (rc != AUTH_GSS_CONTINUE and rc != AUTH_GSS_COMPLETE): raise Exception("Bad GSSAPI return code: {}".format(rc)) data = kerberos.authGSSClientResponse(ctx) # At this point, the protocol says we should unwrap a # security mask from the leading bytes of the decoded # data. However we can't, because the C code in # kerberosgss.c forces GSS_AUTH_P_NONE and also does # not allow setting conf_flag in the wrap. ### Stuff we should do, but can't ### # bytestring = base64.b64decode(data) # bytes = struct.unpack('4B', bytestring) # bufsiz = ((bytes[1] << 8) + bytes[2] << 8) + bytes[3] # security_mask = bytes[0] # for layer in 4,2,1: # then choose a desired_security layer from security_mask # bytestring = struct.pack('4B', desired_security, *bytes[1:]) # then wrap with conf_flag suitable for the desired_security ### End stuff ### # So instead of unwrapping a security mask, we just # assert that we use GSS_AUTH_P_NONE ('\x01') bytestring = base64.b64decode(data) newdata = '\x01' + bytestring[1:] newdata = str(newdata).encode('base64') rc = kerberos.authGSSClientWrap(ctx, newdata, self.username) if (rc != AUTH_GSS_CONTINUE and rc != AUTH_GSS_COMPLETE): raise Exception("Bad GSSAPI return code: {}".format(rc)) payload = kerberos.authGSSClientResponse(ctx) else: raise Exception("Unexpected state: {}".format(self.state)) if payload is None: payload = '' ## print "Leaving callback with payload={}".format(payload) payload = str(payload).decode('base64') return payload
def _authenticate_gssapi(credentials, sock_info, cmd_func): """Authenticate using GSSAPI. """ try: dummy, username, gsn = credentials # Starting here and continuing through the while loop below - establish # the security context. See RFC 4752, Section 3.1, first paragraph. result, ctx = kerberos.authGSSClientInit( gsn + '@' + sock_info.host, gssflags=kerberos.GSS_C_MUTUAL_FLAG) if result != kerberos.AUTH_GSS_COMPLETE: raise OperationFailure('Kerberos context failed to initialize.') try: # pykerberos uses a weird mix of exceptions and return values # to indicate errors. # 0 == continue, 1 == complete, -1 == error # Only authGSSClientStep can return 0. if kerberos.authGSSClientStep(ctx, '') != 0: raise OperationFailure('Unknown kerberos ' 'failure in step function.') # Start a SASL conversation with mongod/s # Note: pykerberos deals with base64 encoded byte strings. # Since mongo accepts base64 strings as the payload we don't # have to use bson.binary.Binary. payload = kerberos.authGSSClientResponse(ctx) cmd = SON([('saslStart', 1), ('mechanism', 'GSSAPI'), ('payload', payload), ('autoAuthorize', 1)]) response, _ = cmd_func(sock_info, '$external', cmd) # Limit how many times we loop to catch protocol / library issues for _ in xrange(10): result = kerberos.authGSSClientStep(ctx, str(response['payload'])) if result == -1: raise OperationFailure('Unknown kerberos ' 'failure in step function.') payload = kerberos.authGSSClientResponse(ctx) or '' cmd = SON([('saslContinue', 1), ('conversationId', response['conversationId']), ('payload', payload)]) response, _ = cmd_func(sock_info, '$external', cmd) if result == kerberos.AUTH_GSS_COMPLETE: break else: raise OperationFailure('Kerberos ' 'authentication failed to complete.') # Once the security context is established actually authenticate. # See RFC 4752, Section 3.1, last two paragraphs. if kerberos.authGSSClientUnwrap(ctx, str(response['payload'])) != 1: raise OperationFailure('Unknown kerberos ' 'failure during GSS_Unwrap step.') if kerberos.authGSSClientWrap(ctx, kerberos.authGSSClientResponse(ctx), username) != 1: raise OperationFailure('Unknown kerberos ' 'failure during GSS_Wrap step.') payload = kerberos.authGSSClientResponse(ctx) cmd = SON([('saslContinue', 1), ('conversationId', response['conversationId']), ('payload', payload)]) response, _ = cmd_func(sock_info, '$external', cmd) finally: kerberos.authGSSClientClean(ctx) except kerberos.KrbError, exc: raise OperationFailure(str(exc))
def unwrap (self, ciphertext): """Once a GSSAPI Context is complete, it can unwrap ciphertext into plaintext. This function operates on binary strings. """ kerberos.authGSSClientUnwrap (self.ctx, b64encode (ciphertext)) return b64decode (kerberos.authGSSClientResponse (self.ctx))
def _authenticate_gssapi(credentials, sock_info, cmd_func): """Authenticate using GSSAPI. """ try: dummy, username, gsn = credentials # Starting here and continuing through the while loop below - establish # the security context. See RFC 4752, Section 3.1, first paragraph. result, ctx = kerberos.authGSSClientInit( gsn + '@' + sock_info.host, gssflags=kerberos.GSS_C_MUTUAL_FLAG) if result != kerberos.AUTH_GSS_COMPLETE: raise OperationFailure('Kerberos context failed to initialize.') try: # pykerberos uses a weird mix of exceptions and return values # to indicate errors. # 0 == continue, 1 == complete, -1 == error # Only authGSSClientStep can return 0. if kerberos.authGSSClientStep(ctx, '') != 0: raise OperationFailure('Unknown kerberos ' 'failure in step function.') # Start a SASL conversation with mongod/s # Note: pykerberos deals with base64 encoded byte strings. # Since mongo accepts base64 strings as the payload we don't # have to use bson.binary.Binary. payload = kerberos.authGSSClientResponse(ctx) cmd = SON([('saslStart', 1), ('mechanism', 'GSSAPI'), ('payload', payload), ('autoAuthorize', 1)]) response, _ = cmd_func(sock_info, '$external', cmd) # Limit how many times we loop to catch protocol / library issues for _ in xrange(10): result = kerberos.authGSSClientStep(ctx, str(response['payload'])) if result == -1: raise OperationFailure('Unknown kerberos ' 'failure in step function.') payload = kerberos.authGSSClientResponse(ctx) or '' cmd = SON([('saslContinue', 1), ('conversationId', response['conversationId']), ('payload', payload)]) response, _ = cmd_func(sock_info, '$external', cmd) if result == kerberos.AUTH_GSS_COMPLETE: break else: raise OperationFailure('Kerberos ' 'authentication failed to complete.') # Once the security context is established actually authenticate. # See RFC 4752, Section 3.1, last two paragraphs. if kerberos.authGSSClientUnwrap(ctx, str( response['payload'])) != 1: raise OperationFailure('Unknown kerberos ' 'failure during GSS_Unwrap step.') if kerberos.authGSSClientWrap( ctx, kerberos.authGSSClientResponse(ctx), username) != 1: raise OperationFailure('Unknown kerberos ' 'failure during GSS_Wrap step.') payload = kerberos.authGSSClientResponse(ctx) cmd = SON([('saslContinue', 1), ('conversationId', response['conversationId']), ('payload', payload)]) response, _ = cmd_func(sock_info, '$external', cmd) finally: kerberos.authGSSClientClean(ctx) except kerberos.KrbError, exc: raise OperationFailure(str(exc))
def sasl_gssapi(connection, controls): """ Performs a bind using the Kerberos v5 ("GSSAPI") SASL mechanism from RFC 4752. Does not support any security layers, only authentication! sasl_credentials can be empty or a 1-element tuple with the requested target_name or the True value to request the target_name from DNS """ if connection.sasl_credentials and len(connection.sasl_credentials) == 1 \ and connection.sasl_credentials[0]: if connection.sasl_credentials[0] is True: hostname = \ socket.gethostbyaddr(connection.socket.getpeername()[0])[0] target_name = 'ldap@' + hostname else: target_name = connection.sasl_credentials[0] else: target_name = 'ldap@' + connection.server.host gssflags = (kerberos.GSS_C_MUTUAL_FLAG | kerberos.GSS_C_SEQUENCE_FLAG | kerberos.GSS_C_INTEG_FLAG | kerberos.GSS_C_CONF_FLAG) _, ctx = kerberos.authGSSClientInit(target_name, gssflags=gssflags) try: in_token = b'' while True: status = kerberos.authGSSClientStep( ctx, base64.b64encode(in_token).decode('ascii')) out_token = kerberos.authGSSClientResponse(ctx) or '' result = send_sasl_negotiation(connection, controls, base64.b64decode(out_token)) in_token = result['saslCreds'] or b'' if status == kerberos.AUTH_GSS_COMPLETE: break kerberos.authGSSClientUnwrap( ctx, base64.b64encode(in_token).decode('ascii')) unwrapped_token = base64.b64decode( kerberos.authGSSClientResponse(ctx) or '') if len(unwrapped_token) != 4: raise LDAPCommunicationError("Incorrect response from server") server_security_layers = unwrapped_token[0] if not isinstance(server_security_layers, int): server_security_layers = ord(server_security_layers) if not server_security_layers & NO_SECURITY_LAYER: raise LDAPCommunicationError( "Server requires a security layer, but this is not implemented" ) client_security_layers = bytearray([NO_SECURITY_LAYER, 0, 0, 0]) kerberos.authGSSClientWrap( ctx, base64.b64encode(client_security_layers).decode('ascii')) out_token = kerberos.authGSSClientResponse(ctx) or '' return send_sasl_negotiation(connection, controls, base64.b64decode(out_token)) except (kerberos.GSSError, LDAPCommunicationError): abort_sasl_negotiation(connection, controls) raise
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 ret = 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) ret = kerberos.authGSSClientWrap(self.context, data) response = kerberos.authGSSClientResponse(self.context) self.complete = True return base64.b64decode(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)