Skip to content

Commit

Permalink
client: fix basic auth with empty password
Browse files Browse the repository at this point in the history
When authenticating using basic auth and only providing username (no
password) the default value of `None` was cast to string, resulting
in an attempt to authenticate using `<username>:None` instead of
providing an empty password.
This broke authentication when providing an auth token as username.
See iterative/dvc#7898 (comment)
  • Loading branch information
dtrifiro committed Jun 20, 2022
1 parent 31490d6 commit f37af59
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 1 deletion.
2 changes: 1 addition & 1 deletion dulwich/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2181,7 +2181,7 @@ def __init__(
if username is not None:
# No escaping needed: ":" is not allowed in username:
# https://tools.ietf.org/html/rfc2617#section-2
credentials = "%s:%s" % (username, password)
credentials = f"{username}:{password or ''}"
import urllib3.util

basic_auth = urllib3.util.make_headers(basic_auth=credentials)
Expand Down
27 changes: 27 additions & 0 deletions dulwich/tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1021,6 +1021,19 @@ def test_init_username_passwd_set(self):
expected_basic_auth = "Basic %s" % b64_credentials.decode("latin1")
self.assertEqual(basic_auth, expected_basic_auth)

def test_init_username_set_no_password(self):
url = "https://github.com/jelmer/dulwich"

c = HttpGitClient(url, config=None, username="user")
self.assertEqual("user", c._username)
self.assertIs(c._password, None)

basic_auth = c.pool_manager.headers["authorization"]
auth_string = b"user:"
b64_credentials = base64.b64encode(auth_string)
expected_basic_auth = f"Basic {b64_credentials.decode('ascii')}"
self.assertEqual(basic_auth, expected_basic_auth)

def test_init_no_username_passwd(self):
url = "https://github.com/jelmer/dulwich"

Expand All @@ -1029,6 +1042,20 @@ def test_init_no_username_passwd(self):
self.assertIs(None, c._password)
self.assertNotIn("authorization", c.pool_manager.headers)

def test_from_parsedurl_username_only(self):
username = "user"
url = f"https://{username}@github.com/jelmer/dulwich"

c = HttpGitClient.from_parsedurl(urlparse(url))
self.assertEqual(c._username, username)
self.assertEqual(c._password, None)

basic_auth = c.pool_manager.headers["authorization"]
auth_string = username.encode('ascii') + b":"
b64_credentials = base64.b64encode(auth_string)
expected_basic_auth = f"Basic {b64_credentials.decode('ascii')}"
self.assertEqual(basic_auth, expected_basic_auth)

def test_from_parsedurl_on_url_with_quoted_credentials(self):
original_username = "john|the|first"
quoted_username = urlquote(original_username)
Expand Down

0 comments on commit f37af59

Please sign in to comment.