예제 #1
0
def test_get_credentials_uses_cached_credentials():
    auth = MultiDomainBasicAuth()
    auth.passwords['example.com'] = ('user', 'pass')

    got = auth._get_url_and_credentials("http://*****:*****@example.com/path")
    expected = ('http://example.com/path', 'user', 'pass')
    assert got == expected
예제 #2
0
def test_get_credentials_uses_cached_credentials_only_username() -> None:
    auth = MultiDomainBasicAuth()
    auth.passwords["example.com"] = ("user", "pass")

    got = auth._get_url_and_credentials("http://[email protected]/path")
    expected = ("http://example.com/path", "user", "pass")
    assert got == expected
예제 #3
0
def test_get_credentials_not_to_uses_cached_credentials() -> None:
    auth = MultiDomainBasicAuth()
    auth.passwords["example.com"] = ("user", "pass")

    got = auth._get_url_and_credentials("http://*****:*****@example.com/path")
    expected = ("http://example.com/path", "foo", "bar")
    assert got == expected
예제 #4
0
def test_keyring_get_credential(monkeypatch, url, expect):
    monkeypatch.setattr(pip._internal.network.auth, 'keyring',
                        KeyringModuleV2())
    auth = MultiDomainBasicAuth(index_urls=["http://example.com/path2"])

    assert auth._get_new_credentials(url,
                                     allow_netrc=False,
                                     allow_keyring=True) == expect
예제 #5
0
def test_keyring_get_password(monkeypatch, url, expect):
    keyring = KeyringModuleV1()
    monkeypatch.setattr('pip._internal.network.auth.keyring', keyring)
    auth = MultiDomainBasicAuth(index_urls=["http://example.com/path2"])

    actual = auth._get_new_credentials(url, allow_netrc=False,
                                       allow_keyring=True)
    assert actual == expect
예제 #6
0
def test_get_index_url_credentials():
    auth = MultiDomainBasicAuth(index_urls=["http://*****:*****@example.com/path"])
    get = functools.partial(auth._get_new_credentials,
                            allow_netrc=False,
                            allow_keyring=False)

    # Check resolution of indexes
    assert get("http://example.com/path/path2") == ('foo', 'bar')
    assert get("http://example.com/path3/path2") == (None, None)
예제 #7
0
def test_keyring_get_password_username_in_index(monkeypatch):
    keyring = KeyringModuleV1()
    monkeypatch.setattr('pip._internal.network.auth.keyring', keyring)
    auth = MultiDomainBasicAuth(index_urls=["http://[email protected]/path2"])
    get = functools.partial(auth._get_new_credentials,
                            allow_netrc=False,
                            allow_keyring=True)

    assert get("http://example.com/path2/path3") == ("user", "user!url")
    assert get("http://example.com/path4/path1") == (None, None)
예제 #8
0
def test_get_credentials_parses_correctly(input_url, url, username, password):
    auth = MultiDomainBasicAuth()
    get = auth._get_url_and_credentials

    # Check URL parsing
    assert get(input_url) == (url, username, password)
    assert (
        # There are no credentials in the URL
        (username is None and password is None) or
        # Credentials were found and "cached" appropriately
        auth.passwords['example.com'] == (username, password))
예제 #9
0
def test_keyring_get_password_after_prompt(monkeypatch):
    keyring = KeyringModuleV1()
    monkeypatch.setattr('pip._internal.network.auth.keyring', keyring)
    auth = MultiDomainBasicAuth()

    def ask_input(prompt):
        assert prompt == "User for example.com: "
        return "user"

    monkeypatch.setattr('pip._internal.network.auth.ask_input', ask_input)
    actual = auth._prompt_for_password("example.com")
    assert actual == ("user", "user!netloc", False)
예제 #10
0
def test_broken_keyring_disables_keyring(monkeypatch):
    keyring_broken = KeyringModuleBroken()
    monkeypatch.setattr(pip._internal.network.auth, 'keyring', keyring_broken)

    auth = MultiDomainBasicAuth(index_urls=["http://example.com/"])

    assert keyring_broken._call_count == 0
    for i in range(5):
        url = "http://example.com/path" + str(i)
        assert auth._get_new_credentials(url,
                                         allow_netrc=False,
                                         allow_keyring=True) == (None, None)
        assert keyring_broken._call_count == 1
예제 #11
0
def test_keyring_get_password(
    monkeypatch: pytest.MonkeyPatch,
    url: str,
    expect: Tuple[Optional[str], Optional[str]],
) -> None:
    keyring = KeyringModuleV1()
    monkeypatch.setattr("pip._internal.network.auth.keyring", keyring)
    auth = MultiDomainBasicAuth(index_urls=["http://example.com/path2"])

    actual = auth._get_new_credentials(url,
                                       allow_netrc=False,
                                       allow_keyring=True)
    assert actual == expect
