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