From ec465f362ea0c7b6e0c0905748bcdfde1b859d0f Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Fri, 09 Feb 2007 21:51:09 +0000
Subject: [PATCH] Add an initial set of privilege support to OpenDS. The current privileges are currently defined and implemented: * config-read (allow reading the configuration) * config-write (allow updating the configuration) * ldif-import (allow invoking LDIF import tasks) * ldif-export (allow invoking LDIF export tasks) * backend-backup (allow invoking backup tasks) * backend-restore (allow invoking restore tasks) * server-shutdown (allow invoking server shutdown tasks) * server-restart (allow invoking server restart tasks) * server-restart (allow invoking server restart tasks) * password-reset (allow resetting user passwords) * update-schema (allow updating the server schema) * privilege-change (allow changing the set of privileges for a user)
---
opendj-sdk/opends/src/server/org/opends/server/tasks/ImportTask.java | 22
opendj-sdk/opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java | 33
opendj-sdk/opends/src/server/org/opends/server/tasks/ExportTask.java | 22
opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskBackend.java | 2
opendj-sdk/opends/src/server/org/opends/server/core/ModifyOperation.java | 29
opendj-sdk/opends/src/server/org/opends/server/config/ConfigConstants.java | 17
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java | 1166 +++++++++++++++++++++++
opendj-sdk/opends/src/server/org/opends/server/backends/SchemaBackend.java | 16
opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java | 86 +
opendj-sdk/opends/resource/config/config.ldif | 18
opendj-sdk/opends/src/server/org/opends/server/types/Privilege.java | 389 +++++++
opendj-sdk/opends/src/server/org/opends/server/messages/ExtensionsMessages.java | 15
opendj-sdk/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java | 116 ++
opendj-sdk/opends/src/server/org/opends/server/core/RootDNConfigManager.java | 312 ++++++
opendj-sdk/opends/src/server/org/opends/server/tasks/AddSchemaFileTask.java | 20
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/BindOperationTestCase.java | 2
opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskScheduler.java | 11
opendj-sdk/opends/src/server/org/opends/server/tools/LDAPPasswordModify.java | 12
opendj-sdk/opends/src/server/org/opends/server/api/ClientConnection.java | 238 ++++
opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java | 23
opendj-sdk/opends/src/server/org/opends/server/messages/TaskMessages.java | 99 +
opendj-sdk/opends/src/server/org/opends/server/tasks/RestoreTask.java | 22
opendj-sdk/opends/src/server/org/opends/server/tasks/ShutdownTask.java | 41
opendj-sdk/opends/src/server/org/opends/server/core/AddOperation.java | 15
opendj-sdk/opends/src/server/org/opends/server/core/CompareOperation.java | 15
opendj-sdk/opends/src/server/org/opends/server/messages/ConfigMessages.java | 140 ++
opendj-sdk/opends/src/server/org/opends/server/tasks/BackupTask.java | 22
opendj-sdk/opends/src/server/org/opends/server/backends/task/Task.java | 38
opendj-sdk/opends/src/server/org/opends/server/protocols/internal/InternalClientConnection.java | 2
opendj-sdk/opends/resource/schema/02-config.ldif | 9
opendj-sdk/opends/src/server/org/opends/server/messages/BackendMessages.java | 13
31 files changed, 2,927 insertions(+), 38 deletions(-)
diff --git a/opendj-sdk/opends/resource/config/config.ldif b/opendj-sdk/opends/resource/config/config.ldif
index 2c730b0..d74958c 100644
--- a/opendj-sdk/opends/resource/config/config.ldif
+++ b/opendj-sdk/opends/resource/config/config.ldif
@@ -1028,8 +1028,24 @@
dn: cn=Root DNs,cn=config
objectClass: top
-objectClass: ds-cfg-branch
+objectClass: ds-cfg-root-dn-base
cn: Root DNs
+ds-cfg-default-root-privilege-name: bypass-acl
+ds-cfg-default-root-privilege-name: modify-acl
+ds-cfg-default-root-privilege-name: config-read
+ds-cfg-default-root-privilege-name: config-write
+ds-cfg-default-root-privilege-name: ldif-import
+ds-cfg-default-root-privilege-name: ldif-export
+ds-cfg-default-root-privilege-name: backend-backup
+ds-cfg-default-root-privilege-name: backend-restore
+ds-cfg-default-root-privilege-name: server-shutdown
+ds-cfg-default-root-privilege-name: server-restart
+ds-cfg-default-root-privilege-name: disconnect-client
+ds-cfg-default-root-privilege-name: cancel-request
+ds-cfg-default-root-privilege-name: search-unindexed
+ds-cfg-default-root-privilege-name: password-reset
+ds-cfg-default-root-privilege-name: update-schema
+ds-cfg-default-root-privilege-name: privilege-change
dn: cn=Directory Manager,cn=Root DNs,cn=config
objectClass: top
diff --git a/opendj-sdk/opends/resource/schema/02-config.ldif b/opendj-sdk/opends/resource/schema/02-config.ldif
index b7605d5..9a1ca7b 100644
--- a/opendj-sdk/opends/resource/schema/02-config.ldif
+++ b/opendj-sdk/opends/resource/schema/02-config.ldif
@@ -1042,6 +1042,12 @@
NAME 'ds-cfg-heartbeat-interval'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE
X-ORIGIN 'OpenDS Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.26027.1.1.307
+ NAME 'ds-privilege-name' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ USAGE directoryOperation X-ORIGIN 'OpenDS Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.26027.1.1.308
+ NAME 'ds-cfg-default-root-privilege-name'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.1
NAME 'ds-cfg-access-control-handler' SUP top STRUCTURAL
MUST ( cn $ ds-cfg-acl-handler-class $ ds-cfg-acl-handler-enabled )
@@ -1429,4 +1435,7 @@
objectClasses: ( 1.3.6.1.4.1.26027.1.2.81 NAME 'ds-cfg-group-implementation'
SUP top STRUCTURAL MUST ( cn $ ds-cfg-group-implementation-class $
ds-cfg-group-implementation-enabled ) X-ORIGIN 'OpenDS Directory Server' )
+objectClasses: ( 1.3.6.1.4.1.26027.1.2.82 NAME 'ds-cfg-root-dn-base' SUP top
+ STRUCTURAL MUST cn MAY ds-cfg-default-root-privilege-name
+ X-ORIGIN 'OpenDS Directory Server' )
diff --git a/opendj-sdk/opends/src/server/org/opends/server/api/ClientConnection.java b/opendj-sdk/opends/src/server/org/opends/server/api/ClientConnection.java
index c113d31..48a98ea 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/api/ClientConnection.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/api/ClientConnection.java
@@ -32,6 +32,7 @@
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -41,6 +42,9 @@
import org.opends.server.core.PersistentSearch;
import org.opends.server.core.PluginConfigManager;
import org.opends.server.core.SearchOperation;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.AttributeValue;
import org.opends.server.types.AuthenticationInfo;
import org.opends.server.types.CancelRequest;
import org.opends.server.types.CancelResult;
@@ -48,13 +52,20 @@
import org.opends.server.types.DisconnectReason;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
+import org.opends.server.types.ErrorLogCategory;
+import org.opends.server.types.ErrorLogSeverity;
import org.opends.server.types.IntermediateResponse;
+import org.opends.server.types.Privilege;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchResultReference;
import org.opends.server.util.TimeThread;
+import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.loggers.Debug.*;
+import static org.opends.server.loggers.Error.*;
+import static org.opends.server.messages.CoreMessages.*;
import static org.opends.server.messages.MessageHandler.*;
+import static org.opends.server.util.StaticUtils.*;
@@ -84,6 +95,9 @@
// for this client connection.
private boolean finalized;
+ // The set of privileges assigned to this client connection.
+ private HashSet<Privilege> privileges;
+
// The size limit for use with this client connection.
private int sizeLimit;
@@ -127,6 +141,7 @@
timeLimit = DirectoryServer.getTimeLimit();
lookthroughLimit = DirectoryServer.getLookthroughLimit();
finalized = false;
+ privileges = new HashSet<Privilege>();
}
@@ -846,6 +861,7 @@
if (authenticationInfo == null)
{
this.authenticationInfo = new AuthenticationInfo();
+ privileges = new HashSet<Privilege>();
}
else
{
@@ -869,11 +885,18 @@
DirectoryServer.getAuthenticatedUsers().put(
authZEntry.getDN(), this);
}
+
+ updatePrivileges(authNEntry, authenticationInfo.isRoot());
}
- else if (authZEntry != null)
+ else
{
- DirectoryServer.getAuthenticatedUsers().put(
- authZEntry.getDN(), this);
+ if (authZEntry != null)
+ {
+ DirectoryServer.getAuthenticatedUsers().put(
+ authZEntry.getDN(), this);
+ }
+
+ privileges = new HashSet<Privilege>();
}
}
}
@@ -908,11 +931,13 @@
{
authenticationInfo =
authenticationInfo.duplicate(newEntry, authZEntry);
+ updatePrivileges(newEntry, authenticationInfo.isRoot());
}
else
{
authenticationInfo =
authenticationInfo.duplicate(newEntry, newEntry);
+ updatePrivileges(newEntry, authenticationInfo.isRoot());
}
}
else if ((authZEntry != null) &&
@@ -943,6 +968,213 @@
/**
+ * Indicates whether the authenticated client has the specified
+ * privilege.
+ *
+ * @param privilege The privilege for which to make the
+ * determination.
+ * @param operation The operation being processed which needs to
+ * make the privilege determination, or
+ * {@code null} if there is no associated
+ * operation.
+ *
+ * @return {@code true} if the authenticated client has the
+ * specified privilege, or {@code false} if not.
+ */
+ public boolean hasPrivilege(Privilege privilege,
+ Operation operation)
+ {
+ assert debugEnter(CLASS_NAME, "hasPrivilege",
+ String.valueOf(privilege),
+ String.valueOf(operation));
+
+ boolean result = privileges.contains(privilege);
+ if (operation == null)
+ {
+ DN authDN = authenticationInfo.getAuthenticationDN();
+
+ int msgID = MSGID_CLIENTCONNECTION_AUDIT_HASPRIVILEGE;
+ String message = getMessage(msgID, getConnectionID(), -1L,
+ String.valueOf(authDN),
+ privilege.getName(), result);
+ logError(ErrorLogCategory.ACCESS_CONTROL,
+ ErrorLogSeverity.INFORMATIONAL, message, msgID);
+ }
+ else
+ {
+ DN authDN = authenticationInfo.getAuthenticationDN();
+
+ int msgID = MSGID_CLIENTCONNECTION_AUDIT_HASPRIVILEGE;
+ String message = getMessage(msgID, getConnectionID(),
+ operation.getOperationID(),
+ String.valueOf(authDN),
+ privilege.getName(), result);
+ logError(ErrorLogCategory.ACCESS_CONTROL,
+ ErrorLogSeverity.INFORMATIONAL, message, msgID);
+ }
+
+ return result;
+ }
+
+
+
+ /**
+ * Indicates whether the authenticate client has all of the
+ * specified privileges.
+ *
+ * @param privileges The array of privileges for which to make the
+ * determination.
+ * @param operation The operation being processed which needs to
+ * make the privilege determination, or
+ * {@code null} if there is no associated
+ * operation.
+ *
+ * @return {@code true} if the authenticated client has all of the
+ * specified privileges, or {@code false} if not.
+ */
+ public boolean hasAllPrivileges(Privilege[] privileges,
+ Operation operation)
+ {
+ assert debugEnter(CLASS_NAME, "hasAllPrivileges",
+ String.valueOf(privileges),
+ String.valueOf(operation));
+
+ HashSet<Privilege> privSet = this.privileges;
+ boolean result = true;
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("{");
+
+ for (int i=0; i < privileges.length; i++)
+ {
+ if (i > 0)
+ {
+ buffer.append(",");
+ }
+
+ buffer.append(privileges[i].getName());
+
+ if (! privSet.contains(privileges[i]))
+ {
+ result = false;
+ }
+ }
+
+ buffer.append(" }");
+
+ if (operation == null)
+ {
+ DN authDN = authenticationInfo.getAuthenticationDN();
+
+ int msgID = MSGID_CLIENTCONNECTION_AUDIT_HASPRIVILEGES;
+ String message = getMessage(msgID, getConnectionID(), -1L,
+ String.valueOf(authDN),
+ buffer.toString(), result);
+ logError(ErrorLogCategory.ACCESS_CONTROL,
+ ErrorLogSeverity.INFORMATIONAL, message, msgID);
+ }
+ else
+ {
+ DN authDN = authenticationInfo.getAuthenticationDN();
+
+ int msgID = MSGID_CLIENTCONNECTION_AUDIT_HASPRIVILEGES;
+ String message = getMessage(msgID, getConnectionID(),
+ operation.getOperationID(),
+ String.valueOf(authDN),
+ buffer.toString(), result);
+ logError(ErrorLogCategory.ACCESS_CONTROL,
+ ErrorLogSeverity.INFORMATIONAL, message, msgID);
+ }
+
+ return result;
+ }
+
+
+
+ /**
+ * Updates the privileges associated with this client connection
+ * object based on the provided entry for the authentication
+ * identity.
+ *
+ * @param entry The entry for the authentication identity
+ * associated with this client connection.
+ * @param isRoot Indicates whether the associated user is a root
+ * user and should automatically inherit the root
+ * privilege set.
+ */
+ private void updatePrivileges(Entry entry, boolean isRoot)
+ {
+ assert debugEnter(CLASS_NAME, "updatePrivileges",
+ String.valueOf(entry));
+
+ HashSet<Privilege> newPrivileges = new HashSet<Privilege>();
+ HashSet<Privilege> removePrivileges = new HashSet<Privilege>();
+
+ if (isRoot)
+ {
+ newPrivileges.addAll(DirectoryServer.getRootPrivileges());
+ }
+
+ AttributeType privType =
+ DirectoryServer.getAttributeType(OP_ATTR_PRIVILEGE_NAME);
+ List<Attribute> attrList = entry.getAttribute(privType);
+ if (attrList != null)
+ {
+ for (Attribute a : attrList)
+ {
+ for (AttributeValue v : a.getValues())
+ {
+ String privName = toLowerCase(v.getStringValue());
+
+ // If the name of the privilege is prefixed with a minus
+ // sign, then we will take away that privilege from the
+ // user. We'll handle that at the end so that we can make
+ // sure it's not added back later.
+ if (privName.startsWith("-"))
+ {
+ privName = privName.substring(1);
+ Privilege p = Privilege.privilegeForName(privName);
+ if (p == null)
+ {
+ // FIXME -- Generate an administrative alert.
+
+ // We don't know what privilege to remove, so we'll
+ // remove all of them.
+ newPrivileges.clear();
+ privileges = newPrivileges;
+ return;
+ }
+ else
+ {
+ removePrivileges.add(p);
+ }
+ }
+ else
+ {
+ Privilege p = Privilege.privilegeForName(privName);
+ if (p == null)
+ {
+ // FIXME -- Generate an administrative alert.
+ }
+ else
+ {
+ newPrivileges.add(p);
+ }
+ }
+ }
+ }
+ }
+
+ for (Privilege p : removePrivileges)
+ {
+ newPrivileges.remove(p);
+ }
+
+ privileges = newPrivileges;
+ }
+
+
+
+ /**
* Retrieves an opaque set of information that may be used for
* processing multi-stage SASL binds.
*
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/SchemaBackend.java b/opendj-sdk/opends/src/server/org/opends/server/backends/SchemaBackend.java
index 571c31f..6a4a349 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/SchemaBackend.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/SchemaBackend.java
@@ -57,6 +57,7 @@
import org.opends.server.api.AlertGenerator;
import org.opends.server.api.Backend;
+import org.opends.server.api.ClientConnection;
import org.opends.server.api.ConfigurableComponent;
import org.opends.server.api.MatchingRule;
import org.opends.server.config.BooleanConfigAttribute;
@@ -103,6 +104,7 @@
import org.opends.server.types.NameForm;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.ObjectClassType;
+import org.opends.server.types.Privilege;
import org.opends.server.types.RDN;
import org.opends.server.types.RestoreConfig;
import org.opends.server.types.ResultCode;
@@ -950,6 +952,20 @@
String.valueOf(modifyOperation));
+ // Make sure that the authenticated user has the necessary UPDATE_SCHEMA
+ // privilege.
+ ClientConnection clientConnection = modifyOperation.getClientConnection();
+ if (! clientConnection.hasPrivilege(Privilege.UPDATE_SCHEMA,
+ modifyOperation))
+ {
+ int msgID = MSGID_SCHEMA_MODIFY_INSUFFICIENT_PRIVILEGES;
+ String message = getMessage(msgID);
+ throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ message, msgID);
+ }
+
+
+
// At present, we only allow the addition of new attribute types,
// object classes, name forms, DIT content rules, DIT structure rules, and
// matching rule uses. We will not support removing or replacing existing
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/task/Task.java b/opendj-sdk/opends/src/server/org/opends/server/backends/task/Task.java
index f147227..e465ee4 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/task/Task.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/task/Task.java
@@ -40,6 +40,7 @@
import java.util.concurrent.locks.Lock;
import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.Operation;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
@@ -114,6 +115,9 @@
// The time that this task was scheduled to start processing.
private long scheduledStartTime;
+ // The operation used to create this task in the server.
+ private Operation operation;
+
// The ID of the recurring task with which this task is associated.
private String recurringTaskID;
@@ -473,6 +477,40 @@
/**
+ * Retrieves the operation used to create this task in the server. Note that
+ * this will only be available when the task is first added to the scheduler,
+ * and it should only be accessed from within the {@code initializeTask}
+ * method (and even that method should not depend on it always being
+ * available, since it will not be available if the server is restarted and
+ * the task needs to be reinitialized).
+ *
+ * @return The operation used to create this task in the server, or
+ * {@code null} if it is not available.
+ */
+ public final Operation getOperation()
+ {
+ assert debugEnter(CLASS_NAME, "getOperation");
+
+ return operation;
+ }
+
+
+
+ /**
+ * Specifies the operation used to create this task in the server.
+ *
+ * @param operation The operation used to create this task in the server.
+ */
+ public final void setOperation(Operation operation)
+ {
+ assert debugEnter(CLASS_NAME, "setOperation", String.valueOf(operation));
+
+ this.operation = operation;
+ }
+
+
+
+ /**
* Retrieves the unique identifier assigned to this task.
*
* @return The unique identifier assigned to this task.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskBackend.java b/opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskBackend.java
index a486838..df42928 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskBackend.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskBackend.java
@@ -608,7 +608,7 @@
// treat the provided entry like a scheduled task.
if (parentDN.equals(scheduledTaskParentDN))
{
- Task task = taskScheduler.entryToScheduledTask(entry);
+ Task task = taskScheduler.entryToScheduledTask(entry, addOperation);
taskScheduler.scheduleTask(task, true);
return;
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskScheduler.java b/opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskScheduler.java
index e23846c..db0c213 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskScheduler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskScheduler.java
@@ -43,6 +43,7 @@
import org.opends.server.api.AlertGenerator;
import org.opends.server.api.DirectoryThread;
import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.Operation;
import org.opends.server.core.SearchOperation;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
@@ -1044,7 +1045,7 @@
{
try
{
- Task task = entryToScheduledTask(entry);
+ Task task = entryToScheduledTask(entry, null);
if (TaskState.isDone(task.getTaskState()))
{
completedTasks.add(task);
@@ -1792,14 +1793,16 @@
* Decodes the contents of the provided entry as a scheduled task. The
* resulting task will not actually be scheduled for processing.
*
- * @param entry The entry to decode as a scheduled task.
+ * @param entry The entry to decode as a scheduled task.
+ * @param operation The operation used to create this task in the server, or
+ * {@code null} if the operation is not available.
*
* @return The scheduled task decoded from the provided entry.
*
* @throws DirectoryException If the provided entry cannot be decoded as a
* scheduled task.
*/
- public Task entryToScheduledTask(Entry entry)
+ public Task entryToScheduledTask(Entry entry, Operation operation)
throws DirectoryException
{
assert debugEnter(CLASS_NAME, "entryToScheduledTask",
@@ -1916,7 +1919,9 @@
}
+ task.setOperation(operation);
task.initializeTask();
+ task.setOperation(null);
return task;
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/config/ConfigConstants.java b/opendj-sdk/opends/src/server/org/opends/server/config/ConfigConstants.java
index 2891767..ee1f4cc 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/config/ConfigConstants.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/config/ConfigConstants.java
@@ -544,6 +544,15 @@
/**
+ * The name of the configuration attribute that specifies the set of
+ * privileges that root users should automatically be granted in the server.
+ */
+ public static final String ATTR_DEFAULT_ROOT_PRIVILEGE_NAME =
+ NAME_PREFIX_CFG + "default-root-privilege-name";
+
+
+
+ /**
* The name of the configuration attribute that indicates which clients
* should not be allowed to establish connections.
*/
@@ -3149,6 +3158,14 @@
/**
+ * The name of the operational attribute that will appear in a user's entry to
+ * specify the set of privileges assigned to that user.
+ */
+ public static final String OP_ATTR_PRIVILEGE_NAME = "ds-privilege-name";
+
+
+
+ /**
* The name of the operational attribute that will appear in a user's entry
* to indicate the time that the password was last changed.
*/
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/AddOperation.java b/opendj-sdk/opends/src/server/org/opends/server/core/AddOperation.java
index 0f3e85b..6d0bd25 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/AddOperation.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/AddOperation.java
@@ -76,6 +76,7 @@
import org.opends.server.types.LockManager;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.OperationType;
+import org.opends.server.types.Privilege;
import org.opends.server.types.RDN;
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchFilter;
@@ -1397,6 +1398,20 @@
operationalAttributes);
+ // Check to see if the entry includes a privilege specification. If so,
+ // then the requester must have the PRIVILEGE_CHANGE privilege.
+ AttributeType privType =
+ DirectoryServer.getAttributeType(OP_ATTR_PRIVILEGE_NAME, true);
+ if (entry.hasAttribute(privType) &&
+ (! clientConnection.hasPrivilege(Privilege.PRIVILEGE_CHANGE, this)))
+ {
+ int msgID = MSGID_ADD_CHANGE_PRIVILEGE_INSUFFICIENT_PRIVILEGES;
+ appendErrorMessage(getMessage(msgID));
+ setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ break addProcessing;
+ }
+
+
// Check to see if the entry contains one or more passwords and if they
// are valid in accordance with the password policies associated with
// the user. Also perform any encoding that might be required by
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/CompareOperation.java b/opendj-sdk/opends/src/server/org/opends/server/core/CompareOperation.java
index a811667..221cc91 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/CompareOperation.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/CompareOperation.java
@@ -57,6 +57,7 @@
import org.opends.server.types.Entry;
import org.opends.server.types.LockManager;
import org.opends.server.types.OperationType;
+import org.opends.server.types.Privilege;
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchFilter;
import org.opends.server.types.operation.PostOperationCompareOperation;
@@ -651,6 +652,20 @@
}
+ // If the target entry is in the server configuration, then make sure the
+ // requester has the CONFIG_READ privilege.
+ if (DirectoryServer.getConfigHandler().handlesEntry(entryDN) &&
+ (! clientConnection.hasPrivilege(Privilege.CONFIG_READ, this)))
+ {
+ int msgID = MSGID_COMPARE_CONFIG_INSUFFICIENT_PRIVILEGES;
+ appendErrorMessage(getMessage(msgID));
+ setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ skipPostOperation = true;
+
+ break compareProcessing;
+ }
+
+
// Check for and handle a request to cancel this operation.
if (cancelRequest != null)
{
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java b/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
index cf95ab6..831cad5 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -146,6 +146,7 @@
import org.opends.server.types.ObjectClassType;
import org.opends.server.types.OperatingSystem;
import org.opends.server.types.OperationType;
+import org.opends.server.types.Privilege;
import org.opends.server.types.RDN;
import org.opends.server.types.ResultCode;
import org.opends.server.types.Schema;
@@ -473,6 +474,9 @@
// The special backend used for the Directory Server root DSE.
private RootDSEBackend rootDSEBackend;
+ // The root DN config manager for the server.
+ private RootDNConfigManager rootDNConfigManager;
+
// The SASL mechanism config manager for the Directory Server.
private SASLConfigManager saslConfigManager;
@@ -982,7 +986,8 @@
// Initialize the root DNs.
- new RootDNConfigManager().initializeRootDNs();
+ rootDNConfigManager = new RootDNConfigManager();
+ rootDNConfigManager.initializeRootDNs();
// Initialize the group manager.
@@ -5007,6 +5012,22 @@
/**
+ * Retrieves the set of privileges that should automatically be granted to
+ * root users when they authenticate.
+ *
+ * @return The set of privileges that should automatically be granted to root
+ * users when they authenticate.
+ */
+ public static Set<Privilege> getRootPrivileges()
+ {
+ assert debugEnter(CLASS_NAME, "getRootPrivileges");
+
+ return directoryServer.rootDNConfigManager.getRootPrivileges();
+ }
+
+
+
+ /**
* Retrieves the DNs for the root users configured in the Directory Server.
* Note that this set should only contain the actual DNs for the root users
* and not any alternate DNs. Also, the contents of the returned set must not
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/ModifyOperation.java b/opendj-sdk/opends/src/server/org/opends/server/core/ModifyOperation.java
index 999c39c..be01a29 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/ModifyOperation.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/ModifyOperation.java
@@ -81,6 +81,7 @@
import org.opends.server.types.Modification;
import org.opends.server.types.ModificationType;
import org.opends.server.types.OperationType;
+import org.opends.server.types.Privilege;
import org.opends.server.types.RDN;
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchFilter;
@@ -1283,6 +1284,18 @@
pwPolicyState.getPasswordAttribute()))
{
passwordChanged = true;
+ if (! selfChange)
+ {
+ if (! clientConnection.hasPrivilege(Privilege.PASSWORD_RESET,
+ this))
+ {
+ int msgID = MSGID_MODIFY_PWRESET_INSUFFICIENT_PRIVILEGES;
+ appendErrorMessage(getMessage(msgID));
+ setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ break modifyProcessing;
+ }
+ }
+
break;
}
}
@@ -1371,6 +1384,22 @@
}
+ // See if the attribute is one which controls the privileges available
+ // for a user. If it is, then the client must have the
+ // PRIVILEGE_CHANGE privilege.
+ if (t.hasName(OP_ATTR_PRIVILEGE_NAME))
+ {
+ if (! clientConnection.hasPrivilege(Privilege.PRIVILEGE_CHANGE,
+ this))
+ {
+ int msgID = MSGID_MODIFY_CHANGE_PRIVILEGE_INSUFFICIENT_PRIVILEGES;
+ appendErrorMessage(getMessage(msgID));
+ setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ break modifyProcessing;
+ }
+ }
+
+
// If the modification is updating the password attribute, then
// perform any necessary password policy processing. This processing
// should be skipped for synchronization operations.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/RootDNConfigManager.java b/opendj-sdk/opends/src/server/org/opends/server/core/RootDNConfigManager.java
index d4c9d95..0affa1e 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/RootDNConfigManager.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/RootDNConfigManager.java
@@ -22,7 +22,7 @@
* CDDL HEADER END
*
*
- * Portions Copyright 2006 Sun Microsystems, Inc.
+ * Portions Copyright 2006-2007 Sun Microsystems, Inc.
*/
package org.opends.server.core;
@@ -30,22 +30,29 @@
import java.util.ArrayList;
import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.opends.server.api.ConfigAddListener;
import org.opends.server.api.ConfigChangeListener;
import org.opends.server.api.ConfigDeleteListener;
import org.opends.server.api.ConfigHandler;
+import org.opends.server.api.ConfigurableComponent;
+import org.opends.server.config.ConfigAttribute;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.config.DNConfigAttribute;
+import org.opends.server.config.MultiChoiceConfigAttribute;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.DN;
import org.opends.server.types.ErrorLogCategory;
import org.opends.server.types.ErrorLogSeverity;
import org.opends.server.types.InitializationException;
+import org.opends.server.types.Privilege;
import org.opends.server.types.ResultCode;
import static org.opends.server.config.ConfigConstants.*;
@@ -66,7 +73,8 @@
* DN for use when binding to the server.
*/
public class RootDNConfigManager
- implements ConfigChangeListener, ConfigAddListener, ConfigDeleteListener
+ implements ConfigChangeListener, ConfigAddListener, ConfigDeleteListener,
+ ConfigurableComponent
{
/**
* The fully-qualified name of this class for debugging purposes.
@@ -80,6 +88,13 @@
// bind DNs for that user.
private ConcurrentHashMap<DN,List<DN>> bindMappings;
+ // The DN of the entry that serves as the base for the root DN
+ // configuration entries.
+ private DN rootDNConfigBaseDN;
+
+ // The set of privileges that will be automatically inherited by root users.
+ private LinkedHashSet<Privilege> rootPrivileges;
+
/**
@@ -116,8 +131,8 @@
ConfigEntry baseEntry;
try
{
- DN configBase = DN.decode(DN_ROOT_DN_CONFIG_BASE);
- baseEntry = configHandler.getConfigEntry(configBase);
+ rootDNConfigBaseDN = DN.decode(DN_ROOT_DN_CONFIG_BASE);
+ baseEntry = configHandler.getConfigEntry(rootDNConfigBaseDN);
}
catch (Exception e)
{
@@ -136,11 +151,62 @@
}
+ // Get the set of privileges that root users should have by default.
+ rootPrivileges = new LinkedHashSet<Privilege>(
+ Privilege.getDefaultRootPrivileges());
+
+ int msgID = MSGID_CONFIG_ROOTDN_DESCRIPTION_ROOT_PRIVILEGE;
+ MultiChoiceConfigAttribute rootPrivStub =
+ new MultiChoiceConfigAttribute(ATTR_DEFAULT_ROOT_PRIVILEGE_NAME,
+ getMessage(msgID), false, true, false,
+ Privilege.getPrivilegeNames());
+ try
+ {
+ MultiChoiceConfigAttribute rootPrivAttr =
+ (MultiChoiceConfigAttribute)
+ baseEntry.getConfigAttribute(rootPrivStub);
+ if (rootPrivAttr != null)
+ {
+ ArrayList<Privilege> privList = new ArrayList<Privilege>();
+ for (String value : rootPrivAttr.activeValues())
+ {
+ String privName = toLowerCase(value);
+ Privilege p = Privilege.privilegeForName(privName);
+ if (p == null)
+ {
+ msgID = MSGID_CONFIG_ROOTDN_UNRECOGNIZED_PRIVILEGE;
+ String message = getMessage(msgID, ATTR_DEFAULT_ROOT_PRIVILEGE_NAME,
+ String.valueOf(rootDNConfigBaseDN),
+ String.valueOf(value));
+ logError(ErrorLogCategory.CONFIGURATION,
+ ErrorLogSeverity.SEVERE_WARNING, message, msgID);
+ }
+ else
+ {
+ privList.add(p);
+ }
+ }
+
+ rootPrivileges = new LinkedHashSet<Privilege>(privList);
+ }
+ }
+ catch (Exception e)
+ {
+ assert debugException(CLASS_NAME, "initializeRootDNs", e);
+
+ msgID = MSGID_CONFIG_ROOTDN_ERROR_DETERMINING_ROOT_PRIVILEGES;
+ String message = getMessage(msgID, stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message, e);
+ }
+
+
// Register with the configuration base entry as an add and delete listener.
// So that we will be notified of attempts to create or remove root DN
- // entries.
+ // entries. Also, register with the server as a configurable component so
+ // that we can detect and apply any changes to the root
baseEntry.registerAddListener(this);
baseEntry.registerDeleteListener(this);
+ DirectoryServer.registerConfigurableComponent(this);
// See if the base entry has any children. If not, then we don't need to
@@ -206,6 +272,22 @@
/**
+ * Retrieves the set of privileges that should automatically be granted to
+ * root users when they authenticate.
+ *
+ * @return The set of privileges that should automatically be granted to root
+ * users when they authenticate.
+ */
+ public Set<Privilege> getRootPrivileges()
+ {
+ assert debugEnter(CLASS_NAME, "getRootPrivileges");
+
+ return rootPrivileges;
+ }
+
+
+
+ /**
* Indicates whether the configuration entry that will result from a proposed
* modification is acceptable to this change listener.
*
@@ -638,5 +720,225 @@
return new ConfigChangeResult(resultCode, adminActionRequired);
}
+
+
+
+ /**
+ * Retrieves the DN of the configuration entry with which this
+ * component is associated.
+ *
+ * @return The DN of the configuration entry with which this
+ * component is associated.
+ */
+ public DN getConfigurableComponentEntryDN()
+ {
+ assert debugEnter(CLASS_NAME, "getConfigurableComponentEntryDN");
+
+ return rootDNConfigBaseDN;
+ }
+
+
+
+ /**
+ * Retrieves the set of configuration attributes that are associated
+ * with this configurable component.
+ *
+ * @return The set of configuration attributes that are associated
+ * with this configurable component.
+ */
+ public List<ConfigAttribute> getConfigurationAttributes()
+ {
+ assert debugEnter(CLASS_NAME, "getConfigurationAttributes");
+
+ LinkedList<ConfigAttribute> attrList = new LinkedList<ConfigAttribute>();
+
+ LinkedList<String> currentValues = new LinkedList<String>();
+ for (Privilege p : rootPrivileges)
+ {
+ currentValues.add(p.getName());
+ }
+
+ int msgID = MSGID_CONFIG_ROOTDN_DESCRIPTION_ROOT_PRIVILEGE;
+ attrList.add(new MultiChoiceConfigAttribute(
+ ATTR_DEFAULT_ROOT_PRIVILEGE_NAME, getMessage(msgID),
+ false, true, false, Privilege.getPrivilegeNames(),
+ currentValues));
+
+ return attrList;
+ }
+
+
+
+ /**
+ * Indicates whether the provided configuration entry has an
+ * acceptable configuration for this component. If it does not,
+ * then detailed information about the problem(s) should be added to
+ * the provided list.
+ *
+ * @param configEntry The configuration entry for which to
+ * make the determination.
+ * @param unacceptableReasons A list that can be used to hold
+ * messages about why the provided
+ * entry does not have an acceptable
+ * configuration.
+ *
+ * @return <CODE>true</CODE> if the provided entry has an
+ * acceptable configuration for this component, or
+ * <CODE>false</CODE> if not.
+ */
+ public boolean hasAcceptableConfiguration(ConfigEntry configEntry,
+ List<String> unacceptableReasons)
+ {
+ assert debugEnter(CLASS_NAME, "hasAcceptableConfiguration",
+ String.valueOf(configEntry), "List<String>");
+
+
+ int msgID = MSGID_CONFIG_ROOTDN_DESCRIPTION_ROOT_PRIVILEGE;
+ MultiChoiceConfigAttribute rootPrivStub =
+ new MultiChoiceConfigAttribute(ATTR_DEFAULT_ROOT_PRIVILEGE_NAME,
+ getMessage(msgID), false, true, false,
+ Privilege.getPrivilegeNames());
+ try
+ {
+ MultiChoiceConfigAttribute rootPrivAttr =
+ (MultiChoiceConfigAttribute)
+ configEntry.getConfigAttribute(rootPrivStub);
+ if (rootPrivAttr != null)
+ {
+ for (String value : rootPrivAttr.activeValues())
+ {
+ String privName = toLowerCase(value);
+ Privilege p = Privilege.privilegeForName(privName);
+ if (p == null)
+ {
+ msgID = MSGID_CONFIG_ROOTDN_UNRECOGNIZED_PRIVILEGE;
+ String message = getMessage(msgID, ATTR_DEFAULT_ROOT_PRIVILEGE_NAME,
+ String.valueOf(rootDNConfigBaseDN),
+ String.valueOf(value));
+ unacceptableReasons.add(message);
+ return false;
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ assert debugException(CLASS_NAME, "initializeRootDNs", e);
+
+ msgID = MSGID_CONFIG_ROOTDN_ERROR_DETERMINING_ROOT_PRIVILEGES;
+ String message = getMessage(msgID, stackTraceToSingleLineString(e));
+ unacceptableReasons.add(message);
+ return false;
+ }
+
+
+ // If we've gotten here, then everything looks OK.
+ return true;
+ }
+
+
+
+ /**
+ * Makes a best-effort attempt to apply the configuration contained
+ * in the provided entry. Information about the result of this
+ * processing should be added to the provided message list.
+ * Information should always be added to this list if a
+ * configuration change could not be applied. If detailed results
+ * are requested, then information about the changes applied
+ * successfully (and optionally about parameters that were not
+ * changed) should also be included.
+ *
+ * @param configEntry The entry containing the new
+ * configuration to apply for this
+ * component.
+ * @param detailedResults Indicates whether detailed information
+ * about the processing should be added to
+ * the list.
+ *
+ * @return Information about the result of the configuration
+ * update.
+ */
+ public ConfigChangeResult applyNewConfiguration(ConfigEntry configEntry,
+ boolean detailedResults)
+ {
+ assert debugEnter(CLASS_NAME, "applyNewConfiguration",
+ String.valueOf(configEntry),
+ String.valueOf(detailedResults));
+
+
+ ResultCode resultCode = ResultCode.SUCCESS;
+ ArrayList<String> messages = new ArrayList<String>();
+ boolean adminActionRequired = false;
+
+
+ LinkedHashSet<Privilege> newRootPrivileges =
+ new LinkedHashSet<Privilege>(Privilege.getDefaultRootPrivileges());
+
+ int msgID = MSGID_CONFIG_ROOTDN_DESCRIPTION_ROOT_PRIVILEGE;
+ MultiChoiceConfigAttribute rootPrivStub =
+ new MultiChoiceConfigAttribute(ATTR_DEFAULT_ROOT_PRIVILEGE_NAME,
+ getMessage(msgID), false, true, false,
+ Privilege.getPrivilegeNames());
+ try
+ {
+ MultiChoiceConfigAttribute rootPrivAttr =
+ (MultiChoiceConfigAttribute)
+ configEntry.getConfigAttribute(rootPrivStub);
+ if (rootPrivAttr != null)
+ {
+ ArrayList<Privilege> privList = new ArrayList<Privilege>();
+ for (String value : rootPrivAttr.activeValues())
+ {
+ String privName = toLowerCase(value);
+ Privilege p = Privilege.privilegeForName(privName);
+ if (p == null)
+ {
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ resultCode = ResultCode.INVALID_ATTRIBUTE_SYNTAX;
+ }
+
+ msgID = MSGID_CONFIG_ROOTDN_UNRECOGNIZED_PRIVILEGE;
+ messages.add(getMessage(msgID, ATTR_DEFAULT_ROOT_PRIVILEGE_NAME,
+ String.valueOf(rootDNConfigBaseDN),
+ String.valueOf(value)));
+ }
+ else
+ {
+ privList.add(p);
+ }
+ }
+
+ newRootPrivileges = new LinkedHashSet<Privilege>(privList);
+ }
+ }
+ catch (Exception e)
+ {
+ assert debugException(CLASS_NAME, "initializeRootDNs", e);
+
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ resultCode = ResultCode.INVALID_ATTRIBUTE_SYNTAX;
+ }
+
+ msgID = MSGID_CONFIG_ROOTDN_ERROR_DETERMINING_ROOT_PRIVILEGES;
+ messages.add(getMessage(msgID, stackTraceToSingleLineString(e)));
+ }
+
+
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ rootPrivileges = newRootPrivileges;
+
+ if (detailedResults)
+ {
+ msgID = MSGID_CONFIG_ROOTDN_UPDATED_PRIVILEGES;
+ messages.add(getMessage(msgID));
+ }
+ }
+
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java b/opendj-sdk/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java
index 8ec35c3..0466c65 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java
@@ -22,7 +22,7 @@
* CDDL HEADER END
*
*
- * Portions Copyright 2006 Sun Microsystems, Inc.
+ * Portions Copyright 2006-2007 Sun Microsystems, Inc.
*/
package org.opends.server.extensions;
@@ -57,6 +57,7 @@
import javax.crypto.Mac;
import org.opends.server.api.AlertGenerator;
+import org.opends.server.api.ClientConnection;
import org.opends.server.api.ConfigAddListener;
import org.opends.server.api.ConfigChangeListener;
import org.opends.server.api.ConfigDeleteListener;
@@ -72,6 +73,7 @@
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.SearchOperation;
import org.opends.server.tools.LDIFModify;
+import org.opends.server.types.AttributeType;
import org.opends.server.types.BackupConfig;
import org.opends.server.types.BackupDirectory;
import org.opends.server.types.BackupInfo;
@@ -86,6 +88,8 @@
import org.opends.server.types.InitializationException;
import org.opends.server.types.LDIFImportConfig;
import org.opends.server.types.LDIFExportConfig;
+import org.opends.server.types.Modification;
+import org.opends.server.types.Privilege;
import org.opends.server.types.ResultCode;
import org.opends.server.types.RestoreConfig;
import org.opends.server.types.SearchFilter;
@@ -122,6 +126,18 @@
+ /**
+ * The privilege array containing both the CONFIG_READ and CONFIG_WRITE
+ * privileges.
+ */
+ private static final Privilege[] CONFIG_READ_AND_WRITE =
+ {
+ Privilege.CONFIG_READ,
+ Privilege.CONFIG_WRITE
+ };
+
+
+
// The mapping that holds all of the configuration entries that have been read
// from the LDIF file.
private ConcurrentHashMap<DN,ConfigEntry> configEntries;
@@ -959,6 +975,22 @@
String.valueOf(addOperation));
+ // If there is an add operation, then make sure that the associated user has
+ // both the CONFIG_READ and CONFIG_WRITE privileges.
+ if (addOperation != null)
+ {
+ ClientConnection clientConnection = addOperation.getClientConnection();
+ if (! (clientConnection.hasAllPrivileges(CONFIG_READ_AND_WRITE,
+ addOperation)))
+ {
+ int msgID = MSGID_CONFIG_FILE_ADD_INSUFFICIENT_PRIVILEGES;
+ String message = getMessage(msgID);
+ throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ message, msgID);
+ }
+ }
+
+
// Grab the config lock to ensure that only one config update may be in
// progress at any given time.
configLock.lock();
@@ -1095,6 +1127,22 @@
String.valueOf(deleteOperation));
+ // If there is a delete operation, then make sure that the associated user
+ // has both the CONFIG_READ and CONFIG_WRITE privileges.
+ if (deleteOperation != null)
+ {
+ ClientConnection clientConnection = deleteOperation.getClientConnection();
+ if (! (clientConnection.hasAllPrivileges(CONFIG_READ_AND_WRITE,
+ deleteOperation)))
+ {
+ int msgID = MSGID_CONFIG_FILE_DELETE_INSUFFICIENT_PRIVILEGES;
+ String message = getMessage(msgID);
+ throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ message, msgID);
+ }
+ }
+
+
// Grab the config lock to ensure that only one config update may be in
// progress at any given time.
configLock.lock();
@@ -1227,6 +1275,44 @@
String.valueOf(modifyOperation));
+ // If there is a modify operation, then make sure that the associated user
+ // has both the CONFIG_READ and CONFIG_WRITE privileges. Also, if the
+ // operation targets the set of root privileges then make sure the user has
+ // the PRIVILEGE_CHANGE privilege.
+ if (modifyOperation != null)
+ {
+ ClientConnection clientConnection = modifyOperation.getClientConnection();
+ if (! (clientConnection.hasAllPrivileges(CONFIG_READ_AND_WRITE,
+ modifyOperation)))
+ {
+ int msgID = MSGID_CONFIG_FILE_MODIFY_INSUFFICIENT_PRIVILEGES;
+ String message = getMessage(msgID);
+ throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ message, msgID);
+ }
+
+ AttributeType privType =
+ DirectoryServer.getAttributeType(ATTR_DEFAULT_ROOT_PRIVILEGE_NAME,
+ true);
+ for (Modification m : modifyOperation.getModifications())
+ {
+ if (m.getAttribute().getAttributeType().equals(privType))
+ {
+ if (! clientConnection.hasPrivilege(Privilege.PRIVILEGE_CHANGE,
+ modifyOperation))
+ {
+ int msgID = MSGID_CONFIG_FILE_MODIFY_PRIVS_INSUFFICIENT_PRIVILEGES;
+ String message = getMessage(msgID);
+ throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ message, msgID);
+ }
+
+ break;
+ }
+ }
+ }
+
+
// Grab the config lock to ensure that only one config update may be in
// progress at any given time.
configLock.lock();
@@ -1381,6 +1467,23 @@
String.valueOf(entry), String.valueOf(modifyDNOperation));
+ // If there is a modify DN operation, then make sure that the associated
+ // user has both the CONFIG_READ and CONFIG_WRITE privileges.
+ if (modifyDNOperation != null)
+ {
+ ClientConnection clientConnection =
+ modifyDNOperation.getClientConnection();
+ if (! (clientConnection.hasAllPrivileges(CONFIG_READ_AND_WRITE,
+ modifyDNOperation)))
+ {
+ int msgID = MSGID_CONFIG_FILE_MODDN_INSUFFICIENT_PRIVILEGES;
+ String message = getMessage(msgID);
+ throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ message, msgID);
+ }
+ }
+
+
// Modify DN operations will not be allowed in the configuration, so this
// will always throw an exception.
int msgID = MSGID_CONFIG_FILE_MODDN_NOT_ALLOWED;
@@ -1407,6 +1510,17 @@
assert debugEnter(CLASS_NAME, "search", String.valueOf(searchOperation));
+ // Make sure that the associated user has the CONFIG_READ privilege.
+ ClientConnection clientConnection = searchOperation.getClientConnection();
+ if (! clientConnection.hasPrivilege(Privilege.CONFIG_READ, searchOperation))
+ {
+ int msgID = MSGID_CONFIG_FILE_SEARCH_INSUFFICIENT_PRIVILEGES;
+ String message = getMessage(msgID);
+ throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ message, msgID);
+ }
+
+
// First, get the base DN for the search and make sure that it exists.
DN baseDN = searchOperation.getBaseDN();
ConfigEntry baseEntry = configEntries.get(baseDN);
diff --git a/opendj-sdk/opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java b/opendj-sdk/opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java
index 5eafa77..000f9b9 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java
@@ -74,6 +74,7 @@
import org.opends.server.types.LockManager;
import org.opends.server.types.Modification;
import org.opends.server.types.ModificationType;
+import org.opends.server.types.Privilege;
import org.opends.server.types.ResultCode;
import static org.opends.server.config.ConfigConstants.*;
@@ -494,10 +495,34 @@
// Determine whether the user is changing his own password or if it's an
- // administrative reset.
- boolean selfChange = ((userIdentity == null) ||
- (requestorEntry == null) ||
- userDN.equals(requestorEntry.getDN()));
+ // administrative reset. If it's an administrative reset, then the
+ // requester must have the PASSWORD_RESET privilege.
+ boolean selfChange;
+ if (userIdentity == null)
+ {
+ selfChange = true;
+ }
+ else if (requestorEntry == null)
+ {
+ selfChange = (oldPassword != null);
+ }
+ else
+ {
+ selfChange = userDN.equals(requestorEntry.getDN());
+ }
+
+ if (! selfChange)
+ {
+ ClientConnection clientConnection = operation.getClientConnection();
+ if (! clientConnection.hasPrivilege(Privilege.PASSWORD_RESET,
+ operation))
+ {
+ int msgID = MSGID_EXTOP_PASSMOD_INSUFFICIENT_PRIVILEGES;
+ operation.appendErrorMessage(getMessage(msgID));
+ operation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ return;
+ }
+ }
// See if the account is locked. If so, then reject the request.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/messages/BackendMessages.java b/opendj-sdk/opends/src/server/org/opends/server/messages/BackendMessages.java
index 0f5e9c9..07671fc 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/messages/BackendMessages.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/messages/BackendMessages.java
@@ -3171,6 +3171,16 @@
/**
+ * The message ID for the message that will be used if a user attempts to
+ * modify the server schema without the appropriate privilege. This does not
+ * take any arguments.
+ */
+ public static final int MSGID_SCHEMA_MODIFY_INSUFFICIENT_PRIVILEGES =
+ CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 293;
+
+
+
+ /**
* Associates a set of generic messages with the message IDs defined in this
* class.
*/
@@ -3397,6 +3407,9 @@
registerMessage(MSGID_SCHEMA_DELETE_NOT_SUPPORTED,
"Unwilling to remove entry \"%s\" because delete " +
"operations are not supported in the schema backend.");
+ registerMessage(MSGID_SCHEMA_MODIFY_INSUFFICIENT_PRIVILEGES,
+ "You do not have sufficient privileges to modify the " +
+ "Directory Server schema.");
registerMessage(MSGID_SCHEMA_MODIFY_NOT_SUPPORTED,
"Unwilling to update entry \"%s\" because modify " +
"operations are not yet supported in the schema " +
diff --git a/opendj-sdk/opends/src/server/org/opends/server/messages/ConfigMessages.java b/opendj-sdk/opends/src/server/org/opends/server/messages/ConfigMessages.java
index af9d07a..7c46619 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/messages/ConfigMessages.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/messages/ConfigMessages.java
@@ -6389,6 +6389,110 @@
CATEGORY_MASK_CONFIG | SEVERITY_MASK_SEVERE_ERROR | 593;
+
+ /**
+ * The message ID for the message that will be used as the description for the
+ * default root privilege names configuration attribute. This does not take
+ * any arguments.
+ */
+ public static final int MSGID_CONFIG_ROOTDN_DESCRIPTION_ROOT_PRIVILEGE =
+ CATEGORY_MASK_CONFIG | SEVERITY_MASK_SEVERE_ERROR | 594;
+
+
+
+ /**
+ * The message ID for the message that will be used if the set of root
+ * privileges contains an unrecognized privilege. This takes three arguments,
+ * which are the name of the attribute holding the privilege names, the DN of
+ * the configuration entry, and the name of the unrecognized privilege.
+ */
+ public static final int MSGID_CONFIG_ROOTDN_UNRECOGNIZED_PRIVILEGE =
+ CATEGORY_MASK_CONFIG | SEVERITY_MASK_SEVERE_WARNING | 595;
+
+
+
+ /**
+ * The message ID for the message that will be used if an error occurs while
+ * attempting to determine the set of root privileges. This takes a single
+ * argument, which is a stack trace of the exception that was caught.
+ */
+ public static final int
+ MSGID_CONFIG_ROOTDN_ERROR_DETERMINING_ROOT_PRIVILEGES =
+ CATEGORY_MASK_CONFIG | SEVERITY_MASK_SEVERE_ERROR | 596;
+
+
+
+ /**
+ * The message ID for the message that will be used to indicate that the set
+ * of root privileges has been updated. This does not take any arguments.
+ */
+ public static final int MSGID_CONFIG_ROOTDN_UPDATED_PRIVILEGES =
+ CATEGORY_MASK_CONFIG | SEVERITY_MASK_INFORMATIONAL | 597;
+
+
+
+ /**
+ * The message ID for the message that will be used if an attempt is made to
+ * perform an add operation in the server configuration but the user doesn't
+ * have the necessary privileges to do so. This does not take any arguments.
+ */
+ public static final int MSGID_CONFIG_FILE_ADD_INSUFFICIENT_PRIVILEGES =
+ CATEGORY_MASK_CONFIG | SEVERITY_MASK_MILD_ERROR | 598;
+
+
+
+ /**
+ * The message ID for the message that will be used if an attempt is made to
+ * perform a delete operation in the server configuration but the user doesn't
+ * have the necessary privileges to do so. This does not take any arguments.
+ */
+ public static final int MSGID_CONFIG_FILE_DELETE_INSUFFICIENT_PRIVILEGES =
+ CATEGORY_MASK_CONFIG | SEVERITY_MASK_MILD_ERROR | 599;
+
+
+
+ /**
+ * The message ID for the message that will be used if an attempt is made to
+ * perform a modify operation in the server configuration but the user doesn't
+ * have the necessary privileges to do so. This does not take any arguments.
+ */
+ public static final int MSGID_CONFIG_FILE_MODIFY_INSUFFICIENT_PRIVILEGES =
+ CATEGORY_MASK_CONFIG | SEVERITY_MASK_MILD_ERROR | 600;
+
+
+
+ /**
+ * The message ID for the message that will be used if an attempt is made to
+ * perform a modify DN operation in the server configuration but the user
+ * doesn't have the necessary privileges to do so. This does not take any
+ * arguments.
+ */
+ public static final int MSGID_CONFIG_FILE_MODDN_INSUFFICIENT_PRIVILEGES =
+ CATEGORY_MASK_CONFIG | SEVERITY_MASK_MILD_ERROR | 601;
+
+
+
+ /**
+ * The message ID for the message that will be used if an attempt is made to
+ * perform a search operation in the server configuration but the user doesn't
+ * have the necessary privileges to do so. This does not take any arguments.
+ */
+ public static final int MSGID_CONFIG_FILE_SEARCH_INSUFFICIENT_PRIVILEGES =
+ CATEGORY_MASK_CONFIG | SEVERITY_MASK_MILD_ERROR | 602;
+
+
+
+ /**
+ * The message ID for the message that will be used if an attempt is made to
+ * modify the set of default root privileges but the user doesn't have the
+ * necessary privileges to do so. This does not take any arguments.
+ */
+ public static final int
+ MSGID_CONFIG_FILE_MODIFY_PRIVS_INSUFFICIENT_PRIVILEGES =
+ CATEGORY_MASK_CONFIG | SEVERITY_MASK_MILD_ERROR | 603;
+
+
+
/**
* Associates a set of generic messages with the message IDs defined in this
* class.
@@ -6721,6 +6825,24 @@
"the server is online. The server configuration should " +
"only be managed using the administration utilities " +
"provided with the Directory Server.");
+ registerMessage(MSGID_CONFIG_FILE_ADD_INSUFFICIENT_PRIVILEGES,
+ "You do not have sufficient privileges to perform add " +
+ "operations in the Directory Server configuration.");
+ registerMessage(MSGID_CONFIG_FILE_DELETE_INSUFFICIENT_PRIVILEGES,
+ "You do not have sufficient privileges to perform delete " +
+ "operations in the Directory Server configuration.");
+ registerMessage(MSGID_CONFIG_FILE_MODIFY_INSUFFICIENT_PRIVILEGES,
+ "You do not have sufficient privileges to perform modify " +
+ "operations in the Directory Server configuration.");
+ registerMessage(MSGID_CONFIG_FILE_MODIFY_PRIVS_INSUFFICIENT_PRIVILEGES,
+ "You do not have sufficient privileges to change the set " +
+ "of default root privileges.");
+ registerMessage(MSGID_CONFIG_FILE_MODDN_INSUFFICIENT_PRIVILEGES,
+ "You do not have sufficient privileges to perform modify " +
+ "DN operations in the Directory Server configuration.");
+ registerMessage(MSGID_CONFIG_FILE_SEARCH_INSUFFICIENT_PRIVILEGES,
+ "You do not have sufficient privileges to perform search " +
+ "operations in the Directory Server configuration.");
registerMessage(MSGID_CONFIG_LOGGER_CANNOT_GET_BASE,
@@ -9032,6 +9154,24 @@
DN_ROOT_DN_CONFIG_BASE + " does not exist in the " +
"Directory Server configuration. This entry must be " +
"present for the server to function properly.");
+ registerMessage(MSGID_CONFIG_ROOTDN_DESCRIPTION_ROOT_PRIVILEGE,
+ "Specifies the set of privileges that should " +
+ "automatically be assigned to root users when they " +
+ "authenticate to the server.");
+ registerMessage(MSGID_CONFIG_ROOTDN_UNRECOGNIZED_PRIVILEGE,
+ "The set of default root privileges contained in " +
+ "configuration attribute %s of entry %s contains an " +
+ "unrecognized privilege %s.");
+ registerMessage(MSGID_CONFIG_ROOTDN_ERROR_DETERMINING_ROOT_PRIVILEGES,
+ "An error occurred while attempting to determine the " +
+ "set of privileges that root users should be granted by " +
+ "default: %s.");
+ registerMessage(MSGID_CONFIG_ROOTDN_UPDATED_PRIVILEGES,
+ "The set of privileges that will automatically be " +
+ "assigned to root users has been updated. This new " +
+ "privilege set will not apply to any existing " +
+ "connection already authenticated as a root user, but " +
+ "will used for any subsequent root user authentications.");
registerMessage(MSGID_CONFIG_ROOTDN_ENTRY_UNACCEPTABLE,
"Configuration entry %s does not contain a valid root DN " +
"configuration: %s. It will be ignored.");
diff --git a/opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java b/opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java
index 295310f..4a6f374 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java
@@ -6161,6 +6161,74 @@
/**
+ * The message ID for the message that will be used if a modify request
+ * includes an attempt to reset another user's password by an individual that
+ * does not have the appropriate privileges. This does not take any
+ * arguments.
+ */
+ public static final int MSGID_MODIFY_PWRESET_INSUFFICIENT_PRIVILEGES =
+ CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 589;
+
+
+
+ /**
+ * The message ID for the message that will be used if a compare request
+ * targets the server configuration but the requester doesn't have the
+ * appropriate privileges. This does not take any arguments.
+ */
+ public static final int MSGID_COMPARE_CONFIG_INSUFFICIENT_PRIVILEGES =
+ CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 590;
+
+
+
+ /**
+ * The message ID for the message that will be used if an attempt is made to
+ * add an entry with one or more privileges but the user doesn't have
+ * sufficient privilege to update privileges. This does not take any
+ * arguments.
+ */
+ public static final int MSGID_ADD_CHANGE_PRIVILEGE_INSUFFICIENT_PRIVILEGES =
+ CATEGORY_MASK_CORE | SEVERITY_MASK_SEVERE_ERROR | 591;
+
+
+
+ /**
+ * The message ID for the message that will be used if an attempt is made to
+ * modify the set of privileges contained in an entry but the user doesn't
+ * have sufficient privileges to make that change. This does not take any
+ * arguments.
+ */
+ public static final int
+ MSGID_MODIFY_CHANGE_PRIVILEGE_INSUFFICIENT_PRIVILEGES =
+ CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 592;
+
+
+
+ /**
+ * The message ID for the audit message that will be generated when a client
+ * attempts to perform a privileged operation that requires a single
+ * privilege. This takes five arguments, which are the connection ID, the
+ * operation ID, the authentication DN, the name of the requested privilege,
+ * and the result of the determination.
+ */
+ public static final int MSGID_CLIENTCONNECTION_AUDIT_HASPRIVILEGE =
+ CATEGORY_MASK_CORE | SEVERITY_MASK_INFORMATIONAL | 593;
+
+
+
+ /**
+ * The message ID for the audit message that will be generated when a client
+ * attempts to perform a privileged operation that requires a multiple
+ * privileges. This takes five arguments, which are the connection ID, the
+ * operation ID, the authentication DN, a formatted list of the names of the
+ * requested privileges, and the result of the determination.
+ */
+ public static final int MSGID_CLIENTCONNECTION_AUDIT_HASPRIVILEGES =
+ CATEGORY_MASK_CORE | SEVERITY_MASK_INFORMATIONAL | 594;
+
+
+
+ /**
* Associates a set of generic messages with the message IDs defined
* in this class.
*/
@@ -6932,6 +7000,9 @@
"attribute %s that is contained in the entry's RDN. " +
"All attributes used in the RDN must also be provided in " +
"the attribute list for the entry.");
+ registerMessage(MSGID_ADD_CHANGE_PRIVILEGE_INSUFFICIENT_PRIVILEGES,
+ "You do not have sufficient privileges to add entries " +
+ "that include privileges.");
registerMessage(MSGID_ADD_NOOP,
"The add operation was not actually performed in the " +
"Directory Server backend because the LDAP no-op control " +
@@ -7047,6 +7118,9 @@
"plugin working on referral %s.");
+ registerMessage(MSGID_COMPARE_CONFIG_INSUFFICIENT_PRIVILEGES,
+ "You do not have sufficient privileges to access the " +
+ "server configuration.");
registerMessage(MSGID_COMPARE_CANNOT_LOCK_ENTRY,
"The Directory Server was unable to obtain a read " +
"lock on entry %s after multiple attempts. Processing " +
@@ -7295,6 +7369,9 @@
"contained a critical control with OID %s that is not " +
"supported by the Directory Server for this type of " +
"operation.");
+ registerMessage(MSGID_MODIFY_PWRESET_INSUFFICIENT_PRIVILEGES,
+ "You do not have sufficient privileges to reset user " +
+ "passwords.");
registerMessage(MSGID_MODIFY_MUST_CHANGE_PASSWORD,
"You must change your password before you will be " +
"allowed to perform any other operations.");
@@ -7306,6 +7383,9 @@
"Entry %s cannot be modified because the modification " +
"attempted to set one or more new values for attribute " +
"%s which is marked OBSOLETE in the server schema.");
+ registerMessage(MSGID_MODIFY_CHANGE_PRIVILEGE_INSUFFICIENT_PRIVILEGES,
+ "You do not have sufficient privileges to modify the " +
+ "set of privileges contained in an entry.");
registerMessage(MSGID_MODIFY_PASSWORDS_CANNOT_HAVE_OPTIONS,
"Attributes used to hold user passwords are not allowed " +
"to have any attribute options.");
@@ -8337,6 +8417,12 @@
"Terminating the client connection because its " +
"associated authentication or authorization entry %s has " +
"been deleted.");
+ registerMessage(MSGID_CLIENTCONNECTION_AUDIT_HASPRIVILEGE,
+ "hasPrivilege determination for connID=%d opID=%d " +
+ "requesterDN=\"%s\" privilege=\"%s\" result=%b");
+ registerMessage(MSGID_CLIENTCONNECTION_AUDIT_HASPRIVILEGES,
+ "hasPrivilege determination for connID=%d opID=%d " +
+ "requesterDN=\"%s\" privilegeSet=\"%s\" result=%b");
}
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/messages/ExtensionsMessages.java b/opendj-sdk/opends/src/server/org/opends/server/messages/ExtensionsMessages.java
index d8fb15c..66e04e5 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/messages/ExtensionsMessages.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/messages/ExtensionsMessages.java
@@ -4140,6 +4140,16 @@
/**
+ * The message ID for the message that will be used if a password modify
+ * extended operation is requested to reset another user's password by a
+ * client without sufficient privileges. This does not take any arguments.
+ */
+ public static final int MSGID_EXTOP_PASSMOD_INSUFFICIENT_PRIVILEGES =
+ CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 392;
+
+
+
+ /**
* Associates a set of generic messages with the message IDs defined in this
* class.
*/
@@ -4396,10 +4406,13 @@
registerMessage(MSGID_EXTOP_PASSMOD_INVALID_OLD_PASSWORD,
"The password modify extended operation cannot be " +
"processed because the current password provided for the " +
- "use is invalid.");
+ "user is invalid.");
registerMessage(MSGID_EXTOP_PASSMOD_CANNOT_GET_PW_POLICY,
"An error occurred while attempting to get the " +
"password policy for user %s: %s.");
+ registerMessage(MSGID_EXTOP_PASSMOD_INSUFFICIENT_PRIVILEGES,
+ "You do not have sufficient privileges to perform " +
+ "password reset operations.");
registerMessage(MSGID_EXTOP_PASSMOD_ACCOUNT_DISABLED,
"The user account has been administratively disabled.");
registerMessage(MSGID_EXTOP_PASSMOD_ACCOUNT_LOCKED,
diff --git a/opendj-sdk/opends/src/server/org/opends/server/messages/TaskMessages.java b/opendj-sdk/opends/src/server/org/opends/server/messages/TaskMessages.java
index 5a7ed00..875d984 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/messages/TaskMessages.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/messages/TaskMessages.java
@@ -122,9 +122,9 @@
/**
- * The message ID for the shutdown message that will be used if the server is
- * unable to obtain a write lock on the server schema. This takes a single
- * argument, which is the DN of the schema entry.
+ * The message ID for the message that will be used if the server is unable to
+ * obtain a write lock on the server schema. This takes a single argument,
+ * which is the DN of the schema entry.
*/
public static final int MSGID_TASK_ADDSCHEMAFILE_CANNOT_LOCK_SCHEMA =
CATEGORY_MASK_TASK | SEVERITY_MASK_SEVERE_ERROR | 9;
@@ -132,6 +132,76 @@
/**
+ * The message ID for the message that will be used an attempt is made to
+ * invoke the add schema file task by a user that does not have the required
+ * privileges. This does not take any arguments.
+ */
+ public static final int MSGID_TASK_ADDSCHEMAFILE_INSUFFICIENT_PRIVILEGES =
+ CATEGORY_MASK_TASK | SEVERITY_MASK_SEVERE_ERROR | 10;
+
+
+
+ /**
+ * The message ID for the message that will be used an attempt is made to
+ * invoke the backend backup task by a user that does not have the required
+ * privileges. This does not take any arguments.
+ */
+ public static final int MSGID_TASK_BACKUP_INSUFFICIENT_PRIVILEGES =
+ CATEGORY_MASK_TASK | SEVERITY_MASK_SEVERE_ERROR | 11;
+
+
+
+ /**
+ * The message ID for the message that will be used an attempt is made to
+ * invoke the backend restore task by a user that does not have the required
+ * privileges. This does not take any arguments.
+ */
+ public static final int MSGID_TASK_RESTORE_INSUFFICIENT_PRIVILEGES =
+ CATEGORY_MASK_TASK | SEVERITY_MASK_SEVERE_ERROR | 12;
+
+
+
+ /**
+ * The message ID for the message that will be used an attempt is made to
+ * invoke the LDIF import task by a user that does not have the required
+ * privileges. This does not take any arguments.
+ */
+ public static final int MSGID_TASK_LDIFIMPORT_INSUFFICIENT_PRIVILEGES =
+ CATEGORY_MASK_TASK | SEVERITY_MASK_SEVERE_ERROR | 13;
+
+
+
+ /**
+ * The message ID for the message that will be used an attempt is made to
+ * invoke the LDIF export task by a user that does not have the required
+ * privileges. This does not take any arguments.
+ */
+ public static final int MSGID_TASK_LDIFEXPORT_INSUFFICIENT_PRIVILEGES =
+ CATEGORY_MASK_TASK | SEVERITY_MASK_SEVERE_ERROR | 14;
+
+
+
+ /**
+ * The message ID for the message that will be used an attempt is made to
+ * invoke the server shutdown task to restart the server by a user that does
+ * not have the required privileges. This does not take any arguments.
+ */
+ public static final int MSGID_TASK_SHUTDOWN_INSUFFICIENT_RESTART_PRIVILEGES =
+ CATEGORY_MASK_TASK | SEVERITY_MASK_SEVERE_ERROR | 15;
+
+
+
+ /**
+ * The message ID for the message that will be used an attempt is made to
+ * invoke the server shutdown task to shut down the server by a user that does
+ * not have the required privileges. This does not take any arguments.
+ */
+ public static final int MSGID_TASK_SHUTDOWN_INSUFFICIENT_SHUTDOWN_PRIVILEGES =
+ CATEGORY_MASK_TASK | SEVERITY_MASK_SEVERE_ERROR | 16;
+
+
+
+ /**
* Associates a set of generic messages with the message IDs defined in this
* class.
*/
@@ -149,8 +219,17 @@
registerMessage(MSGID_TASK_SHUTDOWN_CUSTOM_MESSAGE,
"The Directory Server shutdown process has been " +
"initiated by task %s: %s");
+ registerMessage(MSGID_TASK_SHUTDOWN_INSUFFICIENT_RESTART_PRIVILEGES,
+ "You do not have sufficient privileges to initiate a " +
+ "Directory Server restart.");
+ registerMessage(MSGID_TASK_SHUTDOWN_INSUFFICIENT_SHUTDOWN_PRIVILEGES,
+ "You do not have sufficient privileges to initiate a " +
+ "Directory Server shutdown.");
+ registerMessage(MSGID_TASK_ADDSCHEMAFILE_INSUFFICIENT_PRIVILEGES,
+ "You do not have sufficient privileges to modify the " +
+ "server schema.");
registerMessage(MSGID_TASK_ADDSCHEMAFILE_NO_FILENAME,
"Unable to add one or more files to the server schema " +
"because no schema file names were provided in " +
@@ -170,6 +249,20 @@
"Unable to add one or more files to the server schema " +
"because the server was unable to obtain a write lock on " +
"the schema entry %s after multiple attempts.");
+
+
+ registerMessage(MSGID_TASK_BACKUP_INSUFFICIENT_PRIVILEGES,
+ "You do not have sufficient privileges to initiate a " +
+ "Directory Server backup.");
+ registerMessage(MSGID_TASK_RESTORE_INSUFFICIENT_PRIVILEGES,
+ "You do not have sufficient privileges to initiate a " +
+ "Directory Server restore.");
+ registerMessage(MSGID_TASK_LDIFIMPORT_INSUFFICIENT_PRIVILEGES,
+ "You do not have sufficient privileges to initiate an " +
+ "LDIF import.");
+ registerMessage(MSGID_TASK_LDIFEXPORT_INSUFFICIENT_PRIVILEGES,
+ "You do not have sufficient privileges to initiate an " +
+ "LDIF export.");
}
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/protocols/internal/InternalClientConnection.java b/opendj-sdk/opends/src/server/org/opends/server/protocols/internal/InternalClientConnection.java
index a56704f..9eb75c1 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/protocols/internal/InternalClientConnection.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/protocols/internal/InternalClientConnection.java
@@ -201,7 +201,6 @@
LinkedHashMap<AttributeType,List<Attribute>> operationalAttrs =
new LinkedHashMap<AttributeType,List<Attribute>>();
- // FIXME -- Add privileges here.
DN internalUserDN = DN.decode(fullDNString);
@@ -211,6 +210,7 @@
this.authenticationInfo =
new AuthenticationInfo(internalUserEntry, true);
+ super.setAuthenticationInfo(authenticationInfo);
}
catch (DirectoryException de)
{
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tasks/AddSchemaFileTask.java b/opendj-sdk/opends/src/server/org/opends/server/tasks/AddSchemaFileTask.java
index 9989d36..483b4a8 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tasks/AddSchemaFileTask.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/tasks/AddSchemaFileTask.java
@@ -33,10 +33,12 @@
import java.util.TreeSet;
import java.util.concurrent.locks.Lock;
+import org.opends.server.api.ClientConnection;
import org.opends.server.backends.task.Task;
import org.opends.server.backends.task.TaskState;
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.Operation;
import org.opends.server.core.SchemaConfigManager;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
@@ -48,6 +50,7 @@
import org.opends.server.types.ErrorLogSeverity;
import org.opends.server.types.InitializationException;
import org.opends.server.types.LockManager;
+import org.opends.server.types.Privilege;
import org.opends.server.types.ResultCode;
import org.opends.server.types.Schema;
@@ -88,6 +91,23 @@
{
assert debugEnter(CLASS_NAME, "initializeTask");
+
+ // If the client connection is available, then make sure the associated
+ // client has the UPDATE_SCHEMA privilege.
+ Operation operation = getOperation();
+ if (operation != null)
+ {
+ ClientConnection clientConnection = operation.getClientConnection();
+ if (! clientConnection.hasPrivilege(Privilege.UPDATE_SCHEMA, operation))
+ {
+ int msgID = MSGID_TASK_ADDSCHEMAFILE_INSUFFICIENT_PRIVILEGES;
+ String message = getMessage(msgID);
+ throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ message, msgID);
+ }
+ }
+
+
// Get the attribute that specifies which schema file(s) to add.
Entry taskEntry = getTaskEntry();
AttributeType attrType = DirectoryServer.getAttributeType(
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tasks/BackupTask.java b/opendj-sdk/opends/src/server/org/opends/server/tasks/BackupTask.java
index 0aa7639..9d60704 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tasks/BackupTask.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/tasks/BackupTask.java
@@ -22,13 +22,14 @@
* CDDL HEADER END
*
*
- * Portions Copyright 2006 Sun Microsystems, Inc.
+ * Portions Copyright 2006-2007 Sun Microsystems, Inc.
*/
package org.opends.server.tasks;
import static org.opends.server.loggers.Debug.debugEnter;
import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.core.DirectoryServer.getAttributeType;
+import static org.opends.server.messages.TaskMessages.*;
import static org.opends.server.messages.ToolMessages.*;
import static org.opends.server.messages.MessageHandler.getMessage;
import static org.opends.server.util.ServerConstants.DATE_FORMAT_UTC_TIME;
@@ -41,7 +42,9 @@
import org.opends.server.backends.task.TaskState;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.LockFileManager;
+import org.opends.server.core.Operation;
import org.opends.server.api.Backend;
+import org.opends.server.api.ClientConnection;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.types.Attribute;
@@ -52,6 +55,8 @@
import org.opends.server.types.Entry;
import org.opends.server.types.ErrorLogCategory;
import org.opends.server.types.ErrorLogSeverity;
+import org.opends.server.types.Privilege;
+import org.opends.server.types.ResultCode;
import java.util.ArrayList;
import java.util.Date;
@@ -104,7 +109,20 @@
assert debugEnter(CLASS_NAME, "initializeTask");
- // FIXME -- Do we need any special authorization here?
+ // If the client connection is available, then make sure the associated
+ // client has the BACKEND_BACKUP privilege.
+ Operation operation = getOperation();
+ if (operation != null)
+ {
+ ClientConnection clientConnection = operation.getClientConnection();
+ if (! clientConnection.hasPrivilege(Privilege.BACKEND_BACKUP, operation))
+ {
+ int msgID = MSGID_TASK_BACKUP_INSUFFICIENT_PRIVILEGES;
+ String message = getMessage(msgID);
+ throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ message, msgID);
+ }
+ }
Entry taskEntry = getTaskEntry();
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tasks/ExportTask.java b/opendj-sdk/opends/src/server/org/opends/server/tasks/ExportTask.java
index d57dcff..73d0e0a 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tasks/ExportTask.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/tasks/ExportTask.java
@@ -22,13 +22,14 @@
* CDDL HEADER END
*
*
- * Portions Copyright 2006 Sun Microsystems, Inc.
+ * Portions Copyright 2006-2007 Sun Microsystems, Inc.
*/
package org.opends.server.tasks;
import static org.opends.server.loggers.Debug.debugEnter;
import static org.opends.server.core.DirectoryServer.getAttributeType;
import static org.opends.server.config.ConfigConstants.*;
+import static org.opends.server.messages.TaskMessages.*;
import static org.opends.server.messages.ToolMessages.*;
import static org.opends.server.messages.MessageHandler.getMessage;
import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
@@ -37,7 +38,9 @@
import org.opends.server.backends.task.TaskState;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.LockFileManager;
+import org.opends.server.core.Operation;
import org.opends.server.api.Backend;
+import org.opends.server.api.ClientConnection;
import org.opends.server.config.ConfigEntry;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
@@ -48,6 +51,8 @@
import org.opends.server.types.ErrorLogSeverity;
import org.opends.server.types.ExistingFileBehavior;
import org.opends.server.types.LDIFExportConfig;
+import org.opends.server.types.Privilege;
+import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchFilter;
import java.util.ArrayList;
@@ -90,7 +95,20 @@
assert debugEnter(CLASS_NAME, "initializeTask");
- // FIXME -- Do we need any special authorization here?
+ // If the client connection is available, then make sure the associated
+ // client has the LDIF_EXPORT privilege.
+ Operation operation = getOperation();
+ if (operation != null)
+ {
+ ClientConnection clientConnection = operation.getClientConnection();
+ if (! clientConnection.hasPrivilege(Privilege.LDIF_EXPORT, operation))
+ {
+ int msgID = MSGID_TASK_LDIFEXPORT_INSUFFICIENT_PRIVILEGES;
+ String message = getMessage(msgID);
+ throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ message, msgID);
+ }
+ }
Entry taskEntry = getTaskEntry();
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tasks/ImportTask.java b/opendj-sdk/opends/src/server/org/opends/server/tasks/ImportTask.java
index d3bfbe5..6321313 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tasks/ImportTask.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/tasks/ImportTask.java
@@ -22,10 +22,11 @@
* CDDL HEADER END
*
*
- * Portions Copyright 2006 Sun Microsystems, Inc.
+ * Portions Copyright 2006-2007 Sun Microsystems, Inc.
*/
package org.opends.server.tasks;
+import static org.opends.server.messages.TaskMessages.*;
import static org.opends.server.messages.ToolMessages.*;
import static org.opends.server.messages.MessageHandler.getMessage;
import static org.opends.server.loggers.Debug.*;
@@ -38,7 +39,9 @@
import org.opends.server.backends.task.TaskState;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.LockFileManager;
+import org.opends.server.core.Operation;
import org.opends.server.api.Backend;
+import org.opends.server.api.ClientConnection;
import org.opends.server.config.ConfigEntry;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
@@ -49,6 +52,8 @@
import org.opends.server.types.ErrorLogSeverity;
import org.opends.server.types.ExistingFileBehavior;
import org.opends.server.types.LDIFImportConfig;
+import org.opends.server.types.Privilege;
+import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchFilter;
import java.util.HashSet;
@@ -95,7 +100,20 @@
assert debugEnter(CLASS_NAME, "initializeTask");
- // FIXME -- Do we need any special authorization here?
+ // If the client connection is available, then make sure the associated
+ // client has the LDIF_IMPORT privilege.
+ Operation operation = getOperation();
+ if (operation != null)
+ {
+ ClientConnection clientConnection = operation.getClientConnection();
+ if (! clientConnection.hasPrivilege(Privilege.LDIF_IMPORT, operation))
+ {
+ int msgID = MSGID_TASK_LDIFIMPORT_INSUFFICIENT_PRIVILEGES;
+ String message = getMessage(msgID);
+ throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ message, msgID);
+ }
+ }
Entry taskEntry = getTaskEntry();
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tasks/RestoreTask.java b/opendj-sdk/opends/src/server/org/opends/server/tasks/RestoreTask.java
index 563b154..740cf37 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tasks/RestoreTask.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/tasks/RestoreTask.java
@@ -22,13 +22,14 @@
* CDDL HEADER END
*
*
- * Portions Copyright 2006 Sun Microsystems, Inc.
+ * Portions Copyright 2006-2007 Sun Microsystems, Inc.
*/
package org.opends.server.tasks;
import static org.opends.server.loggers.Debug.debugEnter;
import static org.opends.server.core.DirectoryServer.getAttributeType;
import static org.opends.server.config.ConfigConstants.*;
+import static org.opends.server.messages.TaskMessages.*;
import static org.opends.server.messages.ToolMessages.*;
import static org.opends.server.messages.MessageHandler.getMessage;
import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
@@ -39,7 +40,9 @@
import org.opends.server.backends.task.TaskState;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.LockFileManager;
+import org.opends.server.core.Operation;
import org.opends.server.api.Backend;
+import org.opends.server.api.ClientConnection;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.types.Attribute;
@@ -51,7 +54,9 @@
import org.opends.server.types.Entry;
import org.opends.server.types.ErrorLogCategory;
import org.opends.server.types.ErrorLogSeverity;
+import org.opends.server.types.Privilege;
import org.opends.server.types.RestoreConfig;
+import org.opends.server.types.ResultCode;
import java.util.List;
import java.io.File;
@@ -84,7 +89,20 @@
assert debugEnter(CLASS_NAME, "initializeTask");
- // FIXME -- Do we need any special authorization here?
+ // If the client connection is available, then make sure the associated
+ // client has the BACKEND_RESTORE privilege.
+ Operation operation = getOperation();
+ if (operation != null)
+ {
+ ClientConnection clientConnection = operation.getClientConnection();
+ if (! clientConnection.hasPrivilege(Privilege.BACKEND_RESTORE, operation))
+ {
+ int msgID = MSGID_TASK_RESTORE_INSUFFICIENT_PRIVILEGES;
+ String message = getMessage(msgID);
+ throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ message, msgID);
+ }
+ }
Entry taskEntry = getTaskEntry();
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tasks/ShutdownTask.java b/opendj-sdk/opends/src/server/org/opends/server/tasks/ShutdownTask.java
index 827b883..6c7615b 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tasks/ShutdownTask.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/tasks/ShutdownTask.java
@@ -22,7 +22,7 @@
* CDDL HEADER END
*
*
- * Portions Copyright 2006 Sun Microsystems, Inc.
+ * Portions Copyright 2006-2007 Sun Microsystems, Inc.
*/
package org.opends.server.tasks;
@@ -31,14 +31,18 @@
import java.util.LinkedHashSet;
import java.util.List;
+import org.opends.server.api.ClientConnection;
import org.opends.server.backends.task.Task;
import org.opends.server.backends.task.TaskState;
import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.Operation;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
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 static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.loggers.Debug.*;
@@ -88,9 +92,6 @@
assert debugEnter(CLASS_NAME, "initializeTask");
- // FIXME -- Do we need any special authorization here?
-
-
// See if the entry contains a shutdown message. If so, then use it.
// Otherwise, use a default message.
Entry taskEntry = getTaskEntry();
@@ -132,6 +133,38 @@
valueString.equals("on") || valueString.equals("1"));
}
}
+
+
+ // If the client connection is available, then make sure the associated
+ // client has either the SERVER_SHUTDOWN or SERVER_RESTART privilege, based
+ // on the appropriate action.
+ Operation operation = getOperation();
+ if (operation != null)
+ {
+ ClientConnection clientConnection = operation.getClientConnection();
+ if (restart)
+ {
+ if (! clientConnection.hasPrivilege(Privilege.SERVER_RESTART,
+ operation))
+ {
+ int msgID = MSGID_TASK_SHUTDOWN_INSUFFICIENT_RESTART_PRIVILEGES;
+ String message = getMessage(msgID);
+ throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ message, msgID);
+ }
+ }
+ else
+ {
+ if (! clientConnection.hasPrivilege(Privilege.SERVER_SHUTDOWN,
+ operation))
+ {
+ int msgID = MSGID_TASK_SHUTDOWN_INSUFFICIENT_SHUTDOWN_PRIVILEGES;
+ String message = getMessage(msgID);
+ throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ message, msgID);
+ }
+ }
+ }
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/LDAPPasswordModify.java b/opendj-sdk/opends/src/server/org/opends/server/tools/LDAPPasswordModify.java
index 444bc29..9792843 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tools/LDAPPasswordModify.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/tools/LDAPPasswordModify.java
@@ -22,7 +22,7 @@
* CDDL HEADER END
*
*
- * Portions Copyright 2006 Sun Microsystems, Inc.
+ * Portions Copyright 2006-2007 Sun Microsystems, Inc.
*/
package org.opends.server.tools;
@@ -617,6 +617,11 @@
requestElements.add(new ASN1OctetString(TYPE_PASSWORD_MODIFY_OLD_PASSWORD,
currentPW.getValue()));
}
+ else if (currentPWFile.isPresent())
+ {
+ requestElements.add(new ASN1OctetString(TYPE_PASSWORD_MODIFY_OLD_PASSWORD,
+ currentPWFile.getValue()));
+ }
else if (provideDNForAuthzID.isPresent())
{
requestElements.add(new ASN1OctetString(TYPE_PASSWORD_MODIFY_OLD_PASSWORD,
@@ -628,6 +633,11 @@
requestElements.add(new ASN1OctetString(TYPE_PASSWORD_MODIFY_NEW_PASSWORD,
newPW.getValue()));
}
+ else if (newPWFile.isPresent())
+ {
+ requestElements.add(new ASN1OctetString(TYPE_PASSWORD_MODIFY_NEW_PASSWORD,
+ newPWFile.getValue()));
+ }
ASN1OctetString requestValue =
new ASN1OctetString(new ASN1Sequence(requestElements).encode());
diff --git a/opendj-sdk/opends/src/server/org/opends/server/types/Privilege.java b/opendj-sdk/opends/src/server/org/opends/server/types/Privilege.java
new file mode 100644
index 0000000..f04533d
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/types/Privilege.java
@@ -0,0 +1,389 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+package org.opends.server.types;
+
+
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.opends.server.util.StaticUtils.*;
+
+
+
+/**
+ * This class implements an enumeration that defines the set of
+ * privileges available in the Directory Server.
+ */
+public enum Privilege
+{
+ /**
+ * The privilege that provides the ability to bypass access control
+ * evaluation.
+ */
+ BYPASS_ACL("bypass-acl"),
+
+
+
+ /**
+ * The privilege that provides the ability to modify access control
+ * rules.
+ */
+ MODIFY_ACL("modify-acl"),
+
+
+
+ /**
+ * The privilege that provides the ability to read the server
+ * configuration.
+ */
+ CONFIG_READ("config-read"),
+
+
+
+ /**
+ * The privilege that provides the ability to update the server
+ * configuration.
+ */
+ CONFIG_WRITE("config-write"),
+
+
+
+ /**
+ * The privilege that provides the ability to perform read
+ * operations via JMX.
+ */
+ JMX_READ("jmx-read"),
+
+
+
+ /**
+ * The privilege that provides the ability to perform write
+ * operations via JMX.
+ */
+ JMX_WRITE("jmx-write"),
+
+
+
+ /**
+ * The privilege that provides the ability to subscribe to JMX
+ * notifications.
+ */
+ JMX_NOTIFY("jmx-notify"),
+
+
+
+ /**
+ * The privilege that provides the ability to perform LDIF import
+ * operations.
+ */
+ LDIF_IMPORT("ldif-import"),
+
+
+
+ /**
+ * The privilege that provides the ability to perform LDIF export
+ * operations.
+ */
+ LDIF_EXPORT("ldif-export"),
+
+
+
+ /**
+ * The privilege that provides the ability to perform backend backup
+ * operations.
+ */
+ BACKEND_BACKUP("backend-backup"),
+
+
+
+ /**
+ * The privilege that provides the ability to perform backend
+ * restore operations.
+ */
+ BACKEND_RESTORE("backend-restore"),
+
+
+
+ /**
+ * The privilege that provides the ability to request a server
+ * shutdown.
+ */
+ SERVER_SHUTDOWN("server-shutdown"),
+
+
+
+ /**
+ * The privilege that provides the ability to request a server
+ * restart.
+ */
+ SERVER_RESTART("server-restart"),
+
+
+
+ /**
+ * The privilege that provides the ability to perform proxied
+ * authorization or request an alternate authorization identity.
+ */
+ PROXIED_AUTH("proxied-auth"),
+
+
+
+ /**
+ * The privilege that provides the ability to terminate arbitrary
+ * client connections.
+ */
+ DISCONNECT_CLIENT("disconnect-client"),
+
+
+
+ /**
+ * The privilege that provides the ability to cancel arbitrary
+ * client requests.
+ */
+ CANCEL_REQUEST("cancel-request"),
+
+
+
+ /**
+ * The privilege that provides the ability to request unindexed
+ * searches.
+ */
+ SEARCH_UNINDEXED("search-unindexed"),
+
+
+
+ /**
+ * The privilege that provides the ability to reset user passwords.
+ */
+ PASSWORD_RESET("password-reset"),
+
+
+
+ /**
+ * The privilege that provides the ability to participate in a
+ * data synchronization environment.
+ */
+ DATA_SYNC("data-sync"),
+
+
+
+ /**
+ * The privilege that provides the ability to update the server
+ * schema.
+ */
+ UPDATE_SCHEMA("update-schema"),
+
+
+
+ /**
+ * The privilege that provides the ability to change the set of
+ * privileges for a user, or to change the set of privileges
+ * automatically assigned to a root user.
+ */
+ PRIVILEGE_CHANGE("privilege-change");
+
+
+
+ /**
+ * A map that will be used to hold a mapping between privilege names
+ * and enum values.
+ */
+ private static final HashMap<String,Privilege> PRIV_MAP =
+ new HashMap<String,Privilege>();
+
+
+
+ /**
+ * The set of privileges that will be automatically assigned to root
+ * users if the root privilege set is not specified in the
+ * configuration.
+ */
+ private static final HashSet<Privilege> DEFAULT_ROOT_PRIV_SET =
+ new HashSet<Privilege>();
+
+
+
+ /**
+ * The names of the available privileges defined in this class.
+ */
+ private static final HashSet<String> PRIV_NAMES =
+ new HashSet<String>();
+
+
+
+ // The human-readable name for this privilege.
+ private final String privilegeName;
+
+
+
+ static
+ {
+ PRIV_MAP.put("bypass-acl", BYPASS_ACL);
+ PRIV_MAP.put("modify-acl", MODIFY_ACL);
+ PRIV_MAP.put("config-read", CONFIG_READ);
+ PRIV_MAP.put("config-write", CONFIG_WRITE);
+ PRIV_MAP.put("jmx-read", JMX_READ);
+ PRIV_MAP.put("jmx-write", JMX_WRITE);
+ PRIV_MAP.put("jmx-notify", JMX_NOTIFY);
+ PRIV_MAP.put("ldif-import", LDIF_IMPORT);
+ PRIV_MAP.put("ldif-export", LDIF_EXPORT);
+ PRIV_MAP.put("backend-backup", BACKEND_BACKUP);
+ PRIV_MAP.put("backend-restore", BACKEND_RESTORE);
+ PRIV_MAP.put("server-shutdown", SERVER_SHUTDOWN);
+ PRIV_MAP.put("server-restart", SERVER_RESTART);
+ PRIV_MAP.put("proxied-auth", PROXIED_AUTH);
+ PRIV_MAP.put("disconnect-client", DISCONNECT_CLIENT);
+ PRIV_MAP.put("cancel-request", CANCEL_REQUEST);
+ PRIV_MAP.put("search-unindexed", SEARCH_UNINDEXED);
+ PRIV_MAP.put("password-reset", PASSWORD_RESET);
+ PRIV_MAP.put("data-sync", DATA_SYNC);
+ PRIV_MAP.put("update-schema", UPDATE_SCHEMA);
+ PRIV_MAP.put("privilege-change", PRIVILEGE_CHANGE);
+
+ PRIV_NAMES.add("bypass-acl");
+ PRIV_NAMES.add("modify-acl");
+ PRIV_NAMES.add("config-read");
+ PRIV_NAMES.add("config-write");
+ PRIV_NAMES.add("jmx-read");
+ PRIV_NAMES.add("jmx-write");
+ PRIV_NAMES.add("jmx-notify");
+ PRIV_NAMES.add("ldif-import");
+ PRIV_NAMES.add("ldif-export");
+ PRIV_NAMES.add("backend-backup");
+ PRIV_NAMES.add("backend-restore");
+ PRIV_NAMES.add("server-shutdown");
+ PRIV_NAMES.add("server-restart");
+ PRIV_NAMES.add("proxied-auth");
+ PRIV_NAMES.add("disconnect-client");
+ PRIV_NAMES.add("cancel-request");
+ PRIV_NAMES.add("search-unindexed");
+ PRIV_NAMES.add("password-reset");
+ PRIV_NAMES.add("data-sync");
+ PRIV_NAMES.add("update-schema");
+ PRIV_NAMES.add("privilege-change");
+
+ DEFAULT_ROOT_PRIV_SET.add(BYPASS_ACL);
+ DEFAULT_ROOT_PRIV_SET.add(MODIFY_ACL);
+ DEFAULT_ROOT_PRIV_SET.add(CONFIG_READ);
+ DEFAULT_ROOT_PRIV_SET.add(CONFIG_WRITE);
+ DEFAULT_ROOT_PRIV_SET.add(LDIF_IMPORT);
+ DEFAULT_ROOT_PRIV_SET.add(LDIF_EXPORT);
+ DEFAULT_ROOT_PRIV_SET.add(BACKEND_BACKUP);
+ DEFAULT_ROOT_PRIV_SET.add(BACKEND_RESTORE);
+ DEFAULT_ROOT_PRIV_SET.add(SERVER_SHUTDOWN);
+ DEFAULT_ROOT_PRIV_SET.add(SERVER_RESTART);
+ DEFAULT_ROOT_PRIV_SET.add(DISCONNECT_CLIENT);
+ DEFAULT_ROOT_PRIV_SET.add(CANCEL_REQUEST);
+ DEFAULT_ROOT_PRIV_SET.add(SEARCH_UNINDEXED);
+ DEFAULT_ROOT_PRIV_SET.add(PASSWORD_RESET);
+ DEFAULT_ROOT_PRIV_SET.add(UPDATE_SCHEMA);
+ DEFAULT_ROOT_PRIV_SET.add(PRIVILEGE_CHANGE);
+ }
+
+
+
+ /**
+ * Creates a new privilege with the provided name.
+ *
+ * @param privilegeName The human-readable name for this policy.
+ */
+ private Privilege(String privilegeName)
+ {
+ this.privilegeName = privilegeName;
+ }
+
+
+
+ /**
+ * Retrieves the name for this privilege.
+ *
+ * @return The name for this privilege.
+ */
+ public String getName()
+ {
+ return privilegeName;
+ }
+
+
+
+ /**
+ * Retrieves the privilege with the specified name.
+ *
+ * @param lowerPrivName The name of the privilege to retrieve,
+ * formatted in all lowercase characters.
+ *
+ * @return The requested privilege, or {@code null} if the provided
+ * value is not the name of a valid privilege.
+ */
+ public static Privilege privilegeForName(String lowerPrivName)
+ {
+ return PRIV_MAP.get(lowerPrivName);
+ }
+
+
+
+ /**
+ * Retrieves the human-readable name for this privilege.
+ *
+ * @return The human-readable name for this privilege.
+ */
+ public String toString()
+ {
+ return privilegeName;
+ }
+
+
+
+ /**
+ * Retrieves the set of available privilege names.
+ *
+ * @return The set of available privilege names.
+ */
+ public static Set<String> getPrivilegeNames()
+ {
+ return PRIV_NAMES;
+ }
+
+
+
+ /**
+ * Retrieves the set of privileges that should be automatically
+ * granted to root users if the root privilege set is not specified
+ * in the configuration.
+ *
+ * @return The set of privileges that should be automatically
+ * granted to root users if the root privilege set is not
+ * specified in the configuration.
+ */
+ public static Set<Privilege> getDefaultRootPrivileges()
+ {
+ return DEFAULT_ROOT_PRIV_SET;
+ }
+}
+
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/BindOperationTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/BindOperationTestCase.java
index d715517..9e13bd7 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/BindOperationTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/BindOperationTestCase.java
@@ -1778,7 +1778,7 @@
TestCaseUtils.initializeTestBackend(true);
InternalClientConnection conn =
- new InternalClientConnection(new AuthenticationInfo());
+ InternalClientConnection.getRootConnection();
String attr = "ds-cfg-bind-with-dn-requires-password";
ArrayList<Modification> mods = new ArrayList<Modification>();
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java
new file mode 100644
index 0000000..2fbf660
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java
@@ -0,0 +1,1166 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+package org.opends.server.types;
+
+
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.util.ArrayList;
+import java.util.UUID;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import org.opends.server.TestCaseUtils;
+import org.opends.server.backends.task.Task;
+import org.opends.server.backends.task.TaskBackend;
+import org.opends.server.backends.task.TaskState;
+import org.opends.server.core.AddOperation;
+import org.opends.server.core.CompareOperation;
+import org.opends.server.core.DeleteOperation;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.ModifyOperation;
+import org.opends.server.core.ModifyDNOperation;
+import org.opends.server.core.SchemaConfigManager;
+import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.tools.LDAPModify;
+import org.opends.server.tools.LDAPPasswordModify;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.AuthenticationInfo;
+import org.opends.server.types.DN;
+import org.opends.server.types.Modification;
+import org.opends.server.types.ModificationType;
+import org.opends.server.types.RDN;
+import org.opends.server.types.SearchFilter;
+import org.opends.server.types.SearchScope;
+
+import static org.testng.Assert.*;
+
+
+
+/**
+ * This class provides a set of test cases for the Directory Server privilege
+ * subsystem.
+ *
+ * FIXME -- It will likely be necessary to also have access control rules in
+ * place to allow operations as necessary once that functionality has
+ * integrated into the server.
+ */
+public class PrivilegeTestCase
+ extends TypesTestCase
+{
+ /**
+ * The DN of the user that is associated with the internal root connection.
+ */
+ private static final String INTERNAL_ROOT_DN =
+ "cn=Internal Client,cn=Root DNs,cn=config";
+
+
+
+ // An array of boolean values that indicates whether config read operations
+ // should be successful for users in the corresponding slots of the
+ // connections array.
+ private boolean[] successful;
+
+ // The set of client connections that should be used when performing
+ // operations.
+ private InternalClientConnection[] connections;
+
+
+
+ /**
+ * Make sure that the server is running and that an appropriate set of
+ * structures are in place.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @BeforeClass()
+ public void setUp()
+ throws Exception
+ {
+ TestCaseUtils.startServer();
+
+ TestCaseUtils.initializeTestBackend(true);
+ TestCaseUtils.addEntries(
+ "dn: cn=Unprivileged Root,cn=Root DNs,cn=config",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalPerson",
+ "objectClass: inetOrgPerson",
+ "objectClass: ds-cfg-root-dn",
+ "cn: Unprivileged Root",
+ "givenName: Unprivileged",
+ "sn: Root",
+ "userPassword: password",
+ "ds-privilege-name: -config-read",
+ "ds-privilege-name: -config-write",
+ "ds-privilege-name: -password-reset",
+ "ds-privilege-name: -update-schema",
+ "ds-privilege-name: -ldif-import",
+ "ds-privilege-name: -ldif-export",
+ "ds-privilege-name: -backend-backup",
+ "ds-privilege-name: -backend-restore",
+ "",
+ "dn: cn=Privileged User,o=test",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalPerson",
+ "objectClass: inetOrgPerson",
+ "cn: Privileged User",
+ "givenName: Privileged",
+ "sn: User",
+ "userPassword: password",
+ "ds-privilege-name: config-read",
+ "ds-privilege-name: config-write",
+ "ds-privilege-name: password-reset",
+ "ds-privilege-name: update-schema",
+ "ds-privilege-name: ldif-import",
+ "ds-privilege-name: ldif-export",
+ "ds-privilege-name: backend-backup",
+ "ds-privilege-name: backend-restore",
+ "",
+ "dn: cn=Unprivileged User,o=test",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalPerson",
+ "objectClass: inetOrgPerson",
+ "cn: Unprivileged User",
+ "givenName: Unprivileged",
+ "sn: User",
+ "userPassword: password",
+ "",
+ "dn: cn=PWReset Target,o=test",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalPerson",
+ "objectClass: inetOrgPerson",
+ "cn: PWReset Target",
+ "givenName: PWReset",
+ "sn: Target",
+ "userPassword: password");
+
+// FIXME -- It will likely be necessary to also have access control rules in
+// place to allow operations as necessary once that functionality has
+// integrated into the server.
+
+
+ // Build the array of connections we will use to perform the tests.
+ ArrayList<InternalClientConnection> connList =
+ new ArrayList<InternalClientConnection>();
+ ArrayList<Boolean> successList = new ArrayList<Boolean>();
+
+ connList.add(new InternalClientConnection(new AuthenticationInfo()));
+ successList.add(false);
+
+ connList.add(InternalClientConnection.getRootConnection());
+ successList.add(true);
+
+ String userDN = "cn=Directory Manager,cn=Root DNs,cn=config";
+ Entry userEntry = DirectoryServer.getEntry(DN.decode(userDN));
+ AuthenticationInfo authInfo = new AuthenticationInfo(userEntry, true);
+ connList.add(new InternalClientConnection(authInfo));
+ successList.add(true);
+
+ userDN = "cn=Unprivileged Root,cn=Root DNs,cn=config";
+ userEntry = DirectoryServer.getEntry(DN.decode(userDN));
+ authInfo = new AuthenticationInfo(userEntry, true);
+ connList.add(new InternalClientConnection(authInfo));
+ successList.add(false);
+
+ userDN = "cn=Unprivileged User,o=test";
+ userEntry = DirectoryServer.getEntry(DN.decode(userDN));
+ authInfo = new AuthenticationInfo(userEntry, false);
+ connList.add(new InternalClientConnection(authInfo));
+ successList.add(false);
+
+ userDN = "cn=Privileged User,o=test";
+ userEntry = DirectoryServer.getEntry(DN.decode(userDN));
+ authInfo = new AuthenticationInfo(userEntry, false);
+ connList.add(new InternalClientConnection(authInfo));
+ successList.add(true);
+
+
+ connections = new InternalClientConnection[connList.size()];
+ successful = new boolean[connections.length];
+ for (int i=0; i < connections.length; i++)
+ {
+ connections[i] = connList.get(i);
+ successful[i] = successList.get(i);
+ }
+ }
+
+
+
+ /**
+ * Cleans up anything that might be left around after running the tests in
+ * this class.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @AfterClass()
+ public void cleanUp()
+ throws Exception
+ {
+ InternalClientConnection conn =
+ InternalClientConnection.getRootConnection();
+
+ DeleteOperation deleteOperation =
+ conn.processDelete(
+ DN.decode("cn=Unprivileged Root,cn=Root DNs,cn=config"));
+ assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+
+
+
+ /**
+ * Retrieves a set of data that can be used for performing the tests. The
+ * arguments generated for each method will be:
+ * <OL>
+ * <LI>A client connection to use to perform the operation</LI>
+ * <LI>A flag indicating whether or not the operation should succeed</LI>
+ * </OL>
+ *
+ * @return A set of data that can be used for performing the tests.
+ */
+ @DataProvider(name = "testdata")
+ public Object[][] getTestData()
+ {
+ Object[][] returnArray = new Object[connections.length][2];
+ for (int i=0; i < connections.length; i++)
+ {
+ returnArray[i][0] = connections[i];
+ returnArray[i][1] = successful[i];
+ }
+
+ return returnArray;
+ }
+
+
+
+ /**
+ * Tests to ensure that search operations in the server configuration properly
+ * respect the CONFIG_READ privilege.
+ *
+ * @param conn The client connection to use to perform the search
+ * operation.
+ * @param hasPrivilege Indicates whether the authenticated user is expected
+ * to have the CONFIG_READ privilege and therefore the
+ * search should succeed.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test(dataProvider = "testdata")
+ public void testConfigReadSearch(InternalClientConnection conn,
+ boolean hasPrivilege)
+ throws Exception
+ {
+ assertEquals(conn.hasPrivilege(Privilege.CONFIG_READ, null), hasPrivilege);
+
+ InternalSearchOperation searchOperation =
+ conn.processSearch(DN.decode("cn=config"), SearchScope.BASE_OBJECT,
+ SearchFilter.createFilterFromString("(objectClass=*)"));
+ if (hasPrivilege)
+ {
+ assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+ else
+ {
+ assertEquals(searchOperation.getResultCode(),
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ }
+ }
+
+
+
+ /**
+ * Tests to ensure that compare operations in the server configuration
+ * properly respect the CONFIG_READ privilege.
+ *
+ * @param conn The client connection to use to perform the compare
+ * operation.
+ * @param hasPrivilege Indicates whether the authenticated user is expected
+ * to have the CONFIG_READ privilege and therefore the
+ * compare should succeed.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test(dataProvider = "testdata")
+ public void testConfigReadCompare(InternalClientConnection conn,
+ boolean hasPrivilege)
+ throws Exception
+ {
+ assertEquals(conn.hasPrivilege(Privilege.CONFIG_READ, null), hasPrivilege);
+
+ CompareOperation compareOperation =
+ conn.processCompare(DN.decode("cn=config"),
+ DirectoryServer.getAttributeType("cn"),
+ ByteStringFactory.create("config"));
+ if (hasPrivilege)
+ {
+ assertEquals(compareOperation.getResultCode(), ResultCode.COMPARE_TRUE);
+ }
+ else
+ {
+ assertEquals(compareOperation.getResultCode(),
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ }
+ }
+
+
+
+ /**
+ * Tests to ensure that add and delete operations in the server configuration
+ * properly respect the CONFIG_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 CONFIG_WRITE privilege and therefore the
+ * operations should succeed.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test(dataProvider = "testdata")
+ public void testConfigWriteAddAndDelete(InternalClientConnection conn,
+ boolean hasPrivilege)
+ throws Exception
+ {
+ assertEquals(conn.hasPrivilege(Privilege.CONFIG_WRITE, null), hasPrivilege);
+
+ Entry entry = TestCaseUtils.makeEntry(
+ "dn: cn=Test Root,cn=Root DNs,cn=config",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalPerson",
+ "objectClass: inetOrgPerson",
+ "objectClass: ds-cfg-root-dn",
+ "cn: Test Root",
+ "givenName: Test",
+ "sn: Root",
+ "userPassword: password");
+
+ 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=Telex Number,cn=Syntaxes,cn=config"));
+ assertEquals(deleteOperation.getResultCode(),
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ }
+ }
+
+
+
+ /**
+ * Tests to ensure that modify operations in the server configuration
+ * properly respect the CONFIG_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 CONFIG_WRITE privilege and therefore the
+ * modify should succeed.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test(dataProvider = "testdata")
+ public void testConfigWriteModify(InternalClientConnection conn,
+ boolean hasPrivilege)
+ throws Exception
+ {
+ assertEquals(conn.hasPrivilege(Privilege.CONFIG_WRITE, null), hasPrivilege);
+
+ ArrayList<Modification> mods = new ArrayList<Modification>();
+
+ mods.add(new Modification(ModificationType.REPLACE,
+ new Attribute("ds-cfg-size-limit", "2000")));
+
+ ModifyOperation modifyOperation =
+ conn.processModify(DN.decode("cn=config"), mods);
+ if (hasPrivilege)
+ {
+ assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+
+ mods.clear();
+ mods.add(new Modification(ModificationType.REPLACE,
+ new Attribute("ds-cfg-size-limit", "1000")));
+
+ modifyOperation = conn.processModify(DN.decode("cn=config"), mods);
+ assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+ else
+ {
+ assertEquals(modifyOperation.getResultCode(),
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ }
+ }
+
+
+
+ /**
+ * Tests to ensure that modify DN operations in the server configuration
+ * properly respect the CONFIG_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 CONFIG_WRITE privilege and therefore the
+ * modify DN should succeed (or at least get past the
+ * privilege check, only to fail because we don't
+ * support modify DN in the server configuration).
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test(dataProvider = "testdata")
+ public void testConfigWriteModifyDN(InternalClientConnection conn,
+ boolean hasPrivilege)
+ throws Exception
+ {
+ assertEquals(conn.hasPrivilege(Privilege.CONFIG_WRITE, null), hasPrivilege);
+
+ ModifyDNOperation modifyDNOperation =
+ conn.processModifyDN(DN.decode("cn=Work Queue,cn=config"),
+ RDN.decode("cn=New RDN for Work Queue"), true,
+ null);
+ if (hasPrivilege)
+ {
+ // We don't support modify DN operations in the server configuration, but
+ // at least we need to make sure we're getting past the privilege check.
+ assertEquals(modifyDNOperation.getResultCode(),
+ ResultCode.UNWILLING_TO_PERFORM);
+ }
+ 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.
+ *
+ * @param conn The client connection to use to perform the password
+ * reset.
+ * @param hasPrivilege Indicates whether the authenticated user is expected
+ * to have the PASSWORD_RESET privilege and therefore
+ * the password reset should succeed.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test(dataProvider = "testdata")
+ public void testPasswordResetModify(InternalClientConnection conn,
+ boolean hasPrivilege)
+ throws Exception
+ {
+ // We've got to do this as an external operation rather than internal, so
+ // get the bind DN and password to use from the client connection.
+
+ String userDN;
+ String userPassword;
+ Entry authNEntry = conn.getAuthenticationInfo().getAuthenticationEntry();
+ if (authNEntry == null)
+ {
+ userDN = "";
+ userPassword = "";
+ }
+ else if (authNEntry.getDN().toString().equalsIgnoreCase(INTERNAL_ROOT_DN))
+ {
+ return;
+ }
+ else
+ {
+ userDN = authNEntry.getDN().toString();
+ userPassword = "password";
+ }
+
+ assertEquals(conn.hasPrivilege(Privilege.PASSWORD_RESET, null),
+ hasPrivilege);
+
+ String path = TestCaseUtils.createTempFile(
+ "dn: cn=PWReset Target,o=test",
+ "changetype: modify",
+ "replace: userPassword",
+ "userPassword: newpassword",
+ "",
+ "dn: cn=PWReset Target,o=test",
+ "changetype: modify",
+ "replace: userPassword",
+ "userPassword: password");
+
+ String[] args =
+ {
+ "-h", "127.0.0.1",
+ "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
+ "-D", userDN,
+ "-w", userPassword,
+ "-f", path
+ };
+
+ int resultCode = LDAPModify.mainModify(args, false, null, null);
+ if (hasPrivilege)
+ {
+ assertEquals(resultCode, 0);
+ }
+ else
+ {
+ assertEquals(resultCode, 50);
+ }
+ }
+
+
+
+ /**
+ * Tests to ensure that password modify extended operations which attempt to
+ * reset a user's password properly respect the PASSWORD_RESET privilege.
+ *
+ * @param conn The client connection to use to perform the password
+ * reset.
+ * @param hasPrivilege Indicates whether the authenticated user is expected
+ * to have the PASSWORD_RESET privilege and therefore
+ * the password reset should succeed.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test(dataProvider = "testdata")
+ public void testPasswordResetExtOp(InternalClientConnection conn,
+ boolean hasPrivilege)
+ throws Exception
+ {
+ // We've got to do this as an external operation rather than internal, so
+ // get the bind DN and password to use from the client connection.
+
+ String userDN;
+ String userPassword;
+ Entry authNEntry = conn.getAuthenticationInfo().getAuthenticationEntry();
+ if (authNEntry == null)
+ {
+ userDN = "";
+ userPassword = "";
+ }
+ else if (authNEntry.getDN().toString().equalsIgnoreCase(INTERNAL_ROOT_DN))
+ {
+ return;
+ }
+ else
+ {
+ userDN = authNEntry.getDN().toString();
+ userPassword = "password";
+ }
+
+ assertEquals(conn.hasPrivilege(Privilege.PASSWORD_RESET, null),
+ hasPrivilege);
+
+ String[] args =
+ {
+ "-h", "127.0.0.1",
+ "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
+ "-D", userDN,
+ "-w", userPassword,
+ "-a", "dn:cn=PWReset Target,o=test",
+ "-n", "newpassword"
+ };
+
+ int resultCode =
+ LDAPPasswordModify.mainPasswordModify(args, false, null, null);
+ if (hasPrivilege)
+ {
+ assertEquals(resultCode, 0);
+
+ args = new String[]
+ {
+ "-h", "127.0.0.1",
+ "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
+ "-D", userDN,
+ "-w", userPassword,
+ "-a", "dn:cn=PWReset Target,o=test",
+ "-n", "password"
+ };
+ assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null,
+ null), 0);
+ }
+ else
+ {
+ assertEquals(resultCode, 50);
+ }
+ }
+
+
+
+ /**
+ * Tests to ensure that attempts to update the schema with a modify operation
+ * will properly respect the UPDATE_SCHEMA privilege.
+ *
+ * @param conn The client connection to use to perform the schema
+ * update.
+ * @param hasPrivilege Indicates whether the authenticated user is expected
+ * to have the UPDATE_SCHEMA privilege and therefore
+ * the schema update should succeed.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test(dataProvider = "testdata")
+ public void testUpdateSchemaModify(InternalClientConnection conn,
+ boolean hasPrivilege)
+ throws Exception
+ {
+ assertEquals(conn.hasPrivilege(Privilege.UPDATE_SCHEMA, null),
+ hasPrivilege);
+
+ String attrDefinition =
+ "( testupdateschemaat-oid NAME 'testUpdateSchemaAT' " +
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE " +
+ "X-ORIGIN 'PrivilegeTestCase' )";
+
+ ArrayList<Modification> mods = new ArrayList<Modification>();
+
+ mods.add(new Modification(ModificationType.ADD,
+ new Attribute("attributetypes", attrDefinition)));
+
+ ModifyOperation modifyOperation =
+ conn.processModify(DN.decode("cn=schema"), mods);
+ if (hasPrivilege)
+ {
+ assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+
+ mods.clear();
+ mods.add(new Modification(ModificationType.DELETE,
+ new Attribute("attributetypes", attrDefinition)));
+
+ modifyOperation = conn.processModify(DN.decode("cn=schema"), mods);
+ assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+ else
+ {
+ assertEquals(modifyOperation.getResultCode(),
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ }
+ }
+
+
+
+ /**
+ * Tests to ensure that attempts to update the schema with an add schema file
+ * task will properly respect the UPDATE_SCHEMA privilege.
+ *
+ * @param conn The client connection to use to perform the schema
+ * update.
+ * @param hasPrivilege Indicates whether the authenticated user is expected
+ * to have the UPDATE_SCHEMA privilege and therefore
+ * the schema update should succeed.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test(dataProvider = "testdata")
+ public void testUpdateSchemaAddSchemaFile(InternalClientConnection conn,
+ boolean hasPrivilege)
+ throws Exception
+ {
+ assertEquals(conn.hasPrivilege(Privilege.UPDATE_SCHEMA, null),
+ hasPrivilege);
+
+
+ String schemaDirectory = SchemaConfigManager.getSchemaDirectoryPath();
+
+ String identifier;
+ Entry authNEntry = conn.getAuthenticationInfo().getAuthenticationEntry();
+ if (authNEntry == null)
+ {
+ identifier = "null";
+ }
+ else
+ {
+ identifier = authNEntry.getDN().toString();
+ identifier = identifier.replace(',', '-');
+ identifier = identifier.replace(' ', '-');
+ identifier = identifier.replace('=', '-');
+ }
+
+ String[] fileLines =
+ {
+ "dn: cn=schema",
+ "objectClass: top",
+ "objectClass: ldapSubentry",
+ "objectClass: subschema",
+ "attributeTypes: ( " + identifier.toLowerCase() + "-oid " +
+ "NAME '" + identifier + "' )"
+ };
+
+ File validFile = new File(schemaDirectory, "05-" + identifier + ".ldif");
+ BufferedWriter writer = new BufferedWriter(new FileWriter(validFile));
+ for (String line : fileLines)
+ {
+ writer.write(line);
+ writer.newLine();
+ }
+ writer.close();
+
+ Entry taskEntry = TestCaseUtils.makeEntry(
+ "dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks",
+ "objectClass: top",
+ "objectClass: ds-task",
+ "objectClass: ds-task-add-schema-file",
+ "ds-task-class-name: org.opends.server.tasks.AddSchemaFileTask",
+ "ds-task-schema-file-name: 05-" + identifier + ".ldif");
+
+ AddOperation addOperation =
+ conn.processAdd(taskEntry.getDN(), taskEntry.getObjectClasses(),
+ taskEntry.getUserAttributes(),
+ taskEntry.getOperationalAttributes());
+
+ if (hasPrivilege)
+ {
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+ Task task = getCompletedTask(taskEntry.getDN());
+ assertNotNull(task);
+ assertTrue(TaskState.isSuccessful(task.getTaskState()));
+ }
+ else
+ {
+ assertEquals(addOperation.getResultCode(),
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ }
+ }
+
+
+
+ /**
+ * Tests to ensure that attempts to backup the Directory Server backends
+ * will properly respect the BACKEND_BACKUP privilege.
+ *
+ * @param conn The client connection to use to perform the backup.
+ * @param hasPrivilege Indicates whether the authenticated user is expected
+ * to have the BACKEND_BACKUP privilege and therefore
+ * the backup should succeed.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test(dataProvider = "testdata", groups = { "slow" })
+ public void testBackupBackend(InternalClientConnection conn,
+ boolean hasPrivilege)
+ throws Exception
+ {
+ // We have to sleep here because the backup ID that gets generated will be
+ // based on a timestamp and we don't want two in the same second.
+ Thread.sleep(1100);
+
+ assertEquals(conn.hasPrivilege(Privilege.BACKEND_BACKUP, null),
+ hasPrivilege);
+
+ Entry taskEntry = TestCaseUtils.makeEntry(
+ "dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks",
+ "objectclass: top",
+ "objectclass: ds-task",
+ "objectclass: ds-task-backup",
+ "ds-task-class-name: org.opends.server.tasks.BackupTask",
+ "ds-backup-directory-path: bak",
+ "ds-task-backup-all: TRUE");
+
+ AddOperation addOperation =
+ conn.processAdd(taskEntry.getDN(), taskEntry.getObjectClasses(),
+ taskEntry.getUserAttributes(),
+ taskEntry.getOperationalAttributes());
+
+ if (hasPrivilege)
+ {
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+ Task task = getCompletedTask(taskEntry.getDN());
+ assertNotNull(task);
+ assertTrue(TaskState.isSuccessful(task.getTaskState()));
+ }
+ else
+ {
+ assertEquals(addOperation.getResultCode(),
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ }
+ }
+
+
+
+ /**
+ * Tests to ensure that attempts to restore the Directory Server backends
+ * will properly respect the BACKEND_RESTORE privilege.
+ *
+ * @param conn The client connection to use to perform the restore.
+ * @param hasPrivilege Indicates whether the authenticated user is expected
+ * to have the BACKEND_RESTORE privilege and therefore
+ * the restore should succeed.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test(enabled = false, dataProvider = "testdata", groups = { "slow" },
+ dependsOnMethods = { "testBackupBackend" })
+ public void testRestoreBackend(InternalClientConnection conn,
+ boolean hasPrivilege)
+ throws Exception
+ {
+ assertEquals(conn.hasPrivilege(Privilege.BACKEND_RESTORE, null),
+ hasPrivilege);
+
+ Entry taskEntry = TestCaseUtils.makeEntry(
+ "dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks",
+ "objectclass: top",
+ "objectclass: ds-task",
+ "objectclass: ds-task-restore",
+ "ds-task-class-name: org.opends.server.tasks.RestoreTask",
+ "ds-backup-directory-path: bak" + File.separator + "userRoot");
+
+ AddOperation addOperation =
+ conn.processAdd(taskEntry.getDN(), taskEntry.getObjectClasses(),
+ taskEntry.getUserAttributes(),
+ taskEntry.getOperationalAttributes());
+
+ if (hasPrivilege)
+ {
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+ Task task = getCompletedTask(taskEntry.getDN());
+ assertNotNull(task);
+ assertTrue(TaskState.isSuccessful(task.getTaskState()));
+ }
+ else
+ {
+ assertEquals(addOperation.getResultCode(),
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ }
+ }
+
+
+
+ /**
+ * Tests to ensure that attempts to export the contents of a Directory Server
+ * backend will properly respect the LDIF_EXPORT privilege.
+ *
+ * @param conn The client connection to use to perform the export.
+ * @param hasPrivilege Indicates whether the authenticated user is expected
+ * to have the LDIF_EXPORT privilege and therefore
+ * the export should succeed.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test(dataProvider = "testdata", groups = { "slow" })
+ public void testLDIFExport(InternalClientConnection conn,
+ boolean hasPrivilege)
+ throws Exception
+ {
+ assertEquals(conn.hasPrivilege(Privilege.LDIF_EXPORT, null), hasPrivilege);
+
+ File tempFile = File.createTempFile("export-", ".ldif");
+ String tempFilePath = tempFile.getAbsolutePath();
+ tempFile.delete();
+
+ Entry taskEntry = TestCaseUtils.makeEntry(
+ "dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks",
+ "objectclass: top",
+ "objectclass: ds-task",
+ "objectclass: ds-task-export",
+ "ds-task-class-name: org.opends.server.tasks.ExportTask",
+ "ds-task-export-backend-id: userRoot",
+ "ds-task-export-ldif-file: " + tempFilePath);
+
+ AddOperation addOperation =
+ conn.processAdd(taskEntry.getDN(), taskEntry.getObjectClasses(),
+ taskEntry.getUserAttributes(),
+ taskEntry.getOperationalAttributes());
+
+ if (hasPrivilege)
+ {
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+ Task task = getCompletedTask(taskEntry.getDN());
+ assertNotNull(task);
+ assertTrue(TaskState.isSuccessful(task.getTaskState()));
+
+ tempFile.delete();
+ }
+ else
+ {
+ assertEquals(addOperation.getResultCode(),
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ }
+ }
+
+
+
+ /**
+ * Tests to ensure that attempts to import into a Directory Server backend
+ * will properly respect the LDIF_IMPORT privilege.
+ *
+ * @param conn The client connection to use to perform the import.
+ * @param hasPrivilege Indicates whether the authenticated user is expected
+ * to have the LDIF_IMPORT privilege and therefore
+ * the import should succeed.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test(dataProvider = "testdata", groups = { "slow" })
+ public void testLDIFImport(InternalClientConnection conn,
+ boolean hasPrivilege)
+ throws Exception
+ {
+ assertEquals(conn.hasPrivilege(Privilege.LDIF_IMPORT, null), hasPrivilege);
+
+ String path = TestCaseUtils.createTempFile(
+ "dn: dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: domain",
+ "dc: example");
+
+ Entry taskEntry = TestCaseUtils.makeEntry(
+ "dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks",
+ "objectclass: top",
+ "objectclass: ds-task",
+ "objectclass: ds-task-import",
+ "ds-task-class-name: org.opends.server.tasks.ImportTask",
+ "ds-task-import-backend-id: userRoot",
+ "ds-task-import-ldif-file: " + path);
+
+ AddOperation addOperation =
+ conn.processAdd(taskEntry.getDN(), taskEntry.getObjectClasses(),
+ taskEntry.getUserAttributes(),
+ taskEntry.getOperationalAttributes());
+
+ if (hasPrivilege)
+ {
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+ Task task = getCompletedTask(taskEntry.getDN());
+ assertNotNull(task);
+ assertTrue(TaskState.isSuccessful(task.getTaskState()));
+ }
+ else
+ {
+ assertEquals(addOperation.getResultCode(),
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ }
+ }
+
+
+
+ /**
+ * Tests the ability to update the set of privileges for a user on the fly
+ * and have them take effect immediately.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test()
+ public void testUpdateUserPrivileges()
+ throws Exception
+ {
+ InternalClientConnection rootConnection =
+ InternalClientConnection.getRootConnection();
+
+ TestCaseUtils.addEntry(
+ "dn: cn=Test User,o=test",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalPerson",
+ "objectClass: inetOrgPerson",
+ "cn: Test User",
+ "givenName: Test",
+ "sn: User",
+ "userPassword: password");
+
+ Entry testEntry =
+ DirectoryServer.getEntry(DN.decode("cn=Test User,o=test"));
+ AuthenticationInfo authInfo = new AuthenticationInfo(testEntry, false);
+ InternalClientConnection testConnection =
+ new InternalClientConnection(authInfo);
+
+
+ // Make sure the user starts out without any privileges.
+ for (Privilege p : Privilege.values())
+ {
+ assertFalse(testConnection.hasPrivilege(p, null));
+ }
+
+
+ // Modify the user entry to add the CONFIG_READ privilege and verify that
+ // the client connection reflects that.
+ ArrayList<Modification> mods = new ArrayList<Modification>();
+ mods.add(new Modification(ModificationType.ADD,
+ new Attribute("ds-privilege-name", "config-read")));
+ ModifyOperation modifyOperation =
+ rootConnection.processModify(DN.decode("cn=Test User,o=test"), mods);
+ assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+ assertTrue(testConnection.hasPrivilege(Privilege.CONFIG_READ, null));
+
+
+ // Take the privilege away from the user and verify that it is recognized
+ // immediately.
+ mods.clear();
+ mods.add(new Modification(ModificationType.DELETE,
+ new Attribute("ds-privilege-name", "config-read")));
+ modifyOperation =
+ rootConnection.processModify(DN.decode("cn=Test User,o=test"), mods);
+ assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+ assertFalse(testConnection.hasPrivilege(Privilege.CONFIG_READ, null));
+
+
+ DeleteOperation deleteOperation =
+ rootConnection.processDelete(DN.decode("cn=Test User,o=test"));
+ assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+
+
+
+ /**
+ * Tests the ability to update the set of root privileges and have them take
+ * effect immediately for new root connections.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test()
+ public void testUpdateRootPrivileges()
+ throws Exception
+ {
+ // Make sure that a root connection doesn't have the proxied auth
+ // privilege.
+ DN unprivRootDN = DN.decode("cn=Unprivileged Root,cn=Root DNs,cn=config");
+ Entry unprivRootEntry = DirectoryServer.getEntry(unprivRootDN);
+ AuthenticationInfo authInfo = new AuthenticationInfo(unprivRootEntry, true);
+ InternalClientConnection unprivRootConn =
+ new InternalClientConnection(authInfo);
+ assertFalse(unprivRootConn.hasPrivilege(Privilege.PROXIED_AUTH, null));
+
+
+ // Update the set of root privileges to include proxied auth.
+ InternalClientConnection internalRootConn =
+ InternalClientConnection.getRootConnection();
+
+ ArrayList<Modification> mods = new ArrayList<Modification>();
+ mods.add(new Modification(ModificationType.ADD,
+ new Attribute("ds-cfg-default-root-privilege-name",
+ "proxied-auth")));
+ ModifyOperation modifyOperation =
+ internalRootConn.processModify(DN.decode("cn=Root DNs,cn=config"),
+ mods);
+ assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+
+
+ // Get a new root connection and verify that it now has proxied auth.
+ unprivRootEntry = DirectoryServer.getEntry(unprivRootDN);
+ authInfo = new AuthenticationInfo(unprivRootEntry, true);
+ unprivRootConn = new InternalClientConnection(authInfo);
+ assertTrue(unprivRootConn.hasPrivilege(Privilege.PROXIED_AUTH, null));
+
+
+ // Update the set of root privileges to revoke proxied auth.
+ mods.clear();
+ mods.add(new Modification(ModificationType.DELETE,
+ new Attribute("ds-cfg-default-root-privilege-name",
+ "proxied-auth")));
+ modifyOperation =
+ internalRootConn.processModify(DN.decode("cn=Root DNs,cn=config"),
+ mods);
+ assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+
+
+ // Get a new root connection and verify that it no longer has proxied auth.
+ unprivRootEntry = DirectoryServer.getEntry(unprivRootDN);
+ authInfo = new AuthenticationInfo(unprivRootEntry, true);
+ unprivRootConn = new InternalClientConnection(authInfo);
+ assertFalse(unprivRootConn.hasPrivilege(Privilege.PROXIED_AUTH, null));
+ }
+
+
+
+ /**
+ * Retrieves the specified task from the server, waiting for it to finish all
+ * the running its going to do before returning.
+ *
+ * @param taskEntryDN The DN of the entry for the task to retrieve.
+ *
+ * @return The requested task entry.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ private Task getCompletedTask(DN taskEntryDN)
+ throws Exception
+ {
+ TaskBackend taskBackend =
+ (TaskBackend) DirectoryServer.getBackend(DN.decode("cn=tasks"));
+ Task task = taskBackend.getScheduledTask(taskEntryDN);
+ if (task == null)
+ {
+ long stopWaitingTime = System.currentTimeMillis() + 10000L;
+ while ((task == null) && (System.currentTimeMillis() < stopWaitingTime))
+ {
+ Thread.sleep(10);
+ task = taskBackend.getScheduledTask(taskEntryDN);
+ }
+ }
+
+ if (task == null)
+ {
+ throw new AssertionError("There is no such task " +
+ taskEntryDN.toString());
+ }
+
+ if (! TaskState.isDone(task.getTaskState()))
+ {
+ long stopWaitingTime = System.currentTimeMillis() + 20000L;
+ while ((! TaskState.isDone(task.getTaskState())) &&
+ (System.currentTimeMillis() < stopWaitingTime))
+ {
+ Thread.sleep(10);
+ }
+ }
+
+ if (! TaskState.isDone(task.getTaskState()))
+ {
+ throw new AssertionError("Task " + taskEntryDN.toString() +
+ " did not complete in a timely manner.");
+ }
+
+ return task;
+ }
+}
+
--
Gitblit v1.10.0