Skip to content

Commit ca14fee

Browse files
committed
dulwich: support interactive auth for http
1 parent 57432b4 commit ca14fee

File tree

2 files changed

+49
-4
lines changed

2 files changed

+49
-4
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ module = [
7878
"asyncssh.*",
7979
"pygit2.*",
8080
"pytest_docker.plugin",
81+
"urllib3.*",
8182
]
8283
ignore_missing_imports = true
8384

src/scmrepo/git/backend/dulwich/client.py

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
from typing import Optional
1+
import os
2+
from typing import Any, Dict, Optional
23

3-
from dulwich.client import Urllib3HttpGitClient
4+
from dulwich.client import HTTPUnauthorized, Urllib3HttpGitClient
45

56
from scmrepo.git.credentials import Credential, CredentialNotFoundError
67

@@ -37,8 +38,51 @@ def __init__(
3738
self.pool_manager.headers.update(basic_auth)
3839
self._store_credentials = creds
3940

40-
def _http_request(self, *args, **kwargs):
41-
result = super()._http_request(*args, **kwargs)
41+
def _http_request(
42+
self,
43+
url: str,
44+
headers: Optional[Dict[str, str]] = None,
45+
data: Any = None,
46+
):
47+
try:
48+
result = super()._http_request(url, headers=headers, data=data)
49+
except HTTPUnauthorized:
50+
auth_header = self._get_auth()
51+
if not auth_header:
52+
raise
53+
if headers:
54+
headers.update(auth_header)
55+
else:
56+
headers = auth_header
57+
result = super()._http_request(url, headers=headers, data=data)
4258
if self._store_credentials is not None:
4359
self._store_credentials.approve()
4460
return result
61+
62+
def _get_auth(self) -> Dict[str, str]:
63+
from getpass import getpass
64+
65+
from urllib3.util import make_headers
66+
67+
try:
68+
creds = Credential(username=self._username, url=self._base_url).fill()
69+
self._store_credentials = creds
70+
return make_headers(basic_auth=f"{creds.username}:{creds.password}")
71+
except CredentialNotFoundError:
72+
pass
73+
74+
if os.environ.get("GIT_TERMINAL_PROMPT") == "0":
75+
return {}
76+
77+
try:
78+
if self._username:
79+
username = self._username
80+
else:
81+
username = input(f"Username for '{self._base_url}': ")
82+
if self._password:
83+
password = self._password
84+
else:
85+
password = getpass(f"Password for '{self._base_url}': ")
86+
return make_headers(basic_auth=f"{username}:{password}")
87+
except KeyboardInterrupt:
88+
return {}

0 commit comments

Comments
 (0)