From 272612f1cb4e7ca99b49b170a29988a2b82ff75d Mon Sep 17 00:00:00 2001
From: Tomas Kopecek <tkopecek@redhat.com>
Date: Oct 07 2021 12:30:42 +0000
Subject: [PATCH 1/10] proxy login method


---

diff --git a/koji/auth.py b/koji/auth.py
index 3f169a5..a43a310 100644
--- a/koji/auth.py
+++ b/koji/auth.py
@@ -315,7 +315,7 @@ class Session(object):
 
         return (local_ip, local_port, remote_ip, remote_port)
 
-    def sslLogin(self, proxyuser=None):
+    def sslLogin(self, proxyuser=None, proxyauthtype=None):
         if self.logged_in:
             raise koji.AuthError("Already logged in")
 
@@ -362,6 +362,10 @@ class Session(object):
             else:
                 raise koji.AuthError('%s is not authorized to login other users' % client_dn)
 
+        # in this point we can continue with proxied user in same way as if it is not proxied
+        if proxyauthtype is not None:
+            authtype = proxyauthtype
+
         if authtype == koji.AUTHTYPE_GSSAPI and '@' in username:
             user_id = self.getUserIdFromKerberos(username)
         else:

From 4601472e00fbeb4547a555f830a27b4438ffa178 Mon Sep 17 00:00:00 2001
From: Tim Smith <tim@electronghost.co.uk>
Date: Oct 07 2021 12:30:42 +0000
Subject: [PATCH 2/10] Allow kojiweb to proxy users obtained via different mechanisms


This allows for users authenticated to the Koji Web interface via
Kerberos to be proxied to the HUB using an SSL certificate and
(in theory) vice versa though it's not clear why you'd want that.

This is useful in environments where the owners of the Kerberos
realm are not willing to create service accounts and export
keytabs for them.

Set WebAuth = kerberos to indicate that users are authenticated
to the web via Kerberos. The existing config controls how kojiweb
authenticates to the HUB.

If using this, it is recommended to set

LoginCreatesUser = Off

in hub.conf, to avoid accidental creation of Koji accounts for
users of the wider Kerberos realm.

---

diff --git a/www/conf/web.conf b/www/conf/web.conf
index 4da640d..a0cde34 100644
--- a/www/conf/web.conf
+++ b/www/conf/web.conf
@@ -21,6 +21,14 @@ KojiFilesURL = http://server.example.com/kojifiles
 # it already. Note, that it will override that bundle.
 # KojiHubCA = /etc/kojiweb/kojihubca.crt
 
+# How the users authenticate to kojiweb, if different from the
+# way Kojiweb authenticates to the hub. This can be used
+# to have users authenticate to kojiweb via kerberos while
+# still using an SSL certificate to authenticate to the hub.
+# If doing that, consider also setting "LoginCreatesUser = Off"
+# in the hub config.
+# WebAuth = kerberos
+
 LoginTimeout = 72
 
 # This must be CHANGED to random value and uncommented before deployment
diff --git a/www/kojiweb/index.py b/www/kojiweb/index.py
index 573c71c..e57feaa 100644
--- a/www/kojiweb/index.py
+++ b/www/kojiweb/index.py
@@ -272,8 +272,24 @@ def login(environ, page=None):
     session = _getServer(environ)
     options = environ['koji.options']
 
-    # try SSL first, fall back to Kerberos
-    if options['WebCert']:
+    # If 'WebAuth' is not set, then default it to
+    # match the method of authenticating to the hub.
+    # This matches the original behaviour
+    webauth = options['WebAuth']
+    if not webauth:
+        if options['WebCert']:
+            webauth = 'ssl'
+        if options['WebPrincipal']:
+            webauth = 'kerberos'
+
+    if not webauth:
+        raise koji.AuthError(
+            'KojiWeb is incorrectly configured for authentication, contact the system '
+            'administrator')
+
+    if webauth == 'ssl':
+        ## Clients authenticate to KojiWeb by SSL, so extract
+        ## the username via the (verified) client certificate
         if environ['wsgi.url_scheme'] != 'https':
             dest = 'login'
             if page:
