From 1dc67a6a385130e8db0d4a7e7b1818d31030be9c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 31 Aug 2019 12:09:17 +0200 Subject: [PATCH] Allow bypassing .netrc with `--ignore-netrc` (close #730) --- CHANGELOG.rst | 3 ++- README.rst | 15 ++++++++++++++- httpie/cli.py | 8 ++++++++ httpie/input.py | 6 +++++- httpie/utils.py | 11 +++++++++++ tests/test_auth.py | 25 +++++++++++++++++++++++++ 6 files changed, 65 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 54433ad5..da48f090 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,7 +12,8 @@ This project adheres to `Semantic Versioning `_. * Removed the default 30-second connection ``--timeout`` limit. * Removed Python’s default limit of 100 response headers. * Added ``--max-headers`` to allow setting the max header limit. -* Added ``--compress``. +* Added ``--compress`` to allow request body compression. +* Added ``--ignore-netrc`` to allow bypassing credentials from ``.netrc``. * Added ``https`` alias command with ``https://`` as the default scheme. * Fixed an error when ``stdin`` was a closed fd. * Fixed an error when the config directory was not writeable. diff --git a/README.rst b/README.rst index 06e98307..e0f7a320 100644 --- a/README.rst +++ b/README.rst @@ -776,7 +776,10 @@ Password prompt ``.netrc`` ---------- -Authentication information from your ``~/.netrc`` file is honored as well: +Authentication information from your ``~/.netrc`` +file is by default honored as well. + +For example: .. code-block:: bash @@ -785,10 +788,20 @@ Authentication information from your ``~/.netrc`` file is honored as well: login httpie password test +.. code-block:: bash + $ http httpbin.org/basic-auth/httpie/test HTTP/1.1 200 OK [...] +This can be disable with the ``--ignore-netrc`` option: + +.. code-block:: bash + + $ http --ignore-netrc httpbin.org/basic-auth/httpie/test + HTTP/1.1 401 UNAUTHORIZED + [...] + Auth plugins ------------ diff --git a/httpie/cli.py b/httpie/cli.py index 23a13a7d..5ff0465a 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -492,7 +492,15 @@ auth.add_argument( for plugin in _auth_plugins )), ) +auth.add_argument( + '--ignore-netrc', + default=False, + action='store_true', + help=""" + Ignore credentials from .netrc. + """, +) ####################################################################### # Network diff --git a/httpie/input.py b/httpie/input.py index 71196089..dae89692 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -22,7 +22,7 @@ from httpie.plugins import plugin_manager from requests.structures import CaseInsensitiveDict from httpie.sessions import VALID_SESSION_NAME_PATTERN -from httpie.utils import load_json_preserve_order +from httpie.utils import load_json_preserve_order, ExplicitNullAuth # ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) @@ -287,6 +287,10 @@ class HTTPieArgumentParser(argparse.ArgumentParser): username=credentials.key, password=credentials.value, ) + if not self.args.auth and self.args.ignore_netrc: + # Set a no-op auth to force requests to ignore .netrc + # + self.args.auth = ExplicitNullAuth() def _apply_no_options(self, no_options): """For every `--no-OPTION` in `no_options`, set `args.OPTION` to diff --git a/httpie/utils.py b/httpie/utils.py index 9664bd69..453b67a1 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -2,6 +2,8 @@ from __future__ import division import json from collections import OrderedDict +import requests.auth + def load_json_preserve_order(s): return json.loads(s, object_pairs_hook=OrderedDict) @@ -67,3 +69,12 @@ def humanize_bytes(n, precision=2): # noinspection PyUnboundLocalVariable return '%.*f %s' % (precision, n / factor, suffix) + + +class ExplicitNullAuth(requests.auth.AuthBase): + """Forces requests to ignore the ``.netrc``. + + """ + + def __call__(self, r): + return r diff --git a/tests/test_auth.py b/tests/test_auth.py index 62cceb65..a4d95f80 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -2,6 +2,7 @@ import mock import pytest +from httpie.utils import ExplicitNullAuth from utils import http, add_auth, HTTP_OK, MockEnvironment import httpie.input import httpie.cli @@ -73,3 +74,27 @@ def test_missing_auth(httpbin): ) assert HTTP_OK not in r assert '--auth required' in r.stderr + + +def test_netrc(httpbin_both): + with mock.patch('requests.sessions.get_netrc_auth') as get_netrc_auth: + get_netrc_auth.return_value = ('httpie', 'password') + r = http(httpbin_both + '/basic-auth/httpie/password') + assert get_netrc_auth.call_count == 1 + assert HTTP_OK in r + + +def test_ignore_netrc(httpbin_both): + with mock.patch('requests.sessions.get_netrc_auth') as get_netrc_auth: + get_netrc_auth.return_value = ('httpie', 'password') + r = http('--ignore-netrc', httpbin_both + '/basic-auth/httpie/password') + assert get_netrc_auth.call_count == 0 + assert 'HTTP/1.1 401 UNAUTHORIZED' in r + + +def test_ignore_netrc_null_auth(): + args = httpie.cli.parser.parse_args( + args=['--ignore-netrc', 'example.org'], + env=MockEnvironment(), + ) + assert isinstance(args.auth, ExplicitNullAuth)