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
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
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
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
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
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)
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)
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))
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)
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
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
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 == []
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 == []
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)
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)
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)