@@ -289,22 +305,37 @@ def login(environ, page=None):
         if not username:
             raise koji.AuthError('unable to get user information from client certificate')
 
-        if not _sslLogin(environ, session, username):
-            raise koji.AuthError('could not login %s using SSL certificates' % username)
-
-        authlogger.info('Successful SSL authentication by %s', username)
-
-    elif options['WebPrincipal']:
+    elif webauth == 'kerberos':
+        ## Clients authenticate to KojiWeb by Kerberos, so extract
+        ## the username via the REMOTE_USER which will be the
+        ## Kerberos principal
         principal = environ.get('REMOTE_USER')
         if not principal:
             raise koji.AuthError(
                 'configuration error: mod_auth_gssapi should have performed authentication before '
                 'presenting this page')
 
-        if not _gssapiLogin(environ, session, principal):
-            raise koji.AuthError('could not login using principal: %s' % principal)
-
         username = principal
+    else:
+        ## It is still possible to get here if someone explicitly
+        ## set WebAuth to an incorrect value in the configuration file
+        raise koji.AuthError(
+            'KojiWeb is incorrectly configured for authentication, contact the system '
+            'administrator')
+
+    ## This now is how we proxy the user to the hub
+    if options['WebCert']:
+        ## The username might be a principal user@REALM. Remove
+        ## any @REALM part here.
+        username = username.split('@', 1)[0]
+        if not _sslLogin(environ, session, username):
+            raise koji.AuthError('could not login %s using SSL certificates' % username)
+
+        authlogger.info('Successful SSL authentication by %s', username)
+    elif options['WebPrincipal']:
+        if not _gssapiLogin(environ, session, username):
+            raise koji.AuthError('could not login using principal: %s' % username)
+
         authlogger.info('Successful Kerberos authentication by %s', username)
     else:
         raise koji.AuthError(
diff --git a/www/kojiweb/wsgi_publisher.py b/www/kojiweb/wsgi_publisher.py
index 8dab930..e96ee48 100644
--- a/www/kojiweb/wsgi_publisher.py
+++ b/www/kojiweb/wsgi_publisher.py
@@ -78,6 +78,8 @@ class Dispatcher(object):
         ['KrbCanonHost', 'boolean', False],
         ['KrbServerRealm', 'string', None],
 
+        ['WebAuth', 'string', None],
+
         ['WebCert', 'string', None],
         ['KojiHubCA', 'string', '/etc/kojiweb/kojihubca.crt'],
 

From e5b43b397116f43e73abc2ee16d52d7cadec69c9 Mon Sep 17 00:00:00 2001
From: Tim Smith <tim@electronghost.co.uk>
Date: Oct 07 2021 12:30:42 +0000
Subject: [PATCH 3/10] Reverse check order between WebCert and WebPrincipal in case both are set


In the case that both WebPrincipal and WebCert are set, reverse the
order of checking them so that WebCert is used by default.

---

diff --git a/www/kojiweb/index.py b/www/kojiweb/index.py
index e57feaa..102ff9e 100644
--- a/www/kojiweb/index.py
+++ b/www/kojiweb/index.py
@@ -277,10 +277,10 @@ def login(environ, page=None):
     # This matches the original behaviour
     webauth = options['WebAuth']
     if not webauth:
-        if options['WebCert']:
-            webauth = 'ssl'
         if options['WebPrincipal']:
             webauth = 'kerberos'
+        if options['WebCert']:
+            webauth = 'ssl'
 
     if not webauth:
         raise koji.AuthError(

From 6141fa36b7e561ff48d063612625fbbbf3f89540 Mon Sep 17 00:00:00 2001
From: Tomas Kopecek <tkopecek@redhat.com>
Date: Oct 07 2021 12:30:42 +0000
Subject: [PATCH 4/10] proxyauthtype for web users


---

diff --git a/koji/auth.py b/koji/auth.py
index a43a310..f6345b0 100644
--- a/koji/auth.py
+++ b/koji/auth.py
@@ -316,6 +316,15 @@ class Session(object):
         return (local_ip, local_port, remote_ip, remote_port)
 
     def sslLogin(self, proxyuser=None, proxyauthtype=None):
+
+        """Login into brew via SSL. proxyuser name can be specified and if it is
+        allowed in the configuration file then connection is allowed to login as
+        that user. By default we assume that proxyuser is coming via same
+        authentication mechanism but proxyauthtype can be set to koji.AUTHTYPE_*
+        value for different handling. Typical case is proxying kerberos user via
+        web ui which itself is authenticated via SSL certificate. (See kojiweb
+        for usage).
+        """
         if self.logged_in:
             raise koji.AuthError("Already logged in")
 
@@ -364,6 +373,9 @@ class Session(object):
 
         # in this point we can continue with proxied user in same way as if it is not proxied
         if proxyauthtype is not None:
+            if proxyauthtype not in (koji.AUTHTYPE_GSSAPI, koji.AUTHTYPE_SSL):
+                raise koji.AuthError(
+                    "Proxied authtype %s is not valid for sslLogin" % proxyauthtype)
             authtype = proxyauthtype
 
         if authtype == koji.AUTHTYPE_GSSAPI and '@' in username:
diff --git a/www/conf/web.conf b/www/conf/web.conf
index a0cde34..9f2922e 100644
--- a/www/conf/web.conf
+++ b/www/conf/web.conf
@@ -25,9 +25,7 @@ KojiFilesURL = http://server.example.com/kojifiles
 # way Kojiweb authenticates to the hub. This can be used
 # to have users authenticate to kojiweb via kerberos while
 # still using an SSL certificate to authenticate to the hub.
-# If doing that, consider also setting "LoginCreatesUser = Off"
-# in the hub config.
-# WebAuth = kerberos
+# WebAuthType = kerberos
 
 LoginTimeout = 72
 
diff --git a/www/kojiweb/index.py b/www/kojiweb/index.py
index 102ff9e..4805a1b 100644
--- a/www/kojiweb/index.py
+++ b/www/kojiweb/index.py
@@ -151,17 +151,18 @@ def _gssapiLogin(environ, session, principal):
     wprinc = options['WebPrincipal']
     keytab = options['WebKeytab']
     ccache = options['WebCCache']
+    authtype = options['WebAuthType']
     return session.gssapi_login(principal=wprinc, keytab=keytab,
-                                ccache=ccache, proxyuser=principal)
+                                ccache=ccache, proxyuser=principal, proxyauthtype=authtype)
 
 
 def _sslLogin(environ, session, username):
     options = environ['koji.options']
     client_cert = options['WebCert']
     server_ca = options['KojiHubCA']
-
+    authtype = options['WebAuthType']
     return session.ssl_login(client_cert, None, server_ca,
-                             proxyuser=username)
+                             proxyuser=username, proxyauthtype=authtype)
 
 
 def _assertLogin(environ):
