opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/ConfigFileHandlerBackendConfiguration.xml
File was deleted opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/AciHandler.java
@@ -22,7 +22,6 @@ import java.util.SortedSet; import java.util.TreeSet; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.i18n.LocalizedIllegalArgumentException; import org.forgerock.i18n.slf4j.LocalizedLogger; import org.forgerock.opendj.config.server.ConfigException; @@ -33,23 +32,17 @@ import org.forgerock.opendj.ldap.ModificationType; import org.forgerock.opendj.ldap.RDN; import org.forgerock.opendj.ldap.ResultCode; import org.forgerock.opendj.ldap.SearchScope; import org.forgerock.opendj.ldap.schema.AttributeType; import org.forgerock.opendj.server.config.server.DseeCompatAccessControlHandlerCfg; import org.opends.server.api.AccessControlHandler; import org.opends.server.api.Backend; import org.opends.server.api.ClientConnection; import org.opends.server.backends.pluggable.SuffixContainer; import org.opends.server.controls.GetEffectiveRightsRequestControl; import org.opends.server.core.BindOperation; import org.opends.server.core.ConfigurationBackend; import org.opends.server.core.DirectoryServer; import org.opends.server.core.ExtendedOperation; import org.opends.server.core.ModifyDNOperation; import org.opends.server.core.SearchOperation; import org.opends.server.protocols.internal.InternalClientConnection; import org.opends.server.protocols.internal.InternalSearchOperation; import org.opends.server.protocols.internal.SearchRequest; import org.opends.server.protocols.ldap.LDAPControl; import org.opends.server.types.Attribute; import org.opends.server.types.AttributeBuilder; @@ -68,22 +61,17 @@ import org.opends.server.workflowelement.localbackend.LocalBackendCompareOperation; import org.opends.server.workflowelement.localbackend.LocalBackendDeleteOperation; import org.opends.server.workflowelement.localbackend.LocalBackendModifyOperation; import org.opends.server.workflowelement.localbackend.LocalBackendSearchOperation; import static org.opends.messages.AccessControlMessages.*; import static org.opends.server.authorization.dseecompat.Aci.*; import static org.opends.server.authorization.dseecompat.EnumEvalReason.*; import static org.opends.server.config.ConfigConstants.*; import static org.opends.server.core.DirectoryServer.*; import static org.opends.server.protocols.internal.InternalClientConnection.*; import static org.opends.server.protocols.internal.Requests.*; import static org.opends.server.schema.SchemaConstants.*; import static org.opends.server.util.ServerConstants.*; import static org.opends.server.util.StaticUtils.*; /** * The AciHandler class performs the main processing for the dseecompat package. */ /** The AciHandler class performs the main processing for the dseecompat package. */ public final class AciHandler extends AccessControlHandler<DseeCompatAccessControlHandlerCfg> { @@ -129,8 +117,6 @@ initStatics(); } /** * We initialize these for each new AciHandler so that we can clear out the * stale references that can occur during an in-core restart. @@ -168,7 +154,6 @@ // the intializeAccessControlHandler method. } /** {@inheritDoc} */ @Override public void filterEntry(Operation operation, SearchResultEntry unfilteredEntry, SearchResultEntry filteredEntry) @@ -194,7 +179,6 @@ } } /** {@inheritDoc} */ @Override public void finalizeAccessControlHandler() { @@ -203,7 +187,6 @@ DirectoryServer.deregisterSupportedControl(OID_GET_EFFECTIVE_RIGHTS); } /** {@inheritDoc} */ @Override public void initializeAccessControlHandler( DseeCompatAccessControlHandlerCfg configuration) @@ -214,11 +197,9 @@ aciList = new AciList(configurationDN); aciListenerMgr = new AciListenerManager(aciList, configurationDN); processGlobalAcis(configuration); processConfigAcis(); DirectoryServer.registerSupportedControl(OID_GET_EFFECTIVE_RIGHTS); } /** {@inheritDoc} */ @Override public boolean isAllowed(DN entryDN, Operation op, Control control) throws DirectoryException @@ -257,7 +238,6 @@ return true; } /** {@inheritDoc} */ @Override public boolean isAllowed(ExtendedOperation operation) { @@ -272,7 +252,6 @@ return accessAllowed(container); } /** {@inheritDoc} */ @Override public boolean isAllowed(LocalBackendAddOperation operation) throws DirectoryException @@ -284,7 +263,6 @@ && verifySyntax(operation.getEntryToAdd(), operation, container.getClientDN()); } /** {@inheritDoc} */ @Override public boolean isAllowed(BindOperation bindOperation) { @@ -292,8 +270,6 @@ return true; } /** * Check access on compare operations. Note that the attribute type is * unavailable at this time, so this method partially parses the raw @@ -328,8 +304,6 @@ return isAllowed(container, operation); } /** * Check access on delete operations. * @@ -345,8 +319,6 @@ return isAllowed(container, operation); } /** * Checks access on a modifyDN operation. * @@ -394,7 +366,6 @@ return rdnChangesAllowed; } /** {@inheritDoc} */ @Override public boolean isAllowed(LocalBackendModifyOperation operation) throws DirectoryException @@ -403,7 +374,6 @@ return aciCheckMods(container, operation, skipAccessCheck(operation)); } /** {@inheritDoc} */ @Override public boolean isAllowed(SearchOperation searchOperation) { @@ -411,7 +381,6 @@ return true; } /** {@inheritDoc} */ @Override public boolean isAllowed(Operation operation, Entry entry, SearchFilter filter) throws DirectoryException @@ -426,7 +395,6 @@ return testFilter(container, filter); } /** {@inheritDoc} */ @Override public boolean mayProxy(Entry proxyUser, Entry proxiedUser, Operation op) { @@ -443,7 +411,6 @@ return accessAllowedEntry(container); } /** {@inheritDoc} */ @Override public boolean maySend(DN dn, Operation operation, SearchResultReference reference) { @@ -465,7 +432,6 @@ return accessAllowed(container); } /** {@inheritDoc} */ @Override public boolean maySend(Operation operation, SearchResultEntry entry) { @@ -513,8 +479,6 @@ return true; } /** * Check access using the specified container. This container will * have all of the information to gather applicable ACIs and perform @@ -579,8 +543,6 @@ return ret; } /* * TODO Evaluate performance of this method. TODO Evaluate security * concerns of this method. Logic from this method taken almost @@ -642,8 +604,6 @@ return false; } /** * Performs an access check against all of the attributes of an entry. The * attributes that fail access are removed from the entry. This method @@ -676,8 +636,6 @@ } } /** * Checks to see if a LDAP modification is allowed access. * @@ -708,8 +666,7 @@ if (modAttrType.equals(aciType) /* * Check that the operation has modify privileges if it contains * an "aci" attribute type. * Check that the operation has modify privileges if it contains an "aci" attribute type. */ && !operation.getClientConnection().hasPrivilege( Privilege.MODIFY_ACL, operation)) @@ -725,8 +682,8 @@ || modType == ModificationType.REPLACE || modType == ModificationType.INCREMENT) /* * Check if we have rights to delete all values of an attribute * type in the resource entry. * Check if we have rights to delete all values of an attribute type in the resource * entry. */ && resourceEntry.hasAttribute(modAttrType)) { @@ -816,8 +773,6 @@ return true; } /** * Perform all needed RDN checks for the modifyDN operation. The old RDN is * not equal to the new RDN. The access checks are: @@ -860,8 +815,6 @@ return ret; } /** * Check access on the new superior entry if it exists. If superiordn is null, * the entry does not exist or the DN cannot be locked then false is returned. @@ -891,8 +844,6 @@ } } /** * Check access on each attribute-value pair component of the * specified RDN. There may be more than one attribute-value pair if @@ -922,8 +873,6 @@ return true; } /** * Creates the allow and deny ACI lists based on the provided target * match context. These lists are stored in the evaluation context. @@ -960,8 +909,6 @@ targetMatchCtx.setDenyList(denys); } /** * Gathers all of the attribute types in an entry along with the * "objectclass" attribute type in a List. The "objectclass" attribute @@ -988,8 +935,6 @@ return typeList; } /** * Check access using the accessAllowed method. The LDAP add, compare, * modify and delete operations use this function. The other supported @@ -1021,70 +966,6 @@ return SYNTAX_DN_OID.equals(attribute.getSyntax().getOID()); } /** * Process all ACIs under the "cn=config" naming context and adds them * to the ACI list cache. It also logs messages about the number of * ACIs added to the cache. This method is called once at startup. It * will put the server in lockdown mode if needed. * * @throws InitializationException * If there is an error searching for the ACIs in the naming * context. */ private void processConfigAcis() throws InitializationException { LinkedList<LocalizableMessage> failedACIMsgs = new LinkedList<>(); InternalClientConnection conn = getRootConnection(); Backend<?> configBackend = DirectoryServer.getBackend(ConfigurationBackend.CONFIG_BACKEND_ID); for (DN baseDN : configBackend.getBaseDNs()) { try { if (! configBackend.entryExists(baseDN)) { continue; } } catch (Exception e) { logger.traceException(e); // FIXME -- Is there anything that we need to do here? continue; } try { SearchRequest request = newSearchRequest(baseDN, SearchScope.WHOLE_SUBTREE, "aci=*").addAttribute("aci"); InternalSearchOperation internalSearch = new InternalSearchOperation(conn, nextOperationID(), nextMessageID(), request); LocalBackendSearchOperation localSearch = new LocalBackendSearchOperation(internalSearch); configBackend.search(localSearch); if (!internalSearch.getSearchEntries().isEmpty()) { int validAcis = aciList.addAci(internalSearch.getSearchEntries(), failedACIMsgs); if (!failedACIMsgs.isEmpty()) { aciListenerMgr.logMsgsSetLockDownMode(failedACIMsgs); } logger.debug(INFO_ACI_ADD_LIST_ACIS, validAcis, baseDN); } } catch (Exception e) { LocalizableMessage message = INFO_ACI_HANDLER_FAIL_PROCESS_ACI.get(); throw new InitializationException(message, e); } } } /** * Process all global ACI attribute types found in the configuration * entry and adds them to that ACI list cache. It also logs messages @@ -1105,7 +986,7 @@ { try { final SortedSet<Aci> globalAcis = new TreeSet<Aci>(); final SortedSet<Aci> globalAcis = new TreeSet<>(); for (String value : configuration.getGlobalACI()) { globalAcis.add(Aci.decode(ByteString.valueOfUtf8(value), DN.rootDN())); @@ -1124,8 +1005,6 @@ } } /** * Check to see if the specified entry has the specified privilege. * @@ -1139,8 +1018,6 @@ return ClientConnection.hasPrivilege(e, Privilege.BYPASS_ACL); } /** * Check to see if the client entry has BYPASS_ACL privileges for this * operation. @@ -1156,8 +1033,6 @@ Privilege.BYPASS_ACL, operation); } /** * Performs the test of the deny and allow access lists using the * provided evaluation context. The deny list is checked first. @@ -1185,12 +1060,12 @@ final EnumEvalResult res = Aci.evaluate(evalCtx, denyAci); // Failure could be returned if a system limit is hit or // search fails if (res.equals(EnumEvalResult.FAIL)) if (EnumEvalResult.FAIL.equals(res)) { evalCtx.setEvaluationResult(EVALUATED_DENY_ACI, denyAci); return false; } else if (res.equals(EnumEvalResult.TRUE)) else if (EnumEvalResult.TRUE.equals(res)) { if (testAndSetTargAttrOperationMatches(evalCtx, denyAci, true)) { @@ -1204,7 +1079,7 @@ for (Aci allowAci : evalCtx.getAllowList()) { final EnumEvalResult res = Aci.evaluate(evalCtx, allowAci); if (res.equals(EnumEvalResult.TRUE)) if (EnumEvalResult.TRUE.equals(res)) { if (testAndSetTargAttrOperationMatches(evalCtx, allowAci, false)) { @@ -1281,8 +1156,6 @@ return true; } /** * Evaluate an entry to be added to see if it has any "aci" attribute * type. If it does, examines each "aci" attribute type value for opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/AciListenerManager.java
@@ -16,13 +16,18 @@ */ package org.opends.server.authorization.dseecompat; import java.util.*; import java.util.EnumSet; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.i18n.slf4j.LocalizedLogger; import org.forgerock.opendj.ldap.DN; import org.forgerock.opendj.ldap.ResultCode; import org.forgerock.opendj.ldap.SearchScope; import org.forgerock.opendj.ldap.schema.AttributeType; import org.opends.server.api.AlertGenerator; import org.opends.server.api.Backend; import org.opends.server.api.BackendInitializationListener; @@ -31,13 +36,22 @@ import org.opends.server.api.plugin.PluginResult.PostOperation; import org.opends.server.api.plugin.PluginType; import org.opends.server.core.DirectoryServer; import org.opends.server.protocols.internal.InternalClientConnection; import org.opends.server.protocols.internal.InternalSearchOperation; import org.opends.server.protocols.internal.SearchRequest; import org.opends.server.protocols.ldap.LDAPControl; import org.forgerock.opendj.ldap.schema.AttributeType; import org.opends.server.types.*; import org.opends.server.types.operation.*; import org.opends.server.types.DirectoryException; import org.opends.server.types.Entry; import org.opends.server.types.IndexType; import org.opends.server.types.Modification; import org.opends.server.types.SearchFilter; import org.opends.server.types.operation.PostOperationAddOperation; import org.opends.server.types.operation.PostOperationDeleteOperation; import org.opends.server.types.operation.PostOperationModifyDNOperation; import org.opends.server.types.operation.PostOperationModifyOperation; import org.opends.server.types.operation.PostSynchronizationAddOperation; import org.opends.server.types.operation.PostSynchronizationDeleteOperation; import org.opends.server.types.operation.PostSynchronizationModifyDNOperation; import org.opends.server.types.operation.PostSynchronizationModifyOperation; import org.opends.server.workflowelement.localbackend.LocalBackendSearchOperation; import static org.opends.messages.AccessControlMessages.*; @@ -55,18 +69,11 @@ { private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); /** * The fully-qualified name of this class. */ /** The fully-qualified name of this class. */ private static final String CLASS_NAME = "org.opends.server.authorization.dseecompat.AciListenerManager"; /** * Internal plugin used for updating the cache before a response is * sent to the client. */ /** Internal plugin used for updating the cache before a response is sent to the client. */ private final class AciChangeListenerPlugin extends InternalDirectoryServerPlugin { @@ -83,9 +90,6 @@ PluginType.POST_OPERATION_MODIFY_DN), true); } /** {@inheritDoc} */ @Override public void doPostSynchronization( PostSynchronizationAddOperation addOperation) @@ -97,9 +101,6 @@ } } /** {@inheritDoc} */ @Override public void doPostSynchronization( PostSynchronizationDeleteOperation deleteOperation) @@ -111,9 +112,6 @@ } } /** {@inheritDoc} */ @Override public void doPostSynchronization( PostSynchronizationModifyDNOperation modifyDNOperation) @@ -125,9 +123,6 @@ } } /** {@inheritDoc} */ @Override public void doPostSynchronization( PostSynchronizationModifyOperation modifyOperation) @@ -140,9 +135,6 @@ } } /** {@inheritDoc} */ @Override public PostOperation doPostOperation( PostOperationAddOperation addOperation) @@ -158,9 +150,6 @@ return PluginResult.PostOperation.continueOperationProcessing(); } /** {@inheritDoc} */ @Override public PostOperation doPostOperation( PostOperationDeleteOperation deleteOperation) @@ -176,9 +165,6 @@ return PluginResult.PostOperation.continueOperationProcessing(); } /** {@inheritDoc} */ @Override public PostOperation doPostOperation( PostOperationModifyDNOperation modifyDNOperation) @@ -195,9 +181,6 @@ return PluginResult.PostOperation.continueOperationProcessing(); } /** {@inheritDoc} */ @Override public PostOperation doPostOperation( PostOperationModifyOperation modifyOperation) @@ -214,8 +197,6 @@ return PluginResult.PostOperation.continueOperationProcessing(); } private void doPostAdd(Entry addedEntry) { // This entry might have both global and aci attribute types. @@ -231,8 +212,6 @@ } } private void doPostDelete(Entry deletedEntry) { // This entry might have both global and aci attribute types. @@ -243,15 +222,11 @@ aciList.removeAci(deletedEntry, hasAci, hasGlobalAci); } private void doPostModifyDN(DN fromDN, DN toDN) { aciList.renameAci(fromDN, toDN); } private void doPostModify(List<Modification> mods, Entry oldEntry, Entry newEntry) { @@ -284,11 +259,8 @@ hasGlobalAci); } } } /** The configuration DN. */ private DN configurationDN; @@ -300,15 +272,6 @@ /** Search filter used in context search for "aci" attribute types. */ private static SearchFilter aciFilter; /** * Internal plugin used for updating the cache before a response is * sent to the client. */ private final AciChangeListenerPlugin plugin; /** The aci attribute type is operational so we need to specify it to be returned. */ private static LinkedHashSet<String> attrs = new LinkedHashSet<>(); static { // Set up the filter used to search private and public contexts. @@ -320,10 +283,10 @@ { // TODO should never happen, error message? } attrs.add("aci"); } /** Internal plugin used for updating the cache before a response is sent to the client. */ private final AciChangeListenerPlugin plugin; /** * Save the list created by the AciHandler routine. Registers as an @@ -358,8 +321,6 @@ DirectoryServer.registerAlertGenerator(this); } /** * Deregister from the change notification listener, the backend * initialization listener and the alert generator. @@ -371,8 +332,6 @@ DirectoryServer.deregisterAlertGenerator(this); } /** * {@inheritDoc} In this case, the server will search the backend to * find all aci attribute type values that it may contain and add them @@ -393,9 +352,7 @@ LinkedList<LocalizableMessage> failedACIMsgs = new LinkedList<>(); InternalClientConnection conn = getRootConnection(); // Add manageDsaIT control so any ACIs in referral entries will be // picked up. // Add manageDsaIT control so any ACIs in referral entries will be picked up. LDAPControl c1 = new LDAPControl(OID_MANAGE_DSAIT_CONTROL, true); // Add group membership control to let a backend look for it and // decide if it would abort searches. @@ -418,18 +375,17 @@ SearchRequest request = newSearchRequest(baseDN, SearchScope.WHOLE_SUBTREE, aciFilter) .addControl(c1) .addControl(c2) .addAttribute(attrs); .addAttribute("aci"); InternalSearchOperation internalSearch = new InternalSearchOperation(conn, nextOperationID(), nextMessageID(), request); LocalBackendSearchOperation localInternalSearch = new LocalBackendSearchOperation(internalSearch); new InternalSearchOperation(getRootConnection(), nextOperationID(), nextMessageID(), request); LocalBackendSearchOperation localInternalSearch = new LocalBackendSearchOperation(internalSearch); try { backend.search(localInternalSearch); } catch (Exception e) { logger.traceException(e); logger.trace(INFO_ACI_HANDLER_FAIL_PROCESS_ACI, e); continue; } if (!internalSearch.getSearchEntries().isEmpty()) @@ -444,12 +400,11 @@ } } /** * {@inheritDoc} In this case, the server will remove all aci * attribute type values associated with entries in the provided * backend. * {@inheritDoc} * <p> * In this case, the server will remove all aci attribute type values associated with entries in * the provided backend. */ @Override public void performBackendPostFinalizationProcessing(Backend<?> backend) @@ -467,7 +422,6 @@ // nothing to do. } /** * Retrieves the fully-qualified name of the Java class for this alert * generator implementation. @@ -481,8 +435,6 @@ return CLASS_NAME; } /** * Retrieves the DN of the configuration entry used to configure the * handler. @@ -496,8 +448,6 @@ return this.configurationDN; } /** * Retrieves information about the set of alerts that this generator * may produce. The map returned should be between the notification @@ -536,11 +486,8 @@ } } /** * Send an WARN_ACI_ENTER_LOCKDOWN_MODE alert notification and put the * server in lockdown mode. * Send an WARN_ACI_ENTER_LOCKDOWN_MODE alert notification and put the server in lockdown mode. */ private void setLockDownMode() { @@ -554,7 +501,6 @@ ALERT_TYPE_ACCESS_CONTROL_PARSE_FAILED, lockDownMsg); // Enter lockdown mode. DirectoryServer.setLockdownMode(true); } } } opendj-server-legacy/src/main/java/org/opends/server/core/BackendConfigManager.java
@@ -27,26 +27,25 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.i18n.slf4j.LocalizedLogger; import org.forgerock.opendj.config.server.ConfigChangeResult; import org.forgerock.opendj.config.server.ConfigException; import org.forgerock.opendj.ldap.ResultCode; import org.forgerock.opendj.config.server.ConfigurationAddListener; import org.forgerock.opendj.config.server.ConfigurationChangeListener; import org.forgerock.opendj.config.server.ConfigurationDeleteListener; import org.forgerock.opendj.ldap.DN; import org.forgerock.opendj.ldap.ResultCode; import org.forgerock.opendj.server.config.meta.BackendCfgDefn; import org.forgerock.opendj.server.config.server.BackendCfg; import org.forgerock.opendj.server.config.server.RootCfg; import org.opends.server.api.Backend; import org.opends.server.api.BackendInitializationListener; import org.opends.server.config.ConfigConstants; import org.forgerock.opendj.ldap.DN; import org.opends.server.types.Entry; import org.opends.server.types.DirectoryException; import org.opends.server.types.Entry; import org.opends.server.types.InitializationException; import org.opends.server.types.WritabilityMode; @@ -83,18 +82,20 @@ * Initializes the configuration associated with the Directory Server * backends. This should only be called at Directory Server startup. * * @param backendIDsToStart * The list of backendID to start. Everything will be started if empty. * @throws ConfigException * If a critical configuration problem prevents the backend * initialization from succeeding. * @throws InitializationException * If a problem occurs while initializing the backends that is not * related to the server configuration. * @param backendIDsToStart * The list of backendID to start. Everything will be started if empty. */ public void initializeBackendConfig(Collection<String> backendIDsToStart) throws ConfigException, InitializationException { initializeConfigurationBackend(); // Register add and delete listeners. RootCfg root = serverContext.getRootConfig(); root.addBackendAddListener(this); @@ -115,7 +116,6 @@ LocalizableMessage message = ERR_CONFIG_BACKEND_CANNOT_GET_CONFIG_BASE.get(getExceptionMessage(e)); throw new ConfigException(message, e); } @@ -124,8 +124,7 @@ // configuration, even if there are no backends defined below it. if (backendRoot == null) { LocalizableMessage message = ERR_CONFIG_BACKEND_BASE_DOES_NOT_EXIST.get(); throw new ConfigException(message); throw new ConfigException(ERR_CONFIG_BACKEND_BASE_DOES_NOT_EXIST.get()); } @@ -134,109 +133,77 @@ { // Get the handler's configuration. // This will decode and validate its properties. BackendCfg backendCfg = root.getBackend(name); final BackendCfg backendCfg = root.getBackend(name); final DN backendDN = backendCfg.dn(); final String backendID = backendCfg.getBackendId(); if (!backendIDsToStart.isEmpty() && !backendIDsToStart.contains(backendID)) { continue; } DN backendDN = backendCfg.dn(); // Register as a change listener for this backend so that we can be // notified when it is disabled or enabled. backendCfg.addChangeListener(this); // Ignore this handler if it is disabled. if (backendCfg.isEnabled()) if (!backendCfg.isEnabled()) { // If there is already a backend registered with the specified ID, // then log an error and skip it. if (DirectoryServer.hasBackend(backendID)) { logger.warn(WARN_CONFIG_BACKEND_DUPLICATE_BACKEND_ID, backendID, backendDN); continue; } // See if the entry contains an attribute that specifies the class name // for the backend implementation. If it does, then load it and make // sure that it's a valid backend implementation. There is no such // attribute, the specified class cannot be loaded, or it does not // contain a valid backend implementation, then log an error and skip it. String className = backendCfg.getJavaClass(); Backend<? extends BackendCfg> backend; try { backend = loadBackendClass(className).newInstance(); } catch (Exception e) { logger.traceException(e); logger.error(ERR_CONFIG_BACKEND_CANNOT_INSTANTIATE, className, backendDN, stackTraceToSingleLineString(e)); continue; } // If this backend is the configuration backend, then we don't want to do // any more with it because the configuration will have already been started. if (backend instanceof ConfigurationBackend) { continue; } // Set the backend ID and writability mode for this backend. backend.setBackendID(backendID); backend.setWritabilityMode(toWritabilityMode(backendCfg.getWritabilityMode())); ConfigChangeResult ccr = new ConfigChangeResult(); if (!acquireSharedLock(backend, backendID, ccr) || !initializeBackend(backend, backendCfg, ccr)) { logger.error(ccr.getMessages().get(0)); continue; } onBackendPreInitialization(backend); try { DirectoryServer.registerBackend(backend); } catch (Exception e) { logger.traceException(e); logger.warn(WARN_CONFIG_BACKEND_CANNOT_REGISTER_BACKEND, backendID, getExceptionMessage(e)); // FIXME -- Do we need to send an admin alert? } onBackendPostInitialization(backend); // Put this backend in the hash so that we will be able to find it if it is altered registeredBackends.put(backendDN, backend); } else { // The backend is explicitly disabled. Log a mild warning and continue. logger.debug(INFO_CONFIG_BACKEND_DISABLED, backendDN); continue; } else if (DirectoryServer.hasBackend(backendID)) { logger.warn(WARN_CONFIG_BACKEND_DUPLICATE_BACKEND_ID, backendID, backendDN); continue; } // See if the entry contains an attribute that specifies the class name // for the backend implementation. If it does, then load it and make // sure that it's a valid backend implementation. There is no such // attribute, the specified class cannot be loaded, or it does not // contain a valid backend implementation, then log an error and skip it. String className = backendCfg.getJavaClass(); Backend<? extends BackendCfg> backend; try { backend = loadBackendClass(className).newInstance(); } catch (Exception e) { logger.traceException(e); logger.error(ERR_CONFIG_BACKEND_CANNOT_INSTANTIATE, className, backendDN, stackTraceToSingleLineString(e)); continue; } initializeBackend(backend, backendCfg); } } private void onBackendPreInitialization(Backend<? extends BackendCfg> backend) private void initializeConfigurationBackend() throws InitializationException { for (BackendInitializationListener listener : getBackendInitializationListeners()) final ConfigurationBackend configBackend = new ConfigurationBackend(serverContext, DirectoryServer.getConfigurationHandler()); initializeBackend(configBackend, configBackend.getBackendCfg()); } private void initializeBackend(Backend<? extends BackendCfg> backend, BackendCfg backendCfg) { ConfigChangeResult ccr = new ConfigChangeResult(); initializeBackend(backend, backendCfg, ccr); for (LocalizableMessage msg : ccr.getMessages()) { listener.performBackendPreInitializationProcessing(backend); logger.error(msg); } } private void onBackendPostInitialization(Backend<? extends BackendCfg> backend) private void initializeBackend(Backend<? extends BackendCfg> backend, BackendCfg backendCfg, ConfigChangeResult ccr) { for (BackendInitializationListener listener : getBackendInitializationListeners()) backend.setBackendID(backendCfg.getBackendId()); backend.setWritabilityMode(toWritabilityMode(backendCfg.getWritabilityMode())); if (acquireSharedLock(backend, backendCfg.getBackendId(), ccr) && configureAndOpenBackend(backend, backendCfg, ccr)) { listener.performBackendPostInitializationProcessing(backend); registerBackend(backend, backendCfg, ccr); } } @@ -422,40 +389,11 @@ { // It isn't disabled, so we will do so now and deregister it from the // Directory Server. registeredBackends.remove(backendDN); for (BackendInitializationListener listener : getBackendInitializationListeners()) { listener.performBackendPreFinalizationProcessing(backend); } DirectoryServer.deregisterBackend(backend); for (BackendInitializationListener listener : getBackendInitializationListeners()) { listener.performBackendPostFinalizationProcessing(backend); } deregisterBackend(backendDN, backend); backend.finalizeBackend(); // Remove the shared lock for this backend. try { String lockFile = LockFileManager.getBackendLockFileName(backend); StringBuilder failureReason = new StringBuilder(); if (! LockFileManager.releaseLock(lockFile, failureReason)) { logger.warn(WARN_CONFIG_BACKEND_CANNOT_RELEASE_SHARED_LOCK, backend.getBackendID(), failureReason); // FIXME -- Do we need to send an admin alert? } } catch (Exception e2) { logger.traceException(e2); logger.warn(WARN_CONFIG_BACKEND_CANNOT_RELEASE_SHARED_LOCK, backend .getBackendID(), stackTraceToSingleLineString(e2)); // FIXME -- Do we need to send an admin alert? } releaseSharedLock(backend, backend.getBackendID()); return ccr; } // else already disabled, no need to do anything. @@ -471,10 +409,6 @@ return ccr; } String backendID = cfg.getBackendId(); WritabilityMode writabilityMode = toWritabilityMode(cfg.getWritabilityMode()); // See if the entry contains an attribute that specifies the class name // for the backend implementation. If it does, then load it and make sure // that it's a valid backend implementation. There is no such attribute, @@ -482,13 +416,10 @@ // backend implementation, then log an error and skip it. String className = cfg.getJavaClass(); // See if this backend is currently active and if so if the name of the // class is the same. // See if this backend is currently active and if so if the name of the class is the same. if (backend != null && !className.equals(backend.getClass().getName())) { // It is not the same. Try to load it and see if it is a valid backend // implementation. // It is not the same. Try to load it and see if it is a valid backend implementation. try { Class<?> backendClass = DirectoryServer.loadClass(className); @@ -537,50 +468,51 @@ return ccr; } // Set the backend ID and writability mode for this backend. backend.setBackendID(backendID); backend.setWritabilityMode(writabilityMode); if (!acquireSharedLock(backend, backendID, ccr) || !initializeBackend(backend, cfg, ccr)) { return ccr; } onBackendPreInitialization(backend); // Register the backend with the server. try { DirectoryServer.registerBackend(backend); } catch (Exception e) { logger.traceException(e); LocalizableMessage message = WARN_CONFIG_BACKEND_CANNOT_REGISTER_BACKEND.get( backendID, getExceptionMessage(e)); logger.warn(message); // FIXME -- Do we need to send an admin alert? ccr.setResultCode(DirectoryServer.getServerErrorResultCode()); ccr.addMessage(message); return ccr; } onBackendPostInitialization(backend); registeredBackends.put(backendDN, backend); initializeBackend(backend, cfg, ccr); return ccr; } else if (ccr.getResultCode() == ResultCode.SUCCESS && backend != null) { backend.setWritabilityMode(writabilityMode); backend.setWritabilityMode(toWritabilityMode(cfg.getWritabilityMode())); } return ccr; } private boolean registerBackend(Backend<? extends BackendCfg> backend, BackendCfg backendCfg, ConfigChangeResult ccr) { for (BackendInitializationListener listener : getBackendInitializationListeners()) { listener.performBackendPreInitializationProcessing(backend); } try { DirectoryServer.registerBackend(backend); } catch (Exception e) { logger.traceException(e); LocalizableMessage message = WARN_CONFIG_BACKEND_CANNOT_REGISTER_BACKEND.get(backendCfg.getBackendId(), getExceptionMessage(e)); logger.error(message); // FIXME -- Do we need to send an admin alert? ccr.setResultCode(DirectoryServer.getServerErrorResultCode()); ccr.addMessage(message); return false; } for (BackendInitializationListener listener : getBackendInitializationListeners()) { listener.performBackendPostInitializationProcessing(backend); } registeredBackends.put(backendCfg.dn(), backend); return true; } @Override public boolean isConfigurationAddAcceptable( BackendCfg configEntry, @@ -709,51 +641,15 @@ return ccr; } // Set the backend ID and writability mode for this backend. backend.setBackendID(backendID); backend.setWritabilityMode(toWritabilityMode(cfg.getWritabilityMode())); if (!acquireSharedLock(backend, backendID, ccr) || !initializeBackend(backend, cfg, ccr)) { return ccr; } onBackendPreInitialization(backend); // At this point, the backend should be online. Add it as one of the // registered backends for this backend config manager. try { DirectoryServer.registerBackend(backend); } catch (Exception e) { logger.traceException(e); LocalizableMessage message = WARN_CONFIG_BACKEND_CANNOT_REGISTER_BACKEND.get( backendID, getExceptionMessage(e)); logger.error(message); // FIXME -- Do we need to send an admin alert? ccr.setResultCode(DirectoryServer.getServerErrorResultCode()); ccr.addMessage(message); return ccr; } onBackendPostInitialization(backend); registeredBackends.put(backendDN, backend); initializeBackend(backend, cfg, ccr); return ccr; } private boolean initializeBackend(Backend<? extends BackendCfg> backend, BackendCfg cfg, ConfigChangeResult ccr) private boolean configureAndOpenBackend(Backend<?> backend, BackendCfg cfg, ConfigChangeResult ccr) { try { initializeBackend(backend, cfg); configureAndOpenBackend(backend, cfg); return true; } catch (Exception e) @@ -769,6 +665,13 @@ } } @SuppressWarnings({ "unchecked", "rawtypes" }) private void configureAndOpenBackend(Backend backend, BackendCfg cfg) throws ConfigException, InitializationException { backend.configureBackend(cfg, serverContext); backend.openBackend(); } @SuppressWarnings("unchecked") private Class<Backend<BackendCfg>> loadBackendClass(String className) throws Exception { @@ -844,18 +747,7 @@ return ccr; } for (BackendInitializationListener listener : getBackendInitializationListeners()) { listener.performBackendPreFinalizationProcessing(backend); } registeredBackends.remove(backendDN); DirectoryServer.deregisterBackend(backend); for (BackendInitializationListener listener : getBackendInitializationListeners()) { listener.performBackendPostFinalizationProcessing(backend); } deregisterBackend(backendDN, backend); try { @@ -873,11 +765,19 @@ return ccr; } @SuppressWarnings({ "unchecked", "rawtypes" }) private void initializeBackend(Backend backend, BackendCfg cfg) throws ConfigException, InitializationException private void deregisterBackend(DN backendDN, Backend<?> backend) { backend.configureBackend(cfg, serverContext); backend.openBackend(); for (BackendInitializationListener listener : getBackendInitializationListeners()) { listener.performBackendPreFinalizationProcessing(backend); } registeredBackends.remove(backendDN); DirectoryServer.deregisterBackend(backend); for (BackendInitializationListener listener : getBackendInitializationListeners()) { listener.performBackendPostFinalizationProcessing(backend); } } } opendj-server-legacy/src/main/java/org/opends/server/core/ConfigurationBackend.java
@@ -23,23 +23,28 @@ import java.io.File; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.ListIterator; import java.util.Set; import java.util.SortedSet; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.i18n.slf4j.LocalizedLogger; import org.forgerock.opendj.adapter.server3x.Converters; import org.forgerock.opendj.config.server.ConfigException; import org.forgerock.opendj.config.server.ConfigurationChangeListener; import org.forgerock.opendj.ldap.ConditionResult; import org.forgerock.opendj.ldap.DN; import org.forgerock.opendj.ldap.ResultCode; import org.forgerock.opendj.ldap.schema.AttributeType; import org.forgerock.opendj.server.config.server.ConfigFileHandlerBackendCfg; import org.forgerock.opendj.server.config.meta.BackendCfgDefn.WritabilityMode; import org.forgerock.opendj.server.config.server.BackendCfg; import org.opends.server.api.Backend; import org.opends.server.api.Backupable; import org.opends.server.api.ClientConnection; import org.opends.server.core.ConfigurationBackend.ConfigurationBackendCfg; import org.opends.server.types.BackupConfig; import org.opends.server.types.BackupDirectory; import org.opends.server.types.DirectoryException; @@ -53,12 +58,80 @@ import org.opends.server.types.Privilege; import org.opends.server.types.RestoreConfig; import org.opends.server.util.BackupManager; import org.opends.server.util.CollectionUtils; import org.opends.server.util.StaticUtils; /** Back-end responsible for management of configuration entries. */ public class ConfigurationBackend extends Backend<ConfigFileHandlerBackendCfg> implements Backupable public class ConfigurationBackend extends Backend<ConfigurationBackendCfg> implements Backupable { /** * Dummy {@link BackendCfg} implementation for the {@link ConfigurationBackend}. No config is * needed for this specific backend, but this class is required to behave like other backends * during initialization. */ public final class ConfigurationBackendCfg implements BackendCfg { private ConfigurationBackendCfg() { // let nobody instantiate it } @Override public DN dn() { return getBaseDNs()[0]; } @Override public Class<? extends BackendCfg> configurationClass() { return this.getClass(); } @Override public String getBackendId() { return CONFIG_BACKEND_ID; } @Override public SortedSet<DN> getBaseDN() { return Collections.unmodifiableSortedSet(CollectionUtils.newTreeSet(getBaseDNs())); } @Override public boolean isEnabled() { return true; } @Override public String getJavaClass() { return ConfigurationBackend.class.getName(); } @Override public WritabilityMode getWritabilityMode() { return WritabilityMode.ENABLED; } @Override public void addChangeListener(ConfigurationChangeListener<BackendCfg> listener) { // no-op } @Override public void removeChangeListener(ConfigurationChangeListener<BackendCfg> listener) { // no-op } } /** * The backend ID for the configuration backend. * <p> * Try to avoid potential conflict with user backend identifiers. @@ -114,6 +187,16 @@ setBackendID(CONFIG_BACKEND_ID); } /** * Returns a new {@link ConfigurationBackendCfg} for this {@link ConfigurationBackend}. * * @return a new {@link ConfigurationBackendCfg} for this {@link ConfigurationBackend} */ public ConfigurationBackendCfg getBackendCfg() { return new ConfigurationBackendCfg(); } @Override public void closeBackend() { @@ -128,7 +211,7 @@ } @Override public void configureBackend(ConfigFileHandlerBackendCfg cfg, ServerContext serverContext) throws ConfigException public void configureBackend(ConfigurationBackendCfg cfg, ServerContext serverContext) throws ConfigException { // No action is required. } opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java
@@ -1358,17 +1358,6 @@ configFile = environmentConfig.getConfigFile(); configurationHandler = ConfigurationHandler.bootstrapConfiguration(serverContext); serverManagementContext = new ServerManagementContext(configurationHandler); final ConfigurationBackend configBackend = new ConfigurationBackend(serverContext, configurationHandler); configBackend.openBackend(); try { registerBackend(configBackend); } catch (DirectoryException e) { throw new InitializationException(LocalizableMessage.raw("Unable to register configuration backend", e)); } } /** @@ -1527,18 +1516,8 @@ initializeRootDNConfigManager(); initializeAuthenticatedUsers(); // initialize both subentry manager and group manager for this backend. initializeSubentryManager(); initializeGroupManager(); // Initialize both subentry manager and group manager // for the configuration backend. // TODO : why do we initialize these now ? Can't we do them after backend initialization ? Backend<?> configBackend = getConfigurationBackend(); subentryManager.performBackendPreInitializationProcessing(configBackend); groupManager.performBackendPreInitializationProcessing(configBackend); AccessControlConfigManager.getInstance().initializeAccessControl(serverContext); initializeBackends(Collections.<String> emptyList()); opendj-server-legacy/src/main/java/org/opends/server/tools/upgrade/Upgrade.java
@@ -635,6 +635,10 @@ rebuildIndexesNamed(INFO_UPGRADE_REBUILD_INDEXES_DISTINGUISHED_NAME.get(), "distinguishedName", "member", "owner", "roleOccupant", "seeAlso")); register("4.0.0", deleteConfigEntry(INFO_UPGRADE_TASK_CONFIGURATION_BACKEND_NOT_CONFIGURABLE.get(), "dn: ds-cfg-backend-id=config,cn=Backends,cn=config")); /** * All upgrades will refresh the server configuration schema and generate a new upgrade folder. */ opendj-server-legacy/src/messages/org/opends/messages/tool.properties
@@ -2539,6 +2539,8 @@ ERR_LDIFIMPORT_LDIF_FILE_DOESNT_EXIST_10055=Unable to access the LDIF file %s to import. Please check that the file is \ local to the server and the path correct. INFO_UPGRADE_TASK_BCRYPT_SCHEME_SUMMARY_10056=Adding Bcrypt password storage scheme configuration INFO_UPGRADE_TASK_CONFIGURATION_BACKEND_NOT_CONFIGURABLE_10057=Removing config entry \ for the non-configurable configuration backend # Strings for generated reference documentation. REF_SHORT_DESC_BACKUP_15000=back up OpenDJ directory data