Example #1
0
    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.']
Example #2
0
 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])
Example #3
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)
Example #4
0
 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))
Example #5
0
  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.']
Example #6
0
 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."]
Example #7
0
    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.']
Example #8
0
 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))
Example #9
0
  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)
Example #10
0
    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)
Example #11
0
    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}')