@@ -272,22 +273,7 @@ def login(environ, page=None):
     session = _getServer(environ)
     options = environ['koji.options']
 
-    # If 'WebAuth' is not set, then default it to
-    # match the method of authenticating to the hub.
-    # This matches the original behaviour
-    webauth = options['WebAuth']
-    if not webauth:
-        if options['WebPrincipal']:
-            webauth = 'kerberos'
-        if options['WebCert']:
-            webauth = 'ssl'
-
-    if not webauth:
-        raise koji.AuthError(
-            'KojiWeb is incorrectly configured for authentication, contact the system '
-            'administrator')
-
-    if webauth == 'ssl':
+    if options['WebAuthType'] == koji.AUTHTYPE_SSL:
         ## Clients authenticate to KojiWeb by SSL, so extract
         ## the username via the (verified) client certificate
         if environ['wsgi.url_scheme'] != 'https':
@@ -304,8 +290,7 @@ def login(environ, page=None):
         username = environ.get('SSL_CLIENT_S_DN_CN')
         if not username:
             raise koji.AuthError('unable to get user information from client certificate')
-
-    elif webauth == 'kerberos':
+    elif options['WebAuthType'] == koji.AUTHTYPE_GSSAPI:
         ## Clients authenticate to KojiWeb by Kerberos, so extract
         ## the username via the REMOTE_USER which will be the
         ## Kerberos principal
