001/* 002 * Copyright 2016-2017 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2016-2017 Ping Identity Corporation 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.ldap.sdk.unboundidds.tools; 022 023 024 025import java.io.BufferedReader; 026import java.io.File; 027import java.io.FileOutputStream; 028import java.io.FileReader; 029import java.io.OutputStream; 030import java.util.ArrayList; 031import java.util.Arrays; 032import java.util.LinkedHashMap; 033import java.util.concurrent.atomic.AtomicBoolean; 034 035import com.unboundid.ldap.sdk.DN; 036import com.unboundid.ldap.sdk.ExtendedResult; 037import com.unboundid.ldap.sdk.Filter; 038import com.unboundid.ldap.sdk.LDAPConnection; 039import com.unboundid.ldap.sdk.LDAPConnectionOptions; 040import com.unboundid.ldap.sdk.LDAPConnectionPool; 041import com.unboundid.ldap.sdk.LDAPException; 042import com.unboundid.ldap.sdk.ResultCode; 043import com.unboundid.ldap.sdk.UnsolicitedNotificationHandler; 044import com.unboundid.ldap.sdk.Version; 045import com.unboundid.ldif.LDIFWriter; 046import com.unboundid.util.Debug; 047import com.unboundid.util.DNFileReader; 048import com.unboundid.util.LDAPCommandLineTool; 049import com.unboundid.util.FilterFileReader; 050import com.unboundid.util.FixedRateBarrier; 051import com.unboundid.util.RateAdjustor; 052import com.unboundid.util.StaticUtils; 053import com.unboundid.util.ThreadSafety; 054import com.unboundid.util.ThreadSafetyLevel; 055import com.unboundid.util.args.ArgumentException; 056import com.unboundid.util.args.ArgumentParser; 057import com.unboundid.util.args.BooleanArgument; 058import com.unboundid.util.args.BooleanValueArgument; 059import com.unboundid.util.args.DNArgument; 060import com.unboundid.util.args.FileArgument; 061import com.unboundid.util.args.FilterArgument; 062import com.unboundid.util.args.IPAddressArgumentValueValidator; 063import com.unboundid.util.args.IntegerArgument; 064import com.unboundid.util.args.StringArgument; 065import com.unboundid.util.args.TimestampArgument; 066import com.unboundid.util.args.SubCommand; 067 068import static com.unboundid.ldap.sdk.unboundidds.tools. 069 ManageAccountSubCommandType.*; 070import static com.unboundid.ldap.sdk.unboundidds.tools.ToolMessages.*; 071 072 073 074/** 075 * This class provides a tool that can be used to perform a variety of account 076 * management functions against user entries in the Ping Identity, UnboundID, 077 * or Alcatel-Lucent 8661 Directory Server. It primarily uses the password 078 * policy state extended operation for its processing. 079 * <BR> 080 * <BLOCKQUOTE> 081 * <B>NOTE:</B> This class, and other classes within the 082 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 083 * supported for use against Ping Identity, UnboundID, and Alcatel-Lucent 8661 084 * server products. These classes provide support for proprietary 085 * functionality or for external specifications that are not considered stable 086 * or mature enough to be guaranteed to work in an interoperable way with 087 * other types of LDAP servers. 088 * </BLOCKQUOTE> 089 */ 090@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 091public final class ManageAccount 092 extends LDAPCommandLineTool 093 implements UnsolicitedNotificationHandler 094{ 095 /** 096 * The column at which to wrap long lines. 097 */ 098 static final int WRAP_COLUMN = StaticUtils.TERMINAL_WIDTH_COLUMNS - 1; 099 100 101 102 /** 103 * The primary name of the argument used to indicate that the tool should 104 * append to the reject file rather than overwrite it. 105 */ 106 static final String ARG_APPEND_TO_REJECT_FILE = "appendToRejectFile"; 107 108 109 110 /** 111 * The primary name of the argument used to specify a base DN to use for 112 * searches. 113 */ 114 static final String ARG_BASE_DN = "baseDN"; 115 116 117 118 /** 119 * The primary name of the argument used to specify the path to a file to a 120 * sample variable rate data file to create. 121 */ 122 static final String ARG_GENERATE_SAMPLE_RATE_FILE = "generateSampleRateFile"; 123 124 125 126 /** 127 * The primary name of the argument used to specify the path to a file 128 * containing the DNs of the users on which to operate. 129 */ 130 static final String ARG_DN_INPUT_FILE = "dnInputFile"; 131 132 133 134 /** 135 * The primary name of the argument used to specify the path to a file 136 * containing search filters to use to identify users. 137 */ 138 static final String ARG_FILTER_INPUT_FILE = "filterInputFile"; 139 140 141 142 /** 143 * The primary name of the argument used to specify the number of threads to 144 * use to process search operations to identify which users to target. 145 */ 146 static final String ARG_NUM_SEARCH_THREADS = "numSearchThreads"; 147 148 149 150 /** 151 * The primary name of the argument used to specify the number of threads to 152 * use to perform manage-account processing. 153 */ 154 static final String ARG_NUM_THREADS = "numThreads"; 155 156 157 158 /** 159 * The primary name of the argument used to specify the target rate of 160 * operations per second. 161 */ 162 static final String ARG_RATE_PER_SECOND = "ratePerSecond"; 163 164 165 166 /** 167 * The primary name of the argument used to specify the path to a reject file 168 * to create. 169 */ 170 static final String ARG_REJECT_FILE = "rejectFile"; 171 172 173 174 /** 175 * The primary name of the argument used to specify the simple page size to 176 * use when performing searches. 177 */ 178 static final String ARG_SIMPLE_PAGE_SIZE = "simplePageSize"; 179 180 181 182 /** 183 * The primary name of the argument used to suppress result operation types 184 * without values. 185 */ 186 static final String ARG_SUPPRESS_EMPTY_RESULT_OPERATIONS = 187 "suppressEmptyResultOperations"; 188 189 190 191 /** 192 * The primary name of the argument used to specify the DN of the user on 193 * which to operate. 194 */ 195 static final String ARG_TARGET_DN = "targetDN"; 196 197 198 199 /** 200 * The primary name of the argument used to specify a search filter to use to 201 * identify users. 202 */ 203 static final String ARG_TARGET_FILTER = "targetFilter"; 204 205 206 207 /** 208 * The primary name of the argument used to specify the user IDs of target 209 * users. 210 */ 211 static final String ARG_TARGET_USER_ID = "targetUserID"; 212 213 214 215 /** 216 * The primary name of the argument used to specify the name of the attribute 217 * to identify which user has a given user ID. 218 */ 219 static final String ARG_USER_ID_ATTRIBUTE = "userIDAttribute"; 220 221 222 223 /** 224 * The primary name of the argument used to specify the path to a file 225 * containing the user IDs of the target users. 226 */ 227 static final String ARG_USER_ID_INPUT_FILE = "userIDInputFile"; 228 229 230 231 /** 232 * The primary name of the argument used to specify the path to a variable 233 * rate data file. 234 */ 235 static final String ARG_VARIABLE_RATE_DATA = "variableRateData"; 236 237 238 239 /** 240 * The default search base DN. 241 */ 242 static final DN DEFAULT_BASE_DN = DN.NULL_DN; 243 244 245 246 /** 247 * The default user ID attribute. 248 */ 249 static final String DEFAULT_USER_ID_ATTRIBUTE = "uid"; 250 251 252 253 /** 254 * A target user DN to use in examples. 255 */ 256 static final String EXAMPLE_TARGET_USER_DN = 257 "uid=jdoe,ou=People,dc=example,dc=com"; 258 259 260 261 // The argument parser for this tool. 262 private volatile ArgumentParser parser; 263 264 // Indicates whether all DNs have been provided to the manage-account 265 // processor. 266 private final AtomicBoolean allDNsProvided; 267 268 // Indicates whether all filters have been provided to the manage-account 269 // search processor. 270 private final AtomicBoolean allFiltersProvided; 271 272 // Indicates whether a request has been made to cancel processing. 273 private final AtomicBoolean cancelRequested; 274 275 // The rate limiter to use for this tool. 276 private volatile FixedRateBarrier rateLimiter; 277 278 // The LDAP connection options to use for connections created by this tool. 279 private final LDAPConnectionOptions connectionOptions; 280 281 // The LDIF writer to use to write information about successful and failed 282 // operations. 283 private volatile LDIFWriter outputWriter; 284 285 // The LDIF writer to use to write information about failed operations. 286 private volatile LDIFWriter rejectWriter; 287 288 // The search processor for this tool. 289 private volatile ManageAccountSearchProcessor searchProcessor; 290 291 // The rate adjustor to use to vary the load over time. 292 private volatile RateAdjustor rateAdjustor; 293 294 295 296 /** 297 * Invokes the tool with the provided set of arguments. 298 * 299 * @param args The command-line arguments provided to this tool. 300 */ 301 public static void main(final String... args) 302 { 303 final ResultCode resultCode = main(System.out, System.err, args); 304 if (resultCode != ResultCode.SUCCESS) 305 { 306 System.exit(resultCode.intValue()); 307 } 308 } 309 310 311 312 /** 313 * Invokes the tool with the provided set of arguments. 314 * 315 * @param out The output stream to use for standard out. It may be 316 * {@code null} if standard out should be suppressed. 317 * @param err The output stream to use for standard error. It may be 318 * {@code null} if standard error should be suppressed. 319 * @param args The command-line arguments provided to this tool. 320 * 321 * @return A result code with the status of the tool processing. Any result 322 * code other than {@link ResultCode#SUCCESS} should be considered a 323 * failure. 324 */ 325 public static ResultCode main(final OutputStream out, final OutputStream err, 326 final String... args) 327 { 328 final ManageAccount tool = new ManageAccount(out, err); 329 330 final boolean origCommentAboutBase64EncodedValues = 331 LDIFWriter.commentAboutBase64EncodedValues(); 332 LDIFWriter.setCommentAboutBase64EncodedValues(true); 333 try 334 { 335 return tool.runTool(args); 336 } 337 finally 338 { 339 LDIFWriter.setCommentAboutBase64EncodedValues( 340 origCommentAboutBase64EncodedValues); 341 } 342 } 343 344 345 346 /** 347 * Creates a new instance of this tool with the provided arguments. 348 * 349 * @param out The output stream to use for standard out. It may be 350 * {@code null} if standard out should be suppressed. 351 * @param err The output stream to use for standard error. It may be 352 * {@code null} if standard error should be suppressed. 353 */ 354 public ManageAccount(final OutputStream out, final OutputStream err) 355 { 356 super(out, err); 357 358 connectionOptions = new LDAPConnectionOptions(); 359 connectionOptions.setUnsolicitedNotificationHandler(this); 360 361 allDNsProvided = new AtomicBoolean(false); 362 allFiltersProvided = new AtomicBoolean(false); 363 cancelRequested = new AtomicBoolean(false); 364 365 parser = null; 366 rateLimiter = null; 367 rateAdjustor = null; 368 outputWriter = null; 369 rejectWriter = null; 370 searchProcessor = null; 371 } 372 373 374 375 /** 376 * {@inheritDoc} 377 */ 378 @Override() 379 public String getToolName() 380 { 381 return "manage-account"; 382 } 383 384 385 386 /** 387 * {@inheritDoc} 388 */ 389 @Override() 390 public String getToolDescription() 391 { 392 return INFO_MANAGE_ACCT_TOOL_DESC.get(); 393 } 394 395 396 397 /** 398 * {@inheritDoc} 399 */ 400 @Override() 401 public String getToolVersion() 402 { 403 return Version.NUMERIC_VERSION_STRING; 404 } 405 406 407 408 /** 409 * {@inheritDoc} 410 */ 411 @Override() 412 public boolean supportsInteractiveMode() 413 { 414 return true; 415 } 416 417 418 419 /** 420 * {@inheritDoc} 421 */ 422 @Override() 423 public boolean defaultsToInteractiveMode() 424 { 425 return true; 426 } 427 428 429 430 /** 431 * {@inheritDoc} 432 */ 433 @Override() 434 public boolean supportsPropertiesFile() 435 { 436 return true; 437 } 438 439 440 441 /** 442 * {@inheritDoc} 443 */ 444 @Override() 445 protected boolean supportsOutputFile() 446 { 447 return true; 448 } 449 450 451 452 /** 453 * {@inheritDoc} 454 */ 455 @Override() 456 protected boolean supportsAuthentication() 457 { 458 return true; 459 } 460 461 462 463 /** 464 * {@inheritDoc} 465 */ 466 @Override() 467 protected boolean defaultToPromptForBindPassword() 468 { 469 return true; 470 } 471 472 473 474 /** 475 * {@inheritDoc} 476 */ 477 @Override() 478 protected boolean supportsSASLHelp() 479 { 480 return true; 481 } 482 483 484 485 /** 486 * {@inheritDoc} 487 */ 488 @Override() 489 protected boolean includeAlternateLongIdentifiers() 490 { 491 return true; 492 } 493 494 495 496 /** 497 * {@inheritDoc} 498 */ 499 @Override() 500 protected boolean supportsMultipleServers() 501 { 502 return true; 503 } 504 505 506 507 /** 508 * {@inheritDoc} 509 */ 510 @Override() 511 public void addNonLDAPArguments(final ArgumentParser parser) 512 throws ArgumentException 513 { 514 // Get a copy of the argument parser for later use. 515 this.parser = parser; 516 517 518 // Get the current time formatted as a generalized time. 519 final String currentGeneralizedTime = 520 StaticUtils.encodeGeneralizedTime(System.currentTimeMillis()); 521 final String olderGeneralizedTime = 522 StaticUtils.encodeGeneralizedTime(System.currentTimeMillis() - 12345L); 523 524 525 // Define the global arguments used to indicate which users to target. 526 final DNArgument targetDN = new DNArgument('b', ARG_TARGET_DN, false, 0, 527 null, INFO_MANAGE_ACCT_ARG_DESC_TARGET_DN.get()); 528 targetDN.addLongIdentifier("userDN"); 529 targetDN.addLongIdentifier("target-dn"); 530 targetDN.addLongIdentifier("user-dn"); 531 targetDN.setArgumentGroupName( 532 INFO_MANAGE_ACCT_ARG_GROUP_TARGET_USER_ARGS.get()); 533 parser.addArgument(targetDN); 534 535 final FileArgument dnInputFile = new FileArgument(null, ARG_DN_INPUT_FILE, 536 false, 0, null, INFO_MANAGE_ACCT_ARG_DESC_DN_FILE.get(), true, 537 true, true, false); 538 dnInputFile.addLongIdentifier("targetDNFile"); 539 dnInputFile.addLongIdentifier("userDNFile"); 540 dnInputFile.addLongIdentifier("dn-input-file"); 541 dnInputFile.addLongIdentifier("target-dn-file"); 542 dnInputFile.addLongIdentifier("user-dn-file"); 543 dnInputFile.setArgumentGroupName( 544 INFO_MANAGE_ACCT_ARG_GROUP_TARGET_USER_ARGS.get()); 545 parser.addArgument(dnInputFile); 546 547 final FilterArgument targetFilter = new FilterArgument(null, 548 ARG_TARGET_FILTER, false, 0, null, 549 INFO_MANAGE_ACCT_ARG_DESC_TARGET_FILTER.get(ARG_BASE_DN)); 550 targetFilter.addLongIdentifier("target-filter"); 551 targetFilter.setArgumentGroupName( 552 INFO_MANAGE_ACCT_ARG_GROUP_TARGET_USER_ARGS.get()); 553 parser.addArgument(targetFilter); 554 555 final FileArgument filterInputFile = new FileArgument(null, 556 ARG_FILTER_INPUT_FILE, false, 0, null, 557 INFO_MANAGE_ACCT_ARG_DESC_FILTER_INPUT_FILE.get(ARG_BASE_DN), 558 true, true, true, false); 559 filterInputFile.addLongIdentifier("targetFilterFile"); 560 filterInputFile.addLongIdentifier("filter-input-file"); 561 filterInputFile.addLongIdentifier("target-filter-file"); 562 filterInputFile.setArgumentGroupName( 563 INFO_MANAGE_ACCT_ARG_GROUP_TARGET_USER_ARGS.get()); 564 parser.addArgument(filterInputFile); 565 566 final StringArgument targetUserID = new StringArgument(null, 567 ARG_TARGET_USER_ID, false, 0, null, 568 INFO_MANAGE_ACCT_ARG_DESC_TARGET_USER_ID.get(ARG_BASE_DN, 569 ARG_USER_ID_ATTRIBUTE)); 570 targetUserID.addLongIdentifier("userID"); 571 targetUserID.addLongIdentifier("target-user-id"); 572 targetUserID.addLongIdentifier("user-id"); 573 targetUserID.setArgumentGroupName( 574 INFO_MANAGE_ACCT_ARG_GROUP_TARGET_USER_ARGS.get()); 575 parser.addArgument(targetUserID); 576 577 final FileArgument userIDInputFile = new FileArgument(null, 578 ARG_USER_ID_INPUT_FILE, false, 0, null, 579 INFO_MANAGE_ACCT_ARG_DESC_USER_ID_INPUT_FILE.get(ARG_BASE_DN, 580 ARG_USER_ID_ATTRIBUTE), 581 true, true, true, false); 582 userIDInputFile.addLongIdentifier("targetUserIDFile"); 583 userIDInputFile.addLongIdentifier("user-id-input-file"); 584 userIDInputFile.addLongIdentifier("target-user-id-file"); 585 userIDInputFile.setArgumentGroupName( 586 INFO_MANAGE_ACCT_ARG_GROUP_TARGET_USER_ARGS.get()); 587 parser.addArgument(userIDInputFile); 588 589 final StringArgument userIDAttribute = new StringArgument(null, 590 ARG_USER_ID_ATTRIBUTE, false, 1, null, 591 INFO_MANAGE_ACCT_ARG_DESC_USER_ID_ATTR.get( 592 ARG_TARGET_USER_ID, ARG_USER_ID_INPUT_FILE, 593 DEFAULT_USER_ID_ATTRIBUTE), 594 DEFAULT_USER_ID_ATTRIBUTE); 595 userIDAttribute.addLongIdentifier("user-id-attribute"); 596 userIDAttribute.setArgumentGroupName( 597 INFO_MANAGE_ACCT_ARG_GROUP_TARGET_USER_ARGS.get()); 598 parser.addArgument(userIDAttribute); 599 600 final DNArgument baseDN = new DNArgument(null, ARG_BASE_DN, false, 1, null, 601 INFO_MANAGE_ACCT_ARG_DESC_BASE_DN.get(ARG_TARGET_FILTER, 602 ARG_FILTER_INPUT_FILE, ARG_TARGET_USER_ID, 603 ARG_USER_ID_INPUT_FILE), 604 DEFAULT_BASE_DN); 605 baseDN.addLongIdentifier("base-dn"); 606 baseDN.setArgumentGroupName( 607 INFO_MANAGE_ACCT_ARG_GROUP_TARGET_USER_ARGS.get()); 608 parser.addArgument(baseDN); 609 610 final IntegerArgument simplePageSize = new IntegerArgument('z', 611 ARG_SIMPLE_PAGE_SIZE, false, 1, null, 612 INFO_MANAGE_ACCT_ARG_DESC_SIMPLE_PAGE_SIZE.get(getToolName()), 1, 613 Integer.MAX_VALUE); 614 simplePageSize.addLongIdentifier("simple-page-size"); 615 simplePageSize.setArgumentGroupName( 616 INFO_MANAGE_ACCT_ARG_GROUP_TARGET_USER_ARGS.get(getToolName())); 617 parser.addArgument(simplePageSize); 618 619 620 // Ensure that the user will be required ot provide at least one of the 621 // arguments to specify which users to target. 622 parser.addRequiredArgumentSet(targetDN, dnInputFile, targetFilter, 623 filterInputFile, targetUserID, userIDInputFile); 624 625 626 // Define the global arguments used to control the amount of load the tool 627 // should be permitted to generate. 628 final IntegerArgument numThreads = new IntegerArgument('t', ARG_NUM_THREADS, 629 false, 1, null, 630 INFO_MANAGE_ACCT_ARG_DESC_NUM_THREADS.get(getToolName()), 1, 631 Integer.MAX_VALUE, 1); 632 numThreads.addLongIdentifier("num-threads"); 633 numThreads.setArgumentGroupName( 634 INFO_MANAGE_ACCT_ARG_GROUP_PERFORMANCE.get()); 635 parser.addArgument(numThreads); 636 637 final IntegerArgument numSearchThreads = new IntegerArgument(null, 638 ARG_NUM_SEARCH_THREADS, false, 1, null, 639 INFO_MANAGE_ACCT_ARG_DESC_NUM_SEARCH_THREADS.get(getToolName()), 1, 640 Integer.MAX_VALUE, 1); 641 numSearchThreads.addLongIdentifier("num-search-threads"); 642 numSearchThreads.setArgumentGroupName( 643 INFO_MANAGE_ACCT_ARG_GROUP_PERFORMANCE.get()); 644 parser.addArgument(numSearchThreads); 645 646 final IntegerArgument ratePerSecond = new IntegerArgument('r', 647 ARG_RATE_PER_SECOND, false, 1, null, 648 INFO_MANAGE_ACCT_ARG_DESC_RATE_PER_SECOND.get( 649 ARG_VARIABLE_RATE_DATA), 650 1, Integer.MAX_VALUE); 651 ratePerSecond.addLongIdentifier("rate-per-second"); 652 ratePerSecond.setArgumentGroupName( 653 INFO_MANAGE_ACCT_ARG_GROUP_PERFORMANCE.get()); 654 parser.addArgument(ratePerSecond); 655 656 final FileArgument variableRateData = new FileArgument(null, 657 ARG_VARIABLE_RATE_DATA, false, 1, null, 658 INFO_MANAGE_ACCT_ARG_DESC_VARIABLE_RATE_DATA.get( 659 ARG_RATE_PER_SECOND), 660 true, true, true, false); 661 variableRateData.addLongIdentifier("variable-rate-data"); 662 variableRateData.setArgumentGroupName( 663 INFO_MANAGE_ACCT_ARG_GROUP_PERFORMANCE.get()); 664 parser.addArgument(variableRateData); 665 666 final FileArgument generateSampleRateFile = new FileArgument(null, 667 ARG_GENERATE_SAMPLE_RATE_FILE, false, 1, null, 668 INFO_MANAGE_ACCT_ARG_DESC_GENERATE_SAMPLE_RATE_FILE.get( 669 ARG_VARIABLE_RATE_DATA), 670 false, true, true, false); 671 generateSampleRateFile.addLongIdentifier("generate-sample-rate-file"); 672 generateSampleRateFile.setArgumentGroupName( 673 INFO_MANAGE_ACCT_ARG_GROUP_PERFORMANCE.get()); 674 generateSampleRateFile.setUsageArgument(true); 675 parser.addArgument(generateSampleRateFile); 676 677 678 // Define the global arguments tht pertain to the reject file. 679 final FileArgument rejectFile = new FileArgument('R', ARG_REJECT_FILE, 680 false, 1, null, INFO_MANAGE_ACCT_ARG_DESC_REJECT_FILE.get(), 681 false, true, true, false); 682 rejectFile.addLongIdentifier("reject-file"); 683 parser.addArgument(rejectFile); 684 685 final BooleanArgument appendToRejectFile = new BooleanArgument(null, 686 ARG_APPEND_TO_REJECT_FILE, 1, 687 INFO_MANAGE_ACCT_ARG_DESC_APPEND_TO_REJECT_FILE.get( 688 rejectFile.getIdentifierString())); 689 appendToRejectFile.addLongIdentifier("append-to-reject-file"); 690 parser.addArgument(appendToRejectFile); 691 692 parser.addDependentArgumentSet(appendToRejectFile, rejectFile); 693 694 695 // Define the argument used to suppress result operations without values. 696 final BooleanArgument suppressEmptyResultOperations = 697 new BooleanArgument(null, ARG_SUPPRESS_EMPTY_RESULT_OPERATIONS, 698 1, 699 INFO_MANAGE_ACCT_ARG_DESC_SUPPRESS_EMPTY_RESULT_OPERATIONS.get( 700 getToolName())); 701 parser.addArgument(suppressEmptyResultOperations); 702 703 704 // Define the subcommand used to retrieve all state information for a user. 705 createSubCommand(GET_ALL, 706 INFO_MANAGE_ACCT_SC_GET_ALL_EXAMPLE.get(EXAMPLE_TARGET_USER_DN)); 707 708 709 // Define the subcommand used to retrieve the password policy DN for a user. 710 createSubCommand(GET_PASSWORD_POLICY_DN, 711 INFO_MANAGE_ACCT_SC_GET_POLICY_DN_EXAMPLE.get(EXAMPLE_TARGET_USER_DN)); 712 713 714 // Define the subcommand to determine whether the account is usable. 715 createSubCommand(GET_ACCOUNT_IS_USABLE, 716 INFO_MANAGE_ACCT_SC_GET_IS_USABLE_EXAMPLE.get(EXAMPLE_TARGET_USER_DN)); 717 718 719 // Define the subcommand to retrieve the set of password policy state 720 // account usability notice messages. 721 createSubCommand(GET_ACCOUNT_USABILITY_NOTICES, 722 INFO_MANAGE_ACCT_SC_GET_USABILITY_NOTICES_EXAMPLE.get( 723 EXAMPLE_TARGET_USER_DN)); 724 725 726 // Define the subcommand to retrieve the set of password policy state 727 // account usability warning messages. 728 createSubCommand(GET_ACCOUNT_USABILITY_WARNINGS, 729 INFO_MANAGE_ACCT_SC_GET_USABILITY_WARNINGS_EXAMPLE.get( 730 EXAMPLE_TARGET_USER_DN)); 731 732 733 // Define the subcommand to retrieve the set of password policy state 734 // account usability error messages. 735 createSubCommand(GET_ACCOUNT_USABILITY_ERRORS, 736 INFO_MANAGE_ACCT_SC_GET_USABILITY_ERRORS_EXAMPLE.get( 737 EXAMPLE_TARGET_USER_DN)); 738 739 740 // Define the subcommand to retrieve the password changed time for a user. 741 createSubCommand(GET_PASSWORD_CHANGED_TIME, 742 INFO_MANAGE_ACCT_SC_GET_PW_CHANGED_TIME_EXAMPLE.get( 743 EXAMPLE_TARGET_USER_DN)); 744 745 746 // Define the subcommand to set the password changed time for a user. 747 final ArgumentParser setPWChangedTimeParser = 748 createSubCommandParser(SET_PASSWORD_CHANGED_TIME); 749 750 final TimestampArgument setPWChangedTimeValueArg = new TimestampArgument( 751 'O', "passwordChangedTime", false, 1, null, 752 INFO_MANAGE_ACCT_SC_SET_PW_CHANGED_TIME_ARG_VALUE.get()); 753 setPWChangedTimeValueArg.addLongIdentifier("operationValue"); 754 setPWChangedTimeValueArg.addLongIdentifier("password-changed-time"); 755 setPWChangedTimeValueArg.addLongIdentifier("operation-value"); 756 setPWChangedTimeParser.addArgument(setPWChangedTimeValueArg); 757 758 createSubCommand(SET_PASSWORD_CHANGED_TIME, setPWChangedTimeParser, 759 createSubCommandExample(SET_PASSWORD_CHANGED_TIME, 760 INFO_MANAGE_ACCT_SC_SET_PW_CHANGED_TIME_EXAMPLE.get( 761 EXAMPLE_TARGET_USER_DN, currentGeneralizedTime), 762 "--passwordChangedTime", currentGeneralizedTime)); 763 764 765 // Define the subcommand to clear the password changed time for a user. 766 createSubCommand(CLEAR_PASSWORD_CHANGED_TIME, 767 INFO_MANAGE_ACCT_SC_CLEAR_PW_CHANGED_TIME_EXAMPLE.get( 768 EXAMPLE_TARGET_USER_DN)); 769 770 771 // Define the subcommand to determine whether a user account is disabled. 772 createSubCommand(GET_ACCOUNT_IS_DISABLED, 773 INFO_MANAGE_ACCT_SC_GET_IS_DISABLED_EXAMPLE.get( 774 EXAMPLE_TARGET_USER_DN)); 775 776 777 // Define the subcommand to specify whether a user's account is disabled. 778 final ArgumentParser setAcctDisabledParser = 779 createSubCommandParser(SET_ACCOUNT_IS_DISABLED); 780 781 final BooleanValueArgument setAcctDisabledValueArg = 782 new BooleanValueArgument('O', "accountIsDisabled", true, null, 783 INFO_MANAGE_ACCT_SC_SET_IS_DISABLED_ARG_VALUE.get()); 784 setAcctDisabledValueArg.addLongIdentifier("operationValue"); 785 setAcctDisabledValueArg.addLongIdentifier("account-is-disabled"); 786 setAcctDisabledValueArg.addLongIdentifier("operation-value"); 787 setAcctDisabledParser.addArgument(setAcctDisabledValueArg); 788 789 createSubCommand(SET_ACCOUNT_IS_DISABLED, setAcctDisabledParser, 790 createSubCommandExample(SET_ACCOUNT_IS_DISABLED, 791 INFO_MANAGE_ACCT_SC_SET_IS_DISABLED_EXAMPLE.get( 792 EXAMPLE_TARGET_USER_DN), 793 "--accountIsDisabled", "true")); 794 795 796 // Define the subcommand to clear the account disabled state. 797 createSubCommand(CLEAR_ACCOUNT_IS_DISABLED, 798 INFO_MANAGE_ACCT_SC_CLEAR_IS_DISABLED_EXAMPLE.get( 799 EXAMPLE_TARGET_USER_DN)); 800 801 802 // Define the subcommand to retrieve the account activation time for a user. 803 createSubCommand(GET_ACCOUNT_ACTIVATION_TIME, 804 INFO_MANAGE_ACCT_SC_GET_ACCT_ACT_TIME_EXAMPLE.get( 805 EXAMPLE_TARGET_USER_DN)); 806 807 808 // Define the subcommand to set the account activation time for a user. 809 final ArgumentParser setAcctActivationTimeParser = 810 createSubCommandParser(SET_ACCOUNT_ACTIVATION_TIME); 811 812 final TimestampArgument setAcctActivationTimeValueArg = 813 new TimestampArgument('O', "accountActivationTime", false, 1, null, 814 INFO_MANAGE_ACCT_SC_SET_ACCT_ACT_TIME_ARG_VALUE.get()); 815 setAcctActivationTimeValueArg.addLongIdentifier("operationValue"); 816 setAcctActivationTimeValueArg.addLongIdentifier("account-activation-time"); 817 setAcctActivationTimeValueArg.addLongIdentifier("operation-value"); 818 setAcctActivationTimeParser.addArgument(setAcctActivationTimeValueArg); 819 820 createSubCommand(SET_ACCOUNT_ACTIVATION_TIME, setAcctActivationTimeParser, 821 createSubCommandExample(SET_ACCOUNT_ACTIVATION_TIME, 822 INFO_MANAGE_ACCT_SC_SET_ACCT_ACT_TIME_EXAMPLE.get( 823 EXAMPLE_TARGET_USER_DN, currentGeneralizedTime), 824 "--accountActivationTime", currentGeneralizedTime)); 825 826 827 // Define the subcommand to clear the account activation time for a user. 828 createSubCommand(CLEAR_ACCOUNT_ACTIVATION_TIME, 829 INFO_MANAGE_ACCT_SC_CLEAR_ACCT_ACT_TIME_EXAMPLE.get( 830 EXAMPLE_TARGET_USER_DN)); 831 832 833 // Define the subcommand to retrieve the length of time until a user's 834 // account is activated. 835 createSubCommand(GET_SECONDS_UNTIL_ACCOUNT_ACTIVATION, 836 INFO_MANAGE_ACCT_SC_GET_SECONDS_UNTIL_ACCT_ACT_EXAMPLE.get( 837 EXAMPLE_TARGET_USER_DN)); 838 839 840 // Define the subcommand to determine whether a user's account is not yet 841 // active. 842 createSubCommand(GET_ACCOUNT_IS_NOT_YET_ACTIVE, 843 INFO_MANAGE_ACCT_SC_GET_ACCT_NOT_YET_ACTIVE_EXAMPLE.get( 844 EXAMPLE_TARGET_USER_DN)); 845 846 847 // Define the subcommand to retrieve the account expiration time for a user. 848 createSubCommand(GET_ACCOUNT_EXPIRATION_TIME, 849 INFO_MANAGE_ACCT_SC_GET_ACCT_EXP_TIME_EXAMPLE.get( 850 EXAMPLE_TARGET_USER_DN)); 851 852 853 // Define the subcommand to set the account expiration time for a user. 854 final ArgumentParser setAcctExpirationTimeParser = 855 createSubCommandParser(SET_ACCOUNT_EXPIRATION_TIME); 856 857 final TimestampArgument setAcctExpirationTimeValueArg = 858 new TimestampArgument('O', "accountExpirationTime", false, 1, null, 859 INFO_MANAGE_ACCT_SC_SET_ACCT_EXP_TIME_ARG_VALUE.get()); 860 setAcctExpirationTimeValueArg.addLongIdentifier("operationValue"); 861 setAcctExpirationTimeValueArg.addLongIdentifier("account-expiration-time"); 862 setAcctExpirationTimeValueArg.addLongIdentifier("operation-value"); 863 setAcctExpirationTimeParser.addArgument(setAcctExpirationTimeValueArg); 864 865 createSubCommand(SET_ACCOUNT_EXPIRATION_TIME, setAcctExpirationTimeParser, 866 createSubCommandExample(SET_ACCOUNT_EXPIRATION_TIME, 867 INFO_MANAGE_ACCT_SC_SET_ACCT_EXP_TIME_EXAMPLE.get( 868 EXAMPLE_TARGET_USER_DN, currentGeneralizedTime), 869 "--accountExpirationTime", currentGeneralizedTime)); 870 871 872 // Define the subcommand to clear the account expiration time for a user. 873 createSubCommand(CLEAR_ACCOUNT_EXPIRATION_TIME, 874 INFO_MANAGE_ACCT_SC_CLEAR_ACCT_EXP_TIME_EXAMPLE.get( 875 EXAMPLE_TARGET_USER_DN)); 876 877 878 // Define the subcommand to retrieve the length of time until a user's 879 // account is expired. 880 createSubCommand(GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION, 881 INFO_MANAGE_ACCT_SC_GET_SECONDS_UNTIL_ACCT_EXP_EXAMPLE.get( 882 EXAMPLE_TARGET_USER_DN)); 883 884 885 // Define the subcommand to determine whether a user's account is expired. 886 createSubCommand(GET_ACCOUNT_IS_EXPIRED, 887 INFO_MANAGE_ACCT_SC_GET_ACCT_IS_EXPIRED_EXAMPLE.get( 888 EXAMPLE_TARGET_USER_DN)); 889 890 891 // Define the subcommand to retrieve a user's password expiration warned 892 // time. 893 createSubCommand(GET_PASSWORD_EXPIRATION_WARNED_TIME, 894 INFO_MANAGE_ACCT_SC_GET_PW_EXP_WARNED_TIME_EXAMPLE.get( 895 EXAMPLE_TARGET_USER_DN)); 896 897 898 // Define the subcommand to set a user's password expiration warned time. 899 final ArgumentParser setPWExpWarnedTimeParser = 900 createSubCommandParser(SET_PASSWORD_EXPIRATION_WARNED_TIME); 901 902 final TimestampArgument setPWExpWarnedTimeValueArg = 903 new TimestampArgument('O', "passwordExpirationWarnedTime", false, 1, 904 null, INFO_MANAGE_ACCT_SC_SET_PW_EXP_WARNED_TIME_ARG_VALUE.get()); 905 setPWExpWarnedTimeValueArg.addLongIdentifier("operationValue"); 906 setPWExpWarnedTimeValueArg.addLongIdentifier( 907 "password-expiration-warned-time"); 908 setPWExpWarnedTimeValueArg.addLongIdentifier("operation-value"); 909 setPWExpWarnedTimeParser.addArgument(setPWExpWarnedTimeValueArg); 910 911 createSubCommand(SET_PASSWORD_EXPIRATION_WARNED_TIME, 912 setPWExpWarnedTimeParser, 913 createSubCommandExample(SET_PASSWORD_EXPIRATION_WARNED_TIME, 914 INFO_MANAGE_ACCT_SC_SET_PW_EXP_WARNED_TIME_EXAMPLE.get( 915 EXAMPLE_TARGET_USER_DN, currentGeneralizedTime), 916 "--passwordExpirationWarnedTime", currentGeneralizedTime)); 917 918 919 // Define the subcommand to clear a user's password expiration warned time. 920 createSubCommand(CLEAR_PASSWORD_EXPIRATION_WARNED_TIME, 921 INFO_MANAGE_ACCT_SC_CLEAR_PW_EXP_WARNED_TIME_EXAMPLE.get( 922 EXAMPLE_TARGET_USER_DN)); 923 924 925 // Define the subcommand to get the number of seconds until a user is 926 // eligible to receive a password expiration warning. 927 createSubCommand(GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING, 928 INFO_MANAGE_ACCT_SC_GET_SECONDS_UNTIL_PW_EXP_WARNING_EXAMPLE.get( 929 EXAMPLE_TARGET_USER_DN)); 930 931 932 // Define the subcommand to retrieve a user's password expiration time. 933 createSubCommand(GET_PASSWORD_EXPIRATION_TIME, 934 INFO_MANAGE_ACCT_SC_GET_PW_EXP_TIME_EXAMPLE.get( 935 EXAMPLE_TARGET_USER_DN)); 936 937 938 // Define the subcommand to get the number of seconds until a user's 939 // password expires. 940 createSubCommand(GET_SECONDS_UNTIL_PASSWORD_EXPIRATION, 941 INFO_MANAGE_ACCT_SC_GET_SECONDS_UNTIL_PW_EXP_EXAMPLE.get( 942 EXAMPLE_TARGET_USER_DN)); 943 944 945 // Define the subcommand to determine whether a user's password is expired. 946 createSubCommand(GET_PASSWORD_IS_EXPIRED, 947 INFO_MANAGE_ACCT_SC_GET_PW_IS_EXPIRED_EXAMPLE.get( 948 EXAMPLE_TARGET_USER_DN)); 949 950 951 // Define the subcommand to determine whether an account is failure locked. 952 createSubCommand(GET_ACCOUNT_IS_FAILURE_LOCKED, 953 INFO_MANAGE_ACCT_SC_GET_ACCT_FAILURE_LOCKED_EXAMPLE.get( 954 EXAMPLE_TARGET_USER_DN)); 955 956 957 // Define the subcommand to specify whether an account is failure locked. 958 final ArgumentParser setIsFailureLockedParser = 959 createSubCommandParser(SET_ACCOUNT_IS_FAILURE_LOCKED); 960 961 final BooleanValueArgument setIsFailureLockedValueArg = 962 new BooleanValueArgument('O', "accountIsFailureLocked", true, null, 963 INFO_MANAGE_ACCT_SC_SET_ACCT_FAILURE_LOCKED_ARG_VALUE.get()); 964 setIsFailureLockedValueArg.addLongIdentifier("operationValue"); 965 setIsFailureLockedValueArg.addLongIdentifier("account-is-failure-locked"); 966 setIsFailureLockedValueArg.addLongIdentifier("operation-value"); 967 setIsFailureLockedParser.addArgument(setIsFailureLockedValueArg); 968 969 createSubCommand(SET_ACCOUNT_IS_FAILURE_LOCKED, setIsFailureLockedParser, 970 createSubCommandExample(SET_ACCOUNT_IS_FAILURE_LOCKED, 971 INFO_MANAGE_ACCT_SC_SET_ACCT_FAILURE_LOCKED_EXAMPLE.get( 972 EXAMPLE_TARGET_USER_DN), 973 "--accountIsFailureLocked", "true")); 974 975 976 // Define the subcommand to get the time an account was failure locked. 977 createSubCommand(GET_FAILURE_LOCKOUT_TIME, 978 INFO_MANAGE_ACCT_SC_GET_FAILURE_LOCKED_TIME_EXAMPLE.get( 979 EXAMPLE_TARGET_USER_DN)); 980 981 982 // Define the subcommand to get the length of time until a failure-locked 983 // account will be automatically unlocked. 984 createSubCommand(GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK, 985 INFO_MANAGE_ACCT_SC_GET_SECONDS_UNTIL_FAILURE_UNLOCK_EXAMPLE.get( 986 EXAMPLE_TARGET_USER_DN)); 987 988 989 // Define the subcommand to determine the authentication failure times. 990 createSubCommand(GET_AUTHENTICATION_FAILURE_TIMES, 991 INFO_MANAGE_ACCT_SC_GET_AUTH_FAILURE_TIMES_EXAMPLE.get( 992 EXAMPLE_TARGET_USER_DN)); 993 994 995 // Define the subcommand to add values to the set of authentication failure 996 // times. 997 final ArgumentParser addAuthFailureTimeParser = 998 createSubCommandParser(ADD_AUTHENTICATION_FAILURE_TIME); 999 1000 final TimestampArgument addAuthFailureTimeValueArg = 1001 new TimestampArgument('O', "authenticationFailureTime", false, 0, null, 1002 INFO_MANAGE_ACCT_SC_ADD_AUTH_FAILURE_TIME_ARG_VALUE.get()); 1003 addAuthFailureTimeValueArg.addLongIdentifier("operationValue"); 1004 addAuthFailureTimeValueArg.addLongIdentifier( 1005 "authentication-failure-time"); 1006 addAuthFailureTimeValueArg.addLongIdentifier("operation-value"); 1007 addAuthFailureTimeParser.addArgument(addAuthFailureTimeValueArg); 1008 1009 createSubCommand(ADD_AUTHENTICATION_FAILURE_TIME, addAuthFailureTimeParser, 1010 createSubCommandExample(ADD_AUTHENTICATION_FAILURE_TIME, 1011 INFO_MANAGE_ACCT_SC_ADD_AUTH_FAILURE_TIME_EXAMPLE.get( 1012 EXAMPLE_TARGET_USER_DN))); 1013 1014 1015 // Define the subcommand to replace the authentication failure times. 1016 final ArgumentParser setAuthFailureTimesParser = 1017 createSubCommandParser(SET_AUTHENTICATION_FAILURE_TIMES); 1018 1019 final TimestampArgument setAuthFailureTimesValueArg = 1020 new TimestampArgument('O', "authenticationFailureTime", false, 0, null, 1021 INFO_MANAGE_ACCT_SC_SET_AUTH_FAILURE_TIMES_ARG_VALUE.get()); 1022 setAuthFailureTimesValueArg.addLongIdentifier("operationValue"); 1023 setAuthFailureTimesValueArg.addLongIdentifier( 1024 "authentication-failure-time"); 1025 setAuthFailureTimesValueArg.addLongIdentifier("operation-value"); 1026 setAuthFailureTimesParser.addArgument(setAuthFailureTimesValueArg); 1027 1028 createSubCommand(SET_AUTHENTICATION_FAILURE_TIMES, 1029 setAuthFailureTimesParser, 1030 createSubCommandExample(SET_AUTHENTICATION_FAILURE_TIMES, 1031 INFO_MANAGE_ACCT_SC_SET_AUTH_FAILURE_TIMES_EXAMPLE.get( 1032 EXAMPLE_TARGET_USER_DN, olderGeneralizedTime, 1033 currentGeneralizedTime), 1034 "--authenticationFailureTime", olderGeneralizedTime, 1035 "--authenticationFailureTime", currentGeneralizedTime)); 1036 1037 1038 // Define the subcommand to clear the authentication failure times. 1039 createSubCommand(CLEAR_AUTHENTICATION_FAILURE_TIMES, 1040 INFO_MANAGE_ACCT_SC_CLEAR_AUTH_FAILURE_TIMES_EXAMPLE.get( 1041 EXAMPLE_TARGET_USER_DN)); 1042 1043 1044 // Define the subcommand to get the remaining authentication failure count. 1045 createSubCommand(GET_REMAINING_AUTHENTICATION_FAILURE_COUNT, 1046 INFO_MANAGE_ACCT_SC_GET_REMAINING_FAILURE_COUNT_EXAMPLE.get( 1047 EXAMPLE_TARGET_USER_DN)); 1048 1049 1050 // Define the subcommand to determine whether the account is idle locked. 1051 createSubCommand(GET_ACCOUNT_IS_IDLE_LOCKED, 1052 INFO_MANAGE_ACCT_SC_GET_ACCT_IDLE_LOCKED_EXAMPLE.get( 1053 EXAMPLE_TARGET_USER_DN)); 1054 1055 1056 // Define the subcommand to get the length of time until the account is 1057 // idle locked. 1058 createSubCommand(GET_SECONDS_UNTIL_IDLE_LOCKOUT, 1059 INFO_MANAGE_ACCT_SC_GET_SECONDS_UNTIL_IDLE_LOCKOUT_EXAMPLE.get( 1060 EXAMPLE_TARGET_USER_DN)); 1061 1062 1063 // Define the subcommand to get the idle lockout time for an account. 1064 createSubCommand(GET_IDLE_LOCKOUT_TIME, 1065 INFO_MANAGE_ACCT_SC_GET_IDLE_LOCKOUT_TIME_EXAMPLE.get( 1066 EXAMPLE_TARGET_USER_DN)); 1067 1068 1069 // Define the subcommand to determine whether a user's password has been 1070 // reset. 1071 createSubCommand(GET_MUST_CHANGE_PASSWORD, 1072 INFO_MANAGE_ACCT_SC_GET_MUST_CHANGE_PW_EXAMPLE.get( 1073 EXAMPLE_TARGET_USER_DN)); 1074 1075 1076 // Define the subcommand to specify whether a user's password has been 1077 // reset. 1078 final ArgumentParser setPWIsResetParser = 1079 createSubCommandParser(SET_MUST_CHANGE_PASSWORD); 1080 1081 final BooleanValueArgument setPWIsResetValueArg = 1082 new BooleanValueArgument('O', "mustChangePassword", true, null, 1083 INFO_MANAGE_ACCT_SC_SET_MUST_CHANGE_PW_ARG_VALUE.get()); 1084 setPWIsResetValueArg.addLongIdentifier("passwordIsReset"); 1085 setPWIsResetValueArg.addLongIdentifier("operationValue"); 1086 setPWIsResetValueArg.addLongIdentifier("must-change-password"); 1087 setPWIsResetValueArg.addLongIdentifier("password-is-reset"); 1088 setPWIsResetValueArg.addLongIdentifier("operation-value"); 1089 setPWIsResetParser.addArgument(setPWIsResetValueArg); 1090 1091 createSubCommand(SET_MUST_CHANGE_PASSWORD, setPWIsResetParser, 1092 createSubCommandExample(SET_MUST_CHANGE_PASSWORD, 1093 INFO_MANAGE_ACCT_SC_SET_MUST_CHANGE_PW_EXAMPLE.get( 1094 EXAMPLE_TARGET_USER_DN), 1095 "--mustChangePassword", "true")); 1096 1097 1098 // Define the subcommand to clear the password reset state information. 1099 createSubCommand(CLEAR_MUST_CHANGE_PASSWORD, 1100 INFO_MANAGE_ACCT_SC_CLEAR_MUST_CHANGE_PW_EXAMPLE.get( 1101 EXAMPLE_TARGET_USER_DN)); 1102 1103 1104 // Define the subcommand to determine whether the account is reset locked. 1105 createSubCommand(GET_ACCOUNT_IS_PASSWORD_RESET_LOCKED, 1106 INFO_MANAGE_ACCT_SC_GET_ACCT_IS_RESET_LOCKED_EXAMPLE.get( 1107 EXAMPLE_TARGET_USER_DN)); 1108 1109 1110 // Define the subcommand to get the length of time until the password is 1111 // reset locked. 1112 createSubCommand(GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT, 1113 INFO_MANAGE_ACCT_SC_GET_SECONDS_UNTIL_RESET_LOCKOUT_EXAMPLE.get( 1114 EXAMPLE_TARGET_USER_DN)); 1115 1116 1117 // Define the subcommand to get the password reset lockout time. 1118 createSubCommand(GET_PASSWORD_RESET_LOCKOUT_TIME, 1119 INFO_MANAGE_ACCT_SC_GET_RESET_LOCKOUT_TIME_EXAMPLE.get( 1120 EXAMPLE_TARGET_USER_DN)); 1121 1122 1123 // Define the subcommand to get the last login time. 1124 createSubCommand(GET_LAST_LOGIN_TIME, 1125 INFO_MANAGE_ACCT_SC_GET_LAST_LOGIN_TIME_EXAMPLE.get( 1126 EXAMPLE_TARGET_USER_DN)); 1127 1128 1129 // Define the subcommand to set the last login time. 1130 final ArgumentParser setLastLoginTimeParser = 1131 createSubCommandParser(SET_LAST_LOGIN_TIME); 1132 1133 final TimestampArgument setLastLoginTimeValueArg = new TimestampArgument( 1134 'O', "lastLoginTime", false, 1, null, 1135 INFO_MANAGE_ACCT_SC_SET_LAST_LOGIN_TIME_ARG_VALUE.get()); 1136 setLastLoginTimeValueArg.addLongIdentifier("operationValue"); 1137 setLastLoginTimeValueArg.addLongIdentifier("last-login-time"); 1138 setLastLoginTimeValueArg.addLongIdentifier("operation-value"); 1139 setLastLoginTimeParser.addArgument(setLastLoginTimeValueArg); 1140 1141 createSubCommand(SET_LAST_LOGIN_TIME, setLastLoginTimeParser, 1142 createSubCommandExample(SET_LAST_LOGIN_TIME, 1143 INFO_MANAGE_ACCT_SC_SET_LAST_LOGIN_TIME_EXAMPLE.get( 1144 EXAMPLE_TARGET_USER_DN, currentGeneralizedTime), 1145 "--lastLoginTime", currentGeneralizedTime)); 1146 1147 1148 // Define the subcommand to clear the last login time. 1149 createSubCommand(CLEAR_LAST_LOGIN_TIME, 1150 INFO_MANAGE_ACCT_SC_CLEAR_LAST_LOGIN_TIME_EXAMPLE.get( 1151 EXAMPLE_TARGET_USER_DN)); 1152 1153 1154 // Define the subcommand to get the last login IP address. 1155 createSubCommand(GET_LAST_LOGIN_IP_ADDRESS, 1156 INFO_MANAGE_ACCT_SC_GET_LAST_LOGIN_IP_EXAMPLE.get( 1157 EXAMPLE_TARGET_USER_DN)); 1158 1159 1160 // Define the subcommand to set the last login IP address. 1161 final ArgumentParser setLastLoginIPParser = 1162 createSubCommandParser(SET_LAST_LOGIN_IP_ADDRESS); 1163 1164 final StringArgument setLastLoginIPValueArg = new StringArgument('O', 1165 "lastLoginIPAddress", true, 1, null, 1166 INFO_MANAGE_ACCT_SC_SET_LAST_LOGIN_IP_ARG_VALUE.get()); 1167 setLastLoginIPValueArg.addLongIdentifier("operationValue"); 1168 setLastLoginIPValueArg.addLongIdentifier("last-login-ip-address"); 1169 setLastLoginIPValueArg.addLongIdentifier("operation-value"); 1170 setLastLoginIPValueArg.addValueValidator( 1171 new IPAddressArgumentValueValidator()); 1172 setLastLoginIPParser.addArgument(setLastLoginIPValueArg); 1173 1174 1175 createSubCommand(SET_LAST_LOGIN_IP_ADDRESS, setLastLoginIPParser, 1176 createSubCommandExample(SET_LAST_LOGIN_IP_ADDRESS, 1177 INFO_MANAGE_ACCT_SC_SET_LAST_LOGIN_IP_EXAMPLE.get( 1178 EXAMPLE_TARGET_USER_DN, "1.2.3.4"), 1179 "--lastLoginIPAddress", "1.2.3.4")); 1180 1181 1182 // Define the subcommand to clear the last login IP address. 1183 createSubCommand(CLEAR_LAST_LOGIN_IP_ADDRESS, 1184 INFO_MANAGE_ACCT_SC_CLEAR_LAST_LOGIN_IP_EXAMPLE.get( 1185 EXAMPLE_TARGET_USER_DN)); 1186 1187 1188 // Define the subcommand to get the grace login use times. 1189 createSubCommand(GET_GRACE_LOGIN_USE_TIMES, 1190 INFO_MANAGE_ACCT_SC_GET_GRACE_LOGIN_TIMES_EXAMPLE.get( 1191 EXAMPLE_TARGET_USER_DN)); 1192 1193 1194 // Define the subcommand to add values to the set of grace login use times. 1195 final ArgumentParser addGraceLoginTimeParser = 1196 createSubCommandParser(ADD_GRACE_LOGIN_USE_TIME); 1197 1198 final TimestampArgument addGraceLoginTimeValueArg = 1199 new TimestampArgument('O', "graceLoginUseTime", false, 0, null, 1200 INFO_MANAGE_ACCT_SC_ADD_GRACE_LOGIN_TIME_ARG_VALUE.get()); 1201 addGraceLoginTimeValueArg.addLongIdentifier("operationValue"); 1202 addGraceLoginTimeValueArg.addLongIdentifier("grace-login-use-time"); 1203 addGraceLoginTimeValueArg.addLongIdentifier("operation-value"); 1204 addGraceLoginTimeParser.addArgument(addGraceLoginTimeValueArg); 1205 1206 createSubCommand(ADD_GRACE_LOGIN_USE_TIME, addGraceLoginTimeParser, 1207 createSubCommandExample(ADD_GRACE_LOGIN_USE_TIME, 1208 INFO_MANAGE_ACCT_SC_ADD_GRACE_LOGIN_TIME_EXAMPLE.get( 1209 EXAMPLE_TARGET_USER_DN))); 1210 1211 1212 // Define the subcommand to replace the set of grace login use times. 1213 final ArgumentParser setGraceLoginTimesParser = 1214 createSubCommandParser(SET_GRACE_LOGIN_USE_TIMES); 1215 1216 final TimestampArgument setGraceLoginTimesValueArg = 1217 new TimestampArgument('O', "graceLoginUseTime", false, 0, null, 1218 INFO_MANAGE_ACCT_SC_SET_GRACE_LOGIN_TIMES_ARG_VALUE.get()); 1219 setGraceLoginTimesValueArg.addLongIdentifier("operationValue"); 1220 setGraceLoginTimesValueArg.addLongIdentifier("grace-login-use-time"); 1221 setGraceLoginTimesValueArg.addLongIdentifier("operation-value"); 1222 setGraceLoginTimesParser.addArgument(setGraceLoginTimesValueArg); 1223 1224 createSubCommand(SET_GRACE_LOGIN_USE_TIMES, setGraceLoginTimesParser, 1225 createSubCommandExample(SET_GRACE_LOGIN_USE_TIMES, 1226 INFO_MANAGE_ACCT_SC_SET_GRACE_LOGIN_TIMES_EXAMPLE.get( 1227 EXAMPLE_TARGET_USER_DN, olderGeneralizedTime, 1228 currentGeneralizedTime), 1229 "--graceLoginUseTime", olderGeneralizedTime, 1230 "--graceLoginUseTime", currentGeneralizedTime)); 1231 1232 1233 // Define the subcommand to clear the grace login use times. 1234 createSubCommand(CLEAR_GRACE_LOGIN_USE_TIMES, 1235 INFO_MANAGE_ACCT_SC_CLEAR_GRACE_LOGIN_TIMES_EXAMPLE.get( 1236 EXAMPLE_TARGET_USER_DN)); 1237 1238 1239 // Define the subcommand to get the remaining grace login count. 1240 createSubCommand(GET_REMAINING_GRACE_LOGIN_COUNT, 1241 INFO_MANAGE_ACCT_SC_GET_REMAINING_GRACE_LOGIN_COUNT_EXAMPLE.get( 1242 EXAMPLE_TARGET_USER_DN)); 1243 1244 1245 // Define the subcommand to get the password changed by required time value. 1246 createSubCommand(GET_PASSWORD_CHANGED_BY_REQUIRED_TIME, 1247 INFO_MANAGE_ACCT_SC_GET_PW_CHANGED_BY_REQ_TIME_EXAMPLE.get( 1248 EXAMPLE_TARGET_USER_DN)); 1249 1250 1251 // Define the subcommand to set the password changed by required time value. 1252 final ArgumentParser setPWChangedByReqTimeParser = 1253 createSubCommandParser(SET_PASSWORD_CHANGED_BY_REQUIRED_TIME); 1254 1255 final TimestampArgument setPWChangedByReqTimeValueArg = 1256 new TimestampArgument('O', "passwordChangedByRequiredTime", false, 1, 1257 null, 1258 INFO_MANAGE_ACCT_SC_SET_PW_CHANGED_BY_REQ_TIME_ARG_VALUE.get()); 1259 setPWChangedByReqTimeValueArg.addLongIdentifier("operationValue"); 1260 setPWChangedByReqTimeValueArg.addLongIdentifier( 1261 "password-changed-by-required-time"); 1262 setPWChangedByReqTimeValueArg.addLongIdentifier("operation-value"); 1263 setPWChangedByReqTimeParser.addArgument( 1264 setPWChangedByReqTimeValueArg); 1265 1266 createSubCommand(SET_PASSWORD_CHANGED_BY_REQUIRED_TIME, 1267 setPWChangedByReqTimeParser, 1268 createSubCommandExample(SET_PASSWORD_CHANGED_BY_REQUIRED_TIME, 1269 INFO_MANAGE_ACCT_SC_SET_PW_CHANGED_BY_REQ_TIME_EXAMPLE.get( 1270 EXAMPLE_TARGET_USER_DN))); 1271 1272 1273 // Define the subcommand to clear the password changed by required time 1274 // value. 1275 createSubCommand(CLEAR_PASSWORD_CHANGED_BY_REQUIRED_TIME, 1276 INFO_MANAGE_ACCT_SC_CLEAR_PW_CHANGED_BY_REQ_TIME_EXAMPLE.get( 1277 EXAMPLE_TARGET_USER_DN)); 1278 1279 1280 // Define the subcommand to get the length of time until the required change 1281 // time. 1282 createSubCommand(GET_SECONDS_UNTIL_REQUIRED_PASSWORD_CHANGE_TIME, 1283 INFO_MANAGE_ACCT_SC_GET_SECS_UNTIL_REQ_CHANGE_TIME_EXAMPLE.get( 1284 EXAMPLE_TARGET_USER_DN)); 1285 1286 1287 // Define the subcommand to get the password history count. 1288 createSubCommand(GET_PASSWORD_HISTORY_COUNT, 1289 INFO_MANAGE_ACCT_SC_GET_PW_HISTORY_COUNT_EXAMPLE.get( 1290 EXAMPLE_TARGET_USER_DN)); 1291 1292 1293 // Define the subcommand to clear a user's password history. 1294 createSubCommand(CLEAR_PASSWORD_HISTORY, 1295 INFO_MANAGE_ACCT_SC_CLEAR_PW_HISTORY_EXAMPLE.get( 1296 EXAMPLE_TARGET_USER_DN)); 1297 1298 1299 // Define the subcommand to determine whether a user has a retired password. 1300 createSubCommand(GET_HAS_RETIRED_PASSWORD, 1301 INFO_MANAGE_ACCT_SC_GET_HAS_RETIRED_PW_EXAMPLE.get( 1302 EXAMPLE_TARGET_USER_DN)); 1303 1304 1305 // Define the subcommand to retrieve the time that a user's former password 1306 // was retired. 1307 createSubCommand(GET_PASSWORD_RETIRED_TIME, 1308 INFO_MANAGE_ACCT_SC_GET_PW_RETIRED_TIME_EXAMPLE.get( 1309 EXAMPLE_TARGET_USER_DN)); 1310 1311 1312 // Define the subcommand to retrieve the retired password expiration time. 1313 createSubCommand(GET_RETIRED_PASSWORD_EXPIRATION_TIME, 1314 INFO_MANAGE_ACCT_SC_GET_RETIRED_PW_EXP_TIME_EXAMPLE.get( 1315 EXAMPLE_TARGET_USER_DN)); 1316 1317 1318 // Define the subcommand to purge a retired password. 1319 createSubCommand(CLEAR_RETIRED_PASSWORD, 1320 INFO_MANAGE_ACCT_SC_PURGE_RETIRED_PW_EXAMPLE.get( 1321 EXAMPLE_TARGET_USER_DN)); 1322 1323 1324 // Define the subcommand to get the available SASL mechanisms for a user. 1325 createSubCommand(GET_AVAILABLE_SASL_MECHANISMS, 1326 INFO_MANAGE_ACCT_SC_GET_AVAILABLE_SASL_MECHS_EXAMPLE.get( 1327 EXAMPLE_TARGET_USER_DN)); 1328 1329 1330 // Define the subcommand to get the available OTP delivery mechanisms for a 1331 // user. 1332 createSubCommand(GET_AVAILABLE_OTP_DELIVERY_MECHANISMS, 1333 INFO_MANAGE_ACCT_SC_GET_AVAILABLE_OTP_MECHS_EXAMPLE.get( 1334 EXAMPLE_TARGET_USER_DN)); 1335 1336 1337 // Define the subcommand to determine whether a user has at least one TOTP 1338 // shared secret. 1339 createSubCommand(GET_HAS_TOTP_SHARED_SECRET, 1340 INFO_MANAGE_ACCT_SC_GET_HAS_TOTP_SHARED_SECRET_EXAMPLE.get( 1341 EXAMPLE_TARGET_USER_DN)); 1342 1343 1344 // Define the subcommand to add a value to the set of TOTP shared secrets 1345 // for a user. 1346 final ArgumentParser addTOTPSharedSecretParser = 1347 createSubCommandParser(ADD_TOTP_SHARED_SECRET); 1348 1349 final StringArgument addTOTPSharedSecretValueArg = 1350 new StringArgument('O', "totpSharedSecret", true, 0, null, 1351 INFO_MANAGE_ACCT_SC_ADD_YUBIKEY_ID_ARG_VALUE.get()); 1352 addTOTPSharedSecretValueArg.addLongIdentifier("operationValue"); 1353 addTOTPSharedSecretValueArg.addLongIdentifier("totp-shared-secret"); 1354 addTOTPSharedSecretValueArg.addLongIdentifier("operation-value"); 1355 addTOTPSharedSecretParser.addArgument( 1356 addTOTPSharedSecretValueArg); 1357 1358 createSubCommand(ADD_TOTP_SHARED_SECRET, addTOTPSharedSecretParser, 1359 createSubCommandExample(ADD_TOTP_SHARED_SECRET, 1360 INFO_MANAGE_ACCT_SC_ADD_TOTP_SHARED_SECRET_EXAMPLE.get( 1361 "abcdefghijklmnop", EXAMPLE_TARGET_USER_DN), 1362 "--totpSharedSecret", "abcdefghijklmnop")); 1363 1364 1365 // Define the subcommand to remove a value from the set of TOTP shared 1366 // secrets for a user. 1367 final ArgumentParser removeTOTPSharedSecretParser = 1368 createSubCommandParser(REMOVE_TOTP_SHARED_SECRET); 1369 1370 final StringArgument removeTOTPSharedSecretValueArg = 1371 new StringArgument('O', "totpSharedSecret", true, 0, null, 1372 INFO_MANAGE_ACCT_SC_REMOVE_YUBIKEY_ID_ARG_VALUE.get()); 1373 removeTOTPSharedSecretValueArg.addLongIdentifier("operationValue"); 1374 removeTOTPSharedSecretValueArg.addLongIdentifier("totp-shared-secret"); 1375 removeTOTPSharedSecretValueArg.addLongIdentifier( 1376 "operation-value"); 1377 removeTOTPSharedSecretParser.addArgument( 1378 removeTOTPSharedSecretValueArg); 1379 1380 createSubCommand(REMOVE_TOTP_SHARED_SECRET, removeTOTPSharedSecretParser, 1381 createSubCommandExample(REMOVE_TOTP_SHARED_SECRET, 1382 INFO_MANAGE_ACCT_SC_REMOVE_TOTP_SHARED_SECRET_EXAMPLE.get( 1383 "abcdefghijklmnop", EXAMPLE_TARGET_USER_DN), 1384 "--totpSharedSecret", "abcdefghijklmnop")); 1385 1386 1387 // Define the subcommand to replace set of TOTP shared secrets for a user. 1388 final ArgumentParser setTOTPSharedSecretsParser = 1389 createSubCommandParser(SET_TOTP_SHARED_SECRETS); 1390 1391 final StringArgument setTOTPSharedSecretsValueArg = 1392 new StringArgument('O', "totpSharedSecret", true, 0, null, 1393 INFO_MANAGE_ACCT_SC_SET_TOTP_SHARED_SECRETS_ARG_VALUE.get()); 1394 setTOTPSharedSecretsValueArg.addLongIdentifier("operationValue"); 1395 setTOTPSharedSecretsValueArg.addLongIdentifier("totp-shared-secret"); 1396 setTOTPSharedSecretsValueArg.addLongIdentifier( 1397 "operation-value"); 1398 setTOTPSharedSecretsParser.addArgument( 1399 setTOTPSharedSecretsValueArg); 1400 1401 createSubCommand(SET_TOTP_SHARED_SECRETS, 1402 setTOTPSharedSecretsParser, 1403 createSubCommandExample(SET_TOTP_SHARED_SECRETS, 1404 INFO_MANAGE_ACCT_SC_SET_TOTP_SHARED_SECRETS_EXAMPLE.get( 1405 EXAMPLE_TARGET_USER_DN, "abcdefghijklmnop"), 1406 "--totpSharedSecret", "abcdefghijklmnop")); 1407 1408 1409 // Define the subcommand to clear the set of TOTP shared secrets for a user. 1410 createSubCommand(CLEAR_TOTP_SHARED_SECRETS, 1411 INFO_MANAGE_ACCT_SC_CLEAR_TOTP_SHARED_SECRETS_EXAMPLE.get( 1412 EXAMPLE_TARGET_USER_DN)); 1413 1414 1415 // Define the subcommand to determine whether a user has at least one 1416 // registered YubiKey OTP device public ID. 1417 createSubCommand(GET_HAS_REGISTERED_YUBIKEY_PUBLIC_ID, 1418 INFO_MANAGE_ACCT_SC_GET_HAS_YUBIKEY_ID_EXAMPLE.get( 1419 EXAMPLE_TARGET_USER_DN)); 1420 1421 1422 // Define the subcommand to get the set of registered YubiKey OTP device 1423 // public IDs for a user. 1424 createSubCommand(GET_REGISTERED_YUBIKEY_PUBLIC_IDS, 1425 INFO_MANAGE_ACCT_SC_GET_YUBIKEY_IDS_EXAMPLE.get( 1426 EXAMPLE_TARGET_USER_DN)); 1427 1428 1429 // Define the subcommand to add a value to the set of registered YubiKey OTP 1430 // device public IDs for a user. 1431 final ArgumentParser addRegisteredYubiKeyPublicIDParser = 1432 createSubCommandParser(ADD_REGISTERED_YUBIKEY_PUBLIC_ID); 1433 1434 final StringArgument addRegisteredYubiKeyPublicIDValueArg = 1435 new StringArgument('O', "publicID", true, 0, null, 1436 INFO_MANAGE_ACCT_SC_ADD_YUBIKEY_ID_ARG_VALUE.get()); 1437 addRegisteredYubiKeyPublicIDValueArg.addLongIdentifier("operationValue"); 1438 addRegisteredYubiKeyPublicIDValueArg.addLongIdentifier("public-id"); 1439 addRegisteredYubiKeyPublicIDValueArg.addLongIdentifier("operation-value"); 1440 addRegisteredYubiKeyPublicIDParser.addArgument( 1441 addRegisteredYubiKeyPublicIDValueArg); 1442 1443 createSubCommand(ADD_REGISTERED_YUBIKEY_PUBLIC_ID, 1444 addRegisteredYubiKeyPublicIDParser, 1445 createSubCommandExample(ADD_REGISTERED_YUBIKEY_PUBLIC_ID, 1446 INFO_MANAGE_ACCT_SC_ADD_YUBIKEY_ID_EXAMPLE.get( 1447 "abcdefghijkl", EXAMPLE_TARGET_USER_DN), 1448 "--publicID", "abcdefghijkl")); 1449 1450 1451 // Define the subcommand to remove a value from the set of registered 1452 // YubiKey OTP device public IDs for a user. 1453 final ArgumentParser removeRegisteredYubiKeyPublicIDParser = 1454 createSubCommandParser(REMOVE_REGISTERED_YUBIKEY_PUBLIC_ID); 1455 1456 final StringArgument removeRegisteredYubiKeyPublicIDValueArg = 1457 new StringArgument('O', "publicID", true, 0, null, 1458 INFO_MANAGE_ACCT_SC_REMOVE_YUBIKEY_ID_ARG_VALUE.get()); 1459 removeRegisteredYubiKeyPublicIDValueArg.addLongIdentifier("operationValue"); 1460 removeRegisteredYubiKeyPublicIDValueArg.addLongIdentifier("public-id"); 1461 removeRegisteredYubiKeyPublicIDValueArg.addLongIdentifier( 1462 "operation-value"); 1463 removeRegisteredYubiKeyPublicIDParser.addArgument( 1464 removeRegisteredYubiKeyPublicIDValueArg); 1465 1466 createSubCommand(REMOVE_REGISTERED_YUBIKEY_PUBLIC_ID, 1467 removeRegisteredYubiKeyPublicIDParser, 1468 createSubCommandExample(REMOVE_REGISTERED_YUBIKEY_PUBLIC_ID, 1469 INFO_MANAGE_ACCT_SC_REMOVE_YUBIKEY_ID_EXAMPLE.get( 1470 "abcdefghijkl", EXAMPLE_TARGET_USER_DN), 1471 "--publicID", "abcdefghijkl")); 1472 1473 1474 // Define the subcommand to replace set of registered YubiKey OTP device 1475 // public IDs for a user. 1476 final ArgumentParser setRegisteredYubiKeyPublicIDParser = 1477 createSubCommandParser(SET_REGISTERED_YUBIKEY_PUBLIC_IDS); 1478 1479 final StringArgument setRegisteredYubiKeyPublicIDValueArg = 1480 new StringArgument('O', "publicID", true, 0, null, 1481 INFO_MANAGE_ACCT_SC_SET_YUBIKEY_IDS_ARG_VALUE.get()); 1482 setRegisteredYubiKeyPublicIDValueArg.addLongIdentifier("operationValue"); 1483 setRegisteredYubiKeyPublicIDValueArg.addLongIdentifier("public-id"); 1484 setRegisteredYubiKeyPublicIDValueArg.addLongIdentifier( 1485 "operation-value"); 1486 setRegisteredYubiKeyPublicIDParser.addArgument( 1487 setRegisteredYubiKeyPublicIDValueArg); 1488 1489 createSubCommand(SET_REGISTERED_YUBIKEY_PUBLIC_IDS, 1490 setRegisteredYubiKeyPublicIDParser, 1491 createSubCommandExample(SET_REGISTERED_YUBIKEY_PUBLIC_IDS, 1492 INFO_MANAGE_ACCT_SC_SET_YUBIKEY_IDS_EXAMPLE.get( 1493 EXAMPLE_TARGET_USER_DN, "abcdefghijkl"), 1494 "--publicID", "abcdefghijkl")); 1495 1496 1497 // Define the subcommand to clear the set of registered YubiKey OTP device 1498 // public IDs for a user. 1499 createSubCommand(CLEAR_REGISTERED_YUBIKEY_PUBLIC_IDS, 1500 INFO_MANAGE_ACCT_SC_CLEAR_YUBIKEY_IDS_EXAMPLE.get( 1501 EXAMPLE_TARGET_USER_DN)); 1502 } 1503 1504 1505 1506 /** 1507 * Creates an argument parser for the provided subcommand type. It will not 1508 * have any arguments associated with it. 1509 * 1510 * @param type The subcommand type for which to create the argument parser. 1511 * 1512 * @return The created argument parser. 1513 * 1514 * @throws ArgumentException If a problem is encountered while creating the 1515 * argument parser. 1516 */ 1517 private static ArgumentParser createSubCommandParser( 1518 final ManageAccountSubCommandType type) 1519 throws ArgumentException 1520 { 1521 return new ArgumentParser(type.getPrimaryName(), type.getDescription()); 1522 } 1523 1524 1525 1526 /** 1527 * Generates an example usage map for a specified subcommand. 1528 * 1529 * @param t The subcommand type. 1530 * @param description The description to use for the example. 1531 * @param args The set of arguments to include in the example, 1532 * excluding the subcommand name and the arguments used 1533 * to connect and authenticate to the server. This may 1534 * be empty if no additional arguments are needed. 1535 * 1536 * @return The generated example usage map. 1537 */ 1538 private static LinkedHashMap<String[],String> createSubCommandExample( 1539 final ManageAccountSubCommandType t, 1540 final String description, final String... args) 1541 { 1542 final LinkedHashMap<String[], String> examples = 1543 new LinkedHashMap<String[], String>(1); 1544 createSubCommandExample(examples, t, description, args); 1545 return examples; 1546 } 1547 1548 1549 1550 /** 1551 * Adds an example for a specified subcommand to the given map. 1552 * 1553 * @param examples The map to which the example should be added. 1554 * @param t The subcommand type. 1555 * @param description The description to use for the example. 1556 * @param args The set of arguments to include in the example, 1557 * excluding the subcommand name and the arguments used 1558 * to connect and authenticate to the server. This may 1559 * be empty if no additional arguments are needed. 1560 */ 1561 private static void createSubCommandExample( 1562 final LinkedHashMap<String[], String> examples, 1563 final ManageAccountSubCommandType t, final String description, 1564 final String... args) 1565 { 1566 final ArrayList<String> argList = new ArrayList<String>(10 + args.length); 1567 argList.add(t.getPrimaryName()); 1568 argList.add("--hostname"); 1569 argList.add("server.example.com"); 1570 argList.add("--port"); 1571 argList.add("389"); 1572 argList.add("--bindDN"); 1573 argList.add("uid=admin,dc=example,dc=com"); 1574 argList.add("--promptForBindPassword"); 1575 argList.add("--targetDN"); 1576 argList.add("uid=jdoe,ou=People,dc=example,dc=com"); 1577 1578 if (args.length > 0) 1579 { 1580 argList.addAll(Arrays.asList(args)); 1581 } 1582 1583 final String[] argArray = new String[argList.size()]; 1584 argList.toArray(argArray); 1585 1586 examples.put(argArray, description); 1587 } 1588 1589 1590 1591 /** 1592 * Creates a subcommand with the provided information. 1593 * 1594 * @param subcommandType The subcommand type. 1595 * @param exampleDescription The description to use for the 1596 * automatically-generated example. 1597 * 1598 * @throws ArgumentException If a problem is encountered while creating the 1599 * subcommand. 1600 */ 1601 private void createSubCommand( 1602 final ManageAccountSubCommandType subcommandType, 1603 final String exampleDescription) 1604 throws ArgumentException 1605 { 1606 final ArgumentParser subcommandParser = 1607 createSubCommandParser(subcommandType); 1608 1609 final LinkedHashMap<String[],String> examples = 1610 createSubCommandExample(subcommandType, exampleDescription); 1611 1612 createSubCommand(subcommandType, subcommandParser, examples); 1613 } 1614 1615 1616 1617 /** 1618 * Creates a subcommand with the provided information. 1619 * 1620 * @param subcommandType The subcommand type. 1621 * @param subcommandParser The argument parser for the subcommand-specific 1622 * arguments. 1623 * @param examples The example usages for the subcommand. 1624 * 1625 * @throws ArgumentException If a problem is encountered while creating the 1626 * subcommand. 1627 */ 1628 private void createSubCommand( 1629 final ManageAccountSubCommandType subcommandType, 1630 final ArgumentParser subcommandParser, 1631 final LinkedHashMap<String[],String> examples) 1632 throws ArgumentException 1633 { 1634 final SubCommand subCommand = new SubCommand( 1635 subcommandType.getPrimaryName(), subcommandType.getDescription(), 1636 subcommandParser, examples); 1637 1638 for (final String alternateName : subcommandType.getAlternateNames()) 1639 { 1640 subCommand.addName(alternateName); 1641 } 1642 1643 parser.addSubCommand(subCommand); 1644 } 1645 1646 1647 1648 /** 1649 * {@inheritDoc} 1650 */ 1651 @Override() 1652 public LDAPConnectionOptions getConnectionOptions() 1653 { 1654 return connectionOptions; 1655 } 1656 1657 1658 1659 /** 1660 * {@inheritDoc} 1661 */ 1662 @Override() 1663 public ResultCode doToolProcessing() 1664 { 1665 // If we should just generate a sample rate data file, then do that now. 1666 final FileArgument generateSampleRateFile = 1667 parser.getFileArgument(ARG_GENERATE_SAMPLE_RATE_FILE); 1668 if (generateSampleRateFile.isPresent()) 1669 { 1670 try 1671 { 1672 RateAdjustor.writeSampleVariableRateFile( 1673 generateSampleRateFile.getValue()); 1674 return ResultCode.SUCCESS; 1675 } 1676 catch (final Exception e) 1677 { 1678 Debug.debugException(e); 1679 wrapErr(0, WRAP_COLUMN, 1680 ERR_MANAGE_ACCT_CANNOT_GENERATE_SAMPLE_RATE_FILE.get( 1681 generateSampleRateFile.getValue().getAbsolutePath(), 1682 StaticUtils.getExceptionMessage(e))); 1683 return ResultCode.LOCAL_ERROR; 1684 } 1685 } 1686 1687 1688 // If we need to create a fixed-rate barrier and/or use a variable rate 1689 // definition, then set that up. 1690 final IntegerArgument ratePerSecond = 1691 parser.getIntegerArgument(ARG_RATE_PER_SECOND); 1692 final FileArgument variableRateData = 1693 parser.getFileArgument(ARG_VARIABLE_RATE_DATA); 1694 if (ratePerSecond.isPresent() || variableRateData.isPresent()) 1695 { 1696 if (ratePerSecond.isPresent()) 1697 { 1698 rateLimiter = new FixedRateBarrier(1000L, ratePerSecond.getValue()); 1699 } 1700 else 1701 { 1702 rateLimiter = new FixedRateBarrier(1000L, Integer.MAX_VALUE); 1703 } 1704 1705 if (variableRateData.isPresent()) 1706 { 1707 try 1708 { 1709 rateAdjustor = RateAdjustor.newInstance(rateLimiter, 1710 ratePerSecond.getValue(), variableRateData.getValue()); 1711 } 1712 catch (final Exception e) 1713 { 1714 Debug.debugException(e); 1715 wrapErr(0, WRAP_COLUMN, 1716 ERR_MANAGE_ACCT_CANNOT_CREATE_RATE_ADJUSTOR.get( 1717 variableRateData.getValue().getAbsolutePath(), 1718 StaticUtils.getExceptionMessage(e))); 1719 return ResultCode.PARAM_ERROR; 1720 } 1721 } 1722 } 1723 1724 1725 // Create the connection pool to use for all processing. 1726 final LDAPConnectionPool pool; 1727 final int numSearchThreads = 1728 parser.getIntegerArgument(ARG_NUM_SEARCH_THREADS).getValue(); 1729 try 1730 { 1731 final int numOperationThreads = 1732 parser.getIntegerArgument(ARG_NUM_THREADS).getValue(); 1733 pool = getConnectionPool(numOperationThreads, 1734 (numOperationThreads + numSearchThreads)); 1735 1736 // Explicitly disable automatic retry, since it probably won't work 1737 // reliably for extended operations anyway. We'll handle retry manually. 1738 pool.setRetryFailedOperationsDueToInvalidConnections(false); 1739 1740 // Set a maximum connection age of 30 minutes. 1741 pool.setMaxConnectionAgeMillis(1800000L); 1742 } 1743 catch (final LDAPException le) 1744 { 1745 Debug.debugException(le); 1746 1747 wrapErr(0, WRAP_COLUMN, 1748 ERR_MANAGE_ACCT_CANNOT_CREATE_CONNECTION_POOL.get(getToolName(), 1749 le.getMessage())); 1750 return le.getResultCode(); 1751 } 1752 1753 1754 try 1755 { 1756 // Create the output writer. This should always succeed. 1757 outputWriter = new LDIFWriter(getOut()); 1758 1759 1760 1761 // Create the reject writer if appropriate. 1762 final FileArgument rejectFile = parser.getFileArgument(ARG_REJECT_FILE); 1763 if (rejectFile.isPresent()) 1764 { 1765 final BooleanArgument appendToRejectFile = 1766 parser.getBooleanArgument(ARG_APPEND_TO_REJECT_FILE); 1767 1768 try 1769 { 1770 rejectWriter = new LDIFWriter(new FileOutputStream( 1771 rejectFile.getValue(), appendToRejectFile.isPresent())); 1772 } 1773 catch (final Exception e) 1774 { 1775 Debug.debugException(e); 1776 wrapErr(0, WRAP_COLUMN, 1777 ERR_MANAGE_ACCT_CANNOT_CREATE_REJECT_WRITER.get( 1778 rejectFile.getValue().getAbsolutePath(), 1779 StaticUtils.getExceptionMessage(e))); 1780 return ResultCode.LOCAL_ERROR; 1781 } 1782 } 1783 1784 1785 // Create the processor that will be used to actually perform the 1786 // manage-account operation processing for each entry. 1787 final ManageAccountProcessor processor; 1788 try 1789 { 1790 processor = new ManageAccountProcessor(this, pool, rateLimiter, 1791 outputWriter, rejectWriter); 1792 } 1793 catch (final LDAPException le) 1794 { 1795 Debug.debugException(le); 1796 wrapErr(0, WRAP_COLUMN, 1797 ERR_MANAGE_ACCT_CANNOT_CREATE_PROCESSOR.get( 1798 StaticUtils.getExceptionMessage(le))); 1799 return le.getResultCode(); 1800 } 1801 1802 1803 // If we should use a rate adjustor, then start it now. 1804 if (rateAdjustor != null) 1805 { 1806 rateAdjustor.start(); 1807 } 1808 1809 1810 // If any targetDN values were provided, then process them now. 1811 final DNArgument targetDN = parser.getDNArgument(ARG_TARGET_DN); 1812 if (targetDN.isPresent()) 1813 { 1814 for (final DN dn : targetDN.getValues()) 1815 { 1816 if (cancelRequested()) 1817 { 1818 return ResultCode.USER_CANCELED; 1819 } 1820 1821 processor.process(dn.toString()); 1822 } 1823 } 1824 1825 1826 // If any DN input files were specified, then process them now. 1827 final FileArgument dnInputFile = 1828 parser.getFileArgument(ARG_DN_INPUT_FILE); 1829 if (dnInputFile.isPresent()) 1830 { 1831 for (final File f : dnInputFile.getValues()) 1832 { 1833 DNFileReader reader = null; 1834 try 1835 { 1836 reader = new DNFileReader(f); 1837 while (true) 1838 { 1839 if (cancelRequested()) 1840 { 1841 return ResultCode.USER_CANCELED; 1842 } 1843 1844 final DN dn; 1845 try 1846 { 1847 dn = reader.readDN(); 1848 } 1849 catch (final LDAPException le) 1850 { 1851 Debug.debugException(le); 1852 processor.handleMessage(le.getMessage(), true); 1853 continue; 1854 } 1855 1856 if (dn == null) 1857 { 1858 break; 1859 } 1860 1861 processor.process(dn.toString()); 1862 } 1863 } 1864 catch (final Exception e) 1865 { 1866 Debug.debugException(e); 1867 processor.handleMessage( 1868 ERR_MANAGE_ACCT_ERROR_READING_DN_FILE.get( 1869 f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), 1870 true); 1871 } 1872 finally 1873 { 1874 if (reader != null) 1875 { 1876 try 1877 { 1878 reader.close(); 1879 } 1880 catch (final Exception e2) 1881 { 1882 Debug.debugException(e2); 1883 } 1884 } 1885 } 1886 } 1887 } 1888 1889 1890 // If any target filters were specified, then process them now. 1891 final FilterArgument targetFilter = 1892 parser.getFilterArgument(ARG_TARGET_FILTER); 1893 if (targetFilter.isPresent()) 1894 { 1895 searchProcessor = 1896 new ManageAccountSearchProcessor(this, processor, pool); 1897 for (final Filter f : targetFilter.getValues()) 1898 { 1899 searchProcessor.processFilter(f); 1900 } 1901 } 1902 1903 1904 // If any filter input files were specified, then process them now. 1905 final FileArgument filterInputFile = 1906 parser.getFileArgument(ARG_FILTER_INPUT_FILE); 1907 if (filterInputFile.isPresent()) 1908 { 1909 if (searchProcessor == null) 1910 { 1911 searchProcessor = 1912 new ManageAccountSearchProcessor(this, processor, pool); 1913 } 1914 1915 for (final File f : filterInputFile.getValues()) 1916 { 1917 FilterFileReader reader = null; 1918 try 1919 { 1920 reader = new FilterFileReader(f); 1921 while (true) 1922 { 1923 if (cancelRequested()) 1924 { 1925 return ResultCode.USER_CANCELED; 1926 } 1927 1928 final Filter filter; 1929 try 1930 { 1931 filter = reader.readFilter(); 1932 } 1933 catch (final LDAPException le) 1934 { 1935 Debug.debugException(le); 1936 processor.handleMessage(le.getMessage(), true); 1937 continue; 1938 } 1939 1940 if (filter == null) 1941 { 1942 break; 1943 } 1944 1945 searchProcessor.processFilter(filter); 1946 } 1947 } 1948 catch (final Exception e) 1949 { 1950 Debug.debugException(e); 1951 processor.handleMessage( 1952 ERR_MANAGE_ACCT_ERROR_READING_FILTER_FILE.get( 1953 f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), 1954 true); 1955 } 1956 finally 1957 { 1958 if (reader != null) 1959 { 1960 try 1961 { 1962 reader.close(); 1963 } 1964 catch (final Exception e2) 1965 { 1966 Debug.debugException(e2); 1967 } 1968 } 1969 } 1970 } 1971 } 1972 1973 1974 // If any target user IDs were specified, then process them now. 1975 final StringArgument targetUserID = 1976 parser.getStringArgument(ARG_TARGET_USER_ID); 1977 if (targetUserID.isPresent()) 1978 { 1979 if (searchProcessor == null) 1980 { 1981 searchProcessor = 1982 new ManageAccountSearchProcessor(this, processor, pool); 1983 } 1984 1985 for (final String userID : targetUserID.getValues()) 1986 { 1987 searchProcessor.processUserID(userID); 1988 } 1989 } 1990 1991 1992 // If any user ID input files were specified, then process them now. 1993 final FileArgument userIDInputFile = 1994 parser.getFileArgument(ARG_USER_ID_INPUT_FILE); 1995 if (userIDInputFile.isPresent()) 1996 { 1997 if (searchProcessor == null) 1998 { 1999 searchProcessor = 2000 new ManageAccountSearchProcessor(this, processor, pool); 2001 } 2002 2003 for (final File f : userIDInputFile.getValues()) 2004 { 2005 BufferedReader reader = null; 2006 try 2007 { 2008 reader = new BufferedReader(new FileReader(f)); 2009 while (true) 2010 { 2011 if (cancelRequested()) 2012 { 2013 return ResultCode.USER_CANCELED; 2014 } 2015 2016 final String line = reader.readLine(); 2017 if (line == null) 2018 { 2019 break; 2020 } 2021 2022 if ((line.length() == 0) || line.startsWith("#")) 2023 { 2024 continue; 2025 } 2026 2027 searchProcessor.processUserID(line.trim()); 2028 } 2029 } 2030 catch (final Exception e) 2031 { 2032 Debug.debugException(e); 2033 processor.handleMessage( 2034 ERR_MANAGE_ACCT_ERROR_READING_USER_ID_FILE.get( 2035 f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), 2036 true); 2037 } 2038 finally 2039 { 2040 if (reader != null) 2041 { 2042 try 2043 { 2044 reader.close(); 2045 } 2046 catch (final Exception e2) 2047 { 2048 Debug.debugException(e2); 2049 } 2050 } 2051 } 2052 } 2053 } 2054 2055 2056 allFiltersProvided.set(true); 2057 if (searchProcessor != null) 2058 { 2059 searchProcessor.waitForCompletion(); 2060 } 2061 2062 allDNsProvided.set(true); 2063 processor.waitForCompletion(); 2064 } 2065 finally 2066 { 2067 pool.close(); 2068 2069 if (rejectWriter != null) 2070 { 2071 try 2072 { 2073 rejectWriter.close(); 2074 } 2075 catch (final Exception e) 2076 { 2077 Debug.debugException(e); 2078 } 2079 } 2080 } 2081 2082 2083 // If we've gotten here, then we can consider the command successful, even 2084 // if some of the operations failed. 2085 return ResultCode.SUCCESS; 2086 } 2087 2088 2089 2090 /** 2091 * Retrieves the argument parser for this tool. 2092 * 2093 * @return The argument parser for this tool. 2094 */ 2095 ArgumentParser getArgumentParser() 2096 { 2097 return parser; 2098 } 2099 2100 2101 2102 /** 2103 * Indicates whether the tool should cancel its processing. 2104 * 2105 * @return {@code true} if the tool should cancel its processing, or 2106 * {@code false} if not. 2107 */ 2108 boolean cancelRequested() 2109 { 2110 return cancelRequested.get(); 2111 } 2112 2113 2114 2115 /** 2116 * Indicates whether the manage-account processor has been provided with all 2117 * of the DNs of all of the entries to process. 2118 * 2119 * @return {@code true} if the manage-account processor has been provided 2120 * with all of the DNs of all of the entries to process, or 2121 * {@code false} if not. 2122 */ 2123 boolean allDNsProvided() 2124 { 2125 return allDNsProvided.get(); 2126 } 2127 2128 2129 2130 /** 2131 * Indicates whether the manage-account search processor has been provided 2132 * with all of the filters to use to identify entries to process. 2133 * 2134 * @return {@code true} if the manage-account search processor has been 2135 * provided with all of the filters to use to identify entries to 2136 * process, or {@code false} if not. 2137 */ 2138 boolean allFiltersProvided() 2139 { 2140 return allFiltersProvided.get(); 2141 } 2142 2143 2144 2145 /** 2146 * {@inheritDoc} 2147 */ 2148 @Override() 2149 protected boolean registerShutdownHook() 2150 { 2151 return true; 2152 } 2153 2154 2155 2156 /** 2157 * {@inheritDoc} 2158 */ 2159 @Override() 2160 protected void doShutdownHookProcessing(final ResultCode resultCode) 2161 { 2162 cancelRequested.set(true); 2163 2164 if (rateLimiter != null) 2165 { 2166 rateLimiter.shutdownRequested(); 2167 } 2168 2169 if (searchProcessor != null) 2170 { 2171 searchProcessor.cancelSearches(); 2172 } 2173 } 2174 2175 2176 2177 /** 2178 * Performs any processing that may be necessary in response to the provided 2179 * unsolicited notification that has been received from the server. 2180 * 2181 * @param connection The connection on which the unsolicited notification 2182 * was received. 2183 * @param notification The unsolicited notification that has been received 2184 * from the server. 2185 */ 2186 public void handleUnsolicitedNotification(final LDAPConnection connection, 2187 final ExtendedResult notification) 2188 { 2189 final String message = NOTE_MANAGE_ACCT_UNSOLICITED_NOTIFICATION.get( 2190 String.valueOf(connection), String.valueOf(notification)); 2191 if (outputWriter == null) 2192 { 2193 err(); 2194 err("* " + message); 2195 err(); 2196 } 2197 else 2198 { 2199 try 2200 { 2201 outputWriter.writeComment(message, true, true); 2202 outputWriter.flush(); 2203 } 2204 catch (final Exception e) 2205 { 2206 // We can't really do anything about this. 2207 Debug.debugException(e); 2208 } 2209 } 2210 } 2211 2212 2213 2214 /** 2215 * {@inheritDoc} 2216 */ 2217 @Override() 2218 public LinkedHashMap<String[],String> getExampleUsages() 2219 { 2220 final LinkedHashMap<String[],String> examples = 2221 new LinkedHashMap<String[],String>(4); 2222 2223 createSubCommandExample(examples, GET_ALL, 2224 INFO_MANAGE_ACCT_SC_GET_ALL_EXAMPLE.get(EXAMPLE_TARGET_USER_DN)); 2225 2226 createSubCommandExample(examples, GET_ACCOUNT_USABILITY_ERRORS, 2227 INFO_MANAGE_ACCT_SC_GET_USABILITY_ERRORS_EXAMPLE.get( 2228 EXAMPLE_TARGET_USER_DN)); 2229 2230 createSubCommandExample(examples, SET_ACCOUNT_IS_DISABLED, 2231 INFO_MANAGE_ACCT_SC_SET_IS_DISABLED_EXAMPLE.get( 2232 EXAMPLE_TARGET_USER_DN), 2233 "--accountIsDisabled", "true"); 2234 2235 createSubCommandExample(examples, CLEAR_AUTHENTICATION_FAILURE_TIMES, 2236 INFO_MANAGE_ACCT_SC_CLEAR_AUTH_FAILURE_TIMES_EXAMPLE.get( 2237 EXAMPLE_TARGET_USER_DN)); 2238 2239 return examples; 2240 } 2241}