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
| | |
| | | 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 ) |
| | |
| | | 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' ) |
| | |
| | | </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> |
| | | |
| | |
| | | public boolean hasPrivilege(Privilege privilege, |
| | | Operation operation) |
| | | { |
| | | boolean result; |
| | | |
| | | if (privilege == Privilege.PROXIED_AUTH) |
| | | { |
| | | // This determination should always be made against the |
| | |
| | | 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); |
| | |
| | | if (operation.getAuthorizationDN().equals( |
| | | authenticationInfo.getAuthorizationDN())) |
| | | { |
| | | result = privileges.contains(privilege); |
| | | result = privileges.contains(privilege) || |
| | | DirectoryServer.isDisabled(privilege); |
| | | if (debugEnabled()) |
| | | { |
| | | DN authDN = authenticationInfo.getAuthenticationDN(); |
| | |
| | | boolean isRoot = |
| | | DirectoryServer.isRootDN(authorizationEntry.getDN()); |
| | | result = getPrivileges(authorizationEntry, |
| | | isRoot).contains(privilege); |
| | | isRoot).contains(privilege) || |
| | | DirectoryServer.isDisabled(privilege); |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | |
| | | 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; |
| | |
| | | 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; |
| | | |
| | |
| | | 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); |
| | | } |
| | | |
| | | |
| | |
| | | // 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; |
| | | |
| | |
| | | directoryServer.importTaskListeners = |
| | | new CopyOnWriteArrayList<ImportTaskListener>(); |
| | | directoryServer.allowedTasks = new LinkedHashSet<String>(0); |
| | | directoryServer.disabledPrivileges = new LinkedHashSet<Privilege>(0); |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * 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 |
| | |
| | | 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; |
| | |
| | | |
| | | |
| | | /** |
| | | * 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. |
| | | * |