mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Violette Roche-Montane
10.32.2014 e7dfa40c0ada0bb2d3bcbf7f153e496b5454f1cd
Checkpoint for OPENDJ-1303 "opendj-cli" - OPENDJ-1343 Migrate dsconfig
Rewritten DSConfig connection.
dsconfig package.
- Removed from dsconfig package the dependency on the SecureconnectionCliArgs and LDAPConsoleInteraction.
- Removed unused class InternalManagementContextFactory

Opendj-cli
- Added to ConnectionFactoryProvider an interactive mode which, at this state, just ask for basic authentication fields.
- Added cli messages.
- Added printHeader(...) to ConsoleApplication.

TOOLS SDK
- Added non interactive mode to AuthRate, ldapsearch and modrate to allow anonymous connection. This need to be fixed independently.
1 files deleted
11 files modified
961 ■■■■■ changed files
opendj-sdk/opendj-cli/src/main/java/com/forgerock/opendj/cli/ConnectionFactoryProvider.java 286 ●●●●● patch | view | raw | blame | history
opendj-sdk/opendj-cli/src/main/java/com/forgerock/opendj/cli/ConsoleApplication.java 13 ●●●●● patch | view | raw | blame | history
opendj-sdk/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java 16 ●●●●● patch | view | raw | blame | history
opendj-sdk/opendj-cli/src/main/resources/com/forgerock/opendj/cli/cli.properties 6 ●●●●● patch | view | raw | blame | history
opendj-sdk/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/AuthRate.java 13 ●●●● patch | view | raw | blame | history
opendj-sdk/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDAPSearch.java 25 ●●●●● patch | view | raw | blame | history
opendj-sdk/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ModRate.java 13 ●●●● patch | view | raw | blame | history
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/tools/dsconfig/DSConfig.java 154 ●●●● patch | view | raw | blame | history
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/tools/dsconfig/InternalManagementContextFactory.java 102 ●●●●● patch | view | raw | blame | history
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/tools/dsconfig/LDAPManagementContextFactory.java 236 ●●●● patch | view | raw | blame | history
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/tools/dsconfig/ManagementContextFactory.java 50 ●●●● patch | view | raw | blame | history
opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/tools/dsconfig/DsconfigLdapConnectionTestCase.java 47 ●●●●● patch | view | raw | blame | history
opendj-sdk/opendj-cli/src/main/java/com/forgerock/opendj/cli/ConnectionFactoryProvider.java
@@ -29,6 +29,7 @@
import static com.forgerock.opendj.cli.ArgumentConstants.*;
import static com.forgerock.opendj.cli.CliMessages.*;
import static com.forgerock.opendj.cli.CliConstants.DEFAULT_LDAP_PORT;
import static com.forgerock.opendj.cli.Utils.getHostNameForLdapUrl;
import java.io.File;
import java.io.FileInputStream;
@@ -39,7 +40,7 @@
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.logging.Logger;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
@@ -47,6 +48,7 @@
import javax.net.ssl.X509TrustManager;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.ldap.ConnectionFactory;
import org.forgerock.opendj.ldap.KeyManagers;
import org.forgerock.opendj.ldap.LDAPConnectionFactory;
@@ -66,90 +68,62 @@
/**
 * A connection factory designed for use with command line tools.
 */
