com.unboundid.util.MultiServerLDAPCommandLineTool Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of unboundid-ldapsdk Show documentation
Show all versions of unboundid-ldapsdk Show documentation
The UnboundID LDAP SDK for Java is a fast, comprehensive, and easy-to-use
Java API for communicating with LDAP directory servers and performing
related tasks like reading and writing LDIF, encoding and decoding data
using base64 and ASN.1 BER, and performing secure communication. This
package contains the Standard Edition of the LDAP SDK, which is a
complete, general-purpose library for communicating with LDAPv3 directory
servers.
/*
* Copyright 2012-2023 Ping Identity Corporation
* All Rights Reserved.
*/
/*
* Copyright 2012-2023 Ping Identity Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright (C) 2012-2023 Ping Identity Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPLv2 only)
* or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*/
package com.unboundid.util;
import java.io.OutputStream;
import java.util.concurrent.atomic.AtomicReference;
import javax.net.SocketFactory;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import com.unboundid.ldap.sdk.BindRequest;
import com.unboundid.ldap.sdk.ExtendedResult;
import com.unboundid.ldap.sdk.InternalSDKHelper;
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPConnectionOptions;
import com.unboundid.ldap.sdk.LDAPConnectionPool;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.PostConnectProcessor;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.ldap.sdk.ServerSet;
import com.unboundid.ldap.sdk.SimpleBindRequest;
import com.unboundid.ldap.sdk.SingleServerSet;
import com.unboundid.ldap.sdk.StartTLSPostConnectProcessor;
import com.unboundid.ldap.sdk.extensions.StartTLSExtendedRequest;
import com.unboundid.util.args.ArgumentException;
import com.unboundid.util.args.ArgumentParser;
import com.unboundid.util.args.BooleanArgument;
import com.unboundid.util.args.DNArgument;
import com.unboundid.util.args.FileArgument;
import com.unboundid.util.args.IntegerArgument;
import com.unboundid.util.args.StringArgument;
import com.unboundid.util.ssl.AggregateTrustManager;
import com.unboundid.util.ssl.KeyStoreKeyManager;
import com.unboundid.util.ssl.SSLUtil;
import com.unboundid.util.ssl.TrustAllTrustManager;
import com.unboundid.util.ssl.TrustStoreTrustManager;
import static com.unboundid.util.UtilityMessages.*;
/**
* This class provides a basis for developing command-line tools that have the
* ability to communicate with multiple directory servers, potentially with
* very different settings for each. For example, it may be used to help create
* tools that move or compare data from one server to another.
*
* Each server will be identified by a prefix and/or suffix that will be added
* to the argument name (e.g., if the first server has a prefix of "source",
* then the "hostname" argument will actually be "sourceHostname"). The
* base names for the arguments this class supports include:
*
* - hostname -- Specifies the address of the directory server. If this
* isn't specified, then a default of "localhost" will be used.
* - port -- specifies the port number of the directory server. If this
* isn't specified, then a default port of 389 will be used.
* - bindDN -- Specifies the DN to use to bind to the directory server using
* simple authentication. If this isn't specified, then simple
* authentication will not be performed.
* - bindPassword -- Specifies the password to use when binding with simple
* authentication or a password-based SASL mechanism.
* - bindPasswordFile -- Specifies the path to a file containing the
* password to use when binding with simple authentication or a
* password-based SASL mechanism.
* - useSSL -- Indicates that communication with the server should be
* secured using SSL.
* - useStartTLS -- Indicates that communication with the server should be
* secured using StartTLS.
* - "--defaultTrust" -- Indicates that the client should use a default,
* non-interactive mechanism for determining whether to trust any
* presented server certificate.
* - trustAll -- Indicates that the client should trust any certificate
* that the server presents to it.
* - keyStorePath -- Specifies the path to the key store to use to obtain
* client certificates.
* - keyStorePassword -- Specifies the password to use to access the
* contents of the key store.
* - keyStorePasswordFile -- Specifies the path ot a file containing the
* password to use to access the contents of the key store.
* - keyStoreFormat -- Specifies the format to use for the key store
* file.
* - trustStorePath -- Specifies the path to the trust store to use to
* obtain client certificates.
* - trustStorePassword -- Specifies the password to use to access the
* contents of the trust store.
* - trustStorePasswordFile -- Specifies the path ot a file containing the
* password to use to access the contents of the trust store.
* - trustStoreFormat -- Specifies the format to use for the trust store
* file.
* - certNickname -- Specifies the nickname of the client certificate to
* use when performing SSL client authentication.
* - saslOption -- Specifies a SASL option to use when performing SASL
* authentication.
*
* If SASL authentication is to be used, then a "mech" SASL option must be
* provided to specify the name of the SASL mechanism to use. Depending on the
* SASL mechanism, additional SASL options may be required or optional.
*/
@Extensible()
@ThreadSafety(level=ThreadSafetyLevel.INTERFACE_NOT_THREADSAFE)
public abstract class MultiServerLDAPCommandLineTool
extends CommandLineTool
{
// The set of prefixes and suffixes that will be used for server names.
private final int numServers;
@Nullable private final String[] serverNamePrefixes;
@Nullable private final String[] serverNameSuffixes;
// The set of arguments used to hold information about connection properties.
@NotNull private final BooleanArgument[] defaultTrust;
@NotNull private final BooleanArgument[] trustAll;
@NotNull private final BooleanArgument[] useSSL;
@NotNull private final BooleanArgument[] useStartTLS;
@NotNull private final DNArgument[] bindDN;
@NotNull private final FileArgument[] bindPasswordFile;
@NotNull private final FileArgument[] keyStorePasswordFile;
@NotNull private final FileArgument[] trustStorePasswordFile;
@NotNull private final IntegerArgument[] port;
@NotNull private final StringArgument[] bindPassword;
@NotNull private final StringArgument[] certificateNickname;
@NotNull private final StringArgument[] host;
@NotNull private final StringArgument[] keyStoreFormat;
@NotNull private final StringArgument[] keyStorePath;
@NotNull private final StringArgument[] keyStorePassword;
@NotNull private final StringArgument[] saslOption;
@NotNull private final StringArgument[] trustStoreFormat;
@NotNull private final StringArgument[] trustStorePath;
@NotNull private final StringArgument[] trustStorePassword;
// Variables used when creating and authenticating connections.
@NotNull private final BindRequest[] bindRequest;
@NotNull private final ServerSet[] serverSet;
@NotNull private final SSLSocketFactory[] startTLSSocketFactory;
// An atomic reference to an aggregate trust manager that will check a
// JVM-default set of trusted issuers, and then its own cache, before
// prompting the user about whether to trust the presented certificate chain.
// Re-using this trust manager will allow the tool to benefit from a common
// cache if multiple connections are needed.
@NotNull private final AtomicReference
promptTrustManager;
/**
* Creates a new instance of this multi-server LDAP command-line tool. At
* least one of the set of server name prefixes and suffixes must be
* non-{@code null}. If both are non-{@code null}, then they must have the
* same number of elements.
*
* @param outStream The output stream to use for standard output.
* It may be {@code System.out} for the JVM's
* default standard output stream, {@code null} if
* no output should be generated, or a custom
* output stream if the output should be sent to
* an alternate location.
* @param errStream The output stream to use for standard error.
* It may be {@code System.err} for the JVM's
* default standard error stream, {@code null} if
* no output should be generated, or a custom
* output stream if the output should be sent to
* an alternate location.
* @param serverNamePrefixes The prefixes to include before the names of
* each of the parameters to identify each server.
* It may be {@code null} if only suffixes should
* be used.
* @param serverNameSuffixes The suffixes to include after the names of each
* of the parameters to identify each server. It
* may be {@code null} if only prefixes should be
* used.
*
* @throws LDAPSDKUsageException If both the sets of server name prefixes
* and suffixes are {@code null} or empty, or
* if both sets are non-{@code null} but have
* different numbers of elements.
*/
public MultiServerLDAPCommandLineTool(@Nullable final OutputStream outStream,
@Nullable final OutputStream errStream,
@Nullable final String[] serverNamePrefixes,
@Nullable final String[] serverNameSuffixes)
throws LDAPSDKUsageException
{
super(outStream, errStream);
promptTrustManager = new AtomicReference<>();
this.serverNamePrefixes = serverNamePrefixes;
this.serverNameSuffixes = serverNameSuffixes;
if (serverNamePrefixes == null)
{
if (serverNameSuffixes == null)
{
throw new LDAPSDKUsageException(
ERR_MULTI_LDAP_TOOL_PREFIXES_AND_SUFFIXES_NULL.get());
}
else
{
numServers = serverNameSuffixes.length;
}
}
else
{
numServers = serverNamePrefixes.length;
if ((serverNameSuffixes != null) &&
(serverNamePrefixes.length != serverNameSuffixes.length))
{
throw new LDAPSDKUsageException(
ERR_MULTI_LDAP_TOOL_PREFIXES_AND_SUFFIXES_MISMATCH.get());
}
}
if (numServers == 0)
{
throw new LDAPSDKUsageException(
ERR_MULTI_LDAP_TOOL_PREFIXES_AND_SUFFIXES_EMPTY.get());
}
defaultTrust = new BooleanArgument[numServers];
trustAll = new BooleanArgument[numServers];
useSSL = new BooleanArgument[numServers];
useStartTLS = new BooleanArgument[numServers];
bindDN = new DNArgument[numServers];
bindPasswordFile = new FileArgument[numServers];
keyStorePasswordFile = new FileArgument[numServers];
trustStorePasswordFile = new FileArgument[numServers];
port = new IntegerArgument[numServers];
bindPassword = new StringArgument[numServers];
certificateNickname = new StringArgument[numServers];
host = new StringArgument[numServers];
keyStoreFormat = new StringArgument[numServers];
keyStorePath = new StringArgument[numServers];
keyStorePassword = new StringArgument[numServers];
saslOption = new StringArgument[numServers];
trustStoreFormat = new StringArgument[numServers];
trustStorePath = new StringArgument[numServers];
trustStorePassword = new StringArgument[numServers];
bindRequest = new BindRequest[numServers];
serverSet = new ServerSet[numServers];
startTLSSocketFactory = new SSLSocketFactory[numServers];
}
/**
* {@inheritDoc}
*/
@Override()
public final void addToolArguments(@NotNull final ArgumentParser parser)
throws ArgumentException
{
for (int i=0; i < numServers; i++)
{
final StringBuilder groupNameBuffer = new StringBuilder();
if (serverNamePrefixes != null)
{
final String prefix = serverNamePrefixes[i].replace('-', ' ').trim();
groupNameBuffer.append(StaticUtils.capitalize(prefix, true));
}
if (serverNameSuffixes != null)
{
if (groupNameBuffer.length() > 0)
{
groupNameBuffer.append(' ');
}
final String suffix = serverNameSuffixes[i].replace('-', ' ').trim();
groupNameBuffer.append(StaticUtils.capitalize(suffix, true));
}
groupNameBuffer.append(' ');
groupNameBuffer.append(INFO_MULTI_LDAP_TOOL_GROUP_CONN_AND_AUTH.get());
final String groupName = groupNameBuffer.toString();
host[i] = new StringArgument(null, genArgName(i, "hostname"), true, 1,
INFO_LDAP_TOOL_PLACEHOLDER_HOST.get(),
INFO_LDAP_TOOL_DESCRIPTION_HOST.get(), "localhost");
if (includeAlternateLongIdentifiers())
{
host[i].addLongIdentifier(genDashedArgName(i, "hostname"), true);
host[i].addLongIdentifier(genArgName(i, "host"), true);
host[i].addLongIdentifier(genDashedArgName(i, "host"), true);
host[i].addLongIdentifier(genArgName(i, "address"), true);
host[i].addLongIdentifier(genDashedArgName(i, "address"), true);
}
host[i].setArgumentGroupName(groupName);
parser.addArgument(host[i]);
port[i] = new IntegerArgument(null, genArgName(i, "port"), true, 1,
INFO_LDAP_TOOL_PLACEHOLDER_PORT.get(),
INFO_LDAP_TOOL_DESCRIPTION_PORT.get(), 1, 65_535, 389);
port[i].setArgumentGroupName(groupName);
if (includeAlternateLongIdentifiers())
{
port[i].addLongIdentifier(genDashedArgName(i, "port"), true);
}
parser.addArgument(port[i]);
bindDN[i] = new DNArgument(null, genArgName(i, "bindDN"), false, 1,
INFO_LDAP_TOOL_PLACEHOLDER_DN.get(),
INFO_LDAP_TOOL_DESCRIPTION_BIND_DN.get());
if (includeAlternateLongIdentifiers())
{
bindDN[i].addLongIdentifier(genDashedArgName(i, "bind-dn"), true);
}
bindDN[i].setArgumentGroupName(groupName);
parser.addArgument(bindDN[i]);
bindPassword[i] = new StringArgument(null, genArgName(i, "bindPassword"),
false, 1, INFO_LDAP_TOOL_PLACEHOLDER_PASSWORD.get(),
INFO_LDAP_TOOL_DESCRIPTION_BIND_PW.get());
if (includeAlternateLongIdentifiers())
{
bindPassword[i].addLongIdentifier(genDashedArgName(i, "bind-password"),
true);
}
bindPassword[i].setSensitive(true);
bindPassword[i].setArgumentGroupName(groupName);
parser.addArgument(bindPassword[i]);
bindPasswordFile[i] = new FileArgument(null,
genArgName(i, "bindPasswordFile"), false, 1,
INFO_LDAP_TOOL_PLACEHOLDER_PATH.get(),
INFO_LDAP_TOOL_DESCRIPTION_BIND_PW_FILE.get(), true, true, true,
false);
if (includeAlternateLongIdentifiers())
{
bindPasswordFile[i].addLongIdentifier(genDashedArgName(i,
"bind-password-file"), true);
}
bindPasswordFile[i].setArgumentGroupName(groupName);
parser.addArgument(bindPasswordFile[i]);
useSSL[i] = new BooleanArgument(null, genArgName(i, "useSSL"), 1,
INFO_LDAP_TOOL_DESCRIPTION_USE_SSL.get());
if (includeAlternateLongIdentifiers())
{
useSSL[i].addLongIdentifier(genDashedArgName(i, "use-ssl"), true);
}
useSSL[i].setArgumentGroupName(groupName);
parser.addArgument(useSSL[i]);
useStartTLS[i] = new BooleanArgument(null, genArgName(i, "useStartTLS"),
1, INFO_LDAP_TOOL_DESCRIPTION_USE_START_TLS.get());
if (includeAlternateLongIdentifiers())
{
useStartTLS[i].addLongIdentifier(genDashedArgName(i, "use-start-tls"),
true);
}
useStartTLS[i].setArgumentGroupName(groupName);
parser.addArgument(useStartTLS[i]);
final String defaultTrustArgDesc;
if (InternalSDKHelper.getPingIdentityServerRoot() != null)
{
defaultTrustArgDesc =
INFO_LDAP_TOOL_DESCRIPTION_DEFAULT_TRUST_WITH_PING_DS.get();
}
else
{
defaultTrustArgDesc =
INFO_LDAP_TOOL_DESCRIPTION_DEFAULT_TRUST_WITHOUT_PING_DS.get();
}
defaultTrust[i] = new BooleanArgument(null,
genArgName(i, "defaultTrust"), 1, defaultTrustArgDesc);
defaultTrust[i].setArgumentGroupName(groupName);
if (includeAlternateLongIdentifiers())
{
defaultTrust[i].addLongIdentifier(
genDashedArgName(i, "default-trust"), true);
defaultTrust[i].addLongIdentifier(
genArgName(i, "useDefaultTrust"), true);
defaultTrust[i].addLongIdentifier(
genDashedArgName(i, "use-default-trust"), true);
}
parser.addArgument(defaultTrust[i]);
trustAll[i] = new BooleanArgument(null, genArgName(i, "trustAll"), 1,
INFO_LDAP_TOOL_DESCRIPTION_TRUST_ALL.get());
if (includeAlternateLongIdentifiers())
{
trustAll[i].addLongIdentifier(genDashedArgName(i, "trust-all"), true);
}
trustAll[i].setArgumentGroupName(groupName);
parser.addArgument(trustAll[i]);
keyStorePath[i] = new StringArgument(null, genArgName(i, "keyStorePath"),
false, 1, INFO_LDAP_TOOL_PLACEHOLDER_PATH.get(),
INFO_LDAP_TOOL_DESCRIPTION_KEY_STORE_PATH.get());
if (includeAlternateLongIdentifiers())
{
keyStorePath[i].addLongIdentifier(genDashedArgName(i, "key-store-path"),
true);
}
keyStorePath[i].setArgumentGroupName(groupName);
parser.addArgument(keyStorePath[i]);
keyStorePassword[i] = new StringArgument(null,
genArgName(i, "keyStorePassword"), false, 1,
INFO_LDAP_TOOL_PLACEHOLDER_PASSWORD.get(),
INFO_LDAP_TOOL_DESCRIPTION_KEY_STORE_PASSWORD.get());
if (includeAlternateLongIdentifiers())
{
keyStorePassword[i].addLongIdentifier(genDashedArgName(i,
"key-store-password"), true);
}
keyStorePassword[i].setSensitive(true);
keyStorePassword[i].setArgumentGroupName(groupName);
parser.addArgument(keyStorePassword[i]);
keyStorePasswordFile[i] = new FileArgument(null,
genArgName(i, "keyStorePasswordFile"), false, 1,
INFO_LDAP_TOOL_PLACEHOLDER_PATH.get(),
INFO_LDAP_TOOL_DESCRIPTION_KEY_STORE_PASSWORD_FILE.get(), true,
true, true, false);
if (includeAlternateLongIdentifiers())
{
keyStorePasswordFile[i].addLongIdentifier(genDashedArgName(i,
"key-store-password-file"), true);
}
keyStorePasswordFile[i].setArgumentGroupName(groupName);
parser.addArgument(keyStorePasswordFile[i]);
keyStoreFormat[i] = new StringArgument(null,
genArgName(i, "keyStoreFormat"), false, 1,
INFO_LDAP_TOOL_PLACEHOLDER_FORMAT.get(),
INFO_LDAP_TOOL_DESCRIPTION_KEY_STORE_FORMAT.get());
if (includeAlternateLongIdentifiers())
{
keyStoreFormat[i].addLongIdentifier(genDashedArgName(i,
"key-store-format"), true);
keyStoreFormat[i].addLongIdentifier(genArgName(i, "keyStoreType"),
true);
keyStoreFormat[i].addLongIdentifier(genDashedArgName(i,
"key-store-type"), true);
}
keyStoreFormat[i].setArgumentGroupName(groupName);
parser.addArgument(keyStoreFormat[i]);
trustStorePath[i] = new StringArgument(null,
genArgName(i, "trustStorePath"), false, 1,
INFO_LDAP_TOOL_PLACEHOLDER_PATH.get(),
INFO_LDAP_TOOL_DESCRIPTION_TRUST_STORE_PATH.get());
if (includeAlternateLongIdentifiers())
{
trustStorePath[i].addLongIdentifier(genDashedArgName(i,
"trust-store-path"), true);
}
trustStorePath[i].setArgumentGroupName(groupName);
parser.addArgument(trustStorePath[i]);
trustStorePassword[i] = new StringArgument(null,
genArgName(i, "trustStorePassword"), false, 1,
INFO_LDAP_TOOL_PLACEHOLDER_PASSWORD.get(),
INFO_LDAP_TOOL_DESCRIPTION_TRUST_STORE_PASSWORD.get());
if (includeAlternateLongIdentifiers())
{
trustStorePassword[i].addLongIdentifier(genDashedArgName(i,
"trust-store-password"), true);
}
trustStorePassword[i].setSensitive(true);
trustStorePassword[i].setArgumentGroupName(groupName);
parser.addArgument(trustStorePassword[i]);
trustStorePasswordFile[i] = new FileArgument(null,
genArgName(i, "trustStorePasswordFile"), false, 1,
INFO_LDAP_TOOL_PLACEHOLDER_PATH.get(),
INFO_LDAP_TOOL_DESCRIPTION_TRUST_STORE_PASSWORD_FILE.get(), true,
true, true, false);
if (includeAlternateLongIdentifiers())
{
trustStorePasswordFile[i].addLongIdentifier(genDashedArgName(i,
"trust-store-password-file"), true);
}
trustStorePasswordFile[i].setArgumentGroupName(groupName);
parser.addArgument(trustStorePasswordFile[i]);
trustStoreFormat[i] = new StringArgument(null,
genArgName(i, "trustStoreFormat"), false, 1,
INFO_LDAP_TOOL_PLACEHOLDER_FORMAT.get(),
INFO_LDAP_TOOL_DESCRIPTION_TRUST_STORE_FORMAT.get());
if (includeAlternateLongIdentifiers())
{
trustStoreFormat[i].addLongIdentifier(genDashedArgName(i,
"trust-store-format"), true);
trustStoreFormat[i].addLongIdentifier(genArgName(i, "trustStoreType"),
true);
trustStoreFormat[i].addLongIdentifier(genDashedArgName(i,
"trust-store-type"), true);
}
trustStoreFormat[i].setArgumentGroupName(groupName);
parser.addArgument(trustStoreFormat[i]);
certificateNickname[i] = new StringArgument(null,
genArgName(i, "certNickname"), false, 1,
INFO_LDAP_TOOL_PLACEHOLDER_CERT_NICKNAME.get(),
INFO_LDAP_TOOL_DESCRIPTION_CERT_NICKNAME.get());
if (includeAlternateLongIdentifiers())
{
certificateNickname[i].addLongIdentifier(genDashedArgName(i,
"cert-nickname"), true);
certificateNickname[i].addLongIdentifier(genArgName(i,
"certificateNickname"), true);
certificateNickname[i].addLongIdentifier(genDashedArgName(i,
"certificate-nickname"), true);
}
certificateNickname[i].setArgumentGroupName(groupName);
parser.addArgument(certificateNickname[i]);
saslOption[i] = new StringArgument(null, genArgName(i, "saslOption"),
false, 0, INFO_LDAP_TOOL_PLACEHOLDER_SASL_OPTION.get(),
INFO_LDAP_TOOL_DESCRIPTION_SASL_OPTION.get());
if (includeAlternateLongIdentifiers())
{
saslOption[i].addLongIdentifier(genDashedArgName(i, "sasl-option"),
true);
}
saslOption[i].setArgumentGroupName(groupName);
parser.addArgument(saslOption[i]);
parser.addDependentArgumentSet(bindDN[i], bindPassword[i],
bindPasswordFile[i]);
parser.addExclusiveArgumentSet(useSSL[i], useStartTLS[i]);
parser.addExclusiveArgumentSet(bindPassword[i], bindPasswordFile[i]);
parser.addExclusiveArgumentSet(keyStorePassword[i],
keyStorePasswordFile[i]);
parser.addExclusiveArgumentSet(trustStorePassword[i],
trustStorePasswordFile[i]);
parser.addExclusiveArgumentSet(trustAll[i], trustStorePath[i]);
parser.addExclusiveArgumentSet(trustAll[i], defaultTrust[i]);
}
addNonLDAPArguments(parser);
}
/**
* Constructs the name to use for an argument from the given base and the
* appropriate prefix and suffix.
*
* @param index The index into the set of prefixes and suffixes.
* @param base The base name for the argument.
*
* @return The constructed argument name.
*/
@NotNull()
private String genArgName(final int index, @NotNull final String base)
{
final StringBuilder buffer = new StringBuilder();
if (serverNamePrefixes != null)
{
buffer.append(serverNamePrefixes[index]);
if (base.equals("saslOption"))
{
buffer.append("SASLOption");
}
else
{
buffer.append(StaticUtils.capitalize(base));
}
}
else
{
buffer.append(base);
}
if (serverNameSuffixes != null)
{
buffer.append(serverNameSuffixes[index]);
}
return buffer.toString();
}
/**
* Constructs the name to use for an argument from the given base and the
* appropriate prefix and suffix. In this case, dashes will be used to
* separate words rather than capitalization.
*
* @param index The index into the set of prefixes and suffixes.
* @param base The base name for the argument.
*
* @return The constructed argument name.
*/
@NotNull()
private String genDashedArgName(final int index, @NotNull final String base)
{
final StringBuilder buffer = new StringBuilder();
if (serverNamePrefixes != null)
{
buffer.append(serverNamePrefixes[index]);
buffer.append('-');
}
buffer.append(base);
if (serverNameSuffixes != null)
{
buffer.append('-');
buffer.append(serverNameSuffixes[index]);
}
return buffer.toString();
}
/**
* Indicates whether the LDAP-specific arguments should include alternate
* versions of all long identifiers that consist of multiple words so that
* they are available in both camelCase and dash-separated versions.
*
* @return {@code true} if this tool should provide multiple versions of
* long identifiers for LDAP-specific arguments, or {@code false} if
* not.
*/
protected boolean includeAlternateLongIdentifiers()
{
return false;
}
/**
* Adds the arguments needed by this command-line tool to the provided
* argument parser which are not related to connecting or authenticating to
* the directory server.
*
* @param parser The argument parser to which the arguments should be added.
*
* @throws ArgumentException If a problem occurs while adding the arguments.
*/
public abstract void addNonLDAPArguments(@NotNull ArgumentParser parser)
throws ArgumentException;
/**
* {@inheritDoc}
*/
@Override()
public final void doExtendedArgumentValidation()
throws ArgumentException
{
doExtendedNonLDAPArgumentValidation();
}
/**
* Performs any necessary processing that should be done to ensure that the
* provided set of command-line arguments were valid. This method will be
* called after the basic argument parsing has been performed and after all
* LDAP-specific argument validation has been processed, and immediately
* before the {@link CommandLineTool#doToolProcessing} method is invoked.
*
* @throws ArgumentException If there was a problem with the command-line
* arguments provided to this program.
*/
public void doExtendedNonLDAPArgumentValidation()
throws ArgumentException
{
// No processing will be performed by default.
}
/**
* Retrieves the connection options that should be used for connections that
* are created with this command line tool. Subclasses may override this
* method to use a custom set of connection options.
*
* @return The connection options that should be used for connections that
* are created with this command line tool.
*/
@NotNull()
public LDAPConnectionOptions getConnectionOptions()
{
return new LDAPConnectionOptions();
}
/**
* Retrieves a connection that may be used to communicate with the indicated
* directory server.
*
* Note that this method is threadsafe and may be invoked by multiple threads
* accessing the same instance only while that instance is in the process of
* invoking the {@link #doToolProcessing} method.
*
* @param serverIndex The zero-based index of the server to which the
* connection should be established.
*
* @return A connection that may be used to communicate with the indicated
* directory server.
*
* @throws LDAPException If a problem occurs while creating the connection.
*/
@ThreadSafety(level=ThreadSafetyLevel.METHOD_THREADSAFE)
@NotNull()
public final LDAPConnection getConnection(final int serverIndex)
throws LDAPException
{
final LDAPConnection connection = getUnauthenticatedConnection(serverIndex);
try
{
if (bindRequest[serverIndex] != null)
{
connection.bind(bindRequest[serverIndex]);
}
}
catch (final LDAPException le)
{
Debug.debugException(le);
connection.close();
throw le;
}
return connection;
}
/**
* Retrieves an unauthenticated connection that may be used to communicate
* with the indicated directory server.
*
* Note that this method is threadsafe and may be invoked by multiple threads
* accessing the same instance only while that instance is in the process of
* invoking the {@link #doToolProcessing} method.
*
* @param serverIndex The zero-based index of the server to which the
* connection should be established.
*
* @return An unauthenticated connection that may be used to communicate with
* the indicated directory server.
*
* @throws LDAPException If a problem occurs while creating the connection.
*/
@ThreadSafety(level=ThreadSafetyLevel.METHOD_THREADSAFE)
@NotNull()
public final LDAPConnection getUnauthenticatedConnection(
final int serverIndex)
throws LDAPException
{
if (serverSet[serverIndex] == null)
{
serverSet[serverIndex] = createServerSet(serverIndex);
bindRequest[serverIndex] = createBindRequest(serverIndex);
}
final LDAPConnection connection = serverSet[serverIndex].getConnection();
if (useStartTLS[serverIndex].isPresent())
{
try
{
final ExtendedResult extendedResult =
connection.processExtendedOperation(new StartTLSExtendedRequest(
startTLSSocketFactory[serverIndex]));
if (! extendedResult.getResultCode().equals(ResultCode.SUCCESS))
{
throw new LDAPException(extendedResult.getResultCode(),
ERR_LDAP_TOOL_START_TLS_FAILED.get(
extendedResult.getDiagnosticMessage()));
}
}
catch (final LDAPException le)
{
Debug.debugException(le);
connection.close();
throw le;
}
}
return connection;
}
/**
* Retrieves a connection pool that may be used to communicate with the
* indicated directory server.
*
* Note that this method is threadsafe and may be invoked by multiple threads
* accessing the same instance only while that instance is in the process of
* invoking the {@link #doToolProcessing} method.
*
* @param serverIndex The zero-based index of the server to which the
* connection should be established.
* @param initialConnections The number of connections that should be
* initially established in the pool.
* @param maxConnections The maximum number of connections to maintain
* in the pool.
*
* @return A connection that may be used to communicate with the indicated
* directory server.
*
* @throws LDAPException If a problem occurs while creating the connection
* pool.
*/
@ThreadSafety(level=ThreadSafetyLevel.METHOD_THREADSAFE)
@NotNull()
public final LDAPConnectionPool getConnectionPool(
final int serverIndex,
final int initialConnections,
final int maxConnections)
throws LDAPException
{
if (serverSet[serverIndex] == null)
{
serverSet[serverIndex] = createServerSet(serverIndex);
bindRequest[serverIndex] = createBindRequest(serverIndex);
}
PostConnectProcessor postConnectProcessor = null;
if (useStartTLS[serverIndex].isPresent())
{
postConnectProcessor = new StartTLSPostConnectProcessor(
startTLSSocketFactory[serverIndex]);
}
return new LDAPConnectionPool(serverSet[serverIndex],
bindRequest[serverIndex], initialConnections, maxConnections,
postConnectProcessor);
}
/**
* Creates the server set to use when creating connections or connection
* pools.
*
* @param serverIndex The zero-based index of the server to which the
* connection should be established.
*
* @return The server set to use when creating connections or connection
* pools.
*
* @throws LDAPException If a problem occurs while creating the server set.
*/
@NotNull()
public final ServerSet createServerSet(final int serverIndex)
throws LDAPException
{
final SSLUtil sslUtil = createSSLUtil(serverIndex);
SocketFactory socketFactory = null;
if (useSSL[serverIndex].isPresent())
{
try
{
socketFactory = sslUtil.createSSLSocketFactory();
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.LOCAL_ERROR,
ERR_LDAP_TOOL_CANNOT_CREATE_SSL_SOCKET_FACTORY.get(
StaticUtils.getExceptionMessage(e)), e);
}
}
else if (useStartTLS[serverIndex].isPresent())
{
try
{
startTLSSocketFactory[serverIndex] = sslUtil.createSSLSocketFactory();
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.LOCAL_ERROR,
ERR_LDAP_TOOL_CANNOT_CREATE_SSL_SOCKET_FACTORY.get(
StaticUtils.getExceptionMessage(e)), e);
}
}
return new SingleServerSet(host[serverIndex].getValue(),
port[serverIndex].getValue(), socketFactory, getConnectionOptions());
}
/**
* Creates the SSLUtil instance to use for secure communication.
*
* @param serverIndex The zero-based index of the server to which the
* connection should be established.
*
* @return The SSLUtil instance to use for secure communication, or
* {@code null} if secure communication is not needed.
*
* @throws LDAPException If a problem occurs while creating the SSLUtil
* instance.
*/
@Nullable()
public final SSLUtil createSSLUtil(final int serverIndex)
throws LDAPException
{
if (useSSL[serverIndex].isPresent() || useStartTLS[serverIndex].isPresent())
{
KeyManager keyManager = null;
if (keyStorePath[serverIndex].isPresent())
{
char[] pw = null;
if (keyStorePassword[serverIndex].isPresent())
{
pw = keyStorePassword[serverIndex].getValue().toCharArray();
}
else if (keyStorePasswordFile[serverIndex].isPresent())
{
try
{
pw = getPasswordFileReader().readPassword(
keyStorePasswordFile[serverIndex].getValue());
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.LOCAL_ERROR,
ERR_LDAP_TOOL_CANNOT_READ_KEY_STORE_PASSWORD.get(
StaticUtils.getExceptionMessage(e)), e);
}
}
try
{
keyManager = new KeyStoreKeyManager(
keyStorePath[serverIndex].getValue(), pw,
keyStoreFormat[serverIndex].getValue(),
certificateNickname[serverIndex].getValue(), true);
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.LOCAL_ERROR,
ERR_LDAP_TOOL_CANNOT_CREATE_KEY_MANAGER.get(
StaticUtils.getExceptionMessage(e)), e);
}
}
TrustManager tm;
if (trustAll[serverIndex].isPresent())
{
tm = new TrustAllTrustManager(false);
}
else if (trustStorePath[serverIndex].isPresent())
{
char[] pw = null;
if (trustStorePassword[serverIndex].isPresent())
{
pw = trustStorePassword[serverIndex].getValue().toCharArray();
}
else if (trustStorePasswordFile[serverIndex].isPresent())
{
try
{
pw = getPasswordFileReader().readPassword(
trustStorePasswordFile[serverIndex].getValue());
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.LOCAL_ERROR,
ERR_LDAP_TOOL_CANNOT_READ_TRUST_STORE_PASSWORD.get(
StaticUtils.getExceptionMessage(e)), e);
}
}
final TrustStoreTrustManager trustStoreTrustManager =
new TrustStoreTrustManager(trustStorePath[serverIndex].getValue(),
pw, trustStoreFormat[serverIndex].getValue(), true);
if (defaultTrust[serverIndex].isPresent())
{
tm = InternalSDKHelper.getPreferredNonInteractiveTrustManagerChain(
trustStoreTrustManager);
}
else
{
tm = trustStoreTrustManager;
}
}
else if (defaultTrust[serverIndex].isPresent())
{
tm = InternalSDKHelper.getPreferredNonInteractiveTrustManagerChain();
}
else
{
tm = promptTrustManager.get();
if (tm == null)
{
final AggregateTrustManager atm =
InternalSDKHelper.getPreferredPromptTrustManagerChain(null);
if (promptTrustManager.compareAndSet(null, atm))
{
tm = atm;
}
else
{
tm = promptTrustManager.get();
}
}
}
return new SSLUtil(keyManager, tm);
}
else
{
return null;
}
}
/**
* Creates the bind request to use to authenticate to the indicated server.
*
* @param serverIndex The zero-based index of the server to which the
* connection should be established.
*
* @return The bind request to use to authenticate to the indicated server,
* or {@code null} if no bind should be performed.
*
* @throws LDAPException If a problem occurs while creating the bind
* request.
*/
@Nullable()
public final BindRequest createBindRequest(final int serverIndex)
throws LDAPException
{
final String pw;
if (bindPassword[serverIndex].isPresent())
{
pw = bindPassword[serverIndex].getValue();
}
else if (bindPasswordFile[serverIndex].isPresent())
{
try
{
pw = new String(getPasswordFileReader().readPassword(
bindPasswordFile[serverIndex].getValue()));
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.LOCAL_ERROR,
ERR_LDAP_TOOL_CANNOT_READ_BIND_PASSWORD.get(
StaticUtils.getExceptionMessage(e)), e);
}
}
else
{
pw = null;
}
if (saslOption[serverIndex].isPresent())
{
final String dnStr;
if (bindDN[serverIndex].isPresent())
{
dnStr = bindDN[serverIndex].getValue().toString();
}
else
{
dnStr = null;
}
return SASLUtils.createBindRequest(dnStr, pw, null,
saslOption[serverIndex].getValues());
}
else if (bindDN[serverIndex].isPresent())
{
return new SimpleBindRequest(bindDN[serverIndex].getValue(), pw);
}
else
{
return null;
}
}
}