Skip to content

Commit 144b42d

Browse files
authored
Remove username/password from log message
Merge pull request #5339 from jzafran/remove-password-from-stdout
2 parents 6fdcf23 + 96dd6de commit 144b42d

File tree

7 files changed

+65
-51
lines changed

7 files changed

+65
-51
lines changed

news/5249.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Remove username/password from log message when using index with basic auth

src/pip/_internal/index.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
from pip._internal.utils.logging import indent_log
3434
from pip._internal.utils.misc import (
3535
ARCHIVE_EXTENSIONS, SUPPORTED_EXTENSIONS, cached_property, normalize_path,
36-
splitext,
36+
remove_auth_from_url, splitext,
3737
)
3838
from pip._internal.utils.packaging import check_requires_python
3939
from pip._internal.wheel import Wheel, wheel_ext
@@ -197,7 +197,8 @@ def get_formatted_locations(self):
197197
lines = []
198198
if self.index_urls and self.index_urls != [PyPI.simple_url]:
199199
lines.append(
200-
"Looking in indexes: {}".format(", ".join(self.index_urls))
200+
"Looking in indexes: {}".format(", ".join(
201+
remove_auth_from_url(url) for url in self.index_urls))
201202
)
202203
if self.find_links:
203204
lines.append(

src/pip/_internal/utils/misc.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from pip._vendor.retrying import retry # type: ignore
2525
from pip._vendor.six import PY2
2626
from pip._vendor.six.moves import input
27+
from pip._vendor.six.moves.urllib import parse as urllib_parse
2728

2829
from pip._internal.compat import console_to_str, expanduser, stdlib_pkgs
2930
from pip._internal.exceptions import InstallationError
@@ -47,7 +48,7 @@
4748
'unzip_file', 'untar_file', 'unpack_file', 'call_subprocess',
4849
'captured_stdout', 'ensure_dir',
4950
'ARCHIVE_EXTENSIONS', 'SUPPORTED_EXTENSIONS',
50-
'get_installed_version']
51+
'get_installed_version', 'remove_auth_from_url']
5152

5253

5354
logger = std_logging.getLogger(__name__)
@@ -849,3 +850,21 @@ def enum(*sequential, **named):
849850
reverse = {value: key for key, value in enums.items()}
850851
enums['reverse_mapping'] = reverse
851852
return type('Enum', (), enums)
853+
854+
855+
def remove_auth_from_url(url):
856+
# Return a copy of url with 'username:password@' removed.
857+
# username/pass params are passed to subversion through flags
858+
# and are not recognized in the url.
859+
860+
# parsed url
861+
purl = urllib_parse.urlsplit(url)
862+
stripped_netloc = \
863+
purl.netloc.split('@')[-1]
864+
865+
# stripped url
866+
url_pieces = (
867+
purl.scheme, stripped_netloc, purl.path, purl.query, purl.fragment
868+
)
869+
surl = urllib_parse.urlunsplit(url_pieces)
870+
return surl

src/pip/_internal/vcs/subversion.py

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from pip._internal.index import Link
1010
from pip._internal.utils.logging import indent_log
11-
from pip._internal.utils.misc import display_path, rmtree
11+
from pip._internal.utils.misc import display_path, remove_auth_from_url, rmtree
1212
from pip._internal.vcs import VersionControl, vcs
1313

