From ed39262fa647434d4a0e31f07754a263ce2b16e3 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)
---
opends/src/server/org/opends/server/api/ClientConnection.java | 238 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 235 insertions(+), 3 deletions(-)
diff --git a/opends/src/server/org/opends/server/api/ClientConnection.java b/opends/src/server/org/opends/server/api/ClientConnection.java
index c113d31..48a98ea 100644
--- a/opends/src/server/org/opends/server/api/ClientConnection.java
+++ b/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.
*
--
Gitblit v1.10.0