Commit b7efecd8 by Marc-André Dufresne Committed by Sébastien Eustace

Adding support for HTTP Basic Auth when installing and searching from legacy repo (#233) (#306)

* Adding support for HTTP Basic Auth when pulling from legacy repo

* added docs

* Adding unit test for http auth

* Adding mock to dev deps

* moved config reading logic to helper function, adapted test

* corrections

* rework pip_installer

* use source_reference as repo name when writing lock file and installing
parent eea60483
......@@ -32,3 +32,5 @@ MANIFEST.in
pyproject.lock
/tests/fixtures/simple_project/setup.py
.mypy_cache
.venv
......@@ -63,3 +63,8 @@ url = "https://foo.bar/simple/"
```
From now on, Poetry will also look for packages in your private repository.
If your private repository requires HTTP Basic Auth be sure to add the username and
password to your `http-basic` config using the example above (be sure to use the
same name than in the `tool.poetry.source` section). Poetry will use these values
to authenticate to your private repository when downloading or looking for packages.
......@@ -3,6 +3,9 @@ import tempfile
from subprocess import CalledProcessError
from poetry.utils.helpers import get_http_basic_auth
try:
import urllib.parse as urlparse
except ImportError:
......@@ -32,7 +35,19 @@ class PipInstaller(BaseInstaller):
)
args += ["--trusted-host", parsed.netloc]
args += ["--index-url", package.source_url]
auth = get_http_basic_auth(package.source_reference)
if auth:
index_url = "{scheme}://{username}:{password}@{netloc}{path}".format(
scheme=parsed.scheme,
username=auth[0],
password=auth[1],
netloc=parsed.netloc,
path=parsed.path,
)
else:
index_url = package.source_url
args += ["--index-url", index_url]
if update:
args.append("-U")
......
from poetry.locations import CONFIG_DIR
from poetry.utils._compat import Path
from poetry.utils.helpers import get_http_basic_auth
from poetry.utils.toml_file import TomlFile
from .uploader import Uploader
......@@ -64,18 +65,10 @@ class Publisher:
url = config["repositories"][repository_name]["url"]
if not (username and password):
auth_file = TomlFile(Path(CONFIG_DIR) / "auth.toml")
if auth_file.exists():
auth_config = auth_file.read(raw=True)
if (
"http-basic" in auth_config
and repository_name in auth_config["http-basic"]
):
config = auth_config["http-basic"][repository_name]
username = config.get("username")
password = config.get("password")
auth = get_http_basic_auth(repository_name)
if auth:
username = auth[0]
password = auth[1]
# Requesting missing credentials
if not username:
......
......@@ -28,6 +28,7 @@ from cachy import CacheManager
import poetry.packages
from poetry.config import Config
from poetry.locations import CACHE_DIR
from poetry.masonry.publishing.uploader import wheel_file_re
from poetry.packages import Package
......@@ -37,7 +38,7 @@ from poetry.semver import parse_constraint
from poetry.semver import Version
from poetry.semver import VersionConstraint
from poetry.utils._compat import Path
from poetry.utils.helpers import canonicalize_name
from poetry.utils.helpers import canonicalize_name, get_http_basic_auth
from poetry.version.markers import InvalidMarker
from .pypi_repository import PyPiRepository
......@@ -159,6 +160,10 @@ class LegacyRepository(PyPiRepository):
requests.session(), cache=FileCache(str(self._cache_dir / "_http"))
)
url_parts = urlparse.urlparse(self._url)
if not url_parts.username:
self._session.auth = get_http_basic_auth(self.name)
self._disable_cache = disable_cache
@property
......@@ -237,6 +242,7 @@ class LegacyRepository(PyPiRepository):
package = poetry.packages.Package(name, version, version)
package.source_type = "legacy"
package.source_url = self._url
package.source_reference = self.name
requires_dist = release_info["requires_dist"] or []
for req in requires_dist:
......@@ -333,6 +339,13 @@ class LegacyRepository(PyPiRepository):
return data
def _download(self, url, dest): # type: (str, str) -> None
r = self._session.get(url, stream=True)
with open(dest, "wb") as f:
for chunk in r.iter_content(chunk_size=1024):
if chunk:
f.write(chunk)
def _get(self, endpoint): # type: (str) -> Union[Page, None]
url = self._url + endpoint
response = self._session.get(url)
......
......@@ -5,6 +5,7 @@ import tempfile
from contextlib import contextmanager
from typing import Union
from poetry.config import Config
from poetry.version import Version
_canonicalize_regex = re.compile("[-_]+")
......@@ -77,3 +78,11 @@ def parse_requires(requires): # type: (str) -> Union[list, None]
if requires_dist:
return requires_dist
def get_http_basic_auth(repository_name): # type: (str) -> tuple
config = Config.create("auth.toml")
repo_auth = config.setting("http-basic.{}".format(repository_name))
if repo_auth:
return repo_auth["username"], repo_auth["password"]
return None
import pytest
from poetry.repositories.legacy_repository import LegacyRepository
from poetry.repositories.legacy_repository import Page
from poetry.utils._compat import Path
from poetry.utils._compat import decode
class MockRepository(LegacyRepository):
......@@ -43,3 +40,13 @@ def test_page_absolute_links_path_are_correct():
for link in page.links:
assert link.netloc == "files.pythonhosted.org"
assert link.path.startswith("/packages/")
def test_http_basic_auth_repo(mocker):
mock = mocker.patch("poetry.repositories.legacy_repository.get_http_basic_auth")
mock.return_value = ("user1", "p4ss")
repo = MockRepository()
mock.assert_called_once_with("legacy")
assert repo._session.auth == ("user1", "p4ss")
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