commit f37af59c5d3a66e50a3b83ba574c5caa1182a374 from: Daniele Trifirò date: Mon Jun 20 18:02:24 2022 UTC client: fix basic auth with empty password 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 `:None` instead of providing an empty password. This broke authentication when providing an auth token as username. See https://github.com/iterative/dvc/issues/7898#issuecomment-1157564615 commit - 31490d6b2395abd4459f794863b205b8358978fa commit + f37af59c5d3a66e50a3b83ba574c5caa1182a374 blob - 168e28f0da1198afd1fbb89e87ebedda13f17406 blob + 3e42df1110827c2d294370cb448591d31dc71c55 --- dulwich/client.py +++ dulwich/client.py @@ -2181,7 +2181,7 @@ class Urllib3HttpGitClient(AbstractHttpGitClient): 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) blob - 12f62d15e3ef2f408dc60a906e06e474720ff45a blob + 767fe94a49c684c5c481bf515a8b19c4892dfe1c --- dulwich/tests/test_client.py +++ dulwich/tests/test_client.py @@ -1020,7 +1020,20 @@ class HttpGitClientTests(TestCase): b64_credentials = base64.b64encode(auth_string.encode("latin1")) 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" @@ -1029,6 +1042,20 @@ class HttpGitClientTests(TestCase): 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)