#3010 Honour --force-auth for anonymous commands
Merged 2 years ago by tkopecek. Opened 2 years ago by tkopecek.
tkopecek/koji issue2657  into  master

file modified
+1 -1
@@ -127,7 +127,7 @@ 

      parser.add_option("--password", help=_("specify password"))

      parser.add_option("--noauth", action="store_true", default=False,

                        help=_("do not authenticate"))

-     parser.add_option("--force-auth", action="store_true", default=False,

+     parser.add_option("--force-auth", action="store_true",  # default (False) comes from the config

                        help=_("authenticate even for read-only operations"))

      parser.add_option("--authtype", help=_("force use of a type of authentication, options: "

                                             "noauth, ssl, password, or kerberos"))

file modified
+3
@@ -45,3 +45,6 @@ 

  

  ;timeout of GSSAPI/SSL authentication by seconds, default: 60

  ;auth_timeout = 60

+ 

+ ;enforcing CLI authentication even for anonymous calls

+ ;force_auth = False

file modified
+7 -2
@@ -1793,6 +1793,7 @@ 

      cutoff_ts = time.time() - options.days * 24 * 3600

      if options.debug:

          print("Cutoff date: %s" % time.asctime(time.localtime(cutoff_ts)))

+     activate_session(session, goptions)

      if not options.build:

          if options.verbose:

              print("Getting builds...")
@@ -2145,11 +2146,12 @@ 

      print("Added volume %(name)s with id %(id)i" % volinfo)

  

  

- def handle_list_volumes(options, session, args):

+ def anon_handle_list_volumes(goptions, session, args):

      "[info] List storage volumes"

      usage = _("usage: %prog list-volumes")

      parser = OptionParser(usage=get_usage_str(usage))

      (options, args) = parser.parse_args(args)

+     ensure_connection(session, goptions)

      for volinfo in session.listVolumes():

          print(volinfo['name'])

  
@@ -7265,6 +7267,7 @@ 

              for child_task in child_tasks:

                  save_logs(child_task['id'], match, task_log_dir, recurse)

  

+     ensure_connection(session, options)

      for arg in args:

          if suboptions.nvr:

              suboptions.recurse = True
@@ -7413,6 +7416,7 @@ 

  

      tag = args[0]

  

+     ensure_connection(session, options)

      if suboptions.target:

          target_info = session.getBuildTarget(tag)

          if not target_info:
@@ -7686,7 +7690,7 @@ 

                   'maven', 'win')

  

  

- def anon_handle_search(options, session, args):

+ def anon_handle_search(goptions, session, args):

      "[search] Search the system"

      usage = _("usage: %prog search [options] <search_type> <pattern>")

      usage += _('\nAvailable search types: %s') % ', '.join(_search_types)
@@ -7707,6 +7711,7 @@ 

          matchType = 'regexp'

      elif options.exact:

          matchType = 'exact'

+     ensure_connection(session, goptions)

      data = session.search(pattern, type, matchType)

      for row in data:

          print(row['name'])

file modified
+6
@@ -136,6 +136,10 @@ 

  

  

  def ensure_connection(session, options=None):

+     if options and options.force_auth:

+         # in such case we should act as a real activate_session

+         activate_session(session, options)

+         return

      try:

          ret = session.getAPIVersion()

      except requests.exceptions.ConnectionError as ex:
@@ -751,6 +755,8 @@ 

              warn(_("Could not connect to Kerberos authentication service: %s") % e.args[1])

      if not noauth and not session.logged_in:

          error(_("Unable to log in, no authentication methods available"))

+     # don't add "options" to ensure_connection it would create loop in case of --force-auth

+     # when it calls activate_session

      ensure_connection(session)

      if getattr(options, 'debug', None):

          print("successfully connected to hub")

file modified
+2 -1
@@ -1942,6 +1942,7 @@ 

          'debug_xmlrpc': False,

          'pyver': None,

          'plugin_paths': None,

+         'force_auth': False,

      }

  

      result = config_defaults.copy()
@@ -1978,7 +1979,7 @@ 

              # not have a default value set in the option parser.

              if name in result:

                  if name in ('anon_retry', 'offline_retry', 'use_fast_upload',

-                             'debug', 'debug_xmlrpc'):

+                             'debug', 'debug_xmlrpc', 'force_auth'):

                      result[name] = config.getboolean(profile_name, name)

                  elif name in ('max_retries', 'retry_interval',

                                'offline_retry_interval', 'poll_interval',

@@ -24,7 +24,7 @@ 

              'koji_cli.commands.list_task_output_all_volumes').start()

          self.ensuredir = mock.patch('koji.ensuredir').start()

          self.download_file = mock.patch('koji_cli.commands.download_file').start()

-         self.activate_session = mock.patch('koji_cli.commands.activate_session').start()

+         self.ensure_connection = mock.patch('koji_cli.commands.ensure_connection').start()

          self.stdout = mock.patch('sys.stdout', new_callable=six.StringIO).start()

          self.stderr = mock.patch('sys.stderr', new_callable=six.StringIO).start()

  

