Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support using netrc for non-proxy HTTP credentials #7131

Merged
merged 51 commits into from
Mar 17, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
2ee2464
Read HTTP Basic auth from netrc if no explict auth is passed
yuvipanda Dec 16, 2022
2c8e709
Read from .netrc only when trust_env is passed
yuvipanda Dec 16, 2022
d26d261
Deduplicate creating basicauth from netrc
yuvipanda Dec 17, 2022
f59b4c3
Remove possibly unneeded cast
yuvipanda Dec 17, 2022
3329055
Cleanup how username & password are determined
yuvipanda Dec 17, 2022
dc7833f
Reflow boolean checks to be clearer
yuvipanda Dec 19, 2022
81237e2
Cleanup netrc parsing code
yuvipanda Dec 19, 2022
11e0969
Add tests for netrc helpers
yuvipanda Dec 19, 2022
b691694
Add test for client_req
yuvipanda Dec 19, 2022
cadbbd3
Adding self to CONTRIBUTORS
yuvipanda Dec 19, 2022
fc57968
Add documentation for getting HTTP Basic Auth creds from netrc file
yuvipanda Dec 19, 2022
9bfc648
Add .feature file
yuvipanda Dec 19, 2022
fd362af
Set versionchanged string to 3.9 for HTTP Basic Auth netrc support
yuvipanda Dec 19, 2022
1cbf9ab
Reword changes file
yuvipanda Dec 19, 2022
a8682f1
Use built in tmp_path pytest fixture
yuvipanda Dec 19, 2022
14be170
Use pytest monkeypatch.setenv
yuvipanda Dec 19, 2022
3847daf
Cleanup tests to use better fixtures
yuvipanda Dec 21, 2022
5074c98
Fix comment typo
yuvipanda Dec 21, 2022
e3cbf59
Use exceptions for control flow
yuvipanda Dec 21, 2022
bfba449
Don't touch netrc if self.url.host is not None
yuvipanda Dec 23, 2022
7f60553
Merge pull request #2 from yuvipanda/exceptional
yuvipanda Dec 23, 2022
993675d
Encode information about conditional into variable name
yuvipanda Dec 23, 2022
8330097
Return netrc path from fixture
yuvipanda Jan 7, 2023
19dabd3
Use better rST syntax
yuvipanda Jan 7, 2023
8aad3d0
Simplify parametrize call
yuvipanda Jan 7, 2023
b556229
Simplify parametrize call
yuvipanda Jan 7, 2023
6ff6ffc
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 7, 2023
4722d95
Use a label for boolean condition
yuvipanda Jan 7, 2023
653b93b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 7, 2023
4eadd65
Don't write out netrc file in fixture if not passed in
yuvipanda Jan 7, 2023
5f1111a
Remove spurious re-import of pathlib
yuvipanda Jan 7, 2023
e374b90
Use more rST
yuvipanda Jan 17, 2023
37561cf
Add another rST directive
yuvipanda Jan 17, 2023
e1c7616
Cleanup some unused fixtures
yuvipanda Jan 17, 2023
22df825
Use match= for pytest.raises
yuvipanda Jan 17, 2023
8a2f62a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 17, 2023
6932234
Use match= for pytest.raises *correctly*
yuvipanda Jan 17, 2023
273c049
Remove unused netrc_contents
yuvipanda Jan 17, 2023
8a8f40b
Hardcode "example.com" as hostname
yuvipanda Jan 17, 2023
9b16ad9
Cleanup client_request test
yuvipanda Jan 17, 2023
1d53474
Rename test case
yuvipanda Jan 17, 2023
d7ca088
Split up another test
yuvipanda Jan 17, 2023
deb4cf7
Split up another test
yuvipanda Jan 17, 2023
1a72bfb
Add glossary entry
yuvipanda Jan 17, 2023
a9fc639
Add section for environment variables
yuvipanda Jan 17, 2023
f8c6562
Fix line length 'error'
yuvipanda Jan 17, 2023
4a6f050
Account for netrc_obj being optionally None
yuvipanda Jan 17, 2023
524c04d
Don't use intermediary bools for None checks
yuvipanda Jan 17, 2023
53658b0
Merge pull request #3 from yuvipanda/no-intermediaries
yuvipanda Jan 17, 2023
1e40665
Update docs/glossary.rst
Dreamsorcerer Feb 3, 2023
38a86d9
Fix typo
yuvipanda Feb 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions aiohttp/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,7 @@ async def _request(
ssl=ssl,
proxy_headers=proxy_headers,
traces=traces,
trust_env=self.trust_env,
)

