Hello,
The following patch is adding support for PAM authentication for the koji-hub and BasicAuth for the koji-web.
This is useful for our internal use case as it allows us to login without the overhead of setting up either a CA or a kerberos realm for our users.
The configuration is backwards compatible and hopefully similar to the other authntication methods.
To active PAM support on hub you define the option: PAMService = koji in hub.conf. The value will be the name of the PAM service. Note the call to the PAM module is done via unpriviledged call thus the use of pam_unix won't be possible.
Note that activating this option will have as result that username/password combinations from the DB will no longer be checked (similarly to when activating kerberos or SSL client auth).
The BasicAuth for koji-web requires 2 changes: a) To enable WSGIPassAuthorization for /koji/login in httpd configuration. That passes the authorization variable from the apache to the application. b) Set the "BasicAuthRealm" option to the Basic Authentication Realm that will be presented to the user to login.
Finally python-pam package has been added to the hub's dependencies.
Cheers, Christos
Christos Triantafyllidis (1): - Added PAM support for hub - Added BasicAuth support for web
hub/hub.conf | 4 +++- hub/kojixmlrpc.py | 2 ++ koji.spec | 1 + koji/auth.py | 33 +++++++++++++++++++++++++-------- koji/server.py | 2 ++ www/conf/kojiweb.conf | 5 +++++ www/conf/web.conf | 3 +++ www/kojiweb/index.py | 18 +++++++++++++++++- www/kojiweb/wsgi_publisher.py | 9 +++++++-- 9 files changed, 65 insertions(+), 12 deletions(-)
--- hub/hub.conf | 4 +++- hub/kojixmlrpc.py | 2 ++ koji.spec | 1 + koji/auth.py | 33 +++++++++++++++++++++++++-------- koji/server.py | 2 ++ www/conf/kojiweb.conf | 5 +++++ www/conf/web.conf | 3 +++ www/kojiweb/index.py | 18 +++++++++++++++++- www/kojiweb/wsgi_publisher.py | 9 +++++++-- 9 files changed, 65 insertions(+), 12 deletions(-)
diff --git a/hub/hub.conf b/hub/hub.conf index f1e40c1..e4fd77a 100644 --- a/hub/hub.conf +++ b/hub/hub.conf @@ -36,7 +36,9 @@ KojiDir = /mnt/koji
## end SSL client certificate auth configuration
- +## PAM auth configuration ## +# PAMService = koji +## end PAM auth configuration ##
## Other options ## LoginCreatesUser = On diff --git a/hub/kojixmlrpc.py b/hub/kojixmlrpc.py index efb99a6..2ecc4d1 100644 --- a/hub/kojixmlrpc.py +++ b/hub/kojixmlrpc.py @@ -426,6 +426,8 @@ def load_config(environ): ['DNUsernameComponent', 'string', 'CN'], ['ProxyDNs', 'string', ''],
+ ['PAMService', 'string', None], + ['LoginCreatesUser', 'boolean', True], ['KojiWebURL', 'string', 'http://localhost.localdomain/koji'], ['EmailDomain', 'string', None], diff --git a/koji.spec b/koji.spec index 8a65b6f..73c4132 100644 --- a/koji.spec +++ b/koji.spec @@ -47,6 +47,7 @@ License: LGPLv2 and GPLv2 Requires: httpd Requires: mod_wsgi Requires: postgresql-python +Requires: python-pam Requires: %{name} = %{version}-%{release}
%description hub diff --git a/koji/auth.py b/koji/auth.py index d419d77..f7971ed 100644 --- a/koji/auth.py +++ b/koji/auth.py @@ -27,6 +27,7 @@ import krbV import koji import cgi #for parse_qs from context import context +import pam
# 1 - load session if provided # - check uri for session id @@ -267,14 +268,30 @@ class Session(object): hostip = socket.gethostbyname(socket.gethostname())
# check passwd - c = context.cnx.cursor() - q = """SELECT id FROM users - WHERE name = %(user)s AND password = %(password)s""" - c.execute(q,locals()) - r = c.fetchone() - if not r: - raise koji.AuthError, 'invalid username or password' - user_id = r[0] + if context.opts.get('PAMService'): + if not pam.authenticate(user,password,context.opts.get('PAMService'): + raise koji.AuthError, 'invalid username or password' + cursor = context.cnx.cursor() + query = """SELECT id FROM users + WHERE name = %(user)s""" + cursor.execute(query, locals()) + result = cursor.fetchone() + if result: + user_id = result[0] + else: + if context.opts.get('LoginCreatesUser'): + user_id = self.createUser(user) + else: + raise koji.AuthError, 'Unknown user: %s' % user + else: + c = context.cnx.cursor() + q = """SELECT id FROM users + WHERE name = %(user)s AND password = %(password)s""" + c.execute(q,locals()) + r = c.fetchone() + if not r: + raise koji.AuthError, 'invalid username or password' + user_id = r[0]
self.checkLoginAllowed(user_id)
diff --git a/koji/server.py b/koji/server.py index 52f13f5..5fbf832 100644 --- a/koji/server.py +++ b/koji/server.py @@ -36,6 +36,8 @@ class ServerError(Exception): class ServerRedirect(ServerError): """Used to handle redirects"""
+class NotAuthorized(ServerError): + """Used to handle unauthorized"""
class WSGIWrapper(object): """A very thin wsgi compat layer for mod_python diff --git a/www/conf/kojiweb.conf b/www/conf/kojiweb.conf index 3173ba2..b1d93ca 100644 --- a/www/conf/kojiweb.conf +++ b/www/conf/kojiweb.conf @@ -49,6 +49,11 @@ Alias /koji "/usr/share/koji-web/scripts/wsgi_publisher.py" # SSLOptions +StdEnvVars # </Location>
+# uncomment this to enable authentication via BasicAuth +# <Location /koji/login> +# WSGIPassAuthorization On +# </Location> + Alias /koji-static/ "/usr/share/koji-web/static/"
<Directory "/usr/share/koji-web/static/"> diff --git a/www/conf/web.conf b/www/conf/web.conf index 38f0b61..faad004 100644 --- a/www/conf/web.conf +++ b/www/conf/web.conf @@ -18,6 +18,9 @@ KojiFilesURL = http://server.example.com/kojifiles # ClientCA = /etc/kojiweb/clientca.crt # KojiHubCA = /etc/kojiweb/kojihubca.crt
+# BasicAuth authentication options +# BasicAuthRealm = Koji + LoginTimeout = 72
# This must be changed and uncommented before deployment diff --git a/www/kojiweb/index.py b/www/kojiweb/index.py index 4be6131..656f1ff 100644 --- a/www/kojiweb/index.py +++ b/www/kojiweb/index.py @@ -33,7 +33,7 @@ import logging import time import koji import kojiweb.util -from koji.server import ServerRedirect +from koji.server import ServerRedirect, NotAuthorized from kojiweb.util import _initValues from kojiweb.util import _genHTML from kojiweb.util import _getValidTokens @@ -253,6 +253,22 @@ def login(environ, page=None):
username = principal authlogger.info('Successful Kerberos authentication by %s', username) + elif options['BasicAuthRealm']: + if environ['wsgi.url_scheme'] != 'https': + dest = 'login' + if page: + dest = dest + '?page=' + page + _redirectBack(environ, dest, forceSSL=True) + return + + http_authorization = environ.get('HTTP_AUTHORIZATION') + if not http_authorization: + raise NotAuthorized + session.opts['user'], session.opts['password'] = http_authorization.split(' ')[1].decode('base64').split(':') + if not session.login(): + raise koji.AuthError, 'could not login %s using those credentials' % http_username + username = session.opts['user'] + authlogger.info('Successful BasicAuth authentication by %s', username) else: raise koji.AuthError, 'KojiWeb is incorrectly configured for authentication, contact the system administrator'
diff --git a/www/kojiweb/wsgi_publisher.py b/www/kojiweb/wsgi_publisher.py index e790815..7f167c1 100644 --- a/www/kojiweb/wsgi_publisher.py +++ b/www/kojiweb/wsgi_publisher.py @@ -30,7 +30,7 @@ import sys import traceback
from ConfigParser import RawConfigParser -from koji.server import WSGIWrapper, ServerError, ServerRedirect +from koji.server import WSGIWrapper, ServerError, ServerRedirect, NotAuthorized from koji.util import dslice
@@ -80,6 +80,8 @@ class Dispatcher(object): ['ClientCA', 'string', '/etc/kojiweb/clientca.crt'], ['KojiHubCA', 'string', '/etc/kojiweb/kojihubca.crt'],
+ ['BasicAuthRealm', 'string', None], + ['PythonDebug', 'boolean', False],
['LoginTimeout', 'integer', 72], @@ -141,7 +143,6 @@ class Dispatcher(object): config = None else: raise koji.GenericError, "Configuration missing" - opts = {} for name, dtype, default in self.cfgmap: if config: @@ -395,6 +396,10 @@ class Dispatcher(object): result, headers = self.error_page(environ, message=msg, err=False) start_response(status, headers) return result + except NotAuthorized: + status = "401 Not Authorized" + start_response(status, [('WWW-Authenticate', 'Basic realm="%s"' % self.options['BasicAuthRealm'])]) + return '401 Not Authorized' except Exception: tb_str = ''.join(traceback.format_exception(*sys.exc_info())) self.logger.error(tb_str)
--- koji/auth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/koji/auth.py b/koji/auth.py index f7971ed..1804c09 100644 --- a/koji/auth.py +++ b/koji/auth.py @@ -269,7 +269,7 @@ class Session(object):
# check passwd if context.opts.get('PAMService'): - if not pam.authenticate(user,password,context.opts.get('PAMService'): + if not pam.authenticate(user,password,context.opts.get('PAMService')): raise koji.AuthError, 'invalid username or password' cursor = context.cnx.cursor() query = """SELECT id FROM users
Hello,
Just wanted to follow up this one.
Cheers, Christos
On Wed, Aug 5, 2015 at 4:14 PM, Christos Triantafyllidis < christos.triantafyllidis@gmail.com> wrote:
Hello,
The following patch is adding support for PAM authentication for the koji-hub and BasicAuth for the koji-web.
This is useful for our internal use case as it allows us to login without the overhead of setting up either a CA or a kerberos realm for our users.
The configuration is backwards compatible and hopefully similar to the other authntication methods.
To active PAM support on hub you define the option: PAMService = koji in hub.conf. The value will be the name of the PAM service. Note the call to the PAM module is done via unpriviledged call thus the use of pam_unix won't be possible.
Note that activating this option will have as result that username/password combinations from the DB will no longer be checked (similarly to when activating kerberos or SSL client auth).
The BasicAuth for koji-web requires 2 changes: a) To enable WSGIPassAuthorization for /koji/login in httpd configuration. That passes the authorization variable from the apache to the application. b) Set the "BasicAuthRealm" option to the Basic Authentication Realm that will be presented to the user to login.
Finally python-pam package has been added to the hub's dependencies.
Cheers, Christos
Christos Triantafyllidis (1):
- Added PAM support for hub - Added BasicAuth support for web
hub/hub.conf | 4 +++- hub/kojixmlrpc.py | 2 ++ koji.spec | 1 + koji/auth.py | 33 +++++++++++++++++++++++++-------- koji/server.py | 2 ++ www/conf/kojiweb.conf | 5 +++++ www/conf/web.conf | 3 +++ www/kojiweb/index.py | 18 +++++++++++++++++- www/kojiweb/wsgi_publisher.py | 9 +++++++-- 9 files changed, 65 insertions(+), 12 deletions(-)
-- 2.4.3
buildsys@lists.fedoraproject.org