/*
|
* 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
|
* trunk/opends/resource/legal-notices/OpenDS.LICENSE
|
* or https://OpenDS.dev.java.net/OpenDS.LICENSE.
|
* 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
|
* trunk/opends/resource/legal-notices/OpenDS.LICENSE. 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-2008 Sun Microsystems, Inc.
|
*/
|
package org.opends.server.core;
|
import org.opends.messages.Message;
|
|
|
|
import java.util.ArrayList;
|
import java.util.HashSet;
|
import java.util.List;
|
import java.util.Set;
|
import java.util.concurrent.ConcurrentHashMap;
|
|
import org.opends.server.admin.server.ConfigurationAddListener;
|
import org.opends.server.admin.server.ConfigurationChangeListener;
|
import org.opends.server.admin.server.ConfigurationDeleteListener;
|
import org.opends.server.admin.std.server.RootCfg;
|
import org.opends.server.admin.std.server.RootDNCfg;
|
import org.opends.server.admin.std.server.RootDNUserCfg;
|
import org.opends.server.admin.server.ServerManagementContext;
|
import org.opends.server.config.ConfigException;
|
import org.opends.server.types.ConfigChangeResult;
|
import org.opends.server.types.DirectoryException;
|
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 static org.opends.messages.ConfigMessages.*;
|
|
|
|
/**
|
* This class defines a utility that will be used to manage the set of root
|
* users defined in the Directory Server. It will handle both the
|
* "cn=Root DNs,cn=config" entry itself (through the root privilege change
|
* listener), and all of its children.
|
*/
|
public class RootDNConfigManager
|
implements ConfigurationChangeListener<RootDNUserCfg>,
|
ConfigurationAddListener<RootDNUserCfg>,
|
ConfigurationDeleteListener<RootDNUserCfg>
|
|
{
|
// A mapping between the actual root DNs and their alternate bind DNs.
|
private ConcurrentHashMap<DN,HashSet<DN>> alternateBindDNs;
|
|
// The root privilege change listener that will handle changes to the
|
// "cn=Root DNs,cn=config" entry itself.
|
private RootPrivilegeChangeListener rootPrivilegeChangeListener;
|
|
|
|
/**
|
* Creates a new instance of this root DN config manager.
|
*/
|
public RootDNConfigManager()
|
{
|
alternateBindDNs = new ConcurrentHashMap<DN,HashSet<DN>>();
|
rootPrivilegeChangeListener = new RootPrivilegeChangeListener();
|
}
|
|
|
|
/**
|
* Initializes all of the root users currently defined in the Directory Server
|
* configuration, as well as the set of privileges that root users will
|
* inherit by default.
|
*
|
* @throws ConfigException If a configuration problem causes the identity
|
* mapper initialization process to fail.
|
*
|
* @throws InitializationException If a problem occurs while initializing
|
* the identity mappers that is not related
|
* to the server configuration.
|
*/
|
public void initializeRootDNs()
|
throws ConfigException, InitializationException
|
{
|
// Get the root configuration object.
|
ServerManagementContext managementContext =
|
ServerManagementContext.getInstance();
|
RootCfg rootConfiguration =
|
managementContext.getRootConfiguration();
|
|
|
// Get the root DN configuration object, use it to set the default root
|
// privileges, and register a change listener for it.
|
RootDNCfg rootDNCfg = rootConfiguration.getRootDN();
|
rootPrivilegeChangeListener.setDefaultRootPrivileges(rootDNCfg);
|
rootDNCfg.addChangeListener(rootPrivilegeChangeListener);
|
|
|
// Register as an add and delete listener for new root DN users.
|
rootDNCfg.addRootDNUserAddListener(this);
|
rootDNCfg.addRootDNUserDeleteListener(this);
|
|
|
// Get the set of root users defined below "cn=Root DNs,cn=config". For
|
// each one, register as a change listener, and get the set of alternate
|
// bind DNs.
|
for (String name : rootDNCfg.listRootDNUsers())
|
{
|
RootDNUserCfg rootUserCfg = rootDNCfg.getRootDNUser(name);
|
rootUserCfg.addChangeListener(this);
|
DirectoryServer.registerRootDN(rootUserCfg.dn());
|
|
HashSet<DN> altBindDNs = new HashSet<DN>();
|
for (DN alternateBindDN : rootUserCfg.getAlternateBindDN())
|
{
|
try
|
{
|
altBindDNs.add(alternateBindDN);
|
DirectoryServer.registerAlternateRootDN(rootUserCfg.dn(),
|
alternateBindDN);
|
}
|
catch (DirectoryException de)
|
{
|
throw new InitializationException(de.getMessageObject());
|
}
|
}
|
|
alternateBindDNs.put(rootUserCfg.dn(), altBindDNs);
|
}
|
}
|
|
|
|
/**
|
* Retrieves the set of privileges that will be granted to root users by
|
* default.
|
*
|
* @return The set of privileges that will be granted to root users by
|
* default.
|
*/
|
public Set<Privilege> getRootPrivileges()
|
{
|
return rootPrivilegeChangeListener.getDefaultRootPrivileges();
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public boolean isConfigurationAddAcceptable(RootDNUserCfg configuration,
|
List<Message> unacceptableReasons)
|
{
|
// The new root user must not have an alternate bind DN that is already
|
// in use.
|
boolean configAcceptable = true;
|
for (DN altBindDN : configuration.getAlternateBindDN())
|
{
|
DN existingRootDN = DirectoryServer.getActualRootBindDN(altBindDN);
|
if (existingRootDN != null)
|
{
|
|
Message message = ERR_CONFIG_ROOTDN_CONFLICTING_MAPPING.get(
|
String.valueOf(altBindDN),
|
String.valueOf(configuration.dn()),
|
String.valueOf(existingRootDN));
|
unacceptableReasons.add(message);
|
|
configAcceptable = false;
|
}
|
}
|
|
return configAcceptable;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public ConfigChangeResult applyConfigurationAdd(RootDNUserCfg configuration)
|
{
|
configuration.addChangeListener(this);
|
|
ResultCode resultCode = ResultCode.SUCCESS;
|
boolean adminActionRequired = false;
|
ArrayList<Message> messages = new ArrayList<Message>();
|
|
HashSet<DN> altBindDNs = new HashSet<DN>();
|
for (DN altBindDN : configuration.getAlternateBindDN())
|
{
|
try
|
{
|
DirectoryServer.registerAlternateRootDN(configuration.dn(), altBindDN);
|
altBindDNs.add(altBindDN);
|
}
|
catch (DirectoryException de)
|
{
|
// This shouldn't happen, since the set of DNs should have already been
|
// validated.
|
resultCode = DirectoryServer.getServerErrorResultCode();
|
messages.add(de.getMessageObject());
|
|
for (DN dn : altBindDNs)
|
{
|
DirectoryServer.deregisterAlternateRootBindDN(dn);
|
}
|
break;
|
}
|
}
|
|
if (resultCode == ResultCode.SUCCESS)
|
{
|
DirectoryServer.registerRootDN(configuration.dn());
|
alternateBindDNs.put(configuration.dn(), altBindDNs);
|
}
|
|
return new ConfigChangeResult(resultCode, adminActionRequired, messages);
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public boolean isConfigurationDeleteAcceptable(RootDNUserCfg configuration,
|
List<Message> unacceptableReasons)
|
{
|
return true;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public ConfigChangeResult applyConfigurationDelete(
|
RootDNUserCfg configuration)
|
{
|
DirectoryServer.deregisterRootDN(configuration.dn());
|
configuration.removeChangeListener(this);
|
|
ResultCode resultCode = ResultCode.SUCCESS;
|
boolean adminActionRequired = false;
|
ArrayList<Message> messages = new ArrayList<Message>();
|
|
HashSet<DN> altBindDNs = alternateBindDNs.remove(configuration.dn());
|
if (altBindDNs != null)
|
{
|
for (DN dn : altBindDNs)
|
{
|
DirectoryServer.deregisterAlternateRootBindDN(dn);
|
}
|
}
|
|
return new ConfigChangeResult(resultCode, adminActionRequired, messages);
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public boolean isConfigurationChangeAcceptable(RootDNUserCfg configuration,
|
List<Message> unacceptableReasons)
|
{
|
boolean configAcceptable = true;
|
|
// There must not be any new alternate bind DNs that are already in use by
|
// other root users.
|
for (DN altBindDN: configuration.getAlternateBindDN())
|
{
|
DN existingRootDN = DirectoryServer.getActualRootBindDN(altBindDN);
|
if ((existingRootDN != null) &&
|
(! existingRootDN.equals(configuration.dn())))
|
{
|
Message message = ERR_CONFIG_ROOTDN_CONFLICTING_MAPPING.get(
|
String.valueOf(altBindDN),
|
String.valueOf(configuration.dn()),
|
String.valueOf(existingRootDN));
|
unacceptableReasons.add(message);
|
|
configAcceptable = false;
|
}
|
}
|
|
return configAcceptable;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public ConfigChangeResult applyConfigurationChange(
|
RootDNUserCfg configuration)
|
{
|
ResultCode resultCode = ResultCode.SUCCESS;
|
boolean adminActionRequired = false;
|
ArrayList<Message> messages = new ArrayList<Message>();
|
|
HashSet<DN> setDNs = new HashSet<DN>();
|
HashSet<DN> addDNs = new HashSet<DN>();
|
HashSet<DN> delDNs =
|
new HashSet<DN>(alternateBindDNs.get(configuration.dn()));
|
|
for (DN altBindDN : configuration.getAlternateBindDN())
|
{
|
setDNs.add(altBindDN);
|
|
if (! delDNs.remove(altBindDN))
|
{
|
addDNs.add(altBindDN);
|
}
|
}
|
|
for (DN dn : delDNs)
|
{
|
DirectoryServer.deregisterAlternateRootBindDN(dn);
|
}
|
|
HashSet<DN> addedDNs = new HashSet<DN>(addDNs.size());
|
for (DN dn : addDNs)
|
{
|
try
|
{
|
DirectoryServer.registerAlternateRootDN(configuration.dn(), dn);
|
addedDNs.add(dn);
|
}
|
catch (DirectoryException de)
|
{
|
// This shouldn't happen, since the set of DNs should have already been
|
// validated.
|
resultCode = DirectoryServer.getServerErrorResultCode();
|
messages.add(de.getMessageObject());
|
|
for (DN addedDN : addedDNs)
|
{
|
DirectoryServer.deregisterAlternateRootBindDN(addedDN);
|
}
|
|
for (DN deletedDN : delDNs)
|
{
|
try
|
{
|
DirectoryServer.registerAlternateRootDN(configuration.dn(),
|
deletedDN);
|
}
|
catch (Exception e)
|
{
|
// This should also never happen.
|
alternateBindDNs.get(configuration.dn()).remove(deletedDN);
|
}
|
}
|
}
|
}
|
|
if (resultCode == ResultCode.SUCCESS)
|
{
|
alternateBindDNs.put(configuration.dn(), setDNs);
|
}
|
|
return new ConfigChangeResult(resultCode, adminActionRequired, messages);
|
}
|
}
|