/*
|
* 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
|
* or http://forgerock.org/license/CDDLv1.0.html.
|
* 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-2009 Sun Microsystems, Inc.
|
* Portions Copyright 2012-2015 ForgeRock AS.
|
*/
|
package org.opends.server.tools;
|
|
import static org.opends.messages.ConfigMessages.*;
|
import static org.opends.messages.ExtensionMessages.*;
|
import static org.opends.messages.ProtocolMessages.*;
|
import static org.opends.messages.ToolMessages.*;
|
import static org.opends.server.config.ConfigConstants.*;
|
import static org.opends.server.util.ServerConstants.*;
|
import static org.opends.server.util.StaticUtils.*;
|
|
import static com.forgerock.opendj.cli.ArgumentConstants.*;
|
import static com.forgerock.opendj.cli.Utils.*;
|
|
import java.io.File;
|
import java.io.OutputStream;
|
import java.io.PrintStream;
|
import java.io.StringReader;
|
import java.net.InetAddress;
|
import java.security.GeneralSecurityException;
|
import java.util.Collection;
|
import java.util.HashSet;
|
import java.util.LinkedList;
|
import java.util.List;
|
import java.util.Set;
|
|
import javax.crypto.Cipher;
|
|
import org.forgerock.i18n.LocalizableMessage;
|
import org.forgerock.opendj.config.ManagedObjectDefinition;
|
import org.forgerock.opendj.server.config.client.BackendCfgClient;
|
import org.forgerock.opendj.server.config.server.BackendCfg;
|
import org.opends.quicksetup.installer.Installer;
|
import org.opends.server.admin.DefaultBehaviorProvider;
|
import org.opends.server.admin.DefinedDefaultBehaviorProvider;
|
import org.opends.server.admin.StringPropertyDefinition;
|
import org.opends.server.admin.std.meta.CryptoManagerCfgDefn;
|
import org.opends.server.api.ConfigHandler;
|
import org.opends.server.config.BooleanConfigAttribute;
|
import org.opends.server.config.ConfigEntry;
|
import org.opends.server.config.DNConfigAttribute;
|
import org.opends.server.config.IntegerConfigAttribute;
|
import org.opends.server.config.StringConfigAttribute;
|
import org.opends.server.core.DirectoryServer;
|
import org.opends.server.core.LockFileManager;
|
import org.opends.server.extensions.ConfigFileHandler;
|
import org.opends.server.extensions.SaltedSHA512PasswordStorageScheme;
|
import org.opends.server.protocols.ldap.LDAPResultCode;
|
import org.opends.server.types.DN;
|
import org.opends.server.types.DirectoryEnvironmentConfig;
|
import org.opends.server.types.DirectoryException;
|
import org.opends.server.types.Entry;
|
import org.opends.server.types.InitializationException;
|
import org.opends.server.types.LDIFImportConfig;
|
import org.opends.server.types.NullOutputStream;
|
import org.opends.server.util.LDIFReader;
|
|
import com.forgerock.opendj.cli.Argument;
|
import com.forgerock.opendj.cli.ArgumentException;
|
import com.forgerock.opendj.cli.ArgumentParser;
|
import com.forgerock.opendj.cli.BooleanArgument;
|
import com.forgerock.opendj.cli.CliConstants;
|
import com.forgerock.opendj.cli.CommonArguments;
|
import com.forgerock.opendj.cli.FileBasedArgument;
|
import com.forgerock.opendj.cli.IntegerArgument;
|
import com.forgerock.opendj.cli.StringArgument;
|
|
/**
|
* This class provides a very basic tool that can be used to configure some of
|
* the most important settings in the Directory Server. This configuration is
|
* performed by editing the server's configuration files and therefore the
|
* Directory Server must be offline. This utility will be used during the
|
* Directory Server installation process.
|
* <BR><BR>
|
* The options that this tool can currently set include:
|
* <BR>
|
* <UL>
|
* <LI>The port on which the server will listen for LDAP communication</LI>
|
* <LI>The DN and password for the initial root user.
|
* <LI>The set of base DNs for user data</LI>
|
* </UL>
|
*/
|
public class ConfigureDS
|
{
|
private static final boolean WRONG_USAGE = true;
|
|
/** Private exception class to handle error message printing. */
|
@SuppressWarnings("serial")
|
private class ConfigureDSException extends Exception
|
{
|
private final int returnedErrorCode;
|
private final LocalizableMessage errorMessage;
|
private final boolean wrongUsage;
|
|
ConfigureDSException(final LocalizableMessage errorMessage)
|
{
|
this(new Exception("An error occured in ConfigureDS: " + errorMessage), errorMessage, false);
|
}
|
|
ConfigureDSException(final Exception parentException, final LocalizableMessage errorMessage)
|
{
|
this(parentException, errorMessage, false);
|
}
|
|
ConfigureDSException(final LocalizableMessage errorMessage, final boolean showUsage)
|
{
|
this(new Exception("An error occured in ConfigureDS: " + errorMessage), errorMessage, showUsage);
|
}
|
|
ConfigureDSException(final Exception parentException, final LocalizableMessage errorMessage,
|
final boolean showUsage)
|
{
|
this(parentException, errorMessage, showUsage, ERROR);
|
}
|
|
ConfigureDSException(final Exception parentException, final LocalizableMessage errorMessage,
|
final boolean wrongUsage, final int retCode)
|
{
|
super(parentException);
|
this.errorMessage = errorMessage;
|
this.wrongUsage = wrongUsage;
|
returnedErrorCode = retCode;
|
}
|
|
private LocalizableMessage getErrorMessage()
|
{
|
return errorMessage;
|
}
|
|
private boolean isWrongUsage()
|
{
|
return wrongUsage;
|
}
|
|
private int getErrorCode()
|
{
|
return returnedErrorCode;
|
}
|
}
|
|
//FIXME: Find a better way to do to prevent hardcoded ldif entries.
|
private static final String NEW_LINE = System.getProperty("line.separator");
|
|
private static final String JCKES_KEY_MANAGER_DN = "cn=JCEKS,cn=Key Manager Providers,cn=config";
|
private static final String JCKES_KEY_MANAGER_LDIF_ENTRY =
|
"dn: " + JCKES_KEY_MANAGER_DN + NEW_LINE
|
+ "objectClass: top" + NEW_LINE
|
+ "objectClass: ds-cfg-key-manager-provider" + NEW_LINE
|
+ "objectClass: ds-cfg-file-based-key-manager-provider" + NEW_LINE
|
+ "cn: JCEKS" + NEW_LINE
|
+ "ds-cfg-java-class: org.opends.server.extensions.FileBasedKeyManagerProvider" + NEW_LINE
|
+ "ds-cfg-enabled: true" + NEW_LINE
|
+ "ds-cfg-key-store-type: JCEKS" + NEW_LINE
|
+ "ds-cfg-key-store-file: config/keystore.jceks" + NEW_LINE
|
+ "ds-cfg-key-store-pin-file: config/keystore.pin" + NEW_LINE;
|
|
private static final String JCKES_TRUST_MANAGER_DN = "cn=JCEKS,cn=Trust Manager Providers,cn=config";
|
private static final String JCKES_TRUST_MANAGER_LDIF_ENTRY =
|
"dn: " + JCKES_TRUST_MANAGER_DN + NEW_LINE
|
+ "objectClass: top" + NEW_LINE
|
+ "objectClass: ds-cfg-trust-manager-provider" + NEW_LINE
|
+ "objectClass: ds-cfg-file-based-trust-manager-provider" + NEW_LINE
|
+ "cn: JCEKS" + NEW_LINE
|
+ "ds-cfg-java-class: org.opends.server.extensions.FileBasedTrustManagerProvider" + NEW_LINE
|
+ "ds-cfg-enabled: false" + NEW_LINE
|
+ "ds-cfg-trust-store-type: JCEKS" + NEW_LINE
|
+ "ds-cfg-trust-store-file: config/truststore" + NEW_LINE;
|
|
/** The fully-qualified name of this class. */
|
private static final String CLASS_NAME = "org.opends.server.tools.ConfigureDS";
|
|
/** The DN of the configuration entry defining the LDAP connection handler. */
|
public static final String DN_LDAP_CONNECTION_HANDLER = "cn=LDAP Connection Handler," + DN_CONNHANDLER_BASE;
|
|
/** The DN of the configuration entry defining the Administration connector. */
|
public static final String DN_ADMIN_CONNECTOR = "cn=Administration Connector," + DN_CONFIG_ROOT;
|
|
/** The DN of the configuration entry defining the LDAPS connection handler. */
|
private static final String DN_LDAPS_CONNECTION_HANDLER = "cn=LDAPS Connection Handler," + DN_CONNHANDLER_BASE;
|
|
/** The DN of the configuration entry defining the JMX connection handler. */
|
private static final String DN_JMX_CONNECTION_HANDLER = "cn=JMX Connection Handler," + DN_CONNHANDLER_BASE;
|
|
/** The DN of the configuration entry defining the initial root user. */
|
public static final String DN_ROOT_USER = "cn=Directory Manager," + DN_ROOT_DN_CONFIG_BASE;
|
|
/** The DN of the Crypto Manager. */
|
public static final String DN_CRYPTO_MANAGER = "cn=Crypto Manager,cn=config";
|
|
/** The DN of the DIGEST-MD5 SASL mechanism handler. */
|
public static final String DN_DIGEST_MD5_SASL_MECHANISM = "cn=DIGEST-MD5,cn=SASL Mechanisms,cn=config";
|
|
private static int SUCCESS = 0;
|
private static int ERROR = 1;
|
|
/**
|
* Provides the command-line arguments to the <CODE>configMain</CODE> method
|
* for processing.
|
*
|
* @param args The set of command-line arguments provided to this program.
|
*/
|
public static void main(String[] args)
|
{
|
final int exitCode = configMain(args, System.out, System.err);
|
if (exitCode != SUCCESS)
|
{
|
System.exit(filterExitCode(exitCode));
|
}
|
}
|
|
/**
|
* Parses the provided command-line arguments and makes the appropriate
|
* changes to the Directory Server configuration.
|
*
|
* @param args The command-line arguments provided to this program.
|
*
|
* @param outStream Output stream.
|
* @param errStream Error stream.
|
* @return The exit code from the configuration processing. A nonzero value
|
* indicates that there was some kind of problem during the
|
* configuration processing.
|
*/
|
public static int configMain(final String[] args, final OutputStream outStream, final OutputStream errStream)
|
{
|
final ConfigureDS tool = new ConfigureDS(args, outStream, errStream);
|
return tool.run();
|
}
|
|
private final String[] arguments;
|
private final PrintStream out;
|
private final PrintStream err;
|
|
private final ArgumentParser argParser;
|
|
private BooleanArgument showUsage;
|
private BooleanArgument enableStartTLS;
|
private FileBasedArgument rootPasswordFile;
|
private StringArgument hostName;
|
private IntegerArgument ldapPort;
|
private IntegerArgument adminConnectorPort;
|
private IntegerArgument ldapsPort;
|
private IntegerArgument jmxPort;
|
private StringArgument baseDNString;
|
private StringArgument configClass;
|
private StringArgument configFile;
|
private StringArgument rootDNString;
|
private StringArgument rootPassword;
|
private StringArgument keyManagerProviderDN;
|
private StringArgument trustManagerProviderDN;
|
private StringArgument certNickName;
|
private StringArgument keyManagerPath;
|
private StringArgument serverRoot;
|
private StringArgument backendType;
|
|
private final String serverLockFileName = LockFileManager.getServerLockFileName();
|
private final StringBuilder failureReason = new StringBuilder();
|
private ConfigHandler<?> configHandler;
|
|
private ConfigureDS(final String[] args, final OutputStream outStream, final OutputStream errStream)
|
{
|
arguments = args;
|
out = NullOutputStream.wrapOrNullStream(outStream);
|
err = NullOutputStream.wrapOrNullStream(errStream);
|
argParser = new ArgumentParser(CLASS_NAME, INFO_CONFIGDS_TOOL_DESCRIPTION.get(), false);
|
}
|
|
private int run()
|
{
|
try
|
{
|
initializeArguments();
|
parseArguments();
|
if (argParser.usageOrVersionDisplayed())
|
{
|
return SUCCESS;
|
}
|
|
checkArgumentsConsistency();
|
checkPortArguments();
|
|
tryAcquireExclusiveLocks();
|
updateBaseDNs(parseProvidedBaseDNs());
|
|
initializeDirectoryServer();
|
|
final DN rootDN = parseRootDN();
|
final String rootPW = parseRootDNPassword();
|
|
// Get the Directory Server configuration handler and use it to make the
|
// appropriate configuration changes.
|
configHandler = DirectoryServer.getConfigHandler();
|
|
checkManagerProvider(keyManagerProviderDN, JCKES_KEY_MANAGER_DN, JCKES_KEY_MANAGER_LDIF_ENTRY, true);
|
checkManagerProvider(trustManagerProviderDN, JCKES_TRUST_MANAGER_DN, JCKES_TRUST_MANAGER_LDIF_ENTRY, false);
|
// Check that the keystore path values are valid.
|
if (keyManagerPath.isPresent() && !keyManagerProviderDN.isPresent())
|
{
|
final LocalizableMessage message = ERR_CONFIGDS_KEYMANAGER_PROVIDER_DN_REQUIRED.get(
|
keyManagerProviderDN.getLongIdentifier(), keyManagerPath.getLongIdentifier());
|
throw new ConfigureDSException(message);
|
}
|
|
updateLdapPort();
|
updateAdminConnectorPort();
|
updateLdapSecurePort();
|
updateJMXport();
|
updateStartTLS();
|
updateKeyManager();
|
updateTrustManager();
|
updateRootUser(rootDN, rootPW);
|
addFQDNDigestMD5();
|
updateCryptoCipher();
|
writeUpdatedConfiguration();
|
|
return SUCCESS;
|
}
|
catch (final ConfigureDSException e)
|
{
|
if (e.isWrongUsage())
|
{
|
err.println(argParser.getUsage());
|
}
|
err.println(e.getErrorMessage());
|
return e.getErrorCode();
|
}
|
finally
|
{
|
LockFileManager.releaseLock(serverLockFileName, failureReason);
|
}
|
}
|
|
private void initializeArguments() throws ConfigureDSException
|
{
|
try
|
{
|
configFile = new StringArgument(
|
"configfile", 'c', "configFile",
|
true, false, true, INFO_CONFIGFILE_PLACEHOLDER.get(),
|
null, null, INFO_DESCRIPTION_CONFIG_FILE.get());
|
configFile.setHidden(true);
|
argParser.addArgument(configFile);
|
|
configClass = new StringArgument(
|
"configclass", OPTION_SHORT_CONFIG_CLASS, OPTION_LONG_CONFIG_CLASS,
|
false, false, true, INFO_CONFIGCLASS_PLACEHOLDER.get(),
|
ConfigFileHandler.class.getName(), null, INFO_DESCRIPTION_CONFIG_CLASS.get());
|
configClass.setHidden(true);
|
argParser.addArgument(configClass);
|
|
String defaultHostName;
|
try
|
{
|
defaultHostName = InetAddress.getLocalHost().getHostName();
|
}
|
catch (final Exception e)
|
{
|
// Not much we can do here.
|
defaultHostName = "localhost";
|
}
|
|
hostName = new StringArgument(
|
OPTION_LONG_HOST.toLowerCase(), OPTION_SHORT_HOST, OPTION_LONG_HOST,
|
false, false, true, INFO_HOST_PLACEHOLDER.get(),
|
defaultHostName, null, INFO_INSTALLDS_DESCRIPTION_HOST_NAME.get());
|
argParser.addArgument(hostName);
|
|
ldapPort = new IntegerArgument(
|
"ldapport", OPTION_SHORT_PORT, "ldapPort",
|
false, false, true, INFO_LDAPPORT_PLACEHOLDER.get(),
|
389, null, true, 1, true, 65535, INFO_CONFIGDS_DESCRIPTION_LDAP_PORT.get());
|
argParser.addArgument(ldapPort);
|
|
adminConnectorPort = new IntegerArgument(
|
"adminConnectorPort".toLowerCase(), null, "adminConnectorPort",
|
false, false, true, INFO_PORT_PLACEHOLDER.get(),
|
4444, "adminConnectorPort", true, 1, true, 65535, INFO_INSTALLDS_DESCRIPTION_ADMINCONNECTORPORT.get());
|
argParser.addArgument(adminConnectorPort);
|
|
ldapsPort = new IntegerArgument(
|
"ldapsPort", 'P', "ldapsPort",
|
false, false, true, INFO_LDAPPORT_PLACEHOLDER.get(),
|
636, null, true, 1, true, 65535, INFO_CONFIGDS_DESCRIPTION_LDAPS_PORT.get());
|
argParser.addArgument(ldapsPort);
|
|
enableStartTLS = new BooleanArgument(
|
"enableStartTLS", OPTION_SHORT_START_TLS, "enableStartTLS",
|
INFO_CONFIGDS_DESCRIPTION_ENABLE_START_TLS.get());
|
argParser.addArgument(enableStartTLS);
|
|
jmxPort = new IntegerArgument(
|
"jmxport", 'x', "jmxPort",
|
false, false, true, INFO_JMXPORT_PLACEHOLDER.get(),
|
CliConstants.DEFAULT_JMX_PORT, null, true, 1, true, 65535, INFO_CONFIGDS_DESCRIPTION_JMX_PORT.get());
|
argParser.addArgument(jmxPort);
|
|
keyManagerProviderDN = new StringArgument(
|
"keymanagerproviderdn", 'k', "keyManagerProviderDN",
|
false, false, true, INFO_KEY_MANAGER_PROVIDER_DN_PLACEHOLDER.get(),
|
null, null, INFO_CONFIGDS_DESCRIPTION_KEYMANAGER_PROVIDER_DN.get());
|
argParser.addArgument(keyManagerProviderDN);
|
|
trustManagerProviderDN = new StringArgument(
|
"trustmanagerproviderdn", 't', "trustManagerProviderDN",
|
false, false, true, INFO_TRUST_MANAGER_PROVIDER_DN_PLACEHOLDER.get(),
|
null, null, INFO_CONFIGDS_DESCRIPTION_TRUSTMANAGER_PROVIDER_DN.get());
|
argParser.addArgument(trustManagerProviderDN);
|
|
keyManagerPath = new StringArgument(
|
"keymanagerpath", 'm', "keyManagerPath",
|
false, false, true, INFO_KEY_MANAGER_PATH_PLACEHOLDER.get(),
|
null, null, INFO_CONFIGDS_DESCRIPTION_KEYMANAGER_PATH.get());
|
argParser.addArgument(keyManagerPath);
|
|
certNickName = new StringArgument(
|
"certnickname", 'a', "certNickName",
|
false, false, true, INFO_NICKNAME_PLACEHOLDER.get(),
|
null, null, INFO_CONFIGDS_DESCRIPTION_CERTNICKNAME.get());
|
argParser.addArgument(certNickName);
|
|
baseDNString = new StringArgument(
|
"basedn", OPTION_SHORT_BASEDN, OPTION_LONG_BASEDN,
|
false, true, true, INFO_BASEDN_PLACEHOLDER.get(),
|
"dc=example,dc=com", null, INFO_CONFIGDS_DESCRIPTION_BASE_DN.get());
|
argParser.addArgument(baseDNString);
|
|
rootDNString = new StringArgument(
|
"rootdn", OPTION_SHORT_ROOT_USER_DN, OPTION_LONG_ROOT_USER_DN,
|
false, false, true, INFO_ROOT_USER_DN_PLACEHOLDER.get(),
|
"cn=Directory Manager", null, INFO_CONFIGDS_DESCRIPTION_ROOT_DN.get());
|
argParser.addArgument(rootDNString);
|
|
rootPassword = new StringArgument(
|
"rootpw", OPTION_SHORT_BINDPWD, "rootPassword",
|
false, false, true, INFO_ROOT_USER_PWD_PLACEHOLDER.get(),
|
null, null, INFO_CONFIGDS_DESCRIPTION_ROOT_PW.get());
|
argParser.addArgument(rootPassword);
|
|
rootPasswordFile = new FileBasedArgument(
|
"rootpwfile", OPTION_SHORT_BINDPWD_FILE, "rootPasswordFile",
|
false, false, INFO_FILE_PLACEHOLDER.get(),
|
null, null, INFO_CONFIGDS_DESCRIPTION_ROOT_PW_FILE.get());
|
argParser.addArgument(rootPasswordFile);
|
|
showUsage = CommonArguments.getShowUsage();
|
argParser.addArgument(showUsage);
|
argParser.setUsageArgument(showUsage);
|
|
serverRoot = new StringArgument(
|
"serverRoot", OPTION_SHORT_SERVER_ROOT, OPTION_LONG_SERVER_ROOT,
|
false, false, true, INFO_SERVER_ROOT_DIR_PLACEHOLDER.get(),
|
null, null, null);
|
serverRoot.setHidden(true);
|
argParser.addArgument(serverRoot);
|
|
backendType = new StringArgument(
|
OPTION_LONG_BACKEND_TYPE.toLowerCase(), null, OPTION_LONG_BACKEND_TYPE,
|
false, false, true, INFO_INSTALLDS_BACKEND_TYPE_PLACEHOLDER.get(),
|
null, OPTION_LONG_BACKEND_TYPE, INFO_INSTALLDS_DESCRIPTION_BACKEND_TYPE.get()
|
);
|
argParser.addArgument(backendType);
|
}
|
catch (final ArgumentException ae)
|
{
|
throw new ConfigureDSException(ae, ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage()));
|
}
|
}
|
|
private int parseArguments() throws ConfigureDSException
|
{
|
try
|
{
|
argParser.parseArguments(arguments);
|
return SUCCESS;
|
}
|
catch (final ArgumentException ae)
|
{
|
throw new ConfigureDSException(ae, ERR_ERROR_PARSING_ARGS.get(ae.getMessage()),
|
WRONG_USAGE, LDAPResultCode.CLIENT_SIDE_PARAM_ERROR);
|
}
|
}
|
|
/** Make sure that the user actually tried to configure something. */
|
private void checkArgumentsConsistency() throws ConfigureDSException
|
{
|
if (!baseDNString.isPresent()
|
&& !ldapPort.isPresent()
|
&& !jmxPort.isPresent()
|
&& !rootDNString.isPresent())
|
{
|
throw new ConfigureDSException(ERR_CONFIGDS_NO_CONFIG_CHANGES.get(), WRONG_USAGE);
|
}
|
}
|
|
private void checkPortArguments() throws ConfigureDSException
|
{
|
try
|
{
|
final IntegerArgument[] portArgs = {ldapPort, adminConnectorPort, ldapsPort, jmxPort};
|
final Set<Integer> portsAdded = new HashSet<Integer>();
|
|
for (final IntegerArgument portArg : portArgs)
|
{
|
if (portArg.isPresent())
|
{
|
final int portNumber = portArg.getIntValue();
|
if (portsAdded.contains(portNumber))
|
{
|
throw new ConfigureDSException(ERR_CONFIGDS_PORT_ALREADY_SPECIFIED.get(portArg.getIntValue()), WRONG_USAGE);
|
}
|
portsAdded.add(portNumber);
|
}
|
}
|
}
|
catch (final ArgumentException ae)
|
{
|
throw new ConfigureDSException(ae, ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage()));
|
}
|
}
|
|
private void initializeDirectoryServer() throws ConfigureDSException
|
{
|
if (serverRoot.isPresent()) {
|
final DirectoryEnvironmentConfig env = DirectoryServer.getEnvironmentConfig();
|
final String root = serverRoot.getValue();
|
try {
|
env.setServerRoot(new File(serverRoot.getValue()));
|
} catch (final InitializationException e) {
|
ERR_INITIALIZE_SERVER_ROOT.get(root, e.getMessageObject());
|
}
|
}
|
|
// Initialize the Directory Server configuration handler using the
|
// information that was provided.
|
final DirectoryServer directoryServer = DirectoryServer.getInstance();
|
DirectoryServer.bootstrapClient();
|
|
try
|
{
|
DirectoryServer.initializeJMX();
|
}
|
catch (final Exception e)
|
{
|
final LocalizableMessage msg = ERR_CONFIGDS_CANNOT_INITIALIZE_JMX.get(configFile.getValue(), e.getMessage());
|
throw new ConfigureDSException(e, msg);
|
}
|
|
try
|
{
|
directoryServer.initializeConfiguration(configClass.getValue(), configFile.getValue());
|
}
|
catch (final Exception e)
|
{
|
final LocalizableMessage msg = ERR_CONFIGDS_CANNOT_INITIALIZE_CONFIG.get(configFile.getValue(), e.getMessage());
|
throw new ConfigureDSException(e, msg);
|
}
|
|
try
|
{
|
directoryServer.initializeSchema();
|
}
|
catch (final Exception e)
|
{
|
final LocalizableMessage msg = ERR_CONFIGDS_CANNOT_INITIALIZE_SCHEMA.get(configFile.getValue(), e.getMessage());
|
throw new ConfigureDSException(e, msg);
|
}
|
}
|
|
/**
|
* Make sure that we can get an exclusive lock for the Directory Server, so
|
* that no other operation will be allowed while this is in progress.
|
*
|
* @throws ConfigureDSException
|
*/
|
private void tryAcquireExclusiveLocks() throws ConfigureDSException
|
{
|
if (! LockFileManager.acquireExclusiveLock(serverLockFileName, failureReason))
|
{
|
throw new ConfigureDSException(ERR_CONFIGDS_CANNOT_ACQUIRE_SERVER_LOCK.get(serverLockFileName, failureReason));
|
}
|
}
|
|
private LinkedList<org.forgerock.opendj.ldap.DN> parseProvidedBaseDNs() throws ConfigureDSException
|
{
|
LinkedList<org.forgerock.opendj.ldap.DN> baseDNs = new LinkedList<org.forgerock.opendj.ldap.DN>();
|
if (baseDNString.isPresent())
|
{
|
for (final String dnString : baseDNString.getValues())
|
{
|
try
|
{
|
baseDNs.add(org.forgerock.opendj.ldap.DN.valueOf(dnString));
|
}
|
catch (final Exception e)
|
{
|
throw new ConfigureDSException(e, ERR_CONFIGDS_CANNOT_PARSE_BASE_DN.get(dnString, e.getMessage()));
|
}
|
}
|
}
|
|
return baseDNs;
|
}
|
|
private DN parseRootDN() throws ConfigureDSException
|
{
|
DN rootDN = null;
|
if (rootDNString.isPresent())
|
{
|
try
|
{
|
rootDN = DN.valueOf(rootDNString.getValue());
|
}
|
catch (final DirectoryException de)
|
{
|
final LocalizableMessage msg = ERR_CONFIGDS_CANNOT_PARSE_ROOT_DN.get(
|
rootDNString.getValue(), de.getMessageObject());
|
throw new ConfigureDSException(de, msg);
|
}
|
}
|
return rootDN;
|
}
|
|
private String parseRootDNPassword() throws ConfigureDSException
|
{
|
String rootPW = null;
|
if (rootDNString.isPresent())
|
{
|
if (rootPassword.isPresent())
|
{
|
rootPW = rootPassword.getValue();
|
}
|
else if (rootPasswordFile.isPresent())
|
{
|
rootPW = rootPasswordFile.getValue();
|
}
|
else
|
{
|
throw new ConfigureDSException(ERR_CONFIGDS_NO_ROOT_PW.get());
|
}
|
}
|
return rootPW;
|
}
|
|
private void checkManagerProvider(final Argument arg, final String jckesDN, final String ldifEntry,
|
final boolean isKeyManager) throws ConfigureDSException
|
{
|
if (arg.isPresent())
|
{
|
DN dn = null;
|
DN JCEKSManagerDN = null;
|
try
|
{
|
dn = DN.valueOf(trustManagerProviderDN.getValue());
|
JCEKSManagerDN = DN.valueOf(jckesDN);
|
}
|
catch (final DirectoryException de)
|
{
|
final String value = trustManagerProviderDN.getValue();
|
final LocalizableMessage errorMessage = de.getMessageObject();
|
final LocalizableMessage message =
|
isKeyManager ? ERR_CONFIGDS_CANNOT_PARSE_KEYMANAGER_PROVIDER_DN.get(value, errorMessage)
|
: ERR_CONFIGDS_CANNOT_PARSE_TRUSTMANAGER_PROVIDER_DN.get(value, errorMessage);
|
throw new ConfigureDSException(de, message);
|
}
|
|
if (dn.equals(JCEKSManagerDN))
|
{
|
LDIFReader reader = null;
|
try
|
{
|
|
final String ldif = ldifEntry;
|
final LDIFImportConfig ldifImportConfig = new LDIFImportConfig(new StringReader(ldif));
|
reader = new LDIFReader(ldifImportConfig);
|
Entry mangerConfigEntry;
|
while ((mangerConfigEntry = reader.readEntry()) != null)
|
{
|
configHandler.addEntry(mangerConfigEntry, null);
|
}
|
}
|
catch (final Exception e)
|
{
|
final LocalizableMessage message = isKeyManager ? ERR_CONFIG_KEYMANAGER_CANNOT_CREATE_JCEKS_PROVIDER.get(e)
|
: ERR_CONFIG_KEYMANAGER_CANNOT_GET_BASE.get(e);
|
throw new ConfigureDSException(e, message);
|
}
|
finally
|
{
|
close(reader);
|
}
|
}
|
else
|
{
|
try
|
{
|
configHandler.getConfigEntry(dn);
|
}
|
catch (final Exception e)
|
{
|
final LocalizableMessage message = isKeyManager ? ERR_CONFIG_KEYMANAGER_CANNOT_GET_BASE.get(e)
|
: ERR_CONFIG_TRUSTMANAGER_CANNOT_GET_BASE.get(e);
|
throw new ConfigureDSException(e, message);
|
}
|
}
|
}
|
}
|
|
@SuppressWarnings("unchecked")
|
private void updateBaseDNs(final List<org.forgerock.opendj.ldap.DN> baseDNs) throws ConfigureDSException
|
{
|
if (!baseDNs.isEmpty())
|
{
|
final String backendTypeName = backendType.getValue();
|
final BackendTypeHelper backendTypeHelper = new BackendTypeHelper();
|
final ManagedObjectDefinition<?, ?> backend = backendTypeHelper.retrieveBackendTypeFromName(backendTypeName);
|
if (backend == null)
|
{
|
throw new ConfigureDSException(
|
ERR_CONFIGDS_BACKEND_TYPE_UNKNOWN.get(backendTypeName, backendTypeHelper.getPrintableBackendTypeNames()));
|
}
|
|
try
|
{
|
BackendCreationHelper.createBackendOffline(Installer.ROOT_BACKEND_NAME, baseDNs,
|
(ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg>) backend);
|
}
|
catch (Exception e)
|
{
|
throw new ConfigureDSException(ERR_CONFIGDS_SET_BACKEND_TYPE.get(backendTypeName, e.getMessage()));
|
}
|
}
|
}
|
|
private void updateLdapPort() throws ConfigureDSException
|
{
|
if (ldapPort.isPresent())
|
{
|
try
|
{
|
final IntegerConfigAttribute portAttr = new IntegerConfigAttribute(
|
ATTR_LISTEN_PORT, INFO_LDAP_CONNHANDLER_DESCRIPTION_LISTEN_PORT.get(),
|
true, false, true, true, 1, true, 65535, ldapPort.getIntValue());
|
final ConfigEntry configEntry = configHandler.getConfigEntry(DN.valueOf(DN_LDAP_CONNECTION_HANDLER));
|
configEntry.putConfigAttribute(portAttr);
|
}
|
catch (final Exception e)
|
{
|
throw new ConfigureDSException(e, ERR_CONFIGDS_CANNOT_UPDATE_LDAP_PORT.get(e));
|
}
|
}
|
}
|
|
private void updateAdminConnectorPort() throws ConfigureDSException
|
{
|
if (adminConnectorPort.isPresent())
|
{
|
try
|
{
|
final IntegerConfigAttribute portAttr = new IntegerConfigAttribute(
|
ATTR_LISTEN_PORT, INFO_LDAP_CONNHANDLER_DESCRIPTION_LISTEN_PORT.get(),
|
true, false, true, true, 1, true, 65535, adminConnectorPort.getIntValue());
|
final ConfigEntry configEntry = configHandler.getConfigEntry(DN.valueOf(DN_ADMIN_CONNECTOR));
|
configEntry.putConfigAttribute(portAttr);
|
}
|
catch (final Exception e)
|
{
|
throw new ConfigureDSException(e, ERR_CONFIGDS_CANNOT_UPDATE_ADMIN_CONNECTOR_PORT.get(e));
|
}
|
}
|
}
|
|
private void updateLdapSecurePort() throws ConfigureDSException
|
{
|
if (ldapsPort.isPresent())
|
{
|
try
|
{
|
final IntegerConfigAttribute portAttr = new IntegerConfigAttribute(
|
ATTR_LISTEN_PORT, INFO_LDAP_CONNHANDLER_DESCRIPTION_LISTEN_PORT.get(),
|
true, false, true, true, 1, true, 65535, ldapsPort.getIntValue());
|
final ConfigEntry configEntry = configHandler.getConfigEntry(DN.valueOf(DN_LDAPS_CONNECTION_HANDLER));
|
configEntry.putConfigAttribute(portAttr);
|
|
final BooleanConfigAttribute enablePortAttr = new BooleanConfigAttribute(
|
ATTR_CONNECTION_HANDLER_ENABLED, INFO_LDAPS_CONNHANDLER_DESCRIPTION_ENABLE.get(), true, true);
|
configEntry.putConfigAttribute(enablePortAttr);
|
}
|
catch (final Exception e)
|
{
|
throw new ConfigureDSException(e, ERR_CONFIGDS_CANNOT_UPDATE_LDAPS_PORT.get(e));
|
}
|
}
|
}
|
|
private void updateJMXport() throws ConfigureDSException
|
{
|
if (jmxPort.isPresent())
|
{
|
try
|
{
|
|
final IntegerConfigAttribute portAttr = new IntegerConfigAttribute(
|
ATTR_LISTEN_PORT, INFO_JMX_CONNHANDLER_DESCRIPTION_LISTEN_PORT.get(),
|
true, false, true, true, 1, true, 65535, jmxPort.getIntValue());
|
final ConfigEntry configEntry = configHandler.getConfigEntry(DN.valueOf(DN_JMX_CONNECTION_HANDLER));
|
configEntry.putConfigAttribute(portAttr);
|
|
final BooleanConfigAttribute enablePortAttr = new BooleanConfigAttribute(
|
ATTR_CONNECTION_HANDLER_ENABLED, INFO_JMX_CONNHANDLER_DESCRIPTION_ENABLE.get(), true, true);
|
configEntry.putConfigAttribute(enablePortAttr);
|
}
|
catch (final Exception e)
|
{
|
throw new ConfigureDSException(e, ERR_CONFIGDS_CANNOT_UPDATE_JMX_PORT.get(e));
|
}
|
}
|
}
|
|
private void updateStartTLS() throws ConfigureDSException
|
{
|
if (enableStartTLS.isPresent())
|
{
|
try
|
{
|
final BooleanConfigAttribute startTLS = new BooleanConfigAttribute(
|
ATTR_ALLOW_STARTTLS, INFO_LDAP_CONNHANDLER_DESCRIPTION_ALLOW_STARTTLS.get(), true, true);
|
final ConfigEntry configEntry = configHandler.getConfigEntry(DN.valueOf(DN_LDAP_CONNECTION_HANDLER));
|
configEntry.putConfigAttribute(startTLS);
|
}
|
catch (final Exception e)
|
{
|
throw new ConfigureDSException(e, ERR_CONFIGDS_CANNOT_ENABLE_STARTTLS.get(e));
|
}
|
}
|
}
|
|
private void updateKeyManager() throws ConfigureDSException
|
{
|
if (keyManagerProviderDN.isPresent())
|
{
|
if (enableStartTLS.isPresent() || ldapsPort.isPresent())
|
{
|
try
|
{
|
// Enable the key manager
|
final BooleanConfigAttribute enableAttr = new BooleanConfigAttribute(
|
ATTR_KEYMANAGER_ENABLED, INFO_CONFIG_KEYMANAGER_DESCRIPTION_ENABLED.get(), true, true);
|
final ConfigEntry configEntry = configHandler.getConfigEntry(DN.valueOf(keyManagerProviderDN.getValue()));
|
configEntry.putConfigAttribute(enableAttr);
|
}
|
catch (final Exception e)
|
{
|
throw new ConfigureDSException(e, ERR_CONFIGDS_CANNOT_ENABLE_KEYMANAGER.get(e));
|
}
|
}
|
|
putKeyManagerConfigAttribute(enableStartTLS, DN_LDAP_CONNECTION_HANDLER);
|
putKeyManagerConfigAttribute(ldapsPort, DN_LDAPS_CONNECTION_HANDLER);
|
|
if (keyManagerPath.isPresent())
|
{
|
try
|
{
|
final StringConfigAttribute pathAttr = new StringConfigAttribute(
|
ATTR_KEYSTORE_FILE, INFO_FILE_KEYMANAGER_DESCRIPTION_FILE.get(),
|
true, true, true, keyManagerPath.getValue());
|
final ConfigEntry configEntry = configHandler.getConfigEntry(DN.valueOf(keyManagerProviderDN.getValue()));
|
configEntry.putConfigAttribute(pathAttr);
|
}
|
catch (final Exception e)
|
{
|
throw new ConfigureDSException(e, LocalizableMessage.raw(e.toString()));
|
}
|
}
|
}
|
}
|
|
private void putKeyManagerConfigAttribute(final Argument arg, final String attributeDN)
|
throws ConfigureDSException
|
{
|
if (arg.isPresent())
|
{
|
try
|
{
|
final StringConfigAttribute keyManagerProviderAttr = new StringConfigAttribute(
|
ATTR_KEYMANAGER_DN, INFO_LDAP_CONNHANDLER_DESCRIPTION_KEYMANAGER_DN.get(),
|
false, false, true, keyManagerProviderDN.getValue());
|
final ConfigEntry configEntry = configHandler.getConfigEntry(DN.valueOf(attributeDN));
|
configEntry.putConfigAttribute(keyManagerProviderAttr);
|
}
|
catch (final Exception e)
|
{
|
throw new ConfigureDSException(e, ERR_CONFIGDS_CANNOT_UPDATE_KEYMANAGER_REFERENCE.get(e));
|
}
|
}
|
}
|
|
private void updateTrustManager() throws ConfigureDSException
|
{
|
if (trustManagerProviderDN.isPresent())
|
{
|
if (enableStartTLS.isPresent() || ldapsPort.isPresent())
|
{
|
try
|
{
|
final BooleanConfigAttribute enableAttr = new BooleanConfigAttribute(
|
ATTR_TRUSTMANAGER_ENABLED, ERR_CONFIG_TRUSTMANAGER_DESCRIPTION_ENABLED.get(), true, true);
|
final ConfigEntry configEntry = configHandler.getConfigEntry(DN.valueOf(trustManagerProviderDN.getValue()));
|
configEntry.putConfigAttribute(enableAttr);
|
}
|
catch (final Exception e)
|
{
|
throw new ConfigureDSException(e, ERR_CONFIGDS_CANNOT_ENABLE_TRUSTMANAGER.get(e));
|
}
|
}
|
putTrustManagerAttribute(enableStartTLS, DN_LDAP_CONNECTION_HANDLER);
|
putTrustManagerAttribute(ldapsPort, DN_LDAPS_CONNECTION_HANDLER);
|
}
|
|
if (certNickName.isPresent())
|
{
|
final StringConfigAttribute certNickNameAttr = new StringConfigAttribute(
|
ATTR_SSL_CERT_NICKNAME, INFO_LDAP_CONNHANDLER_DESCRIPTION_SSL_CERT_NICKNAME.get(),
|
false, false, true, certNickName.getValue());
|
updateCertNicknameEntry(ldapPort, DN_LDAP_CONNECTION_HANDLER, certNickNameAttr);
|
updateCertNicknameEntry(ldapsPort, DN_LDAPS_CONNECTION_HANDLER, certNickNameAttr);
|
|
final StringConfigAttribute certNickNameJmxAttr = new StringConfigAttribute(
|
ATTR_SSL_CERT_NICKNAME, INFO_JMX_CONNHANDLER_DESCRIPTION_SSL_CERT_NICKNAME.get(),
|
false, false, true, certNickName.getValue());
|
updateCertNicknameEntry(jmxPort, DN_JMX_CONNECTION_HANDLER, certNickNameJmxAttr);
|
}
|
else
|
{
|
// Use the key manager specified for connection handlers
|
removeSSLCertNicknameAttribute(DN_LDAP_CONNECTION_HANDLER);
|
removeSSLCertNicknameAttribute(DN_LDAPS_CONNECTION_HANDLER);
|
removeSSLCertNicknameAttribute(DN_JMX_CONNECTION_HANDLER);
|
}
|
}
|
|
private void putTrustManagerAttribute(final Argument arg, final String attributeDN) throws ConfigureDSException
|
{
|
if (arg.isPresent())
|
{
|
try
|
{
|
final StringConfigAttribute trustManagerProviderAttr = new StringConfigAttribute(
|
ATTR_TRUSTMANAGER_DN, INFO_LDAP_CONNHANDLER_DESCRIPTION_TRUSTMANAGER_DN.get(),
|
false, false, true, trustManagerProviderDN.getValue());
|
final ConfigEntry configEntry = configHandler.getConfigEntry(DN.valueOf(attributeDN));
|
configEntry.putConfigAttribute(trustManagerProviderAttr);
|
}
|
catch (final Exception e)
|
{
|
throw new ConfigureDSException(e, ERR_CONFIGDS_CANNOT_UPDATE_TRUSTMANAGER_REFERENCE.get(e));
|
}
|
}
|
}
|
|
private void updateCertNicknameEntry(final Argument arg, final String attributeDN,
|
final StringConfigAttribute configAttr) throws ConfigureDSException
|
{
|
try
|
{
|
ConfigEntry configEntry = configHandler.getConfigEntry(DN.valueOf(attributeDN));
|
if (arg.isPresent())
|
{
|
configEntry.putConfigAttribute(configAttr);
|
}
|
else
|
{
|
configEntry.removeConfigAttribute(ATTR_SSL_CERT_NICKNAME);
|
}
|
}
|
catch (final Exception e)
|
{
|
throw new ConfigureDSException(e, ERR_CONFIGDS_CANNOT_UPDATE_CERT_NICKNAME.get(e));
|
}
|
}
|
|
private void removeSSLCertNicknameAttribute(final String attributeDN) throws ConfigureDSException
|
{
|
try
|
{
|
final ConfigEntry configEntry = configHandler.getConfigEntry(DN.valueOf(attributeDN));
|
configEntry.removeConfigAttribute(ATTR_SSL_CERT_NICKNAME.toLowerCase());
|
}
|
catch (final Exception e)
|
{
|
throw new ConfigureDSException(e, ERR_CONFIGDS_CANNOT_UPDATE_CERT_NICKNAME.get(e));
|
}
|
}
|
|
private void updateRootUser(final DN rootDN, final String rootPW) throws ConfigureDSException
|
{
|
if (rootDN != null)
|
{
|
try
|
{
|
final DNConfigAttribute bindDNAttr = new DNConfigAttribute(
|
ATTR_ROOTDN_ALTERNATE_BIND_DN, INFO_CONFIG_ROOTDN_DESCRIPTION_ALTERNATE_BIND_DN.get(),
|
false, true, false, rootDN);
|
final ConfigEntry configEntry = configHandler.getConfigEntry(DN.valueOf(DN_ROOT_USER));
|
configEntry.putConfigAttribute(bindDNAttr);
|
|
final String encodedPassword = SaltedSHA512PasswordStorageScheme.encodeOffline(getBytes(rootPW));
|
final StringConfigAttribute bindPWAttr = new StringConfigAttribute(
|
ATTR_USER_PASSWORD, LocalizableMessage.EMPTY, false, false, false, encodedPassword);
|
configEntry.putConfigAttribute(bindPWAttr);
|
}
|
catch (final Exception e)
|
{
|
throw new ConfigureDSException(e, ERR_CONFIGDS_CANNOT_UPDATE_ROOT_USER.get(e));
|
}
|
}
|
}
|
|
/** Set the FQDN for the DIGEST-MD5 SASL mechanism. */
|
private void addFQDNDigestMD5() throws ConfigureDSException
|
{
|
try
|
{
|
final StringConfigAttribute fqdnAttr = new StringConfigAttribute(
|
"ds-cfg-server-fqdn", LocalizableMessage.EMPTY, false, false, false, hostName.getValue());
|
final ConfigEntry configEntry = configHandler.getConfigEntry(DN.valueOf(DN_DIGEST_MD5_SASL_MECHANISM));
|
configEntry.putConfigAttribute(fqdnAttr);
|
}
|
catch (final Exception e)
|
{
|
throw new ConfigureDSException(e, ERR_CONFIGDS_CANNOT_UPDATE_DIGEST_MD5_FQDN.get(e));
|
}
|
}
|
|
/**
|
* Check that the cipher specified is supported. This is intended to fix
|
* issues with JVM that do not support the default cipher (see issue 3075 for
|
* instance).
|
*
|
* @throws ConfigureDSException
|
*/
|
private void updateCryptoCipher() throws ConfigureDSException
|
{
|
final CryptoManagerCfgDefn cryptoManager = CryptoManagerCfgDefn.getInstance();
|
final StringPropertyDefinition prop = cryptoManager.getKeyWrappingTransformationPropertyDefinition();
|
String defaultCipher = null;
|
|
final DefaultBehaviorProvider<?> p = prop.getDefaultBehaviorProvider();
|
if (p instanceof DefinedDefaultBehaviorProvider)
|
{
|
final Collection<?> defaultValues = ((DefinedDefaultBehaviorProvider<?>) p).getDefaultValues();
|
if (!defaultValues.isEmpty())
|
{
|
defaultCipher = defaultValues.iterator().next().toString();
|
}
|
}
|
|
if (defaultCipher != null)
|
{
|
// Check that the default cipher is supported by the JVM.
|
try
|
{
|
Cipher.getInstance(defaultCipher);
|
}
|
catch (final GeneralSecurityException ex)
|
{
|
// The cipher is not supported: try to find an alternative one.
|
final String alternativeCipher = getAlternativeCipher();
|
if (alternativeCipher != null)
|
{
|
try
|
{
|
final StringConfigAttribute keyWrappingTransformation = new StringConfigAttribute(
|
ATTR_CRYPTO_CIPHER_KEY_WRAPPING_TRANSFORMATION, LocalizableMessage.EMPTY,
|
false, false, true, alternativeCipher);
|
final ConfigEntry configEntry = configHandler.getConfigEntry(DN.valueOf(DN_CRYPTO_MANAGER));
|
configEntry.putConfigAttribute(keyWrappingTransformation);
|
}
|
catch (final Exception e)
|
{
|
throw new ConfigureDSException(e, ERR_CONFIGDS_CANNOT_UPDATE_CRYPTO_MANAGER.get(e));
|
}
|
}
|
}
|
}
|
}
|
|
private void writeUpdatedConfiguration() throws ConfigureDSException
|
{
|
try
|
{
|
configHandler.writeUpdatedConfig();
|
out.println(wrapText(INFO_CONFIGDS_WROTE_UPDATED_CONFIG.get(), MAX_LINE_WIDTH));
|
}
|
catch (final DirectoryException de)
|
{
|
throw new ConfigureDSException(de, ERR_CONFIGDS_CANNOT_WRITE_UPDATED_CONFIG.get(de.getMessageObject()));
|
}
|
}
|
|
/**
|
* Returns a cipher that is supported by the JVM we are running at.
|
* Returns <CODE>null</CODE> if no alternative cipher could be found.
|
* @return a cipher that is supported by the JVM we are running at.
|
*/
|
public static String getAlternativeCipher()
|
{
|
final String[] preferredAlternativeCiphers =
|
{
|
"RSA/ECB/OAEPWITHSHA1ANDMGF1PADDING",
|
"RSA/ECB/PKCS1Padding"
|
};
|
String alternativeCipher = null;
|
for (final String cipher : preferredAlternativeCiphers)
|
{
|
try
|
{
|
Cipher.getInstance(cipher);
|
alternativeCipher = cipher;
|
break;
|
}
|
catch (final Throwable t)
|
{
|
}
|
}
|
return alternativeCipher;
|
}
|
}
|