summaryrefslogtreecommitdiffstats
path: root/ipalib
diff options
context:
space:
mode:
Diffstat (limited to 'ipalib')
-rw-r--r--ipalib/plugins/aci.py95
-rw-r--r--ipalib/plugins/delegation.py9
-rw-r--r--ipalib/plugins/permission.py55
-rw-r--r--ipalib/plugins/selfservice.py16
4 files changed, 131 insertions, 44 deletions
diff --git a/ipalib/plugins/aci.py b/ipalib/plugins/aci.py
index 7f9b0f216..648f5111f 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']
diff --git a/ipalib/plugins/delegation.py b/ipalib/plugins/delegation.py
index 19d4c6da6..d5ff08a82 100644
--- a/ipalib/plugins/delegation.py
+++ b/ipalib/plugins/delegation.py
@@ -50,6 +50,8 @@ from ipalib import api, crud, errors
from ipalib import output
from ipalib import Object, Command
+ACI_PREFIX=u"delegation"
+
def convert_delegation(ldap, aci):
"""
memberOf is in filter but we want to pull out the group for easier
@@ -70,6 +72,7 @@ def convert_delegation(ldap, aci):
aci['membergroup'] = entry_attrs['cn']
del aci['filter']
+ del aci['aciprefix'] # do not include prefix in result
return aci
@@ -81,7 +84,7 @@ def is_delegation(ldap, aciname):
Return the result if it is a delegation ACI, adding a new attribute
membergroup.
"""
- result = api.Command['aci_show'](aciname)['result']
+ result = api.Command['aci_show'](aciname, aciprefix=ACI_PREFIX)['result']
if 'filter' in result:
result = convert_delegation(ldap, result)
else:
@@ -157,6 +160,7 @@ class delegation_add(crud.Create):
ldap = self.api.Backend.ldap2
if not 'permissions' in kw:
kw['permissions'] = (u'write',)
+ kw['aciprefix'] = ACI_PREFIX
result = api.Command['aci_add'](aciname, **kw)['result']
if 'filter' in result:
result = convert_delegation(ldap, result)
@@ -180,6 +184,7 @@ class delegation_del(crud.Delete):
def execute(self, aciname, **kw):
ldap = self.api.Backend.ldap2
is_delegation(ldap, aciname)
+ kw['aciprefix'] = ACI_PREFIX
result = api.Command['aci_del'](aciname, **kw)
return dict(
result=True,
@@ -199,6 +204,7 @@ class delegation_mod(crud.Update):
def execute(self, aciname, **kw):
ldap = self.api.Backend.ldap2
is_delegation(ldap, aciname)
+ kw['aciprefix'] = ACI_PREFIX
result = api.Command['aci_mod'](aciname, **kw)['result']
if 'filter' in result:
result = convert_delegation(ldap, result)
@@ -221,6 +227,7 @@ class delegation_find(crud.Search):
def execute(self, term, **kw):
ldap = self.api.Backend.ldap2
+ kw['aciprefix'] = ACI_PREFIX
acis = api.Command['aci_find'](term, **kw)['result']
results = []
for aci in acis:
diff --git a/ipalib/plugins/permission.py b/ipalib/plugins/permission.py
index 14d7b9656..0c2855ff5 100644
--- a/ipalib/plugins/permission.py
+++ b/ipalib/plugins/permission.py
@@ -61,7 +61,7 @@ EXAMPLES:
ipa permission-add --desc="Add a User" --type=user --permissions=add adduser
Add a permission that grants the ability to manage group membership:
- ipa permission-add --desc='Manage group members' --attrs=member --permissions=-write --type=group manage_group_members
+ ipa permission-add --desc='Manage group members' --attrs=member --permissions=write --type=group manage_group_members
"""
import copy
@@ -70,6 +70,7 @@ from ipalib import api, _, ngettext
from ipalib import Flag, Str, StrEnum
from ipalib.request import context
+ACI_PREFIX=u"permission"
class permission(LDAPObject):
"""
@@ -167,8 +168,9 @@ class permission_add(LDAPCreate):
del opts['description']
opts['test'] = True
opts['permission'] = keys[-1]
+ opts['aciprefix'] = ACI_PREFIX
try:
- self.api.Command.aci_add(options['description'], **opts)
+ self.api.Command.aci_add(keys[-1], **opts)
except Exception, e:
raise e
@@ -187,8 +189,9 @@ class permission_add(LDAPCreate):
del opts['description']
opts['test'] = False
opts['permission'] = keys[-1]
+ opts['aciprefix'] = ACI_PREFIX
try:
- result = self.api.Command.aci_add(options['description'], **opts)['result']
+ result = self.api.Command.aci_add(keys[-1], **opts)['result']
for attr in self.obj.aci_attributes:
if attr in result:
entry_attrs[attr] = result[attr]
@@ -204,7 +207,7 @@ class permission_add(LDAPCreate):
except Exception, ignore:
pass
try:
- self.api.Command.aci_del(keys[-1])
+ self.api.Command.aci_del(keys[-1], aciprefix=ACI_PREFIX)
except Exception, ignore:
pass
raise e
@@ -221,12 +224,11 @@ class permission_del(LDAPDelete):
msg_summary = _('Deleted permission "%(value)s"')
def pre_callback(self, ldap, dn, *keys, **options):
- (dn, entry_attrs) = ldap.get_entry(dn, ['*'])
- if 'description' in entry_attrs:
- try:
- self.api.Command.aci_del(entry_attrs['description'][0])
- except errors.NotFound:
- pass
+ # remove permission even when the underlying ACI is missing
+ try:
+ self.api.Command.aci_del(keys[-1], aciprefix=ACI_PREFIX)
+ except errors.NotFound:
+ pass
return dn
api.register(permission_del)
@@ -247,9 +249,7 @@ class permission_mod(LDAPUpdate):
except errors.NotFound:
self.obj.handle_not_found(*keys)
opts = copy.copy(options)
- if 'description' in opts:
- del opts['description']
- for o in ['all', 'raw', 'rights', 'description']:
+ for o in ['all', 'raw', 'rights', 'description', 'rename']:
if o in opts:
del opts[o]
setattr(context, 'aciupdate', False)
@@ -258,8 +258,9 @@ class permission_mod(LDAPUpdate):
if len(opts) > 0:
opts['test'] = False
opts['permission'] = keys[-1]
+ opts['aciprefix'] = ACI_PREFIX
try:
- self.api.Command.aci_mod(attrs['description'][0], **opts)
+ self.api.Command.aci_mod(keys[-1], **opts)
setattr(context, 'aciupdate', True)
except Exception, e:
raise e
@@ -271,10 +272,6 @@ class permission_mod(LDAPUpdate):
except:
pass
- if 'description' in options:
- if attrs['description'][0] != options['description']:
- self.api.Command.aci_rename(attrs['description'][0], newname=options['description'])
-
return dn
def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs):
@@ -294,6 +291,15 @@ class permission_mod(LDAPUpdate):
raise exc
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ # rename the underlying ACI after the change to permission
+ if 'rename' in options:
+ aciname = keys[-1] # ACI still refers to the old permission CN
+ self.api.Command.aci_mod(aciname,aciprefix=ACI_PREFIX,
+ permission=options['rename'])
+
+ self.api.Command.aci_rename(aciname, aciprefix=ACI_PREFIX,
+ newname=keys[-1], newprefix=ACI_PREFIX)
+
result = self.api.Command.permission_show(keys[-1])['result']
for r in result:
if not r.startswith('member'):
@@ -317,24 +323,29 @@ class permission_find(LDAPSearch):
for entry in entries:
(dn, attrs) = entry
try:
- aci = self.api.Command.aci_show(attrs['description'][0])['result']
+ aci = self.api.Command.aci_show(attrs['cn'][0], aciprefix=ACI_PREFIX)['result']
+
+ # copy information from respective ACI to permission entry
for attr in self.obj.aci_attributes:
if attr in aci:
attrs[attr] = aci[attr]
except errors.NotFound:
- self.debug('ACI not found for %s' % attrs['description'][0])
+ self.debug('ACI not found for %s' % attrs['cn'][0])
# Now find all the ACIs that match. Once we find them, add any that
# aren't already in the list along with their permission info.
+ options['aciprefix'] = ACI_PREFIX
+
aciresults = self.api.Command.aci_find(*args, **options)
truncated = truncated or aciresults['truncated']
results = aciresults['result']
+
for aci in results:
found = False
if 'permission' in aci:
for entry in entries:
(dn, attrs) = entry
- if aci['permission'] == attrs['cn']:
+ if aci['permission'] == attrs['cn'][0]:
found = True
break
if not found:
@@ -359,7 +370,7 @@ class permission_show(LDAPRetrieve):
"""
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
try:
- aci = self.api.Command.aci_show(entry_attrs['description'][0])['result']
+ aci = self.api.Command.aci_show(keys[-1], aciprefix=ACI_PREFIX)['result']
for attr in self.obj.aci_attributes:
if attr in aci:
entry_attrs[attr] = aci[attr]
diff --git a/ipalib/plugins/selfservice.py b/ipalib/plugins/selfservice.py
index adf6acb79..557304241 100644
--- a/ipalib/plugins/selfservice.py
+++ b/ipalib/plugins/selfservice.py
@@ -50,6 +50,8 @@ from ipalib import api, crud, errors
from ipalib import output
from ipalib import Object, Command
+ACI_PREFIX=u"selfservice"
+
def is_selfservice(aciname):
"""
Determine if the ACI is a Self-Service ACI and raise an exception if it
@@ -57,7 +59,7 @@ def is_selfservice(aciname):
Return the result if it is a self-service ACI.
"""
- result = api.Command['aci_show'](aciname)['result']
+ result = api.Command['aci_show'](aciname, aciprefix=ACI_PREFIX)['result']
if 'selfaci' not in result or result['selfaci'] == False:
raise errors.NotFound(reason=_('Self-service permission \'%(permission)s\' not found') % dict(permission=aciname))
return result
@@ -119,7 +121,9 @@ class selfservice_add(crud.Create):
if not 'permissions' in kw:
kw['permissions'] = (u'write',)
kw['selfaci'] = True
+ kw['aciprefix'] = ACI_PREFIX
result = api.Command['aci_add'](aciname, **kw)['result']
+ del result['aciprefix'] # do not include prefix in result
return dict(
result=result,
@@ -139,7 +143,9 @@ class selfservice_del(crud.Delete):
def execute(self, aciname, **kw):
is_selfservice(aciname)
+ kw['aciprefix'] = ACI_PREFIX
result = api.Command['aci_del'](aciname, **kw)
+
return dict(
result=True,
value=aciname,
@@ -159,7 +165,10 @@ class selfservice_mod(crud.Update):
is_selfservice(aciname)
if 'attrs' in kw and kw['attrs'] is None:
raise errors.RequirementError(name='attrs')
+
+ kw['aciprefix'] = ACI_PREFIX
result = api.Command['aci_mod'](aciname, **kw)['result']
+ del result['aciprefix'] # do not include prefix in result
return dict(
result=result,
value=aciname,
@@ -179,8 +188,12 @@ class selfservice_find(crud.Search):
def execute(self, term, **kw):
kw['selfaci'] = True
+ kw['aciprefix'] = ACI_PREFIX
result = api.Command['aci_find'](term, **kw)['result']
+ for aci in result:
+ del aci['aciprefix'] # do not include prefix in result
+
return dict(
result=result,
count=len(result),
@@ -202,6 +215,7 @@ class selfservice_show(crud.Retrieve):
def execute(self, aciname, **kw):
result = is_selfservice(aciname)
+ del result['aciprefix'] # do not include prefix in result
return dict(
result=result,
value=aciname,