@@ -316,18 +301,9 @@ def login(environ, page=None):
                 'presenting this page')
 
         username = principal
-    else:
-        ## It is still possible to get here if someone explicitly
-        ## set WebAuth to an incorrect value in the configuration file
-        raise koji.AuthError(
-            'KojiWeb is incorrectly configured for authentication, contact the system '
-            'administrator')
 
     ## This now is how we proxy the user to the hub
     if options['WebCert']:
-        ## The username might be a principal user@REALM. Remove
-        ## any @REALM part here.
-        username = username.split('@', 1)[0]
         if not _sslLogin(environ, session, username):
             raise koji.AuthError('could not login %s using SSL certificates' % username)
 
diff --git a/www/kojiweb/wsgi_publisher.py b/www/kojiweb/wsgi_publisher.py
index e96ee48..f703f1e 100644
--- a/www/kojiweb/wsgi_publisher.py
+++ b/www/kojiweb/wsgi_publisher.py
@@ -78,7 +78,7 @@ class Dispatcher(object):
         ['KrbCanonHost', 'boolean', False],
         ['KrbServerRealm', 'string', None],
 
-        ['WebAuth', 'string', None],
+        ['WebAuthType', 'string', None],
 
         ['WebCert', 'string', None],
         ['KojiHubCA', 'string', '/etc/kojiweb/kojihubca.crt'],
@@ -150,6 +150,20 @@ class Dispatcher(object):
             else:
                 opts[name] = default
         opts['Secret'] = koji.util.HiddenValue(opts['Secret'])
+
+        if opts['WebAuthType'] not in (None, 'gssapi', 'ssl'):
+            raise koji.ConfigurationError(f"Invalid value {opts['WebAuthType']} for "
+                                          "WebAuthType (ssl/gssapi)")
+        if opts['WebAuthType'] == 'gssapi':
+            opts['WebAuthType'] = koji.AUTHTYPE_GSSAPI
+        elif opts['WebAuthType'] == 'ssl':
+            opts['WebAuthType'] = koji.AUTHTYPE_SSL
+        # if there is no explicit request, use same authtype as web has
+        elif opts['WebPrincipal']:
+            opts['WebAuthType'] = koji.AUTHTYPE_GSSAPI
+        elif opts['WebCert']:
+            opts['WebAuthType'] = koji.AUTHTYPE_SSL
+
         self.options = opts
         return opts
 

From 3f6c8b8805a2c88b5b59fbc15ea2ea5e3af3c937 Mon Sep 17 00:00:00 2001
From: Tomas Kopecek <tkopecek@redhat.com>
Date: Oct 07 2021 12:30:42 +0000
Subject: [PATCH 5/10] further fixes (will be squashed before merge)


---

diff --git a/hub/hub.conf b/hub/hub.conf
index 7aabe7c..220cab9 100644
--- a/hub/hub.conf
+++ b/hub/hub.conf
@@ -54,6 +54,9 @@ KojiDir = /mnt/koji
 
 ##  Other options  ##
 LoginCreatesUser = On
+# Clients with ProxyPrincipals can use different method for proxying user than GSSAPI. In such case
+# it need to be explicitely allowed via ProxyAuthType.
+# ProxyAuthType = Off
 KojiWebURL = http://kojiweb.example.com/koji
 # The domain name that will be appended to Koji usernames
 # when creating email notifications
diff --git a/hub/kojixmlrpc.py b/hub/kojixmlrpc.py
index 1263c7d..324de87 100644
--- a/hub/kojixmlrpc.py
+++ b/hub/kojixmlrpc.py
@@ -427,6 +427,7 @@ def load_config(environ):
         ['CheckClientIP', 'boolean', True],
 
         ['LoginCreatesUser', 'boolean', True],
+        ['ProxyAuthType', 'boolean', False],
         ['KojiWebURL', 'string', 'http://localhost.localdomain/koji'],
         ['EmailDomain', 'string', None],
         ['NotifyOnSuccess', 'boolean', True],
