On Wed, 2011-01-26 at 10:56 -0500, Rob Crittenden wrote:
> Dmitri Pal wrote:
> > Martin Kosek wrote:
> >> On Wed, 2011-01-26 at 10:20 -0500, Dmitri Pal wrote:
> >>
> >>> I took a quick look.
> >>>
> >>> Rob, I thought that there are different APIs for self and delegation. Is
> >>> this is the case?
> >>> ipa permission-... functions should never deal with self service or
> >>> delegation acis
> >>> They are just for the permission ACIs connected to the target groups.
> >>> I do not think this is the right approach.
> >>> The prefix is need but it should be automatically added if you use this
> >>> interface.
> >>>
> >>
> >> Well, this patch ensures that permission-* functions will not deal with
> >> selfservice od delegation ACIs. Each of these plugins has its own prefix
> >> (e.g. "permission:" or "delegation:") which is added to the underlying
> >> ACI name.
> >>
> >> Because of this, the Permission, Selfservice and Delegation plugins work
> >> only with ACIs with "their" prefix. Prefix is not visible for user, it
> >> is passed to ACI functions automatically by Permission, Delegation and
> >> Selfservice plugins.
> >>
> >>
> >
> >
> >    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
> > +   ipa permission-add  --permissions=add 
> > --subtree="cn=*,cn=orange,cn=accounts,dc=example,dc=com" --desc="Add Orange 
> > Entries" --prefix=none add_orange
> >
> > This change exposes the prefix on the command line which means you can
> > manage ACIs with different prefixes.
> > Do i misread it?
> 
> The help changes are unneeded. The prefix is not configurable by the user.
> 
> rob

Ah, now I see the source of confusion. My bad. I fixed help in ACI
plugin (even though this plugin is not visible for CLI). There were
examples for using aci-add command and I wanted to add a new mandatory
parameter here, so that user is not prompted for it.

Unfortunately, I didn't notice there was one permission-add example -
--prefix attribute is not valid for this command. A patch #2 with fixed
permission-add example + rebase to current master is attached.

Martin
>From 2cc286d32f4fa63ac584851a9dc1834eb9fe0c19 Mon Sep 17 00:00:00 2001
From: Martin Kosek <mko...@redhat.com>
Date: Fri, 21 Jan 2011 09:20:01 +0100
Subject: [PATCH] ACI plugin supports prefixes

When more than one plugin produce ACIs, they share common namespace
of ACI name. This may lead to name collisions between the ACIs
from different plugins.

This patch introduces a mandatory "prefix" attribute for non-find
ACI operations which allow plugins to use their own prefixes
(i.e. namespaces) which is then used when a name of the ACI is
generated.

Permission, Delegation and Selfservice plugins has been updated
to use their own prefixes thus avoiding name collisions by using
their own namespaces. Default ACIs in LDIFs has been updated to
follow this new policy.

Permission plugin now uses its CN (=primary key) instead of
description in ACI names as Description may not be unique.

This change requires an IPA server reinstall since the default ACI
set has been changed.

https://fedorahosted.org/freeipa/ticket/764
---
 install/share/default-aci.ldif  |    2 +-
 install/share/delegation.ldif   |   88 ++++++++++++++++++------------------
 install/share/replica-acis.ldif |    6 +-
 ipalib/plugins/aci.py           |   95 ++++++++++++++++++++++++++++++--------
 ipalib/plugins/delegation.py    |    9 +++-
 ipalib/plugins/permission.py    |   55 +++++++++++++---------
 ipalib/plugins/selfservice.py   |   16 ++++++-
 7 files changed, 179 insertions(+), 92 deletions(-)

