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/core/RootDNConfigManager.java |  312 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 307 insertions(+), 5 deletions(-)

diff --git a/opends/src/server/org/opends/server/core/RootDNConfigManager.java b/opends/src/server/org/opends/server/core/RootDNConfigManager.java
index d4c9d95..0affa1e 100644
--- a/opends/src/server/org/opends/server/core/RootDNConfigManager.java
+++ b/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);
+  }
 }
 

--
Gitblit v1.10.0