def console_output(self, targets): if targets: raise TaskError( 'The login task does not take any target arguments.') deprecated_conditional( lambda: self.get_passthru_args(), removal_version='1.26.0.dev1', entity_description='Using passthrough args with `./pants login`', hint_message= "Instead of passing the provider through `--login-passthrough-args` or the " "style `./pants login -- prod`, use the option `--login-to`, such as " "`./pants login --to=prod`.", ) # TODO: When we have other auth methods (e.g., OAuth2), select one by provider name. requested_providers = list( filter(None, [self.get_options().to] + self.get_passthru_args())) if len(requested_providers) != 1: raise TaskError('Must specify exactly one provider.') provider = requested_providers[0] try: BasicAuth.global_instance().authenticate(provider) return ['', 'Logged in successfully using .netrc credentials.'] except Challenged as e: creds = self._ask_for_creds(provider, e.url, e.realm) BasicAuth.global_instance().authenticate(provider, creds=creds) return ['', 'Logged in successfully.']
def execute(self): # TODO: When we have other auth methods (e.g., OAuth2), select one by provider name. requested_providers = list( filter(None, [self.get_options().to] + self.get_passthru_args())) if len(requested_providers) != 1: raise TaskError('Must specify exactly one provider.') # TODO: An interactive mode where we prompt for creds. Currently we assume they are in netrc. BasicAuth.global_instance().authenticate(requested_providers[0])
def _do_test_basic_auth(self, creds): with temporary_dir() as tmpcookiedir: cookie_file = os.path.join(tmpcookiedir, 'pants.test.cookies') self.context(for_subsystems=[BasicAuth, Cookies], options={ BasicAuth.options_scope: { 'providers': { 'foobar': { 'url': 'http://localhost:{}'.format( self.port) } } }, Cookies.options_scope: { 'path': cookie_file } }) basic_auth = BasicAuth.global_instance() cookies = Cookies.global_instance() self.assertListEqual([], list(cookies.get_cookie_jar())) basic_auth.authenticate(provider='foobar', creds=creds, cookies=cookies) cookies_list = list(cookies.get_cookie_jar()) self.assertEqual(1, len(cookies_list)) auth_cookie = cookies_list[0] self.assertEqual('test_auth_key', auth_cookie.name) self.assertEqual('test_auth_value', auth_cookie.value)
def test_basic_auth_with_bad_creds(self): self._do_test_basic_auth(creds=BasicAuthCreds('test_user', 'test_password')) basic_auth = BasicAuth.global_instance() cookies = Cookies.global_instance() bad_creds = BasicAuthCreds('test_user', 'bad_password') self.assertRaises(BasicAuthException, lambda: basic_auth.authenticate(provider='foobar', creds=bad_creds, cookies=cookies))
def console_output(self, targets): if targets: raise TaskError('The login task does not take any target arguments.') # TODO: When we have other auth methods (e.g., OAuth2), select one by provider name. requested_providers = list(filter(None, [self.get_options().to] + self.get_passthru_args())) if len(requested_providers) != 1: raise TaskError('Must specify exactly one provider.') provider = requested_providers[0] try: BasicAuth.global_instance().authenticate(provider) return ['', 'Logged in successfully using .netrc credentials.'] except Challenged as e: creds = self._ask_for_creds(provider, e.url, e.realm) BasicAuth.global_instance().authenticate(provider, creds=creds) return ['', 'Logged in successfully.']
def console_output(self, targets): if targets: raise TaskError( "The login task does not take any target arguments.") provider = self.get_options().to if provider is None: raise TaskError( "Please give the provider with `./pants login --to`. (Run " "`./pants help login` to see what this option expects.)") try: BasicAuth.global_instance().authenticate(provider) return ["", "Logged in successfully using .netrc credentials."] except Challenged as e: creds = self._ask_for_creds(provider, e.url, e.realm) BasicAuth.global_instance().authenticate(provider, creds=creds) return ["", "Logged in successfully."]
def console_output(self, targets): if targets: raise TaskError( 'The login task does not take any target arguments.') # TODO: When we have other auth methods (e.g., OAuth2), select one by provider name. requested_providers = list( filter(None, [self.get_options().to] + self.get_passthru_args())) if len(requested_providers) != 1: raise TaskError('Must specify exactly one provider.') provider = requested_providers[0] try: BasicAuth.global_instance().authenticate(provider) return ['', 'Logged in successfully using .netrc credentials.'] except Challenged as e: creds = self._ask_for_creds(provider, e.url, e.realm) BasicAuth.global_instance().authenticate(provider, creds=creds) return ['', 'Logged in successfully.']
def test_basic_auth_with_bad_creds(self): self._do_test_basic_auth( creds=BasicAuthCreds('test_user', 'test_password')) basic_auth = BasicAuth.global_instance() cookies = Cookies.global_instance() bad_creds = BasicAuthCreds('test_user', 'bad_password') self.assertRaises( BasicAuthException, lambda: basic_auth.authenticate( provider='foobar', creds=bad_creds, cookies=cookies))
def _do_test_basic_auth(self, creds): with self._test_options(): basic_auth = BasicAuth.global_instance() cookies = Cookies.global_instance() self.assertListEqual([], list(cookies.get_cookie_jar())) basic_auth.authenticate(provider='foobar', creds=creds, cookies=cookies) cookies_list = list(cookies.get_cookie_jar()) self.assertEqual(1, len(cookies_list)) auth_cookie = cookies_list[0] self.assertEqual('test_auth_key', auth_cookie.name) self.assertEqual('test_auth_value', auth_cookie.value)
def _do_test_basic_auth(self, creds): with self._test_options(): basic_auth = BasicAuth.global_instance() cookies = Cookies.global_instance() self.assertListEqual([], list(cookies.get_cookie_jar())) basic_auth.authenticate(provider="foobar", creds=creds, cookies=cookies) cookies_list = list(cookies.get_cookie_jar()) self.assertEqual(1, len(cookies_list)) auth_cookie = cookies_list[0] self.assertEqual("test_auth_key", auth_cookie.name) self.assertEqual("test_auth_value", auth_cookie.value)
def post_stats(cls, stats_url: str, stats: Dict[str, Any], timeout: int = 2, auth_provider: Optional[str] = None, stats_version: int = 1): """POST stats to the given url. :return: True if upload was successful, False otherwise. """ def error(msg): # Report aleady closed, so just print error. print( f'WARNING: Failed to upload stats to {stats_url} due to {msg}', file=sys.stderr) return False if stats_version not in cls.SUPPORTED_STATS_VERSIONS: raise ValueError("Invalid stats version") auth_data = BasicAuth.global_instance().get_auth_for_provider( auth_provider) headers = cls._get_headers(stats_version=stats_version) headers.update(auth_data.headers) if stats_version == 2: params = cls._json_dump_options({'builds': [stats]}) headers['Content-Type'] = 'application/json' else: # TODO(benjy): The upload protocol currently requires separate top-level params, with JSON # values. Probably better for there to be one top-level JSON value, namely json.dumps(stats). # But this will first require changing the upload receiver at every shop that uses this. params = { k: cls._json_dump_options(v) for (k, v) in stats.items() } # type: ignore[assignment] # We can't simply let requests handle redirects, as we only allow them for specific codes: # 307 and 308 indicate that the redirected request must use the same method, POST in this case. # So they indicate a true redirect of the POST itself, and we allow them. # The other redirect codes either must, or in practice do, cause the user agent to switch the # method to GET. So when they are encountered on a POST, it indicates an auth problem (a # redirection to a login page). def do_post(url, num_redirects_allowed): if num_redirects_allowed < 0: return error('too many redirects.') res = requests.post(url, data=params, timeout=timeout, headers=headers, allow_redirects=False, **auth_data.request_args) if res.status_code in {307, 308}: return do_post(res.headers['location'], num_redirects_allowed - 1) elif 300 <= res.status_code < 400 or res.status_code == 401: error( f'HTTP error code: {res.status_code}. Reason: {res.reason}.' ) print( f'Use `path/to/pants login --to={auth_provider}` to authenticate ' 'against the stats upload service.', file=sys.stderr) return False elif not res.ok: error( f'HTTP error code: {res.status_code}. Reason: {res.reason}.' ) return False return True try: return do_post(stats_url, num_redirects_allowed=6) except Exception as e: # Broad catch - we don't want to fail the build over upload errors. return error(f'Error: {e!r}')