summaryrefslogtreecommitdiffstats
path: root/ipaserver/plugins
diff options
context:
space:
mode:
authorPetr Viktorin <pviktori@redhat.com>2013-01-18 06:44:53 -0500
committerMartin Kosek <mkosek@redhat.com>2013-03-01 16:59:43 +0100
commit0c26913309fc97b59f2312b4e04f063fec6550b1 (patch)
tree35d7fa61429374e0b88c770d648dfcafe904ec9c /ipaserver/plugins
parentddee3aa900fb0e34cadb1d80842f254ffbe4d575 (diff)
downloadfreeipa-0c26913309fc97b59f2312b4e04f063fec6550b1.tar.gz
freeipa-0c26913309fc97b59f2312b4e04f063fec6550b1.tar.xz
freeipa-0c26913309fc97b59f2312b4e04f063fec6550b1.zip
Move entry finding methods to LDAPConnection
The get_ipa_config method relies on IPA being installed. Leave the implementation in ldap2, and add stub get_ipa_config that simply returns an empty dictionary to LDAPConnection. The get_members method contains an optimization that also relies on the api object. The optimization is disabled in base LDAPConfig. Part of the work for: https://fedorahosted.org/freeipa/ticket/2660
Diffstat (limited to 'ipaserver/plugins')
-rw-r--r--ipaserver/plugins/ldap2.py299
1 files changed, 7 insertions, 292 deletions
diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py
index a75e6bbc5..d7cd0a4ec 100644
--- a/ipaserver/plugins/ldap2.py
+++ b/ipaserver/plugins/ldap2.py
@@ -35,7 +35,6 @@ import pwd
import krbV
import ldap as _ldap
-import ldap.filter as _ldap_filter
from ipapython.dn import DN, RDN
from ipaserver.ipaldap import (
@@ -60,11 +59,6 @@ from ipalib import api, errors
from ipalib.crud import CrudBackend
from ipalib.request import context
-# Group Member types
-MEMBERS_ALL = 0
-MEMBERS_DIRECT = 1
-MEMBERS_INDIRECT = 2
-
class ldap2(LDAPConnection, CrudBackend):
"""
@@ -97,6 +91,9 @@ class ldap2(LDAPConnection, CrudBackend):
# do not set it
pass
+ def get_api(self):
+ return api
+
def __del__(self):
if self.isconnected():
self.disconnect()
@@ -225,146 +222,6 @@ class ldap2(LDAPConnection, CrudBackend):
except _ldap.LDAPError, e:
self.handle_errors(e)
- def find_entries(self, filter=None, attrs_list=None, base_dn=None,
- scope=_ldap.SCOPE_SUBTREE, time_limit=None, size_limit=None,
- normalize=True, search_refs=False):
- """
- Return a list of entries and indication of whether the results were
- truncated ([(dn, entry_attrs)], truncated) matching specified search
- parameters followed by truncated flag. If the truncated flag is True,
- search hit a server limit and its results are incomplete.
-
- Keyword arguments:
- attrs_list -- list of attributes to return, all if None (default None)
- base_dn -- dn of the entry at which to start the search (default '')
- scope -- search scope, see LDAP docs (default ldap2.SCOPE_SUBTREE)
- time_limit -- time limit in seconds (default use IPA config values)
- size_limit -- size (number of entries returned) limit (default use IPA config values)
- normalize -- normalize the DN (default True)
- search_refs -- allow search references to be returned (default skips these entries)
- """
- if base_dn is None:
- base_dn = DN()
- assert isinstance(base_dn, DN)
- if normalize:
- base_dn = self.normalize_dn(base_dn)
- if not filter:
- filter = '(objectClass=*)'
- res = []
- truncated = False
-
- if time_limit is None or size_limit is None:
- (cdn, config) = self.get_ipa_config()
- if time_limit is None:
- time_limit = config.get('ipasearchtimelimit', [-1])[0]
- if size_limit is None:
- size_limit = config.get('ipasearchrecordslimit', [0])[0]
- if time_limit == 0:
- time_limit = -1
- if not isinstance(size_limit, int):
- size_limit = int(size_limit)
- if not isinstance(time_limit, float):
- time_limit = float(time_limit)
-
- if attrs_list:
- attrs_list = list(set(attrs_list))
-
- # pass arguments to python-ldap
- try:
- id = self.conn.search_ext(
- base_dn, scope, filter, attrs_list, timeout=time_limit,
- sizelimit=size_limit
- )
- while True:
- (objtype, res_list) = self.conn.result(id, 0)
- if not res_list:
- break
- if objtype == _ldap.RES_SEARCH_ENTRY or \
- (search_refs and objtype == _ldap.RES_SEARCH_REFERENCE):
- res.append(res_list[0])
- except (_ldap.ADMINLIMIT_EXCEEDED, _ldap.TIMELIMIT_EXCEEDED,
- _ldap.SIZELIMIT_EXCEEDED), e:
- truncated = True
- except _ldap.LDAPError, e:
- self.handle_errors(e)
-
- if not res and not truncated:
- raise errors.NotFound(reason='no such entry')
-
- if attrs_list and ('memberindirect' in attrs_list or '*' in attrs_list):
- for r in res:
- if not 'member' in r[1]:
- continue
- else:
- members = r[1]['member']
- indirect = self.get_members(r[0], members, membertype=MEMBERS_INDIRECT,
- time_limit=time_limit, size_limit=size_limit, normalize=normalize)
- if len(indirect) > 0:
- r[1]['memberindirect'] = indirect
- if attrs_list and ('memberofindirect' in attrs_list or '*' in attrs_list):
- for r in res:
- if 'memberof' in r[1]:
- memberof = r[1]['memberof']
- del r[1]['memberof']
- elif 'memberOf' in r[1]:
- memberof = r[1]['memberOf']
- del r[1]['memberOf']
- else:
- continue
- (direct, indirect) = self.get_memberof(r[0], memberof, time_limit=time_limit,
- size_limit=size_limit, normalize=normalize)
- if len(direct) > 0:
- r[1]['memberof'] = direct
- if len(indirect) > 0:
- r[1]['memberofindirect'] = indirect
-
- return (res, truncated)
-
- def find_entry_by_attr(self, attr, value, object_class, attrs_list=None, base_dn=None):
- """
- Find entry (dn, entry_attrs) by attribute and object class.
-
- Keyword arguments:
- attrs_list - list of attributes to return, all if None (default None)
- base_dn - dn of the entry at which to start the search (default '')
- """
-
- if base_dn is None:
- base_dn = DN()
- assert isinstance(base_dn, DN)
-
- search_kw = {attr: value, 'objectClass': object_class}
- filter = self.make_filter(search_kw, rules=self.MATCH_ALL)
- (entries, truncated) = self.find_entries(filter, attrs_list, base_dn)
-
- if len(entries) > 1:
- raise errors.SingleMatchExpected(found=len(entries))
- else:
- if truncated:
- raise errors.LimitsExceeded()
- else:
- return entries[0]
-
- def get_entry(self, dn, attrs_list=None, time_limit=None,
- size_limit=None, normalize=True):
- """
- Get entry (dn, entry_attrs) by dn.
-
- Keyword arguments:
- attrs_list - list of attributes to return, all if None (default None)
- """
-
- assert isinstance(dn, DN)
-
- (entry, truncated) = self.find_entries(
- None, attrs_list, dn, self.SCOPE_BASE, time_limit=time_limit,
- size_limit=size_limit, normalize=normalize
- )
-
- if truncated:
- raise errors.LimitsExceeded()
- return entry[0]
-
config_defaults = {'ipasearchtimelimit': [2], 'ipasearchrecordslimit': [0]}
def get_ipa_config(self, attrs_list=None):
"""Returns the IPA configuration entry (dn, entry_attrs)."""
@@ -376,7 +233,7 @@ class ldap2(LDAPConnection, CrudBackend):
try:
config_entry = getattr(context, 'config_entry')
- return (cdn, copy.deepcopy(config_entry))
+ return copy.deepcopy(config_entry)
except AttributeError:
# Not in our context yet
pass
@@ -387,14 +244,14 @@ class ldap2(LDAPConnection, CrudBackend):
)
if truncated:
raise errors.LimitsExceeded()
- (cdn, config_entry) = entry[0]
+ config_entry = entry[0]
except errors.NotFound:
config_entry = {}
for a in self.config_defaults:
if a not in config_entry:
config_entry[a] = self.config_defaults[a]
- setattr(context, 'config_entry', copy.deepcopy(config_entry))
- return (cdn, config_entry)
+ context.config_entry = copy.deepcopy(config_entry)
+ return config_entry
def has_upg(self):
"""Returns True/False whether User-Private Groups are enabled.
@@ -706,148 +563,6 @@ class ldap2(LDAPConnection, CrudBackend):
# update group entry
self.update_entry(group_dn, group_entry_attrs)
- def get_members(self, group_dn, members, attr_list=[], membertype=MEMBERS_ALL, time_limit=None, size_limit=None, normalize=True):
- """Do a memberOf search of groupdn and return the attributes in
- attr_list (an empty list returns all attributes).
-
- membertype = MEMBERS_ALL all members returned
- membertype = MEMBERS_DIRECT only direct members are returned
- membertype = MEMBERS_INDIRECT only inherited members are returned
-
- Members may be included in a group as a result of being a member
- of a group that is a member of the group being queried.
-
- Returns a list of DNs.
- """
-
- assert isinstance(group_dn, DN)
-
- if membertype not in [MEMBERS_ALL, MEMBERS_DIRECT, MEMBERS_INDIRECT]:
- return None
-
- self.log.debug(
- "get_members: group_dn=%s members=%s membertype=%s",
- group_dn, members, membertype)
- search_group_dn = _ldap_filter.escape_filter_chars(str(group_dn))
- searchfilter = "(memberof=%s)" % search_group_dn
-
- attr_list.append("member")
-
- # Verify group membership
-
- results = []
- if membertype == MEMBERS_ALL or membertype == MEMBERS_INDIRECT:
- user_container_dn = DN(api.env.container_user, api.env.basedn) # FIXME, initialize once
- host_container_dn = DN(api.env.container_host, api.env.basedn)
- checkmembers = set(DN(x) for x in members)
- checked = set()
- while checkmembers:
- member_dn = checkmembers.pop()
- checked.add(member_dn)
-
- # No need to check entry types that are not nested for
- # additional members
- if member_dn.endswith(user_container_dn) or \
- member_dn.endswith(host_container_dn):
- results.append([member_dn, {}])
- continue
- try:
- (result, truncated) = self.find_entries(searchfilter,
- attr_list, member_dn, time_limit=time_limit,
- size_limit=size_limit, scope=_ldap.SCOPE_BASE,
- normalize=normalize)
- if truncated:
- raise errors.LimitsExceeded()
- results.append(list(result[0]))
- for m in result[0][1].get('member', []):
- # This member may contain other members, add it to our
- # candidate list
- if m not in checked:
- checkmembers.add(m)
- except errors.NotFound:
- pass
-
- if membertype == MEMBERS_ALL:
- entries = []
- for e in results:
- entries.append(e[0])
-
- return entries
-
- (dn, group) = self.get_entry(group_dn, ['dn', 'member'],
- size_limit=size_limit, time_limit=time_limit)
- real_members = group.get('member', [])
-
- entries = []
- for e in results:
- if e[0] not in real_members and e[0] not in entries:
- if membertype == MEMBERS_INDIRECT:
- entries.append(e[0])
- else:
- if membertype == MEMBERS_DIRECT:
- entries.append(e[0])
-
- self.log.debug("get_members: result=%s", entries)
- return entries
-
- def get_memberof(self, entry_dn, memberof, time_limit=None, size_limit=None, normalize=True):
- """
- Examine the objects that an entry is a member of and determine if they
- are a direct or indirect member of that group.
-
- entry_dn: dn of the entry we want the direct/indirect members of
- memberof: the memberOf attribute for entry_dn
-
- Returns two memberof lists: (direct, indirect)
- """
-
- assert isinstance(entry_dn, DN)
-
- self.log.debug(
- "get_memberof: entry_dn=%s memberof=%s", entry_dn, memberof)
- if not type(memberof) in (list, tuple):
- return ([], [])
- if len(memberof) == 0:
- return ([], [])
-
- search_entry_dn = _ldap_filter.escape_filter_chars(str(entry_dn))
- attr_list = ["dn", "memberof"]
- searchfilter = "(|(member=%s)(memberhost=%s)(memberuser=%s))" % (
- search_entry_dn, search_entry_dn, search_entry_dn)
-
- # Search only the groups for which the object is a member to
- # determine if it is directly or indirectly associated.
-
- results = []
- for group in memberof:
- assert isinstance(group, DN)
- try:
- (result, truncated) = self.find_entries(searchfilter, attr_list,
- group, time_limit=time_limit,size_limit=size_limit,
- scope=_ldap.SCOPE_BASE, normalize=normalize)
- results.extend(list(result))
- except errors.NotFound:
- pass
-
- direct = []
- # If there is an exception here, it is likely due to a failure in
- # referential integrity. All members should have corresponding
- # memberOf entries.
- indirect = list(memberof)
- for r in results:
- direct.append(r[0])
- try:
- indirect.remove(r[0])
- except ValueError, e:
- self.log.info(
- 'Failed to remove indirect entry %s from %s',
- r[0], entry_dn)
- raise e
-
- self.log.debug(
- "get_memberof: result direct=%s indirect=%s", direct, indirect)
- return (direct, indirect)
-
def set_entry_active(self, dn, active):
"""Mark entry active/inactive."""