diff --git a/koji/auth.py b/koji/auth.py
index f6345b0..fd9fd4a 100644
--- a/koji/auth.py
+++ b/koji/auth.py
@@ -324,6 +324,9 @@ class Session(object):
         value for different handling. Typical case is proxying kerberos user via
         web ui which itself is authenticated via SSL certificate. (See kojiweb
         for usage).
+
+        proxyauthtype is working only if ProxyAuthType option is set to 'On' in
+        the hub.conf
         """
         if self.logged_in:
             raise koji.AuthError("Already logged in")
@@ -373,6 +376,9 @@ class Session(object):
 
         # in this point we can continue with proxied user in same way as if it is not proxied
         if proxyauthtype is not None:
+            if not context.opts['ProxyAuthType']:
+                raise koji.AuthError("Proxy must use same auth mechanism as hub "
+                                     "(behaviour can be overriden via ProxyAuthType hub option)")
             if proxyauthtype not in (koji.AUTHTYPE_GSSAPI, koji.AUTHTYPE_SSL):
                 raise koji.AuthError(
                     "Proxied authtype %s is not valid for sslLogin" % proxyauthtype)
diff --git a/www/kojiweb/index.py b/www/kojiweb/index.py
index 4805a1b..b5e0122 100644
--- a/www/kojiweb/index.py
+++ b/www/kojiweb/index.py
@@ -301,6 +301,9 @@ def login(environ, page=None):
                 'presenting this page')
 
         username = principal
+    else:
+        raise koji.AuthError(
+            'configuration error: set WebAuthType or on of WebPrincipal/WebCert options')
 
     ## This now is how we proxy the user to the hub
     if options['WebCert']:

From 04aa48e93b055bc4daeeff29f337f5bfbbf85f52 Mon Sep 17 00:00:00 2001
From: Tomas Kopecek <tkopecek@redhat.com>
Date: Oct 07 2021 12:30:42 +0000
Subject: [PATCH 6/10] conditional evaluation of proxyauthtype


---

diff --git a/koji/auth.py b/koji/auth.py
index fd9fd4a..7b539ab 100644
--- a/koji/auth.py
+++ b/koji/auth.py
@@ -374,15 +374,15 @@ class Session(object):
             else:
                 raise koji.AuthError('%s is not authorized to login other users' % client_dn)
 
-        # in this point we can continue with proxied user in same way as if it is not proxied
-        if proxyauthtype is not None:
-            if not context.opts['ProxyAuthType']:
-                raise koji.AuthError("Proxy must use same auth mechanism as hub "
-                                     "(behaviour can be overriden via ProxyAuthType hub option)")
-            if proxyauthtype not in (koji.AUTHTYPE_GSSAPI, koji.AUTHTYPE_SSL):
-                raise koji.AuthError(
-                    "Proxied authtype %s is not valid for sslLogin" % proxyauthtype)
-            authtype = proxyauthtype
+            # in this point we can continue with proxied user in same way as if it is not proxied
+            if proxyauthtype is not None:
+                if not context.opts['ProxyAuthType']:
+                    raise koji.AuthError("Proxy must use same auth mechanism as hub (behaviour "
+                                         "can be overriden via ProxyAuthType hub option)")
+                if proxyauthtype not in (koji.AUTHTYPE_GSSAPI, koji.AUTHTYPE_SSL):
+                    raise koji.AuthError(
+                        "Proxied authtype %s is not valid for sslLogin" % proxyauthtype)
+                authtype = proxyauthtype
 
         if authtype == koji.AUTHTYPE_GSSAPI and '@' in username:
             user_id = self.getUserIdFromKerberos(username)

From 4ded3d3fefa8895527120ea0362adb73e91e677c Mon Sep 17 00:00:00 2001
From: Tomas Kopecek <tkopecek@redhat.com>
Date: Oct 07 2021 12:30:42 +0000
Subject: [PATCH 7/10] propagate proxyauthtype in login calls


---

diff --git a/koji/__init__.py b/koji/__init__.py
index 4fe2209..25c8e76 100644
--- a/koji/__init__.py
+++ b/koji/__init__.py
@@ -2472,7 +2472,8 @@ class ClientSession(object):
         return self.gssapi_login(principal=principal, keytab=keytab,
                                  ccache=ccache, proxyuser=proxyuser)
 
-    def gssapi_login(self, principal=None, keytab=None, ccache=None, proxyuser=None):
+    def gssapi_login(self, principal=None, keytab=None, ccache=None,
+                     proxyuser=None, proxyauthtype=None):
         if not reqgssapi:
             raise PythonImportError(
                 "Please install python-requests-gssapi to use GSSAPI."
@@ -2515,7 +2516,9 @@ class ClientSession(object):
                 # Depending on the server configuration, we might not be able to
                 # connect without client certificate, which means that the conn
                 # will fail with a handshake failure, which is retried by default.
-                sinfo = self._callMethod('sslLogin', [proxyuser], retry=False)
+                sinfo = self._callMethod('sslLogin', [],
+                                         {'proxyuser': proxyuser, 'proxyauthtype': proxyauthtype},
+                                         retry=False)
             except Exception as e:
                 e_str = ''.join(traceback.format_exception_only(type(e), e)).strip('\n')
                 e_str = '(gssapi auth failed: %s)\n' % e_str
@@ -2542,7 +2545,7 @@ class ClientSession(object):
         self.authtype = AUTHTYPE_GSSAPI
         return True
 
-    def ssl_login(self, cert=None, ca=None, serverca=None, proxyuser=None):
+    def ssl_login(self, cert=None, ca=None, serverca=None, proxyuser=None, proxyauthtype=None):
         cert = cert or self.opts.get('cert')
         serverca = serverca or self.opts.get('serverca')
         if cert is None:
@@ -2571,7 +2574,9 @@ class ClientSession(object):
         self.opts['serverca'] = serverca
         e_str = None
         try:
-            sinfo = self.callMethod('sslLogin', proxyuser)
+            sinfo = self.callMethod('sslLogin', [],
+                                    {'proxyuser': proxyuser, 'proxyauthtype': proxyauthtype})
+
         except Exception as ex:
             e_str = ''.join(traceback.format_exception_only(type(ex), ex))
             e_str = 'ssl auth failed: %s' % e_str
diff --git a/tests/test_lib/test_gssapi.py b/tests/test_lib/test_gssapi.py
index afbc897..da57c68 100644
--- a/tests/test_lib/test_gssapi.py
+++ b/tests/test_lib/test_gssapi.py
@@ -26,8 +26,8 @@ class TestGSSAPI(unittest.TestCase):
     def test_gssapi_login(self):
         old_environ = dict(**os.environ)
         self.session.gssapi_login()
-        self.session._callMethod.assert_called_once_with('sslLogin', [None],
-                                                         retry=False)
+        self.session._callMethod.assert_called_once_with(
+                'sslLogin', [], {'proxyuser': None, 'proxyauthtype': None}, retry=False)
         self.assertEqual(old_environ, dict(**os.environ))
 
     @mock.patch('koji.reqgssapi.HTTPKerberosAuth')
@@ -46,9 +46,8 @@ class TestGSSAPI(unittest.TestCase):
         for accepted_version in accepted_versions:
             koji.reqgssapi.__version__ = accepted_version
             rv = self.session.gssapi_login(principal, keytab, ccache)
-            self.session._callMethod.assert_called_once_with('sslLogin',
-                                                             [None],
-                                                             retry=False)
+            self.session._callMethod.assert_called_once_with(
+                    'sslLogin', [], {'proxyuser': None, 'proxyauthtype': None}, retry=False)
             self.assertEqual(old_environ, dict(**os.environ))
             self.assertTrue(rv)
             self.session._callMethod.reset_mock()
@@ -84,8 +83,8 @@ class TestGSSAPI(unittest.TestCase):
         self.session._callMethod.side_effect = Exception('login failed')
         with self.assertRaises(koji.GSSAPIAuthError):
             self.session.gssapi_login()
-        self.session._callMethod.assert_called_once_with('sslLogin', [None],
-                                                         retry=False)
+        self.session._callMethod.assert_called_once_with(
+                'sslLogin', [], {'proxyuser': None, 'proxyauthtype': None}, retry=False)
         self.assertEqual(old_environ, dict(**os.environ))
 
     def test_gssapi_login_http(self):

From 446b9ae8f2abb17ea4d288ed0e23b4dde8c46d72 Mon Sep 17 00:00:00 2001
From: Tomas Kopecek <tkopecek@redhat.com>
Date: Oct 07 2021 12:30:42 +0000
Subject: [PATCH 8/10] rename ProxyAuthType -> AllowProxyAuthType


---

diff --git a/hub/hub.conf b/hub/hub.conf
index 220cab9..d8740b2 100644
--- a/hub/hub.conf
+++ b/hub/hub.conf
@@ -55,8 +55,8 @@ KojiDir = /mnt/koji
 ##  Other options  ##
 LoginCreatesUser = On
 # Clients with ProxyPrincipals can use different method for proxying user than GSSAPI. In such case
-# it need to be explicitely allowed via ProxyAuthType.
-# ProxyAuthType = Off
+# it need to be explicitely allowed via AllowProxyAuthType.
+# AllowProxyAuthType = Off
 KojiWebURL = http://kojiweb.example.com/koji
 # The domain name that will be appended to Koji usernames
 # when creating email notifications
diff --git a/hub/kojixmlrpc.py b/hub/kojixmlrpc.py
index 324de87..ebdfdc2 100644
--- a/hub/kojixmlrpc.py
+++ b/hub/kojixmlrpc.py
@@ -427,7 +427,7 @@ def load_config(environ):
         ['CheckClientIP', 'boolean', True],
 
         ['LoginCreatesUser', 'boolean', True],
-        ['ProxyAuthType', 'boolean', False],
+        ['AllowProxyAuthType', 'boolean', False],
         ['KojiWebURL', 'string', 'http://localhost.localdomain/koji'],
         ['EmailDomain', 'string', None],
         ['NotifyOnSuccess', 'boolean', True],
diff --git a/koji/auth.py b/koji/auth.py
index 7b539ab..15f7071 100644
--- a/koji/auth.py
+++ b/koji/auth.py
@@ -325,8 +325,8 @@ class Session(object):
         web ui which itself is authenticated via SSL certificate. (See kojiweb
         for usage).
 
-        proxyauthtype is working only if ProxyAuthType option is set to 'On' in
-        the hub.conf
+        proxyauthtype is working only if AllowProxyAuthType option is set to
+        'On' in the hub.conf
         """
         if self.logged_in:
             raise koji.AuthError("Already logged in")
