RootDSEBackend.java revision 8ed24d57f423f11acc2a5c0ccdea5d3e685d8189
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at legal-notices/CDDLv1_0.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2006-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2015 ForgeRock AS
*/
/**
* This class defines a backend to hold the Directory Server root DSE. It is a
* kind of meta-backend in that it will dynamically generate the root DSE entry
* (although there will be some caching) for base-level searches, and will
* simply redirect to other backends for operations in other scopes.
* <BR><BR>
* This should not be treated like a regular backend when it comes to
* initializing the server configuration. It should only be initialized after
* all other backends are configured. As such, it should have a special entry
* in the configuration rather than being placed under the cn=Backends branch
* with the other backends.
*/
public class RootDSEBackend
extends Backend<RootDSEBackendCfg>
implements ConfigurationChangeListener<RootDSEBackendCfg>
{
/**
* The set of standard "static" attributes that we will always include in the
* root DSE entry and won't change while the server is running.
*/
/**
* The set of user-defined attributes that will be included in the root DSE
* entry.
*/
/**
* Indicates whether the attributes of the root DSE should always be treated
* as user attributes even if they are defined as operational in the schema.
*/
private boolean showAllAttributes;
/**
* The set of subordinate base DNs and their associated backends that will be
* used for non-base searches.
*/
/** The set of objectclasses that will be used in the root DSE entry. */
/** The current configuration state. */
private RootDSEBackendCfg currentConfig;
/** The DN of the configuration entry for this backend. */
private DN configEntryDN;
/** The DN for the root DSE. */
/** The set of base DNs for this backend. */
/**
* Creates a new backend with the provided information. All backend
* implementations must implement a default constructor that use
* <CODE>super()</CODE> to invoke this constructor.
*/
public RootDSEBackend()
{
super();
// Perform all initialization in initializeBackend.
}
/** {@inheritDoc} */
public void configureBackend(RootDSEBackendCfg config, ServerContext serverContext) throws ConfigException
{
}
/** {@inheritDoc} */
{
// Make sure that a configuration entry was provided. If not, then we will
// not be able to complete initialization.
if (configEntry == null)
{
throw new ConfigException(message);
}
// Create the set of base DNs that we will handle. In this case, it's just
// the root DSE.
// Create the set of subordinate base DNs. If this is specified in the
// configuration, then use that set. Otherwise, use the set of non-private
// backends defined in the server.
try
{
{
// This is fine -- we'll just use the set of user-defined suffixes.
}
else
{
{
{
}
else
{
}
}
}
}
catch (Exception e)
{
logger.traceException(e);
throw new InitializationException(message, e);
}
// Determine whether all root DSE attributes should be treated as user
// attributes.
// Construct the set of "static" attributes that will always be present in
// the root DSE.
// Construct the set of objectclasses to include in the root DSE entry.
{
}
{
}
// Set the backend ID for this backend. The identifier needs to be
// specific enough to avoid conflict with user backend identifiers.
setBackendID("__root.dse__");
// Register as a change listener.
currentConfig.addChangeListener(this);
}
/**
* Get the set of user-defined attributes for the configuration entry. Any
* attributes that we do not recognize will be included directly in the root
* DSE.
*/
{
{
{
if (!isDSEConfigAttribute(a))
{
userDefinedAttrs.add(a);
}
}
}
{
{
if (!isDSEConfigAttribute(a))
{
userDefinedAttrs.add(a);
}
}
}
}
/** {@inheritDoc} */
public void closeBackend()
{
}
/**
* Indicates whether the provided attribute is one that is used in the
* configuration of this backend.
*
* @param attribute The attribute for which to make the determination.
*
* @return <CODE>true</CODE> if the provided attribute is one that is used in
* the configuration of this backend, <CODE>false</CODE> if not.
*/
{
}
/** {@inheritDoc} */
public DN[] getBaseDNs()
{
return baseDNs;
}
/** {@inheritDoc} */
public synchronized long getEntryCount()
{
// There is always just a single entry in this backend.
return 1;
}
/** {@inheritDoc} */
{
// All searches in this backend will always be considered indexed.
return true;
}
/** {@inheritDoc} */
throws DirectoryException
{
if(ret < 0)
{
return ConditionResult.UNDEFINED;
}
}
/** {@inheritDoc} */
throws DirectoryException
{
{
return -1;
}
long count = 0;
{
if (subBaseEntry != null)
{
if(subtree)
{
if(subCount < 0)
{
return -1;
}
}
count ++;
}
}
return count;
}
/** {@inheritDoc} */
throws DirectoryException
{
// If the requested entry was the root DSE, then create and return it.
{
return getRootDSE();
}
// This method should never be used to get anything other than the root DSE.
// If we got here, then that appears to be the case, so log a message.
// Go ahead and check the subordinate backends to see if we can find the
// entry there. Note that in order to avoid potential loop conditions, this
// will only work if the set of subordinate bases has been explicitly
// specified.
if (subordinateBaseDNs != null)
{
{
if (b.handlesEntry(entryDN))
{
}
}
}
// If we've gotten here, then we couldn't find the entry so return null.
return null;
}
/**
* Retrieves the root DSE entry for the Directory Server.
*
* @return The root DSE entry for the Directory Server.
*/
public Entry getRootDSE()
{
return getRootDSE(null);
}
/**
* Retrieves the root DSE entry for the Directory Server.
*
* @param connection
* The client connection, or {@code null} if there is no associated
* client connection.
* @return The root DSE entry for the Directory Server.
*/
{
// Add the "ds-private-naming-contexts" attribute.
// Add the "supportedControl" attribute.
// Add the "supportedExtension" attribute.
.getSupportedExtensions().keySet());
// Add the "supportedFeature" attribute.
// Add the "supportedSASLMechanisms" attribute.
// Add the "supportedLDAPVersions" attribute.
{
}
// Add the "supportedAuthPasswordSchemes" attribute.
if (!authPWSchemes.isEmpty())
{
{
}
else
{
}
}
// Obtain TLS protocol and cipher support.
if (connection != null)
{
// Only return the list of enabled protocols / ciphers for the connection
// handler to which the client is connected.
}
else
{
try
{
}
catch (Exception e)
{
// A default SSL context should always be available.
}
}
// Add the "supportedTLSProtocols" attribute.
// Add the "supportedTLSCiphers" attribute.
// Construct and return the entry.
return e;
}
Map<AttributeType, List<Attribute>> userAttrs, Map<AttributeType, List<Attribute>> operationalAttrs)
{
for (Attribute a : attributes)
{
: userAttrs;
{
}
}
}
{
if (!publicNamingContextAttr.isEmpty())
{
{
}
else
{
}
}
}
/**
* Creates an attribute for the root DSE meant to hold a set of DNs.
*
* @param name The name for the attribute.
* @param lowerName The name for the attribute formatted in all lowercase
* characters.
* @param values The set of DN values to use for the attribute.
*
* @return The constructed attribute.
*/
{
{
}
}
return builder.toAttribute();
}
/**
* Creates an attribute for the root DSE with the following
* criteria.
*
* @param name
* The name for the attribute.
* @param lowerName
* The name for the attribute formatted in all lowercase
* characters.
* @param values
* The set of values to use for the attribute.
* @return The constructed attribute.
*/
{
{
}
}
return builder.toAttribute();
}
/** {@inheritDoc} */
throws DirectoryException
{
// If the specified DN was the null DN, then it exists.
{
return true;
}
// If it was not the null DN, then iterate through the associated
// subordinate backends to make the determination.
{
{
if (b.entryExists(entryDN))
{
return true;
}
}
}
return false;
}
/** {@inheritDoc} */
throws DirectoryException
{
}
/** {@inheritDoc} */
throws DirectoryException
{
}
/** {@inheritDoc} */
{
}
/** {@inheritDoc} */
throws DirectoryException
{
}
/** {@inheritDoc} */
throws DirectoryException, CanceledOperationException {
{
}
{
case BASE_OBJECT:
{
}
break;
case SINGLE_LEVEL:
{
searchOperation.checkIfCanceled(false);
{
}
}
break;
case WHOLE_SUBTREE:
case SUBORDINATES:
try
{
{
searchOperation.checkIfCanceled(false);
try
{
}
catch (DirectoryException de)
{
// If it's a "no such object" exception, then the base entry for
// the backend doesn't exist. This isn't an error, so ignore it.
// We'll propogate all other errors, though.
{
throw de;
}
}
}
}
catch (DirectoryException de)
{
throw de;
}
catch (Exception e)
{
logger.traceException(e);
throw new DirectoryException(
e);
}
finally
{
}
break;
default:
}
}
/**
* Returns the subordinate base DNs of the root DSE.
*
* @return the subordinate base DNs of the root DSE
*/
{
if (subordinateBaseDNs != null)
{
return subordinateBaseDNs;
}
}
/** {@inheritDoc} */
{
return Collections.emptySet();
}
/** {@inheritDoc} */
{
return Collections.emptySet();
}
/** {@inheritDoc} */
{
// We will only export the DSE entry itself.
}
/** {@inheritDoc} */
throws DirectoryException
{
// Create the LDIF writer.
try
{
}
catch (Exception e)
{
logger.traceException(e);
message);
}
// Write the root DSE entry itself to it. Make sure to close the LDIF
// writer when we're done.
try
{
}
catch (Exception e)
{
logger.traceException(e);
message);
}
finally
{
}
}
/** {@inheritDoc} */
throws DirectoryException
{
}
/** {@inheritDoc} */
throws DirectoryException
{
}
/** {@inheritDoc} */
throws DirectoryException
{
}
/** {@inheritDoc} */
throws DirectoryException
{
}
/** {@inheritDoc} */
{
}
/** {@inheritDoc} */
public boolean isConfigurationChangeAcceptable(
{
boolean configIsAcceptable = true;
try
{
{
// This is fine -- we'll just use the set of user-defined suffixes.
}
else
{
{
{
configIsAcceptable = false;
}
}
}
}
catch (Exception e)
{
logger.traceException(e);
configIsAcceptable = false;
}
return configIsAcceptable;
}
/** {@inheritDoc} */
{
// Check to see if we should apply a new set of base DNs.
try
{
{
// This is fine -- we'll just use the set of user-defined suffixes.
}
else
{
{
{
// This is not fine. We can't use a suffix that doesn't exist.
}
else
{
}
}
}
}
catch (Exception e)
{
logger.traceException(e);
}
// Check to see if there is a new set of user-defined attributes.
try
{
}
catch (ConfigException e)
{
logger.traceException(e);
}
{
if (subordinateBaseDNs == null)
{
}
else
{
}
if (showAllAttributes != newShowAll)
{
}
}
return ccr;
}
/** {@inheritDoc} */
public void preloadEntryCache() throws UnsupportedOperationException {
throw new UnsupportedOperationException("Operation not supported.");
}
}