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 }