@@ -376,9 +376,9 @@ class Session(object):
 
             # in this point we can continue with proxied user in same way as if it is not proxied
             if proxyauthtype is not None:
-                if not context.opts['ProxyAuthType']:
+                if not context.opts['AllowProxyAuthType']:
                     raise koji.AuthError("Proxy must use same auth mechanism as hub (behaviour "
-                                         "can be overriden via ProxyAuthType hub option)")
+                                         "can be overriden via AllowProxyAuthType hub option)")
                 if proxyauthtype not in (koji.AUTHTYPE_GSSAPI, koji.AUTHTYPE_SSL):
                     raise koji.AuthError(
                         "Proxied authtype %s is not valid for sslLogin" % proxyauthtype)

From bab6517b4a0c3d86a36eca6bdb5126f354d40730 Mon Sep 17 00:00:00 2001
From: Tomas Kopecek <tkopecek@redhat.com>
Date: Oct 07 2021 12:53:12 +0000
Subject: [PATCH 9/10] backward compatibility for older hub


use proxyauthtype only if it is explicetly requested. Older hubs
don't know this option and will refuse login attempt.

---

diff --git a/koji/__init__.py b/koji/__init__.py
index 25c8e76..5c2a100 100644
--- a/koji/__init__.py
+++ b/koji/__init__.py
@@ -2516,9 +2516,10 @@ class ClientSession(object):
                 # Depending on the server configuration, we might not be able to
                 # connect without client certificate, which means that the conn
                 # will fail with a handshake failure, which is retried by default.