diff --git a/install/share/default-aci.ldif b/install/share/default-aci.ldif
index 945b0bb316b0c54cf8f1da066ea6ad6ec865c3d6..8b00f46097bdaaa8c44e9603bb93b0552b34f816 100644
--- a/install/share/default-aci.ldif
+++ b/install/share/default-aci.ldif
@@ -6,7 +6,7 @@ add: aci
 aci: (targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey")(version 3.0; acl "Enable Anonymous access"; allow (read, search, compare) userdn = "ldap:///anyone";;)
 aci: (targetattr = "memberOf || memberHost || memberUser")(version 3.0; acl "No anonymous access to member information"; deny (read,search,compare) userdn != "ldap:///all";;)
 aci: (targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey || krbPrincipalName || krbCanonicalName || krbUPEnabled || krbTicketPolicyReference || krbPrincipalExpiration || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData || krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount || krbTicketFlags || ipaUniqueId || memberOf || serverHostName || enrolledBy")(version 3.0; acl "Admin can manage any entry"; allow (all) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";;)
-aci: (targetattr = "userpassword || krbprincipalkey || sambalmpassword || sambantpassword")(version 3.0; acl "Self can write own password"; allow (write) userdn="ldap:///self";;)
+aci: (targetattr = "userpassword || krbprincipalkey || sambalmpassword || sambantpassword")(version 3.0; acl "selfservice:Self can write own password"; allow (write) userdn="ldap:///self";;)
 aci: (targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Admins can write passwords"; allow (add,delete,write) groupdn="ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";;)
 aci: (targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Password change service can read/write passwords"; allow (read, write) userdn="ldap:///krbprincipalname=kadmin/changepw@$REALM,cn=$REALM,cn=kerberos,$SUFFIX";;)
 aci: (targetattr = "userPassword || krbPrincipalKey || krbPasswordExpiration || sambaLMPassword || sambaNTPassword || passwordHistory || krbExtraData")(version 3.0; acl "KDC System Account can access passwords"; allow (all) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";;)
diff --git a/install/share/delegation.ldif b/install/share/delegation.ldif
index 9a96365d53d9b39f122fe0b6b80adfa4b3e45615..415d3090b75b0b72904b7cc6a702d1ca2d6c50c2 100644
--- a/install/share/delegation.ldif
+++ b/install/share/delegation.ldif
@@ -507,51 +507,51 @@ member: cn=entitlementadmin,cn=privileges,cn=pbac,$SUFFIX
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX";)(version 3.0;acl "Add Users";allow (add) groupdn = "ldap:///cn=addusers,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX";)(targetattr = "userpassword || krbprincipalkey || sambalmpassword || sambantpassword || passwordhistory")(version 3.0;acl "Change a user password";allow (write) groupdn = "ldap:///cn=change_password,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (targetattr = "member")(target = "ldap:///cn=ipausers,cn=groups,cn=accounts,$SUFFIX";)(version 3.0;acl "Add user to default group";allow (write) groupdn = "ldap:///cn=add_user_to_default_group,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX";)(version 3.0;acl "Remove Users";allow (delete) groupdn = "ldap:///cn=removeusers,cn=permissions,cn=pbac,$SUFFIX";;)
-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 || mepmanagedentry || objectclass")(target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX";)(version 3.0;acl "Modify Users";allow (write) groupdn = "ldap:///cn=modifyusers,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:addusers";allow (add) groupdn = "ldap:///cn=addusers,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX";)(targetattr = "userpassword || krbprincipalkey || sambalmpassword || sambantpassword || passwordhistory")(version 3.0;acl "permission:change_password";allow (write) groupdn = "ldap:///cn=change_password,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "member")(target = "ldap:///cn=ipausers,cn=groups,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:add_user_to_default_group";allow (write) groupdn = "ldap:///cn=add_user_to_default_group,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:removeusers";allow (delete) groupdn = "ldap:///cn=removeusers,cn=permissions,cn=pbac,$SUFFIX";;)
+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 || mepmanagedentry || objectclass")(target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:modifyusers";allow (write) groupdn = "ldap:///cn=modifyusers,cn=permissions,cn=pbac,$SUFFIX";;)
 
 # Group administration
 
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (target = "ldap:///cn=*,cn=groups,cn=accounts,$SUFFIX";)(version 3.0;acl "Add Groups";allow (add) groupdn = "ldap:///cn=addgroups,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (targetattr = "member")(target = "ldap:///cn=*,cn=groups,cn=accounts,$SUFFIX";)(version 3.0;acl "Modify group membership";allow (write) groupdn = "ldap:///cn=modifygroupmembership,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (target = "ldap:///cn=*,cn=groups,cn=accounts,$SUFFIX";)(version 3.0;acl "Remove Groups";allow (delete) groupdn = "ldap:///cn=removegroups,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (target = "ldap:///cn=*,cn=groups,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:addgroups";allow (add) groupdn = "ldap:///cn=addgroups,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "member")(target = "ldap:///cn=*,cn=groups,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:modifygroupmembership";allow (write) groupdn = "ldap:///cn=modifygroupmembership,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (target = "ldap:///cn=*,cn=groups,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:removegroups";allow (delete) groupdn = "ldap:///cn=removegroups,cn=permissions,cn=pbac,$SUFFIX";;)
 # We need objectclass and gidnumber in modify so a non-posix group can be
 # promoted. We need mqpManagedBy and ipaUniqueId so a group can be detached.
-aci: (targetattr = "cn || description || gidnumber || objectclass || mepmanagedby || ipauniqueid")(target = "ldap:///cn=*,cn=groups,cn=accounts,$SUFFIX";)(version 3.0;acl "Modify Groups";allow (write) groupdn = "ldap:///cn=modifygroups,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "cn || description || gidnumber || objectclass || mepmanagedby || ipauniqueid")(target = "ldap:///cn=*,cn=groups,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:modifygroups";allow (write) groupdn = "ldap:///cn=modifygroups,cn=permissions,cn=pbac,$SUFFIX";;)
 
 # Host administration
 
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX";)(version 3.0;acl "Add Hosts";allow (add) groupdn = "ldap:///cn=addhosts,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX";)(version 3.0;acl "Remove Hosts";allow (delete) groupdn = "ldap:///cn=removehosts,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (targetattr = "description || l || nshostlocation || nshardwareplatform || nsosversion")(target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX";)(version 3.0;acl "Modify Hosts";allow (write) groupdn = "ldap:///cn=modifyhosts,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:addhosts";allow (add) groupdn = "ldap:///cn=addhosts,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:removehosts";allow (delete) groupdn = "ldap:///cn=removehosts,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "description || l || nshostlocation || nshardwareplatform || nsosversion")(target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:modifyhosts";allow (write) groupdn = "ldap:///cn=modifyhosts,cn=permissions,cn=pbac,$SUFFIX";;)
 
 # Hostgroup administration
 
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (target = "ldap:///cn=*,cn=hostgroups,cn=accounts,$SUFFIX";)(version 3.0;acl "Add Hostgroups";allow (add) groupdn = "ldap:///cn=addhostgroups,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (target = "ldap:///cn=*,cn=hostgroups,cn=accounts,$SUFFIX";)(version 3.0;acl "Remove Hostgroups";allow (delete) groupdn = "ldap:///cn=removehostgroups,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (targetattr = "cn || description")(target = "ldap:///cn=*,cn=hostgroups,cn=accounts,$SUFFIX";)(version 3.0; acl "Modify Hostgroups";allow (write) groupdn = "ldap:///cn=modifyhostgroups,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (targetattr = "member")(target = "ldap:///cn=*,cn=hostgroups,cn=accounts,$SUFFIX";)(version 3.0;acl "Modify Hostgroup membership";allow (write) groupdn = "ldap:///cn=modifyhostgroupmembership,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (target = "ldap:///cn=*,cn=hostgroups,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:addhostgroups";allow (add) groupdn = "ldap:///cn=addhostgroups,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (target = "ldap:///cn=*,cn=hostgroups,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:removehostgroups";allow (delete) groupdn = "ldap:///cn=removehostgroups,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "cn || description")(target = "ldap:///cn=*,cn=hostgroups,cn=accounts,$SUFFIX";)(version 3.0; acl "permission:modifyhostgroups";allow (write) groupdn = "ldap:///cn=modifyhostgroups,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "member")(target = "ldap:///cn=*,cn=hostgroups,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:modifyhostgroupmembership";allow (write) groupdn = "ldap:///cn=modifyhostgroupmembership,cn=permissions,cn=pbac,$SUFFIX";;)
 
 # Service administration
 
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (target = "ldap:///krbprincipalname=*,cn=services,cn=accounts,$SUFFIX";)(version 3.0;acl "Add Services";allow (add) groupdn = "ldap:///cn=addservices,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (target = "ldap:///krbprincipalname=*,cn=services,cn=accounts,$SUFFIX";)(version 3.0;acl "Remove Services";allow (delete) groupdn = "ldap:///cn=removeservices,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (targetattr = "usercertificate")(target = "ldap:///krbprincipalname=*,cn=services,cn=accounts,$SUFFIX";)(version 3.0;acl "Modify Services";allow (write) groupdn = "ldap:///cn=modifyservices,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (target = "ldap:///krbprincipalname=*,cn=services,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:addservices";allow (add) groupdn = "ldap:///cn=addservices,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (target = "ldap:///krbprincipalname=*,cn=services,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:removeservices";allow (delete) groupdn = "ldap:///cn=removeservices,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "usercertificate")(target = "ldap:///krbprincipalname=*,cn=services,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:modifyservices";allow (write) groupdn = "ldap:///cn=modifyservices,cn=permissions,cn=pbac,$SUFFIX";;)
 
 # Delegation administration
 
@@ -563,45 +563,45 @@ aci: (targetattr = "*")(target = "ldap:///cn=*,cn=roles,cn=accounts,$SUFFIX";)(ve
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (target = "ldap:///cn=*,cn=roles,cn=accounts,$SUFFIX";)(version 3.0;acl "Add Roles";allow (add) groupdn = "ldap:///cn=addroles,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (target = "ldap:///cn=*,cn=roles,cn=accounts,$SUFFIX";)(version 3.0;acl "Remove Roles";allow (delete) groupdn = "ldap:///cn=removeroles,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (targetattr = "cn || description")(target = "ldap:///cn=*,cn=roles,cn=accounts,$SUFFIX";)(version 3.0; acl "Modify Roles";allow (write) groupdn = "ldap:///cn=modifyroles,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (targetattr = "member")(target = "ldap:///cn=*,cn=roles,cn=accounts,$SUFFIX";)(version 3.0;acl "Modify role group membership";allow (write) groupdn = "ldap:///cn=modifyrolemembership,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (targetattr = "member")(target = "ldap:///cn=*,cn=permissions,cn=pbac,$SUFFIX";)(version 3.0;acl "Modify privilege membership";allow (write) groupdn = "ldap:///cn=modifyprivilegemembership,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (target = "ldap:///cn=*,cn=roles,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:addroles";allow (add) groupdn = "ldap:///cn=addroles,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (target = "ldap:///cn=*,cn=roles,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:removeroles";allow (delete) groupdn = "ldap:///cn=removeroles,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "cn || description")(target = "ldap:///cn=*,cn=roles,cn=accounts,$SUFFIX";)(version 3.0; acl "permission:modifyroles";allow (write) groupdn = "ldap:///cn=modifyroles,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "member")(target = "ldap:///cn=*,cn=roles,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:modifyrolemembership";allow (write) groupdn = "ldap:///cn=modifyrolemembership,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "member")(target = "ldap:///cn=*,cn=permissions,cn=pbac,$SUFFIX";)(version 3.0;acl "permission:modifyprivilegemembership";allow (write) groupdn = "ldap:///cn=modifyprivilegemembership,cn=permissions,cn=pbac,$SUFFIX";;)
 
 # Automount administration
 
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (target = "ldap:///automountmapname=*,cn=automount,$SUFFIX";)(version 3.0;acl "Add Automount maps";allow (add) groupdn = "ldap:///cn=addautomountmaps,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (target = "ldap:///automountmapname=*,cn=automount,$SUFFIX";)(version 3.0;acl "Remove automount maps";allow (delete) groupdn = "ldap:///cn=removeautomountmaps,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (target = "ldap:///automountkey=*,automountmapname=*,cn=automount,$SUFFIX";)(version 3.0;acl "Add automount keys";allow (add) groupdn = "ldap:///cn=addautomountkeys,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (target = "ldap:///automountkey=*,automountmapname=*,cn=automount,$SUFFIX";)(version 3.0;acl "Remove automount keys";allow (delete) groupdn = "ldap:///cn=removeautomountkeys,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (target = "ldap:///automountmapname=*,cn=automount,$SUFFIX";)(version 3.0;acl "permission:addautomountmaps";allow (add) groupdn = "ldap:///cn=addautomountmaps,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (target = "ldap:///automountmapname=*,cn=automount,$SUFFIX";)(version 3.0;acl "permission:removeautomountmaps";allow (delete) groupdn = "ldap:///cn=removeautomountmaps,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (target = "ldap:///automountkey=*,automountmapname=*,cn=automount,$SUFFIX";)(version 3.0;acl "permission:addautomountkeys";allow (add) groupdn = "ldap:///cn=addautomountkeys,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (target = "ldap:///automountkey=*,automountmapname=*,cn=automount,$SUFFIX";)(version 3.0;acl "permission:removeautomountkeys";allow (delete) groupdn = "ldap:///cn=removeautomountkeys,cn=permissions,cn=pbac,$SUFFIX";;)
 
 # Netgroup administration
 
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (target = "ldap:///ipauniqueid=*,cn=ng,cn=alt,$SUFFIX";)(version 3.0;acl "Add netgroups";allow (add) groupdn = "ldap:///cn=addnetgroups,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (target = "ldap:///ipauniqueid=*,cn=ng,cn=alt,$SUFFIX";)(version 3.0;acl "Remove netgroups";allow (delete) groupdn = "ldap:///cn=removenetgroups,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (targetattr = "description")(target = "ldap:///ipauniqueid=*,cn=ng,cn=alt,$SUFFIX";)(version 3.0; acl "Modify netgroups";allow (write) groupdn = "ldap:///cn=modifynetgroups,cn=permissions,cn=pbac,$SUFFIX";;)
-aci: (targetattr = "memberhost || externalhost || memberuser || member")(target = "ldap:///ipauniqueid=*,cn=ng,cn=alt,$SUFFIX";)(version 3.0;acl "Modify netgroup membership";allow (write) groupdn = "ldap:///cn=modifynetgroupmembership,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (target = "ldap:///ipauniqueid=*,cn=ng,cn=alt,$SUFFIX";)(version 3.0;acl "permission:addnetgroups";allow (add) groupdn = "ldap:///cn=addnetgroups,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (target = "ldap:///ipauniqueid=*,cn=ng,cn=alt,$SUFFIX";)(version 3.0;acl "permission:removenetgroups";allow (delete) groupdn = "ldap:///cn=removenetgroups,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "description")(target = "ldap:///ipauniqueid=*,cn=ng,cn=alt,$SUFFIX";)(version 3.0; acl "permission:modifynetgroups";allow (write) groupdn = "ldap:///cn=modifynetgroups,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "memberhost || externalhost || memberuser || member")(target = "ldap:///ipauniqueid=*,cn=ng,cn=alt,$SUFFIX";)(version 3.0;acl "permission:modifynetgroupmembership";allow (write) groupdn = "ldap:///cn=modifynetgroupmembership,cn=permissions,cn=pbac,$SUFFIX";;)
 
 # Host keytab admin
 
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (targetattr = "krbprincipalkey || krblastpwdchange")(target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX";)(version 3.0;acl "Manage host keytab";allow (write) groupdn = "ldap:///cn=manage_host_keytab,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "krbprincipalkey || krblastpwdchange")(target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:manage_host_keytab";allow (write) groupdn = "ldap:///cn=manage_host_keytab,cn=permissions,cn=pbac,$SUFFIX";;)
 
 # Service keytab admin
 
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (targetattr = "krbprincipalkey || krblastpwdchange")(target = "ldap:///krbprincipalname=*,cn=services,cn=accounts,$SUFFIX";)(version 3.0;acl "Manage service keytab";allow (write) groupdn = "ldap:///cn=manage_service_keytab,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "krbprincipalkey || krblastpwdchange")(target = "ldap:///krbprincipalname=*,cn=services,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:manage_service_keytab";allow (write) groupdn = "ldap:///cn=manage_service_keytab,cn=permissions,cn=pbac,$SUFFIX";;)
 
 # Add the ACI needed to do host enrollment. When this occurs we
 # set the krbPrincipalName, add krbPrincipalAux to objectClass and
@@ -610,24 +610,24 @@ aci: (targetattr = "krbprincipalkey || krblastpwdchange")(target = "ldap:///krbp
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (targetattr = "enrolledby || objectclass")(target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX";)(version 3.0;acl "Enroll a host";allow (write) groupdn = "ldap:///cn=enroll_host,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "enrolledby || objectclass")(target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX";)(version 3.0;acl "permission:enroll_host";allow (write) groupdn = "ldap:///cn=enroll_host,cn=permissions,cn=pbac,$SUFFIX";;)
 
 # Entitlement administration
 
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (target = "ldap:///ipauniqueid=*,cn=entitlements,cn=etc,$SUFFIX";)(version 3.0;acl "Add Entitlements";allow (add) groupdn = "ldap:///cn=addentitlements,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (target = "ldap:///ipauniqueid=*,cn=entitlements,cn=etc,$SUFFIX";)(version 3.0;acl "permission:addentitlements";allow (add) groupdn = "ldap:///cn=addentitlements,cn=permissions,cn=pbac,$SUFFIX";;)
 
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (targetattr = "usercertificate")(target = "ldap:///ipauniqueid=*,cn=entitlements,cn=etc,$SUFFIX";)(version 3.0;acl "Modify Entitlements";allow (write) groupdn = "ldap:///cn=modifyentitlements,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "usercertificate")(target = "ldap:///ipauniqueid=*,cn=entitlements,cn=etc,$SUFFIX";)(version 3.0;acl "permission:modifyentitlements";allow (write) groupdn = "ldap:///cn=modifyentitlements,cn=permissions,cn=pbac,$SUFFIX";;)
 
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (target = "ldap:///ipauniqueid=*,cn=entitlements,cn=etc,$SUFFIX";)(version 3.0;acl "Remove Entitlements";allow (delete) groupdn = "ldap:///cn=removeentitlements,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (target = "ldap:///ipauniqueid=*,cn=entitlements,cn=etc,$SUFFIX";)(version 3.0;acl "permission:removeentitlements";allow (delete) groupdn = "ldap:///cn=removeentitlements,cn=permissions,cn=pbac,$SUFFIX";;)
 
 # Create virtual operations entry. This is used to control access to
 # operations that don't rely on LDAP directly.
@@ -655,7 +655,7 @@ member: cn=certadmin,cn=privileges,cn=pbac,$SUFFIX
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (targetattr = "objectclass")(target = "ldap:///cn=retrieve certificate,cn=virtual operations,cn=etc,$SUFFIX" )(version 3.0 ; acl "Retrieve Certificates from the CA" ; allow (write) groupdn = "ldap:///cn=retrieve_certs,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "objectclass")(target = "ldap:///cn=retrieve certificate,cn=virtual operations,cn=etc,$SUFFIX" )(version 3.0 ; acl "permission:retrieve_certs" ; allow (write) groupdn = "ldap:///cn=retrieve_certs,cn=permissions,cn=pbac,$SUFFIX";;)
 
 # Request Certificate virtual op
 dn: cn=request certificate,cn=virtual operations,cn=etc,$SUFFIX
@@ -675,7 +675,7 @@ member: cn=certadmin,cn=privileges,cn=pbac,$SUFFIX
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (targetattr = "objectclass")(target = "ldap:///cn=request certificate,cn=virtual operations,cn=etc,$SUFFIX" )(version 3.0 ; acl "Request Certificates from the CA" ; allow (write) groupdn = "ldap:///cn=request_certs,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "objectclass")(target = "ldap:///cn=request certificate,cn=virtual operations,cn=etc,$SUFFIX" )(version 3.0 ; acl "permission:request_certs" ; allow (write) groupdn = "ldap:///cn=request_certs,cn=permissions,cn=pbac,$SUFFIX";;)
 
 # Request Certificate from different host virtual op
 dn: cn=request certificate different host,cn=virtual operations,cn=etc,$SUFFIX
@@ -695,7 +695,7 @@ member: cn=certadmin,cn=privileges,cn=pbac,$SUFFIX
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (targetattr = "objectclass")(target = "ldap:///cn=request certificate different host,cn=virtual operations,cn=etc,$SUFFIX" )(version 3.0 ; acl "Request Certificates from a different host" ; allow (write) groupdn = "ldap:///cn=request_cert_different_host,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "objectclass")(target = "ldap:///cn=request certificate different host,cn=virtual operations,cn=etc,$SUFFIX" )(version 3.0 ; acl "permission:request_cert_different_host" ; allow (write) groupdn = "ldap:///cn=request_cert_different_host,cn=permissions,cn=pbac,$SUFFIX";;)
 
 # Certificate Status virtual op
 dn: cn=certificate status,cn=virtual operations,cn=etc,$SUFFIX
@@ -715,7 +715,7 @@ member: cn=certadmin,cn=privileges,cn=pbac,$SUFFIX
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (targetattr = "objectclass")(target = "ldap:///cn=certificate status,cn=virtual operations,cn=etc,$SUFFIX" )(version 3.0 ; acl "Get Certificates status from the CA" ; allow (write) groupdn = "ldap:///cn=certificate_status,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "objectclass")(target = "ldap:///cn=certificate status,cn=virtual operations,cn=etc,$SUFFIX" )(version 3.0 ; acl "permission:certificate_status" ; allow (write) groupdn = "ldap:///cn=certificate_status,cn=permissions,cn=pbac,$SUFFIX";;)
 
 # Revoke Certificate virtual op
 dn: cn=revoke certificate,cn=virtual operations,cn=etc,$SUFFIX
@@ -735,7 +735,7 @@ member: cn=certadmin,cn=privileges,cn=pbac,$SUFFIX
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (targetattr = "objectclass")(target = "ldap:///cn=revoke certificate,cn=virtual operations,cn=etc,$SUFFIX" )(version 3.0 ; acl "Revoke Certificate"; allow (write) groupdn = "ldap:///cn=revoke_certificate,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "objectclass")(target = "ldap:///cn=revoke certificate,cn=virtual operations,cn=etc,$SUFFIX" )(version 3.0 ; acl "permission:revoke_certificate"; allow (write) groupdn = "ldap:///cn=revoke_certificate,cn=permissions,cn=pbac,$SUFFIX";;)
 
 # Certificate Remove Hold virtual op
 dn: cn=certificate remove hold,cn=virtual operations,cn=etc,$SUFFIX
@@ -755,4 +755,4 @@ member: cn=certadmin,cn=privileges,cn=pbac,$SUFFIX
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (targetattr = "objectclass")(target = "ldap:///cn=certificate remove hold,cn=virtual operations,cn=etc,$SUFFIX" )(version 3.0 ; acl "Certificate Remove Hold"; allow (write) groupdn = "ldap:///cn=certificate_remove_hold,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr = "objectclass")(target = "ldap:///cn=certificate remove hold,cn=virtual operations,cn=etc,$SUFFIX" )(version 3.0 ; acl "permission:certificate_remove_hold"; allow (write) groupdn = "ldap:///cn=certificate_remove_hold,cn=permissions,cn=pbac,$SUFFIX";;)
diff --git a/install/share/replica-acis.ldif b/install/share/replica-acis.ldif
index 2acbd92dc45b403a180d32105e17986779c7582d..49d6b75c9d8f7be2e40d5f77fe5f3379e2e94e52 100644
--- a/install/share/replica-acis.ldif
+++ b/install/share/replica-acis.ldif
@@ -3,17 +3,17 @@
 dn: cn="$SUFFIX",cn=mapping tree,cn=config
 changetype: modify
 add: aci
-aci: (targetattr=*)(version 3.0;acl "Add Replication Agreements";allow (add) groupdn = "ldap:///cn=addreplica,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr=*)(version 3.0;acl "permission:addreplica";allow (add) groupdn = "ldap:///cn=addreplica,cn=permissions,cn=pbac,$SUFFIX";;)
 
 dn: cn="$SUFFIX",cn=mapping tree,cn=config
 changetype: modify
 add: aci
-aci: (targetattr=*)(targetfilter="(|(objectclass=nsds5Replica)(objectclass=nsds5replicationagreement)(objectclass=nsDSWindowsReplicationAgreement)(objectClass=nsMappingTree))")(version 3.0; acl "Modify Replication Agreements"; allow (read, write, search) groupdn = "ldap:///cn=modifyreplica,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr=*)(targetfilter="(|(objectclass=nsds5Replica)(objectclass=nsds5replicationagreement)(objectclass=nsDSWindowsReplicationAgreement)(objectClass=nsMappingTree))")(version 3.0; acl "permission:modifyreplica"; allow (read, write, search) groupdn = "ldap:///cn=modifyreplica,cn=permissions,cn=pbac,$SUFFIX";;)
 
 dn: cn="$SUFFIX",cn=mapping tree,cn=config
 changetype: modify
 add: aci
-aci: (targetattr=*)(targetfilter="(|(objectclass=nsds5replicationagreement)(objectclass=nsDSWindowsReplicationAgreement))")(version 3.0;acl "Remove Replication Agreements";allow (delete) groupdn = "ldap:///cn=removereplica,cn=permissions,cn=pbac,$SUFFIX";;)
+aci: (targetattr=*)(targetfilter="(|(objectclass=nsds5replicationagreement)(objectclass=nsDSWindowsReplicationAgreement))")(version 3.0;acl "permission:removereplica";allow (delete) groupdn = "ldap:///cn=removereplica,cn=permissions,cn=pbac,$SUFFIX";;)
 
 dn: cn=tasks,cn=config
 changetype: modify
diff --git a/ipalib/plugins/aci.py b/ipalib/plugins/aci.py
index 7f9b0f2168ee0c64a72367ea601526e96aa00dbe..648f5111fcfd23975fe317d6b89b6163508a15a3 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 19d4c6da6a5bc70599732caa9b6f4144df80ebf4..d5ff08a82a9e38c410b1fe161166f152a8bd5e66 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 14d7b96569cc9e228bebaac37d67d6709039e164..0c2855ff5c181a56455bb9b180b6f22472ce8fa4 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 adf6acb7927444515d59a03bcf311c39c3c53792..557304241ae6c2c569aa8a30a61c8c771d3119bd 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,
-- 
1.7.3.5

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to