From 9376e1bcaf90a83599c4102222b919dfd6526a91 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Fri, 17 Sep 2010 22:21:02 +0000
Subject: [PATCH] More fixes to the sub-entry security model: add new subentry-write privilege; rename inheritFromBaseDN to inheritFromBaseRDN and restrict it to the root entry of the subentry scope; restrict DNs derived from inheritFromDNAttribute to the root entry of the subentry scope; remove band-aid subentry write access global ACI.
---
opends/src/messages/messages/core.properties | 2
opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java | 3
opends/tests/unit-tests-testng/src/server/org/opends/server/core/SubentryManagerTestCase.java | 6
opends/src/server/org/opends/server/types/Entry.java | 6 +
opends/src/server/org/opends/server/core/RootPrivilegeChangeListener.java | 3
opends/src/server/org/opends/server/types/Privilege.java | 13 ++
opends/src/server/org/opends/server/core/SubentryManager.java | 55 +++++++++++
opends/resource/config/config.ldif | 2
opends/src/admin/defn/org/opends/server/admin/std/GlobalConfiguration.xml | 6 +
opends/src/server/org/opends/server/types/SubEntry.java | 17 ++-
opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java | 160 +++++++++++++++++++++++++++++++
opends/src/admin/defn/org/opends/server/admin/std/RootDNConfiguration.xml | 7 +
opends/src/ads/org/opends/admin/ads/ADSContext.java | 1
opends/resource/schema/00-core.ldif | 4
opends/src/admin/messages/GlobalCfgDefn.properties | 1
opends/src/admin/messages/RootDNCfgDefn.properties | 1
opends/src/server/org/opends/server/core/CoreConfigManager.java | 3
17 files changed, 275 insertions(+), 15 deletions(-)
diff --git a/opends/resource/config/config.ldif b/opends/resource/config/config.ldif
index e820ba1..e7c1fd2 100644
--- a/opends/resource/config/config.ldif
+++ b/opends/resource/config/config.ldif
@@ -82,7 +82,6 @@
ds-cfg-global-aci: (targetattr="createTimestamp||creatorsName||modifiersName||modifyTimestamp||entryDN||entryUUID||subschemaSubentry")(version 3.0; acl "User-Visible Operational Attributes"; allow (read,search,compare) userdn="ldap:///anyone";)
ds-cfg-global-aci: (target="ldap:///dc=replicationchanges")(targetattr="*")(version 3.0; acl "Replication backend access"; deny (all) userdn="ldap:///anyone";)
ds-cfg-global-aci: (target="ldap:///cn=changelog")(targetattr="*")(version 3.0; acl "External changelog access"; deny (all) userdn="ldap:///anyone";)
-ds-cfg-global-aci: (targetfilter="(|(objectclass=subentry)(objectclass=ldapsubentry))")(version 3.0; acl "Subentry write access"; deny (add,write,delete) userdn="ldap:///anyone";)
cn: Access Control Handler
ds-cfg-java-class: org.opends.server.authorization.dseecompat.AciHandler
ds-cfg-enabled: true
@@ -1880,6 +1879,7 @@
ds-cfg-default-root-privilege-name: update-schema
ds-cfg-default-root-privilege-name: privilege-change
ds-cfg-default-root-privilege-name: unindexed-search
+ds-cfg-default-root-privilege-name: subentry-write
dn: cn=Directory Manager,cn=Root DNs,cn=config
objectClass: top
diff --git a/opends/resource/schema/00-core.ldif b/opends/resource/schema/00-core.ldif
index 0ab7dc0..342bb0c 100644
--- a/opends/resource/schema/00-core.ldif
+++ b/opends/resource/schema/00-core.ldif
@@ -402,7 +402,7 @@
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.621 NAME 'inheritFromDNAttribute'
EQUALITY objectIdentifierMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.38
SINGLE-VALUE X-ORIGIN 'OpenDS Directory Server' )
-attributeTypes: ( 1.3.6.1.4.1.26027.1.1.622 NAME 'inheritFromBaseDN'
+attributeTypes: ( 1.3.6.1.4.1.26027.1.1.622 NAME 'inheritFromBaseRDN'
EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
SINGLE-VALUE X-ORIGIN 'OpenDS Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.623 NAME 'inheritFromRDNType'
@@ -689,7 +689,7 @@
'inheritedFromRDNCollectiveAttributeSubentry'
DESC 'Inherited from RDN Collective Attributes Subentry class'
SUP inheritedCollectiveAttributeSubentry STRUCTURAL
- MUST ( inheritFromRDNAttribute $ inheritFromRDNType $ inheritFromBaseDN )
+ MUST ( inheritFromRDNAttribute $ inheritFromRDNType $ inheritFromBaseRDN )
X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 2.16.840.1.113730.3.2.33 NAME 'groupOfURLs'
DESC 'Sun-defined objectclass' SUP top STRUCTURAL MUST ( cn )
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/GlobalConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/GlobalConfiguration.xml
index 20d24d7..c5d7c3c 100644
--- a/opends/src/admin/defn/org/opends/server/admin/std/GlobalConfiguration.xml
+++ b/opends/src/admin/defn/org/opends/server/admin/std/GlobalConfiguration.xml
@@ -670,6 +670,12 @@
that cannot be optimized using server indexes.
</adm:synopsis>
</adm:value>
+ <adm:value name="subentry-write">
+ <adm:synopsis>
+ Allows the associated user to perform LDAP subentry write
+ operations.
+ </adm:synopsis>
+ </adm:value>
</adm:enumeration>
</adm:syntax>
<adm:profile name="ldap">
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/RootDNConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/RootDNConfiguration.xml
index e493841..42ea75c 100644
--- a/opends/src/admin/defn/org/opends/server/admin/std/RootDNConfiguration.xml
+++ b/opends/src/admin/defn/org/opends/server/admin/std/RootDNConfiguration.xml
@@ -76,6 +76,7 @@
<adm:value>update-schema</adm:value>
<adm:value>privilege-change</adm:value>
<adm:value>unindexed-search</adm:value>
+ <adm:value>subentry-write</adm:value>
</adm:defined>
</adm:default-behavior>
<adm:syntax>
@@ -210,6 +211,12 @@
that cannot be optimized using server indexes.
</adm:synopsis>
</adm:value>
+ <adm:value name="subentry-write">
+ <adm:synopsis>
+ Allows the associated user to perform LDAP subentry write
+ operations.
+ </adm:synopsis>
+ </adm:value>
</adm:enumeration>
</adm:syntax>
<adm:profile name="ldap">
diff --git a/opends/src/admin/messages/GlobalCfgDefn.properties b/opends/src/admin/messages/GlobalCfgDefn.properties
index 6e81ff5..2dd3d75 100644
--- a/opends/src/admin/messages/GlobalCfgDefn.properties
+++ b/opends/src/admin/messages/GlobalCfgDefn.properties
@@ -35,6 +35,7 @@
property.disabled-privilege.syntax.enumeration.value.server-lockdown.synopsis=Allows the user to place and bring the server of lockdown mode.
property.disabled-privilege.syntax.enumeration.value.server-restart.synopsis=Allows the user to request that the server perform an in-core restart.
property.disabled-privilege.syntax.enumeration.value.server-shutdown.synopsis=Allows the user to request that the server shut down.
+property.disabled-privilege.syntax.enumeration.value.subentry-write.synopsis=Allows the associated user to perform LDAP subentry write operations.
property.disabled-privilege.syntax.enumeration.value.unindexed-search.synopsis=Allows the user to request that the server process a search that cannot be optimized using server indexes.
property.disabled-privilege.syntax.enumeration.value.update-schema.synopsis=Allows the user to make changes to the server schema.
property.entry-cache-preload.synopsis=Indicates whether or not to preload the entry cache on startup.
diff --git a/opends/src/admin/messages/RootDNCfgDefn.properties b/opends/src/admin/messages/RootDNCfgDefn.properties
index ad0cb6f..097758f 100644
--- a/opends/src/admin/messages/RootDNCfgDefn.properties
+++ b/opends/src/admin/messages/RootDNCfgDefn.properties
@@ -23,6 +23,7 @@
property.default-root-privilege-name.syntax.enumeration.value.server-lockdown.synopsis=Allows the user to place and bring the server of lockdown mode.
property.default-root-privilege-name.syntax.enumeration.value.server-restart.synopsis=Allows the user to request that the server perform an in-core restart.
property.default-root-privilege-name.syntax.enumeration.value.server-shutdown.synopsis=Allows the user to request that the server shut down.
+property.default-root-privilege-name.syntax.enumeration.value.subentry-write.synopsis=Allows the associated user to perform LDAP subentry write operations.
property.default-root-privilege-name.syntax.enumeration.value.unindexed-search.synopsis=Allows the user to request that the server process a search that cannot be optimized using server indexes.
property.default-root-privilege-name.syntax.enumeration.value.update-schema.synopsis=Allows the user to make changes to the server schema.
relation.root-dn-user.user-friendly-name=Root DN User
diff --git a/opends/src/ads/org/opends/admin/ads/ADSContext.java b/opends/src/ads/org/opends/admin/ads/ADSContext.java
index 1f3634f..fd93d9f 100644
--- a/opends/src/ads/org/opends/admin/ads/ADSContext.java
+++ b/opends/src/ads/org/opends/admin/ads/ADSContext.java
@@ -1695,6 +1695,7 @@
privilege.add("update-schema");
privilege.add("privilege-change");
privilege.add("unindexed-search");
+ privilege.add("subentry-write");
return privilege;
}
diff --git a/opends/src/messages/messages/core.properties b/opends/src/messages/messages/core.properties
index 55ed59a..e8df13c 100644
--- a/opends/src/messages/messages/core.properties
+++ b/opends/src/messages/messages/core.properties
@@ -1846,3 +1846,5 @@
operations each %d ms
SEVERE_ERR_MAX_OPS_PER_INTERVAL_738=The value "%d" is not a valid value for \
the maximum number of operations per interval (must be positive)
+MILD_ERR_SUBENTRY_WRITE_INSUFFICIENT_PRIVILEGES_739=This operation involves \
+ LDAP subentries which you do not have sufficient privileges to administer
diff --git a/opends/src/server/org/opends/server/core/CoreConfigManager.java b/opends/src/server/org/opends/server/core/CoreConfigManager.java
index 81b1ecf..51b9b65 100644
--- a/opends/src/server/org/opends/server/core/CoreConfigManager.java
+++ b/opends/src/server/org/opends/server/core/CoreConfigManager.java
@@ -326,6 +326,9 @@
case UPDATE_SCHEMA:
disabledPrivileges.add(Privilege.UPDATE_SCHEMA);
break;
+ case SUBENTRY_WRITE:
+ disabledPrivileges.add(Privilege.SUBENTRY_WRITE);
+ break;
}
}
}
diff --git a/opends/src/server/org/opends/server/core/RootPrivilegeChangeListener.java b/opends/src/server/org/opends/server/core/RootPrivilegeChangeListener.java
index 6a51e37..8387cb7 100644
--- a/opends/src/server/org/opends/server/core/RootPrivilegeChangeListener.java
+++ b/opends/src/server/org/opends/server/core/RootPrivilegeChangeListener.java
@@ -188,6 +188,9 @@
case UNINDEXED_SEARCH:
privSet.add(Privilege.UNINDEXED_SEARCH);
break;
+ case SUBENTRY_WRITE:
+ privSet.add(Privilege.SUBENTRY_WRITE);
+ break;
}
}
diff --git a/opends/src/server/org/opends/server/core/SubentryManager.java b/opends/src/server/org/opends/server/core/SubentryManager.java
index adfa86d..b94f46a 100644
--- a/opends/src/server/org/opends/server/core/SubentryManager.java
+++ b/opends/src/server/org/opends/server/core/SubentryManager.java
@@ -28,6 +28,7 @@
+import org.opends.server.api.ClientConnection;
import org.opends.server.api.SubtreeSpecification;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -52,6 +53,8 @@
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
+import org.opends.server.types.Privilege;
+import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchScope;
import org.opends.server.types.SearchFilter;
@@ -944,6 +947,15 @@
if (entry.isSubentry() || entry.isLDAPSubentry())
{
+ ClientConnection conn = addOperation.getClientConnection();
+ if (!conn.hasPrivilege(Privilege.SUBENTRY_WRITE,
+ conn.getOperationInProgress(
+ addOperation.getMessageID())))
+ {
+ return PluginResult.PreOperation.stopProcessing(
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ ERR_SUBENTRY_WRITE_INSUFFICIENT_PRIVILEGES.get());
+ }
for (SubentryChangeListener changeListener :
changeListeners)
{
@@ -975,12 +987,29 @@
PreOperationDeleteOperation deleteOperation)
{
Entry entry = deleteOperation.getEntryToDelete();
+ boolean hasSubentryWritePrivilege = false;
lock.readLock().lock();
try
{
for (SubEntry subEntry : dit2SubEntry.getSubtree(entry.getDN()))
{
+ if (!hasSubentryWritePrivilege)
+ {
+ ClientConnection conn = deleteOperation.getClientConnection();
+ if (!conn.hasPrivilege(Privilege.SUBENTRY_WRITE,
+ conn.getOperationInProgress(
+ deleteOperation.getMessageID())))
+ {
+ return PluginResult.PreOperation.stopProcessing(
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ ERR_SUBENTRY_WRITE_INSUFFICIENT_PRIVILEGES.get());
+ }
+ else
+ {
+ hasSubentryWritePrivilege = true;
+ }
+ }
for (SubentryChangeListener changeListener :
changeListeners)
{
@@ -1023,6 +1052,15 @@
if ((newEntry.isSubentry() || newEntry.isLDAPSubentry()) ||
(oldEntry.isSubentry() || oldEntry.isLDAPSubentry()))
{
+ ClientConnection conn = modifyOperation.getClientConnection();
+ if (!conn.hasPrivilege(Privilege.SUBENTRY_WRITE,
+ conn.getOperationInProgress(
+ modifyOperation.getMessageID())))
+ {
+ return PluginResult.PreOperation.stopProcessing(
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ ERR_SUBENTRY_WRITE_INSUFFICIENT_PRIVILEGES.get());
+ }
for (SubentryChangeListener changeListener :
changeListeners)
{
@@ -1058,6 +1096,7 @@
Entry newEntry = modifyDNOperation.getUpdatedEntry();
String oldDNString = oldEntry.getDN().toNormalizedString();
String newDNString = newEntry.getDN().toNormalizedString();
+ boolean hasSubentryWritePrivilege = false;
lock.readLock().lock();
try
@@ -1066,6 +1105,22 @@
dit2SubEntry.getSubtree(oldEntry.getDN());
for (SubEntry subentry : setToDelete)
{
+ if (!hasSubentryWritePrivilege)
+ {
+ ClientConnection conn = modifyDNOperation.getClientConnection();
+ if (!conn.hasPrivilege(Privilege.SUBENTRY_WRITE,
+ conn.getOperationInProgress(
+ modifyDNOperation.getMessageID())))
+ {
+ return PluginResult.PreOperation.stopProcessing(
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ ERR_SUBENTRY_WRITE_INSUFFICIENT_PRIVILEGES.get());
+ }
+ else
+ {
+ hasSubentryWritePrivilege = true;
+ }
+ }
oldEntry = subentry.getEntry();
try
{
diff --git a/opends/src/server/org/opends/server/types/Entry.java b/opends/src/server/org/opends/server/types/Entry.java
index fd37d33..26016d5 100644
--- a/opends/src/server/org/opends/server/types/Entry.java
+++ b/opends/src/server/org/opends/server/types/Entry.java
@@ -3707,6 +3707,12 @@
{
inheritFromDN = DN.decode(
value.getNormalizedValue());
+ // Respect subentry root scope.
+ if (!inheritFromDN.isDescendantOf(
+ subEntry.getDN().getParent()))
+ {
+ inheritFromDN = null;
+ }
break;
}
}
diff --git a/opends/src/server/org/opends/server/types/Privilege.java b/opends/src/server/org/opends/server/types/Privilege.java
index 9386ec5..7608b98 100644
--- a/opends/src/server/org/opends/server/types/Privilege.java
+++ b/opends/src/server/org/opends/server/types/Privilege.java
@@ -226,7 +226,15 @@
* The privilege that provides the ability to perform an unindexed
* search in the JE backend.
*/
- UNINDEXED_SEARCH("unindexed-search");
+ UNINDEXED_SEARCH("unindexed-search"),
+
+
+
+ /**
+ * The privilege that provides the ability to perform write
+ * operations on LDAP subentries.
+ */
+ SUBENTRY_WRITE("subentry-write");
@@ -287,6 +295,7 @@
PRIV_MAP.put("update-schema", UPDATE_SCHEMA);
PRIV_MAP.put("privilege-change", PRIVILEGE_CHANGE);
PRIV_MAP.put("unindexed-search", UNINDEXED_SEARCH);
+ PRIV_MAP.put("subentry-write", SUBENTRY_WRITE);
PRIV_NAMES.add("bypass-acl");
PRIV_NAMES.add("bypass-lockdown");
@@ -311,6 +320,7 @@
PRIV_NAMES.add("update-schema");
PRIV_NAMES.add("privilege-change");
PRIV_NAMES.add("unindexed-search");
+ PRIV_NAMES.add("subentry-write");
DEFAULT_ROOT_PRIV_SET.add(BYPASS_ACL);
DEFAULT_ROOT_PRIV_SET.add(BYPASS_LOCKDOWN);
@@ -330,6 +340,7 @@
DEFAULT_ROOT_PRIV_SET.add(UPDATE_SCHEMA);
DEFAULT_ROOT_PRIV_SET.add(PRIVILEGE_CHANGE);
DEFAULT_ROOT_PRIV_SET.add(UNINDEXED_SEARCH);
+ DEFAULT_ROOT_PRIV_SET.add(SUBENTRY_WRITE);
}
diff --git a/opends/src/server/org/opends/server/types/SubEntry.java b/opends/src/server/org/opends/server/types/SubEntry.java
index 4e529b4..3c6a344 100644
--- a/opends/src/server/org/opends/server/types/SubEntry.java
+++ b/opends/src/server/org/opends/server/types/SubEntry.java
@@ -131,11 +131,11 @@
"inheritfromrdntype";
/**
- * The name of the "inheritFromBaseDN" attribute type,
+ * The name of the "inheritFromBaseRDN" attribute type,
* formatted in all lowercase characters.
*/
public static final String ATTR_INHERIT_COLLECTIVE_FROM_BASE =
- "inheritfrombasedn";
+ "inheritfrombaserdn";
/**
* The name of the "inheritAttribute" attribute type,
@@ -390,6 +390,11 @@
{
this.inheritFromBaseDN =
DN.decode(value.getNormalizedValue());
+ // Has to have a parent since subentry itself
+ // cannot be a suffix entry within the server.
+ this.inheritFromBaseDN =
+ getDN().getParent().concat(
+ inheritFromBaseDN);
break;
}
}
@@ -442,7 +447,7 @@
* Retrieves the distinguished name for this subentry.
* @return The distinguished name for this subentry.
*/
- public DN getDN()
+ public final DN getDN()
{
return this.entry.getDN();
}
@@ -452,7 +457,7 @@
* for this subentry.
* @return entry object for this subentry.
*/
- public Entry getEntry()
+ public final Entry getEntry()
{
return this.entry;
}
@@ -562,9 +567,9 @@
}
/**
- * Getter to retrieve inheritFromBaseDN DN
+ * Getter to retrieve inheritFromBaseRDN DN
* for inherited collective attribute subentry.
- * @return DN of inheritFromBaseDN or,
+ * @return DN of inheritFromBaseRDN or,
* <code>null</code> if there is none.
*/
public DN getInheritFromBaseDN()
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SubentryManagerTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SubentryManagerTestCase.java
index 5cbe963..d75ee68 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SubentryManagerTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SubentryManagerTestCase.java
@@ -64,8 +64,8 @@
public class SubentryManagerTestCase extends CoreTestCase
{
private static final String SUFFIX = "dc=example,dc=com";
- private static final String BASE =
- "ou=Test SubEntry Manager," + SUFFIX;
+ private static final String BASE_RDN = "ou=Test SubEntry Manager";
+ private static final String BASE = BASE_RDN + "," + SUFFIX;
private Entry testEntry;
private Entry ldapSubentry;
@@ -192,7 +192,7 @@
"objectclass: subentry",
"objectClass: inheritedCollectiveAttributeSubentry",
"objectClass: inheritedFromRDNCollectiveAttributeSubentry",
- "inheritFromBaseDN: " + BASE,
+ "inheritFromBaseRDN: " + BASE_RDN,
"inheritFromRDNAttribute: title",
"inheritFromRDNType: cn",
"inheritAttribute: telephoneNumber",
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java
index 059d2bc..7f3bf87 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java
@@ -22,7 +22,7 @@
* CDDL HEADER END
*
*
- * Copyright 2008 Sun Microsystems, Inc.
+ * Copyright 2008-2010 Sun Microsystems, Inc.
*/
package org.opends.server.protocols.jmx;
@@ -180,6 +180,7 @@
"ds-privilege-name: unindexed-search",
"ds-privilege-name: jmx-read",
"ds-privilege-name: jmx-write",
+ "ds-privilege-name: subentry-write",
"ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
"cn=Password Policies,cn=config",
"",
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java
index 32b9aba..0921a0c 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java
@@ -22,7 +22,7 @@
* CDDL HEADER END
*
*
- * Copyright 2007-2009 Sun Microsystems, Inc.
+ * Copyright 2007-2010 Sun Microsystems, Inc.
*/
package org.opends.server.types;
@@ -141,6 +141,7 @@
"ds-privilege-name: -backend-backup",
"ds-privilege-name: -backend-restore",
"ds-privilege-name: -unindexed-search",
+ "ds-privilege-name: -subentry-write",
"",
"dn: cn=Proxy Root,cn=Root DNs,cn=config",
"objectClass: top",
@@ -176,6 +177,7 @@
"ds-privilege-name: proxied-auth",
"ds-privilege-name: bypass-acl",
"ds-privilege-name: unindexed-search",
+ "ds-privilege-name: subentry-write",
"ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
"cn=Password Policies,cn=config",
"",
@@ -193,6 +195,15 @@
"ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
"cn=Password Policies,cn=config",
"",
+ "dn: cn=Subentry Target,o=test",
+ "objectClass: top",
+ "objectClass: subentry",
+ "objectClass: collectiveAttributeSubentry",
+ "objectClass: extensibleObject",
+ "cn: Subentry Target",
+ "l;collective: Test",
+ "subtreeSpecification: {}",
+ "",
"dn: cn=PWReset Target,o=test",
"objectClass: top",
"objectClass: person",
@@ -633,6 +644,153 @@
/**
+ * Tests to ensure that add and delete operations
+ * properly respect the SUBENTRY_WRITE privilege.
+ *
+ * @param conn The client connection to use to perform the
+ * operations.
+ * @param hasPrivilege Indicates whether the authenticated user is expected
+ * to have the SUBENTRY_WRITE privilege and therefore
+ * the operations should succeed.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test(dataProvider = "testdata")
+ public void testSubentryWriteAddAndDelete(InternalClientConnection conn,
+ boolean hasPrivilege)
+ throws Exception
+ {
+ assertEquals(conn.hasPrivilege(Privilege.SUBENTRY_WRITE, null),
+ hasPrivilege);
+
+ Entry entry = TestCaseUtils.makeEntry(
+ "dn: cn=Test Subentry,o=test",
+ "objectClass: top",
+ "objectClass: subentry",
+ "objectClass: collectiveAttributeSubentry",
+ "objectClass: extensibleObject",
+ "cn: Test Subentry",
+ "l;collective: Test",
+ "subtreeSpecification: {}");
+
+ AddOperation addOperation =
+ conn.processAdd(entry.getDN(), entry.getObjectClasses(),
+ entry.getUserAttributes(),
+ entry.getOperationalAttributes());
+ if (hasPrivilege)
+ {
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+ DeleteOperation deleteOperation = conn.processDelete(entry.getDN());
+ assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+ else
+ {
+ assertEquals(addOperation.getResultCode(),
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+
+ DeleteOperation deleteOperation =
+ conn.processDelete(
+ DN.decode("cn=Subentry Target,o=test"));
+ assertEquals(deleteOperation.getResultCode(),
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ }
+ }
+
+
+
+ /**
+ * Tests to ensure that modify operations properly respect
+ * the SUBENTRY_WRITE privilege.
+ *
+ * @param conn The client connection to use to perform the modify
+ * operation.
+ * @param hasPrivilege Indicates whether the authenticated user is expected
+ * to have the SUBENTRY_WRITE privilege and therefore
+ * the modify should succeed.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test(dataProvider = "testdata")
+ public void testSubentryWriteModify(InternalClientConnection conn,
+ boolean hasPrivilege)
+ throws Exception
+ {
+ assertEquals(conn.hasPrivilege(Privilege.SUBENTRY_WRITE, null),
+ hasPrivilege);
+
+ ArrayList<Modification> mods = new ArrayList<Modification>();
+
+ mods.add(new Modification(ModificationType.REPLACE,
+ Attributes.create("subtreeSpecification",
+ "{base \"ou=doesnotexist\"}")));
+
+ ModifyOperation modifyOperation =
+ conn.processModify(DN.decode("cn=Subentry Target,o=test"), mods);
+ if (hasPrivilege)
+ {
+ assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+
+ mods.clear();
+ mods.add(new Modification(ModificationType.REPLACE,
+ Attributes.create("subtreeSpecification", "{}")));
+
+ modifyOperation = conn.processModify(
+ DN.decode("cn=Subentry Target,o=test"), mods);
+ assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+ else
+ {
+ assertEquals(modifyOperation.getResultCode(),
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ }
+ }
+
+
+
+ /**
+ * Tests to ensure that modify DN operations
+ * properly respect the SUBENTRY_WRITE privilege.
+ *
+ * @param conn The client connection to use to perform the modify DN
+ * operation.
+ * @param hasPrivilege Indicates whether the authenticated user is expected
+ * to have the SUBENTRY_WRITE privilege and therefore
+ * the modify DN should succeed.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test(dataProvider = "testdata")
+ public void testSubentryWriteModifyDN(InternalClientConnection conn,
+ boolean hasPrivilege)
+ throws Exception
+ {
+ assertEquals(conn.hasPrivilege(Privilege.SUBENTRY_WRITE, null),
+ hasPrivilege);
+
+ ModifyDNOperation modifyDNOperation =
+ conn.processModifyDN(DN.decode("cn=Subentry Target,o=test"),
+ RDN.decode("cn=New Subentry Target"),
+ true, null);
+ if (hasPrivilege)
+ {
+ assertEquals(modifyDNOperation.getResultCode(),
+ ResultCode.SUCCESS);
+ modifyDNOperation =
+ conn.processModifyDN(DN.decode("cn=New Subentry Target,o=test"),
+ RDN.decode("cn=Subentry Target"),
+ true, null);
+ }
+ else
+ {
+ assertEquals(modifyDNOperation.getResultCode(),
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ }
+ }
+
+
+
+ /**
* Tests to ensure that modify operations which attempt to reset a user's
* password properly respect the PASSWORD_RESET privilege.
*
--
Gitblit v1.10.0