def __init__(self, pkg_name, spn=None, scflags=None, datarep=sspicon.SECURITY_NETWORK_DREP): self.spn = spn self.datarep = datarep if scflags is None: scflags = (sspicon.ASC_REQ_INTEGRITY | sspicon.ASC_REQ_SEQUENCE_DETECT | sspicon.ASC_REQ_REPLAY_DETECT | sspicon.ASC_REQ_CONFIDENTIALITY) # Should we default to sspicon.KerbAddExtraCredentialsMessage # if pkg_name=='Kerberos'? self.scflags = scflags self.pkg_info = win32security.QuerySecurityPackageInfo(pkg_name) ( self.credentials, self.credentials_expiry, ) = win32security.AcquireCredentialsHandle(spn, self.pkg_info["Name"], sspicon.SECPKG_CRED_INBOUND, None, None) _BaseAuth.__init__(self)
def __init__( self, pkg_name, # Name of the package to used. client_name=None, # User for whom credentials are used. auth_info=None, # or a tuple of (username, domain, password) targetspn=None, # Target security context provider name. scflags=None, # security context flags datarep=sspicon.SECURITY_NETWORK_DREP, ): if scflags is None: scflags = (sspicon.ISC_REQ_INTEGRITY | sspicon.ISC_REQ_SEQUENCE_DETECT | sspicon.ISC_REQ_REPLAY_DETECT | sspicon.ISC_REQ_CONFIDENTIALITY) self.scflags = scflags self.datarep = datarep self.targetspn = targetspn self.pkg_info = win32security.QuerySecurityPackageInfo(pkg_name) ( self.credentials, self.credentials_expiry, ) = win32security.AcquireCredentialsHandle( client_name, self.pkg_info["Name"], sspicon.SECPKG_CRED_OUTBOUND, None, auth_info, ) _BaseAuth.__init__(self)
def __init__( self, pkg_name, # Name of the package to used. client_name=None, # User for whom credentials are used. auth_info=None, # or a tuple of (username, domain, password) targetspn=None, # Target security context provider name. scflags=None, # security context flags datarep=sspicon.SECURITY_NETWORK_DREP): if scflags is None: scflags = sspicon.ISC_REQ_INTEGRITY | sspicon.ISC_REQ_SEQUENCE_DETECT | sspicon.ISC_REQ_REPLAY_DETECT | sspicon.ISC_REQ_CONFIDENTIALITY #|sspicon.SEC_WINNT_AUTH_IDENTITY_ANSI self.scflags = scflags self.datarep = datarep self.targetspn = targetspn username = win32api.GetUserName() domain = win32api.GetDomainName() password = None auth_info = username, domain, password self.pkg_info = win32security.QuerySecurityPackageInfo(pkg_name) self.credentials, \ self.credentials_expiry = win32security.AcquireCredentialsHandle( client_name, self.pkg_info['Name'], sspicon.SECPKG_CRED_OUTBOUND, None, auth_info) _BaseAuth.__init__(self)
def __init__(self, pkg_name): self.pkg_info = win32security.QuerySecurityPackageInfo(pkg_name) auth = PasswordAuthentication('workgroup', 'developer', 'password', compatibility=4) ntlm_context = NtlmContext(auth, session_security='none') self.context = ntlm_context.initialize_security_context() _BaseAuth.__init__(self)
def __init__(self, pkg_name, spn=None, flags=None, data_representation=sspicon.SECURITY_NETWORK_DREP): self.spn = spn self.datarep = data_representation if flags is None: flags = sspicon.ASC_REQ_REPLAY_DETECT | sspicon.ASC_REQ_SEQUENCE_DETECT # sspicon.ASC_REQ_INTEGRITY|sspicon.ASC_REQ_SEQUENCE_DETECT|\ #sspicon.ASC_REQ_REPLAY_DETECT|sspicon.ASC_REQ_CONFIDENTIALITY self.scflags = flags self.pkg_info = win32security.QuerySecurityPackageInfo(pkg_name) self.credentials, \ self.credentials_expiry=win32security.AcquireCredentialsHandle(spn, self.pkg_info['Name'], sspicon.SECPKG_CRED_INBOUND, None, None) _BaseAuth.__init__(self)
def _retry_using_http_Negotiate_auth(self, response, scheme, args): if 'Authorization' in response.request.headers: return response if self._host is None: targeturl = urlparse(response.request.url) self._host = targeturl.hostname try: self._host = socket.getaddrinfo(self._host, None, 0, 0, 0, socket.AI_CANONNAME)[0][3] except socket.gaierror as e: _logger.info( 'Skipping canonicalization of name %s due to error: %s', self._host, e) targetspn = '{}/{}'.format(self._service, self._host) # Set up SSPI connection structure pkg_info = win32security.QuerySecurityPackageInfo(scheme) clientauth = sspi.ClientAuth(scheme, targetspn=targetspn, auth_info=self._auth_info) sec_buffer = win32security.PySecBufferDescType() # Channel Binding Hash (aka Extended Protection for Authentication) # If this is a SSL connection, we need to hash the peer certificate, prepend the RFC5929 channel binding type, # and stuff it into a SEC_CHANNEL_BINDINGS structure. # This should be sent along in the initial handshake or Kerberos auth will fail. if hasattr(response, 'peercert') and response.peercert is not None: md = hashlib.sha256() md.update(response.peercert) appdata = 'tls-server-end-point:'.encode('ASCII') + md.digest() cbtbuf = win32security.PySecBufferType( pkg_info['MaxToken'], sspicon.SECBUFFER_CHANNEL_BINDINGS) cbtbuf.Buffer = struct.pack('LLLLLLLL{}s'.format(len(appdata)), 0, 0, 0, 0, 0, 0, len(appdata), 32, appdata) sec_buffer.append(cbtbuf) content_length = int(response.request.headers.get( 'Content-Length', '0'), base=10) if hasattr(response.request.body, 'seek'): if content_length > 0: response.request.body.seek(-content_length, 1) else: response.request.body.seek(0, 0) # Consume content and release the original connection # to allow our new request to reuse the same one. response.content response.raw.release_conn() request = response.request.copy() # this is important for some web applications that store # authentication-related info in cookies if response.headers.get('set-cookie'): request.headers['Cookie'] = response.headers.get('set-cookie') # Send initial challenge auth header try: error, auth = clientauth.authorize(sec_buffer) request.headers['Authorization'] = '{} {}'.format( scheme, base64.b64encode(auth[0].Buffer).decode('ASCII')) _logger.debug( 'Sending Initial Context Token - error={} authenticated={}'. format(error, clientauth.authenticated)) except pywintypes.error as e: _logger.error('Error calling {}: {}'.format(e[1], e[2]), exc_info=e) return response # A streaming response breaks authentication. # This can be fixed by not streaming this request, which is safe # because the returned response3 will still have stream=True set if # specified in args. In addition, we expect this request to give us a # challenge and not the real content, so the content will be short # anyway. args_nostream = dict(args, stream=False) response2 = response.connection.send(request, **args_nostream) # Should get another 401 if we are doing challenge-response (NTLM) if response2.status_code != 401: if response2.status_code == 200: # Kerberos may have succeeded; if so, finalize our auth context final = response2.headers.get('WWW-Authenticate') if final is not None: try: # Sometimes Windows seems to forget to prepend 'Negotiate' to the success response, # and we get just a bare chunk of base64 token. Not sure why. final = final.replace(scheme, '', 1).lstrip() tokenbuf = win32security.PySecBufferType( pkg_info['MaxToken'], sspicon.SECBUFFER_TOKEN) tokenbuf.Buffer = base64.b64decode(final) sec_buffer.append(tokenbuf) error, auth = clientauth.authorize(sec_buffer) _logger.debug( 'Kerberos Authentication succeeded - error={} authenticated={}' .format(error, clientauth.authenticated)) except TypeError: pass # Regardless of whether or not we finalized our auth context, # without a 401 we've got nothing to do. Update the history and return. response2.history.append(response) return response2 # Consume content and release the original connection # to allow our new request to reuse the same one. response2.content response2.raw.release_conn() request = response2.request.copy() # Keep passing the cookies along if response2.headers.get('set-cookie'): request.headers['Cookie'] = response2.headers.get('set-cookie') # Extract challenge message from server challenge = [ val[len(scheme) + 1:] for val in response2.headers.get( 'WWW-Authenticate', '').split(', ') if scheme in val ] if len(challenge) != 1: raise HTTPError( 'Did not get exactly one {} challenge from server.'.format( scheme)) # Add challenge to security buffer tokenbuf = win32security.PySecBufferType(pkg_info['MaxToken'], sspicon.SECBUFFER_TOKEN) tokenbuf.Buffer = base64.b64decode(challenge[0]) sec_buffer.append(tokenbuf) _logger.debug('Got Challenge Token (NTLM)') # Perform next authorization step error, auth = clientauth.authorize(sec_buffer) request.headers['Authorization'] = '{} {}'.format( scheme, base64.b64encode(auth[0].Buffer).decode('ASCII')) _logger.debug('Sending Response - error={} authenticated={}'.format( error, clientauth.authenticated)) response3 = response2.connection.send(request, **args) # Update the history and return response3.history.append(response) response3.history.append(response2) return response3
def retry_using_http_NTLM_auth(self, auth_header_field, auth_header, response, auth_type, args): """Attempt to authenticate using HTTP NTLM challenge/response.""" if auth_header in response.request.headers: return response content_length = int(response.request.headers.get( 'Content-Length', '0'), base=10) if hasattr(response.request.body, 'seek'): if content_length > 0: response.request.body.seek(-content_length, 1) else: response.request.body.seek(0, 0) # Consume content and release the original connection # to allow our new request to reuse the same one. response.content response.raw.release_conn() request = response.request.copy() # initial auth header with username. will result in challenge if self._use_default_credentials: pkg_info = win32security.QuerySecurityPackageInfo(_package) clientauth = sspi.ClientAuth(_package) sec_buffer = win32security.PySecBufferDescType() error, auth = clientauth.authorize(sec_buffer) request.headers[auth_header] = '{} {}'.format( _package, b64encode(auth[0].Buffer).decode('ascii')) else: msg = "%s\\%s" % (self.domain, self.username) if self.domain else self.username # ntlm returns the headers as a base64 encoded bytestring. Convert to # a string. auth = '%s %s' % (auth_type, ntlm.create_NTLM_NEGOTIATE_MESSAGE( msg).decode('ascii')) request.headers[auth_header] = auth # A streaming response breaks authentication. # This can be fixed by not streaming this request, which is safe # because the returned response3 will still have stream=True set if # specified in args. In addition, we expect this request to give us a # challenge and not the real content, so the content will be short # anyway. args_nostream = dict(args, stream=False) response2 = response.connection.send(request, **args_nostream) # needed to make NTLM auth compatible with requests-2.3.0 # Consume content and release the original connection # to allow our new request to reuse the same one. response2.content response2.raw.release_conn() request = response2.request.copy() # this is important for some web applications that store # authentication-related info in cookies (it took a long time to # figure out) if response2.headers.get('set-cookie'): request.headers['Cookie'] = response2.headers.get('set-cookie') # get the challenge auth_header_value = response2.headers[auth_header_field] auth_strip = auth_type + ' ' ntlm_header_value = next( s for s in (val.lstrip() for val in auth_header_value.split(',')) if s.startswith(auth_strip)).strip() challenge_value = ntlm_header_value[len(auth_strip):] # build response if self._use_default_credentials: # Add challenge to security buffer tokenbuf = win32security.PySecBufferType(pkg_info['MaxToken'], sspicon.SECBUFFER_TOKEN) tokenbuf.Buffer = b64decode(challenge_value) sec_buffer.append(tokenbuf) # Perform next authorization step error, auth = clientauth.authorize(sec_buffer) request.headers[auth_header] = '{} {}'.format( _package, b64encode(auth[0].Buffer).decode('ascii')) else: ServerChallenge, NegotiateFlags = ntlm.parse_NTLM_CHALLENGE_MESSAGE( challenge_value) # ntlm returns the headers as a base64 encoded bytestring. Convert to a # string. auth = '%s %s' % (auth_type, ntlm.create_NTLM_AUTHENTICATE_MESSAGE( ServerChallenge, self.username, self.domain, self.password, NegotiateFlags).decode('ascii')) request.headers[auth_header] = auth response3 = response2.connection.send(request, **args) # Update the history. response3.history.append(response) response3.history.append(response2) return response3