Repository: python-poetry/poetry

Issue:
Setting credentials through env. variable are not working
<!-- Checked checkbox should look like this: [x] -->
- [ x ] I am on the [latest](https://github.com/python-poetry/poetry/releases/latest) Poetry version.
- [ x ] I have searched the [issues](https://github.com/python-poetry/poetry/issues) of this repo and believe that this is not a duplicate.
- [ x ] If an exception occurs when executing a command, I executed it again in debug mode (`-vvv` option).

<!--
  Once those are done, if you're able to fill in the following list with your information,
  it'd be very helpful to whoever handles the issue.
-->

- **OS version and name**: *nix
- **Poetry version**: Poetry version 1.0.0

## Issue
<!-- Now feel free to write your issue, but please be descriptive! Thanks again 🙌 ❤️ -->
I'm failing to use env. variables to set custom pypi credentials. 

My pyproject.toml contains private pypi's like this:
```toml
[[tool.poetry.source]]
url = "https://XXXXX/nexus/repository/pypi-central/simple"
name = "nexus"
```
I'm running this script:
```sh
export POETRY_HTTP_BASIC_NEXUS_USERNAME=****
export POETRY_HTTP_BASIC_NEXUS_PASSWORD=****
poetry install
```
and it fails with:
```
[EnvCommandError]
Command ['/opt/.cache/pypoetry/virtualenvs/YYYY-4zvP7SOo-py3.8/bin/pip', 'install', '--no-deps', '--index-url', 'https://XXXXX/nexus/repository/pypi-central/simple', '--extra-index-url', 'https://pypi.org/', 'six==1.12.0'] errored with the following return code 2, and output: 
Looking in indexes: https://RESOLVED-XXXXX/nexus/repository/pypi-central/simple, https://****:****@XXXXX/nexus/repository/epd-pypi/simple, https://pypi.org/
Collecting six==1.12.0

....

File "/opt/.cache/pypoetry/virtualenvs/YYYY-4zvP7SOo-py3.8/lib/python3.8/site-packages/pip/_internal/download.py", line 386, in handle_401
    username, password, save = self._prompt_for_password(parsed.netloc)
  File "/opt/.cache/pypoetry/virtualenvs/YYYY-4zvP7SOo-py3.8/lib/python3.8/site-packages/pip/_internal/download.py", line 358, in _prompt_for_password
    username = ask_input("User for %s: " % netloc)
  File "/opt/.cache/pypoetry/virtualenvs/YYYY-4zvP7SOo-py3.8/lib/python3.8/site-packages/pip/_internal/utils/misc.py", line 281, in ask_input
    return input(message)
EOFError: EOF when reading a line
User for XXXXX: 
```

I investigated the code and it seems that credentials are never acquired separately from config, but always as a pair. That means that code never ask for `http-basic.nexus.password` and `http-basic.nexus.username`, but for `http-basic.nexus` then the value is used as a dict (search for `password_manager.get_http_auth` usage). I could not find single test case, so I wrote one, fill free to use it:
```diff
diff --git a/tests/config/test_config.py b/tests/config/test_config.py
index 07373ad..72ad236 100644
--- a/tests/config/test_config.py
+++ b/tests/config/test_config.py
@@ -14,3 +14,13 @@ def test_config_get_from_environment_variable(config, environ):

     os.environ["POETRY_VIRTUALENVS_CREATE"] = "false"
     assert not config.get("virtualenvs.create")
+
+def test_basic_http_credentials_through_env(config, environ):
+    assert config.get("http-basic.test_repo") is None
+
+    os.environ["POETRY_HTTP_BASIC_TEST_REPO_USERNAME"] = "foo"
+    os.environ["POETRY_HTTP_BASIC_TEST_REPO_PASSWORD"] = "bar"
+    credentials = config.get("http-basic.test-repo")
+    assert credentials is not None
+    assert credentials["username"] == "foo"
+    assert credentials["password"] == "bar"
```


Discussion:
I had a similar issue today. I spent a good part of my evening looking at poetry's source code. It seems, based on poetry's pyproject.toml, that poetry runs on anything python v2.7 thru v3.6.
Have you worked on your issue using, perhaps v3.6 or below?
Nope, I was trying on python 3.7.5 and some 3.8, I think :(

Resolving patch:
diff --git a/poetry/utils/password_manager.py b/poetry/utils/password_manager.py
--- a/poetry/utils/password_manager.py
+++ b/poetry/utils/password_manager.py
@@ -155,11 +155,14 @@ def delete_pypi_token(self, name):
     def get_http_auth(self, name):
         auth = self._config.get("http-basic.{}".format(name))
         if not auth:
-            return None
-
-        username, password = auth["username"], auth.get("password")
-        if password is None:
-            password = self.keyring.get_password(name, username)
+            username = self._config.get("http-basic.{}.username".format(name))
+            password = self._config.get("http-basic.{}.password".format(name))
+            if not username and not password:
+                return None
+        else:
+            username, password = auth["username"], auth.get("password")
+            if password is None:
+                password = self.keyring.get_password(name, username)
 
         return {
             "username": username,


Test patch:
diff --git a/tests/utils/test_password_manager.py b/tests/utils/test_password_manager.py
--- a/tests/utils/test_password_manager.py
+++ b/tests/utils/test_password_manager.py
@@ -1,3 +1,5 @@
+import os
+
 import pytest
 
 from keyring.backend import KeyringBackend
@@ -208,3 +210,17 @@ def test_keyring_with_chainer_backend_and_not_compatible_only_should_be_unavaila
     key_ring = KeyRing("poetry")
 
     assert not key_ring.is_available()
+
+
+def test_get_http_auth_from_environment_variables(
+    environ, config, mock_available_backend
+):
+    os.environ["POETRY_HTTP_BASIC_FOO_USERNAME"] = "bar"
+    os.environ["POETRY_HTTP_BASIC_FOO_PASSWORD"] = "baz"
+
+    manager = PasswordManager(config)
+
+    auth = manager.get_http_auth("foo")
+
+    assert "bar" == auth["username"]
+    assert "baz" == auth["password"]