Pip: Pip never asks for password when connecting to private repo

Created on 8 Apr 2020  ·  6Comments  ·  Source: pypa/pip

Environment

  • pip version: 20.0.2
  • Python version: 3.8.2
  • OS: Arch Linux
  • Keyring in use: gnome keyring

Description

When fetching a package from a private repo for the first time, pip asks
for the username, then fails without asking for the password.

Expected behavior

Pip should ask for the password.

How to Reproduce

  1. Add https://py.briq.it/simple/ as extra index url
  2. Run pip install -v briq_utils

Output

$ pip install -v briq_utils                                                                                                                                                       
Defaulting to user installation because normal site-packages is not writeable
Created temporary directory: /tmp/pip-ephem-wheel-cache-h0go_59q
Created temporary directory: /tmp/pip-req-tracker-_zrb96hk
Initialized build tracking at /tmp/pip-req-tracker-_zrb96hk
Created build tracker: /tmp/pip-req-tracker-_zrb96hk
Entered build tracker: /tmp/pip-req-tracker-_zrb96hk
Created temporary directory: /tmp/pip-install-cjulioxj
Looking in indexes: https://pypi.org/simple, https://py.briq.it/simple/
2 location(s) to search for versions of briq-utils:
* https://pypi.org/simple/briq-utils/
* https://py.briq.it/simple/briq-utils/
Fetching project page and analyzing links: https://pypi.org/simple/briq-utils/
Getting page https://pypi.org/simple/briq-utils/
Found index url https://pypi.org/simple
Getting credentials from keyring for https://pypi.org/simple
Getting credentials from keyring for pypi.org
Looking up "https://pypi.org/simple/briq-utils/" in the cache
Request header has "max_age" as 0, cache bypassed
Starting new HTTPS connection (1): pypi.org:443
https://pypi.org:443 "GET /simple/briq-utils/ HTTP/1.1" 404 13
Status code 404 not in (200, 203, 300, 301)
Could not fetch URL https://pypi.org/simple/briq-utils/: 404 Client Error: Not Found for url: https://pypi.org/simple/briq-utils/ - skipping
Fetching project page and analyzing links: https://py.briq.it/simple/briq-utils/
Getting page https://py.briq.it/simple/briq-utils/
Found index url https://py.briq.it/simple/
Getting credentials from keyring for https://py.briq.it/simple/
Getting credentials from keyring for py.briq.it
Looking up "https://py.briq.it/simple/briq-utils/" in the cache
Request header has "max_age" as 0, cache bypassed
Starting new HTTPS connection (1): py.briq.it:443
https://py.briq.it:443 "GET /simple/briq-utils/ HTTP/1.1" 401 727
User for py.briq.it: [type username]
Getting credentials from keyring for py.briq.it
Status code 401 not in (200, 203, 300, 301)
Looking up "https://py.briq.it/simple/briq-utils/" in the cache
Request header has "max_age" as 0, cache bypassed
https://py.briq.it:443 "GET /simple/briq-utils/ HTTP/1.1" 403 721
Status code 403 not in (200, 203, 300, 301)
Could not fetch URL https://py.briq.it/simple/briq-utils/: 403 Client Error: Forbidden for url: https://py.briq.it/simple/briq-utils/ - skipping
[...]

Workaround

>>> import keyring
>>> keyring.set_password("py.briq.it", "myusername", "mypassword")
auto-locked

All 6 comments

The problem seems to be in _internal/network/auth.py, where function _prompt_for_password calls get_keyring_auth after reading the username; however, at least with my keyring, an object that is not None is returned even if there is no credential (auth.password is None).

It is a matter of opinion if get_keyring_auth should be called at all: one would expect the program to always ask for the password after the username.

one would expect the program to always ask for the password after the username.

I’m less sure about that; it seems natural to me for a program to auto-fill the password if it “knows” it already.

Do you happen to know what is returned by keyring.get_password() in this case? Maybe it’s just a matter of improving detection.

I’m less sure about that; it seems natural to me for a program to auto-fill the password if it “knows” it already.

For CLI, I don't think that's a good idea, since it's difficult to make good UX for accessing (changing/deleting) the saved pasword.

Do you happen to know what is returned by keyring.get_password() in this case? Maybe it’s just a matter of improving detection.

In my case, keyring.get_password returns None, so that in _prompt_for_password, auth[0] == "myusername" and auth[1] is None

In my case, keyring.get_password returns None, so that in _prompt_for_password, auth[0] == "myusername" and auth[1] is None

Sounds like we just need to get_keyring_auth() to detect this.

I would like to resolve this issue.

To me, it seems that using the condition as if auth[0] and auth[1] in place of the currently used condition i.e. if auth here https://github.com/pypa/pip/blob/master/src/pip/_internal/network/auth.py#L222, would resolve the problem. Am I seeking the correct approach?

Was this page helpful?
0 / 5 - 0 ratings