-                sinfo = self._callMethod('sslLogin', [],
-                                         {'proxyuser': proxyuser, 'proxyauthtype': proxyauthtype},
-                                         retry=False)
+                kwargs = {'proxyuser': proxyuser}
+                if proxyauthtype is not None:
+                    kwargs['proxyauthtype'] = proxyauthtype
+                sinfo = self._callMethod('sslLogin', [], kwargs, retry=False)
             except Exception as e:
                 e_str = ''.join(traceback.format_exception_only(type(e), e)).strip('\n')
                 e_str = '(gssapi auth failed: %s)\n' % e_str
@@ -2574,8 +2575,10 @@ class ClientSession(object):
         self.opts['serverca'] = serverca
         e_str = None
         try:
-            sinfo = self.callMethod('sslLogin', [],
-                                    {'proxyuser': proxyuser, 'proxyauthtype': proxyauthtype})
+            kwargs = {'proxyuser': proxyuser}
+            if proxyauthtype is not None:
+                kwargs['proxyauthtype'] = proxyauthtype
+            sinfo = self.callMethod('sslLogin', [], kwargs)
 
         except Exception as ex:
             e_str = ''.join(traceback.format_exception_only(type(ex), ex))
diff --git a/tests/test_lib/test_gssapi.py b/tests/test_lib/test_gssapi.py
index da57c68..c5f71be 100644
--- a/tests/test_lib/test_gssapi.py
+++ b/tests/test_lib/test_gssapi.py
@@ -27,7 +27,7 @@ class TestGSSAPI(unittest.TestCase):
         old_environ = dict(**os.environ)
         self.session.gssapi_login()
         self.session._callMethod.assert_called_once_with(
-                'sslLogin', [], {'proxyuser': None, 'proxyauthtype': None}, retry=False)
+                'sslLogin', [], {'proxyuser': None}, retry=False)
         self.assertEqual(old_environ, dict(**os.environ))
 
     @mock.patch('koji.reqgssapi.HTTPKerberosAuth')
