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

Feat: Added option to disable SSL verify #3676

Closed
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ed1819c
feat: add trusted option to repository on develop branch, but require…
Celeborn2BeAlive May 29, 2020
7c056a7
removed redundant double check of http scheme
maayanbar13 Sep 12, 2020
af7b1e7
Added trusted source tests and fixture to test_factory
maayanbar13 Sep 12, 2020
c3dccac
Added trusted source tests to pip_installer
maayanbar13 Sep 12, 2020
92dad18
Merge branch 'master' of https://github.com/python-poetry/poetry into…
maayanbar13 Feb 6, 2021
2304072
Implemented saving trusted state in cert configuration
maayanbar13 Feb 7, 2021
e0711ca
Fixed handling trusted as str and being overriden by default certific…
maayanbar13 Feb 8, 2021
f4c52a7
doc: Added docs about configurating trusted repositories in poetry co…
maayanbar13 Feb 10, 2021
9e40186
fix: Fixed bug where warnings are not reset to default when the reque…
maayanbar13 Feb 10, 2021
423236a
Apply suggestions from code review
maayanbar13 Aug 19, 2021
624c7ce
Fixed conflicts with latest upstream
maayanbar13 Aug 19, 2021
0270182
Fixed typo in get_truested
maayanbar13 Sep 25, 2021
514a531
Merge branch 'option-to-disable-ssl-verify-develop' of https://github…
maayanbar13 Sep 25, 2021
1be75fa
Fixed merge conflicts with latest changes
maayanbar13 Mar 28, 2022
20b31e6
Fixed lint issues
maayanbar13 Apr 7, 2022
28f5087
Fixed merge conflicts
maayanbar13 Apr 21, 2022
b90c3db
Fixed fstring formatting according to pyupgrade
maayanbar13 Apr 21, 2022
54656d3
Merged latest changes
maayanbar13 May 27, 2022
be3e319
Added trusted host verification for authenticator and legacy reposito…
maayanbar13 May 27, 2022
986fb2b
Updated tests according to authenticator changes
maayanbar13 May 27, 2022
270ceb1
Reverted small changes relative to dev
maayanbar13 May 27, 2022
61a65a7
Moved trusted option to seperate property then certs
maayanbar13 May 27, 2022
cbac250
Fixed test monkeypatch
maayanbar13 May 28, 2022
8b84ca6
Fixed acciderntaly deleted files in conflict merge and moved the trus…
maayanbar13 May 28, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 12 additions & 4 deletions docs/repositories.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ on PyPI.

This represents most cases and will likely be enough for most users.


## Using a private repository

However, at times, you may need to keep your package private while still being
Expand Down Expand Up @@ -65,8 +64,8 @@ call to `config`.
```bash
poetry config http-basic.pypi username password
```
{{% /note %}}

{{% /note %}}

You can also specify the username and password when using the `publish` command
with the `--username` and `--password` options.
Expand Down Expand Up @@ -110,8 +109,9 @@ poetry config -- http-basic.pypi myUsername -myPasswordStartingWithDash
```

#### Custom certificate authority and mutual TLS authentication

Poetry supports repositories that are secured by a custom certificate authority as well as those that require
certificate-based client authentication. The following will configure the "foo" repository to validate the repository's
certificate-based client authentication. The following will configure the "foo" repository to validate the repository's
certificate using a custom certificate authority and use a client certificate (note that these config variables do not
both need to be set):

Expand Down Expand Up @@ -147,6 +147,7 @@ name = "foo"
url = "https://foo.bar/simple/"
secondary = true
```

{{% /note %}}

If your private repository requires HTTP Basic Auth be sure to add the username and
Expand All @@ -156,7 +157,6 @@ a custom certificate authority or client certificates, similarly refer to the ex
`certificates` section. Poetry will use these values to authenticate to your private repository when downloading or
looking for packages.


### Disabling the PyPI repository

