summaryrefslogtreecommitdiffstats
path: root/ipalib
diff options
context:
space:
mode:
authorRob Crittenden <rcritten@redhat.com>2009-03-16 17:38:48 -0400
committerRob Crittenden <rcritten@redhat.com>2009-03-18 15:47:06 -0400
commitbc056cda2dc9f55371064430a72b3667b5c29344 (patch)
treedf198ecf2d2114f51f2961e3ebddd1938338f709 /ipalib
parent4c5806b4b42c63f08b286f984e4032fcefcfd1e8 (diff)
downloadfreeipa-bc056cda2dc9f55371064430a72b3667b5c29344.tar.gz
freeipa-bc056cda2dc9f55371064430a72b3667b5c29344.tar.xz
freeipa-bc056cda2dc9f55371064430a72b3667b5c29344.zip
Update the ACI class to be more robust and the beginnings of an ACI plugin
The ACI plugin is really meant for developers to help manage the ACIs. It may or may not be shipped. If it is it will be disabled by default. It is very much a shoot-in-foot problem waiting to happen.
Diffstat (limited to 'ipalib')
-rwxr-xr-xipalib/aci.py251
-rw-r--r--ipalib/plugins/aci.py438
2 files changed, 602 insertions, 87 deletions
diff --git a/ipalib/aci.py b/ipalib/aci.py
index 9dde767c0..a9219f8dc 100755
--- a/ipalib/aci.py
+++ b/ipalib/aci.py
@@ -29,6 +29,16 @@ ACIPat = re.compile(r'\s*(\(.*\)+)\s*\(version\s+3.0\s*;\s*acl\s+\"(.*)\"\s*;\s*
# Break the permissions/bind_rules out
PermPat = re.compile(r'(\w+)\s*\((.*)\)\s+(.*)')
+# Break the bind rule out
+BindPat = re.compile(r'([a-zA-Z0-9;\.]+)\s*(\!?=)\s*(.*)')
+
+# Don't allow arbitrary attributes to be set in our __setattr__ implementation.
+OBJECTATTRS = ["name", "orig_acistr", "target", "action", "permissions",
+ "bindrule"]
+ACTIONS = ["allow", "deny"]
+
+PERMISSIONS = ["read", "write", "add", "delete", "search", "compare",
+ "selfwrite", "proxy", "all"]
class ACI:
"""
@@ -36,23 +46,13 @@ class ACI:
entry in LDAP. Has methods to parse an ACI string and export to an
ACI String.
"""
-
- # Don't allow arbitrary attributes to be set in our __setattr__ implementation.
- _objectattrs = ["name", "orig_acistr", "target", "action", "permissions",
- "bindrule"]
-
- __actions = ["allow", "deny"]
-
- __permissions = ["read", "write", "add", "delete", "search", "compare",
- "selfwrite", "proxy", "all"]
-
def __init__(self,acistr=None):
self.name = None
self.orig_acistr = acistr
self.target = {}
self.action = "allow"
self.permissions = ["write"]
- self.bindrule = None
+ self.bindrule = {}
if acistr is not None:
self._parse_acistr(acistr)
@@ -70,73 +70,21 @@ class ACI:
"""An alias for export_to_string()"""
return self.export_to_string()
- def __getattr__(self, name):
- """
- Backward compatibility for the old ACI class.
-
- The following extra attributes are available:
-
- - source_group
- - dest_group
- - attrs
- """
- if name == 'source_group':
- group = ''
- dn = self.bindrule.split('=',1)
- if dn[0] == "groupdn":
- group = self._remove_quotes(dn[1])
- if group.startswith("ldap:///"):
- group = group[8:]
- return group
- if name == 'dest_group':
- group = self.target.get('targetfilter', '')
- if group:
- g = group.split('=',1)[1]
- if g.endswith(')'):
- g = g[:-1]
- return g
- return ''
- if name == 'attrs':
- return self.target.get('targetattr', None)
- raise AttributeError, "object has no attribute '%s'" % name
-
- def __setattr__(self, name, value):
- """
- Backward compatibility for the old ACI class.
-
- The following extra attributes are available:
- - source_group
- - dest_group
- - attrs
- """
- if name == 'source_group':
- self.__dict__['bindrule'] = 'groupdn="ldap:///%s"' % value
- elif name == 'dest_group':
- if value.startswith('('):
- self.__dict__['target']['targetfilter'] = 'memberOf=%s' % value
- else:
- self.__dict__['target']['targetfilter'] = '(memberOf=%s)' % value
- elif name == 'attrs':
- self.__dict__['target']['targetattr'] = value
- elif name in self._objectattrs:
- self.__dict__[name] = value
- else:
- raise AttributeError, "object has no attribute '%s'" % name
-
def export_to_string(self):
"""Output a Directory Server-compatible ACI string"""
self.validate()
aci = ""
for t in self.target:
- if isinstance(self.target[t], list):
+ op = self.target[t]['operator']
+ if isinstance(self.target[t]['expression'], list):
target = ""
- for l in self.target[t]:
+ for l in self.target[t]['expression']:
target = target + l + " || "
target = target[:-4]
- aci = aci + "(%s=\"%s\")" % (t, target)
+ aci = aci + "(%s %s \"%s\")" % (t, op, target)
else:
- aci = aci + "(%s=\"%s\")" % (t, self.target[t])
- aci = aci + "(version 3.0;acl \"%s\";%s (%s) %s" % (self.name, self.action, ",".join(self.permissions), self.bindrule) + ";)"
+ aci = aci + "(%s %s \"%s\")" % (t, op, self.target[t]['expression'])
+ aci = aci + "(version 3.0;acl \"%s\";%s (%s) %s %s \"%s\"" % (self.name, self.action, ",".join(self.permissions), self.bindrule['keyword'], self.bindrule['operator'], self.bindrule['expression']) + ";)"
return aci
def _remove_quotes(self, s):
@@ -154,13 +102,18 @@ class ACI:
l = []
var = False
+ op = "="
for token in lexer:
# We should have the form (a = b)(a = b)...
if token == "(":
var = lexer.next().strip()
operator = lexer.next()
if operator != "=" and operator != "!=":
- raise SyntaxError('No operator in target, got %s' % operator)
+ # Peek at the next char before giving up
+ operator = operator + lexer.next()
+ if operator != "=" and operator != "!=":
+ raise SyntaxError("No operator in target, got '%s'" % operator)
+ op = operator
val = lexer.next().strip()
val = self._remove_quotes(val)
end = lexer.next()
@@ -169,10 +122,14 @@ class ACI:
if var == 'targetattr':
# Make a string of the form attr || attr || ... into a list
- t = re.split('[\W]+', val)
- self.target[var] = t
+ t = re.split('[^a-zA-Z0-9;\*]+', val)
+ self.target[var] = {}
+ self.target[var]['operator'] = op
+ self.target[var]['expression'] = t
else:
- self.target[var] = val
+ self.target[var] = {}
+ self.target[var]['operator'] = op
+ self.target[var]['expression'] = val
def _parse_acistr(self, acistr):
acimatch = ACIPat.match(acistr)
@@ -184,8 +141,8 @@ class ACI:
if not bindperms or len(bindperms.groups()) < 3:
raise SyntaxError, "malformed ACI"
self.action = bindperms.group(1)
- self.permissions = bindperms.group(2).split(',')
- self.bindrule = bindperms.group(3)
+ self.permissions = bindperms.group(2).replace(' ','').split(',')
+ self.set_bindrule(bindperms.group(3))
def validate(self):
"""Do some basic verification that this will produce a
@@ -196,7 +153,7 @@ class ACI:
if not isinstance(self.permissions, list):
raise SyntaxError, "permissions must be a list"
for p in self.permissions:
- if not p.lower() in self.__permissions:
+ if not p.lower() in PERMISSIONS:
raise SyntaxError, "invalid permission: '%s'" % p
if not self.name:
raise SyntaxError, "name must be set"
@@ -204,14 +161,100 @@ class ACI:
raise SyntaxError, "name must be a string"
if not isinstance(self.target, dict) or len(self.target) == 0:
raise SyntaxError, "target must be a non-empty dictionary"
+ if not isinstance(self.bindrule, dict):
+ raise SyntaxError, "bindrule must be a dictionary"
+ if not self.bindrule.get('operator') or not self.bindrule.get('keyword') or not self.bindrule.get('expression'):
+ raise SyntaxError, "bindrule is missing a component"
+ return True
+
+ def set_target_filter(self, filter, operator="="):
+ self.target['targetfilter'] = {}
+ if not filter.startswith("("):
+ filter = "(" + filter + ")"
+ self.target['targetfilter']['expression'] = filter
+ self.target['targetfilter']['operator'] = operator
+
+ def set_target_attr(self, attr, operator="="):
+ if not isinstance(attr, list):
+ attr = [attr]
+ self.target['targetattr'] = {}
+ self.target['targetattr']['expression'] = attr
+ self.target['targetattr']['operator'] = operator
+
+ def set_target(self, target, operator="="):
+ assert target.startswith("ldap:///")
+ self.target['target'] = {}
+ self.target['target']['expression'] = target
+ self.target['target']['operator'] = operator
+
+ def set_bindrule(self, bindrule):
+ match = BindPat.match(bindrule)
+ if not match or len(match.groups()) < 3:
+ raise SyntaxError, "malformed bind rule"
+ self.set_bindrule_keyword(match.group(1))
+ self.set_bindrule_operator(match.group(2))
+ self.set_bindrule_expression(match.group(3).replace('"',''))
+
+ def set_bindrule_keyword(self, keyword):
+ self.bindrule['keyword'] = keyword
+
+ def set_bindrule_operator(self, operator):
+ self.bindrule['operator'] = operator
+
+ def set_bindrule_expression(self, expression):
+ self.bindrule['expression'] = expression
+
+ def isequal(self, b):
+ """
+ Compare the current ACI to another one to see if they are
+ the same.
+
+ returns True if equal, False if not.
+ """
+ try:
+ if self.name != b.name:
+ return False
+
+ if set(self.permissions) != set(b.permissions):
+ return False
+
+ if self.bindrule.get('keyword') != b.bindrule.get('keyword'):
+ return False
+ if self.bindrule.get('operator') != b.bindrule.get('operator'):
+ return False
+ if self.bindrule.get('expression') != b.bindrule.get('expression'):
+ return False
+
+ if self.target.get('targetfilter',{}).get('expression') != b.target.get('targetfilter',{}).get('expression'):
+ return False
+ if self.target.get('targetfilter',{}).get('operator') != b.target.get('targetfilter',{}).get('operator'):
+ return False
+
+ if set(self.target.get('targetattr',{}).get('expression')) != set(b.target.get('targetattr',{}).get('expression')):
+ return False
+ if self.target.get('targetattr',{}).get('operator') != b.target.get('targetattr',{}).get('operator'):
+ return False
+
+ if self.target.get('target',{}).get('expression') != b.target.get('target',{}).get('expression'):
+ return False
+ if self.target.get('target',{}).get('operator') != b.target.get('target',{}).get('operator'):
+ return False
+
+ except Exception:
+ # If anything throws up then they are not equal
+ return False
+
+ # We got this far so lets declare them the same
return True
def extract_group_cns(aci_list, client):
- """Extracts all the cn's from a list of aci's and returns them as a hash
- from group_dn to group_cn.
+ """
+ Extracts all the cn's from a list of aci's and returns them as a hash
+ from group_dn to group_cn.
- It first tries to cheat by looking at the first rdn for the
- group dn. If that's not cn for some reason, it looks up the group."""
+ It first tries to cheat by looking at the first rdn for the
+ group dn. If that's not cn for some reason, it looks up the group.
+ """
group_dn_to_cn = {}
for aci in aci_list:
for dn in (aci.source_group, aci.dest_group):
@@ -231,15 +274,49 @@ def extract_group_cns(aci_list, client):
return group_dn_to_cn
if __name__ == '__main__':
- # Pass in an ACI as a string
- a = ACI('(targetattr="title")(targetfilter="(memberOf=cn=bar,cn=groups,cn=accounts ,dc=example,dc=com)")(version 3.0;acl "foobar";allow (write) groupdn="ldap:///cn=foo,cn=groups,cn=accounts,dc=example,dc=com";)')
+# a = ACI('(targetattr="title")(targetfilter="(memberOf=cn=bar,cn=groups,cn=accounts ,dc=example,dc=com)")(version 3.0;acl "foobar";allow (write) groupdn="ldap:///cn=foo,cn=groups,cn=accounts,dc=example,dc=com";)')
+# print a
+# a = ACI('(target="ldap:///uid=bjensen,dc=example,dc=com")(targetattr=*) (version 3.0;acl "aci1";allow (write) userdn="ldap:///self";)')
+# print a
+# a = ACI(' (targetattr = "givenName || sn || cn || displayName || title || initials || loginShell || gecos || homePhone || mobile || pager || facsimileTelephoneNumber || telephoneNumber || street || roomNumber || l || st || postalCode || manager || secretary || description || carLicense || labeledURI || inetUserHTTPURL || seeAlso || employeeType || businessCategory || ou")(version 3.0;acl "Self service";allow (write) userdn = "ldap:///self";)')
+# print a
+
+ a = ACI('(target="ldap:///uid=*,cn=users,cn=accounts,dc=example,dc=com")(version 3.0;acl "add_user";allow (add) groupdn="ldap:///cn=add_user,cn=taskgroups,dc=example,dc=com";)')
+ print a
+ print "---"
+
+ a = ACI('(targetattr=member)(target="ldap:///cn=ipausers,cn=groups,cn=accounts,dc=example,dc=com")(version 3.0;acl "add_user_to_default_group";allow (write) groupdn="ldap:///cn=add_user_to_default_group,cn=taskgroups,dc=example,dc=com";)')
+ print a
+ print "---"
+
+ a = ACI('(targetattr!=member)(target="ldap:///cn=ipausers,cn=groups,cn=accounts,dc=example,dc=com")(version 3.0;acl "add_user_to_default_group";allow (write) groupdn="ldap:///cn=add_user_to_default_group,cn=taskgroups,dc=example,dc=com";)')
print a
+ print "---"
+
+ a = ACI('(targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "change_password"; allow (write) groupdn = "ldap:///cn=change_password,cn=taskgroups,dc=example,dc=com";)')
+ print a
+ print "---"
- # Create an ACI in pieces
a = ACI()
- a.name ="foobar"
- a.source_group="cn=foo,cn=groups,dc=example,dc=org"
- a.dest_group="cn=bar,cn=groups,dc=example,dc=org"
- a.attrs = ['title']
+ a.name ="foo"
+ a.set_target_attr(['title','givenname'], "!=")
+# a.set_bindrule("groupdn = \"ldap:///cn=foo,cn=groups,cn=accounts,dc=example,dc=com\"")
+ a.set_bindrule_keyword("groupdn")
+ a.set_bindrule_operator("=")
+ a.set_bindrule_expression ("\"ldap:///cn=foo,cn=groups,cn=accounts,dc=example,dc=com\"")
a.permissions = ['read','write','add']
print a
+
+ b = ACI()
+ b.name ="foo"
+ b.set_target_attr(['givenname','title'], "!=")
+ b.set_bindrule_keyword("groupdn")
+ b.set_bindrule_operator("=")
+ b.set_bindrule_expression ("\"ldap:///cn=foo,cn=groups,cn=accounts,dc=example,dc=com\"")
+ b.permissions = ['add','read','write']
+ print b
+
+ print a.isequal(b)
+
+ a = ACI('(targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey")(version 3.0; acl "Enable Anonymous access"; allow (read, search, compare) userdn = "ldap:///anyone";)')
+ print a
diff --git a/ipalib/plugins/aci.py b/ipalib/plugins/aci.py
new file mode 100644
index 000000000..6eb482642
--- /dev/null
+++ b/ipalib/plugins/aci.py
@@ -0,0 +1,438 @@
+# Authors:
+# Rob Crittenden <rcritten@redhat.com>
+#
+# Copyright (C) 2009 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2 only
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+Frontend plugins for managing DS ACIs
+"""
+
+from ipalib import api, crud, errors2
+from ipalib import Object, Command # Plugin base classes
+from ipalib import Str, Flag, Int # Parameter types
+from ipalib.aci import ACI
+
+def make_aci(current, aciname, kw):
+ try:
+ taskgroup = api.Command['taskgroup_show'](kw['taskgroup'])
+ except errors2.NotFound:
+ # The task group doesn't exist, let's be helpful and add it
+ tgkw = {'description':aciname}
+ taskgroup = api.Command['taskgroup_add'](kw['taskgroup'], **tgkw)
+
+ a = ACI(current)
+ a.name = aciname
+ a.permissions = kw['permissions'].replace(' ','').split(',')
+ a.set_bindrule("groupdn = \"ldap:///%s\"" % taskgroup['dn'])
+ if kw.get('attrs', None):
+ a.set_target_attr(kw['attrs'].split())
+ if kw.get('type', None):
+ a.set_target_attr(kw['attrs'].split())
+ if kw.get('memberof', None):
+ group = api.Command['group_show'](kw['memberof'])
+ a.set_target_filter("memberOf=%s" % group['dn'].decode('UTF-8'))
+ return a
+
+def search_by_name(acis, aciname):
+ """
+ Find an aci using the name field.
+
+ Must be an exact match of the entire name.
+ """
+ for a in acis:
+ try:
+ t = ACI(a)
+ if t.name == aciname:
+ return str(t)
+ except SyntaxError, e:
+ # FIXME: need to log syntax errors, ignore for now
+ pass
+
+ raise errors2.NotFound()
+
+def search_by_attr(acis, attrlist):
+ """
+ Find an aci by targetattr.
+
+ Returns an ACI list of all acis the attribute appears in.
+ """
+ results = []
+ for a in acis:
+ try:
+ t = ACI(a)
+ for attr in attrlist:
+ attr = attr.lower()
+ for v in t.target['targetattr'].get('expression'):
+ if attr == v.lower():
+ results.append(str(t))
+ except SyntaxError, e:
+ # FIXME: need to log syntax errors, ignore for now
+ pass
+
+ if results:
+ return results
+
+ raise errors2.NotFound()
+
+def search_by_taskgroup(acis, tgdn):
+ """
+ Find an aci by taskgroup. This searches the ACI bind rule.
+
+ Returns an ACI list of all acis that match.
+ """
+ results = []
+ for a in acis:
+ try:
+ t = ACI(a)
+ if t.bindrule['expression'] == "ldap:///" + tgdn:
+ results.append(str(t))
+ except SyntaxError, e:
+ # FIXME: need to log syntax errors, ignore for now
+ pass
+
+ if results:
+ return results
+
+ raise errors2.NotFound()
+
+def search_by_perm(acis, permlist):
+ """
+ Find an aci by permissions
+
+ Returns an ACI list of all acis the permission appears in.
+ """
+ results = []
+ for a in acis:
+ try:
+ t = ACI(a)
+ for perm in permlist:
+ if perm.lower() in t.permissions:
+ results.append(str(t))
+ except SyntaxError, e:
+ # FIXME: need to log syntax errors, ignore for now
+ pass
+
+ if results:
+ return results
+
+ raise errors2.NotFound()
+
+def search_by_memberof(acis, memberoffilter):
+ """
+ Find an aci by memberof
+
+ Returns an ACI list of all acis that has a matching memberOf as a
+ targetfilter.
+ """
+ results = []
+ memberoffilter = memberoffilter.lower()
+ for a in acis:
+ try:
+ t = ACI(a)
+ try:
+ if memberoffilter == t.target['targetfilter'].get('expression').lower():
+ results.append(str(t))
+ except KeyError:
+ pass
+ except SyntaxError, e:
+ # FIXME: need to log syntax errors, ignore for now
+ pass
+
+ if results:
+ return results
+
+ raise errors2.NotFound()
+
+class aci(Object):
+ """
+ ACI object.
+ """
+ takes_params = (
+ Str('aciname',
+ doc='Name of ACI',
+ primary_key=True,
+ ),
+ Str('taskgroup',
+ doc='Name of taskgroup this ACI grants access to',
+ ),
+ Str('permissions',
+ doc='Permissions to grant: read, write',
+ ),
+ Str('attrs?',
+ doc='Comma-separated list of attributes',
+ ),
+ Str('type?',
+ doc='type of IPA object: user, group, host',
+ ),
+ Str('memberof?',
+ doc='member of a group',
+ ),
+ Str('filter?',
+ doc='A legal LDAP filter (ou=Engineering)',
+ ),
+ Str('subtree?',
+ doc='A subtree to apply the ACI to',
+ ),
+ )
+api.register(aci)
+
+
+class aci_add(crud.Create):
+ """
+ Add a new aci.
+ """
+
+ def execute(self, aciname, **kw):
+ """
+ Execute the aci-add operation.
+
+ Returns the entry as it will be created in LDAP.
+
+ :param aciname: The name of the ACI being added.
+ :param kw: Keyword arguments for the other LDAP attributes.
+ """
+ assert 'aciname' not in kw
+ ldap = self.api.Backend.ldap
+
+ newaci = make_aci(None, aciname, kw)
+
+ currentaci = ldap.retrieve(self.api.env.basedn, ['aci'])
+
+ acilist = currentaci.get('aci')
+ for a in acilist:
+ try:
+ b = ACI(a)
+ if newaci.isequal(b):
+ raise errors2.DuplicateEntry()
+ except SyntaxError:
+ pass
+ acilist.append(str(newaci))
+ kwupdate = {'aci': acilist}
+
+ return ldap.update(currentaci.get('dn'), **kwupdate)
+
+api.register(aci_add)
+
+
+class aci_del(crud.Delete):
+ 'Delete an existing aci.'
+ """
+ Remove an aci by name.
+ """
+
+ def execute(self, aciname, **kw):
+ """
+ Execute the aci-del operation.
+
+ :param aciname: The name of the ACI being added.
+ :param kw: unused
+ """
+ assert 'aciname' not in kw
+ ldap = self.api.Backend.ldap
+
+ currentaci = ldap.retrieve(self.api.env.basedn, ['aci'])
+ acilist = currentaci.get('aci')
+ a = search_by_name(acilist, aciname)
+ i = acilist.index(str(a))
+ del acilist[i]
+
+ kwupdate = {'aci': acilist}
+
+ return ldap.update(currentaci.get('dn'), **kwupdate)
+
+ def output_for_cli(self, textui, result, aciname):
+ """
+ Output result of this command to command line interface.
+ """
+ textui.print_plain('Deleted aci "%s"' % aciname)
+
+api.register(aci_del)
+
+
+class aci_mod(crud.Update):
+ 'Edit an existing aci.'
+ def execute(self, aciname, **kw):
+ return "Not implemented"
+ def output_for_cli(self, textui, result, aciname, **options):
+ textui.print_plain(result)
+api.register(aci_mod)
+
+
+class aci_find(crud.Search):
+ 'Search for a aci.'
+ takes_options = (
+ Str('bindrule?',
+ doc='The bindrule (e.g. ldap:///self)'
+ ),
+ Flag('and?',
+ doc='Consider multiple options to be \"and\" so all are required.')
+ )
+ def execute(self, term, **kw):
+ ldap = self.api.Backend.ldap
+ currentaci = ldap.retrieve(self.api.env.basedn, ['aci'])
+ currentaci = currentaci.get('aci')
+ results = []
+
+ # aciname
+ if kw.get('aciname'):
+ try:
+ a = search_by_name(currentaci, kw.get('aciname'))
+ results = [a]
+ if kw.get('and'):
+ currentaci = results
+ except errors2.NotFound:
+ if kw.get('and'):
+ results = []
+ currentaci = []
+ pass
+
+ # attributes
+ if kw.get('attrs'):
+ try:
+ attrs = kw.get('attrs')
+ attrs = attrs.replace(' ','').split(',')
+ a=search_by_attr(currentaci, attrs)
+ if kw.get('and'):
+ results = a
+ currentaci = results
+ else:
+ results = results + a
+ except errors2.NotFound:
+ if kw.get('and'):
+ results = []
+ currentaci = []
+ pass
+
+ # taskgroup
+ if kw.get('taskgroup'):
+ try:
+ tg = api.Command['taskgroup_show'](kw.get('taskgroup'))
+ except errors2.NotFound:
+ # FIXME, need more precise error
+ raise
+ try:
+ a=search_by_taskgroup(currentaci, tg.get('dn'))
+ if kw.get('and'):
+ results = a
+ currentaci = results
+ else:
+ results = results + a
+ except errors2.NotFound:
+ if kw.get('and'):
+ results = []
+ currentaci = []
+ pass
+
+ # permissions
+ if kw.get('permissions'):
+ try:
+ permissions = kw.get('permissions')
+ permissions = permissions.replace(' ','').split(',')
+ a=search_by_perm(currentaci, permissions)
+ if kw.get('and'):
+ results = a
+ currentaci = results
+ else:
+ results = results + a
+ except errors2.NotFound:
+ if kw.get('and'):
+ results = []
+ currentaci = []
+ pass
+
+ # memberOf
+ if kw.get('memberof'):
+ try:
+ group = api.Command['group_show'](kw['memberof'])
+ memberof = "(memberOf=%s)" % group['dn'].decode('UTF-8')
+ a=search_by_memberof(currentaci, memberof)
+ results = results + a
+ if kw.get('and'):
+ currentaci = results
+ except errors2.NotFound:
+ if kw.get('and'):
+ results = []
+ currentaci = []
+ pass
+
+# TODO
+# --type=STR type of IPA object: user, group, host
+# --filter=STR A legal LDAP filter (ou=Engineering)
+# --subtree=STR A subtree to apply the ACI to
+# --bindrule=STR A subtree to apply the ACI to
+
+ # Make sure we have no dupes in the list
+ results = list(set(results))
+
+ # the first entry contains the count
+ counter = len(results)
+ return [counter] + results
+
+ def output_for_cli(self, textui, result, term, **options):
+ counter = result[0]
+ acis = result[1:]
+ if counter == 0 or len(acis) == 0:
+ textui.print_plain("No entries found")
+ return
+ textui.print_name(self.name)
+ for a in acis:
+ textui.print_plain(a)
+ textui.print_count(acis, '%d acis matched')
+
+api.register(aci_find)
+
+
+class aci_show(crud.Retrieve):
+ 'Examine an existing aci.'
+ def execute(self, aciname, **kw):
+ """
+ Execute the aci-show operation.
+
+ Returns the entry
+
+ :param uid: The login name of the user to retrieve.
+ :param kw: unused
+ """
+ ldap = self.api.Backend.ldap
+ currentaci = ldap.retrieve(self.api.env.basedn, ['aci'])
+
+ a = search_by_name(currentaci.get('aci'), aciname)
+ return str(a)
+
+ def output_for_cli(self, textui, result, aciname, **options):
+ textui.print_plain(result)
+
+api.register(aci_show)
+
+
+class aci_showall(Command):
+ 'Examine all existing acis.'
+ def execute(self):
+ """
+ Execute the aci-show operation.
+
+ Returns the entry
+
+ :param uid: The login name of the user to retrieve.
+ :param kw: unused
+ """
+ ldap = self.api.Backend.ldap
+ return ldap.retrieve(self.api.env.basedn, ['aci'])
+ def output_for_cli(self, textui, result, **options):
+ textui.print_entry(result)
+
+api.register(aci_showall)