001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2007-2008 Sun Microsystems, Inc.
026 */
027
028 package org.opends.server.admin.client.cli;
029
030 import static org.opends.server.admin.client.cli.DsFrameworkCliReturnCode.*;
031 import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
032 import static org.opends.server.loggers.debug.DebugLogger.getTracer;
033 import static org.opends.messages.ToolMessages.*;
034
035 import org.opends.messages.Message;
036 import org.opends.messages.MessageBuilder;
037 import static org.opends.server.tools.ToolConstants.*;
038 import static org.opends.server.util.ServerConstants.MAX_LINE_WIDTH;
039 import static org.opends.server.util.StaticUtils.wrapText;
040
041 import java.io.IOException;
042 import java.io.OutputStream;
043 import java.io.PrintStream;
044 import java.util.Collection;
045 import java.util.LinkedHashSet;
046 import java.util.logging.Logger;
047
048 import javax.net.ssl.KeyManager;
049
050 import org.opends.admin.ads.util.ApplicationTrustManager;
051 import org.opends.server.loggers.debug.DebugTracer;
052 import org.opends.server.types.DebugLogLevel;
053 import org.opends.server.util.PasswordReader;
054 import org.opends.server.util.args.Argument;
055 import org.opends.server.util.args.ArgumentException;
056 import org.opends.server.util.args.BooleanArgument;
057 import org.opends.server.util.args.FileBasedArgument;
058 import org.opends.server.util.args.StringArgument;
059 import org.opends.server.util.args.SubCommandArgumentParser;
060 import org.opends.server.util.args.ArgumentGroup;
061
062 /**
063 * This is a commodity class that can be used to check the arguments required
064 * to establish a secure connection in the command line. It can be used
065 * to generate an ApplicationTrustManager object based on the options provided
066 * by the user in the command line.
067 *
068 */
069 public abstract class SecureConnectionCliParser extends SubCommandArgumentParser
070 {
071 /**
072 * The showUsage' global argument.
073 */
074 protected BooleanArgument showUsageArg = null;
075
076 /**
077 * The 'verbose' global argument.
078 */
079 protected BooleanArgument verboseArg = null;
080
081 /**
082 * The secure args list object.
083 */
084 protected SecureConnectionCliArgs secureArgsList ;
085
086 /**
087 * Argument indicating a properties file argument.
088 */
089 protected StringArgument propertiesFileArg = null;
090
091 /**
092 * The argument which should be used to indicate that we will not
093 * look for properties file.
094 */
095 protected BooleanArgument noPropertiesFileArg;
096
097 /**
098 * The tracer object for the debug logger.
099 */
100 private static final DebugTracer TRACER = getTracer();
101
102 /**
103 * End Of Line.
104 */
105 public static String EOL = System.getProperty("line.separator");
106
107 /**
108 * The Logger.
109 */
110 static private final Logger LOG =
111 Logger.getLogger(SecureConnectionCliParser.class.getName());
112
113 /**
114 * Creates a new instance of this argument parser with no arguments.
115 *
116 * @param mainClassName
117 * The fully-qualified name of the Java class that should
118 * be invoked to launch the program with which this
119 * argument parser is associated.
120 * @param toolDescription
121 * A human-readable description for the tool, which will be
122 * included when displaying usage information.
123 * @param longArgumentsCaseSensitive
124 * Indicates whether subcommand and long argument names
125 * should be treated in a case-sensitive manner.
126 */
127 protected SecureConnectionCliParser(String mainClassName,
128 Message toolDescription, boolean longArgumentsCaseSensitive)
129 {
130 super(mainClassName, toolDescription, longArgumentsCaseSensitive);
131 }
132
133 /**
134 * Get the bindDN which has to be used for the command.
135 *
136 * @return The bindDN specified by the command line argument, or the
137 * default value, if not specified.
138 */
139 public String getBindDN()
140 {
141 return secureArgsList.getBindDN();
142 }
143
144
145 /**
146 * Returns the Administrator UID provided in the command-line.
147 * @return the Administrator UID provided in the command-line.
148 */
149 public String getAdministratorUID()
150 {
151 return secureArgsList.getAdministratorUID();
152 }
153
154 /**
155 * Get the password which has to be used for the command.
156 *
157 * @param dn
158 * The user DN for which to password could be asked.
159 * @param out
160 * The input stream to used if we have to prompt to the
161 * user.
162 * @param err
163 * The error stream to used if we have to prompt to the
164 * user.
165 * @param clearArg
166 * The password StringArgument argument.
167 * @param fileArg
168 * The password FileBased argument.
169 * @return The password stored into the specified file on by the
170 * command line argument, or prompts it if not specified.
171 */
172 protected String getBindPassword(String dn,
173 OutputStream out, OutputStream err, StringArgument clearArg,
174 FileBasedArgument fileArg)
175 {
176 if (clearArg.isPresent())
177 {
178 String bindPasswordValue = clearArg.getValue();
179 if(bindPasswordValue != null && bindPasswordValue.equals("-"))
180 {
181 // read the password from the stdin.
182 try
183 {
184 out.write(INFO_LDAPAUTH_PASSWORD_PROMPT.get(dn).getBytes());
185 out.flush();
186 char[] pwChars = PasswordReader.readPassword();
187 bindPasswordValue = new String(pwChars);
188 } catch(Exception ex)
189 {
190 if (debugEnabled())
191 {
192 TRACER.debugCaught(DebugLogLevel.ERROR, ex);
193 }
194 try
195 {
196 err.write(wrapText(ex.getMessage(), MAX_LINE_WIDTH).getBytes());
197 err.write(EOL.getBytes());
198 }
199 catch (IOException e)
200 {
201 }
202 return null;
203 }
204 }
205 return bindPasswordValue;
206 }
207 else
208 if (fileArg.isPresent())
209 {
210 return fileArg.getValue();
211 }
212 else
213 {
214 // read the password from the stdin.
215 try
216 {
217 out.write(INFO_LDAPAUTH_PASSWORD_PROMPT.get(dn).toString().getBytes());
218 out.flush();
219 char[] pwChars = PasswordReader.readPassword();
220 return new String(pwChars);
221 }
222 catch (Exception ex)
223 {
224 if (debugEnabled())
225 {
226 TRACER.debugCaught(DebugLogLevel.ERROR, ex);
227 }
228 try
229 {
230 err.write(wrapText(ex.getMessage(), MAX_LINE_WIDTH).getBytes());
231 err.write(EOL.getBytes());
232 }
233 catch (IOException e)
234 {
235 }
236 return null;
237 }
238 }
239
240 }
241
242 /**
243 * Get the password which has to be used for the command.
244 *
245 * @param dn
246 * The user DN for which to password could be asked.
247 * @param out
248 * The input stream to used if we have to prompt to the
249 * user.
250 * @param err
251 * The error stream to used if we have to prompt to the
252 * user.
253 * @return The password stored into the specified file on by the
254 * command line argument, or prompts it if not specified.
255 */
256 public String getBindPassword(String dn, OutputStream out, OutputStream err)
257 {
258 return getBindPassword(dn, out, err, secureArgsList.bindPasswordArg,
259 secureArgsList.bindPasswordFileArg);
260 }
261
262 /**
263 * Get the password which has to be used for the command without prompting
264 * the user. If no password was specified, return null.
265 *
266 * @param clearArg
267 * The password StringArgument argument.
268 * @param fileArg
269 * The password FileBased argument.
270 * @return The password stored into the specified file on by the
271 * command line argument, or null it if not specified.
272 */
273 public String getBindPassword(StringArgument clearArg,
274 FileBasedArgument fileArg)
275 {
276 String pwd;
277 if (clearArg.isPresent())
278 {
279 pwd = clearArg.getValue();
280 }
281 else
282 if (fileArg.isPresent())
283 {
284 pwd = fileArg.getValue();
285 }
286 else
287 {
288 pwd = null;
289 }
290 return pwd;
291 }
292
293 /**
294 * Get the password which has to be used for the command without prompting
295 * the user. If no password was specified, return null.
296 *
297 * @return The password stored into the specified file on by the
298 * command line argument, or null it if not specified.
299 */
300 public String getBindPassword()
301 {
302 return getBindPassword(secureArgsList.bindPasswordArg,
303 secureArgsList.bindPasswordFileArg);
304 }
305
306 /**
307 * Initialize Global option.
308 *
309 * @param outStream
310 * The output stream used for the usage.
311 * @throws ArgumentException
312 * If there is a problem with any of the parameters used
313 * to create this argument.
314 * @return a ArrayList with the options created.
315 */
316 protected LinkedHashSet<Argument> createGlobalArguments(
317 OutputStream outStream)
318 throws ArgumentException
319 {
320 secureArgsList = new SecureConnectionCliArgs();
321 LinkedHashSet<Argument> set = secureArgsList.createGlobalArguments();
322
323 showUsageArg = new BooleanArgument("showUsage", OPTION_SHORT_HELP,
324 OPTION_LONG_HELP, INFO_DESCRIPTION_SHOWUSAGE.get());
325 setUsageArgument(showUsageArg, outStream);
326 set.add(showUsageArg);
327
328 verboseArg = new BooleanArgument("verbose", OPTION_SHORT_VERBOSE,
329 OPTION_LONG_VERBOSE, INFO_DESCRIPTION_VERBOSE.get());
330 set.add(verboseArg);
331
332 propertiesFileArg = new StringArgument("propertiesFilePath",
333 null, OPTION_LONG_PROP_FILE_PATH,
334 false, false, true, INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null,
335 INFO_DESCRIPTION_PROP_FILE_PATH.get());
336 setFilePropertiesArgument(propertiesFileArg);
337 set.add(propertiesFileArg);
338
339 noPropertiesFileArg = new BooleanArgument(
340 "noPropertiesFileArgument", null, OPTION_LONG_NO_PROP_FILE,
341 INFO_DESCRIPTION_NO_PROP_FILE.get());
342 setNoPropertiesFileArgument(noPropertiesFileArg);
343 set.add(noPropertiesFileArg);
344
345
346 return set;
347 }
348
349 /**
350 * Initialize the global options with the provided set of arguments.
351 * @param args the arguments to use to initialize the global options.
352 * @throws ArgumentException if there is a conflict with the provided
353 * arguments.
354 */
355 protected void initializeGlobalArguments(Collection<Argument> args)
356 throws ArgumentException
357 {
358 initializeGlobalArguments(args, null);
359 }
360
361
362 /**
363 * Initialize the global options with the provided set of arguments.
364 * @param args the arguments to use to initialize the global options.
365 * @param argGroup to which args will be added
366 * @throws ArgumentException if there is a conflict with the provided
367 * arguments.
368 */
369 protected void initializeGlobalArguments(
370 Collection<Argument> args,
371 ArgumentGroup argGroup)
372 throws ArgumentException
373 {
374
375 for (Argument arg : args)
376 {
377 addGlobalArgument(arg, argGroup);
378 }
379
380 // Set the propertiesFile argument
381 setFilePropertiesArgument(propertiesFileArg);
382 }
383
384 /**
385 * Get the host name which has to be used for the command.
386 *
387 * @return The host name specified by the command line argument, or
388 * the default value, if not specified.
389 */
390 public String getHostName()
391 {
392 return secureArgsList.getHostName();
393 }
394
395 /**
396 * Get the port which has to be used for the command.
397 *
398 * @return The port specified by the command line argument, or the
399 * default value, if not specified.
400 */
401 public String getPort()
402 {
403 return secureArgsList.getPort();
404 }
405
406 /**
407 * Indication if provided global options are validate.
408 *
409 * @param buf the MessageBuilder to write the error messages.
410 * @return return code.
411 */
412 public int validateGlobalOptions(MessageBuilder buf)
413 {
414 int ret = secureArgsList.validateGlobalOptions(buf) ;
415
416 // Couldn't have at the same time properties file arg and
417 // propertiesFileArg
418 if (noPropertiesFileArg.isPresent()
419 && propertiesFileArg.isPresent())
420 {
421 Message message = ERR_TOOL_CONFLICTING_ARGS.get(
422 noPropertiesFileArg.getLongIdentifier(), propertiesFileArg
423 .getLongIdentifier());
424 if (buf.length() > 0)
425 {
426 buf.append(EOL);
427 }
428 buf.append(message);
429 ret = CONFLICTING_ARGS.getReturnCode();
430 }
431
432 return ret;
433 }
434 /**
435 * Indication if provided global options are validate.
436 *
437 * @param err the stream to be used to print error message.
438 * @return return code.
439 */
440 public int validateGlobalOptions(PrintStream err)
441 {
442 MessageBuilder buf = new MessageBuilder();
443 int returnValue = validateGlobalOptions(buf);
444 if (buf.length() > 0)
445 {
446 err.println(wrapText(buf.toString(), MAX_LINE_WIDTH));
447 }
448 return returnValue;
449 }
450
451 /**
452 * Indicate if the verbose mode is required.
453 *
454 * @return True if verbose mode is required
455 */
456 public boolean isVerbose()
457 {
458 if (verboseArg.isPresent())
459 {
460 return true;
461 }
462 else
463 {
464 return false ;
465 }
466 }
467
468
469 /**
470 * Indicate if the SSL mode is required.
471 *
472 * @return True if SSL mode is required
473 */
474 public boolean useSSL()
475 {
476 return secureArgsList.useSSL();
477 }
478
479 /**
480 * Indicate if the startTLS mode is required.
481 *
482 * @return True if startTLS mode is required
483 */
484 public boolean useStartTLS()
485 {
486 return secureArgsList.useStartTLS();
487 }
488
489 /**
490 * Handle TrustStore.
491 *
492 * @return The trustStore manager to be used for the command.
493 */
494 public ApplicationTrustManager getTrustManager()
495 {
496 return secureArgsList.getTrustManager();
497 }
498
499 /**
500 * Handle KeyStore.
501 *
502 * @return The keyStore manager to be used for the command.
503 */
504 public KeyManager getKeyManager()
505 {
506 return secureArgsList.getKeyManager() ;
507 }
508 }