If you want your packages to be exclusively looked up from a private
Expand All @@ -170,3 +170,11 @@ default = true
```

A default source will also be the fallback source if you add other sources.

### Trusting a repository

You can bypass SSL verification for a repository if you know it can be trusted (useful for private repositories):

```bash
poetry config certificates.foo.trusted true
```
21 changes: 19 additions & 2 deletions src/poetry/console/commands/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,20 +255,37 @@ def handle(self) -> int | None:

# handle certs
m = re.match(
r"(?:certificates)\.([^.]+)\.(cert|client-cert)", self.argument("key")
r"(?:certificates)\.([^.]+)\.(cert|client-cert|trusted)",
self.argument("key"),
)
if m:
key = f"certificates.{m.group(1)}.{m.group(2)}"
if self.option("unset"):
config.auth_config_source.remove_property(
f"certificates.{m.group(1)}.{m.group(2)}"
)

return 0

if m.group(2) == "trusted":
from poetry.config.config import boolean_normalizer
from poetry.config.config import boolean_validator

self._handle_single_value(
config.auth_config_source,
key,
(
boolean_validator,
boolean_normalizer,
False,
),
values,
)
if len(values) == 1:
config.auth_config_source.add_property(
f"certificates.{m.group(1)}.{m.group(2)}", values[0]
)
elif len(values) == 1:
config.auth_config_source.add_property(key, values[0])
else:
raise ValueError("You must pass exactly 1 value")

Expand Down
2 changes: 2 additions & 0 deletions src/poetry/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from poetry.plugins.plugin import Plugin
from poetry.plugins.plugin_manager import PluginManager
from poetry.poetry import Poetry
from poetry.utils.helpers import get_trusted


if TYPE_CHECKING:
Expand Down Expand Up @@ -175,6 +176,7 @@ def create_legacy_repository(
config=auth_config,
cert=get_cert(auth_config, name),
client_cert=get_client_cert(auth_config, name),
trusted=get_trusted(auth_config, name),
)

@classmethod
Expand Down
2 changes: 2 additions & 0 deletions src/poetry/installation/pip_installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ def install(self, package: Package, update: bool = False) -> None:
f" {parsed.hostname}</warning>"
)
args += ["--trusted-host", parsed.hostname]
elif repository.trusted:
args += ["--trusted-host", parsed.hostname]
maayanbar13 marked this conversation as resolved.
Show resolved Hide resolved

if repository.cert:
args += ["--cert", str(repository.cert)]
Expand Down
6 changes: 6 additions & 0 deletions src/poetry/repositories/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,13 @@ def __init__(
disable_cache: bool = False,
cert: Path | None = None,
client_cert: Path | None = None,
trusted: bool | None = False,
) -> None:
super().__init__(name, "_http", disable_cache)
self._url = url
self._client_cert = client_cert
self._cert = cert
self._trusted = trusted

self._authenticator = Authenticator(
config=config or Config(use_environment=True)
Expand Down Expand Up @@ -89,6 +91,10 @@ def cert(self) -> Path | None:
def client_cert(self) -> Path | None:
return self._client_cert

@property
def trusted(self) -> bool | None:
return self._trusted

@property
def authenticated_url(self) -> str:
if not self._session.auth:
Expand Down
3 changes: 2 additions & 1 deletion src/poetry/repositories/legacy_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@ def __init__(
disable_cache: bool = False,
cert: Path | None = None,
client_cert: Path | None = None,
trusted: bool | None = False,
) -> None:
if name == "pypi":
raise ValueError("The name [pypi] is reserved for repositories")

super().__init__(
name, url.rstrip("/"), config, disable_cache, cert, client_cert
name, url.rstrip("/"), config, disable_cache, cert, client_cert, trusted
)

def find_packages(self, dependency: Dependency) -> list[Package]:
Expand Down
8 changes: 8 additions & 0 deletions src/poetry/utils/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ def get_client_cert(config: Config, repository_name: str) -> Path | None:
return None


def get_trusted(config: Config, repository_name: str) -> bool | None:
trusted = config.get(f"certificates.{repository_name}.trusted")
if trusted:
return bool(trusted)
else:
return None


def _on_rm_error(func: Callable, path: str, exc_info: Exception) -> None:
if not os.path.exists(path):
return
Expand Down
10 changes: 10 additions & 0 deletions tests/console/commands/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,16 @@ def test_set_cert(
assert auth_config_source.config["certificates"]["foo"]["cert"] == "path/to/ca.pem"


def test_set_trusted(
tester: CommandTester, auth_config_source: DictConfigSource, mocker: MockerFixture
):
mocker.spy(ConfigSource, "__init__")

tester.execute("certificates.foo.trusted true")

assert auth_config_source.config["certificates"]["foo"]["trusted"] == "true"


def test_config_installer_parallel(
tester: CommandTester, command_tester_factory: CommandTesterFactory
):
Expand Down
2 changes: 2 additions & 0 deletions tests/fixtures/with_trusted_source/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
My Package
==========
62 changes: 62 additions & 0 deletions tests/fixtures/with_trusted_source/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
[tool.poetry]
name = "my-package"
version = "1.2.3"
description = "Some description."
authors = [
"Sébastien Eustace <sebastien@eustace.io>"
]
license = "MIT"

readme = "README.rst"

homepage = "https://python-poetry.org"
repository = "https://github.com/python-poetry/poetry"
documentation = "https://python-poetry.org/docs"

keywords = ["packaging", "dependency", "poetry"]

classifiers = [
"Topic :: Software Development :: Build Tools",
"Topic :: Software Development :: Libraries :: Python Modules"
]

# Requirements
[tool.poetry.dependencies]
python = "~2.7 || ^3.6"
cleo = "^0.6"
pendulum = { git = "https://github.com/sdispater/pendulum.git", branch = "2.0" }
requests = { version = "^2.18", optional = true, extras=[ "security" ] }
pathlib2 = { version = "^2.2", python = "~2.7" }

orator = { version = "^0.9", optional = true }

# File dependency
demo = { path = "../distributions/demo-0.1.0-py2.py3-none-any.whl" }

# Dir dependency with setup.py
my-package = { path = "../project_with_setup/" }

# Dir dependency with pyproject.toml
simple-project = { path = "../simple_project/" }


[tool.poetry.extras]
db = [ "orator" ]

[tool.poetry.dev-dependencies]
pytest = "~3.4"


[tool.poetry.scripts]
my-script = "my_package:main"


[tool.poetry.plugins."blogtool.parsers"]
".rst" = "some_module::SomeClass"


[[tool.poetry.source]]
name = "foo"
url = "https://foo.bar/simple/"
default = true
trusted = true
30 changes: 30 additions & 0 deletions tests/installation/test_pip_installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,36 @@ def test_requirement_git_develop_true(installer: PipInstaller, package_git: Pack
assert result == expected


def test_install_with_trusted_host():
pool = Pool()
host = "foo.bar"

default = LegacyRepository("default", f"https://{host}", trusted=True)

pool.add_repository(default, default=True)

null_env = NullEnv()

installer = PipInstaller(null_env, NullIO(), pool)

foo = Package(
"foo",
"0.0.0",
source_type="legacy",
source_reference=default._name,
source_url=default._url,
)

installer.install(foo)

assert len(null_env.executed) == 1
cmd = null_env.executed[0]
assert "--trusted-host" in cmd
trusted_host_index = cmd.index("--trusted-host")

assert cmd[trusted_host_index + 1] == host


def test_uninstall_git_package_nspkg_pth_cleanup(
mocker: MockerFixture, tmp_venv: VirtualEnv, pool: Pool
):
Expand Down
8 changes: 8 additions & 0 deletions tests/utils/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from poetry.utils.helpers import canonicalize_name
from poetry.utils.helpers import get_cert
from poetry.utils.helpers import get_client_cert
from poetry.utils.helpers import get_trusted


if TYPE_CHECKING:
Expand Down Expand Up @@ -86,6 +87,13 @@ def test_get_client_cert(config: Config):
assert get_client_cert(config, "foo") == Path(client_cert)


def test_get_trusted(config: Config):
trusted = "true"
config.merge({"certificates": {"foo": {"trusted": trusted}}})

assert get_trusted(config, "foo")


test_canonicalize_name_cases = [
("flask", "flask"),
("Flask", "flask"),
Expand Down