mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Enhanced user search:
- "configurable" fields to search on - tokenize search words - prioritize exact matches over partial matches - split match filter generation into a re-usable function. Other updates: - use finally block to return ldap connections - update web gui to use new get_user methods
This commit is contained in:
parent
f437ecfad1
commit
e31b526c81
@ -92,7 +92,7 @@ class Root(controllers.RootController):
|
||||
if tg_errors:
|
||||
turbogears.flash("There was a problem with the form!")
|
||||
|
||||
user = client.get_user(uid)
|
||||
user = client.get_user_by_uid(uid)
|
||||
user_dict = user.toDict()
|
||||
# store a copy of the original user for the update later
|
||||
user_data = b64encode(dumps(user_dict))
|
||||
@ -155,7 +155,7 @@ class Root(controllers.RootController):
|
||||
def usershow(self, uid):
|
||||
"""Retrieve a single user for display"""
|
||||
try:
|
||||
user = client.get_user(uid)
|
||||
user = client.get_user_by_uid(uid)
|
||||
return dict(user=user.toDict(), fields=forms.user.UserFields())
|
||||
except ipaerror.IPAError, e:
|
||||
turbogears.flash("User show failed: " + str(e))
|
||||
|
@ -90,8 +90,10 @@ class IPAServer:
|
||||
filter = "(krbPrincipalName=" + princ + ")"
|
||||
# The only anonymous search we should have
|
||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,None)
|
||||
ent = m1.getEntry(self.basedn, self.scope, filter, ['dn'])
|
||||
_LDAPPool.releaseConn(m1)
|
||||
try:
|
||||
ent = m1.getEntry(self.basedn, self.scope, filter, ['dn'])
|
||||
finally:
|
||||
_LDAPPool.releaseConn(m1)
|
||||
|
||||
return "dn:" + ent.dn
|
||||
|
||||
@ -139,8 +141,10 @@ class IPAServer:
|
||||
dn = self.get_dn_from_principal(self.princ)
|
||||
|
||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
|
||||
ent = m1.getEntry(base, self.scope, filter, sattrs)
|
||||
_LDAPPool.releaseConn(m1)
|
||||
try:
|
||||
ent = m1.getEntry(base, self.scope, filter, sattrs)
|
||||
finally:
|
||||
_LDAPPool.releaseConn(m1)
|
||||
|
||||
return self.convert_entry(ent)
|
||||
|
||||
@ -169,8 +173,10 @@ class IPAServer:
|
||||
proxydn = self.get_dn_from_principal(self.princ)
|
||||
|
||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,proxydn)
|
||||
res = m1.updateEntry(moddn, oldentry, newentry)
|
||||
_LDAPPool.releaseConn(m1)
|
||||
try:
|
||||
res = m1.updateEntry(moddn, oldentry, newentry)
|
||||
finally:
|
||||
_LDAPPool.releaseConn(m1)
|
||||
return res
|
||||
|
||||
def __safe_filter(self, criteria):
|
||||
@ -181,9 +187,34 @@ class IPAServer:
|
||||
# where the second byte in a multi-byte character
|
||||
# is (illegally) ')' and make sure python-ldap
|
||||
# bombs out.
|
||||
criteria = re.sub(r'[\(\)\\]', ldap_search_escape, criteria)
|
||||
criteria = re.sub(r'[\(\)\\\*]', ldap_search_escape, criteria)
|
||||
|
||||
return criteria
|
||||
|
||||
def __generate_match_filters(self, search_fields, criteria_words):
|
||||
"""Generates a search filter based on a list of words and a list
|
||||
of fields to search against.
|
||||
|
||||
Returns a tuple of two filters: (exact_match, partial_match)"""
|
||||
|
||||
# construct search pattern for a single word
|
||||
# (|(f1=word)(f2=word)...)
|
||||
search_pattern = "(|"
|
||||
for field in search_fields:
|
||||
search_pattern += "(" + field + "=%(match)s)"
|
||||
search_pattern += ")"
|
||||
gen_search_pattern = lambda word: search_pattern % {'match':word}
|
||||
|
||||
# construct the giant match for all words
|
||||
exact_match_filter = "(&"
|
||||
partial_match_filter = "(&"
|
||||
for word in criteria_words:
|
||||
exact_match_filter += gen_search_pattern(word)
|
||||
partial_match_filter += gen_search_pattern("*%s*" % word)
|
||||
exact_match_filter += ")"
|
||||
partial_match_filter += ")"
|
||||
|
||||
return (exact_match_filter, partial_match_filter)
|
||||
|
||||
# User support
|
||||
|
||||
@ -282,8 +313,10 @@ class IPAServer:
|
||||
dn = self.get_dn_from_principal(self.princ)
|
||||
|
||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
|
||||
res = m1.addEntry(entry)
|
||||
_LDAPPool.releaseConn(m1)
|
||||
try:
|
||||
res = m1.addEntry(entry)
|
||||
finally:
|
||||
_LDAPPool.releaseConn(m1)
|
||||
return res
|
||||
|
||||
def get_add_schema (self):
|
||||
@ -344,8 +377,10 @@ class IPAServer:
|
||||
filter = "(objectclass=posixAccount)"
|
||||
|
||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
|
||||
all_users = m1.getList(self.basedn, self.scope, filter, None)
|
||||
_LDAPPool.releaseConn(m1)
|
||||
try:
|
||||
all_users = m1.getList(self.basedn, self.scope, filter, None)
|
||||
finally:
|
||||
_LDAPPool.releaseConn(m1)
|
||||
|
||||
users = []
|
||||
for u in all_users:
|
||||
@ -364,20 +399,46 @@ class IPAServer:
|
||||
|
||||
dn = self.get_dn_from_principal(self.princ)
|
||||
|
||||
criteria = self.__safe_filter(criteria)
|
||||
# Assume the list of fields to search will come from a central
|
||||
# configuration repository. A good format for that would be
|
||||
# a comma-separated list of fields
|
||||
search_fields_conf_str = "uid,givenName,sn,telephoneNumber"
|
||||
search_fields = string.split(search_fields_conf_str, ",")
|
||||
|
||||
filter = "(|(uid=%s)(cn=%s))" % (criteria, criteria)
|
||||
criteria = self.__safe_filter(criteria)
|
||||
criteria_words = re.split(r'\s+', criteria)
|
||||
criteria_words = filter(lambda value:value!="", criteria_words)
|
||||
if len(criteria_words) == 0:
|
||||
return []
|
||||
|
||||
(exact_match_filter, partial_match_filter) = self.__generate_match_filters(
|
||||
search_fields, criteria_words)
|
||||
|
||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
|
||||
try:
|
||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
|
||||
results = m1.getList(self.basedn, self.scope, filter, sattrs)
|
||||
try:
|
||||
exact_results = m1.getList(self.basedn, self.scope,
|
||||
exact_match_filter, sattrs)
|
||||
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
|
||||
exact_results = []
|
||||
|
||||
try:
|
||||
partial_results = m1.getList(self.basedn, self.scope,
|
||||
partial_match_filter, sattrs)
|
||||
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
|
||||
partial_results = []
|
||||
finally:
|
||||
_LDAPPool.releaseConn(m1)
|
||||
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
|
||||
results = []
|
||||
|
||||
# Remove exact matches from the partial_match list
|
||||
exact_dns = set(map(lambda e: e.dn, exact_results))
|
||||
partial_results = filter(lambda e: e.dn not in exact_dns,
|
||||
partial_results)
|
||||
|
||||
users = []
|
||||
for u in results:
|
||||
for u in exact_results + partial_results:
|
||||
users.append(self.convert_entry(u))
|
||||
|
||||
|
||||
return users
|
||||
|
||||
def convert_scalar_values(self, orig_dict):
|
||||
@ -416,8 +477,10 @@ class IPAServer:
|
||||
has_key = False
|
||||
|
||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,proxydn)
|
||||
res = m1.inactivateEntry(user['dn'], has_key)
|
||||
_LDAPPool.releaseConn(m1)
|
||||
try:
|
||||
res = m1.inactivateEntry(user['dn'], has_key)
|
||||
finally:
|
||||
_LDAPPool.releaseConn(m1)
|
||||
return res
|
||||
|
||||
# Group support
|
||||
@ -484,8 +547,10 @@ class IPAServer:
|
||||
dn = self.get_dn_from_principal(self.princ)
|
||||
|
||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
|
||||
res = m1.addEntry(entry)
|
||||
_LDAPPool.releaseConn(m1)
|
||||
try:
|
||||
res = m1.addEntry(entry)
|
||||
finally:
|
||||
_LDAPPool.releaseConn(m1)
|
||||
|
||||
def find_groups (self, criteria, sattrs=None, opts=None):
|
||||
"""Return a list containing a User object for each
|
||||
@ -501,12 +566,13 @@ class IPAServer:
|
||||
criteria = self.__safe_filter(criteria)
|
||||
|
||||
filter = "(&(cn=%s)(objectClass=posixGroup))" % criteria
|
||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
|
||||
try:
|
||||
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
|
||||
results = m1.getList(self.basedn, self.scope, filter, sattrs)
|
||||
_LDAPPool.releaseConn(m1)
|
||||
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
|
||||
results = []
|
||||
finally:
|
||||
_LDAPPool.releaseConn(m1)
|
||||
|
||||
groups = []
|
||||
for u in results:
|
||||
@ -645,5 +711,8 @@ def ldap_search_escape(match):
|
||||
return "\\29"
|
||||
elif value == "\\":
|
||||
return "\\5c"
|
||||
elif value == "*":
|
||||
# drop '*' from input. search performs its own wildcarding
|
||||
return ""
|
||||
else:
|
||||
return value
|
||||
|
Loading…
Reference in New Issue
Block a user