mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Enable LDAP SASL authentication using a forwarded kerberos ticket
Handle both SASL auth and proxied authentication Refactor LDAP connection code to be simpler Other small bug fixes
This commit is contained in:
parent
82943c31de
commit
9b30f46744
@ -50,7 +50,9 @@ def main():
|
|||||||
client = ipaclient.IPAClient()
|
client = ipaclient.IPAClient()
|
||||||
users = client.find_users(args[1], sattrs=['dn','uid','cn','homeDirectory'])
|
users = client.find_users(args[1], sattrs=['dn','uid','cn','homeDirectory'])
|
||||||
|
|
||||||
if len(users) == 0:
|
counter = users[0]
|
||||||
|
users = users[1:]
|
||||||
|
if counter == 0:
|
||||||
print "No entries found for", args[1]
|
print "No entries found for", args[1]
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
@ -59,6 +59,9 @@ def main():
|
|||||||
except ipa.ipaerror.IPAError, e:
|
except ipa.ipaerror.IPAError, e:
|
||||||
print "%s" % e.message
|
print "%s" % e.message
|
||||||
return 1
|
return 1
|
||||||
|
except kerberos.GSSError, e:
|
||||||
|
print "Could not initialize GSSAPI: %s/%s" % (e[0][0][0], e[0][1][0])
|
||||||
|
return 1
|
||||||
|
|
||||||
if options.gecos:
|
if options.gecos:
|
||||||
user.setValue('gecos', options.gecos)
|
user.setValue('gecos', options.gecos)
|
||||||
@ -79,6 +82,9 @@ def main():
|
|||||||
except xmlrpclib.ProtocolError, e:
|
except xmlrpclib.ProtocolError, e:
|
||||||
print "Unable to connect to IPA server: %s" % (e.errmsg)
|
print "Unable to connect to IPA server: %s" % (e.errmsg)
|
||||||
return 1
|
return 1
|
||||||
|
except ipa.ipaerror.IPAError, e:
|
||||||
|
print "%s" % (e.message)
|
||||||
|
return 1
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
@ -35,13 +35,14 @@ import cStringIO
|
|||||||
import time
|
import time
|
||||||
import operator
|
import operator
|
||||||
import struct
|
import struct
|
||||||
|
import ldap.sasl
|
||||||
from ldap.controls import LDAPControl,DecodeControlTuples,EncodeControlTuples
|
from ldap.controls import LDAPControl,DecodeControlTuples,EncodeControlTuples
|
||||||
from ldap.modlist import modifyModlist
|
|
||||||
|
|
||||||
from ldap.ldapobject import SimpleLDAPObject
|
from ldap.ldapobject import SimpleLDAPObject
|
||||||
|
|
||||||
from ipa import ipaerror, ipautil
|
from ipa import ipaerror, ipautil
|
||||||
|
|
||||||
|
# Global variable to define SASL auth
|
||||||
|
sasl_auth = ldap.sasl.sasl({},'GSSAPI')
|
||||||
|
|
||||||
class Entry:
|
class Entry:
|
||||||
"""This class represents an LDAP Entry object. An LDAP entry consists of a DN
|
"""This class represents an LDAP Entry object. An LDAP entry consists of a DN
|
||||||
and a list of attributes. Each attribute consists of a name and a list of
|
and a list of attributes. Each attribute consists of a name and a list of
|
||||||
@ -196,22 +197,34 @@ class IPAdmin(SimpleLDAPObject):
|
|||||||
raise ipaerror.gen_exception(ipaerror.LDAP_DATABASE_ERROR, None, e)
|
raise ipaerror.gen_exception(ipaerror.LDAP_DATABASE_ERROR, None, e)
|
||||||
|
|
||||||
def __localinit__(self):
|
def __localinit__(self):
|
||||||
|
"""If a CA certificate is provided then it is assumed that we are
|
||||||
|
doing SSL client authentication with proxy auth.
|
||||||
|
|
||||||
|
If a CA certificate is not present then it is assumed that we are
|
||||||
|
using a forwarded kerberos ticket for SASL auth. SASL provides
|
||||||
|
its own encryption.
|
||||||
|
"""
|
||||||
|
if self.cacert is not None:
|
||||||
SimpleLDAPObject.__init__(self,'ldaps://%s:%d' % (self.host,self.port))
|
SimpleLDAPObject.__init__(self,'ldaps://%s:%d' % (self.host,self.port))
|
||||||
|
else:
|
||||||
|
SimpleLDAPObject.__init__(self,'ldap://%s:%d' % (self.host,self.port))
|
||||||
|
|
||||||
def __init__(self,host,port,cacert,bindcert,bindkey,proxydn=None):
|
def __init__(self,host,port,cacert,bindcert,bindkey,proxydn=None):
|
||||||
"""We just set our instance variables and wrap the methods - the real work is
|
"""We just set our instance variables and wrap the methods - the real
|
||||||
done in __localinit__ and __initPart2 - these are separated out this way so
|
work is done in __localinit__ and __initPart2 - these are separated
|
||||||
that we can call them from places other than instance creation e.g. when
|
out this way so that we can call them from places other than
|
||||||
using the start command, we just need to reconnect, not create a new instance"""
|
instance creation e.g. when we just need to reconnect, not create a
|
||||||
|
new instance"""
|
||||||
# ldap.set_option(ldap.OPT_DEBUG_LEVEL,255)
|
# ldap.set_option(ldap.OPT_DEBUG_LEVEL,255)
|
||||||
|
if cacert is not None:
|
||||||
ldap.set_option(ldap.OPT_X_TLS_CACERTFILE,cacert)
|
ldap.set_option(ldap.OPT_X_TLS_CACERTFILE,cacert)
|
||||||
ldap.set_option(ldap.OPT_X_TLS_CERTFILE,bindcert)
|
ldap.set_option(ldap.OPT_X_TLS_CERTFILE,bindcert)
|
||||||
ldap.set_option(ldap.OPT_X_TLS_KEYFILE,bindkey)
|
ldap.set_option(ldap.OPT_X_TLS_KEYFILE,bindkey)
|
||||||
|
|
||||||
self.__wrapmethods()
|
self.__wrapmethods()
|
||||||
self.port = port or 389
|
self.port = port or 389
|
||||||
self.sslport = 0
|
|
||||||
self.host = host
|
self.host = host
|
||||||
|
self.cacert = cacert
|
||||||
self.bindcert = bindcert
|
self.bindcert = bindcert
|
||||||
self.bindkey = bindkey
|
self.bindkey = bindkey
|
||||||
self.proxydn = proxydn
|
self.proxydn = proxydn
|
||||||
@ -251,6 +264,12 @@ class IPAdmin(SimpleLDAPObject):
|
|||||||
def set_proxydn(self, proxydn):
|
def set_proxydn(self, proxydn):
|
||||||
self.proxydn = proxydn
|
self.proxydn = proxydn
|
||||||
|
|
||||||
|
def set_keytab(self, keytab):
|
||||||
|
if keytab is not None:
|
||||||
|
os.environ["KRB5CCNAME"] = keytab
|
||||||
|
self.sasl_interactive_bind_s("", sasl_auth)
|
||||||
|
self.proxydn = None
|
||||||
|
|
||||||
def getEntry(self,*args):
|
def getEntry(self,*args):
|
||||||
"""This wraps the search function. It is common to just get one entry"""
|
"""This wraps the search function. It is common to just get one entry"""
|
||||||
|
|
||||||
@ -346,6 +365,7 @@ class IPAdmin(SimpleLDAPObject):
|
|||||||
sctrl = self.__get_server_controls__()
|
sctrl = self.__get_server_controls__()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if sctrl is not None:
|
||||||
self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
|
self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
|
||||||
self.add_s(*args)
|
self.add_s(*args)
|
||||||
except ldap.ALREADY_EXISTS:
|
except ldap.ALREADY_EXISTS:
|
||||||
@ -366,6 +386,7 @@ class IPAdmin(SimpleLDAPObject):
|
|||||||
raise ipaerror.gen_exception(ipaerror.LDAP_EMPTY_MODLIST)
|
raise ipaerror.gen_exception(ipaerror.LDAP_EMPTY_MODLIST)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if sctrl is not None:
|
||||||
self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
|
self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
|
||||||
self.modify_s(dn, modlist)
|
self.modify_s(dn, modlist)
|
||||||
# this is raised when a 'delete' attribute isn't found.
|
# this is raised when a 'delete' attribute isn't found.
|
||||||
@ -428,6 +449,7 @@ class IPAdmin(SimpleLDAPObject):
|
|||||||
modlist.append((operation, "nsAccountlock", "true"))
|
modlist.append((operation, "nsAccountlock", "true"))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if sctrl is not None:
|
||||||
self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
|
self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
|
||||||
self.modify_s(dn, modlist)
|
self.modify_s(dn, modlist)
|
||||||
except ldap.LDAPError, e:
|
except ldap.LDAPError, e:
|
||||||
@ -440,6 +462,7 @@ class IPAdmin(SimpleLDAPObject):
|
|||||||
sctrl = self.__get_server_controls__()
|
sctrl = self.__get_server_controls__()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if sctrl is not None:
|
||||||
self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
|
self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
|
||||||
self.delete_s(*args)
|
self.delete_s(*args)
|
||||||
except ldap.LDAPError, e:
|
except ldap.LDAPError, e:
|
||||||
|
@ -47,19 +47,30 @@ DefaultGroupContainer = "cn=groups,cn=accounts"
|
|||||||
# this is not anticipated.
|
# this is not anticipated.
|
||||||
class IPAConnPool:
|
class IPAConnPool:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.numentries = 0
|
|
||||||
self.freelist = []
|
self.freelist = []
|
||||||
|
|
||||||
def getConn(self, host, port, bindca, bindcert, bindkey, proxydn=None):
|
def getConn(self, host, port, bindca, bindcert, bindkey, proxydn=None, keytab=None):
|
||||||
self.numentries = self.numentries + 1
|
conn = None
|
||||||
if len(self.freelist) > 0:
|
if len(self.freelist) > 0:
|
||||||
conn = self.freelist.pop()
|
for i in range(len(self.freelist)):
|
||||||
else:
|
c = self.freelist[i]
|
||||||
|
if ((c.host == host) and (c.port == port)):
|
||||||
|
conn = self.freelist.pop(i)
|
||||||
|
break
|
||||||
|
if conn is None:
|
||||||
conn = ipaserver.ipaldap.IPAdmin(host,port,bindca,bindcert,bindkey)
|
conn = ipaserver.ipaldap.IPAdmin(host,port,bindca,bindcert,bindkey)
|
||||||
|
if proxydn is not None:
|
||||||
conn.set_proxydn(proxydn)
|
conn.set_proxydn(proxydn)
|
||||||
|
else:
|
||||||
|
conn.set_keytab(keytab)
|
||||||
return conn
|
return conn
|
||||||
|
|
||||||
def releaseConn(self, conn):
|
def releaseConn(self, conn):
|
||||||
|
# We can't re-use SASL connections. If proxydn is None it means
|
||||||
|
# we have a keytab set. See ipaldap.set_keytab
|
||||||
|
if conn.proxydn is None:
|
||||||
|
conn.unbind_s()
|
||||||
|
else:
|
||||||
self.freelist.append(conn)
|
self.freelist.append(conn)
|
||||||
|
|
||||||
class IPAServer:
|
class IPAServer:
|
||||||
@ -68,7 +79,8 @@ class IPAServer:
|
|||||||
global _LDAPPool
|
global _LDAPPool
|
||||||
# FIXME, this needs to be auto-discovered
|
# FIXME, this needs to be auto-discovered
|
||||||
self.host = 'localhost'
|
self.host = 'localhost'
|
||||||
self.port = 636
|
self.port = 389
|
||||||
|
self.sslport = 636
|
||||||
self.bindcert = "/usr/share/ipa/cert.pem"
|
self.bindcert = "/usr/share/ipa/cert.pem"
|
||||||
self.bindkey = "/usr/share/ipa/key.pem"
|
self.bindkey = "/usr/share/ipa/key.pem"
|
||||||
self.bindca = "/usr/share/ipa/cacert.asc"
|
self.bindca = "/usr/share/ipa/cacert.asc"
|
||||||
@ -79,24 +91,84 @@ class IPAServer:
|
|||||||
self.basedn = ipa.ipautil.realm_to_suffix(ipa.config.config.get_realm())
|
self.basedn = ipa.ipautil.realm_to_suffix(ipa.config.config.get_realm())
|
||||||
self.scope = ldap.SCOPE_SUBTREE
|
self.scope = ldap.SCOPE_SUBTREE
|
||||||
self.princ = None
|
self.princ = None
|
||||||
|
self.keytab = None
|
||||||
|
|
||||||
def set_principal(self, princ):
|
def set_principal(self, princ):
|
||||||
self.princ = princ
|
self.princ = princ
|
||||||
|
|
||||||
|
def set_keytab(self, keytab):
|
||||||
|
self.keytab = keytab
|
||||||
|
|
||||||
def get_dn_from_principal(self, princ):
|
def get_dn_from_principal(self, princ):
|
||||||
"""Given a kerberls principal get the LDAP uid"""
|
"""Given a kerberos principal get the LDAP uid"""
|
||||||
global _LDAPPool
|
global _LDAPPool
|
||||||
|
|
||||||
filter = "(krbPrincipalName=" + princ + ")"
|
filter = "(krbPrincipalName=" + princ + ")"
|
||||||
# The only anonymous search we should have
|
# The only anonymous search we should have
|
||||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,None)
|
conn = _LDAPPool.getConn(self.host,self.sslport,self.bindca,self.bindcert,self.bindkey,None,None)
|
||||||
try:
|
try:
|
||||||
ent = m1.getEntry(self.basedn, self.scope, filter, ['dn'])
|
ent = conn.getEntry(self.basedn, self.scope, filter, ['dn'])
|
||||||
finally:
|
finally:
|
||||||
_LDAPPool.releaseConn(m1)
|
_LDAPPool.releaseConn(conn)
|
||||||
|
|
||||||
return "dn:" + ent.dn
|
return "dn:" + ent.dn
|
||||||
|
|
||||||
|
def __setup_connection(self, opts):
|
||||||
|
"""Set up common things done in the connection.
|
||||||
|
If there is a keytab then return None as the proxy dn and the keytab
|
||||||
|
otherwise return the proxy dn and None as the keytab.
|
||||||
|
|
||||||
|
We only want one or the other used at one time and we prefer
|
||||||
|
the keytab. So if there is a keytab, return that and None for
|
||||||
|
proxy dn to make calling getConn() easier.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if opts:
|
||||||
|
if opts.get('keytab'):
|
||||||
|
self.set_keytab(opts['keytab'])
|
||||||
|
self.set_principal(None)
|
||||||
|
else:
|
||||||
|
self.set_keytab(None)
|
||||||
|
self.set_principal(opts['remoteuser'])
|
||||||
|
else:
|
||||||
|
self.set_keytab(None)
|
||||||
|
# The caller should have already set the principal
|
||||||
|
|
||||||
|
if self.princ is not None:
|
||||||
|
return self.get_dn_from_principal(self.princ), None
|
||||||
|
else:
|
||||||
|
return None, self.keytab
|
||||||
|
|
||||||
|
def getConnection(self, opts):
|
||||||
|
"""Wrapper around IPAConnPool.getConn() so we don't have to pass
|
||||||
|
around self.* every time a connection is needed.
|
||||||
|
|
||||||
|
For SASL connections (where we have a keytab) we can't set
|
||||||
|
the SSL variables for certificates. It confuses the ldap
|
||||||
|
module.
|
||||||
|
"""
|
||||||
|
global _LDAPPool
|
||||||
|
|
||||||
|
(proxy_dn, keytab) = self.__setup_connection(opts)
|
||||||
|
|
||||||
|
if keytab is not None:
|
||||||
|
bindca = None
|
||||||
|
bindcert = None
|
||||||
|
bindkey = None
|
||||||
|
port = self.port
|
||||||
|
else:
|
||||||
|
bindca = self.bindca
|
||||||
|
bindcert = self.bindcert
|
||||||
|
bindkey = self.bindkey
|
||||||
|
port = self.sslport
|
||||||
|
|
||||||
|
return _LDAPPool.getConn(self.host,port,bindca,bindcert,bindkey,proxy_dn,keytab)
|
||||||
|
|
||||||
|
def releaseConnection(self, conn):
|
||||||
|
global _LDAPPool
|
||||||
|
|
||||||
|
_LDAPPool.releaseConn(conn)
|
||||||
|
|
||||||
def convert_entry(self, ent):
|
def convert_entry(self, ent):
|
||||||
entry = dict(ent.data)
|
entry = dict(ent.data)
|
||||||
entry['dn'] = ent.dn
|
entry['dn'] = ent.dn
|
||||||
@ -110,24 +182,17 @@ class IPAServer:
|
|||||||
entry[key] = value[0]
|
entry[key] = value[0]
|
||||||
return entry
|
return entry
|
||||||
|
|
||||||
|
|
||||||
def __get_entry (self, base, filter, sattrs=None, opts=None):
|
def __get_entry (self, base, filter, sattrs=None, opts=None):
|
||||||
"""Get a specific entry. Return as a dict of values.
|
"""Get a specific entry. Return as a dict of values.
|
||||||
Multi-valued fields are represented as lists.
|
Multi-valued fields are represented as lists.
|
||||||
"""
|
"""
|
||||||
global _LDAPPool
|
|
||||||
ent=""
|
ent=""
|
||||||
|
|
||||||
if opts:
|
conn = self.getConnection(opts)
|
||||||
self.set_principal(opts['remoteuser'])
|
|
||||||
|
|
||||||
dn = self.get_dn_from_principal(self.princ)
|
|
||||||
|
|
||||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
|
|
||||||
try:
|
try:
|
||||||
ent = m1.getEntry(base, self.scope, filter, sattrs)
|
ent = conn.getEntry(base, self.scope, filter, sattrs)
|
||||||
finally:
|
finally:
|
||||||
_LDAPPool.releaseConn(m1)
|
self.releaseConnection(conn)
|
||||||
|
|
||||||
return self.convert_entry(ent)
|
return self.convert_entry(ent)
|
||||||
|
|
||||||
@ -137,8 +202,6 @@ class IPAServer:
|
|||||||
oldentry is a dict
|
oldentry is a dict
|
||||||
newentry is a dict
|
newentry is a dict
|
||||||
"""
|
"""
|
||||||
global _LDAPPool
|
|
||||||
|
|
||||||
oldentry = self.convert_scalar_values(oldentry)
|
oldentry = self.convert_scalar_values(oldentry)
|
||||||
newentry = self.convert_scalar_values(newentry)
|
newentry = self.convert_scalar_values(newentry)
|
||||||
|
|
||||||
@ -150,16 +213,11 @@ class IPAServer:
|
|||||||
except KeyError, e:
|
except KeyError, e:
|
||||||
raise ipaerror.gen_exception(ipaerror.LDAP_MISSING_DN)
|
raise ipaerror.gen_exception(ipaerror.LDAP_MISSING_DN)
|
||||||
|
|
||||||
if opts:
|
conn = self.getConnection(opts)
|
||||||
self.set_principal(opts['remoteuser'])
|
|
||||||
|
|
||||||
proxydn = self.get_dn_from_principal(self.princ)
|
|
||||||
|
|
||||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,proxydn)
|
|
||||||
try:
|
try:
|
||||||
res = m1.updateEntry(moddn, oldentry, newentry)
|
res = conn.updateEntry(moddn, oldentry, newentry)
|
||||||
finally:
|
finally:
|
||||||
_LDAPPool.releaseConn(m1)
|
self.releaseConnection(conn)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def __safe_filter(self, criteria):
|
def __safe_filter(self, criteria):
|
||||||
@ -234,8 +292,6 @@ class IPAServer:
|
|||||||
attribute name and the value is either a string or in the case
|
attribute name and the value is either a string or in the case
|
||||||
of a multi-valued field a list of values. user_container sets
|
of a multi-valued field a list of values. user_container sets
|
||||||
where in the tree the user is placed."""
|
where in the tree the user is placed."""
|
||||||
global _LDAPPool
|
|
||||||
|
|
||||||
if user_container is None:
|
if user_container is None:
|
||||||
user_container = DefaultUserContainer
|
user_container = DefaultUserContainer
|
||||||
|
|
||||||
@ -288,16 +344,11 @@ class IPAServer:
|
|||||||
for u in user:
|
for u in user:
|
||||||
entry.setValues(u, user[u])
|
entry.setValues(u, user[u])
|
||||||
|
|
||||||
if opts:
|
conn = self.getConnection(opts)
|
||||||
self.set_principal(opts['remoteuser'])
|
|
||||||
|
|
||||||
dn = self.get_dn_from_principal(self.princ)
|
|
||||||
|
|
||||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
|
|
||||||
try:
|
try:
|
||||||
res = m1.addEntry(entry)
|
res = conn.addEntry(entry)
|
||||||
finally:
|
finally:
|
||||||
_LDAPPool.releaseConn(m1)
|
self.releaseConnection(conn)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def get_add_schema (self):
|
def get_add_schema (self):
|
||||||
@ -348,20 +399,13 @@ class IPAServer:
|
|||||||
"""Return a list containing a User object for each
|
"""Return a list containing a User object for each
|
||||||
existing user.
|
existing user.
|
||||||
"""
|
"""
|
||||||
global _LDAPPool
|
|
||||||
|
|
||||||
if opts:
|
|
||||||
self.set_principal(opts['remoteuser'])
|
|
||||||
|
|
||||||
dn = self.get_dn_from_principal(self.princ)
|
|
||||||
|
|
||||||
filter = "(objectclass=posixAccount)"
|
filter = "(objectclass=posixAccount)"
|
||||||
|
|
||||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
|
conn = self.getConnection(opts)
|
||||||
try:
|
try:
|
||||||
all_users = m1.getList(self.basedn, self.scope, filter, None)
|
all_users = conn.getList(self.basedn, self.scope, filter, None)
|
||||||
finally:
|
finally:
|
||||||
_LDAPPool.releaseConn(m1)
|
self.releaseConnection(conn)
|
||||||
|
|
||||||
users = []
|
users = []
|
||||||
for u in all_users:
|
for u in all_users:
|
||||||
@ -372,13 +416,6 @@ class IPAServer:
|
|||||||
def find_users (self, criteria, sattrs=None, opts=None):
|
def find_users (self, criteria, sattrs=None, opts=None):
|
||||||
"""Returns a list: counter followed by the results.
|
"""Returns a list: counter followed by the results.
|
||||||
If the results are truncated, counter will be set to -1."""
|
If the results are truncated, counter will be set to -1."""
|
||||||
global _LDAPPool
|
|
||||||
|
|
||||||
if opts:
|
|
||||||
self.set_principal(opts['remoteuser'])
|
|
||||||
|
|
||||||
dn = self.get_dn_from_principal(self.princ)
|
|
||||||
|
|
||||||
# Assume the list of fields to search will come from a central
|
# Assume the list of fields to search will come from a central
|
||||||
# configuration repository. A good format for that would be
|
# configuration repository. A good format for that would be
|
||||||
# a comma-separated list of fields
|
# a comma-separated list of fields
|
||||||
@ -394,21 +431,21 @@ class IPAServer:
|
|||||||
(exact_match_filter, partial_match_filter) = self.__generate_match_filters(
|
(exact_match_filter, partial_match_filter) = self.__generate_match_filters(
|
||||||
search_fields, criteria_words)
|
search_fields, criteria_words)
|
||||||
|
|
||||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
|
conn = self.getConnection(opts)
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
exact_results = m1.getListAsync(self.basedn, self.scope,
|
exact_results = conn.getListAsync(self.basedn, self.scope,
|
||||||
exact_match_filter, sattrs)
|
exact_match_filter, sattrs)
|
||||||
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
|
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
|
||||||
exact_results = [0]
|
exact_results = [0]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
partial_results = m1.getListAsync(self.basedn, self.scope,
|
partial_results = conn.getListAsync(self.basedn, self.scope,
|
||||||
partial_match_filter, sattrs)
|
partial_match_filter, sattrs)
|
||||||
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
|
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
|
||||||
partial_results = [0]
|
partial_results = [0]
|
||||||
finally:
|
finally:
|
||||||
_LDAPPool.releaseConn(m1)
|
self.releaseConnection(conn)
|
||||||
|
|
||||||
exact_counter = exact_results[0]
|
exact_counter = exact_results[0]
|
||||||
partial_counter = partial_results[0]
|
partial_counter = partial_results[0]
|
||||||
@ -450,13 +487,6 @@ class IPAServer:
|
|||||||
def mark_user_deleted (self, uid, opts=None):
|
def mark_user_deleted (self, uid, opts=None):
|
||||||
"""Mark a user as inactive in LDAP. We aren't actually deleting
|
"""Mark a user as inactive in LDAP. We aren't actually deleting
|
||||||
users here, just making it so they can't log in, etc."""
|
users here, just making it so they can't log in, etc."""
|
||||||
global _LDAPPool
|
|
||||||
|
|
||||||
if opts:
|
|
||||||
self.set_principal(opts['remoteuser'])
|
|
||||||
|
|
||||||
proxydn = self.get_dn_from_principal(self.princ)
|
|
||||||
|
|
||||||
user = self.get_user_by_uid(uid, ['dn', 'uid', 'nsAccountlock'], opts)
|
user = self.get_user_by_uid(uid, ['dn', 'uid', 'nsAccountlock'], opts)
|
||||||
|
|
||||||
# Are we doing an add or replace operation?
|
# Are we doing an add or replace operation?
|
||||||
@ -467,11 +497,11 @@ class IPAServer:
|
|||||||
else:
|
else:
|
||||||
has_key = False
|
has_key = False
|
||||||
|
|
||||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,proxydn)
|
conn = self.getConnection(opts)
|
||||||
try:
|
try:
|
||||||
res = m1.inactivateEntry(user['dn'], has_key)
|
res = conn.inactivateEntry(user['dn'], has_key)
|
||||||
finally:
|
finally:
|
||||||
_LDAPPool.releaseConn(m1)
|
self.releaseConnection(conn)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def delete_user (self, uid, opts=None):
|
def delete_user (self, uid, opts=None):
|
||||||
@ -483,18 +513,15 @@ class IPAServer:
|
|||||||
The memberOf plugin handles removing the user from any other
|
The memberOf plugin handles removing the user from any other
|
||||||
groups.
|
groups.
|
||||||
"""
|
"""
|
||||||
if opts:
|
|
||||||
self.set_principal(opts['remoteuser'])
|
|
||||||
|
|
||||||
dn = self.get_dn_from_principal(self.princ)
|
|
||||||
|
|
||||||
user_dn = self.get_user_by_uid(uid, ['dn', 'uid', 'objectclass'], opts)
|
user_dn = self.get_user_by_uid(uid, ['dn', 'uid', 'objectclass'], opts)
|
||||||
if user_dn is None:
|
if user_dn is None:
|
||||||
raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
|
raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
|
||||||
|
|
||||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
|
conn = self.getConnection(opts)
|
||||||
res = m1.deleteEntry(user_dn['dn'])
|
try:
|
||||||
_LDAPPool.releaseConn(m1)
|
res = conn.deleteEntry(user_dn['dn'])
|
||||||
|
finally:
|
||||||
|
self.releaseConnection(conn)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
# Group support
|
# Group support
|
||||||
@ -532,8 +559,6 @@ class IPAServer:
|
|||||||
attribute name and the value is either a string or in the case
|
attribute name and the value is either a string or in the case
|
||||||
of a multi-valued field a list of values. group_container sets
|
of a multi-valued field a list of values. group_container sets
|
||||||
where in the tree the group is placed."""
|
where in the tree the group is placed."""
|
||||||
global _LDAPPool
|
|
||||||
|
|
||||||
if group_container is None:
|
if group_container is None:
|
||||||
group_container = DefaultGroupContainer
|
group_container = DefaultGroupContainer
|
||||||
|
|
||||||
@ -554,38 +579,26 @@ class IPAServer:
|
|||||||
for g in group:
|
for g in group:
|
||||||
entry.setValues(g, group[g])
|
entry.setValues(g, group[g])
|
||||||
|
|
||||||
if opts:
|
conn = self.getConnection(opts)
|
||||||
self.set_principal(opts['remoteuser'])
|
|
||||||
|
|
||||||
dn = self.get_dn_from_principal(self.princ)
|
|
||||||
|
|
||||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
|
|
||||||
try:
|
try:
|
||||||
res = m1.addEntry(entry)
|
res = conn.addEntry(entry)
|
||||||
finally:
|
finally:
|
||||||
_LDAPPool.releaseConn(m1)
|
self.releaseConnection(conn)
|
||||||
|
|
||||||
def find_groups (self, criteria, sattrs=None, opts=None):
|
def find_groups (self, criteria, sattrs=None, opts=None):
|
||||||
"""Return a list containing a User object for each
|
"""Return a list containing a User object for each
|
||||||
existing group that matches the criteria.
|
existing group that matches the criteria.
|
||||||
"""
|
"""
|
||||||
global _LDAPPool
|
|
||||||
|
|
||||||
if opts:
|
|
||||||
self.set_principal(opts['remoteuser'])
|
|
||||||
|
|
||||||
dn = self.get_dn_from_principal(self.princ)
|
|
||||||
|
|
||||||
criteria = self.__safe_filter(criteria)
|
criteria = self.__safe_filter(criteria)
|
||||||
|
|
||||||
filter = "(&(cn=%s)(objectClass=posixGroup))" % criteria
|
filter = "(&(cn=%s)(objectClass=posixGroup))" % criteria
|
||||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
|
conn = self.getConnection(opts)
|
||||||
try:
|
try:
|
||||||
results = m1.getList(self.basedn, self.scope, filter, sattrs)
|
results = conn.getList(self.basedn, self.scope, filter, sattrs)
|
||||||
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
|
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
|
||||||
results = []
|
results = []
|
||||||
finally:
|
finally:
|
||||||
_LDAPPool.releaseConn(m1)
|
self.releaseConnection(conn)
|
||||||
|
|
||||||
groups = []
|
groups = []
|
||||||
for u in results:
|
for u in results:
|
||||||
@ -599,9 +612,6 @@ class IPAServer:
|
|||||||
group is the cn of the group to be added to
|
group is the cn of the group to be added to
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if opts:
|
|
||||||
self.set_principal(opts['remoteuser'])
|
|
||||||
|
|
||||||
old_group = self.get_group_by_cn(group, None, opts)
|
old_group = self.get_group_by_cn(group, None, opts)
|
||||||
if old_group is None:
|
if old_group is None:
|
||||||
raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
|
raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
|
||||||
@ -652,9 +662,6 @@ class IPAServer:
|
|||||||
group is the cn of the group to be removed from
|
group is the cn of the group to be removed from
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if opts:
|
|
||||||
self.set_principal(opts['remoteuser'])
|
|
||||||
|
|
||||||
old_group = self.get_group_by_cn(group, None, opts)
|
old_group = self.get_group_by_cn(group, None, opts)
|
||||||
if old_group is None:
|
if old_group is None:
|
||||||
raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
|
raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
|
||||||
@ -718,19 +725,16 @@ class IPAServer:
|
|||||||
The memberOf plugin handles removing the group from any other
|
The memberOf plugin handles removing the group from any other
|
||||||
groups.
|
groups.
|
||||||
"""
|
"""
|
||||||
if opts:
|
|
||||||
self.set_principal(opts['remoteuser'])
|
|
||||||
|
|
||||||
dn = self.get_dn_from_principal(self.princ)
|
|
||||||
|
|
||||||
group = self.get_group_by_cn(group_cn, ['dn', 'cn'], opts)
|
group = self.get_group_by_cn(group_cn, ['dn', 'cn'], opts)
|
||||||
|
|
||||||
if len(group) != 1:
|
if len(group) != 1:
|
||||||
raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
|
raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
|
||||||
|
|
||||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
|
conn = self.getConnection(opts)
|
||||||
res = m1.deleteEntry(group[0]['dn'])
|
try:
|
||||||
_LDAPPool.releaseConn(m1)
|
res = conn.deleteEntry(group[0]['dn'])
|
||||||
|
finally:
|
||||||
|
self.releaseConnection(conn)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def add_group_to_group(self, group, tgroup, opts=None):
|
def add_group_to_group(self, group, tgroup, opts=None):
|
||||||
@ -739,9 +743,6 @@ class IPAServer:
|
|||||||
tgroup is the cn of the group to be added to
|
tgroup is the cn of the group to be added to
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if opts:
|
|
||||||
self.set_principal(opts['remoteuser'])
|
|
||||||
|
|
||||||
old_group = self.get_group_by_cn(tgroup, None, opts)
|
old_group = self.get_group_by_cn(tgroup, None, opts)
|
||||||
if old_group is None:
|
if old_group is None:
|
||||||
raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
|
raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
|
||||||
|
@ -126,13 +126,19 @@ class ModXMLRPCRequestHandler(object):
|
|||||||
def register_instance(self,instance):
|
def register_instance(self,instance):
|
||||||
self.register_module(instance)
|
self.register_module(instance)
|
||||||
|
|
||||||
def _marshaled_dispatch(self, data, remoteuser):
|
def _marshaled_dispatch(self, data, req):
|
||||||
"""Dispatches an XML-RPC method from marshalled (XML) data."""
|
"""Dispatches an XML-RPC method from marshalled (XML) data."""
|
||||||
|
|
||||||
params, method = loads(data)
|
params, method = loads(data)
|
||||||
|
|
||||||
|
# Populate the Apache environment variables
|
||||||
|
req.add_common_vars()
|
||||||
|
|
||||||
opts={}
|
opts={}
|
||||||
opts['remoteuser'] = remoteuser
|
opts['remoteuser'] = req.user
|
||||||
|
|
||||||
|
if req.subprocess_env.get("KRB5CCNAME") is not None:
|
||||||
|
opts['keytab'] = req.subprocess_env.get("KRB5CCNAME")
|
||||||
|
|
||||||
# Tack onto the end of the passed-in arguments any options we also
|
# Tack onto the end of the passed-in arguments any options we also
|
||||||
# need
|
# need
|
||||||
@ -263,7 +269,7 @@ class ModXMLRPCRequestHandler(object):
|
|||||||
req.allow_methods(['POST'],1)
|
req.allow_methods(['POST'],1)
|
||||||
raise apache.SERVER_RETURN, apache.HTTP_METHOD_NOT_ALLOWED
|
raise apache.SERVER_RETURN, apache.HTTP_METHOD_NOT_ALLOWED
|
||||||
|
|
||||||
response = self._marshaled_dispatch(req.read(), req.user)
|
response = self._marshaled_dispatch(req.read(), req)
|
||||||
|
|
||||||
req.content_type = "text/xml"
|
req.content_type = "text/xml"
|
||||||
req.set_content_length(len(response))
|
req.set_content_length(len(response))
|
||||||
|
Loading…
Reference in New Issue
Block a user