@@ -47,7 +47,7 @@ class TestGSSAPI(unittest.TestCase):
             koji.reqgssapi.__version__ = accepted_version
             rv = self.session.gssapi_login(principal, keytab, ccache)
             self.session._callMethod.assert_called_once_with(
-                    'sslLogin', [], {'proxyuser': None, 'proxyauthtype': None}, retry=False)
+                    'sslLogin', [], {'proxyuser': None}, retry=False)
             self.assertEqual(old_environ, dict(**os.environ))
             self.assertTrue(rv)
             self.session._callMethod.reset_mock()
@@ -84,7 +84,7 @@ class TestGSSAPI(unittest.TestCase):
         with self.assertRaises(koji.GSSAPIAuthError):
             self.session.gssapi_login()
         self.session._callMethod.assert_called_once_with(
-                'sslLogin', [], {'proxyuser': None, 'proxyauthtype': None}, retry=False)
+                'sslLogin', [], {'proxyuser': None}, retry=False)
         self.assertEqual(old_environ, dict(**os.environ))
 
     def test_gssapi_login_http(self):

From dada27f2fab276a68d75592d922eba50fdfa60a6 Mon Sep 17 00:00:00 2001
From: Tomas Kopecek <tkopecek@redhat.com>
Date: Oct 13 2021 11:27:13 +0000
Subject: [PATCH 10/10] fix callMethod


---

diff --git a/koji/__init__.py b/koji/__init__.py
index 5c2a100..82d2e64 100644
--- a/koji/__init__.py
+++ b/koji/__init__.py
@@ -2578,7 +2578,7 @@ class ClientSession(object):
             kwargs = {'proxyuser': proxyuser}
             if proxyauthtype is not None:
                 kwargs['proxyauthtype'] = proxyauthtype
-            sinfo = self.callMethod('sslLogin', [], kwargs)
+            sinfo = self._callMethod('sslLogin', [], kwargs)
 
         except Exception as ex:
             e_str = ''.join(traceback.format_exception_only(type(ex), ex))

