def gssapi_login(self, user): # Try GSSAPI login first # Used FTP response codes: # 235 [ADAT=base64data] - indicates that the security data exchange # completed successfully. # 334 [ADAT=base64data] - indicates that the requested security # mechanism is ok, and includes security data to be used by the # client to construct the next command. # 335 [ADAT=base64data] - indicates that the security data is # acceptable, and more is required to complete the security # data exchange. resp = self.sendcmd('AUTH GSSAPI') if resp.startswith('334 '): rc, self.vc = kerberos.authGSSClientInit("ftp@%s" % self.host) if kerberos.authGSSClientStep(self.vc, "") != 1: while resp[:4] in ('334 ', '335 '): authdata = kerberos.authGSSClientResponse(self.vc) resp = self.sendcmd('ADAT ' + authdata) if resp[:9] in ('235 ADAT=', '335 ADAT='): rc = kerberos.authGSSClientStep(self.vc, resp[9:]) if not ((resp.startswith('235 ') and rc == 1) or (resp.startswith('335 ') and rc == 0)): raise ftplib.error_reply, resp note(gettext("Authenticated as %s") % kerberos.authGSSClientUserName(self.vc)) # Monkey patch ftplib self.putcmd = self.mic_putcmd self.getline = self.mic_getline self.sendcmd('USER ' + user) return resp mutter("Unable to use GSSAPI authentication: %s", resp)
def gssapi_login(self, user): # Try GSSAPI login first # Used FTP response codes: # 235 [ADAT=base64data] - indicates that the security data exchange # completed successfully. # 334 [ADAT=base64data] - indicates that the requested security # mechanism is ok, and includes security data to be used by the # client to construct the next command. # 335 [ADAT=base64data] - indicates that the security data is # acceptable, and more is required to complete the security # data exchange. resp = self.sendcmd('AUTH GSSAPI') if resp.startswith('334 '): rc, self.vc = kerberos.authGSSClientInit("ftp@%s" % self.host) if kerberos.authGSSClientStep(self.vc, "") != 1: while resp[:4] in ('334 ', '335 '): authdata = kerberos.authGSSClientResponse(self.vc) resp = self.sendcmd('ADAT ' + authdata) if resp[:9] in ('235 ADAT=', '335 ADAT='): rc = kerberos.authGSSClientStep(self.vc, resp[9:]) if not ((resp.startswith('235 ') and rc == 1) or (resp.startswith('335 ') and rc == 0)): raise ftplib.error_reply, resp note( gettext("Authenticated as %s") % kerberos.authGSSClientUserName(self.vc)) # Monkey patch ftplib self.putcmd = self.mic_putcmd self.getline = self.mic_getline self.sendcmd('USER ' + user) return resp mutter("Unable to use GSSAPI authentication: %s", resp)
def __init__(self, endpoint, auth=None, capath=True): logger.debug("Initializing service (endpoint: %s, auth: %s", endpoint, auth) self._endpoint = endpoint if auth == 'kerberos': # This step has been extended to work around issue #942 in the # kerberos library where the default principal cannot be # derived without raising an error. An explicit principal has # to be provided. # # This is ignored if PyKerberos is used. from urllib.parse import urlparse import kerberos if 'authGSSClientInquireCred' in dir(kerberos): parse = urlparse(endpoint) kerb_spn = "{0}@{1}".format("HTTP", parse.netloc) _, krb_context = kerberos.authGSSClientInit(kerb_spn) kerberos.authGSSClientInquireCred(krb_context) principal = kerberos.authGSSClientUserName(krb_context) # kerberos.authGSSClientClean(krb_context) auth = HTTPKerberosAuth(principal=principal) else: auth = HTTPKerberosAuth() self._auth = auth self._capath = capath
def __request_authenticate(self, method, url, body, extra_hdrs): self.__probe_mechanisms() try: result, gssctx = kerberos.authGSSClientInit(self.__spn, principal=self.__upn) except kerberos.GSSError as ex: raise Krb5Error('%s (%s)' % (ex[0][0], ex[1][0])) response = None blob = '' while True: try: result, blob = self.__challenge(gssctx, blob) except Krb5Error as ex: kerberos.authGSSClientClean(gssctx) raise ex if result: self.__upn = kerberos.authGSSClientUserName(gssctx) break self.close() extra_hdrs['Authorization'] = 'Negotiate %s' % (blob, ) response = davlib.DAV._request(self, method, url, body, extra_hdrs) self.__store_cookies(response) authstr = response.getheader('www-authenticate') (mech, blob) = authstr.split(' ') persistauth = response.getheader('persistent-auth') self.__persistauth = persistauth == 'true' kerberos.authGSSClientClean(gssctx) return 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).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 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 get_username(self, challenge): """ Get the user name of the principal authenticated via the now complete GSSAPI client-side operations. @param challenge: a string containing the base64-encoded server data @return: a string containing the user name. """ result_code = yield self._step(challenge) if result_code != kerberos.AUTH_GSS_COMPLETE: raise Exception('kerberos authGSSClientStep failed ({0}). ' 'challenge={1}'.format(result_code, challenge)) defer.returnValue(kerberos.authGSSClientUserName(self._context))
def get_current_principal(): try: import kerberos rc, vc = kerberos.authGSSClientInit("notempty") rc = kerberos.authGSSClientInquireCred(vc) username = kerberos.authGSSClientUserName(vc) kerberos.authGSSClientClean(vc) return unicode(username) except ImportError: raise RuntimeError('python-kerberos is not available.') except kerberos.GSSError, e: #TODO: do a kinit? raise errors.CCacheError()
def noImpersonationCalls(args): """ A non impersonated call using the kerberos package. """ import kerberos _ignore, ctx = kerberos.authGSSClientInit(args.servicename) h = getConn(args.host, args.port) callserver(h, args.path, ctx, kerberos.authGSSClientStep, kerberos.authGSSClientResponse) callserver(h, args.path, ctx, kerberos.authGSSClientStep, kerberos.authGSSClientResponse) print "username", kerberos.authGSSClientUserName(ctx) kerberos.authGSSClientClean(ctx) # clean up
def get_username(self, challenge): """ Get the user name of the principal authenticated via the now complete GSSAPI client-side operations. @param challenge: a string containing the base64-encoded server data @return: a string containing the user name. """ result_code = self._step(challenge) if result_code != kerberos.AUTH_GSS_COMPLETE: raise Exception('kerberos authGSSClientStep failed ({0}). ' 'challenge={1}' .format(result_code, challenge)) return kerberos.authGSSClientUserName(self._context)
def do_collect(self, conn_info, enum_infos): """ conn_info has the following attributes hostname auth_type: basic or kerberos username password scheme: http (https coming soon) port: int """ client = EnumerateClient(conn_info) items = {} for enum_info in enum_infos: try: items[enum_info] = yield client.enumerate( enum_info.wql, enum_info.resource_uri) except (UnauthorizedError, ForbiddenError): # Fail the collection for general errors. raise except RequestError: # Store empty results for other query-specific errors. continue try: assert(conn_info.username.lower() == authGSSClientUserName( client.session()._gssclient._context).lower()) except Exception: print 'ERROR: Expected and Actual usernames do not match for host'\ ' {}'.format(conn_info.hostname) print 'Expected username: {}, Actual username {}'.format( conn_info.username, authGSSClientUserName(client.session()._gssclient._context)) else: print 'Expected and Actual usernames match for host {}: {}'\ .format(conn_info.hostname, conn_info.username) defer.returnValue(None)
def do_collect(self, conn_info, enum_infos): """ conn_info has the following attributes hostname auth_type: basic or kerberos username password scheme: http (https coming soon) port: int """ client = EnumerateClient(conn_info) items = {} for enum_info in enum_infos: try: items[enum_info] = yield client.enumerate( enum_info.wql, enum_info.resource_uri) except (UnauthorizedError, ForbiddenError): # Fail the collection for general errors. raise except RequestError: # Store empty results for other query-specific errors. continue try: assert (conn_info.username.lower() == authGSSClientUserName( client._connection._gssclient._context).lower()) except Exception: print 'ERROR: Expected and Actual usernames do not match for host'\ ' {}'.format(conn_info.hostname) print 'Expected username: {}, Actual username {}'.format( conn_info.username, authGSSClientUserName(client._connection._gssclient._context)) else: print 'Expected and Actual usernames match for host {}: {}'\ .format(conn_info.hostname, conn_info.username) defer.returnValue(None)
def _set_username(self, **kwargs): if self._username is not None: return try: (ret, ctx) = kerberos.authGSSClientInit('*****@*****.**') assert (ret == kerberos.AUTH_GSS_COMPLETE) ret = kerberos.authGSSClientInquireCred(ctx) assert (ret == kerberos.AUTH_GSS_COMPLETE) # XXX What if you have >1 ticket? ret = kerberos.authGSSClientUserName(ctx) if '@' in ret: self._username = ret.split('@')[0] else: self._username = ret except AssertionError: raise ErrataException('Pigeon crap. Did it forget to run kinit?')
def _PassthroughLoginGSSAPI(self, host, sessionMgr, passthroughAuthPackage): """ Passthrough Authentication """ userSession = None try: import kerberos except ImportError as err: LogException(err) return userSession context = None service = "host@%s" % host try: result, context = kerberos.authGSSClientInit(service, 0) challenge = "" while True: # Call GSS step result = kerberos.authGSSClientStep(context, challenge) if result < 0: logging.error("authGSSClientStep failed for %s" % service) break secToken = kerberos.authGSSClientResponse(context) try: userSession = sessionMgr.LoginBySSPI(secToken) # No exception => logged in userName = kerberos.authGSSClientUserName(context) logging.info("Passthru authentication: Logged in %s as %s" % \ service, userName) del secToken break except vim.fault.SSPIChallenge as err: # Continue gssapi challenges challenge = err.base64Token del challenge except Exception as err: LogException(err) logging.error("Login failed for %s" % service) if context: try: kerberos.authGSSClientClean(context) except Exception as err: LogException(err) return userSession
def testGSSAPI(service): def statusText(r): if r == 1: return "Complete" elif r == 0: return "Continue" else: return "Error" rc, vc = kerberos.authGSSClientInit(service) print("Status for authGSSClientInit = %s" % statusText(rc)) if rc != 1: return rs, vs = kerberos.authGSSServerInit(service) print("Status for authGSSServerInit = %s" % statusText(rs)) if rs != 1: return rc = kerberos.authGSSClientStep(vc, "") print("Status for authGSSClientStep = %s" % statusText(rc)) if rc != 0: return rs = kerberos.authGSSServerStep(vs, kerberos.authGSSClientResponse(vc)) print("Status for authGSSServerStep = %s" % statusText(rs)) if rs == -1: return rc = kerberos.authGSSClientStep(vc, kerberos.authGSSServerResponse(vs)) print("Status for authGSSClientStep = %s" % statusText(rc)) if rc == -1: return print("Server user name: %s" % kerberos.authGSSServerUserName(vs)) print("Server target name: %s" % kerberos.authGSSServerTargetName(vs)) print("Client user name: %s" % kerberos.authGSSClientUserName(vc)) rc = kerberos.authGSSClientClean(vc) print("Status for authGSSClientClean = %s" % statusText(rc)) rs = kerberos.authGSSServerClean(vs) print("Status for authGSSServerClean = %s" % statusText(rs))
def testGSSAPI(service): def statusText(r): if r == 1: return "Complete" elif r == 0: return "Continue" else: return "Error" rc, vc = kerberos.authGSSClientInit(service); print "Status for authGSSClientInit = %s" % statusText(rc); if rc != 1: return rs, vs = kerberos.authGSSServerInit(service); print "Status for authGSSServerInit = %s" % statusText(rs); if rs != 1: return rc = kerberos.authGSSClientStep(vc, ""); print "Status for authGSSClientStep = %s" % statusText(rc); if rc != 0: return rs = kerberos.authGSSServerStep(vs, kerberos.authGSSClientResponse(vc)); print "Status for authGSSServerStep = %s" % statusText(rs); if rs == -1: return rc = kerberos.authGSSClientStep(vc, kerberos.authGSSServerResponse(vs)); print "Status for authGSSClientStep = %s" % statusText(rc); if rc == -1: return print "Server user name: %s" % kerberos.authGSSServerUserName(vs); print "Server target name: %s" % kerberos.authGSSServerTargetName(vs); print "Client user name: %s" % kerberos.authGSSClientUserName(vc); rc = kerberos.authGSSClientClean(vc); print "Status for authGSSClientClean = %s" % statusText(rc); rs = kerberos.authGSSServerClean(vs); print "Status for authGSSServerClean = %s" % statusText(rs);
def verify_response(self, auth_header): # Handle comma-separated lists of authentication fields for field in auth_header.split(','): kind, ignored_space, details = field.strip().partition(' ') if kind.lower() == 'negotiate': auth_details = details.strip() break else: raise ValueError('Negotiate not found in {0}'.format(auth_header)) # Finish the Kerberos handshake krb_context = self._krb_context if krb_context is None: raise RuntimeError('Ticket already used for verification') self._krb_context = None kerberos.authGSSClientStep(krb_context, auth_details) print( 'User {0} authenticated successfully using Kerberos authentication' .format(kerberos.authGSSClientUserName(krb_context))) kerberos.authGSSClientClean(krb_context)
def test_gssapi(): """ Return Code Values 0 = Continue 1 = Complete Other = Error """ service = "HTTP@%s" % hostname rc, vc = kerberos.authGSSClientInit(service) assert rc == 1, "authGSSClientInit = %d, expecting 1" % rc rs, vs = kerberos.authGSSServerInit(service) assert rs == 1, "authGSSServerInit = %d, expecting 1" % rs rc = kerberos.authGSSClientStep(vc, "") assert rc == 0, "authGSSClientStep = %d, expecting 0" % rc rs = kerberos.authGSSServerStep(vs, kerberos.authGSSClientResponse(vc)) assert rs != -1, "authGSSServerStep = %d, not expecting it to be -1" % rs rc = kerberos.authGSSClientStep(vc, kerberos.authGSSServerResponse(vs)) assert rc != -1, "authGSSClientStep = %d, not expecting it to be -1" % rc expected_username = "******" % (username, realm.upper()) server_user_name = kerberos.authGSSServerUserName(vs) assert server_user_name == expected_username, "Invalid server username returned" client_user_name = kerberos.authGSSClientUserName(vc) assert client_user_name == expected_username, "Invalid client username returned" server_target_name = kerberos.authGSSServerTargetName(vs) assert server_target_name is None, "Server target name is not None" rc = kerberos.authGSSClientClean(vc) assert rc == 1, "authGSSClientClean = %d, expecting it to be 0" % rc rs = kerberos.authGSSServerClean(vs) assert rs == 1, "authGSSServerClean = %d, expecting it to be 0" % rs
def finish(self, data): self.username = kerberos.authGSSClientUserName(self._gss) logger.debug("Authenticated as {0!r}".format( kerberos.authGSSClientUserName(self._gss))) return Success({"username": self.username, "authzid": self.authzid})
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)
def username(self): return kerberos.authGSSClientUserName(self.context)
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)
# set up headers url = "http://{k_hostname}:5985/wsman".format(k_hostname=k_hostname) k_headers = _ENCRYPTED_CONTENT_TYPE kerbkey = 'Kerberos {0}'.format(base64_client_data) i_headers = _CONTENT_TYPE i_headers['Authorization'] = kerbkey s.headers.update({'Accept-Encoding': '*'}) resp = s.request('POST', url, headers=i_headers) kind, challenge = resp.headers['www-authenticate'].strip().split(' ', 1) rc = kerberos.authGSSClientStep(context, challenge) if rc == kerberos.AUTH_GSS_COMPLETE: print("Authenticated {0}".format(kerberos.authGSSClientUserName(context))) # load request template and create payload path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'enumerate.xml') with open(path) as f: request_template = _XML_WHITESPACE_PATTERN.sub('><', f.read()).strip() payload = request_template.format(resource_uri=DEFAULT_RESOURCE_URI, wql=query) payload_xml = xml.dom.minidom.parseString(payload) pretty_xml_as_string = payload_xml.toprettyxml(indent=" ") print( "Enumeration payload before encryption:\n{0}".format(pretty_xml_as_string)) req = bytes(payload) orig_len = len(payload)
def _get_token_with_kerberos(self): """Authenticate with a Kerberos ticket.""" if kerberos is None: raise RuntimeError("Kerberos package not found. Run 'pip " "install sasctl[kerberos]' to install.") user = self._settings.get('username') # realm = user.rsplit('@', maxsplit=1)[-1] if '@' in user else None client_id = 'sas.tkmtrb' flags = kerberos.GSS_C_MUTUAL_FLAG | kerberos.GSS_C_SEQUENCE_FLAG service = 'HTTP@%s' % self._settings['domain'] logger.info('Attempting Kerberos authentication to %s as %s' % (service, user)) url = self._build_url( '/SASLogon/oauth/authorize?client_id=%s&response_type=token' % client_id) # Get Kerberos challenge r = self.get(url, allow_redirects=False, verify=self.verify) if r.status_code != 401: raise ValueError('Kerberos challenge response not received. ' 'Expected HTTP 401 but received %s' % r.status_code) if 'www-authenticate' not in r.headers: raise ValueError("Kerberos challenge response not received. " "'WWW-Authenticate' header not received.") if 'Negotiate' not in r.headers['www-authenticate']: raise ValueError("Kerberos challenge response not received. " "'WWW-Authenticate' header contained '%s', " "expected 'Negotiate'." % r.headers['www-authenticate']) # Initialize a request to KDC for a ticket to access the service. _, context = kerberos.authGSSClientInit(service, principal=user, gssflags=flags) # Send the request. # NOTE: empty-string parameter required for initial call. kerberos.authGSSClientStep(context, '') # Get the KDC response auth_header = 'Negotiate %s' % kerberos.authGSSClientResponse(context) # Get the user that was used for authentication username = kerberos.authGSSClientUserName(context) logger.info('Authenticated as %s' % username) # Drop @REALM from username and store if username is not None: self._settings['username'] = username.rsplit('@', maxsplit=1)[0] # Response to Kerberos challenge with ticket r = self.get(url, headers={'Authorization': auth_header}, allow_redirects=False, verify=self.verify) if 'Location' not in r.headers: raise ValueError("Invalid authentication response." "'Location' header not received.") match = re.search('(?<=access_token=)[^&]*', r.headers['Location']) if match is None: raise ValueError("Invalid authentication response. 'Location' " "header does not contain an access token.") return match.group(0)
def finish(self, data): self.username = kerberos.authGSSClientUserName(self._gss) self.__logger.debug("Authenticated as %s" % kerberos.authGSSClientUserName(self._gss)) return Success(self.username,None,self.authzid)
def finish(self, data): self.username = kerberos.authGSSClientUserName(self._gss) logger.debug("Authenticated as {0!r}".format( kerberos.authGSSClientUserName(self._gss))) return Success(self.username, None, self.authzid)
def verify_response(self, auth_header): # Handle comma-separated lists of authentication fields for field in auth_header.split(','): kind, ignored_space, details = field.strip().partition(' ') if kind.lower() == 'negotiate': auth_details = details.strip() break else: raise ValueError('Negotiate not found in {0}'.format(auth_header)) # Finish the Kerberos handshake krb_context = self._krb_context if krb_context is None: raise RuntimeError('Ticket already used for verification') self._krb_context = None kerberos.authGSSClientStep(krb_context, auth_details) print('User {0} authenticated successfully using Kerberos authentication'.format(kerberos.authGSSClientUserName(krb_context))) kerberos.authGSSClientClean(krb_context)
# set up headers url = "http://{k_hostname}:5985/wsman".format(k_hostname=k_hostname) k_headers = _ENCRYPTED_CONTENT_TYPE kerbkey = 'Kerberos {0}'.format(base64_client_data) i_headers = _CONTENT_TYPE i_headers['Authorization'] = kerbkey s.headers.update({'Accept-Encoding': '*'}) resp = s.request('POST', url, headers=i_headers) kind, challenge = resp.headers['www-authenticate'].strip().split(' ',1) rc = kerberos.authGSSClientStep(context,challenge) if rc == kerberos.AUTH_GSS_COMPLETE: print("Authenticated {0}".format(kerberos.authGSSClientUserName(context))) # load request template and create payload path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'enumerate.xml') with open(path) as f: request_template = _XML_WHITESPACE_PATTERN.sub('><', f.read()).strip() payload = request_template.format(resource_uri=DEFAULT_RESOURCE_URI,wql=query) payload_xml = xml.dom.minidom.parseString(payload) pretty_xml_as_string = payload_xml.toprettyxml(indent=" ") print("Enumeration payload before encryption:\n{0}".format(pretty_xml_as_string)) req = bytes(payload) orig_len = len(payload) ereq = base64.b64encode(payload) rc,pad_len = kerberos.authGSSClientWrapIov(context,ereq,1)