@@ -37,7 +37,7 @@ 

          time.tzset()

  

      @mock.patch('sys.stderr', new_callable=six.StringIO)

-     @mock.patch('koji_cli.commands.activate_session')

+     @mock.patch('koji_cli.commands.ensure_connection')

      def test_list_targets_error_args(self, ensure_connection_mock, stderr):

          session = mock.MagicMock(getAPIVersion=lambda: koji.API_VERSION,

                                   getBuildTargets=lambda n: [])
@@ -47,7 +47,7 @@ 

          self.assertExitCode(ex, 2)

  

      @mock.patch('sys.stderr', new_callable=six.StringIO)

-     @mock.patch('koji_cli.commands.activate_session')

+     @mock.patch('koji_cli.commands.ensure_connection')

      def test_list_targets_error_all_not_found(self, ensure_connection_mock, stderr):

          session = mock.MagicMock(getAPIVersion=lambda: koji.API_VERSION,

                                   getBuildTargets=lambda n: [])
@@ -60,7 +60,7 @@ 

      @mock.patch('optparse.OptionParser.parse_args',

                  return_value=(Values({'quiet': False, 'name': 'f50'}), []))

      @mock.patch('sys.stderr', new_callable=six.StringIO)

-     @mock.patch('koji_cli.commands.activate_session')

+     @mock.patch('koji_cli.commands.ensure_connection')

      def test_list_targets_error_name_not_found(self, ensure_connection_mock, stderr, opt):

          session = mock.MagicMock(getAPIVersion=lambda: koji.API_VERSION,

                                   getBuildTargets=lambda n: [])
@@ -71,7 +71,7 @@ 

          self.assertTrue('No such build target:' in stderr.getvalue())

  

      @mock.patch('sys.stdout', new_callable=six.StringIO)

-     @mock.patch('koji_cli.commands.activate_session')

+     @mock.patch('koji_cli.commands.ensure_connection')

      def test_list_targets_all(self, ensure_connection_mock, stdout):

          session = mock.MagicMock(getAPIVersion=lambda: koji.API_VERSION,

                                   getBuildTargets=lambda n: _mock_targets)
@@ -88,7 +88,7 @@ 

      @mock.patch('optparse.OptionParser.parse_args',

                  return_value=(Values({'quiet': False, 'name': 'f50'}), []))

      @mock.patch('sys.stdout', new_callable=six.StringIO)

-     @mock.patch('koji_cli.commands.activate_session')

+     @mock.patch('koji_cli.commands.ensure_connection')

      def test_list_targets_one(self, ensure_connection_mock, stdout, opt):

          session = mock.MagicMock(getAPIVersion=lambda: koji.API_VERSION,

                                   getBuildTargets=lambda n: _mock_targets)

@@ -3,7 +3,7 @@ 

  import six

  import unittest

  

- from koji_cli.commands import handle_list_volumes

+ from koji_cli.commands import anon_handle_list_volumes

  from . import utils

  

  
@@ -13,12 +13,12 @@ 

      maxDiff = None

  

      @mock.patch('sys.stdout', new_callable=six.StringIO)

-     @mock.patch('koji_cli.commands.activate_session')

-     def test_handle_list_volumes(

+     @mock.patch('koji_cli.commands.ensure_connection')

+     def test_anon_handle_list_volumes(

              self,

-             activate_session_mock,

+             ensure_connection_mock,

              stdout):

-         """Test handle_list_volumes function"""

+         """Test anon_handle_list_volumes function"""

          session = mock.MagicMock()

          options = mock.MagicMock()

          vol_info = [
@@ -29,12 +29,12 @@ 

  

          expected = "\n".join([v['name'] for v in vol_info]) + "\n"

          session.listVolumes.return_value = vol_info

-         handle_list_volumes(options, session, [])

+         anon_handle_list_volumes(options, session, [])

          self.assert_console_message(stdout, expected)

  

-     def test_handle_list_volumes_help(self):

+     def test_anon_handle_list_volumes_help(self):

          self.assert_help(

-             handle_list_volumes,

+             anon_handle_list_volumes,

              """Usage: %s list-volumes

  (Specify the --help global option for a list of other help options)

  

@@ -20,10 +20,12 @@ 

  %s: error: {message}

  """ % (self.progname, self.progname)

  

+     @mock.patch('koji_cli.commands.ensure_connection')

      @mock.patch('sys.stdout', new_callable=six.StringIO)

      def test_anon_handle_search(

              self,

-             stdout):

+             stdout,

+             ensure_connection_mock):

          """Test anon_handle_search function"""

          session = mock.MagicMock()

          options = mock.MagicMock()

@@ -54,6 +54,7 @@ 

  

      def setUpMocks(self):

          self.activate_session = mock.patch('koji_cli.commands.activate_session').start()

+         self.ensure_connection = mock.patch('koji_cli.commands.ensure_connection').start()

          self.checkForBuilds = mock.patch('koji.util.checkForBuilds').start()

  

      def tearDown(self):