Skip to content

Commit 940f340

Browse files
committed
Ignore http credentials with empty usernames
See-also: jaraco/keyring#668 jaraco/keyring#687
1 parent 70ce299 commit 940f340

File tree

4 files changed

+17
-13
lines changed

4 files changed

+17
-13
lines changed

docs/repositories.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,17 @@ You can prevent this by adding double dashes to prevent any following argument f
511511
poetry config -- http-basic.pypi myUsername -myPasswordStartingWithDash
512512
```
513513

514+
{{% note %}}
515+
In some cases like that of [Gemfury](https://gemfury.com/help/errors/repo-url-password/) repositories, it might be
516+
required to set an empty password. This is supported by Poetry.
517+
518+
```bash
519+
poetry config http-basic.foo <TOKEN> ""
520+
```
521+
522+
**Note:** Usernames cannot be empty. Attempting to use an empty username can result in an unpredictable failure.
523+
{{% /note %}}
524+
514525
## Certificates
515526

516527
### Custom certificate authority and mutual TLS authentication

src/poetry/utils/password_manager.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -196,23 +196,17 @@ def get_http_auth(self, repo_name: str) -> dict[str, str | None] | None:
196196
username = self._config.get(f"http-basic.{repo_name}.username")
197197
password = self._config.get(f"http-basic.{repo_name}.password")
198198

199-
# we only return None if both values are None or ""
200-
# password can be None at this stage with the username ""
201-
if (username is password is None) or (username == password == ""):
199+
if not username:
202200
return None
203201

204202
if not password:
205203
if self.use_keyring:
206204
password = self.keyring.get_password(repo_name, username)
207205
elif not username:
208-
# at this tage if username is "" or None, auth is invalid
209206
return None
210207

211-
if not username and not password:
212-
return None
213-
214208
return {
215-
"username": username or "",
209+
"username": username,
216210
"password": password or "",
217211
}
218212

tests/utils/test_authenticator.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ def test_authenticator_uses_empty_strings_as_default_password(
153153
assert request.headers["Authorization"] == f"Basic {basic_auth}"
154154

155155

156-
def test_authenticator_uses_empty_strings_as_default_username(
156+
def test_authenticator_ignores_empty_strings_as_default_username(
157157
config: Config,
158158
mock_remote: None,
159159
repo: dict[str, dict[str, str]],
@@ -170,8 +170,7 @@ def test_authenticator_uses_empty_strings_as_default_username(
170170
authenticator.request("get", "https://foo.bar/files/foo-0.1.0.tar.gz")
171171

172172
request = http.last_request()
173-
basic_auth = base64.b64encode(b":bar").decode()
174-
assert request.headers["Authorization"] == f"Basic {basic_auth}"
173+
assert request.headers["Authorization"] is None
175174

176175

177176
def test_authenticator_falls_back_to_keyring_url(

tests/utils/test_password_manager.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def test_set_http_password(
4040
("username", "password", "is_valid"),
4141
[
4242
("bar", "baz", True),
43-
("", "baz", True),
43+
("", "baz", False),
4444
("bar", "", True),
4545
("", "", False),
4646
],
@@ -134,7 +134,7 @@ def test_set_http_password_with_unavailable_backend(
134134
("username", "password", "is_valid"),
135135
[
136136
("bar", "baz", True),
137-
("", "baz", True),
137+
("", "baz", False),
138138
("bar", "", True),
139139
("", "", False),
140140
],

0 commit comments

Comments
 (0)