From acd7cde21c2c02faf2611721d6f265e88870ecfe Mon Sep 17 00:00:00 2001 From: Mike Bonnet Date: Mon, 19 Mar 2007 17:27:48 -0400 Subject: [PATCH] - centralize user creation in the Session class - check user status on login as well as session creation - don't even create sessions for blocked users --- cli/koji | 6 ++--- docs/schema.sql | 6 ++--- hub/kojihub.py | 38 +++++++------------------------- koji/auth.py | 58 ++++++++++++++++++++++++++++++++++++++----------- 4 files changed, 59 insertions(+), 49 deletions(-) diff --git a/cli/koji b/cli/koji index cdee8c2c..877ae9d7 100755 --- a/cli/koji +++ b/cli/koji @@ -1045,19 +1045,19 @@ def handle_add_user(options, session, args): usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) parser.add_option("--principal", help=_("The Kerberos principal for this user")) - parser.add_option("--disabled", help=_("Prohibit logins by this user"), action="store_true") + parser.add_option("--disable", help=_("Prohibit logins by this user"), action="store_true") (options, args) = parser.parse_args(args) if len(args) < 1: parser.error(_("You must specify the username of the user to add")) elif len(args) > 1: parser.error(_("This command only accepts one argument (username)")) username = args[0] - if options.disabled: + if options.disable: status = koji.USER_STATUS['BLOCKED'] else: status = koji.USER_STATUS['NORMAL'] activate_session(session) - user_id = session.addUser(username, status=status, krb_principal=options.principal) + user_id = session.createUser(username, status=status, krb_principal=options.principal) print "Added user %s (%i)" % (username, user_id) def handle_enable_user(options, session, args): diff --git a/docs/schema.sql b/docs/schema.sql index 02fe02ba..b94915f8 100644 --- a/docs/schema.sql +++ b/docs/schema.sql @@ -85,8 +85,8 @@ CREATE TABLE users ( id SERIAL NOT NULL PRIMARY KEY, name VARCHAR(255) UNIQUE NOT NULL, password VARCHAR(255), - status INTEGER, - usertype INTEGER, + status INTEGER NOT NULL, + usertype INTEGER NOT NULL, krb_principal VARCHAR(255) UNIQUE ) WITHOUT OIDS; @@ -598,7 +598,7 @@ rpminfo, rpmdeps, rpmfiles TO PUBLIC; -- example code to add initial admins --- insert into users (name, usertype, krb_principal) values ('admin', 0, 'admin@EXAMPLE.COM'); +-- insert into users (name, usertype, status, krb_principal) values ('admin', 0, 0, 'admin@EXAMPLE.COM'); -- insert into user_perms (user_id, perm_id) -- select users.id, permissions.id from users, permissions -- where users.name in ('admin') diff --git a/hub/kojihub.py b/hub/kojihub.py index 0d0f5cff..39693e45 100644 --- a/hub/kojihub.py +++ b/hub/kojihub.py @@ -3558,15 +3558,9 @@ def get_build_notifications(user_id): def new_group(name): """Add a user group to the database""" - context.session.assertPerm('admin') if get_user(name): raise koji.GenericError, 'user/group already exists: %s' % name - group_id = _singleValue("SELECT nextval('users_id_seq')", strict=True) - usertype = koji.USERTYPES['GROUP'] - insert = """INSERT INTO users (id, name, password, usertype) - VALUES (%(group_id)i, %(name)s, NULL, %(usertype)i)""" - _dml(insert, locals()) - return group_id + return context.session.createUser(name, usertype=koji.USERTYPES['GROUP']) def add_group_member(group,user): """Add user to group""" @@ -3621,6 +3615,7 @@ def get_group_members(group): return _multiRow(q, locals(), fields) def set_user_status(user, status): + context.session.assertPerm('admin') if not koji.USER_STATUS.get(status): raise koji.GenericError, 'invalid status: %s' % status if user['status'] == status: @@ -4717,28 +4712,17 @@ class RootExports(object): VALUES (%(user_id)i, %(perm_id)i)""" _dml(insert, locals()) - def addUser(self, username, password=None, status=None, krb_principal=None): + def createUser(self, username, status=None, krb_principal=None): """Add a user to the database""" - - context.session.assertPerm('admin') if get_user(username): raise koji.GenericError, 'user already exists: %s' % username if krb_principal and get_user(krb_principal): raise koji.GenericError, 'user with this Kerberos principal already exists: %s' % krb_principal - c = context.cnx.cursor() - userID = koji.get_sequence_value(c, 'users_id_seq') - userType = koji.USERTYPES['NORMAL'] - if status == None: - status = koji.USER_STATUS['NORMAL'] - insert = """INSERT INTO users (id, name, password, usertype, status, krb_principal) - VALUES (%(userID)i, %(username)s, %(password)s, %(userType)i, %(status)i, %(krb_principal)s)""" - context.commit_pending = True - c.execute(insert, locals()) - return userID + + return context.session.createUser(username, status=status, krb_principal=krb_principal) def enableUser(self, username): """Enable logins by the specified user""" - context.session.assertPerm('admin') user = get_user(username) if not user: raise koji.GenericError, 'unknown user: %s' % username @@ -4746,7 +4730,6 @@ class RootExports(object): def disableUser(self, username): """Disable logins by the specified user""" - context.session.assertPerm('admin') user = get_user(username) if not user: raise koji.GenericError, 'unknown user: %s' % username @@ -5035,21 +5018,17 @@ class RootExports(object): def addHost(self, hostname, arches, krb_principal=None): """Add a host to the database""" - context.session.assertPerm('admin') if get_host(hostname): raise koji.GenericError, 'host already exists: %s' % hostname q = """SELECT id FROM channels WHERE name = 'default'""" default_channel = _singleValue(q) - #users entry - userID = _singleValue("SELECT nextval('users_id_seq')", strict=True) - userType = koji.USERTYPES['HOST'] if krb_principal is None: fmt = context.opts.get('HostPrincipalFormat','compile/%s@EXAMPLE.COM') krb_principal = fmt % hostname - insert = """INSERT INTO users (id, name, password, usertype, krb_principal) - VALUES (%(userID)i, %(hostname)s, null, %(userType)i, %(krb_principal)s)""" - _dml(insert, locals()) + #users entry + userID = context.session.createUser(hostname, usertype=koji.USERTYPES['HOST'], + krb_principal=krb_principal) #host entry hostID = _singleValue("SELECT nextval('host_id_seq')", strict=True) arches = " ".join(arches) @@ -5062,7 +5041,6 @@ class RootExports(object): _dml(insert, locals()) return hostID - def enableHost(self, hostname): """Mark a host as enabled""" set_host_enabled(hostname, True) diff --git a/koji/auth.py b/koji/auth.py index a32611d0..bb5017c4 100644 --- a/koji/auth.py +++ b/koji/auth.py @@ -122,8 +122,8 @@ class Session(object): c.execute(q,session_data) user_data = dict(zip(fields,c.fetchone())) - if user_data['status'] == koji.USER_STATUS['BLOCKED']: - raise koji.AuthError, 'User not allowed' + if user_data['status'] != koji.USER_STATUS['NORMAL']: + raise koji.AuthError, 'logins by %s are not allowed' % user_data['name'] #check for exclusive sessions if session_data['exclusive']: #we are the exclusive session for this user @@ -209,6 +209,19 @@ class Session(object): raise koji.AuthLockError, self.lockerror return True + def checkLoginAllowed(self, user_id): + """Verify that the user is allowed to login""" + cursor = context.cnx.cursor() + query = """SELECT name, usertype, status FROM users WHERE id = %(user_id)i""" + cursor.execute(query, locals()) + result = cursor.fetchone() + if not result: + raise koji.AuthError, 'invalid user_id: %s' % user_id + name, usertype, status = result + + if status != koji.USER_STATUS['NORMAL']: + raise koji.AuthError, 'logins by %s are not allowed' % name + def login(self,user,password,opts=None): """create a login session""" if opts is None: @@ -225,13 +238,15 @@ class Session(object): # check passwd c = context.cnx.cursor() - q = """SELECT id,status,usertype FROM users + 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,status,usertype) = r + user_id = r[0] + + self.checkLoginAllowed(user_id) #create session and return sinfo = self.createSession(user_id, hostip, koji.AUTHTYPE_NORMAL) @@ -281,6 +296,8 @@ class Session(object): else: raise koji.AuthError, 'Unknown Kerberos principal: %s' % login_principal + self.checkLoginAllowed(user_id) + hostip = context.req.connection.remote_ip if hostip == '127.0.0.1': hostip = socket.gethostbyname(socket.gethostname()) @@ -350,18 +367,19 @@ class Session(object): username = client_name cursor = context.cnx.cursor() - query = """SELECT id, status FROM users + query = """SELECT id FROM users WHERE name = %(username)s""" cursor.execute(query, locals()) result = cursor.fetchone() if result: - user_id, status = result + user_id = result[0] else: if context.opts['LoginCreatesUser'].lower() in ('yes', 'on', 'true', '1'): - user_id = self.createUser(username, koji.USERTYPES['NORMAL'], None) - status = None + user_id = self.createUser(username) else: raise koji.AuthError, 'Unknown user: %s' % username + + self.checkLoginAllowed(user_id) hostip = context.req.connection.remote_ip if hostip == '127.0.0.1': @@ -541,18 +559,33 @@ class Session(object): else: return None - def createUser(self, name, usertype, krb_principal): + def createUser(self, name, usertype=None, status=None, krb_principal=None): """ Create a new user, using the provided values. Return the user_id of the newly-created user. """ + self.assertPerm('admin') + + if not name: + raise koji.GenericError, 'a user must have a non-empty name' + + if usertype == None: + usertype = koji.USERTYPES['NORMAL'] + elif not koji.USERTYPES.get(usertype): + raise koji.GenericError, 'invalid user type: %s' % usertype + + if status == None: + status = koji.USER_STATUS['NORMAL'] + elif not koji.USER_STATUS.get(status): + raise koji.GenericError, 'invalid status: %s' % status + cursor = context.cnx.cursor() select = """SELECT nextval('users_id_seq')""" cursor.execute(select, locals()) user_id = cursor.fetchone()[0] - insert = """INSERT INTO users (id, name, usertype, krb_principal) - VALUES (%(user_id)i, %(name)s, %(usertype)i, %(krb_principal)s)""" + insert = """INSERT INTO users (id, name, usertype, status, krb_principal) + VALUES (%(user_id)i, %(name)s, %(usertype)i, %(status)i, %(krb_principal)s)""" cursor.execute(insert, locals()) context.cnx.commit() @@ -566,9 +599,8 @@ class Session(object): if atidx == -1: raise koji.AuthError, 'invalid Kerberos principal: %s' % krb_principal user_name = krb_principal[:atidx] - user_type = koji.USERTYPES['NORMAL'] - return self.createUser(user_name, user_type, krb_principal) + return self.createUser(user_name, krb_principal=krb_principal) def get_user_groups(user_id): """Get user groups