예제 #12
0
def test_keyring_set_password(
    monkeypatch: pytest.MonkeyPatch,
    response_status: int,
    creds: Tuple[str, str, bool],
    expect_save: bool,
) -> None:
    keyring = KeyringModuleV1()
    monkeypatch.setattr("pip._internal.network.auth.keyring", keyring)
    auth = MultiDomainBasicAuth(prompting=True)
    monkeypatch.setattr(auth, "_get_url_and_credentials", lambda u:
                        (u, None, None))
    monkeypatch.setattr(auth, "_prompt_for_password", lambda *a: creds)
    if creds[2]:
        # when _prompt_for_password indicates to save, we should save
        def should_save_password_to_keyring(*a: Any) -> bool:
            return True

    else:
        # when _prompt_for_password indicates not to save, we should
        # never call this function
        def should_save_password_to_keyring(*a: Any) -> bool:
            assert False, "_should_save_password_to_keyring should not be called"

    monkeypatch.setattr(auth, "_should_save_password_to_keyring",
                        should_save_password_to_keyring)

    req = MockRequest("https://example.com")
    resp = MockResponse(b"")
    resp.url = req.url
    connection = MockConnection()

    def _send(sent_req: MockRequest, **kwargs: Any) -> MockResponse:
        assert sent_req is req
        assert "Authorization" in sent_req.headers
        r = MockResponse(b"")
        r.status_code = response_status
        return r

    # https://github.com/python/mypy/issues/2427
    connection._send = _send  # type: ignore[assignment]

    resp.request = req
    resp.status_code = 401
    resp.connection = connection

    auth.handle_401(resp)

    if expect_save:
        assert keyring.saved_passwords == [("example.com", creds[0], creds[1])]
    else:
        assert keyring.saved_passwords == []
예제 #13
0
def test_keyring_set_password(monkeypatch, response_status, creds,
                              expect_save):
    keyring = KeyringModuleV1()
    monkeypatch.setattr('pip._internal.network.auth.keyring', keyring)
    auth = MultiDomainBasicAuth(prompting=True)
    monkeypatch.setattr(auth, '_get_url_and_credentials', lambda u:
                        (u, None, None))
    monkeypatch.setattr(auth, '_prompt_for_password', lambda *a: creds)
    if creds[2]:
        # when _prompt_for_password indicates to save, we should save
        def should_save_password_to_keyring(*a):
            return True
    else:
        # when _prompt_for_password indicates not to save, we should
        # never call this function
        def should_save_password_to_keyring(*a):
            assert False, ("_should_save_password_to_keyring should not be " +
                           "called")

    monkeypatch.setattr(auth, '_should_save_password_to_keyring',
                        should_save_password_to_keyring)

    req = MockRequest("https://example.com")
    resp = MockResponse(b"")
    resp.url = req.url
    connection = MockConnection()

    def _send(sent_req, **kwargs):
        assert sent_req is req
        assert "Authorization" in sent_req.headers
        r = MockResponse(b"")
        r.status_code = response_status
        return r

    connection._send = _send

    resp.request = req
    resp.status_code = 401
    resp.connection = connection

    auth.handle_401(resp)

    if expect_save:
        assert keyring.saved_passwords == [("example.com", creds[0], creds[1])]
    else:
        assert keyring.saved_passwords == []
예제 #14
0
def test_keyring_get_password_after_prompt_when_none(monkeypatch):
    keyring = KeyringModuleV1()
    monkeypatch.setattr('pip._internal.network.auth.keyring', keyring)
    auth = MultiDomainBasicAuth()

    def ask_input(prompt):
        assert prompt == "User for unknown.com: "
        return "user"

    def ask_password(prompt):
        assert prompt == "Password: "******"fake_password"

    monkeypatch.setattr('pip._internal.network.auth.ask_input', ask_input)
    monkeypatch.setattr('pip._internal.network.auth.ask_password',
                        ask_password)
    actual = auth._prompt_for_password("unknown.com")
    assert actual == ("user", "fake_password", True)
