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); } } else { return hostNameArg.getDefaultValue() == null ? value : hostNameArg.getDefaultValue(); } return 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()) { try { value = app.readPassword(LocalizableMessage.raw("Bind Password:")); } catch (ClientException e) { throw new ArgumentException(LocalizableMessage.raw("Unable to read password"), e); LocalizableMessage msg; if (isAdminConnection) { msg = INFO_LDAPAUTH_PASSWORD_PROMPT.get(getBindName()); } else { msg = INFO_DESCRIPTION_BINDPASSWORD.get(); } try { value = app.readPassword(msg); app.println(); } catch (ClientException 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; } // Parse the command-line arguments provided to this program. try { 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. 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(); } } } // Make sure that management context's arguments are valid. try { factory.validateGlobalArguments(); } catch (ArgumentException e) { println(e.getMessageObject()); return 1; // 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(); } // 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 { 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) { throw new ClientException(ReturnCode.CLIENT_SIDE_CONNECT_ERROR, ERR_FAILED_TO_CONNECT_NOT_TRUSTED.get(hostName, portNumber)); } throw couldNotConnect(cause, hostName, portNumber, bindDN); } catch (GeneralSecurityException e) connection = factory.getConnection(); } catch (ErrorResultException e) { if (e.getCause() instanceof SSLException) { throw new ClientException(ReturnCode.CLIENT_SIDE_CONNECT_ERROR, ERR_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT.get(hostName, portNumber)); } finally { closeSilently(factory); ERR_FAILED_TO_CONNECT_NOT_TRUSTED.get(hostName, String .valueOf(port))); } else { throw new ClientException(ReturnCode.CLIENT_SIDE_CONNECT_ERROR, 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,53 +61,17 @@ 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. * interactive mode to get the management context. */ CommandBuilder getContextCommandBuilder(); } opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/tools/dsconfig/DsconfigLdapConnectionTestCase.java
@@ -129,7 +129,53 @@ assertFalse(DSConfig.main(args, System.out, System.err) == SUCCESS.get()); } /** * --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. */ @@ -229,7 +275,7 @@ { String trustStorePath = DirectoryServer.getInstanceRoot() + File.separator + "config" + File.separator + "admin-truststore"; String[] args = { "-n", @@ -237,6 +283,7 @@ "-Q", "list-connection-handlers", "-p", String.valueOf(TestCaseUtils.getServerAdminPort()), "-D", "cn=Directory Manager", "-w", "password", "-P", trustStorePath };