2018-03-03 12:22:56 +00:00
# authentication module
# Copyright (c) 2005-2014 Red Hat, Inc.
#
# Koji is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation;
# version 2.1 of the License.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this software; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# Authors:
# Mike McLean <mikem@redhat.com>
# Mike Bonnet <mikeb@redhat.com>
from __future__ import absolute_import
import socket
import string
import random
import base64
try :
import krbV
except ImportError :
krbV = None
import urlparse #for parse_qs
from . context import context
from six . moves import range
2019-06-01 22:55:04 +02:00
from six . moves import urllib
2018-03-03 12:22:56 +00:00
from six . moves import zip
import six
2019-06-01 22:55:04 +02:00
from . util import to_list
2018-03-03 12:22:56 +00:00
# 1 - load session if provided
# - check uri for session id
# - load session info from db
# - validate session
# 2 - create a session
# - maybe in two steps
# -
RetryWhitelist = [
' host.taskWait ' ,
' host.taskUnwait ' ,
' host.taskSetWait ' ,
' host.updateHost ' ,
' host.setBuildRootState ' ,
' repoExpire ' ,
' repoDelete ' ,
' repoProblem ' ,
]
class Session ( object ) :
def __init__ ( self , args = None , hostip = None ) :
self . logged_in = False
self . id = None
self . master = None
self . key = None
self . user_id = None
self . authtype = None
self . hostip = None
self . user_data = { }
self . message = ' '
self . exclusive = False
self . lockerror = None
self . callnum = None
2018-10-03 19:20:31 +00:00
# we look up perms, groups, and host_id on demand, see __getattr__
2018-10-03 19:19:49 +00:00
self . _perms = None
self . _groups = None
self . _host_id = ' '
2018-03-03 12:22:56 +00:00
#get session data from request
if args is None :
environ = getattr ( context , ' environ ' , { } )
args = environ . get ( ' QUERY_STRING ' , ' ' )
if not args :
self . message = ' no session args '
return
args = urlparse . parse_qs ( args , strict_parsing = True )
2019-06-01 22:55:04 +02:00
args = urllib . parse . parse_qs ( args , strict_parsing = True )
2018-03-03 12:22:56 +00:00
try :
2018-10-03 19:19:49 +00:00
id = int ( args [ ' session-id ' ] [ 0 ] )
2018-03-03 12:22:56 +00:00
key = args [ ' session-key ' ] [ 0 ]
except KeyError as field :
raise koji . AuthError ( ' %s not specified in session args ' % field )
try :
callnum = args [ ' callnum ' ] [ 0 ]
except :
callnum = None
#lookup the session
c = context . cnx . cursor ( )
fields = {
' authtype ' : ' authtype ' ,
' callnum ' : ' callnum ' ,
' exclusive ' : ' exclusive ' ,
' expired ' : ' expired ' ,
' master ' : ' master ' ,
' start_time ' : ' start_time ' ,
' update_time ' : ' update_time ' ,
' EXTRACT(EPOCH FROM start_time) ' : ' start_ts ' ,
' EXTRACT(EPOCH FROM update_time) ' : ' update_ts ' ,
' user_id ' : ' user_id ' ,
}
# sort for stability (unittests)
2019-06-01 22:55:04 +02:00
fields , aliases = zip ( * sorted ( fields . items ( ) , key = lambda x : x [ 1 ] ) )
2018-03-03 12:22:56 +00:00
q = """
SELECT % s FROM sessions
WHERE id = % % ( id ) i
AND key = % % ( key ) s
AND hostip = % % ( hostip ) s
FOR UPDATE
""" % " , " .join(fields)
c . execute ( q , locals ( ) )
row = c . fetchone ( )
if not row :
raise koji . AuthError ( ' Invalid session or bad credentials ' )
2019-06-01 22:55:04 +02:00
session_data = dict ( zip ( aliases , row ) )
2018-03-03 12:22:56 +00:00
#check for expiration
if session_data [ ' expired ' ] :
raise koji . AuthExpired ( ' session " %i " has expired ' % id )
#check for callnum sanity
if callnum is not None :
try :
callnum = int ( callnum )
except ( ValueError , TypeError ) :
raise koji . AuthError ( " Invalid callnum: %r " % callnum )
lastcall = session_data [ ' callnum ' ]
if lastcall is not None :
if lastcall > callnum :
raise koji . SequenceError ( " %d > %d (session %d ) " \
% ( lastcall , callnum , id ) )
elif lastcall == callnum :
#Some explanation:
#This function is one of the few that performs its own commit.
#However, our storage of the current callnum is /after/ that
#commit. This means the the current callnum only gets committed if
#a commit happens afterward.
#We only schedule a commit for dml operations, so if we find the
#callnum in the db then a previous attempt succeeded but failed to
#return. Data was changed, so we cannot simply try the call again.
method = getattr ( context , ' method ' , ' UNKNOWN ' )
if method not in RetryWhitelist :
raise koji . RetryError (
" unable to retry call %d (method %s ) for session %d " \
% ( callnum , method , id ) )
# read user data
#historical note:
# we used to get a row lock here as an attempt to maintain sanity of exclusive
# sessions, but it was an imperfect approach and the lock could cause some
# performance issues.
fields = ( ' name ' , ' status ' , ' usertype ' )
q = """ SELECT %s FROM users WHERE id= %% (user_id)s """ % ' , ' . join ( fields )
c . execute ( q , session_data )
2019-06-01 22:55:04 +02:00
user_data = dict ( zip ( fields , c . fetchone ( ) ) )
2018-03-03 12:22:56 +00:00
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
self . exclusive = True
else :
#see if an exclusive session exists
q = """ SELECT id FROM sessions WHERE user_id= %(user_id)s
AND " exclusive " = TRUE AND expired = FALSE """
#should not return multiple rows (unique constraint)
c . execute ( q , session_data )
row = c . fetchone ( )
if row :
( excl_id , ) = row
if excl_id == session_data [ ' master ' ] :
#(note excl_id cannot be None)
#our master session has the lock
self . exclusive = True
else :
#a session unrelated to us has the lock
self . lockerror = " User locked by another session "
# we don't enforce here, but rely on the dispatcher to enforce
# if appropriate (otherwise it would be impossible to steal
# an exclusive session with the force option).
# update timestamp
q = """ UPDATE sessions SET update_time=NOW() WHERE id = %(id)i """
c . execute ( q , locals ( ) )
#save update time
context . cnx . commit ( )
#update callnum (this is deliberately after the commit)
#see earlier note near RetryError
if callnum is not None :
q = """ UPDATE sessions SET callnum= %(callnum)i WHERE id = %(id)i """
c . execute ( q , locals ( ) )
# record the login data
self . id = id
self . key = key
self . hostip = hostip
self . callnum = callnum
self . user_id = session_data [ ' user_id ' ]
self . authtype = session_data [ ' authtype ' ]
self . master = session_data [ ' master ' ]
self . session_data = session_data
self . user_data = user_data
self . logged_in = True
def __getattr__ ( self , name ) :
# grab perm and groups data on the fly
if name == ' perms ' :
if self . _perms is None :
#in a dict for quicker lookup
self . _perms = dict ( [ [ name , 1 ] for name in get_user_perms ( self . user_id ) ] )
return self . _perms
elif name == ' groups ' :
if self . _groups is None :
self . _groups = get_user_groups ( self . user_id )
return self . _groups
elif name == ' host_id ' :
if self . _host_id == ' ' :
self . _host_id = self . _getHostId ( )
return self . _host_id
else :
raise AttributeError ( " %s " % name )
def __str__ ( self ) :
# convenient display for debugging
if not self . logged_in :
s = " session: not logged in "
else :
s = " session %d : %r " % ( self . id , self . __dict__ )
if self . message :
s + = " ( %s ) " % self . message
return s
def validate ( self ) :
if self . lockerror :
raise koji . AuthLockError ( self . lockerror )
return True
def get_remote_ip ( self , override = None ) :
if not context . opts [ ' CheckClientIP ' ] :
return ' - '
elif override is not None :
return override
else :
hostip = context . environ [ ' REMOTE_ADDR ' ]
#XXX - REMOTE_ADDR not promised by wsgi spec
if hostip == ' 127.0.0.1 ' :
hostip = socket . gethostbyname ( socket . gethostname ( ) )
return hostip
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 :
opts = { }
if not isinstance ( password , str ) or len ( password ) == 0 :
raise koji . AuthError ( ' invalid username or password ' )
if self . logged_in :
raise koji . GenericError ( " Already logged in " )
hostip = self . get_remote_ip ( override = opts . get ( ' hostip ' ) )
# 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 ]
self . checkLoginAllowed ( user_id )
#create session and return
sinfo = self . createSession ( user_id , hostip , koji . AUTHTYPE_NORMAL )
session_id = sinfo [ ' session-id ' ]
context . cnx . commit ( )
return sinfo
def krbLogin ( self , krb_req , proxyuser = None ) :
""" Authenticate the user using the base64-encoded
AP_REQ message in krb_req . If proxyuser is not None ,
log in that user instead of the user associated with the
Kerberos principal . The principal must be an authorized
" proxy_principal " in the server config . """
if self . logged_in :
raise koji . AuthError ( " Already logged in " )
if krbV is None :
# python3 is not supported
raise koji . AuthError ( " krbV module not installed " )
if not ( context . opts . get ( ' AuthPrincipal ' ) and context . opts . get ( ' AuthKeytab ' ) ) :
raise koji . AuthError ( ' not configured for Kerberos authentication ' )
ctx = krbV . default_context ( )
srvprinc = krbV . Principal ( name = context . opts . get ( ' AuthPrincipal ' ) , context = ctx )
srvkt = krbV . Keytab ( name = context . opts . get ( ' AuthKeytab ' ) , context = ctx )
ac = krbV . AuthContext ( context = ctx )
ac . flags = krbV . KRB5_AUTH_CONTEXT_DO_SEQUENCE | krbV . KRB5_AUTH_CONTEXT_DO_TIME
conninfo = self . getConnInfo ( )
ac . addrs = conninfo
# decode and read the authentication request
2019-06-01 22:55:04 +02:00
req = base64 . b64decode ( krb_req )
2018-03-03 12:22:56 +00:00
ac , opts , sprinc , ccreds = ctx . rd_req ( req , server = srvprinc , keytab = srvkt ,
auth_context = ac ,
options = krbV . AP_OPTS_MUTUAL_REQUIRED )
cprinc = ccreds [ 2 ]
# Successfully authenticated via Kerberos, now log in
if proxyuser :
proxyprincs = [ princ . strip ( ) for princ in context . opts . get ( ' ProxyPrincipals ' , ' ' ) . split ( ' , ' ) ]
if cprinc . name in proxyprincs :
login_principal = proxyuser
else :
raise koji . AuthError (
' Kerberos principal %s is not authorized to log in other users ' % cprinc . name )
else :
login_principal = cprinc . name
user_id = self . getUserIdFromKerberos ( login_principal )
if not user_id :
user_id = self . getUserId ( login_principal )
if not user_id :
# Only do autocreate if we also couldn't find by username AND the proxyuser
# looks like a krb5 principal
if context . opts . get ( ' LoginCreatesUser ' ) and ' @ ' in login_principal :
user_id = self . createUserFromKerberos ( login_principal )
else :
raise koji . AuthError ( ' Unknown Kerberos principal: %s ' % login_principal )
self . checkLoginAllowed ( user_id )
hostip = self . get_remote_ip ( )
sinfo = self . createSession ( user_id , hostip , koji . AUTHTYPE_KERB )
# encode the reply
rep = ctx . mk_rep ( auth_context = ac )
rep_enc = base64 . encodestring ( rep )
# encrypt and encode the login info
sinfo_priv = ac . mk_priv ( ' % (session-id)s % (session-key)s ' % sinfo )
sinfo_enc = base64 . encodestring ( sinfo_priv )
return ( rep_enc , sinfo_enc , conninfo )
def getConnInfo ( self ) :
""" Return a tuple containing connection information
in the following format :
( local ip addr , local port , remote ip , remote port ) """
# For some reason req.connection.{local,remote}_addr contain port info,
# but no IP info. Use req.connection.{local,remote}_ip for that instead.
# See: http://lists.planet-lab.org/pipermail/devel-community/2005-June/001084.html
# local_ip seems to always be set to the same value as remote_ip,
# so get the local ip via a different method
local_ip = socket . gethostbyname ( context . environ [ ' SERVER_NAME ' ] )
remote_ip = context . environ [ ' REMOTE_ADDR ' ]
#XXX - REMOTE_ADDR not promised by wsgi spec
# it appears that calling setports() with *any* value results in authentication
# failing with "Incorrect net address", so return 0 (which prevents
# python-krbV from calling setports())
local_port = 0
remote_port = 0
return ( local_ip , local_port , remote_ip , remote_port )
def sslLogin ( self , proxyuser = None ) :
if self . logged_in :
raise koji . AuthError ( " Already logged in " )
if context . environ . get ( ' REMOTE_USER ' ) :
username = context . environ . get ( ' REMOTE_USER ' )
client_dn = username
authtype = koji . AUTHTYPE_GSSAPI
else :
if context . environ . get ( ' SSL_CLIENT_VERIFY ' ) != ' SUCCESS ' :
raise koji . AuthError ( ' could not verify client: %s ' % context . environ . get ( ' SSL_CLIENT_VERIFY ' ) )
name_dn_component = context . opts . get ( ' DNUsernameComponent ' , ' CN ' )
username = context . environ . get ( ' SSL_CLIENT_S_DN_ %s ' % name_dn_component )
if not username :
raise koji . AuthError ( ' unable to get user information ( %s ) from client certificate ' % name_dn_component )
client_dn = context . environ . get ( ' SSL_CLIENT_S_DN ' )
authtype = koji . AUTHTYPE_SSL
if proxyuser :
proxy_dns = [ dn . strip ( ) for dn in context . opts . get ( ' ProxyDNs ' , ' ' ) . split ( ' | ' ) ]
if client_dn in proxy_dns :
# the SSL-authenticated user authorized to login other users
username = proxyuser
else :
raise koji . AuthError ( ' %s is not authorized to login other users ' % client_dn )
2018-03-03 12:23:15 +00:00
user_id = self . getUserIdFromKerberos ( username )
2018-03-03 12:22:56 +00:00
if not user_id :
2018-03-03 12:23:15 +00:00
user_id = self . getUserId ( username )
if not user_id :
if context . opts . get ( ' LoginCreatesUser ' ) :
user_id = self . createUser ( username )
else :
raise koji . AuthError ( ' Unknown user: %s ' % username )
2018-03-03 12:22:56 +00:00
self . checkLoginAllowed ( user_id )
hostip = self . get_remote_ip ( )
sinfo = self . createSession ( user_id , hostip , authtype )
return sinfo
def makeExclusive ( self , force = False ) :
""" Make this session exclusive """
c = context . cnx . cursor ( )
if self . master is not None :
raise koji . GenericError ( " subsessions cannot become exclusive " )
if self . exclusive :
#shouldn't happen
raise koji . GenericError ( " session is already exclusive " )
user_id = self . user_id
session_id = self . id
#acquire a row lock on the user entry
q = """ SELECT id FROM users WHERE id= %(user_id)s FOR UPDATE """
c . execute ( q , locals ( ) )
# check that no other sessions for this user are exclusive
q = """ SELECT id FROM sessions WHERE user_id= %(user_id)s
AND expired = FALSE AND " exclusive " = TRUE
FOR UPDATE """
c . execute ( q , locals ( ) )
row = c . fetchone ( )
if row :
if force :
#expire the previous exclusive session and try again
( excl_id , ) = row
q = """ UPDATE sessions SET expired=TRUE, " exclusive " =NULL WHERE id= %(excl_id)s """
c . execute ( q , locals ( ) )
else :
raise koji . AuthLockError ( " Cannot get exclusive session " )
#mark this session exclusive
q = """ UPDATE sessions SET " exclusive " =TRUE WHERE id= %(session_id)s """
c . execute ( q , locals ( ) )
context . cnx . commit ( )
def makeShared ( self ) :
""" Drop out of exclusive mode """
c = context . cnx . cursor ( )
session_id = self . id
q = """ UPDATE sessions SET " exclusive " =NULL WHERE id= %(session_id)s """
c . execute ( q , locals ( ) )
context . cnx . commit ( )
def logout ( self ) :
""" expire a login session """
if not self . logged_in :
#XXX raise an error?
raise koji . AuthError ( " Not logged in " )
update = """ UPDATE sessions
SET expired = TRUE , exclusive = NULL
WHERE id = % ( id ) i OR master = % ( id ) i """
#note we expire subsessions as well
c = context . cnx . cursor ( )
c . execute ( update , { ' id ' : self . id } )
context . cnx . commit ( )
self . logged_in = False
def logoutChild ( self , session_id ) :
""" expire a subsession """
if not self . logged_in :
#XXX raise an error?
raise koji . AuthError ( " Not logged in " )
update = """ UPDATE sessions
SET expired = TRUE , exclusive = NULL
WHERE id = % ( session_id ) i AND master = % ( master ) i """
master = self . id
c = context . cnx . cursor ( )
c . execute ( update , locals ( ) )
context . cnx . commit ( )
def createSession ( self , user_id , hostip , authtype , master = None ) :
""" Create a new session for the given user.
Return a map containing the session - id and session - key .
If master is specified , create a subsession
"""
c = context . cnx . cursor ( )
# generate a random key
alnum = string . ascii_letters + string . digits
key = " %s - %s " % ( user_id ,
' ' . join ( [ random . choice ( alnum ) for x in range ( 1 , 20 ) ] ) )
# use sha? sha.new(phrase).hexdigest()
# get a session id
q = """ SELECT nextval( ' sessions_id_seq ' ) """
c . execute ( q , { } )
( session_id , ) = c . fetchone ( )
#add session id to database
q = """
INSERT INTO sessions ( id , user_id , key , hostip , authtype , master )
VALUES ( % ( session_id ) i , % ( user_id ) i , % ( key ) s , % ( hostip ) s , % ( authtype ) i , % ( master ) s )
"""
c . execute ( q , locals ( ) )
context . cnx . commit ( )
#return session info
return { ' session-id ' : session_id , ' session-key ' : key }
def subsession ( self ) :
" Create a subsession "
if not self . logged_in :
raise koji . AuthError ( " Not logged in " )
master = self . master
if master is None :
master = self . id
return self . createSession ( self . user_id , self . hostip , self . authtype ,
master = master )
def getPerms ( self ) :
if not self . logged_in :
return [ ]
2019-06-01 22:55:04 +02:00
return to_list ( self . perms . keys ( ) )
2018-03-03 12:22:56 +00:00
def hasPerm ( self , name ) :
if not self . logged_in :
return False
return name in self . perms
def assertPerm ( self , name ) :
if not self . hasPerm ( name ) and not self . hasPerm ( ' admin ' ) :
raise koji . ActionNotAllowed ( " %s permission required " % name )
def assertLogin ( self ) :
if not self . logged_in :
raise koji . ActionNotAllowed ( " you must be logged in for this operation " )
def hasGroup ( self , group_id ) :
if not self . logged_in :
return False
#groups indexed by id
return group_id in self . groups
def isUser ( self , user_id ) :
if not self . logged_in :
return False
return ( self . user_id == user_id or self . hasGroup ( user_id ) )
def assertUser ( self , user_id ) :
if not self . isUser ( user_id ) and not self . hasPerm ( ' admin ' ) :
raise koji . ActionNotAllowed ( " not owner " )
def _getHostId ( self ) :
''' Using session data, find host id (if there is one) '''
if self . user_id is None :
return None
c = context . cnx . cursor ( )
q = """ SELECT id FROM host WHERE user_id = %(uid)d """
c . execute ( q , { ' uid ' : self . user_id } )
r = c . fetchone ( )
c . close ( )
if r :
return r [ 0 ]
else :
return None
def getHostId ( self ) :
#for compatibility
return self . host_id
def getUserId ( self , username ) :
""" Return the user ID associated with a particular username. If no user
with the given username if found , return None . """
c = context . cnx . cursor ( )
q = """ SELECT id FROM users WHERE name = %(username)s """
c . execute ( q , locals ( ) )
r = c . fetchone ( )
c . close ( )
if r :
return r [ 0 ]
else :
return None
def getUserIdFromKerberos ( self , krb_principal ) :
""" Return the user ID associated with a particular Kerberos principal.
If no user with the given princpal if found , return None . """
c = context . cnx . cursor ( )
q = """ SELECT id FROM users WHERE krb_principal = %(krb_principal)s """
c . execute ( q , locals ( ) )
r = c . fetchone ( )
c . close ( )
if r :
return r [ 0 ]
else :
return None
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 .
"""
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, status, krb_principal)
VALUES ( % ( user_id ) i , % ( name ) s , % ( usertype ) i , % ( status ) i , % ( krb_principal ) s ) """
cursor . execute ( insert , locals ( ) )
context . cnx . commit ( )
return user_id
def setKrbPrincipal ( self , name , krb_principal ) :
usertype = koji . USERTYPES [ ' NORMAL ' ]
status = koji . USER_STATUS [ ' NORMAL ' ]
update = """ UPDATE users SET krb_principal = %(krb_principal)s WHERE name = %(name)s AND usertype = %(usertype)i AND status = %(status)i RETURNING users.id """
cursor = context . cnx . cursor ( )
cursor . execute ( update , locals ( ) )
r = cursor . fetchall ( )
if len ( r ) != 1 :
context . cnx . rollback ( )
raise koji . AuthError ( ' could not automatically associate Kerberos Principal with existing user %s ' % name )
else :
context . cnx . commit ( )
return r [ 0 ] [ 0 ]
def createUserFromKerberos ( self , krb_principal ) :
""" Create a new user, based on the Kerberos principal. Their
username will be everything before the " @ " in the principal .
Return the ID of the newly created user . """
atidx = krb_principal . find ( ' @ ' )
if atidx == - 1 :
raise koji . AuthError ( ' invalid Kerberos principal: %s ' % krb_principal )
user_name = krb_principal [ : atidx ]
# check if user already exists
c = context . cnx . cursor ( )
q = """ SELECT krb_principal FROM users
WHERE name = % ( user_name ) s """
c . execute ( q , locals ( ) )
r = c . fetchone ( )
if not r :
return self . createUser ( user_name , krb_principal = krb_principal )
else :
existing_user_krb = r [ 0 ]
if existing_user_krb is not None :
raise koji . AuthError ( ' user %s already associated with other Kerberos principal: %s ' % ( user_name , existing_user_krb ) )
return self . setKrbPrincipal ( user_name , krb_principal )
def get_user_groups ( user_id ) :
""" Get user groups
returns a dictionary where the keys are the group ids and the values
are the group names """
c = context . cnx . cursor ( )
t_group = koji . USERTYPES [ ' GROUP ' ]
q = """ SELECT group_id,name
FROM user_groups JOIN users ON group_id = users . id
WHERE active = TRUE AND users . usertype = % ( t_group ) i
AND user_id = % ( user_id ) i """
c . execute ( q , locals ( ) )
return dict ( c . fetchall ( ) )
def get_user_perms ( user_id ) :
c = context . cnx . cursor ( )
q = """ SELECT name
FROM user_perms JOIN permissions ON perm_id = permissions . id
WHERE active = TRUE AND user_id = % ( user_id ) s """
c . execute ( q , locals ( ) )
#return a list of permissions by name
return [ row [ 0 ] for row in c . fetchall ( ) ]
def get_user_data ( user_id ) :
c = context . cnx . cursor ( )
fields = ( ' name ' , ' status ' , ' usertype ' )
q = """ SELECT %s FROM users WHERE id= %% (user_id)s """ % ' , ' . join ( fields )
c . execute ( q , locals ( ) )
row = c . fetchone ( )
if not row :
return None
2019-06-01 22:55:04 +02:00
return dict ( zip ( fields , row ) )
2018-03-03 12:22:56 +00:00
def login ( * args , * * opts ) :
return context . session . login ( * args , * * opts )
def krbLogin ( * args , * * opts ) :
return context . session . krbLogin ( * args , * * opts )
def sslLogin ( * args , * * opts ) :
return context . session . sslLogin ( * args , * * opts )
def logout ( ) :
return context . session . logout ( )
def subsession ( ) :
return context . session . subsession ( )
def logoutChild ( session_id ) :
return context . session . logoutChild ( session_id )
def exclusiveSession ( * args , * * opts ) :
""" Make this session exclusive """
return context . session . makeExclusive ( * args , * * opts )
def sharedSession ( ) :
""" Drop out of exclusive mode """
return context . session . makeShared ( )
if __name__ == ' __main__ ' : # pragma: no cover
# XXX - testing defaults
import db
db . setDBopts ( database = " test " , user = " test " )
print ( " Connecting to db " )
context . cnx = db . connect ( )
print ( " starting session 1 " )
sess = Session ( None , hostip = ' 127.0.0.1 ' )
print ( " Session 1: %s " % sess )
print ( " logging in with session 1 " )
session_info = sess . login ( ' host/1 ' , ' foobar ' , { ' hostip ' : ' 127.0.0.1 ' } )
#wrap values in lists
session_info = dict ( [ [ k , [ v ] ] for k , v in six . iteritems ( session_info ) ] )
print ( " Session 1: %s " % sess )
print ( " Session 1 info: %r " % session_info )
print ( " Creating session 2 " )
s2 = Session ( session_info , ' 127.0.0.1 ' )
print ( " Session 2: %s " % s2 )