public class ConnectionFactoryProvider {
    /**
     * The Logger.
     */
    static final Logger LOG = Logger.getLogger(ConnectionFactoryProvider.class.getName());
public final class ConnectionFactoryProvider {
    /** The Logger. */
    static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
    /**
     * The 'hostName' global argument.
     */
    /** The 'hostName' global argument. */
    private StringArgument hostNameArg = null;
    /**
     * The 'port' global argument.
     */
    /** The 'port' global argument. */
    private IntegerArgument portArg = null;
    /**
     * The 'bindDN' global argument.
     */
    /** The 'bindDN' global argument. */
    private StringArgument bindNameArg = null;
    /**
     * The 'bindPasswordFile' global argument.
     */
    /** The 'bindPasswordFile' global argument. */
    private FileBasedArgument bindPasswordFileArg = null;
    /**
     * The 'bindPassword' global argument.
     */
    /** The 'password' value. */
    private char[] password = null;
    /** The 'bindPassword' global argument. */
    private StringArgument bindPasswordArg = null;
    /**
     * The 'trustAllArg' global argument.
     */
    /** The 'connectTimeOut' global argument. */
    private IntegerArgument connectTimeOut = null;
    /** The 'trustAllArg' global argument. */
    private BooleanArgument trustAllArg = null;
    /**
     * The 'trustStore' global argument.
     */
    /** The 'trustStore' global argument. */
    private StringArgument trustStorePathArg = null;
    /**
     * The 'trustStorePassword' global argument.
     */
    /** The 'trustStorePassword' global argument. */
    private StringArgument trustStorePasswordArg = null;
    /**
     * The 'trustStorePasswordFile' global argument.
     */
    /** The 'trustStorePasswordFile' global argument. */
    private FileBasedArgument trustStorePasswordFileArg = null;
    /**
     * The 'keyStore' global argument.
     */
    /** The 'keyStore' global argument. */
    private StringArgument keyStorePathArg = null;
    /**
     * The 'keyStorePassword' global argument.
     */
    /** The 'keyStorePassword' global argument. */
    private StringArgument keyStorePasswordArg = null;
    /**
     * The 'keyStorePasswordFile' global argument.
     */
    /** The 'keyStorePasswordFile' global argument. */
    private FileBasedArgument keyStorePasswordFileArg = null;
    /**
     * The 'certNicknameArg' global argument.
     */
    /** The 'certNicknameArg' global argument. */
    private StringArgument certNicknameArg = null;
    /**
     * The 'useSSLArg' global argument.
     */
    /** The 'useSSLArg' global argument. */
    private BooleanArgument useSSLArg = null;
    /**
     * The 'useStartTLSArg' global argument.
     */
    /** The 'useStartTLSArg' global argument. */
    private BooleanArgument useStartTLSArg = null;
    /**
     * Argument indicating a SASL option.
     */
    /** Argument indicating a SASL option. */
    private StringArgument saslOptionArg = null;
    /**
@@ -163,23 +137,33 @@
     */
    private final BooleanArgument usePasswordPolicyControlArg;
    /** The port number to used to connect. */
    private int port = DEFAULT_LDAP_PORT;
    /** The SSL context linked to this connection. */
    private SSLContext sslContext;
    /**  The basic connection factory. */
    private ConnectionFactory connFactory;
    /** The authenticated connection factory. */
    protected ConnectionFactory authenticatedConnFactory;
    /** The bind request to connect with. */
    private BindRequest bindRequest = null;
    /** The console application linked to this connection in interactive mode. */
    private final ConsoleApplication app;
    /** The LDAP options for this connection. */
    private LDAPOptions options;
    /** If this connection should be an admin connection. */
    private boolean isAdminConnection = false;
    /**
     * Default constructor to create a connection factory designed for use with command line tools.
     * Default constructor to create a connection factory designed for use with command line tools,
     * adding basic LDAP connection arguments to the specified parser (e.g: hostname, bindname...etc).
     *
     * @param argumentParser
     *            The argument parser.
@@ -190,11 +174,12 @@
     */
    public ConnectionFactoryProvider(final ArgumentParser argumentParser,
            final ConsoleApplication app) throws ArgumentException {
        this(argumentParser, app, "cn=Directory Manager", DEFAULT_LDAP_PORT, false, null);
        this(argumentParser, app, CliConstants.DEFAULT_ROOT_USER_DN, DEFAULT_LDAP_PORT, false, null);
    }
    /**
     * Default constructor to create a connection factory designed for use with command line tools.
     * Default constructor to create a connection factory designed for use with command line tools,
     * adding basic LDAP connection arguments to the specified parser (e.g: hostname, bindname...etc).
     *
     * @param argumentParser
     *            The argument parser.
@@ -205,13 +190,14 @@
     * @throws ArgumentException
     *             If an error occurs during parsing the arguments.
     */
    public ConnectionFactoryProvider(final ArgumentParser argumentParser,
            final ConsoleApplication app, final LDAPOptions options) throws ArgumentException {
        this(argumentParser, app, "cn=Directory Manager", DEFAULT_LDAP_PORT, false, options);
    public ConnectionFactoryProvider(final ArgumentParser argumentParser, final ConsoleApplication app,
            final LDAPOptions options) throws ArgumentException {
        this(argumentParser, app, CliConstants.DEFAULT_ROOT_USER_DN, DEFAULT_LDAP_PORT, false, options);
    }
    /**
     * Constructor to create a connection factory designed for use with command line tools.
     * Constructor to create a connection factory designed for use with command line tools,
     * adding basic LDAP connection arguments to the specified parser (e.g: hostname, bindname...etc).
     *
     * @param argumentParser
     *            The argument parser.
@@ -303,6 +289,9 @@
        reportAuthzIDArg = CommonArguments.getReportAuthzId();
        argumentParser.addArgument(reportAuthzIDArg);
        connectTimeOut = CommonArguments.getConnectTimeOut();
        argumentParser.addArgument(connectTimeOut);
        usePasswordPolicyControlArg =
                new BooleanArgument("usepwpolicycontrol", null, OPTION_LONG_USE_PW_POLICY_CTL,
                        INFO_DESCRIPTION_USE_PWP_CONTROL.get());
@@ -311,15 +300,50 @@
    }
    /**
     * Returns the host name.
     * Returns the connect time out.
     *
     * @return The connect time out value.
     */
    public int getConnectTimeout() {
        if (connectTimeOut.isPresent()) {
            try {
                return connectTimeOut.getIntValue();
            } catch (ArgumentException e) {
                return Integer.valueOf(connectTimeOut.getDefaultValue());
            }
        }
        return Integer.valueOf(connectTimeOut.getDefaultValue());
    }
    /**
     * Returns the host name if the argument is present otherwise, if the application
     * is interactive, prompt the user for it.
     *
     * @return The host name value.
     * @throws ArgumentException
     *             If the host name cannot be retrieved.
     */
    public String getHostname() {
    public String getHostname() throws ArgumentException {
        String value = "";
        if (hostNameArg.isPresent()) {
            return hostNameArg.getValue();
            value = hostNameArg.getValue();
        } else if (app.isInteractive()) {
            try {
                value = app.readInput(INFO_DESCRIPTION_HOST.get(),
                        hostNameArg.getDefaultValue() == null ? value : hostNameArg.getDefaultValue());
                app.println();
                hostNameArg.addValue(value);
                hostNameArg.setPresent(true);
            } catch (ClientException e) {
                throw new ArgumentException(ERR_ERROR_CANNOT_READ_HOST_NAME.get(), e);
        }
        return hostNameArg.getDefaultValue();
        } else {
            return hostNameArg.getDefaultValue() == null ? value : hostNameArg.getDefaultValue();
        }
        return getHostNameForLdapUrl(value);
    }
    /**
@@ -357,20 +381,46 @@
    }
    /**
     * Checks if any conflicting arguments are present, build the connection with
     * selected arguments and returns the connection factory.
     * Checks if any conflicting arguments are present, build the connection with selected arguments and returns the
     * connection factory. If the application is interactive, it will prompt the user for missing parameters.
     *
     * @return The connection factory.
     * @throws ArgumentException
     *             If an error occurs during the parsing of the arguments. (conflicting
     *             arguments or if an error occurs during building SSL context).
     *             If an error occurs during the parsing of the arguments.
     *             (conflicting arguments or if an error occurs during building SSL context).
     */
    public ConnectionFactory getConnectionFactory() throws ArgumentException {
        if (connFactory == null) {
            port = portArg.getIntValue();
            port = portArg.isPresent() ? portArg.getIntValue() : 0;
            checkForConflictingArguments();
            if (app.isInteractive()) {
                if (!hostNameArg.isPresent() || port == 0 || !bindNameArg.isPresent()
                        || (!bindPasswordArg.isPresent() && !bindPasswordFileArg.isPresent())) {
                    app.printHeader(INFO_LDAP_CONN_HEADING_CONNECTION_PARAMETERS.get());
                }
                if (!hostNameArg.isPresent()) {
                    getHostname();
                }
                if (port == 0) {
                    LocalizableMessage portMsg;
                    if (isAdminConnection) {
                        portMsg = INFO_DESCRIPTION_ADMIN_PORT.get();
                    } else {
                        portMsg = INFO_DESCRIPTION_PORT.get();
                    }
                    port = app.askPort(portMsg, Integer.valueOf(portArg.getDefaultValue()), logger);
                    app.println();
                }
                if (!bindNameArg.isPresent()) {
                    getBindName();
                }
                if (!bindPasswordArg.isPresent() && !bindPasswordFileArg.isPresent()) {
                    getPassword();
                }
            }
            try {
                if (useSSLArg.isPresent() || useStartTLSArg.isPresent()) {
                    String clientAlias;
@@ -403,13 +453,14 @@
            if (sslContext != null) {
                options.setSSLContext(sslContext).setUseStartTLS(useStartTLSArg.isPresent());
            }
            options.setConnectTimeout(getConnectTimeout(), TimeUnit.MILLISECONDS);
            connFactory = new LDAPConnectionFactory(hostNameArg.getValue(), port, options);
        }
        return connFactory;
    }
    /**
     * Verifies if the arguments are not conflicting together or if they are readable.
     * Verifies if the connection arguments are not conflicting together or if they are readable.
     *
     * @throws ArgumentException
     *             If arguments are conflicting or if the files cannot be read,
@@ -502,13 +553,13 @@
    }
    /**
     * Returns <CODE>true</CODE> if we can read on the provided path and
     * <CODE>false</CODE> otherwise.
     * Returns {@code true} if we can read on the provided path and
     * {@code false} otherwise.
     *
     * @param path
     *            the path.
     * @return <CODE>true</CODE> if we can read on the provided path and
     *         <CODE>false</CODE> otherwise.
     * @return {@code true} if we can read on the provided path and
     *         {@code false} otherwise.
     */
    private boolean canReadPath(final String path) {
        final File file = new File(path);
@@ -555,17 +606,34 @@
        return value;
    }
    private String getBindName() throws ArgumentException {
    /**
     * Returns the bind name if the argument is present otherwise, in interactive mode, it
     * will prompt the user.
     *
     * @return The bind name used for this connection.
     * @throws ArgumentException
     *             If the bind name cannot be retrieved.
     */
    public String getBindName() throws ArgumentException {
        String value = "";
        if (bindNameArg.isPresent()) {
            value = bindNameArg.getValue();
        } else if (app.isInteractive()) {
            LocalizableMessage bindMsg;
            if (isAdminConnection) {
                bindMsg = INFO_DESCRIPTION_ADMIN_BINDDN.get();
            } else {
                bindMsg = INFO_DESCRIPTION_BINDDN.get();
            }
            try {
                value =
                        app.readInput(LocalizableMessage.raw("Bind name:"), bindNameArg
                                .getDefaultValue() == null ? value : bindNameArg.getDefaultValue());
                value = app.readInput(bindMsg,
                        bindNameArg.getDefaultValue() == null ? value : bindNameArg.getDefaultValue());
                app.println();
                bindNameArg.clearValues();
                bindNameArg.addValue(value);
                bindNameArg.setPresent(true);
            } catch (ClientException e) {
                throw new ArgumentException(LocalizableMessage.raw("Unable to read bind name"), e);
                throw new ArgumentException(ERR_ERROR_CANNOT_READ_BIND_NAME.get(), e);
            }
        }
@@ -669,9 +737,14 @@
     *         interactions requiring access to a key manager.
     * @throws java.security.KeyStoreException
     *             If a problem occurs while interacting with the key store.
     * @throws IOException
     *             If there is an I/O or format problem with the keystore data.
     * @throws NoSuchAlgorithmException
     *             If a problem occurs while loading with the key store.
     * @throws CertificateException
     *             If a problem occurs while loading with the key store.
     */
    private X509KeyManager getKeyManager(String keyStoreFile) throws KeyStoreException,
    public X509KeyManager getKeyManager(String keyStoreFile) throws KeyStoreException,
            IOException, NoSuchAlgorithmException, CertificateException {
        if (keyStoreFile == null) {
            // Lookup the file name through the JDK property.
@@ -725,29 +798,40 @@
    }
    /**
     * Get the password which has to be used for the command. If no password was
     * specified, return null.
     * Get the password which has to be used for the command. In interactive mode, if
     * the password arguments are missing, the user will be prompted.
     *
     * @return The password stored into the specified file on by the command
     *         line argument, or null it if not specified.
     *         line argument, or empty it if not specified.
     * @throws ArgumentException
     *             If a problem occurs while interacting with the password.
     */
    private char[] getPassword() throws ArgumentException {
    public char[] getPassword() throws ArgumentException {
        char[] value = "".toCharArray();
        if (bindPasswordArg.isPresent()) {
            value = bindPasswordArg.getValue().toCharArray();
        } else if (bindPasswordFileArg.isPresent()) {
            value = bindPasswordFileArg.getValue().toCharArray();
        } else if (password != null) {
            return password;
        }
        if (value.length == 0 && app.isInteractive()) {
            LocalizableMessage msg;
            if (isAdminConnection) {
                msg = INFO_LDAPAUTH_PASSWORD_PROMPT.get(getBindName());
            } else {
                msg = INFO_DESCRIPTION_BINDPASSWORD.get();
            }
            try {
                value = app.readPassword(LocalizableMessage.raw("Bind Password:"));
                value = app.readPassword(msg);
                app.println();
            } catch (ClientException e) {
                throw new ArgumentException(LocalizableMessage.raw("Unable to read password"), e);
                throw new ArgumentException(ERR_ERROR_CANNOT_READ_PASSWORD.get(), e);
            }
            password = value;
        }
        return value;
    }
@@ -791,7 +875,7 @@
            return new PromptingTrustManager(app, tm);
        }
        return null;
        return tm;
    }
    /**
@@ -831,4 +915,26 @@
        return option.substring(equalPos + 1, option.length());
    }
    /**
     * Specifies if this connection should be an administrator connection. If sets as one, the messages prompted to the
     * user will be different as a normal connection. E.g if set :
     *
     * <pre>
     * >>>> Specify OpenDJ LDAP connection parameters
     *
     * Directory server administration port number [4444]:
     * </pre>
     *
     * vs normal mode
     *
     * <pre>
     * >>>> Specify OpenDJ LDAP connection parameters
     *
     * Directory server port number [1389]:
     * </pre>
     */
    public void setIsAnAdminConnection() {
        isAdminConnection = true;
    }
}
opendj-sdk/opendj-cli/src/main/java/com/forgerock/opendj/cli/ConsoleApplication.java
@@ -819,4 +819,17 @@
        }
        return port;
    }
    /**
     * Prints a header in the console application.
     *
     * @param header
     *            The message to display as a header.
     */
    void printHeader(final LocalizableMessage header) {
        println();
        println();
        println(header);
        println();
    }
}
opendj-sdk/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java
@@ -363,6 +363,22 @@
        addGlobalArgument(argument, null);
    }
    /**
     * Adds the provided argument to the set of arguments handled by this parser and puts the argument in the LDAP
     * connection group.
     *
     * @param argument
     *            The argument to add to this sub command.
     * @throws ArgumentException
     *             If the provided argument conflicts with another global or subcommand argument that has already been
     *             defined.
     */
    @Override
    public void addLdapConnectionArgument(final Argument argument) throws ArgumentException {
        addGlobalArgument(argument, null);
    }
    /**
     * Adds the provided argument to the set of global arguments handled by this parser.
     *
opendj-sdk/opendj-cli/src/main/resources/com/forgerock/opendj/cli/cli.properties
@@ -467,6 +467,7 @@
ERR_CANNOT_READ_KEYSTORE=Cannot access key store '%s'.  Verify \
 that the provided key store exists and that you have read access rights to it
INFO_DESCRIPTION_ADMIN_PORT=Directory server administration port number
INFO_DESCRIPTION_ADMIN_BINDDN=Administrator user bind DN
ERR_LDAPCOMPARE_ERROR_READING_FILE=An error occurred reading file \
 '%s'.  Check that the file exists and that you have read access rights to \
 it.  Details: %s
@@ -959,4 +960,9 @@
ERR_ERROR_INCOMPATIBLE_PROPERTY_MOD=The property \
 modification "%s" is incompatible with another modification to the same \
 property
INFO_LDAP_CONN_HEADING_CONNECTION_PARAMETERS=>>>> Specify OpenDJ LDAP \
  connection parameters
ERR_ERROR_CANNOT_READ_PASSWORD=Unable to read password
ERR_ERROR_CANNOT_READ_BIND_NAME=Unable to read bind name
ERR_ERROR_CANNOT_READ_HOST_NAME=Cannot read the host name
 
opendj-sdk/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/AuthRate.java
@@ -356,17 +356,18 @@
        // Nothing to do.
    }
    /**
     * {@inheritDoc}
     */
    /** {@inheritDoc} */
    public boolean isInteractive() {
        return false;
    }
    /** {@inheritDoc} */
    @Override
    public boolean isScriptFriendly() {
        return scriptFriendly.isPresent();
    }
    /**
     * {@inheritDoc}
     */
    /** {@inheritDoc} */
    @Override
    public boolean isVerbose() {
        return verbose.isPresent();
opendj-sdk/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDAPSearch.java
@@ -95,9 +95,7 @@
    private class LDAPSearchResultHandler implements SearchResultHandler {
        private int entryCount = 0;
        /**
         * {@inheritDoc}
         */
        /** {@inheritDoc} */
        public boolean handleEntry(final SearchResultEntry entry) {
            entryCount++;
@@ -179,24 +177,18 @@
            return true;
        }
        /**
         * {@inheritDoc}
         */
        /** {@inheritDoc} */
        public boolean handleReference(final SearchResultReference reference) {
            println(LocalizableMessage.raw(reference.toString()));
            return true;
        }
        /**
         * {@inheritDoc}
         */
        /** {@inheritDoc} */
        public void handleErrorResult(ErrorResultException error) {
            // Ignore.
        }
        /**
         * {@inheritDoc}
         */
        /** {@inheritDoc} */
        public void handleResult(Result result) {
            // Ignore.
        }
@@ -222,9 +214,12 @@
        // Nothing to do.
    }
    /**
     * {@inheritDoc}
     */
    /** {@inheritDoc} */
    public boolean isInteractive() {
        return false;
    }
    /** {@inheritDoc} */
    @Override
    public boolean isVerbose() {
        return verbose.isPresent();
opendj-sdk/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ModRate.java
@@ -138,17 +138,18 @@
        // Nothing to do.
    }
    /**
     * {@inheritDoc}
     */
    /** {@inheritDoc} */
    public boolean isInteractive() {
        return false;
    }
    /** {@inheritDoc} */
    @Override
    public boolean isScriptFriendly() {
        return scriptFriendly.isPresent();
    }
    /**
     * {@inheritDoc}
     */
    /** {@inheritDoc} */
    @Override
    public boolean isVerbose() {
        return verbose.isPresent();
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/tools/dsconfig/DSConfig.java
@@ -80,14 +80,17 @@
import com.forgerock.opendj.cli.ArgumentException;
import com.forgerock.opendj.cli.ArgumentGroup;
import com.forgerock.opendj.cli.BooleanArgument;
import com.forgerock.opendj.cli.CliConstants;
import com.forgerock.opendj.cli.ClientException;
import com.forgerock.opendj.cli.CommandBuilder;
import com.forgerock.opendj.cli.CommonArguments;
import com.forgerock.opendj.cli.ConnectionFactoryProvider;
import com.forgerock.opendj.cli.ConsoleApplication;
import com.forgerock.opendj.cli.Menu;
import com.forgerock.opendj.cli.MenuBuilder;
import com.forgerock.opendj.cli.MenuCallback;
import com.forgerock.opendj.cli.MenuResult;
import com.forgerock.opendj.cli.ReturnCode;
import com.forgerock.opendj.cli.StringArgument;
import com.forgerock.opendj.cli.SubCommand;
import com.forgerock.opendj.cli.SubCommandArgumentParser;
@@ -332,8 +335,7 @@
  {
    JDKLogging.disableLogging();
    DSConfig app =
        new DSConfig(System.in, outStream, errStream,
            new LDAPManagementContextFactory());
        new DSConfig(System.in, outStream, errStream);
    app.sessionStartTime = System.currentTimeMillis();
    /*
     * FIXME: obtain path info from system properties.
@@ -363,7 +365,7 @@
   * The factory which the application should use to retrieve its management
   * context.
   */
  private final ManagementContextFactory factory;
  private ManagementContextFactory factory = null;
  /**
   * Flag indicating whether or not the global arguments have already been
@@ -407,9 +409,7 @@
  /** The argument which should be used to request quiet output. */
  private BooleanArgument quietArgument;
  /**
   * The argument which should be used to request script-friendly output.
   */
  /** The argument which should be used to request script-friendly output. */
  private BooleanArgument scriptFriendlyArgument;
  /** The argument which should be used to request usage information. */
@@ -428,7 +428,7 @@
  private BooleanArgument noPropertiesFileArgument;
  /**
   * Creates a new dsconfig application instance.
   * Creates a new DSConfig application instance.
   *
   * @param in
   *          The application input stream.
@@ -440,14 +440,11 @@
   *          The factory which this application instance should use
   *          for obtaining management contexts.
   */
  private DSConfig(InputStream in, OutputStream out, OutputStream err,
      ManagementContextFactory factory) {
  private DSConfig(InputStream in, OutputStream out, OutputStream err) {
    super(new PrintStream(out), new PrintStream(err));
    this.parser = new SubCommandArgumentParser(getClass().getName(),
        INFO_DSCFG_TOOL_DESCRIPTION.get(), false);
    this.factory = factory;
  }
@@ -572,11 +569,6 @@
      parser.addGlobalArgument(noPropertiesFileArgument);
      parser.setNoPropertiesFileArgument(noPropertiesFileArgument);
      // Register any global arguments required by the management
      // context factory.
      factory.setRawArguments(args);
      factory.registerGlobalArguments(parser);
      globalArgumentsInitialized = true;
    }
  }
@@ -672,64 +664,32 @@
      return 1;
    }
    ConnectionFactoryProvider cfp = null;
    try
    {
      cfp =
          new ConnectionFactoryProvider(parser, this,
              CliConstants.DEFAULT_ROOT_USER_DN,
              CliConstants.DEFAULT_ADMINISTRATION_CONNECTOR_PORT, true, null);
      cfp.setIsAnAdminConnection();
    // Parse the command-line arguments provided to this program.
    try {
      parser.parseArguments(args);
    } catch (ArgumentException ae) {
      checkForConflictingArguments();
    }
    catch (ArgumentException ae)
    {
      LocalizableMessage message = ERR_ERROR_PARSING_ARGS.get(ae.getMessage());
      displayMessageAndUsageReference(message);
      return 1;
      return ReturnCode.CONFLICTING_ARGS.get();
    }
    // If the usage/version argument was provided, then we don't need
    // to do anything else.
    if (parser.usageOrVersionDisplayed()) {
      return 0;
      return ReturnCode.SUCCESS.get();
    }
    // Check for conflicting arguments.
    if (quietArgument.isPresent() && verboseArgument.isPresent()) {
      LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(quietArgument
          .getLongIdentifier(), verboseArgument.getLongIdentifier());
      displayMessageAndUsageReference(message);
      return 1;
    }
    if (batchFileArgument.isPresent() && !noPromptArgument.isPresent()) {
      LocalizableMessage message =
          ERR_DSCFG_ERROR_QUIET_AND_INTERACTIVE_INCOMPATIBLE.get(
              batchFileArgument.getLongIdentifier(), noPromptArgument
                  .getLongIdentifier());
      displayMessageAndUsageReference(message);
      return 1;
    }
    if (quietArgument.isPresent() && !noPromptArgument.isPresent()) {
      LocalizableMessage message = ERR_DSCFG_ERROR_QUIET_AND_INTERACTIVE_INCOMPATIBLE.get(
          quietArgument.getLongIdentifier(), noPromptArgument
          .getLongIdentifier());
      displayMessageAndUsageReference(message);
      return 1;
    }
    if (scriptFriendlyArgument.isPresent() && verboseArgument.isPresent()) {
      LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(scriptFriendlyArgument
          .getLongIdentifier(), verboseArgument.getLongIdentifier());
      displayMessageAndUsageReference(message);
      return 1;
    }
    if (noPropertiesFileArgument.isPresent()
        && propertiesFileArgument.isPresent())
    {
      LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
          noPropertiesFileArgument.getLongIdentifier(),
          propertiesFileArgument.getLongIdentifier());
      displayMessageAndUsageReference(message);
      return 1;
    }
    // Checks the version - if upgrade required, the tool is unusable
    try
    {
@@ -749,31 +709,36 @@
      if (!canWrite(file))
      {
        println(ERR_DSCFG_CANNOT_WRITE_EQUIVALENT_COMMAND_LINE_FILE.get(file));
        return 1;
        return ReturnCode.ERROR_UNEXPECTED.get();
      }
      else
      {
        if (new File(file).isDirectory())
        {
          println(ERR_DSCFG_EQUIVALENT_COMMAND_LINE_FILE_DIRECTORY.get(file));
          return 1;
          return ReturnCode.ERROR_UNEXPECTED.get();
        }
      }
    }
    // Creates the management context factory which is based on the connection
    // provider factory and an authenticated connection factory.
    try
    {
      factory = new LDAPManagementContextFactory(cfp);
    }
    catch (ArgumentException e)
    {
      LocalizableMessage message = ERR_ERROR_PARSING_ARGS.get(e.getMessage());
      displayMessageAndUsageReference(message);
      return ReturnCode.CONFLICTING_ARGS.get();
    }
    // Make sure that management context's arguments are valid.
    try {
      factory.validateGlobalArguments();
    } catch (ArgumentException e) {
      println(e.getMessageObject());
      return 1;
    }
    // Handle batch file if any
    if (batchFileArgument.isPresent()) {
      handleBatchFile(args);
      // don't need to do anything else
      return 0;
      return ReturnCode.SUCCESS.get();
    }
    int retCode = 0;
@@ -807,6 +772,45 @@
    return retCode;
  }
  private void checkForConflictingArguments() throws ArgumentException
  {
    if (quietArgument.isPresent() && verboseArgument.isPresent()) {
      final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(quietArgument
          .getLongIdentifier(), verboseArgument.getLongIdentifier());
      throw new ArgumentException(message);
    }
    if (batchFileArgument.isPresent() && !noPromptArgument.isPresent()) {
      final LocalizableMessage message =
          ERR_DSCFG_ERROR_QUIET_AND_INTERACTIVE_INCOMPATIBLE.get(
              batchFileArgument.getLongIdentifier(), noPromptArgument
                  .getLongIdentifier());
      throw new ArgumentException(message);
    }
    if (quietArgument.isPresent() && !noPromptArgument.isPresent()) {
      final LocalizableMessage message = ERR_DSCFG_ERROR_QUIET_AND_INTERACTIVE_INCOMPATIBLE.get(
          quietArgument.getLongIdentifier(), noPromptArgument
          .getLongIdentifier());
      throw new ArgumentException(message);
    }
    if (scriptFriendlyArgument.isPresent() && verboseArgument.isPresent()) {
      final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(scriptFriendlyArgument
          .getLongIdentifier(), verboseArgument.getLongIdentifier());
      throw new ArgumentException(message);
    }
    if (noPropertiesFileArgument.isPresent()
        && propertiesFileArgument.isPresent())
    {
      final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
          noPropertiesFileArgument.getLongIdentifier(),
          propertiesFileArgument.getLongIdentifier());
      throw new ArgumentException(message);
    }
  }
  /** Run the top-level interactive console. */
@@ -893,6 +897,8 @@
    try {
      // Force retrieval of management context.
      factory.getManagementContext(app);
    } catch (ArgumentException e) {
      app.println(e.getMessageObject());
      return 1;
@@ -908,7 +914,7 @@
      MenuResult<Integer> result = menu.run();
      if (result.isQuit()) {
        return 0;
        return ReturnCode.SUCCESS.get();
      } else {
        return result.getValue();
      }
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/tools/dsconfig/InternalManagementContextFactory.java
File was deleted
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/tools/dsconfig/LDAPManagementContextFactory.java
@@ -26,56 +26,30 @@
 */
package org.opends.server.tools.dsconfig;
import static com.forgerock.opendj.cli.ArgumentConstants.OPTION_LONG_HELP;
import static com.forgerock.opendj.cli.ArgumentConstants.OPTION_SHORT_HELP;
import static com.forgerock.opendj.dsconfig.DsconfigMessages.*;
import static com.forgerock.opendj.cli.CliMessages.*;
import static org.forgerock.util.Utils.closeSilently;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.LinkedHashSet;
import java.util.concurrent.TimeUnit;
import javax.naming.AuthenticationException;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLException;
import javax.net.ssl.TrustManager;
import org.forgerock.i18n.LocalizableMessageBuilder;
import org.forgerock.opendj.config.LDAPProfile;
import org.forgerock.opendj.config.client.ManagementContext;
import org.forgerock.opendj.config.client.ldap.LDAPManagementContext;
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.ldap.ErrorResultException;
import org.forgerock.opendj.ldap.AuthorizationException;
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.LDAPConnectionFactory;
import org.forgerock.opendj.ldap.LDAPOptions;
import org.forgerock.opendj.ldap.SSLContextBuilder;
import org.forgerock.opendj.ldap.TrustManagers;
import org.opends.admin.ads.util.ApplicationTrustManager;
import org.opends.admin.ads.util.ConnectionUtils;
import org.opends.server.admin.client.cli.SecureConnectionCliArgs;
import org.opends.server.util.cli.LDAPConnectionConsoleInteraction;
import org.forgerock.opendj.ldap.ConnectionFactory;
import org.forgerock.opendj.ldap.ErrorResultException;
import com.forgerock.opendj.cli.Argument;
import com.forgerock.opendj.cli.ArgumentException;
import com.forgerock.opendj.cli.ClientException;
import com.forgerock.opendj.cli.CommandBuilder;
import com.forgerock.opendj.cli.ConnectionFactoryProvider;
import com.forgerock.opendj.cli.ConsoleApplication;
import com.forgerock.opendj.cli.ReturnCode;
import com.forgerock.opendj.cli.SubCommandArgumentParser;
/**
 * An LDAP management context factory.
 */
public final class LDAPManagementContextFactory implements
    ManagementContextFactory {
  /** The SecureConnectionCliArgsList object. */
  private SecureConnectionCliArgs secureArgsList;
public final class LDAPManagementContextFactory implements ManagementContextFactory
{
  /** The management context. */
  private ManagementContext context;
@@ -83,31 +57,26 @@
  /** The connection parameters command builder. */
  private CommandBuilder contextCommandBuilder;
  /** Raw arguments. */
  private String[] rawArgs;
  /** The connection factory provider. */
  private final ConnectionFactoryProvider provider;
  /** The connection factory. */
  private final ConnectionFactory factory;
  /**
   * Creates a new LDAP management context factory.
   * Creates a new LDAP management context factory based on an authenticated
   * connection factory.
   *
   * @param cfp
   *          The connection factory provider which should be used in this
   *          context.
   * @throws ArgumentException
   *           If an exception occurs when creating the authenticated connection
   *           factory linked to this context.
   */
  public LDAPManagementContextFactory() {
    // Nothing to do.
  }
  /** {@inheritDoc} */
  @Override
  public ManagementContext getManagementContext(ConsoleApplication app)
      throws ArgumentException, ClientException
  {
    // Lazily create the LDAP management context.
    if (context == null)
    {
      LDAPConnectionConsoleInteraction ci =
        new LDAPConnectionConsoleInteraction(app, secureArgsList);
      ci.run();
      context = getManagementContext(app, ci);
      contextCommandBuilder = ci.getCommandBuilder();
    }
    return context;
  public LDAPManagementContextFactory(ConnectionFactoryProvider cfp) throws ArgumentException {
    this.provider = cfp;
    factory = cfp.getAuthenticatedConnectionFactory();
  }
  /** {@inheritDoc} */
@@ -126,13 +95,10 @@
  /**
   * Gets the management context which sub-commands should use in
   * order to manage the directory server. Implementations can use the
   * application instance for retrieving passwords interactively.
   * order to manage the directory server.
   *
   * @param app
   *          The application instance.
   * @param ci the LDAPConsoleInteraction object to be used.  The code assumes
   *        that the LDAPConsoleInteraction has already been run.
   *          The console application instance.
   * @return Returns the management context which sub-commands should
   *         use in order to manage the directory server.
   * @throws ArgumentException
@@ -141,162 +107,48 @@
   * @throws ClientException
   *           If the management context could not be created.
   */
  public ManagementContext getManagementContext(ConsoleApplication app,
      LDAPConnectionConsoleInteraction ci)
  public ManagementContext getManagementContext(ConsoleApplication app)
      throws ArgumentException, ClientException
  {
    // Lazily create the LDAP management context.
    if (context == null)
    {
      // Interact with the user though the console to get
      // LDAP connection information
      final String hostName = ConnectionUtils.getHostNameForLdapUrl(ci.getHostName());
      final Integer portNumber = ci.getPortNumber();
      final String bindDN = ci.getBindDN();
      final String bindPassword = ci.getBindPassword();
      TrustManager trustManager = ci.getTrustManager();
      final KeyManager keyManager = ci.getKeyManager();
      final LDAPOptions options = new LDAPOptions();
      options.setConnectTimeout(ci.getConnectTimeout(), TimeUnit.MILLISECONDS);
      LDAPConnectionFactory factory = null;
      Connection connection = null;
      while (true)
      {
      Connection connection;
      final String hostName = provider.getHostname();
      final int port = provider.getPort();
        try
        {
          final SSLContextBuilder sslBuilder = new SSLContextBuilder();
          sslBuilder.setTrustManager((trustManager == null ? TrustManagers
              .trustAll() : trustManager));
          sslBuilder.setKeyManager(keyManager);
          options.setUseStartTLS(ci.useStartTLS());
          options.setSSLContext(sslBuilder.getSSLContext());
          factory = new LDAPConnectionFactory(hostName, portNumber, options);
          connection = factory.getConnection();
          connection.bind(bindDN, bindPassword.toCharArray());
          break;
        }
        catch (ErrorResultException e)
        {
          final Throwable cause = e.getCause();
          if (app.isInteractive() && ci.isTrustStoreInMemory() && cause != null
              && cause instanceof SSLException
              && cause.getCause() instanceof CertificateException)
          {
            String authType = null;
            if (trustManager instanceof ApplicationTrustManager)
            { // FIXME use PromptingTrustManager
              ApplicationTrustManager appTrustManager =
                  (ApplicationTrustManager) trustManager;
              authType = appTrustManager.getLastRefusedAuthType();
              X509Certificate[] cert = appTrustManager.getLastRefusedChain();
              if (ci.checkServerCertificate(cert, authType, hostName))
              {
                // If the certificate is trusted, update the trust manager.
                trustManager = ci.getTrustManager();
                // Try to connect again.
                continue;
              }
            }
          }
          if (cause instanceof SSLException)
        if (e.getCause() instanceof SSLException)
          {
            throw new ClientException(ReturnCode.CLIENT_SIDE_CONNECT_ERROR,
                ERR_FAILED_TO_CONNECT_NOT_TRUSTED.get(hostName, portNumber));
              ERR_FAILED_TO_CONNECT_NOT_TRUSTED.get(hostName, String
                  .valueOf(port)));
          }
          throw couldNotConnect(cause, hostName, portNumber, bindDN);
        }
        catch (GeneralSecurityException e)
        else
        {
          throw new ClientException(ReturnCode.CLIENT_SIDE_CONNECT_ERROR,
              ERR_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT.get(hostName, portNumber));
        } finally {
              ERR_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT.get(hostName, String
                  .valueOf(port)));
        }
      }
      catch (Exception ex)
      {
        throw new ClientException(ReturnCode.CLIENT_SIDE_CONNECT_ERROR,
            ERR_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT.get(hostName, port));
      }
      finally
      {
          closeSilently(factory);
        }
      }
      context =
          LDAPManagementContext.newManagementContext(connection, LDAPProfile
              .getInstance());
    }
    return context;
  }
  private ClientException couldNotConnect(Throwable cause, String hostName,
      Integer portNumber, String bindDN)
  {
    if (cause instanceof AuthorizationException)
    {
      return new ClientException(ReturnCode.AUTH_METHOD_NOT_SUPPORTED,
          ERR_DSCFG_ERROR_LDAP_SIMPLE_BIND_NOT_SUPPORTED.get());
    }
    else if (cause instanceof AuthenticationException)
    {
      return new ClientException(ReturnCode.INVALID_CREDENTIALS,
          ERR_DSCFG_ERROR_LDAP_SIMPLE_BIND_FAILED.get(bindDN));
    }
    return new ClientException(ReturnCode.CLIENT_SIDE_CONNECT_ERROR,
        ERR_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT.get(hostName, portNumber));
  }
  /** {@inheritDoc} */
  @Override
  public void setRawArguments(String[] args) {
    this.rawArgs = args;
  }
  /** {@inheritDoc} */
  @Override
  public void registerGlobalArguments(SubCommandArgumentParser parser)
      throws ArgumentException {
    // Create the global arguments.
    secureArgsList = new SecureConnectionCliArgs(true);
    LinkedHashSet<Argument> args = secureArgsList.createGlobalArguments();
    // Register the global arguments.
    for (Argument arg : args)
    {
      parser.addGlobalArgument(arg);
    }
    try
    {
      if (rawArgs != null) {
        for (String rawArg : rawArgs) {
          if (rawArg.length() < 2) {
            // This is not a help command
            continue;
          }
          if (rawArg.contains(OPTION_LONG_HELP) ||
            rawArg.charAt(1) == OPTION_SHORT_HELP || rawArg.charAt(1) == '?') {
            // used for usage help default values only
            secureArgsList.initArgumentsWithConfiguration();
          }
        }
      }
    }
    catch (ConfigException ce)
    {
      // Ignore.
    }
  }
  /** {@inheritDoc} */
  @Override
  public void validateGlobalArguments() throws ArgumentException {
    // Make sure that the user didn't specify any conflicting
    // arguments.
    LocalizableMessageBuilder buf = new LocalizableMessageBuilder();
    int v = secureArgsList.validateGlobalOptions(buf);
    if (v != ReturnCode.SUCCESS.get())
    {
      throw new ArgumentException(buf.toMessage());
    }
  }
}
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/tools/dsconfig/ManagementContextFactory.java
@@ -32,23 +32,21 @@
import com.forgerock.opendj.cli.ClientException;
import com.forgerock.opendj.cli.CommandBuilder;
import com.forgerock.opendj.cli.ConsoleApplication;
import com.forgerock.opendj.cli.SubCommandArgumentParser;
/**
 * A factory for retrieving the management context which should be
 * used by the dsconfig application.
 * A factory for retrieving the management context which should be used by the
 * DSConfig application.
 * <p>
 * Factory implementations are responsible for registering their
 * required global options during initialization.
 * Factory implementations are responsible for registering their required global
 * options during initialization.
 */
public interface ManagementContextFactory {
  /**
   * Gets the management context which sub-commands should use in
   * order to manage the directory server. Implementations can use the
   * application instance for retrieving passwords interactively.
   * order to manage the directory server.
   *
   * @param app
   *          The application instance.
@@ -63,51 +61,15 @@
  ManagementContext getManagementContext(ConsoleApplication app)
      throws ArgumentException, ClientException;
  /**
   * Closes this management context.
   */
  void close();
  /**
   * Initializes this management context factory using the provided
   * parser. The management context factory can register global
   * options with the parser if required.
   *
   * @param parser
   *          The application sub-command argument parser.
   * @throws ArgumentException
   *           If the factory failed to register its required global
   *           options.
   */
  void registerGlobalArguments(SubCommandArgumentParser parser)
      throws ArgumentException;
  /**
   * Set the raw arguments (used for default value setting).
   *
   * @param args raw arguments.
   */
  void setRawArguments(String[] args);
  /**
   * Validates any global arguments passed to the application.
   * Implementations of this method should check that the values
   * passed to their global arguments are valid and are not
   * incompatible with each other.
   *
   * @throws ArgumentException
   *           If the global arguments are invalid for some reason.
   */
  void validateGlobalArguments() throws ArgumentException;
  /**
   * Returns the command builder that provides the equivalent arguments in
   * interactive mode to get the management context.
   *
   * @return the command builder that provides the equivalent arguments in
   * interactive mode to get the management context.
   */
opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/tools/dsconfig/DsconfigLdapConnectionTestCase.java
@@ -131,6 +131,52 @@
  }
  /**
   *  --bindPassword and the --bindPasswordFile arguments can not be provided
   *  together.
   */
  @Test()
  public void testConflictualArgumentsPasswordAndFilePassword()
  {
    String[] args =
    {
      "-n",
      "--noPropertiesFile",
      "-Q",
      "list-connection-handlers",
      "-p", String.valueOf(TestCaseUtils.getServerAdminPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-j", validPasswordFile,
      "-X"
    };
    assertTrue(DSConfig.main(args, System.out, System.err) == CONFLICTING_ARGS.get());
  }
  /**
   *  Quiet mode and verbose arguments can not be provided
   *  together.
   */
  @Test()
  public void testConflictualArgumentsQuietAndVerbose()
  {
    String[] args =
    {
      "-n",
      "--noPropertiesFile",
      "-Q",
      "list-connection-handlers",
      "-p", String.valueOf(TestCaseUtils.getServerAdminPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-v",
      "-X"
    };
    assertTrue(DSConfig.main(args, System.out, System.err) == CONFLICTING_ARGS.get());
  }
  /**
   * Tests list-connection-handlers with an invalid password.
   */
  @Test()
@@ -237,6 +283,7 @@
      "-Q",
      "list-connection-handlers",
      "-p", String.valueOf(TestCaseUtils.getServerAdminPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-P", trustStorePath
    };