ldap/schema/02common.ldif | 3 +
ldap/servers/plugins/roles/roles_cache.c | 58 +++++++++++++++++++++++++++----
ldap/servers/plugins/roles/roles_cache.h | 2 +
3 files changed, 55 insertions(+), 8 deletions(-)
New commits:
commit 839c46c8124e6dabc40b568dc90968db9761cf98
Author: Thierry bordaz (tbordaz) <tbordaz(a)redhat.com>
Date: Fri Jun 28 14:30:59 2013 +0200
Ticket 208 - [RFE] Roles with explicit scoping in RHDS
Bug Description:
A limitation of the application using the role mechanism is that the scope of a role
is the subtree where the role is defined.
That means the role definitions are often mixed with the entries they are dealing
with.
Usually configuration info are seperated from the data. This RFE aims to separate
the
role definitions from the DIT subtree where are stored the entries
Fix Description:
This RFE introduces a new configuration attribute 'nsRoleScopeDN' in the role
definition.
This attribute specifies the subtree where the role apply.
See
http://directory.fedoraproject.org/wiki/Creation_of_an_explicit_scoping_f...
https://fedorahosted.org/389/ticket/208
Reviewed by: Noriko Hosoi (thanks Noriko !)
Platforms tested: Fedora 17
Flag Day: no
Doc impact: yes
A role definition (entry with Objectclass=nsRoleDefinition), may contain an optional
single valued attribute
'nsRoleScopeDN'.
In that case, the role does not apply to the subtree where it is defined but to the
subtree referred by 'nsRoleScopeDN'.
'nsRoleScopeDN' is a DN syntax attribute. To be taken into account, its value
must be a subtree under the suffix
where the role is defined.
If not present or with invalid value, the role will apply to the subtree where it is
defined.
diff --git a/ldap/schema/02common.ldif b/ldap/schema/02common.ldif
index fa604c6..b67ec8d 100644
--- a/ldap/schema/02common.ldif
+++ b/ldap/schema/02common.ldif
@@ -146,6 +146,7 @@ attributeTypes: ( 2.16.840.1.113730.3.1.1004 NAME
'nsds7WindowsDomain' DESC 'Net
attributeTypes: ( 2.16.840.1.113730.3.1.1005 NAME 'nsds7DirsyncCookie' DESC
'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5
SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
attributeTypes: ( 2.16.840.1.113730.3.1.1099 NAME 'winSyncInterval' DESC
'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
attributeTypes: ( 2.16.840.1.113730.3.1.1100 NAME 'oneWaySync' DESC 'Netscape
defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN
'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.1101 NAME 'nsRoleScopeDN' DESC 'Scope
of a role' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN '389
Directory Server' )
attributeTypes: ( 2.16.840.1.113730.3.1.2139 NAME 'winSyncMoveAction' DESC
'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
attributeTypes: ( 1.3.6.1.1.4 NAME 'vendorName' EQUALITY
1.3.6.1.4.1.1466.109.114.1 SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE
NO-USER-MODIFICATION USAGE dSAOperation X-ORIGIN 'RFC 3045' )
attributeTypes: ( 1.3.6.1.1.5 NAME 'vendorVersion' EQUALITY
1.3.6.1.4.1.1466.109.114.1 SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE
NO-USER-MODIFICATION USAGE dSAOperation X-ORIGIN 'RFC 3045' )
@@ -171,7 +172,7 @@ objectClasses: ( 2.16.840.1.113730.3.2.32 NAME
'netscapeMachineData' DESC 'Netsc
objectClasses: ( 2.16.840.1.113730.3.2.38 NAME 'vlvSearch' DESC 'Netscape
defined objectclass' SUP top MUST ( cn $ vlvBase $ vlvScope $ vlvFilter ) MAY (
multiLineDescription ) X-ORIGIN 'Netscape Directory Server' )
objectClasses: ( 2.16.840.1.113730.3.2.42 NAME 'vlvIndex' DESC 'Netscape
defined objectclass' SUP top MUST ( cn $ vlvSort ) MAY ( vlvEnabled $ vlvUses )
X-ORIGIN 'Netscape Directory Server' )
objectClasses: ( 2.16.840.1.113730.3.2.84 NAME 'cosDefinition' DESC 'Netscape
defined objectclass' SUP top MAY ( costargettree $ costemplatedn $ cosspecifier $
cosattribute $ aci $ cn $ uid ) X-ORIGIN 'Netscape Directory Server' )
-objectClasses: ( 2.16.840.1.113730.3.2.93 NAME 'nsRoleDefinition' DESC
'Netscape defined objectclass' SUP ldapSubEntry MAY ( description ) X-ORIGIN
'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.93 NAME 'nsRoleDefinition' DESC
'Netscape defined objectclass' SUP ldapSubEntry MAY ( description $ nsRoleScopeDN
) X-ORIGIN 'Netscape Directory Server' )
objectClasses: ( 2.16.840.1.113730.3.2.94 NAME 'nsSimpleRoleDefinition' DESC
'Netscape defined objectclass' SUP nsRoleDefinition X-ORIGIN 'Netscape
Directory Server' )
objectClasses: ( 2.16.840.1.113730.3.2.95 NAME 'nsComplexRoleDefinition' DESC
'Netscape defined objectclass' SUP nsRoleDefinition X-ORIGIN 'Netscape
Directory Server' )
objectClasses: ( 2.16.840.1.113730.3.2.96 NAME 'nsManagedRoleDefinition' DESC
'Netscape defined objectclass' SUP nsSimpleRoleDefinition X-ORIGIN 'Netscape
Directory Server' )
diff --git a/ldap/servers/plugins/roles/roles_cache.c
b/ldap/servers/plugins/roles/roles_cache.c
index 89acc59..664ced1 100644
--- a/ldap/servers/plugins/roles/roles_cache.c
+++ b/ldap/servers/plugins/roles/roles_cache.c
@@ -88,6 +88,7 @@ typedef struct _role_object_nested {
/* Role object structure */
typedef struct _role_object {
Slapi_DN *dn; /* dn of a role entry */
+ Slapi_DN *rolescopedn; /* if set, this role will apply to any entry in the scope of
this dn */
int type; /* ROLE_TYPE_MANAGED|ROLE_TYPE_FILTERED|ROLE_TYPE_NESTED */
Slapi_Filter *filter; /* if ROLE_TYPE_FILTERED */
Avlnode *avl_tree; /* if ROLE_TYPE_NESTED: tree of nested DNs (avl_data is a
role_object_nested struct) */
@@ -181,7 +182,7 @@ static int roles_is_entry_member_of_object_ext(vattr_context *c,
caddr_t data, c
static int roles_check_managed(Slapi_Entry *entry_to_check, role_object *role, int
*present);
static int roles_check_filtered(vattr_context *c, Slapi_Entry *entry_to_check,
role_object *role, int *present);
static int roles_check_nested(caddr_t data, caddr_t arg);
-static int roles_is_inscope(Slapi_Entry *entry_to_check, Slapi_DN *role_dn);
+static int roles_is_inscope(Slapi_Entry *entry_to_check, role_object *this_role);
static void berval_set_string(struct berval *bv, const char* string);
static void roles_cache_role_def_delete(roles_cache_def *role_def);
static void roles_cache_role_def_free(roles_cache_def *role_def);
@@ -1110,6 +1111,7 @@ static int roles_cache_create_object_from_entry(Slapi_Entry
*role_entry, role_ob
int rc = 0;
int type = 0;
role_object *this_role = NULL;
+ char *rolescopeDN = NULL;
slapi_log_error(SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
"--> roles_cache_create_object_from_entry\n");
@@ -1164,6 +1166,41 @@ static int roles_cache_create_object_from_entry(Slapi_Entry
*role_entry, role_ob
this_role->dn = slapi_sdn_new();
slapi_sdn_copy(slapi_entry_get_sdn(role_entry),this_role->dn);
+
+ rolescopeDN = slapi_entry_attr_get_charptr(role_entry, ROLE_SCOPE_DN);
+ if (rolescopeDN) {
+ Slapi_DN *rolescopeSDN;
+ Slapi_DN *top_rolescopeSDN, *top_this_roleSDN;
+
+ /* Before accepting to use this scope, first check if it belongs to the
same suffix */
+ rolescopeSDN = slapi_sdn_new_dn_byref(rolescopeDN);
+ if ((strlen((char *) slapi_sdn_get_ndn(rolescopeSDN)) > 0) &&
+ (slapi_dn_syntax_check(NULL, (char *)
slapi_sdn_get_ndn(rolescopeSDN), 1) == 0)) {
+ top_rolescopeSDN = roles_cache_get_top_suffix(rolescopeSDN);
+ top_this_roleSDN = roles_cache_get_top_suffix(this_role->dn);
+ if (slapi_sdn_compare(top_rolescopeSDN, top_this_roleSDN) == 0)
{
+ /* rolescopeDN belongs to the same suffix as the role, we
can use this scope */
+ this_role->rolescopedn = rolescopeSDN;
+ } else {
+ slapi_log_error(SLAPI_LOG_FATAL, ROLES_PLUGIN_SUBSYSTEM,
+ "%s: invalid %s - %s not in the same suffix.
Scope skipped.\n",
+ (char*) slapi_sdn_get_dn(this_role->dn),
+ ROLE_SCOPE_DN,
+ rolescopeDN);
+ slapi_sdn_free(&rolescopeSDN);
+ }
+ slapi_sdn_free(&top_rolescopeSDN);
+ slapi_sdn_free(&top_this_roleSDN);
+ } else {
+ /* this is an invalid DN, just ignore this parameter*/
+ slapi_log_error(SLAPI_LOG_FATAL, ROLES_PLUGIN_SUBSYSTEM,
+ "%s: invalid %s - %s not a valid DN. Scope
skipped.\n",
+ (char*) slapi_sdn_get_dn(this_role->dn),
+ ROLE_SCOPE_DN,
+ rolescopeDN);
+ slapi_sdn_free(&rolescopeSDN);
+ }
+ }
/* Depending upon role type, pull out the remaining information we need */
switch (this_role->type)
@@ -1776,7 +1813,7 @@ static int roles_is_entry_member_of_object_ext(vattr_context *c,
caddr_t data, c
goto done;
}
- if (!roles_is_inscope(entry_to_check, this_role->dn))
+ if (!roles_is_inscope(entry_to_check, this_role))
{
slapi_log_error(SLAPI_LOG_PLUGIN,
ROLES_PLUGIN_SUBSYSTEM, "roles_is_entry_member_of_object-> entry not in
scope of role\n");
@@ -1955,7 +1992,7 @@ static int roles_check_nested(caddr_t data, caddr_t arg)
return rc;
}
/* get the role_object data associated to that dn */
- if ( roles_is_inscope(get_nsrole->is_entry_member_of, this_role->dn) )
+ if ( roles_is_inscope(get_nsrole->is_entry_member_of, this_role) )
{
/* The list of nested roles is contained in the role definition */
roles_is_entry_member_of_object((caddr_t)this_role, (caddr_t)get_nsrole);
@@ -1974,17 +2011,23 @@ static int roles_check_nested(caddr_t data, caddr_t arg)
----------------------
Tells us if a presented role is in scope with respect to the presented entry
*/
-static int roles_is_inscope(Slapi_Entry *entry_to_check, Slapi_DN *role_dn)
+static int roles_is_inscope(Slapi_Entry *entry_to_check, role_object *this_role)
{
int rc;
- Slapi_DN role_parent;
+ Slapi_DN role_parent;
+ Slapi_DN *scope_dn = NULL;
slapi_log_error(SLAPI_LOG_PLUGIN,
ROLES_PLUGIN_SUBSYSTEM, "--> roles_is_inscope\n");
+ if (this_role->rolescopedn) {
+ scope_dn = this_role->rolescopedn;
+ } else {
+ scope_dn = this_role->dn;
+ }
slapi_sdn_init(&role_parent);
- slapi_sdn_get_parent(role_dn,&role_parent);
+ slapi_sdn_get_parent(scope_dn,&role_parent);
rc = slapi_sdn_scope_test(slapi_entry_get_sdn( entry_to_check ),
&role_parent,
@@ -2000,7 +2043,7 @@ static int roles_is_inscope(Slapi_Entry *entry_to_check, Slapi_DN
*role_dn)
slapi_log_error(SLAPI_LOG_PLUGIN,
ROLES_PLUGIN_SUBSYSTEM, "<-- roles_is_inscope: entry %s role %s result
%d\n",
- slapi_entry_get_dn_const(entry_to_check),(char*)slapi_sdn_get_ndn(role_dn), rc);
+ slapi_entry_get_dn_const(entry_to_check),(char*)slapi_sdn_get_ndn(scope_dn), rc);
return (rc);
}
@@ -2127,6 +2170,7 @@ static void roles_cache_role_object_free(role_object *this_role)
}
slapi_sdn_free(&this_role->dn);
+ slapi_sdn_free(&this_role->rolescopedn);
/* Free the object */
slapi_ch_free((void**)&this_role);
diff --git a/ldap/servers/plugins/roles/roles_cache.h
b/ldap/servers/plugins/roles/roles_cache.h
index 870f5a0..3a1e26c 100644
--- a/ldap/servers/plugins/roles/roles_cache.h
+++ b/ldap/servers/plugins/roles/roles_cache.h
@@ -62,6 +62,8 @@
#define ROLE_MANAGED_ATTR_NAME "nsRoleDN"
#define ROLE_NESTED_ATTR_NAME "nsRoleDN"
+#define ROLE_SCOPE_DN "nsRoleScopeDN"
+
#define SLAPI_ROLE_ERROR_NO_FILTER_SPECIFIED -1
#define SLAPI_ROLE_ERROR_FILTER_BAD -2
#define SLAPI_ROLE_DEFINITION_DOESNT_EXIST -3