예제 #15
0
    def __init__(
        self,
        *args: Any,
        retries: int = 0,
        cache: Optional[str] = None,
        trusted_hosts: Sequence[str] = (),
        index_urls: Optional[List[str]] = None,
        **kwargs: Any,
    ) -> None:
        """
        :param trusted_hosts: Domains not to emit warnings for when not using
            HTTPS.
        """
        super().__init__(*args, **kwargs)

        # Namespace the attribute with "pip_" just in case to prevent
        # possible conflicts with the base class.
        self.pip_trusted_origins: List[Tuple[str, Optional[int]]] = []

        # Attach our User Agent to the request
        self.headers["User-Agent"] = user_agent()

        # Attach our Authentication handler to the session
        self.auth = MultiDomainBasicAuth(index_urls=index_urls)

        # Create our urllib3.Retry instance which will allow us to customize
        # how we handle retries.
        retries = urllib3.Retry(
            # Set the total number of retries that a particular request can
            # have.
            total=retries,
            # A 503 error from PyPI typically means that the Fastly -> Origin
            # connection got interrupted in some way. A 503 error in general
            # is typically considered a transient error so we'll go ahead and
            # retry it.
            # A 500 may indicate transient error in Amazon S3
            # A 520 or 527 - may indicate transient error in CloudFlare
            status_forcelist=[500, 503, 520, 527],
            # Add a small amount of back off between failed requests in
            # order to prevent hammering the service.
            backoff_factor=0.25,
        )  # type: ignore

        # Our Insecure HTTPAdapter disables HTTPS validation. It does not
        # support caching so we'll use it for all http:// URLs.
        # If caching is disabled, we will also use it for
        # https:// hosts that we've marked as ignoring
        # TLS errors for (trusted-hosts).
        insecure_adapter = InsecureHTTPAdapter(max_retries=retries)

        # We want to _only_ cache responses on securely fetched origins or when
        # the host is specified as trusted. We do this because
        # we can't validate the response of an insecurely/untrusted fetched
        # origin, and we don't want someone to be able to poison the cache and
        # require manual eviction from the cache to fix it.
        if cache:
            secure_adapter = CacheControlAdapter(
                cache=SafeFileCache(cache),
                max_retries=retries,
            )
            self._trusted_host_adapter = InsecureCacheControlAdapter(
                cache=SafeFileCache(cache),
                max_retries=retries,
            )
        else:
            secure_adapter = HTTPAdapter(max_retries=retries)
            self._trusted_host_adapter = insecure_adapter

        self.mount("https://", secure_adapter)
        self.mount("http://", insecure_adapter)

        # Enable file:// urls
        self.mount("file://", LocalFSAdapter())

        for host in trusted_hosts:
            self.add_trusted_host(host, suppress_logging=True)
예제 #16
0
    def __init__(self, *args, **kwargs):
        """
        :param trusted_hosts: Domains not to emit warnings for when not using
            HTTPS.
        """
        retries = kwargs.pop("retries", 0)
        cache = kwargs.pop("cache", None)
        trusted_hosts = kwargs.pop("trusted_hosts", [])  # type: List[str]
        index_urls = kwargs.pop("index_urls", None)

        super(PipSession, self).__init__(*args, **kwargs)

        # Namespace the attribute with "pip_" just in case to prevent
        # possible conflicts with the base class.
        self.pip_trusted_origins = []  # type: List[Tuple[str, Optional[int]]]

        # Attach our User Agent to the request
        self.headers["User-Agent"] = user_agent()

        # Attach our Authentication handler to the session
        self.auth = MultiDomainBasicAuth(index_urls=index_urls)

        # Create our urllib3.Retry instance which will allow us to customize
        # how we handle retries.
        retries = urllib3.Retry(
            # Set the total number of retries that a particular request can
            # have.
            total=retries,

            # A 503 error from PyPI typically means that the Fastly -> Origin
            # connection got interrupted in some way. A 503 error in base
            # is typically considered a transient error so we'll go ahead and
            # retry it.
            # A 500 may indicate transient error in Amazon S3
            # A 520 or 527 - may indicate transient error in CloudFlare
            status_forcelist=[500, 503, 520, 527],

            # Add a small amount of back off between failed requests in
            # order to prevent hammering the service.
            backoff_factor=0.25,
        )

        # Check to ensure that the directory containing our cache directory
        # is owned by the user current executing pip. If it does not exist
        # we will check the parent directory until we find one that does exist.
        if cache and not check_path_owner(cache):
            logger.warning(
                "The directory '%s' or its parent directory is not owned by "
                "the current user and the cache has been disabled. Please "
                "check the permissions and owner of that directory. If "
                "executing pip with sudo, you may want sudo's -H flag.",
                cache,
            )
            cache = None

        # We want to _only_ cache responses on securely fetched origins. We do
        # this because we can't validate the response of an insecurely fetched
        # origin, and we don't want someone to be able to poison the cache and
        # require manual eviction from the cache to fix it.
        if cache:
            secure_adapter = CacheControlAdapter(
                cache=SafeFileCache(cache),
                max_retries=retries,
            )
        else:
            secure_adapter = HTTPAdapter(max_retries=retries)

        # Our Insecure HTTPAdapter disables HTTPS validation. It does not
        # support caching (see above) so we'll use it for all http:// URLs as
        # well as any https:// host that we've marked as ignoring TLS errors
        # for.
        insecure_adapter = InsecureHTTPAdapter(max_retries=retries)
        # Save this for later use in add_insecure_host().
        self._insecure_adapter = insecure_adapter

        self.mount("https://", secure_adapter)
        self.mount("http://", insecure_adapter)

        # Enable file:// urls
        self.mount("file://", LocalFSAdapter())

        for host in trusted_hosts:
            self.add_trusted_host(host, suppress_logging=True)