mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

neil_a_wilson
30.42.2007 fe10ac8a380a9a349bbe26794263501611918e69
Provide a mechanism to disable privileges in the server if necessary.  If a
privilege is disabled, then the server will behave as if all users have that
privilege. This can help improve compatibility with environments that expect
a feature to always be available, or to only be governed by access control.


OpenDS Issue Number: 1683
6 files modified
343 ■■■■■ changed files
opends/resource/schema/02-config.ldif 4 ●●● patch | view | raw | blame | history
opends/src/admin/defn/org/opends/server/admin/std/GlobalConfiguration.xml 141 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/api/ClientConnection.java 12 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/CoreConfigManager.java 81 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/DirectoryServer.java 44 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java 61 ●●●●● patch | view | raw | blame | history
opends/resource/schema/02-config.ldif
@@ -1532,6 +1532,8 @@
  SINGLE-VALUE X-ORIGIN 'OpenDS Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.456 NAME 'ds-cfg-allowed-task'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenDS Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.457 NAME 'ds-cfg-disabled-privilege'
  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 )
@@ -1746,7 +1748,7 @@
  ds-cfg-proxied-authorization-identity-mapper-dn $ ds-cfg-writability-mode $
  ds-cfg-reject-unauthenticated-requests  $
  ds-cfg-bind-with-dn-requires-password $ ds-cfg-lookthrough-limit $
  ds-cfg-smtp-server $ ds-cfg-allowed-task )
  ds-cfg-smtp-server $ ds-cfg-allowed-task $ ds-cfg-disabled-privilege )
  X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.41 NAME 'ds-cfg-root-dn' SUP top
  AUXILIARY MAY ds-cfg-alternate-bind-dn X-ORIGIN 'OpenDS Directory Server' )
opends/src/admin/defn/org/opends/server/admin/std/GlobalConfiguration.xml
@@ -526,5 +526,146 @@
    </adm:profile>
  </adm:property>
  <adm:property name="disabled-privilege" mandatory="false" multi-valued="true">
    <adm:synopsis>
      Specifies the name of a privilege that should not be evaluated by the
      server.  If a privilege is disabled, then it will be assumed that all
      clients (including unauthenticated clients) will have that privilege.
    </adm:synopsis>
    <adm:default-behavior>
      <adm:alias>
        <adm:synopsis>
          If no values are defined, then the server will enforce all privileges.
        </adm:synopsis>
      </adm:alias>
    </adm:default-behavior>
    <adm:syntax>
      <adm:enumeration>
        <adm:value name="bypass-acl">
          <adm:synopsis>
            Allows the associated user to bypass access control checks performed
            by the server.
          </adm:synopsis>
        </adm:value>
        <adm:value name="modify-acl">
          <adm:synopsis>
            Allows the associated user to modify the server's access control
            configuration.
          </adm:synopsis>
        </adm:value>
        <adm:value name="config-read">
          <adm:synopsis>
            Allows the associated user to read the server configuration.
          </adm:synopsis>
        </adm:value>
        <adm:value name="config-write">
          <adm:synopsis>
            Allows the associated user to update the server configuration.  The
            config-read privilege is also required.
          </adm:synopsis>
        </adm:value>
        <adm:value name="jmx-read">
          <adm:synopsis>
            Allows the associated user to perform JMX read operations.
          </adm:synopsis>
        </adm:value>
        <adm:value name="jmx-write">
          <adm:synopsis>
            Allows the associated user to perform JMX write operations.
          </adm:synopsis>
        </adm:value>
        <adm:value name="jmx-notify">
          <adm:synopsis>
            Allows the associated user to subscribe to receive JMX
            notifications.
          </adm:synopsis>
        </adm:value>
        <adm:value name="ldif-import">
          <adm:synopsis>
            Allows the user to request that the server process LDIF import
            tasks.
          </adm:synopsis>
        </adm:value>
        <adm:value name="ldif-export">
          <adm:synopsis>
            Allows the user to request that the server process LDIF export
            tasks.
          </adm:synopsis>
        </adm:value>
        <adm:value name="backend-backup">
          <adm:synopsis>
            Allows the user to request that the server process backup tasks.
          </adm:synopsis>
        </adm:value>
        <adm:value name="backend-restore">
          <adm:synopsis>
            Allows the user to request that the server process restore tasks.
          </adm:synopsis>
        </adm:value>
        <adm:value name="server-shutdown">
          <adm:synopsis>
            Allows the user to request that the server shut down.
          </adm:synopsis>
        </adm:value>
        <adm:value name="server-restart">
          <adm:synopsis>
            Allows the user to request that the server perform an in-core
            restart.
          </adm:synopsis>
        </adm:value>
        <adm:value name="proxied-auth">
          <adm:synopsis>
            Allows the user to use the proxied authorization control, or to
            perform a bind that specifies an alternate authorization identity.
          </adm:synopsis>
        </adm:value>
        <adm:value name="disconnect-client">
          <adm:synopsis>
            Allows the user to terminate other client connections.
          </adm:synopsis>
        </adm:value>
        <adm:value name="cancel-request">
          <adm:synopsis>
            Allows the user to cancel operations in progress on other client
            connections.
          </adm:synopsis>
        </adm:value>
        <adm:value name="password-reset">
          <adm:synopsis>
            Allows the user to reset user passwords.
          </adm:synopsis>
        </adm:value>
        <adm:value name="data-sync">
          <adm:synopsis>
            Allows the user to participate in data synchronization.
          </adm:synopsis>
        </adm:value>
        <adm:value name="update-schema">
          <adm:synopsis>
            Allows the user to make changes to the server schema.
          </adm:synopsis>
        </adm:value>
        <adm:value name="privilege-change">
          <adm:synopsis>
            Allows the user to make changes to the set of defined root
            privileges, as well as to grant and revoke privileges for users.
          </adm:synopsis>
        </adm:value>
        <adm:value name="unindexed-search">
          <adm:synopsis>
            Allows the user to request that the server process a search that
            cannot be optimized using server indexes.
          </adm:synopsis>
        </adm:value>
      </adm:enumeration>
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
        <ldap:oid>1.3.6.1.4.1.26027.1.1.455</ldap:oid>
        <ldap:name>ds-cfg-disabled-privilege</ldap:name>
      </ldap:attribute>
    </adm:profile>
  </adm:property>
