summaryrefslogtreecommitdiffstats
path: root/ipalib/plugins/aci.py
diff options
context:
space:
mode:
Diffstat (limited to 'ipalib/plugins/aci.py')
-rw-r--r--ipalib/plugins/aci.py95
1 files changed, 75 insertions, 20 deletions
diff --git a/ipalib/plugins/aci.py b/ipalib/plugins/aci.py
index 7f9b0f21..648f5111 100644
--- a/ipalib/plugins/aci.py
+++ b/ipalib/plugins/aci.py
@@ -89,22 +89,22 @@ command-line now (see last example).
Add an ACI so that the group "secretaries" can update the address on any user:
ipa group-add --desc="Office secretaries" secretaries
- ipa aci-add --attrs=streetAddress --memberof=ipausers --group=secretaries --permissions=write "Secretaries write addresses"
+ ipa aci-add --attrs=streetAddress --memberof=ipausers --group=secretaries --permissions=write --prefix=none "Secretaries write addresses"
Show the new ACI:
- ipa aci-show "Secretaries write addresses"
+ ipa aci-show --prefix=none "Secretaries write addresses"
Add an ACI that allows members of the "addusers" permission to add new users:
- ipa aci-add --type=user --permission=addusers --permissions=add "Add new users"
+ ipa aci-add --type=user --permission=addusers --permissions=add --prefix=none "Add new users"
Add an ACI that allows members of the editors manage members of the admins group:
- ipa aci-add --permissions=write --attrs=member --targetgroup=admins --group=editors "Editors manage admins"
+ ipa aci-add --permissions=write --attrs=member --targetgroup=admins --group=editors --prefix=none "Editors manage admins"
Add an ACI that allows members of the admin group to manage the street and zip code of those in the editors group:
- ipa aci-add --permissions=write --memberof=editors --group=admins --attrs=street,postalcode "admins edit the address of editors"
+ ipa aci-add --permissions=write --memberof=editors --group=admins --attrs=street,postalcode --prefix=none "admins edit the address of editors"
Add an ACI that allows the admins group manage the street and zipcode of those who work for the boss:
- ipa aci-add --permissions=write --group=admins --attrs=street,postalcode --filter="(manager=uid=boss,cn=users,cn=accounts,dc=example,dc=com)" "Edit the address of those who work for the boss"
+ ipa aci-add --permissions=write --group=admins --attrs=street,postalcode --filter="(manager=uid=boss,cn=users,cn=accounts,dc=example,dc=com)" --prefix=none "Edit the address of those who work for the boss"
Add an entirely new kind of record to IPA that isn't covered by any of the --type options, creating a permission:
ipa permission-add --permissions=add --subtree="cn=*,cn=orange,cn=accounts,dc=example,dc=com" --desc="Add Orange Entries" add_orange
@@ -128,6 +128,8 @@ if api.env.in_server and api.env.context in ['lite', 'server']:
from ldap import explode_dn
import logging
+ACI_NAME_PREFIX_SEP = ":"
+
_type_map = {
'user': 'ldap:///uid=*,%s,%s' % (api.env.container_user, api.env.basedn),
'group': 'ldap:///cn=*,%s,%s' % (api.env.container_group, api.env.basedn),
@@ -142,6 +144,10 @@ _valid_permissions_values = [
u'read', u'write', u'add', u'delete', u'all'
]
+_valid_prefix_values = (
+ u'permission', u'delegation', u'selfservice', u'none'
+)
+
class ListOfACI(output.Output):
type = (list, tuple)
doc = _('A list of ACI values')
@@ -162,6 +168,26 @@ aci_output = (
)
+def _make_aci_name(aciprefix, aciname):
+ """
+ Given a name and a prefix construct an ACI name.
+ """
+ if aciprefix == u"none":
+ return aciname
+
+ return aciprefix + ACI_NAME_PREFIX_SEP + aciname
+
+def _parse_aci_name(aciname):
+ """
+ Parse the raw ACI name and return a tuple containing the ACI prefix
+ and the actual ACI name.
+ """
+ aciparts = aciname.partition(ACI_NAME_PREFIX_SEP)
+
+ if not aciparts[2]: # no prefix/name separator found
+ return (u"none",aciparts[0])
+
+ return (aciparts[0], aciparts[2])
def _make_aci(ldap, current, aciname, kw):
"""
@@ -177,6 +203,9 @@ def _make_aci(ldap, current, aciname, kw):
if t1 + t2 + t3 + t4 > 1:
raise errors.ValidationError(name='target', error=_('type, filter, subtree and targetgroup are mutually exclusive'))
+ if 'aciprefix' not in kw:
+ raise errors.ValidationError(name='aciprefix', error=_('ACI prefix is required'))
+
if t1 + t2 + t3 + t4 + t5 + t6 == 0:
raise errors.ValidationError(name='target', error=_('at least one of: type, filter, subtree, targetgroup, attrs or memberof are required'))
@@ -209,7 +238,7 @@ def _make_aci(ldap, current, aciname, kw):
try:
a = ACI(current)
- a.name = aciname
+ a.name = _make_aci_name(kw['aciprefix'], aciname)
a.permissions = kw['permissions']
if 'selfaci' in kw and kw['selfaci']:
a.set_bindrule('userdn = "ldap:///self"')
@@ -260,7 +289,7 @@ def _aci_to_kw(ldap, a, test=False):
_make_aci().
"""
kw = {}
- kw['aciname'] = a.name
+ kw['aciprefix'], kw['aciname'] = _parse_aci_name(a.name)
kw['permissions'] = tuple(a.permissions)
if 'targetattr' in a.target:
kw['attrs'] = list(a.target['targetattr']['expression'])
@@ -328,9 +357,10 @@ def _convert_strings_to_acis(acistrs):
logging.warn("Failed to parse: %s" % a)
return acis
-def _find_aci_by_name(acis, aciname):
+def _find_aci_by_name(acis, aciprefix, aciname):
+ name = _make_aci_name(aciprefix, aciname).lower()
for a in acis:
- if a.name.lower() == aciname.lower():
+ if a.name.lower() == name:
return a
raise errors.NotFound(reason=_('ACI with name "%s" not found') % aciname)
@@ -351,6 +381,13 @@ def _normalize_permissions(permissions):
valid_permissions.append(p)
return ','.join(valid_permissions)
+_prefix_option = StrEnum('aciprefix',
+ cli_name='prefix',
+ label=_('ACI prefix'),
+ doc=_('Prefix used to distinguish ACI types ' \
+ '(permission, delegation, selfservice, none)'),
+ values=_valid_prefix_values,
+ )
class aci(Object):
"""
@@ -423,7 +460,6 @@ class aci(Object):
api.register(aci)
-
class aci_add(crud.Create):
"""
Create new ACI.
@@ -432,6 +468,7 @@ class aci_add(crud.Create):
msg_summary = _('Created ACI "%(value)s"')
takes_options = (
+ _prefix_option,
Flag('test?',
doc=_('Test the ACI syntax but don\'t write anything'),
default=False,
@@ -486,6 +523,8 @@ class aci_del(crud.Delete):
has_output = output.standard_boolean
msg_summary = _('Deleted ACI "%(value)s"')
+ takes_options = (_prefix_option,)
+
def execute(self, aciname, **kw):
"""
Execute the aci-delete operation.
@@ -500,7 +539,7 @@ class aci_del(crud.Delete):
acistrs = entry_attrs.get('aci', [])
acis = _convert_strings_to_acis(acistrs)
- aci = _find_aci_by_name(acis, aciname)
+ aci = _find_aci_by_name(acis, kw['aciprefix'], aciname)
for a in acistrs:
candidate = ACI(a)
if aci.isequal(candidate):
@@ -530,6 +569,8 @@ class aci_mod(crud.Update):
),
)
+ takes_options = (_prefix_option,)
+
msg_summary = _('Modified ACI "%(value)s"')
def execute(self, aciname, **kw):
@@ -538,7 +579,7 @@ class aci_mod(crud.Update):
(dn, entry_attrs) = ldap.get_entry(self.api.env.basedn, ['aci'])
acis = _convert_strings_to_acis(entry_attrs.get('aci', []))
- aci = _find_aci_by_name(acis, aciname)
+ aci = _find_aci_by_name(acis, kw['aciprefix'], aciname)
# The strategy here is to convert the ACI we're updating back into
# a series of keywords. Then we replace any keywords that have been
@@ -558,7 +599,7 @@ class aci_mod(crud.Update):
if aci.isequal(newaci):
raise errors.EmptyModlist()
- self.api.Command['aci_del'](aciname)
+ self.api.Command['aci_del'](aciname, **kw)
result = self.api.Command['aci_add'](aciname, **newkw)['result']
@@ -597,6 +638,8 @@ class aci_find(crud.Search):
NO_CLI = True
msg_summary = ngettext('%(count)d ACI matched', '%(count)d ACIs matched', 0)
+ takes_options = (_prefix_option.clone_rename("aciprefix?", required=False),)
+
def execute(self, term, **kw):
ldap = self.api.Backend.ldap2
@@ -616,7 +659,15 @@ class aci_find(crud.Search):
if 'aciname' in kw:
for a in acis:
- if a.name != kw['aciname']:
+ prefix, name = _parse_aci_name(a.name)
+ if name != kw['aciname']:
+ results.remove(a)
+ acis = list(results)
+
+ if 'aciprefix' in kw:
+ for a in acis:
+ prefix, name = _parse_aci_name(a.name)
+ if prefix != kw['aciprefix']:
results.remove(a)
acis = list(results)
@@ -760,6 +811,8 @@ class aci_show(crud.Retrieve):
),
)
+ takes_options = (_prefix_option,)
+
def execute(self, aciname, **kw):
"""
Execute the aci-show operation.
@@ -775,7 +828,7 @@ class aci_show(crud.Retrieve):
acis = _convert_strings_to_acis(entry_attrs.get('aci', []))
- aci = _find_aci_by_name(acis, aciname)
+ aci = _find_aci_by_name(acis, kw['aciprefix'], aciname)
if kw.get('raw', False):
result = dict(aci=unicode(aci))
else:
@@ -800,12 +853,13 @@ class aci_rename(crud.Update):
)
takes_options = (
+ _prefix_option,
Str('newname',
doc=_('New ACI name'),
),
)
- msg_summary = _('Renameed ACI to "%(value)s"')
+ msg_summary = _('Renamed ACI to "%(value)s"')
def execute(self, aciname, **kw):
ldap = self.api.Backend.ldap2
@@ -813,10 +867,11 @@ class aci_rename(crud.Update):
(dn, entry_attrs) = ldap.get_entry(self.api.env.basedn, ['aci'])
acis = _convert_strings_to_acis(entry_attrs.get('aci', []))
- aci = _find_aci_by_name(acis, aciname)
+ aci = _find_aci_by_name(acis, kw['aciprefix'], aciname)
for a in acis:
- if kw['newname'] == a.name:
+ prefix, name = _parse_aci_name(a.name)
+ if _make_aci_name(prefix, kw['newname']) == a.name:
raise errors.DuplicateEntry()
# The strategy here is to convert the ACI we're updating back into
@@ -833,7 +888,7 @@ class aci_rename(crud.Update):
# Do this before we delete the existing ACI.
newaci = _make_aci(ldap, None, kw['newname'], newkw)
- self.api.Command['aci_del'](aciname)
+ self.api.Command['aci_del'](aciname, **kw)
result = self.api.Command['aci_add'](kw['newname'], **newkw)['result']