1414
_svn_xml_url_re = re.compile('url="([^"]+)"')
@@ -63,7 +63,7 @@ def export(self, location):
6363
"""Export the svn repository at the url to the destination location"""
6464
url, rev = self.get_url_rev()
6565
rev_options = get_rev_options(self, url, rev)
66-
url = self.remove_auth_from_url(url)
66+
url = remove_auth_from_url(url)
6767
logger.info('Exporting svn repository %s to %s', url, location)
6868
with indent_log():
6969
if os.path.exists(location):
@@ -84,7 +84,7 @@ def update(self, dest, rev_options):
8484
def obtain(self, dest):
8585
url, rev = self.get_url_rev()
8686
rev_options = get_rev_options(self, url, rev)
87-
url = self.remove_auth_from_url(url)
87+
url = remove_auth_from_url(url)
8888
if self.check_destination(dest, url, rev_options):
8989
rev_display = rev_options.to_display()
9090
logger.info(
@@ -221,24 +221,6 @@ def is_commit_id_equal(self, dest, name):
221221
"""Always assume the versions don't match"""
222222
return False
223223

224-
@staticmethod
225-
def remove_auth_from_url(url):
226-
# Return a copy of url with 'username:password@' removed.
227-
# username/pass params are passed to subversion through flags
228-
# and are not recognized in the url.
229-
230-
# parsed url
231-
purl = urllib_parse.urlsplit(url)
232-
stripped_netloc = \
233-
purl.netloc.split('@')[-1]
234-
235-
# stripped url
236-
url_pieces = (
237-
purl.scheme, stripped_netloc, purl.path, purl.query, purl.fragment
238-
)
239-
surl = urllib_parse.urlunsplit(url_pieces)
240-
return surl
241-
242224

243225
def get_rev_options(vcs, url, rev):
244226
"""

tests/unit/test_index.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,18 @@ def test_secure_origin(location, trusted, expected):
139139
logger = MockLogger()
140140
finder._validate_secure_origin(logger, location)
141141
assert logger.called == expected
142+
143+
144+
def test_get_formatted_locations_basic_auth():
145+
"""
146+
Test that basic authentication credentials defined in URL
147+
is not included in formatted output.
148+
"""
149+
index_urls = [
150+
'https://pypi.org/simple',
151+
'https://user:[email protected]',
152+
]
153+
finder = PackageFinder([], index_urls, session=[])
154+
155+
result = finder.get_formatted_locations()
156+
assert 'user' not in result and 'pass' not in result

tests/unit/test_utils.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
from pip._internal.utils.hashes import Hashes, MissingHashes
2525
from pip._internal.utils.misc import (
2626
call_subprocess, egg_link_path, ensure_dir, get_installed_distributions,
27-
get_prog, normalize_path, rmtree, untar_file, unzip_file,
27+
get_prog, normalize_path, remove_auth_from_url, rmtree, untar_file,
28+
unzip_file,
2829
)
2930
from pip._internal.utils.packaging import check_dist_requires_python
3031
from pip._internal.utils.temp_dir import TempDirectory
@@ -624,3 +625,24 @@ def test_call_subprocess_works_okay_when_just_given_nothing():
624625
def test_call_subprocess_closes_stdin():
625626
with pytest.raises(InstallationError):
626627
call_subprocess([sys.executable, '-c', 'input()'])
628+
629+
630+
@pytest.mark.parametrize('auth_url, expected_url', [
631+
('https://user:[email protected]/project/tags/v0.2',
632+
'https://domain.tld/project/tags/v0.2'),
633+
('https://domain.tld/project/tags/v0.2',
634+
'https://domain.tld/project/tags/v0.2',),
635+
('https://user:[email protected]/svn/project/trunk@8181',
636+
'https://domain.tld/svn/project/trunk@8181'),
637+
('https://domain.tld/project/trunk@8181',
638+
'https://domain.tld/project/trunk@8181',),
639+
('git+https://pypi.org/something',
640+
'git+https://pypi.org/something'),
641+
('git+https://user:[email protected]/something',
642+
'git+https://pypi.org/something'),
643+
('git+ssh://[email protected]/something',
644+
'git+ssh://pypi.org/something'),
645+
])
646+
def test_remove_auth_from_url(auth_url, expected_url):
647+
url = remove_auth_from_url(auth_url)
648+
assert url == expected_url

tests/unit/test_vcs.py

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -173,32 +173,6 @@ def test_bazaar_simple_urls():
173173
)
174174

175175

176-
def test_subversion_remove_auth_from_url():
177-
# Check that the url is doctored appropriately to remove auth elements
178-
# from the url
179-
svn_auth_url = 'https://user:[email protected]/svn/project/tags/v0.2'
180-
expected_url = 'https://svnrepo.org/svn/project/tags/v0.2'
181-
url = Subversion.remove_auth_from_url(svn_auth_url)
182-
assert url == expected_url
183-
184-
# Check that this doesn't impact urls without authentication'
185-
svn_noauth_url = 'https://svnrepo.org/svn/project/tags/v0.2'
186-
expected_url = svn_noauth_url
187-
url = Subversion.remove_auth_from_url(svn_noauth_url)
188-
assert url == expected_url
189-
190-
# Check that links to specific revisions are handled properly
191-
svn_rev_url = 'https://user:[email protected]/svn/project/trunk@8181'
192-
expected_url = 'https://svnrepo.org/svn/project/trunk@8181'
193-
url = Subversion.remove_auth_from_url(svn_rev_url)
194-
assert url == expected_url
195-
196-
svn_rev_url = 'https://svnrepo.org/svn/project/trunk@8181'
197-
expected_url = 'https://svnrepo.org/svn/project/trunk@8181'
198-
url = Subversion.remove_auth_from_url(svn_rev_url)
199-
assert url == expected_url
200-
201-
202176
def test_get_git_version():
203177
git_version = Git().get_git_version()
204178
assert git_version >= parse_version('1.0.0')

0 commit comments

Comments
 (0)