</adm:managed-object>
opends/src/server/org/opends/server/api/ClientConnection.java
@@ -960,8 +960,6 @@
  public boolean hasPrivilege(Privilege privilege,
                              Operation operation)
  {
    boolean result;
    if (privilege == Privilege.PROXIED_AUTH)
    {
      // This determination should always be made against the
@@ -970,9 +968,11 @@
      Entry authEntry = authenticationInfo.getAuthenticationEntry();
      boolean isRoot  = authenticationInfo.isRoot();
      return getPrivileges(authEntry,
                           isRoot).contains(Privilege.PROXIED_AUTH);
                           isRoot).contains(Privilege.PROXIED_AUTH) ||
             DirectoryServer.isDisabled(Privilege.PROXIED_AUTH);
    }
    boolean result;
    if (operation == null)
    {
      result = privileges.contains(privilege);
@@ -992,7 +992,8 @@
      if (operation.getAuthorizationDN().equals(
               authenticationInfo.getAuthorizationDN()))
      {
        result = privileges.contains(privilege);
        result = privileges.contains(privilege) ||
                 DirectoryServer.isDisabled(privilege);
        if (debugEnabled())
        {
          DN authDN = authenticationInfo.getAuthenticationDN();
@@ -1017,7 +1018,8 @@
          boolean isRoot =
               DirectoryServer.isRootDN(authorizationEntry.getDN());
          result = getPrivileges(authorizationEntry,
                                 isRoot).contains(privilege);
                                 isRoot).contains(privilege) ||
                   DirectoryServer.isDisabled(privilege);
        }
      }
    }
opends/src/server/org/opends/server/core/CoreConfigManager.java
@@ -29,11 +29,13 @@
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.meta.GlobalCfgDefn;
import org.opends.server.admin.std.server.GlobalCfg;
import org.opends.server.admin.std.server.RootCfg;
import org.opends.server.admin.server.ServerManagementContext;
@@ -43,6 +45,7 @@
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DN;
import org.opends.server.types.InitializationException;
import org.opends.server.types.Privilege;
import org.opends.server.types.ResultCode;
import org.opends.server.types.WritabilityMode;
@@ -253,6 +256,84 @@
    DirectoryServer.setMailServerPropertySets(mailServerProperties);
    DirectoryServer.setAllowedTasks(globalConfig.getAllowedTask());
    HashSet<Privilege> disabledPrivileges = new HashSet<Privilege>();
    Set<GlobalCfgDefn.DisabledPrivilege> configuredDisabledPrivs =
         globalConfig.getDisabledPrivilege();
    if (configuredDisabledPrivs != null)
    {
      for (GlobalCfgDefn.DisabledPrivilege p : configuredDisabledPrivs)
      {
        switch (p)
        {
          case BACKEND_BACKUP:
            disabledPrivileges.add(Privilege.BACKEND_BACKUP);
            break;
          case BACKEND_RESTORE:
            disabledPrivileges.add(Privilege.BACKEND_RESTORE);
            break;
          case BYPASS_ACL:
            disabledPrivileges.add(Privilege.BYPASS_ACL);
            break;
          case CANCEL_REQUEST:
            disabledPrivileges.add(Privilege.CANCEL_REQUEST);
            break;
          case CONFIG_READ:
            disabledPrivileges.add(Privilege.CONFIG_READ);
            break;
          case CONFIG_WRITE:
            disabledPrivileges.add(Privilege.CONFIG_WRITE);
            break;
          case DATA_SYNC:
            disabledPrivileges.add(Privilege.DATA_SYNC);
            break;
          case DISCONNECT_CLIENT:
            disabledPrivileges.add(Privilege.DISCONNECT_CLIENT);
            break;
          case JMX_NOTIFY:
            disabledPrivileges.add(Privilege.JMX_NOTIFY);
            break;
          case JMX_READ:
            disabledPrivileges.add(Privilege.JMX_READ);
            break;
          case JMX_WRITE:
            disabledPrivileges.add(Privilege.JMX_WRITE);
            break;
          case LDIF_EXPORT:
            disabledPrivileges.add(Privilege.LDIF_EXPORT);
            break;
          case LDIF_IMPORT:
            disabledPrivileges.add(Privilege.LDIF_IMPORT);
            break;
          case MODIFY_ACL:
            disabledPrivileges.add(Privilege.MODIFY_ACL);
            break;
          case PASSWORD_RESET:
            disabledPrivileges.add(Privilege.PASSWORD_RESET);
            break;
          case PRIVILEGE_CHANGE:
            disabledPrivileges.add(Privilege.PRIVILEGE_CHANGE);
            break;
          case PROXIED_AUTH:
            disabledPrivileges.add(Privilege.PROXIED_AUTH);
            break;
          case SERVER_RESTART:
            disabledPrivileges.add(Privilege.SERVER_RESTART);
            break;
          case SERVER_SHUTDOWN:
            disabledPrivileges.add(Privilege.SERVER_SHUTDOWN);
            break;
          case UNINDEXED_SEARCH:
            disabledPrivileges.add(Privilege.UNINDEXED_SEARCH);
            break;
          case UPDATE_SCHEMA:
            disabledPrivileges.add(Privilege.UPDATE_SCHEMA);
            break;
        }
      }
    }
    DirectoryServer.setDisabledPrivileges(disabledPrivileges);
  }
opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -522,6 +522,9 @@
  // The error logger that will be used during the Directory Server startup.
  private TextErrorLogPublisher startupErrorLogPublisher;
  // The set of disabled privileges.
  private Set<Privilege> disabledPrivileges;
  // The set of allowed task classes.
  private Set<String> allowedTasks;
@@ -722,6 +725,7 @@
    directoryServer.importTaskListeners =
         new CopyOnWriteArrayList<ImportTaskListener>();
    directoryServer.allowedTasks = new LinkedHashSet<String>(0);
    directoryServer.disabledPrivileges = new LinkedHashSet<Privilege>(0);
  }
@@ -7423,6 +7427,46 @@
  /**
   * Retrieves the set of privileges that have been disabled.
   *
   * @return  The set of privileges that have been disabled.
   */
  public static Set<Privilege> getDisabledPrivileges()
  {
    return directoryServer.disabledPrivileges;
  }
  /**
   * Indicates whether the specified privilege is disabled.
   *
   * @param  privilege  The privilege for which to make the determination.
   *
   * @return  {@code true} if the specified privilege is disabled, or
   *          {@code false} if not.
   */
  public static boolean isDisabled(Privilege privilege)
  {
    return directoryServer.disabledPrivileges.contains(privilege);
  }
  /**
   * Specifies the set of privileges that should be disabled in the server.
   *
   * @param  disabledPrivileges  The set of privileges that should be disabled
   *                             in the server.
   */
  public static void setDisabledPrivileges(Set<Privilege> disabledPrivileges)
  {
    directoryServer.disabledPrivileges = disabledPrivileges;
  }
  /**
   * Registers the provided backup task listener with the Directory Server.
   *
   * @param  listener  The backup task listener to register with the Directory
opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java
@@ -63,6 +63,7 @@
import org.opends.server.tools.LDAPModify;
import org.opends.server.tools.LDAPPasswordModify;
import org.opends.server.tools.LDAPSearch;
import org.opends.server.tools.dsconfig.DSConfig;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
@@ -2300,6 +2301,66 @@
  /**
   * Tests the ability to disable a privilege so that an operation which will
   * fail for a user without an appropriate privilege will succeed if that
   * privilege is disabled.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDisablePrivilege()
         throws Exception
  {
    // Make sure that the operation fails when the privilege is not disabled.
    String[] searchArgs =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=PLAIN",
      "-o", "authid=dn:cn=Directory Manager",
      "-o", "authzid=u:privileged.user",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertFalse(LDAPSearch.mainSearch(searchArgs, false, null, null) == 0);
    // Disable the PROXIED_AUTH privilege and verify that the operation now
    // succeeds.
    String[] configArgs =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "set-global-configuration-prop",
      "--add", "disabled-privilege:proxied-auth"
    };
    assertEquals(DSConfig.main(configArgs, false, System.out, System.err), 0);
    assertEquals(LDAPSearch.mainSearch(searchArgs, false, null, null), 0);
    // Re-enable the PROXIED_AUTH privilege and verify that the operation
    // fails again.
    configArgs = new String[]
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "set-global-configuration-prop",
      "--remove", "disabled-privilege:proxied-auth"
    };
    assertEquals(DSConfig.main(configArgs, false, System.out, System.err), 0);
    assertFalse(LDAPSearch.mainSearch(searchArgs, false, null, null) == 0);
  }
  /**
   * Tests the ability to update the set of privileges for a user on the fly
   * and have them take effect immediately.
   *