Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 8 commits into from
Jul 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ MANIFEST.in
pyproject.lock
/tests/fixtures/simple_project/setup.py
.mypy_cache

.venv
5 changes: 5 additions & 0 deletions docs/docs/repositories.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
17 changes: 16 additions & 1 deletion poetry/installation/pip_installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

from subprocess import CalledProcessError

from poetry.utils.helpers import get_http_basic_auth


try:
import urllib.parse as urlparse
except ImportError:
Expand Down Expand Up @@ -32,7 +35,19 @@ def install(self, package, update=False):
)
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")
Expand Down
17 changes: 5 additions & 12 deletions poetry/masonry/publishing/publisher.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
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
Expand Down Expand Up @@ -64,18 +65,10 @@ def publish(self, repository_name, username, password):
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:
Expand Down
15 changes: 14 additions & 1 deletion poetry/repositories/legacy_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

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
Expand All @@ -37,7 +38,7 @@
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
Expand Down Expand Up @@ -159,6 +160,10 @@ def __init__(self, name, url, disable_cache=False):
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
Expand Down Expand Up @@ -237,6 +242,7 @@ def package(
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:
Expand Down Expand Up @@ -333,6 +339,13 @@ def _get_release_info(self, name, version): # type: (str, str) -> dict

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)
Expand Down
9 changes: 9 additions & 0 deletions poetry/utils/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from contextlib import contextmanager
from typing import Union

from poetry.config import Config
from poetry.version import Version

_canonicalize_regex = re.compile("[-_]+")
Expand Down Expand Up @@ -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
13 changes: 10 additions & 3 deletions tests/repositories/test_legacy_repository.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
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):
Expand Down Expand Up @@ -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")