fix editUser api for multiple kerberos support

This commit is contained in:
Yu Ming Zhu 2019-10-14 08:27:08 +00:00 committed by Tomas Kopecek
parent 180cf894e2
commit 3e124f685a
3 changed files with 105 additions and 26 deletions

View file

@ -3732,22 +3732,28 @@ def get_user(userInfo=None, strict=False, krb_princs=False):
user['krb_principals'] = list_user_krb_principals(user['id'])
return user
def edit_user(userInfo, name=None, krb_principal=None):
def edit_user(userInfo, name=None, krb_principal_mappings=None):
"""Edit information for an existing user.
userInfo specifies the user to edit
fields changes are provided as keyword arguments:
name: rename the user
krb_principal: change user's kerberos principal
krb_principal_mappings: change user's kerberos principal, it is a list
contains krb_principal pair(s)
- old: krb_principal to modify, None and ''
indicates adding a new krb_principal
- new: new value of krb_principal, None and ''
indicates removing the old krb_principal
"""
context.session.assertPerm('admin')
_edit_user(userInfo, name=name, krb_principal=krb_principal)
_edit_user(userInfo, name=name,
krb_principal_mappings=krb_principal_mappings)
def _edit_user(userInfo, name=None, krb_principal=None):
def _edit_user(userInfo, name=None, krb_principal_mappings=None):
"""Edit information for an existing user."""
user = get_user(userInfo, strict=True)
user = get_user(userInfo, strict=True, krb_princs=True)
if name and user['name'] != name:
# attempt to update user name
values = {
@ -3759,14 +3765,42 @@ def _edit_user(userInfo, name=None, krb_principal=None):
if id is not None:
# new name is taken
raise koji.GenericError("Name %s already taken by user %s" % (name, id))
update = UpdateProcessor('users', values={'userID': user['id']}, clauses=['id = %(userID)i'])
update = UpdateProcessor('users',
values={'userID': user['id']},
clauses=['id = %(userID)i'])
update.set(name=name)
update.execute()
if krb_principal and user['krb_principal'] != krb_principal:
if krb_principal_mappings:
added = set()
removed = set()
for pairs in krb_principal_mappings:
old = pairs.get('old')
new = pairs.get('new')
if old:
removed.add(old)
if new:
added.add(new)
dups = added & removed
if dups:
raise koji.GenericError("There are some conflicts between added"
" and removed Kerberos principals: %s"
% ', '.join(dups))
currents = set(user.get('krb_principals'))
dups = added & currents
if dups:
raise koji.GenericError("Cannot add existing Kerberos"
" principals: %s" % ', '.join(dups))
unable_removed = removed - currents
if unable_removed:
raise koji.GenericError("Cannot remove non-existent Kerberos"
" principals: %s"
% ', '.join(unable_removed))
# attempt to update kerberos principal
update = UpdateProcessor('users', values={'userID': user['id']}, clauses=['id = %(userID)i'])
update.set(krb_principal=krb_principal)
update.execute()
for r in removed:
context.session.removeKrbPrincipal(user['id'], krb_principal=r)
for a in added:
context.session.setKrbPrincipal(user['id'], krb_principal=a)
def list_user_krb_principals(user_info=None):

View file

@ -689,7 +689,12 @@ class Session(object):
def setKrbPrincipal(self, name, krb_principal, krb_princ_check=True):
if krb_princ_check:
self.checkKrbPrincipal(krb_principal)
select = """SELECT id FROM users WHERE name = %(name)s"""
select = """SELECT id FROM users WHERE %s"""
if isinstance(name, six.integer_types):
user_condition = 'id = %(name)i'
else:
user_condition = 'name = %(name)s'
select = select % user_condition
cursor = context.cnx.cursor()
cursor.execute(select, locals())
r = cursor.fetchone()
@ -708,15 +713,20 @@ class Session(object):
select = """SELECT id FROM users
JOIN user_krb_principals
ON users.id = user_krb_principals.user_id
WHERE name = %(name)s
AND krb_principal = %(krb_principal)s"""
WHERE %s
AND krb_principal = %%(krb_principal)s"""
if isinstance(name, six.integer_types):
user_condition = 'id = %(name)i'
else:
user_condition = 'name = %(name)s'
select = select % user_condition
cursor = context.cnx.cursor()
cursor.execute(select, locals())
r = cursor.fetchone()
if not r:
context.cnx.rollback()
raise koji.AuthError(
'could not automatically remove Kerberos Principal:'
'cannot remove Kerberos Principal:'
' %(krb_principal)s with user %(name)s' % locals())
else:
user_id = r[0]

View file

@ -30,11 +30,11 @@ class TestEditUser(unittest.TestCase):
def test_edit(self):
self.get_user.return_value = {'id': 333,
'name': 'user',
'krb_principal': 'krb'}
'name': 'user',
'krb_principals': ['krb']}
self._singleValue.return_value = None
kojihub._edit_user('user', name='newuser', krb_principal='krb')
kojihub._edit_user('user', name='newuser')
# check the update
self.assertEqual(len(self.updates), 1)
update = self.updates[0]
@ -43,18 +43,53 @@ class TestEditUser(unittest.TestCase):
self.assertEqual(update.values, {'userID': 333})
self.assertEqual(update.clauses, ['id = %(userID)i'])
kojihub._edit_user('user', name='user', krb_principal='newkrb')
# check the insert/update
self.assertEqual(len(self.updates), 2)
update = self.updates[1]
self.assertEqual(update.table, 'users')
self.assertEqual(update.data, {'krb_principal': 'newkrb'})
self.assertEqual(update.values, {'userID': 333})
self.assertEqual(update.clauses, ['id = %(userID)i'])
kojihub._edit_user('user', krb_principal_mappings=[{'old': 'krb',
'new': 'newkrb'}])
self.context.session.removeKrbPrincipal. \
assert_called_once_with(333, krb_principal='krb')
self.context.session.setKrbPrincipal. \
assert_called_once_with(333, krb_principal='newkrb')
self.context.reset_mock()
with self.assertRaises(koji.GenericError) as cm:
kojihub._edit_user('user',
krb_principal_mappings=[{'old': 'krb',
'new': 'newkrb'},
{'old': 'newkrb',
'new': 'newnewkrb'}
])
self.assertEqual(cm.exception.args[0],
'There are some conflicts between added and removed'
' Kerberos principals: newkrb')
self.context.session.removeKrbPrincipal.assert_not_called()
self.context.session.setKrbPrincipal.assert_not_called()
self.context.reset_mock()
with self.assertRaises(koji.GenericError) as cm:
kojihub._edit_user('user',
krb_principal_mappings=[{'old': 'otherkrb',
'new': 'newkrb'}])
self.assertEqual(cm.exception.args[0],
'Cannot remove non-existent Kerberos principals:'
' otherkrb')
self.context.session.removeKrbPrincipal.assert_not_called()
self.context.session.setKrbPrincipal.assert_not_called()
self.context.reset_mock()
with self.assertRaises(koji.GenericError) as cm:
kojihub._edit_user('user',
krb_principal_mappings=[{'old': None,
'new': 'krb'}])
self.assertEqual(cm.exception.args[0],
'Cannot add existing Kerberos principals: krb')
self.context.session.removeKrbPrincipal.assert_not_called()
self.context.session.setKrbPrincipal.assert_not_called()
self._singleValue.reset_mock()
self._singleValue.return_value = 2
with self.assertRaises(koji.GenericError) as cm:
kojihub._edit_user('user', name='newuser')
self._singleValue.assert_called_once()
self.assertEqual(cm.exception.args[0], 'Name newuser already taken by user 2')
self.assertEqual(cm.exception.args[0],
'Name newuser already taken by user 2')