# connection timeout
Expand Down
16 changes: 14 additions & 2 deletions aiohttp/client_reqrep.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@
BasicAuth,
HeadersMixin,
TimerNoop,
basicauth_from_netrc,
is_expected_content_type,
netrc_from_env,
noop,
parse_mimetype,
reify,
Expand Down Expand Up @@ -210,6 +212,7 @@ def __init__(
ssl: Union[SSLContext, bool, Fingerprint, None] = None,
proxy_headers: Optional[LooseHeaders] = None,
traces: Optional[List["Trace"]] = None,
trust_env: bool = False,
):
match = _CONTAINS_CONTROL_CHAR_RE.search(method)
if match:
Expand Down Expand Up @@ -251,7 +254,7 @@ def __init__(
self.update_auto_headers(skip_auto_headers)
self.update_cookies(cookies)
self.update_content_encoding(data)
self.update_auth(auth)
self.update_auth(auth, trust_env)
self.update_proxy(proxy, proxy_auth, proxy_headers)

self.update_body_from_data(data)
Expand Down Expand Up @@ -428,11 +431,20 @@ def update_transfer_encoding(self) -> None:
if hdrs.CONTENT_LENGTH not in self.headers:
self.headers[hdrs.CONTENT_LENGTH] = str(len(self.body))

def update_auth(self, auth: Optional[BasicAuth]) -> None:
def update_auth(self, auth: Optional[BasicAuth], trust_env: bool = False) -> None:
"""Set basic auth."""
if auth is None:
auth = self.auth
if auth is None:
if trust_env:
# If no auth is specified, we read from netrc.

netrc_obj = netrc_from_env()
if netrc_obj:
auth = basicauth_from_netrc(netrc_obj, self.url.host)
if auth:
self.headers[hdrs.AUTHORIZATION] = auth.encode()
Dreamsorcerer marked this conversation as resolved.
Show resolved Hide resolved

return
yuvipanda marked this conversation as resolved.
Show resolved Hide resolved

if not isinstance(auth, helpers.BasicAuth):
Expand Down
36 changes: 26 additions & 10 deletions aiohttp/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
Type,
TypeVar,
Union,
cast,
overload,
)
from urllib.parse import quote
Expand Down Expand Up @@ -244,6 +243,31 @@ class ProxyInfo:
proxy_auth: Optional[BasicAuth]


def basicauth_from_netrc(netrc_obj: netrc.netrc, host: str) -> Optional[BasicAuth]:
auth_from_netrc = netrc_obj.authenticators(host)
yuvipanda marked this conversation as resolved.
Show resolved Hide resolved
if auth_from_netrc is not None:
login, account, password = auth_from_netrc
if not login:
# login is provided, we just use it as username.
Dreamsorcerer marked this conversation as resolved.
Show resolved Hide resolved
# If login and account are both provided, only login is used
username = login
elif account:
# login is not provided, but account is
username = account
else:
# neither login nore account are provided, we use blank username
# this matches python 3.11 behavior
username = ""
Dreamsorcerer marked this conversation as resolved.
Show resolved Hide resolved

if password is None:
Dreamsorcerer marked this conversation as resolved.
Show resolved Hide resolved
# Password is not provided, we use blank string.
# this matches python 3.11 behavior
password = ""

auth = BasicAuth(username, password)
return auth
Dreamsorcerer marked this conversation as resolved.
Show resolved Hide resolved

Dreamsorcerer marked this conversation as resolved.
Show resolved Hide resolved

def proxies_from_env() -> Dict[str, ProxyInfo]:
proxy_urls = {
k: URL(v)
Expand All @@ -261,16 +285,8 @@ def proxies_from_env() -> Dict[str, ProxyInfo]:
)
continue
if netrc_obj and auth is None:
auth_from_netrc = None
if proxy.host is not None:
auth_from_netrc = netrc_obj.authenticators(proxy.host)
if auth_from_netrc is not None:
# auth_from_netrc is a (`user`, `account`, `password`) tuple,
# `user` and `account` both can be username,
# if `user` is None, use `account`
*logins, password = auth_from_netrc
login = logins[0] if logins[0] else logins[-1]
auth = BasicAuth(cast(str, login), cast(str, password))
auth = basicauth_from_netrc(netrc_obj, proxy.host)
yuvipanda marked this conversation as resolved.
Show resolved Hide resolved
ret[proto] = ProxyInfo(proxy, auth)
return ret

Expand Down