Commit b2b8c859 by Arun Babu Neelicattu Committed by Bjorn Neergaard

ensure git repository authn uses exact urls

Since git repository authentication is a special case of repository
configuration, the existing assumptions around path matching do not
apply. In order to prevent unexpected behaviour due to similar path
matching, git authentication will use exact url matching.
parent 404ab141
...@@ -245,8 +245,10 @@ class Authenticator: ...@@ -245,8 +245,10 @@ class Authenticator:
return self._credentials[key] return self._credentials[key]
def _get_credentials_for_url(self, url: str) -> HTTPAuthCredential: def _get_credentials_for_url(
repository = self.get_repository_config_for_url(url) self, url: str, exact_match: bool = False
) -> HTTPAuthCredential:
repository = self.get_repository_config_for_url(url, exact_match)
credential = ( credential = (
self._get_credentials_for_repository(repository=repository) self._get_credentials_for_repository(repository=repository)
...@@ -267,6 +269,14 @@ class Authenticator: ...@@ -267,6 +269,14 @@ class Authenticator:
return credential return credential
def get_credentials_for_git_url(self, url: str) -> HTTPAuthCredential:
key = f"git+{url}"
if key not in self._credentials:
self._credentials[key] = self._get_credentials_for_url(url, True)
return self._credentials[key]
def get_credentials_for_url(self, url: str) -> HTTPAuthCredential: def get_credentials_for_url(self, url: str) -> HTTPAuthCredential:
parsed_url = urllib.parse.urlsplit(url) parsed_url = urllib.parse.urlsplit(url)
netloc = parsed_url.netloc netloc = parsed_url.netloc
...@@ -338,13 +348,17 @@ class Authenticator: ...@@ -338,13 +348,17 @@ class Authenticator:
@functools.lru_cache(maxsize=None) @functools.lru_cache(maxsize=None)
def get_repository_config_for_url( def get_repository_config_for_url(
self, url: str self, url: str, exact_match: bool = False
) -> AuthenticatorRepositoryConfig | None: ) -> AuthenticatorRepositoryConfig | None:
parsed_url = urllib.parse.urlsplit(url) parsed_url = urllib.parse.urlsplit(url)
candidates_netloc_only = [] candidates_netloc_only = []
candidates_path_match = [] candidates_path_match = []
for repository in self.configured_repositories.values(): for repository in self.configured_repositories.values():
if exact_match:
if parsed_url.path == repository.path:
return repository
continue
if repository.netloc == parsed_url.netloc: if repository.netloc == parsed_url.netloc:
if parsed_url.path.startswith(repository.path) or commonprefix( if parsed_url.path.startswith(repository.path) or commonprefix(
......
...@@ -186,7 +186,7 @@ class Git: ...@@ -186,7 +186,7 @@ class Git:
client: GitClient client: GitClient
path: str path: str
credentials = get_default_authenticator().get_credentials_for_url(url=url) credentials = get_default_authenticator().get_credentials_for_git_url(url=url)
client, path = get_transport_and_path( # type: ignore[no-untyped-call] client, path = get_transport_and_path( # type: ignore[no-untyped-call]
url, username=credentials.username, password=credentials.password url, username=credentials.username, password=credentials.password
) )
......
...@@ -560,3 +560,38 @@ def test_authenticator_add_repository( ...@@ -560,3 +560,38 @@ def test_authenticator_add_repository(
basic_auth = base64.b64encode(b"foo:bar").decode() basic_auth = base64.b64encode(b"foo:bar").decode()
assert request.headers["Authorization"] == f"Basic {basic_auth}" assert request.headers["Authorization"] == f"Basic {basic_auth}"
def test_authenticator_git_repositories(
config: Config,
mock_remote: None,
http: type[httpretty.httpretty],
with_simple_keyring: None,
dummy_keyring: DummyBackend,
):
config.merge(
{
"repositories": {
"one": {"url": "https://foo.bar/org/one.git"},
"two": {"url": "https://foo.bar/org/two.git"},
},
"http-basic": {
"one": {"username": "foo", "password": "bar"},
"two": {"username": "baz", "password": "qux"},
},
}
)
authenticator = Authenticator(config, NullIO())
one = authenticator.get_credentials_for_git_url("https://foo.bar/org/one.git")
assert one.username == "foo"
assert one.password == "bar"
two = authenticator.get_credentials_for_git_url("https://foo.bar/org/two.git")
assert two.username == "baz"
assert two.password == "qux"
three = authenticator.get_credentials_for_git_url("https://foo.bar/org/three.git")
assert not three.username
assert not three.password
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment