vcrpy
vcrpy copied to clipboard
Doesn't play nicely with requests-ntlm
Here's what happens when you use auth=requests_ntlm.HttpNtlmAuth(username, password)
:
File "/venv/lib/python3.5/site-packages/requests/api.py", line 72, in get
return request('get', url, params=params, **kwargs)
File "/venv/lib/python3.5/site-packages/requests/api.py", line 58, in request
return session.request(method=method, url=url, **kwargs)
File "/venv/lib/python3.5/site-packages/requests/sessions.py", line 512, in request
resp = self.send(prep, **send_kwargs)
File "/venv/lib/python3.5/site-packages/requests/sessions.py", line 629, in send
r = dispatch_hook('response', hooks, r, **kwargs)
File "/venv/lib/python3.5/site-packages/requests/hooks.py", line 31, in dispatch_hook
_hook_data = hook(hook_data, **kwargs)
File "/venv/lib/python3.5/site-packages/requests_ntlm/requests_ntlm.py", line 151, in response_hook
kwargs
File "/venv/lib/python3.5/site-packages/requests_ntlm/requests_ntlm.py", line 52, in retry_using_http_NTLM_auth
server_certificate_hash = self._get_server_cert(response)
File "/venv/lib/python3.5/site-packages/requests_ntlm/requests_ntlm.py", line 187, in _get_server_cert
socket = raw_response._fp.fp.raw._sock
AttributeError: 'VCRHTTPResponse' object has no attribute 'fp'
A lot of changes have happened to VCRpy since this ticket was opened. As this ticket has become stale, would you mind closing it if it is no longer needed / relevant?
If I haven't heard anything in a week I'll mark it as closed as we have a lot of old tickets that need to be groomed to make it easier to see what is still relevant.
However if it is still needed, please feel free to re-open or create a new ticket.
Thanks! 🙏
I'm having a similar issue with NTLM authentication. I've managed to come up with a small pytest script that uses a public NTLM test webpage that shows the issue.
import requests
import requests_ntlm
import vcr
def test_ntlm_auth():
resp = requests.get(
"http://ntlm.herokuapp.com/",
auth=requests_ntlm.HttpNtlmAuth("user", "pass"),
)
assert "ello" in str(resp.content)
def test_ntlm_auth_with_vcr():
with vcr.use_cassette("/tmp/test_ntlm_auth.yaml"):
resp = requests.get(
"http://ntlm.herokuapp.com/",
auth=requests_ntlm.HttpNtlmAuth("user", "pass"),
)
assert True
Output running with pytest -v looks like this:
$ pytest -v
================================================= test session starts ==================================================
platform linux -- Python 3.8.6, pytest-6.2.2, py-1.10.0, pluggy-0.13.1 -- /home/marko/.pyenv/versions/3.8.6/envs/ntlm_auth/bin/python3.8
cachedir: .pytest_cache
rootdir: /mnt/c/Users/Mark Osbourne/ntlm_auth
collected 2 items
test_ntlm_auth.py::test_ntlm_auth PASSED [ 50%]
test_ntlm_auth.py::test_ntlm_auth_with_vcr FAILED [100%]
======================================================= FAILURES =======================================================
_______________________________________________ test_ntlm_auth_with_vcr ________________________________________________
def test_ntlm_auth_with_vcr():
with vcr.use_cassette("/tmp/test_ntlm_auth.yaml"):
> resp = requests.get(
"http://ntlm.herokuapp.com/",
auth=requests_ntlm.HttpNtlmAuth("user", "pass"),
)
test_ntlm_auth.py:16:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/home/marko/.pyenv/versions/3.8.6/envs/ntlm_auth/lib/python3.8/site-packages/requests/api.py:76: in get
return request('get', url, params=params, **kwargs)
/home/marko/.pyenv/versions/3.8.6/envs/ntlm_auth/lib/python3.8/site-packages/requests/api.py:61: in request
return session.request(method=method, url=url, **kwargs)
/home/marko/.pyenv/versions/3.8.6/envs/ntlm_auth/lib/python3.8/site-packages/requests/sessions.py:542: in request
resp = self.send(prep, **send_kwargs)
/home/marko/.pyenv/versions/3.8.6/envs/ntlm_auth/lib/python3.8/site-packages/requests/sessions.py:662: in send
r = dispatch_hook('response', hooks, r, **kwargs)
/home/marko/.pyenv/versions/3.8.6/envs/ntlm_auth/lib/python3.8/site-packages/requests/hooks.py:31: in dispatch_hook
_hook_data = hook(hook_data, **kwargs)
/home/marko/.pyenv/versions/3.8.6/envs/ntlm_auth/lib/python3.8/site-packages/requests_ntlm/requests_ntlm.py:146: in response_hook
return self.retry_using_http_NTLM_auth(
/home/marko/.pyenv/versions/3.8.6/envs/ntlm_auth/lib/python3.8/site-packages/requests_ntlm/requests_ntlm.py:52: in retry_using_http_NTLM_auth
server_certificate_hash = self._get_server_cert(response)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <requests_ntlm.requests_ntlm.HttpNtlmAuth object at 0x7f6bed88c5e0>, response = <Response [401]>
def _get_server_cert(self, response):
"""
Get the certificate at the request_url and return it as a hash. Will get the raw socket from the
original response from the server. This socket is then checked if it is an SSL socket and then used to
get the hash of the certificate. The certificate hash is then used with NTLMv2 authentication for
Channel Binding Tokens support. If the raw object is not a urllib3 HTTPReponse (default with requests)
then no certificate will be returned.
:param response: The original 401 response from the server
:return: The hash of the DER encoded certificate at the request_url or None if not a HTTPS endpoint
"""
if self.send_cbt:
certificate_hash = None
raw_response = response.raw
if isinstance(raw_response, HTTPResponse):
if sys.version_info > (3, 0):
> socket = raw_response._fp.fp.raw._sock
E AttributeError: 'NoneType' object has no attribute 'raw'
/home/marko/.pyenv/versions/3.8.6/envs/ntlm_auth/lib/python3.8/site-packages/requests_ntlm/requests_ntlm.py:187: AttributeError
=============================================== short test summary info ================================================
FAILED test_ntlm_auth.py::test_ntlm_auth_with_vcr - AttributeError: 'NoneType' object has no attribute 'raw'
============================================= 1 failed, 1 passed in 0.71s ==============================================
I found a workaround for this issue that works in my particular situation.
I use pytest, in conftest.py
, I add the following monkeypatch:
from vcr.stubs import VCRHTTPResponse
from unittest import mock
def stubbed__setattr__(self, attribute, value):
if attribute == 'fp':
value = mock.Mock(raw=mock.Mock(_sock=None))
rez = super(VCRHTTPResponse, self).__setattr__(attribute, value)
return rez
VCRHTTPResponse.__setattr__ = stubbed__setattr__