From b1d29de273aab542c1a3b105923f5b3a0b5ebce9 Mon Sep 17 00:00:00 2001 From: Tim Smith Date: Feb 15 2021 11:59:07 +0000 Subject: [PATCH 1/2] 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 2be8578..1e9506a 100644 --- a/www/conf/web.conf +++ b/www/conf/web.conf @@ -19,6 +19,14 @@ KojiFilesURL = http://server.example.com/kojifiles # WebCert = /etc/kojiweb/kojiweb.crt # 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 de56d55..33962c8 100644 --- a/www/kojiweb/index.py +++ b/www/kojiweb/index.py @@ -271,8 +271,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: @@ -288,22 +304,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 19e9f13be12c024a20930fb4d008eed4627f8d3f Mon Sep 17 00:00:00 2001 From: Tim Smith Date: Apr 15 2021 21:54:30 +0000 Subject: [PATCH 2/2] 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 33962c8..a566771 100644 --- a/www/kojiweb/index.py +++ b/www/kojiweb/index.py @@ -276,10 +276,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(