Open franklighter opened 7 years ago
I'm not really familiar with how this would work for proxy auth. From some brief research, I believe we'd need to work with the Proxy-Authorization
and Proxy-Authenticate
headers, but I don't have any infrastructure available to test this with. It could be as simple as just providing a method to use the proxy auth headers instead of the standard auth headers, or it could be completely different. The channel-binding stuff in might require special handling as well.
Do you have a particular proxy you're trying to use this with? Is there an easy way to set up a test environment?
am having trouble finding the dependent sspi module... is it supported in 2.7?
@cameronwallace the sspi
module comes from pywin32
/pypiwin32
; this module (currently) only works on Windows as SSPI is a Windows-specific API . There are other modules that support generic Kerberos implementations (see requests-kerberos
, for example).
I'm also interested in NTLM proxy authentication. It is not much different than accessing a NTLM protected web-page. To test it, you can set up a NTLM proxy with authentication as described here: https://stackoverflow.com/questions/3868291/how-to-test-a-http-client-using-ntlm-authentication
You library is working fine for direct access, however when trying to use as a proxy maybe detail in the authentication does not work out.
If I want to access a secure HTTPS website through an NTLM auth proxy. I patched the code to handle 407 error messages (HTTP/1.1 407 Proxy Authentication Required) in addition to the 401, and also change the
auth_header 'Authorization' to 'Proxy-authorization'
auth_header_field 'WWW-Authenticate' to 'proxy-authenticate'
But, then I get the following error message:
Traceback (most recent call last):
File "C:\a1\testMySSPI.py", line 14, in <module>
r = requests.get('https://www.google.de/', proxies=proxy_dict, auth=HttpNegotiateAuth())
File "C:\b2\Python27\lib\site-packages\requests\api.py", line 69, in get
return request('get', url, params=params, **kwargs)
File "C:\b2\Python27\lib\site-packages\requests\api.py", line 50, in request
response = session.request(method=method, url=url, **kwargs)
File "C:\b2\Python27\lib\site-packages\requests\sessions.py", line 465, in request
resp = self.send(prep, **send_kwargs)
File "C:\b2\Python27\lib\site-packages\requests\sessions.py", line 573, in send
r = adapter.send(request, **kwargs)
File "C:\b2\Python27\lib\site-packages\requests\adapters.py", line 424, in send
raise ConnectionError(e, request=request)
ConnectionError: HTTPSConnectionPool(host='www.google.de', port=443):
Max retries exceeded with url: /
(Caused by ProxyError('Cannot connect to proxy.',
error('Tunnel connection failed: 407 Proxy Authentication Required',)))
Unencrypted http GET works over NTLM auth proxy, but I need the https CONNECT variant.
@railocius The problem of accessing https sites lies with requests and urllib3 libraries. Try changing the following lines and see what happens:
<path-to>\Python37\Lib\site-packages\requests\adapters.py:
344 scheme = urlparse(request.url).scheme
345
346: #@Glaukon
347 #is_proxied_http_request = (proxy and scheme != 'https')
348 is_proxied_http_request = (proxy)
349: #@Glaukon
350
351 using_socks_proxy = False
<path-to>\Python37\Lib\site-packages\urllib3\poolmanager.py:
411
412 def connection_from_host(self, host, port=None, scheme='http', pool_kwargs=None):
413: #@Glaukon
414 #if scheme == "https":
415 # return super(ProxyManager, self).connection_from_host(
416 # host, port, scheme, pool_kwargs=pool_kwargs)
417: #@Glaukon
418
419 return super(ProxyManager, self).connection_from_host(
EDIT: I have opened an issue #1520 for this in the urllib3 project.
This is my work-in-progress modification of requests_negotiate_sspi.py to add proxy support. It works in my environment, but only for HTTP scheme due to urllib2 issue #1520. The gist of the changes is that I have reused the code from the Px project that deals with the NTLM authentication.
import base64
import hashlib
import logging
import socket
import struct
from requests.auth import AuthBase
from requests.exceptions import HTTPError
import pywintypes
import sspi
import sspicon
import win32security
try:
from urllib.parse import urlparse
except ImportError:
from urlparse import urlparse
########################################################################## PX
# Print if possible
def pprint(*objs):
try:
print(*objs)
except:
pass
# Dependencies
import os
import sys
import ctypes.wintypes
import multiprocessing
import threading
import time
#try:
# import winkerberos
#except ImportError:
# pprint("Requires module winkerberos")
# sys.exit()
#try:
# import ntlm_auth.ntlm
#except ImportError:
# pprint("Requires module ntlm-auth")
# sys.exit()
#try:
# import keyring
# import keyring.backends.Windows
#
# keyring.set_keyring(keyring.backends.Windows.WinVaultKeyring())
#except ImportError:
# pprint("Requires module keyring")
# sys.exit()
#
## https://github.com/genotrance/px/blob/master/px.py
#
# Windows version
# 6.1 = Windows 7
# 6.2 = Windows 8
# 6.3 = Windows 8.1
# 10.0 = Windows 10
WIN_VERSION = float(str(sys.getwindowsversion().major) + "." + str(sys.getwindowsversion().minor))
logging.basicConfig(level=logging.DEBUG)
_logger = logging.getLogger(__name__)
def dprint(msg):
#sys.stdout.write(
_logger.debug(
#multiprocessing.current_process().name + ": " +
#threading.current_thread().name + ": " +
sys._getframe(1).f_code.co_name + "@" + str(int(time.time())) + ": " + msg)
###
# NTLM support
def b64decode(val):
try:
return base64.decodebytes(val.encode("utf-8"))
except AttributeError:
return base64.decodestring(val)
def b64encode(val):
try:
return base64.encodebytes(val.encode("utf-8"))
except AttributeError:
return base64.encodestring(val)
class NtlmMessageGenerator:
# use proxy server as parameter to use the one to which connecting was successful (doesn't need to be the first of the list)
def __init__(self, proxy_type, proxy_server_address, delegate, authInfo):
(username, domain, password) = authInfo if authInfo else (None, None, None)
pwd = ""
if username:
pwd = keyring.get_password("Px", domain + "\\" + username)
if proxy_type in ('NEGOTIATE', 'NTLM'):
if not pwd:
self.ctx = sspi.ClientAuth(proxy_type, os.environ.get("USERNAME"), scflags=0)
self.get_response = self.get_response_sspi
# Calling sspi.ClientAuth with scflags set requires you to specify all the flags, including defaults.
# We just want to add ISC_REQ_DELEGATE.
if delegate:
self.ctx.clientauth.scflags |= sspicon.ISC_REQ_DELEGATE
#@#Glaukon[old code]
#@# 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)
else:
self.ctx = ntlm_auth.ntlm.NtlmContext(username, pwd, domain, "", ntlm_compatibility=3)
self.get_response = self.get_response_ntlm
else:
principal = None
if pwd:
if domain:
principal = (urlparse.quote(username) + "@" +
urlparse.quote(domain) + ":" + urlparse.quote(pwd))
else:
principal = urlparse.quote(username) + ":" + urlparse.quote(pwd)
_, self.ctx = winkerberos.authGSSClientInit("HTTP@" + proxy_server_address,
principal=principal, gssflags=0, mech_oid=winkerberos.GSS_MECH_OID_SPNEGO)
self.get_response = self.get_response_wkb
def get_response_sspi(self, challenge=None):
dprint("pywin32 SSPI")
if challenge:
challenge = b64decode(challenge)
output_buffer = None
try:
error_msg, output_buffer = self.ctx.authorize(challenge)
except pywintypes.error:
traceback.print_exc(file=sys.stdout)
return None
response_msg = b64encode(output_buffer[0].Buffer)
response_msg = response_msg.decode("utf-8").replace('\012', '')
return response_msg
def get_response_wkb(self, challenge=""):
dprint("winkerberos SSPI")
try:
winkerberos.authGSSClientStep(self.ctx, challenge)
auth_req = winkerberos.authGSSClientResponse(self.ctx)
except winkerberos.GSSError:
traceback.print_exc(file=sys.stdout)
return None
return auth_req
def get_response_ntlm(self, challenge=""):
dprint("ntlm-auth")
if challenge:
challenge = b64decode(challenge)
response_msg = b64encode(self.ctx.step(challenge))
response_msg = response_msg.decode("utf-8").replace('\012', '')
return response_msg
########################################################################## PX
class HttpNegotiateAuth(AuthBase):
_auth_info = None
_service = 'HTTP'
_host = None
_delegate = False
def __init__(self, username=None, password=None, domain=None, service=None, host=None, delegate=False):
"""Create a new Negotiate auth handler
Args:
username: Username.
password: Password.
domain: NT Domain name.
Default: '.' for local account.
service: Kerberos Service type for remote Service Principal Name.
Default: 'HTTP'
host: Host name for Service Principal Name.
Default: Extracted from request URI
delegate: Indicates that the user's credentials are to be delegated to the server.
Default: False
If username and password are not specified, the user's default credentials are used.
This allows for single-sign-on to domain resources if the user is currently logged on
with a domain account.
"""
if domain is None:
domain = '.'
if username is not None and password is not None:
self._auth_info = (username, domain, password)
if service is not None:
self._service = service
if host is not None:
self._host = host
self._delegate = delegate
def _update_host(self, url):
if self._host is None:
targeturl = urlparse(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)
def _prepare_new_request(self, response):
# 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')
return request
def _retry_using_http_Negotiate_auth(self, response, scheme, authFields, args):
if authFields[1] in response.request.headers:
return response
self._update_host(response.request.url)
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)
# Send initial challenge auth header
dprint('Sending Initial Context Token')
ntlm = NtlmMessageGenerator(scheme, None, self._delegate, self._auth_info)
ntlm_resp = ntlm.get_response()
if ntlm_resp:
request = self._prepare_new_request(response)
request.headers[authFields[1]] = "%s %s" % (scheme, ntlm_resp)
else:
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 not in (401, 407):
if response2.status_code == 200:
# Kerberos may have succeeded; if so, finalize our auth context
token = response2.headers.get(authFields[0])
if token:
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.
token = token.replace(scheme, '', 1).lstrip()
dprint('Kerberos Authentication')
ntlm_resp = ntlm.get_response(token)
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
# Extract challenge message from server
challenge = [val[len(scheme)+1:] for val in response2.headers.get(authFields[0], '').split(', ') if scheme in val]
if len(challenge) != 1:
raise HTTPError('Did not get exactly one {} challenge from server.'.format(scheme))
dprint('Got Challenge Token ({}) {}'.format(scheme, challenge[0]))
# Perform next authorization step
dprint('Sending Response')
ntlm_resp = ntlm.get_response(challenge[0])
if ntlm_resp:
request = self._prepare_new_request(response2)
request.headers[authFields[1]] = "%s %s" % (scheme, ntlm_resp)
else:
return response
response3 = response2.connection.send(request, **args)
# Update the history and return
response3.history.append(response)
response3.history.append(response2)
return response3
def _response_hook(self, r, **kwargs):
if r.status_code in (401, 407):
authFields = ('WWW-Authenticate', 'Authorization') if r.status_code == 401 else ('Proxy-Authenticate', 'Proxy-Authorization')
auth = r.headers.get(authFields[0], '').upper()
for scheme in ('NEGOTIATE', 'NTLM', 'KERBEROS'):
if scheme in auth:
return self._retry_using_http_Negotiate_auth(r, scheme, authFields, kwargs)
def __call__(self, r):
r.headers['Connection'] = 'Keep-Alive'
r.headers['Proxy-Connection'] = 'Keep-Alive'
r.register_hook('response', self._response_hook)
return r
I can confirm that password-less proxy authentication works for HTTP with the changes provides by @glaukon-ariston. As he said, HTTPS fails.
@glaukon-ariston Is there any (dirty?) workaround for HTTPS? Do you have any idea how to get that working?
@andrenam I have given up on any solution that relies on urllib3. Instead, I found out that pycurl is working fine with both HTTPS and HTTP over a proxy for SSPI authentication. Below is the code that I use to initialise pycurl. Hope it helps.
pip install pycurl
#
# Pycurl-vs-Requests
# https://github.com/0xyd/Pycurl-vs-Requests
#
import pycurl
import certifi
import io
import sys
import proxy
# Python 2.x vs 3.x support
try:
import urllib.parse as urlparse
except ImportError:
import urlparse
#==================================================================== CURL Init
def initPyCURL(proxy_servers):
c = pycurl.Curl()
if len(proxy_servers) > 0:
c.setopt(c.PROXY, proxy_servers[0][0])
c.setopt(c.PROXYPORT, proxy_servers[0][1])
c.setopt(c.PROXYAUTH, c.HTTPAUTH_ANY)
# http://curl.haxx.se/mail/tracker-2010-10/0019.html
#c.setopt(c.PROXYAUTH, c.HTTPAUTH_NTLM)
c.setopt(c.PROXYUSERPWD, ":")
# tunnel to get to secure site.
c.setopt(c.HTTPPROXYTUNNEL, True)
#CURL_setopt(c.CURLOPT_POSTREDIR, 3);
c.setopt(c.FOLLOWLOCATION, True)
CURLOPT_ENCODING = getattr(c, 'ACCEPT_ENCODING', c.ENCODING)
c.setopt(CURLOPT_ENCODING, '')
c.setopt(c.FAILONERROR, True)
#c.setopt(c.COOKIEJAR, 'cookie.txt')
c.setopt(c.COOKIEFILE, '')
c.setopt(c.CAINFO, certifi.where())
c.setopt(c.SSL_VERIFYPEER, 0)
c.setopt(c.SSL_VERIFYHOST, 0)
#c.setopt(c.SSL_VERIFYPEER, 1)
#c.setopt(c.SSL_VERIFYHOST, 2)
# Define a callback function for logging.
def log(debug_type, debug_msg):
print("[%d] %s" % (debug_type, debug_msg.decode('utf-8', 'backslashreplace').strip()))
c.setopt(c.VERBOSE, True)
c.setopt(c.DEBUGFUNCTION, log)
return c
#==================================================================== CURL Init
url = 'https://python.org/'
pycurl.global_init(pycurl.GLOBAL_WIN32)
pycurl.global_init(pycurl.GLOBAL_SSL)
sys.stderr.write("Using %s\n" % pycurl.version)
buffer = io.BytesIO()
proxy_str = proxy.winhttp_find_proxy_for_url(url, autodetect=True)
proxy_servers = proxy.parse_proxy(proxy_str)
c = initPyCURL(proxy_servers)
c.setopt(c.URL, url)
#c.setopt(c.WRITEFUNCTION, buffer.write)
c.setopt(c.WRITEDATA, buffer)
c.perform()
c.close()
body = buffer.getvalue()
# Body is a byte string.
# We have to know the encoding in order to print it to a text file
# such as standard output.
#print(body.decode('utf-8'))
print(len(body))
#
# proxy.py
# Taken from the Px project
# https://github.com/genotrance/px/blob/master/px.py
import sys
import ctypes
import ctypes.wintypes
# Print if possible
def pprint(*objs):
try:
print(*objs)
except:
pass
# Windows version
# 6.1 = Windows 7
# 6.2 = Windows 8
# 6.3 = Windows 8.1
# 10.0 = Windows 10
WIN_VERSION = float(str(sys.getwindowsversion().major) + "." + str(sys.getwindowsversion().minor))
###
# Proxy detection
class WINHTTP_CURRENT_USER_IE_PROXY_CONFIG(ctypes.Structure):
_fields_ = [("fAutoDetect", ctypes.wintypes.BOOL), # "Automatically detect settings"
("lpszAutoConfigUrl", ctypes.wintypes.LPWSTR), # "Use automatic configuration script, Address"
("lpszProxy", ctypes.wintypes.LPWSTR), # "1.2.3.4:5" if "Use the same proxy server for all protocols",
# else advanced "ftp=1.2.3.4:5;http=1.2.3.4:5;https=1.2.3.4:5;socks=1.2.3.4:5"
("lpszProxyBypass", ctypes.wintypes.LPWSTR), # ";"-separated list, "Bypass proxy server for local addresses" adds "<local>"
]
class WINHTTP_AUTOPROXY_OPTIONS(ctypes.Structure):
_fields_ = [("dwFlags", ctypes.wintypes.DWORD),
("dwAutoDetectFlags", ctypes.wintypes.DWORD),
("lpszAutoConfigUrl", ctypes.wintypes.LPCWSTR),
("lpvReserved", ctypes.c_void_p),
("dwReserved", ctypes.wintypes.DWORD),
("fAutoLogonIfChallenged", ctypes.wintypes.BOOL), ]
class WINHTTP_PROXY_INFO(ctypes.Structure):
_fields_ = [("dwAccessType", ctypes.wintypes.DWORD),
("lpszProxy", ctypes.wintypes.LPCWSTR),
("lpszProxyBypass", ctypes.wintypes.LPCWSTR), ]
# Parameters for WinHttpOpen, http://msdn.microsoft.com/en-us/library/aa384098(VS.85).aspx
WINHTTP_NO_PROXY_NAME = 0
WINHTTP_NO_PROXY_BYPASS = 0
WINHTTP_FLAG_ASYNC = 0x10000000
# dwFlags values
WINHTTP_AUTOPROXY_AUTO_DETECT = 0x00000001
WINHTTP_AUTOPROXY_CONFIG_URL = 0x00000002
# dwAutoDetectFlags values
WINHTTP_AUTO_DETECT_TYPE_DHCP = 0x00000001
WINHTTP_AUTO_DETECT_TYPE_DNS_A = 0x00000002
# dwAccessType values
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY = 0
WINHTTP_ACCESS_TYPE_NO_PROXY = 1
WINHTTP_ACCESS_TYPE_NAMED_PROXY = 3
WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY = 4
# Error messages
WINHTTP_ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT = 12167
def winhttp_find_proxy_for_url(url, autodetect=False, pac_url=None, autologon=True):
# Fix issue #51
ACCESS_TYPE = WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY
if WIN_VERSION < 6.3:
ACCESS_TYPE = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY
ctypes.windll.winhttp.WinHttpOpen.restype = ctypes.c_void_p
hInternet = ctypes.windll.winhttp.WinHttpOpen(
ctypes.wintypes.LPCWSTR("Px"),
ACCESS_TYPE, WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, WINHTTP_FLAG_ASYNC)
if not hInternet:
dprint("WinHttpOpen failed: " + str(ctypes.GetLastError()))
return ""
autoproxy_options = WINHTTP_AUTOPROXY_OPTIONS()
if pac_url:
autoproxy_options.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL
autoproxy_options.dwAutoDetectFlags = 0
autoproxy_options.lpszAutoConfigUrl = pac_url
elif autodetect:
autoproxy_options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT
autoproxy_options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A
autoproxy_options.lpszAutoConfigUrl = 0
else:
return ""
autoproxy_options.fAutoLogonIfChallenged = autologon
proxy_info = WINHTTP_PROXY_INFO()
# Fix issue #43
ctypes.windll.winhttp.WinHttpGetProxyForUrl.argtypes = [ctypes.c_void_p,
ctypes.wintypes.LPCWSTR, ctypes.POINTER(WINHTTP_AUTOPROXY_OPTIONS),
ctypes.POINTER(WINHTTP_PROXY_INFO)]
ok = ctypes.windll.winhttp.WinHttpGetProxyForUrl(hInternet, ctypes.wintypes.LPCWSTR(url),
ctypes.byref(autoproxy_options), ctypes.byref(proxy_info))
if not ok:
error = ctypes.GetLastError()
dprint("WinHttpGetProxyForUrl error %s" % error)
if error == WINHTTP_ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT:
dprint("Could not download PAC file, trying DIRECT instead")
return "DIRECT"
return ""
if proxy_info.dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY:
# Note: proxy_info.lpszProxyBypass makes no sense here!
if not proxy_info.lpszProxy:
dprint('WinHttpGetProxyForUrl named proxy without name')
return ""
return proxy_info.lpszProxy.replace(" ", ",").replace(";", ",").replace(",DIRECT", "") # Note: We only see the first!
if proxy_info.dwAccessType == WINHTTP_ACCESS_TYPE_NO_PROXY:
return "DIRECT"
# WinHttpCloseHandle()
dprint("WinHttpGetProxyForUrl accesstype %s" % (proxy_info.dwAccessType,))
return ""
def parse_proxy(proxystrs):
if not proxystrs:
return []
servers = []
for proxystr in [i.strip() for i in proxystrs.split(",")]:
pserver = [i.strip() for i in proxystr.split(":")]
if len(pserver) == 1 and pserver != 'DIRECT':
pserver.append(80)
elif len(pserver) == 2:
try:
pserver[1] = int(pserver[1])
except ValueError:
pprint("Bad proxy server port: " + pserver[1])
sys.exit()
else:
pprint("Bad proxy server definition: " + proxystr)
sys.exit()
if tuple(pserver) not in servers:
servers.append(tuple(pserver))
return servers
@glaukon-ariston Thank you :+1: I'll try it next week in our Windows corporate environment. Do I need some special binary or curl version with sspi on windows? Or just install pycurl via pip and I'm good to go?
In my environment I could not do direct pip install pycurl
, so I downloaded the appropriate pycurl's whl and installed it locally with pip install pycurl-7.43.1-cp37-cp37m-win_amd64.whl
. Repeat the process with any dependent libraries if pip
barks at you.
@glaukon-ariston thanks, your code is working fine. :+1:
Only thing that didnt work was auto-discovery of the proxy:
proxy_str = proxy.winhttp_find_proxy_for_url(url, autodetect=True)
Setting this manually, the rest works fine.
Searching the web, I also found pywebcore. Do you know this - might be worth a try? I didnt get it running though, see https://github.com/benjimin/pywebcorp/issues/2
@glaukon-ariston @andrenam Hey, have you guys tried maybe using Requests libary or python3.8 64bit for HTTPS? also - curl now supports sspi itself.. have you triedi it?
@J3wker which curl you exactly mean? can u pls send link to py module? thank you
@J3wker which curl you exactly mean? can u pls send link to py module? thank you
I've checked it, it does not work bro... have you guys solved the issue with SSL using requests? maybe force authentication on every packet?
@J3wker which curl you exactly mean? can u pls send link to py module? thank you
@andrenam @eissko Hey, I managed to get PyCurl to get this working !
I will be writing a library to replace requests using PyCurl in order to use SSPI proxies and etc. Follow me on github i will post in the weekend to come. right now using PyCurl is really a pain to be honest..
As promised SSPI support to proxies (HTTP and HTTPs)- automatic PAC parsing and manual proxy detection / or DIRECT access to the internet:
here is my git repo: https://github.com/J3wker/besoCurl
Easy to use!
@glaukon-ariston's examples were very useful, but even with urllib3/urllib3#1520 I could not find a solution to the HTTPS tunneling issue with requests-negotiate-sspi
. Fortunately, I found this from request-kerberos which worked for my case (http proxy used for https scheme/endpoints, only empty challenge needed for a token)
I am searching SSPI authentication and glad to come across this package. May I wonder if there is any planned enhancement to extend WWW authentication to Proxy Authentication. Thank you.