Author: tmckay
Date: 2011-09-30 16:29:36 +0000 (Fri, 30 Sep 2011)
New Revision: 5033
Removed:
branches/lucidity/cumin/python/cumin/authenticator.py
Modified:
branches/lucidity/cumin/bin/cumin-admin
branches/lucidity/cumin/bin/cumin-web
branches/lucidity/cumin/python/cumin/account/widgets.py
branches/lucidity/cumin/python/cumin/config.py
branches/lucidity/cumin/python/cumin/main.py
Log:
Back out external authentication changes inherited from trunk.
Retain changes to cumin/python/cumin/admin.py (exception handling)
Retain addition of "def confirm" in cumin-admin
svn merge -c -4971
svn+ssh://svn.fedorahosted.org/svn/cumin/trunk
svn merge -c -4945
svn+ssh://svn.fedorahosted.org/svn/cumin/trunk
Modified: branches/lucidity/cumin/bin/cumin-admin
===================================================================
--- branches/lucidity/cumin/bin/cumin-admin 2011-09-30 15:45:25 UTC (rev 5032)
+++ branches/lucidity/cumin/bin/cumin-admin 2011-09-30 16:29:36 UTC (rev 5033)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
import os
import sys
@@ -65,9 +65,8 @@
sys.exit(1)
broker_uris = [x.strip() for x in opts.brokers.split(",")]
- authmech = [x.strip() for x in values.common.auth.split(";")]
- app = Cumin(config.get_home(), broker_uris, opts.database, authmech=authmech)
+ app = Cumin(config.get_home(), broker_uris, opts.database)
app.check()
app.init()
@@ -97,9 +96,6 @@
lines.append("User commands:")
lines.append("")
lines.append(" add-user USER [PASSWORD] Add USER")
- lines.append(" external-user USER Add USER with external
authentication")
- lines.append(" external-sync AUTH [VERBOSE] Batch import users with external
authentication")
- lines.append(" AUTH is the name of a mechanism
like 'ldap' or 'script'")
lines.append(" remove-user USER Remove USER")
lines.append(" add-assignment USER ROLE Add USER to ROLE")
lines.append(" remove-assignment USER ROLE Remove USER from ROLE")
@@ -108,8 +104,6 @@
lines.append(" list-roles List roles")
lines.append(" export-users FILE Export user list to file")
lines.append(" import-users FILE Import user list from file")
- lines.append(" expunge-users Remove all users. Use with
caution")
- lines.append(" You may want to run export-users
first")
lines.append("")
lines.append("Schema commands:")
lines.append("")
@@ -121,7 +115,6 @@
lines.append(" the expected version if
necessary")
return "\n".join(lines)
-
def confirm(prompt, resp=False):
if resp:
prompt = '%s [%s]|%s: ' % (prompt, 'yes', 'no')
@@ -288,79 +281,24 @@
def handle_list_users(app, cursor, opts, args):
- print " ID Name Roles"
- print "---- -------------------- --------------------"
+ print " ID Name Roles"
+ print "---- -------------------- --------------------"
users, roles_by_user_id = get_users(app, cursor)
- externals = 0
+
for user in users:
try:
roles = ", ".join(roles_by_user_id[user._id])
except KeyError:
roles = ""
- if len(user.password) == 0:
- ex = "*"
- externals += 1
- else:
- ex = " "
- print "%4i %s %-20s %-20s" % (user._id, ex, user.name, roles)
+ print "%4i %-20s %-20s" % (user._id, user.name, roles)
+
count = len(users)
print
print "(%i user%s found)" % (count, ess(count))
- if externals > 0:
- print "(%i external user%s, indicated by *)" % (externals,
ess(externals))
-def handle_external_user(app, cursor, opts, args):
- try:
- name = args[0]
- except IndexError:
- error("USER is required")
- role = app.admin.get_role(cursor, "user")
- try:
- user = app.admin.add_user(cursor, name, "")
- except IntegrityError:
- error("A user called '%s' already exists" % name)
-
- app.admin.add_assignment(cursor, user, role)
- print "External user '%s' is added" % name
-
-def handle_external_sync(app, cursor, opts, args):
- try:
- authenticatorname = args[0]
- except IndexError:
- error("AUTHENTICATOR name is required")
-
- output_on = False
- if len(args) > 1:
- output_on = args[1].lower() in ("t", "true", "1")
-
- users, conflicts, errors = \
- app.authenticator.batch_import(authenticatorname, output_on)
-
- print("Successfully imported %s users, %s conflicts" % (users, conflicts))
- if errors:
- print("Errors reported, check logs for details.")
-
-def handle_expunge_users(app, cursor, opts, args):
-
- print("This will remove all users from Cumin's database.")
- print("Hint: you may want to backup Cumin's user database "\
- "with export-users first.\n")
- try:
- go = confirm( "Are you sure you want to do this?", resp=False)
- except KeyboardInterrupt:
- go = False
-
- if go:
- cls = app.model.com_redhat_cumin.User
- cls.delete_selection(cursor)
- print("\nAll users removed.")
- else:
- print("\nNo users removed.")
-
-
def handle_add_user(app, cursor, opts, args):
try:
name = args[0]
@@ -376,14 +314,18 @@
password = args[1]
except IndexError:
password = prompt_password()
+
crypted = crypt_password(password)
+
role = app.admin.get_role(cursor, "user")
+
try:
user = app.admin.add_user(cursor, name, crypted)
except IntegrityError:
error("A user called '%s' already exists" % name)
app.admin.add_assignment(cursor, user, role)
+
print "User '%s' is added" % name
def handle_export_users(app, cursor, opts, args):
@@ -423,19 +365,15 @@
for info in user_data:
line += 1
- count = 0
for field in info:
# Don't suppose it's possible for data to be anything other than
# strings from csv, but this is where such type checking goes
if type(field) != str:
error("Data error, line %u, fields must be strings" % line)
+ if len(field) == 0:
+ error("Data error, line %u, importer "\
+ "does not allow empty fields" % line)
- # Empty password field is external auth indicator, allow it
- if len(field) == 0 and count != 1:
- error("Data error, line %u, field %u, importer "\
- "does not allow empty field" % (line, field+1))
- count += 1
-
if len(info) < 2:
error("Data error, line %u, not enough fields. "\
" User and password are required" % (line))
@@ -450,7 +388,7 @@
# before we get an integrity error
warn("A user called '%s' already exists, skipping" %
info[0])
continue
-
+
try:
user = app.admin.add_user(cursor, info[0], info[1])
except IntegrityError:
@@ -538,11 +476,10 @@
if not user:
error("User '%s' is not found" % user_name)
- if user.password == "":
- error("User '%s' is an external user, password cannot be changed
"\
- "through this mechanism" % user_name)
+
user.password = crypt_password(prompt_password())
user.save(cursor)
+
print "Password of user '%s' is changed" % user.name
def handle_load_demo_data(app, cursor, opts, args):
Modified: branches/lucidity/cumin/bin/cumin-web
===================================================================
--- branches/lucidity/cumin/bin/cumin-web 2011-09-30 15:45:25 UTC (rev 5032)
+++ branches/lucidity/cumin/bin/cumin-web 2011-09-30 16:29:36 UTC (rev 5033)
@@ -103,9 +103,8 @@
values.log_max_archives)
broker_uris = [x.strip() for x in opts.brokers.split(",")]
- authmech = [x.strip() for x in values.auth.split(";")]
cumin = Cumin(config.get_home(), broker_uris, opts.database,
- opts.host, opts.port, values.persona, authmech)
+ opts.host, opts.port, values.persona)
if type(values.sasl_mech_list) == str:
cumin.sasl_mech_list = values.sasl_mech_list.upper()
Modified: branches/lucidity/cumin/python/cumin/account/widgets.py
===================================================================
--- branches/lucidity/cumin/python/cumin/account/widgets.py 2011-09-30 15:45:25 UTC (rev
5032)
+++ branches/lucidity/cumin/python/cumin/account/widgets.py 2011-09-30 16:29:36 UTC (rev
5033)
@@ -61,6 +61,7 @@
def render_content(self, sessino):
return "Change password"
+
class LoginPage(HtmlPage):
def __init__(self, app, name):
super(LoginPage, self).__init__(app, name)
@@ -127,11 +128,14 @@
self.login_invalid.set(session, True)
return
- authenticated = self.app.authenticator.authenticate(name,password)
- if authenticated:
+ crypted = user.password
+
+ if crypted and crypt(password, crypted) == crypted:
# You're in!
+
login = LoginSession(self.app, user)
session.client_session.attributes["login_session"] = login
+
url = self.page.origin.get(session)
self.page.redirect.set(session, url)
@@ -174,51 +178,53 @@
self.add_field(self.new1)
def validate(self, session):
+ super(ChangePasswordForm, self).validate(session)
+
+ current = self.current.get(session)
+ new0 = self.new0.get(session)
+ new1 = self.new1.get(session)
+
user = session.client_session.attributes["login_session"].user
+
# In case a different login session for this user has made
# changes, refresh the user object
+
user.load(session.cursor)
-
- new0 = self.new0.get(session)
- new1 = self.new1.get(session)
+ crypted = user.password
+
+ if crypt_password(current, crypted) != crypted:
+ error = FormError("The password is incorrect")
+ self.errors.add(session, error)
+
if new0 != new1:
error = FormError("The new passwords do not match")
self.errors.add(session, error)
- return
- super(ChangePasswordForm, self).validate(session)
-
- # authenticator.update_password does authentication
- # before allowing the password change, no need to authenticate here
-
def process_submit(self, session):
self.validate(session)
if not self.errors.get(session):
- newpassword = self.new0.get(session)
- oldpassword = self.current.get(session)
- user = session.client_session.attributes["login_session"].user
+ password = self.new0.get(session)
+
+ conn = self.app.database.get_connection()
+
try:
- status, message = self.app.authenticator.update_password(user.name,
- oldpassword,
- newpassword)
- if not status:
- if not message:
- message = "Update failed."
- error = FormError(message)
- self.errors.add(session, error)
+ cursor = conn.cursor()
- except Exception,e:
- log.debug("Error in external authenticator: %s" , e )
- error = FormError("Password change error. Please contact your site
administrator.")
- self.errors.add(session,error)
+ user = session.client_session.attributes["login_session"].user
+ user.password = crypt_password(password)
+ user.save(cursor)
- if not self.errors.get(session):
+ conn.commit()
+ finally:
+ conn.close()
+
task = ObjectTask(self.app)
invoc = task.start(session, None)
invoc.description = "Password changed"
invoc.end()
+
url = self.return_url.get(session)
self.page.redirect.set(session, url)
Deleted: branches/lucidity/cumin/python/cumin/authenticator.py
===================================================================
--- branches/lucidity/cumin/python/cumin/authenticator.py 2011-09-30 15:45:25 UTC (rev
5032)
+++ branches/lucidity/cumin/python/cumin/authenticator.py 2011-09-30 16:29:36 UTC (rev
5033)
@@ -1,347 +0,0 @@
-from util import *
-try:
- import ldap
- import ldapurl
- have_ldap = True
-except:
- have_ldap = False
-
-import subprocess
-from subprocess import PIPE
-from psycopg2 import IntegrityError
-import syslog
-
-# Send sensitive authentication logs to syslog
-# but use this for other stuff. We want to keep
-# all user and password information out of the
-# publically readable log file.
-log = logging.getLogger("cumin.authenticator")
-
-
-class _syslog(object):
- log_auth = False
- @classmethod
- def log(cls, msg):
- if _syslog.log_auth:
- syslog.syslog(msg)
-
-class CuminAuthenticatorLDAP(object):
- def __init__(self, url):
- log.info("Initializing %s", self)
- myurl = url.split("=",1)[1]
- try:
- self.url = ldapurl.LDAPUrl(myurl)
- log.info("Authenticator: parsed LDAP url successfully.")
- except Exception,e:
- log.error("Authenticator: cannot parse LDAP url %s", e)
-
- def __prep_con(self):
- try:
- conn = ldap.initialize(self.url.urlscheme + "://"
+self.url.hostport)
- except Exception,e:
- log.error("Authenticator: cannot contact ldap server %s",e)
- return False
-
- if self.url.who and self.url.cred:
- try:
- conn.simple_bind_s(self.url.who,self.url.cred)
- except:
- log.error("Authenticator: cannot authenticate as service %s",
- self.url.who)
- return False
- return conn
-
- def change_pw(self,user,oldpass,newpass):
- conn = self.__prep_con()
- if not conn:
- return False
- filter = self.url.filterstr % user
- try:
- res = conn.search_s(self.url.dn, self.url.scope, filter)
- except Exception, e:
- log.error("Authenticator: update password, "\
- "query returned exception %s", e)
- res = []
- if not res:
- log.info("Authenticator: update password, "\
- "query returned no results in %s",
self.__class__.__name__)
- else:
- dn,ent = res[0]
- conn.simple_bind_s(dn,oldpass)
- conn.passwd_s(dn,oldpass,newpass)
- log.info("Authenticator: update password succeeded in %s",
- self.__class__.__name__)
- _syslog.log("cumin: updated password via LDAP for user %s" % dn)
- return True
- return False
-
- def batch_import(self):
- log.debug("Authenticator: batch import in %s",
self.__class__.__name__)
- userlist = res = []
- conn = self.__prep_con()
- error = not conn
- if not error:
- filter = self.url.filterstr % '*'
- try:
- res = conn.search_s(self.url.dn, self.url.scope, filter)
- except Exception, e:
- log.error("Authenticator:, batch import, "\
- "query returned exception %s", e)
- error = True
- if not res:
- log.info("Authenticator: batch import failed, "\
- "query returned no results in %s",
self.__class__.__name__)
- else:
- for dn,ent in res:
- dn_arr = ldap.dn.explode_rdn(dn)
- naming_attr = dn_arr[0].split('=')[0]
- userlist.append(ent[naming_attr][0])
- return userlist, error
-
- def authenticate(self, username, password):
- log.debug("Authenticating against %s", self.__class__.__name__)
- conn = self.__prep_con()
- if not conn:
- return False
- filter = self.url.filterstr % username
- try:
- res = conn.search_s(self.url.dn, self.url.scope, filter)
- except Exception, e:
- log.error("Authenticator: authenticate, "\
- "query returned exception %s", e)
- res = []
- if not res:
- log.info("Authenticator: authentication failed, "\
- "query returned no results in %s",
self.__class__.__name__)
- else:
- for dn,ent in res:
- try:
- conn.simple_bind_s(dn,password)
- _syslog.log("cumin: authenticated user %s via LDAP" % dn)
- return True
- except Exception, e:
- log.info("Authenticator: LDAP authentication "\
- "returned exception %s" % e)
- _syslog.log("cumin: authentication via LDAP failed "\
- "for user" % dn)
- return False
-
-class CuminAuthenticatorScript(object):
- def __init__(self, commandline):
- self.params = {}
- self.cap = []
- me = self.__class__.__name__
- for a in commandline.split(','):
- param,val = a.split('=')
- self.params[param] = val
-
- if self.params.has_key('script') and \
- os.access(self.params['script'], os.X_OK):
- if self.params.has_key('auth'):
- log.debug("Authenticator: adding auth capability to %s", me)
- self.cap.append('a')
- if self.params.has_key('change'):
- log.debug("Authenticator: adding change capability to %s", me)
- self.cap.append('c')
- if self.params.has_key('list'):
- log.debug("Authenticator: adding list capability to %s", me)
- self.cap.append('l')
- else:
- log.error('Authenticator: script parameter missing or target file '\
- 'not executable in %s', me)
-
- def authenticate(self, username, password):
- me = self.__class__.__name__
- if 'a' in self.cap:
- log.debug("Authenticator: executing %s in %s",
- self.params['script'], me)
- # Use nameless pipes to pass parameters.
- # If they are passed as arguments they show up in the output
- # of ps, etc. This way is secure.
- # Note, the call to communicate causes an EOF on stdin
- cmd = [self.params['script']]
- res = subprocess.Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
- out, err = res.communicate(input="%s %s %s" % \
- (self.params['auth'], username,
password))
- log.debug("Authenticator: authenticate, script returned "\
- "%s, %s, exitcode %s", out, err, res.returncode)
- if res.returncode == 0:
- _syslog.log("cumin: authenticated user %s via script" %
username)
- return True
- _syslog.log("cumin: authentication via script failed for user %s" %
username)
- return False
-
- def batch_import(self):
- if 'l' in self.cap:
- log.debug("Authenticator: batch import in %s",
- self.__class__.__name__)
- # Use nameless pipes to pass parameters.
- # If they are passed as arguments they show up in the output
- # of ps, etc. This way is secure.
- # Note, the call to communicate causes an EOF on stdin
- cmd = [self.params['script']]
- res = subprocess.Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
- out, err = res.communicate(input=self.params['list'])
- log.debug("Authenticator: batch import, script returned "\
- "%s, %s, exitcode %s", out, err, res.returncode)
- return out.split(','), False
- return [], False
-
- def change_pw(self, user, newpass, oldpass):
- if 'c' in self.cap:
- me = self.__class__.__name__
- log.debug("Authenticator: change password in %s", me)
-
- # Use nameless pipes to pass parameters.
- # If they are passed as arguments they show up in the output
- # of ps, etc. This way is secure.
- # Note, the call to communicate causes an EOF on stdin
- cmd = [self.params['script']]
- try:
- res = subprocess.Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
- out, err = res.communicate(input="%s %s %s %s" % \
- (self.params['change'], user, newpass,
oldpass))
- log.debug("Authenticator: update password, script returned "\
- "%s, %s, exitcode %s", out, err, res.returncode)
- except Exception, e:
- import traceback
- traceback.print_exc()
- res.returncode = -1
-
- if res.returncode == 0:
- _syslog.log("cumin: updated password via script for user %s" %
user)
- return True
- return False
-
-if have_ldap:
- authen_map = {'ldap': CuminAuthenticatorLDAP,
- 'script': CuminAuthenticatorScript}
-else:
- authen_map = {'script': CuminAuthenticatorScript}
-
-class CuminAuthenticator(object):
- def __init__(self, app, log_authentication=True):
- self.authenticators=[]
- self.app = app
- _syslog.log_auth = log_authentication
- log.info("Initializing %s", self)
- if not have_ldap:
- log.info("Authenticator: import of ldap modules failed, "\
- "ldap mechanism not available")
- for authmech in app.authmech:
- if authmech != "internal":
- try:
- mechname = authmech.split('=')[0]
- log.info("Authenticator: adding auth mechanism %s",
mechname)
- classname = authen_map[mechname]
- except KeyError:
- log.error("Authenticator: unsupported authenticator type
%s",
- mechname)
- continue
- self.authenticators.append(classname(authmech))
-
- def batch_import(self, backend, output_on=False):
- numusers = 0
- numconflicts = 0
- errors = False
- import_list = []
- log.debug("Authenticator: calling batch import")
- try:
- classname = authen_map[backend]
- except KeyError:
- log.error("Authenticator: batch import, unsupported authenticator
"\
- "type '%s'", backend)
- errors = True
-
- if not errors:
- try:
- idx = [x.__class__.__name__ for x in self.authenticators]
- idx = idx.index(classname.__name__)
- except ValueError:
- log.error("Authenticator: batch import, authenticator "\
- "not configured '%s'", backend)
- errors = True
-
- if not errors:
- users, errors = self.authenticators[idx].batch_import()
- for imp in users:
- import_list.append(imp)
-
- if len(import_list) > 0:
- try:
- conn = self.app.database.get_connection()
- cursor = conn.cursor()
- role = self.app.admin.get_role(cursor, "user")
- for importuser in import_list:
- try:
- user = self.app.admin.add_user(cursor, importuser, "")
- if output_on:
- print("Importing user %s" % importuser)
- self.app.admin.add_assignment(cursor, user, role)
- conn.commit()
- numusers += 1
- except IntegrityError:
- if output_on:
- print("Import failed, a user called '%s'
"\
- "already exists" % importuser)
- numconflicts += 1
- conn.rollback()
- finally:
- conn.close()
- return numusers, numconflicts, errors
-
- def authenticate(self, username, password):
- log.debug("Authenticator: calling authenticate")
- cursor = self.app.database.get_read_cursor()
- cls = self.app.model.com_redhat_cumin.User
- user = cls.get_object(cursor, name=username)
- external = len(user.password) == 0
- log.info("Authenticator: authenticating external user %s" % external)
- if not external:
- res = crypt(password, user.password) == user.password
- if res:
- msg = "cumin: authenticated user %s" % username
- else:
- msg = "cumin: authentication failed for user %s" % username
- _syslog.log(msg)
- return res
- else:
- for authenticator in self.authenticators:
- log.debug("Authenticator: authenticate, try %s",
authenticator)
- if authenticator.authenticate(username, password):
- return True
- return False
-
- def update_password(self, username, oldpassword, newpassword):
- status = False
- message = ""
- log.debug("Authenticator: calling update_password")
- conn = self.app.database.get_connection()
- try:
- cursor = conn.cursor()
- cls = self.app.model.com_redhat_cumin.User
- user = cls.get_object(cursor, name=username)
- if user.password == "":
- for authenticator in self.authenticators:
- status = authenticator.authenticate(username, oldpassword)
- if status:
- status = authenticator.change_pw(username,
- oldpassword, newpassword)
- if not status:
- message = "Could not change password"
- break
-
- if not status and message == "":
- message = "The password is incorrect"
- else:
- status = crypt(oldpassword, user.password) == user.password
- if status:
- user.password = crypt_password(newpassword)
- user.save(cursor)
- conn.commit()
- _syslog.log("cumin: updated password for user %s" %
username)
- else:
- message = "The password is incorrect"
- finally:
- conn.close()
- return status, message
Modified: branches/lucidity/cumin/python/cumin/config.py
===================================================================
--- branches/lucidity/cumin/python/cumin/config.py 2011-09-30 15:45:25 UTC (rev 5032)
+++ branches/lucidity/cumin/python/cumin/config.py 2011-09-30 16:29:36 UTC (rev 5033)
@@ -145,9 +145,6 @@
param = ConfigParameter(self, "brokers", str)
param.default = "amqp://localhost"
- param = ConfigParameter(self, "auth", str)
- param.default = 'internal'
-
# Leave default set to None, which is equivalent to
# previous behavior
param = ConfigParameter(self, "sasl-mech-list", str)
Modified: branches/lucidity/cumin/python/cumin/main.py
===================================================================
--- branches/lucidity/cumin/python/cumin/main.py 2011-09-30 15:45:25 UTC (rev 5032)
+++ branches/lucidity/cumin/python/cumin/main.py 2011-09-30 16:29:36 UTC (rev 5033)
@@ -21,7 +21,6 @@
from user import *
from util import *
from widgets import *
-from authenticator import *
from sage.catalog import Catalog
from sage.qmf.qmfoperations import QmfOperations
from sage.wallaby.wallabyoperations import WallabyOperations
@@ -34,12 +33,10 @@
class Cumin(Application):
def __init__(self, home, broker_uris, database_dsn,
- host="localhost", port=45672, persona="default",
- authmech=["internal"]):
+ host="localhost", port=45672, persona="default"):
super(Cumin, self).__init__()
self.home = home
- self.authmech = authmech
model_dir = os.path.join(self.home, "model")
@@ -49,7 +46,6 @@
self.database = CuminDatabase(self, database_dsn)
self.server = CuminServer(self, host, port)
self.admin = CuminAdmin(self)
- self.authenticator = CuminAuthenticator(self)
self.add_resource_dir(os.path.join(self.home, "resources-wooly"))
self.add_resource_dir(os.path.join(self.home, "resources"))
@@ -670,7 +666,6 @@
if qdate is None:
return 0
- import time
return fmt_duration(time.time() - secs(qdate))
def render_text_align(self, session):