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 protected boolean logToolInvocationByDefault() 512 { 513 return true; 514 } 515 516 517 518 /** 519 * {@inheritDoc} 520 */ 521 @Override() 522 public void addNonLDAPArguments(final ArgumentParser parser) 523 throws ArgumentException 524 { 525 // Get a copy of the argument parser for later use. 526 this.parser = parser; 527 528 529 // Get the current time formatted as a generalized time. 530 final String currentGeneralizedTime = 531 StaticUtils.encodeGeneralizedTime(System.currentTimeMillis()); 532 final String olderGeneralizedTime = 533 StaticUtils.encodeGeneralizedTime(System.currentTimeMillis() - 12345L); 534 535 536 // Define the global arguments used to indicate which users to target. 537 final DNArgument targetDN = new DNArgument('b', ARG_TARGET_DN, false, 0, 538 null, INFO_MANAGE_ACCT_ARG_DESC_TARGET_DN.get()); 539 targetDN.addLongIdentifier("userDN"); 540 targetDN.addLongIdentifier("target-dn"); 541 targetDN.addLongIdentifier("user-dn"); 542 targetDN.setArgumentGroupName( 543 INFO_MANAGE_ACCT_ARG_GROUP_TARGET_USER_ARGS.get()); 544 parser.addArgument(targetDN); 545 546 final FileArgument dnInputFile = new FileArgument(null, ARG_DN_INPUT_FILE, 547 false, 0, null, INFO_MANAGE_ACCT_ARG_DESC_DN_FILE.get(), true, 548 true, true, false); 549 dnInputFile.addLongIdentifier("targetDNFile"); 550 dnInputFile.addLongIdentifier("userDNFile"); 551 dnInputFile.addLongIdentifier("dn-input-file"); 552 dnInputFile.addLongIdentifier("target-dn-file"); 553 dnInputFile.addLongIdentifier("user-dn-file"); 554 dnInputFile.setArgumentGroupName( 555 INFO_MANAGE_ACCT_ARG_GROUP_TARGET_USER_ARGS.get()); 556 parser.addArgument(dnInputFile); 557 558 final FilterArgument targetFilter = new FilterArgument(null, 559 ARG_TARGET_FILTER, false, 0, null, 560 INFO_MANAGE_ACCT_ARG_DESC_TARGET_FILTER.get(ARG_BASE_DN)); 561 targetFilter.addLongIdentifier("target-filter"); 562 targetFilter.setArgumentGroupName( 563 INFO_MANAGE_ACCT_ARG_GROUP_TARGET_USER_ARGS.get()); 564 parser.addArgument(targetFilter); 565 566 final FileArgument filterInputFile = new FileArgument(null, 567 ARG_FILTER_INPUT_FILE, false, 0, null, 568 INFO_MANAGE_ACCT_ARG_DESC_FILTER_INPUT_FILE.get(ARG_BASE_DN), 569 true, true, true, false); 570 filterInputFile.addLongIdentifier("targetFilterFile"); 571 filterInputFile.addLongIdentifier("filter-input-file"); 572 filterInputFile.addLongIdentifier("target-filter-file"); 573 filterInputFile.setArgumentGroupName( 574 INFO_MANAGE_ACCT_ARG_GROUP_TARGET_USER_ARGS.get()); 575 parser.addArgument(filterInputFile); 576 577 final StringArgument targetUserID = new StringArgument(null, 578 ARG_TARGET_USER_ID, false, 0, null, 579 INFO_MANAGE_ACCT_ARG_DESC_TARGET_USER_ID.get(ARG_BASE_DN, 580 ARG_USER_ID_ATTRIBUTE)); 581 targetUserID.addLongIdentifier("userID"); 582 targetUserID.addLongIdentifier("target-user-id"); 583 targetUserID.addLongIdentifier("user-id"); 584 targetUserID.setArgumentGroupName( 585 INFO_MANAGE_ACCT_ARG_GROUP_TARGET_USER_ARGS.get()); 586 parser.addArgument(targetUserID); 587 588 final FileArgument userIDInputFile = new FileArgument(null, 589 ARG_USER_ID_INPUT_FILE, false, 0, null, 590 INFO_MANAGE_ACCT_ARG_DESC_USER_ID_INPUT_FILE.get(ARG_BASE_DN, 591 ARG_USER_ID_ATTRIBUTE), 592 true, true, true, false); 593 userIDInputFile.addLongIdentifier("targetUserIDFile"); 594 userIDInputFile.addLongIdentifier("user-id-input-file"); 595 userIDInputFile.addLongIdentifier("target-user-id-file"); 596 userIDInputFile.setArgumentGroupName( 597 INFO_MANAGE_ACCT_ARG_GROUP_TARGET_USER_ARGS.get()); 598 parser.addArgument(userIDInputFile); 599 600 final StringArgument userIDAttribute = new StringArgument(null, 601 ARG_USER_ID_ATTRIBUTE, false, 1, null, 602 INFO_MANAGE_ACCT_ARG_DESC_USER_ID_ATTR.get( 603 ARG_TARGET_USER_ID, ARG_USER_ID_INPUT_FILE, 604 DEFAULT_USER_ID_ATTRIBUTE), 605 DEFAULT_USER_ID_ATTRIBUTE); 606 userIDAttribute.addLongIdentifier("user-id-attribute"); 607 userIDAttribute.setArgumentGroupName( 608 INFO_MANAGE_ACCT_ARG_GROUP_TARGET_USER_ARGS.get()); 609 parser.addArgument(userIDAttribute); 610 611 final DNArgument baseDN = new DNArgument(null, ARG_BASE_DN, false, 1, null, 612 INFO_MANAGE_ACCT_ARG_DESC_BASE_DN.get(ARG_TARGET_FILTER, 613 ARG_FILTER_INPUT_FILE, ARG_TARGET_USER_ID, 614 ARG_USER_ID_INPUT_FILE), 615 DEFAULT_BASE_DN); 616 baseDN.addLongIdentifier("base-dn"); 617 baseDN.setArgumentGroupName( 618 INFO_MANAGE_ACCT_ARG_GROUP_TARGET_USER_ARGS.get()); 619 parser.addArgument(baseDN); 620 621 final IntegerArgument simplePageSize = new IntegerArgument('z', 622 ARG_SIMPLE_PAGE_SIZE, false, 1, null, 623 INFO_MANAGE_ACCT_ARG_DESC_SIMPLE_PAGE_SIZE.get(getToolName()), 1, 624 Integer.MAX_VALUE); 625 simplePageSize.addLongIdentifier("simple-page-size"); 626 simplePageSize.setArgumentGroupName( 627 INFO_MANAGE_ACCT_ARG_GROUP_TARGET_USER_ARGS.get(getToolName())); 628 parser.addArgument(simplePageSize); 629 630 631 // Ensure that the user will be required ot provide at least one of the 632 // arguments to specify which users to target. 633 parser.addRequiredArgumentSet(targetDN, dnInputFile, targetFilter, 634 filterInputFile, targetUserID, userIDInputFile); 635 636 637 // Define the global arguments used to control the amount of load the tool 638 // should be permitted to generate. 639 final IntegerArgument numThreads = new IntegerArgument('t', ARG_NUM_THREADS, 640 false, 1, null, 641 INFO_MANAGE_ACCT_ARG_DESC_NUM_THREADS.get(getToolName()), 1, 642 Integer.MAX_VALUE, 1); 643 numThreads.addLongIdentifier("num-threads"); 644 numThreads.setArgumentGroupName( 645 INFO_MANAGE_ACCT_ARG_GROUP_PERFORMANCE.get()); 646 parser.addArgument(numThreads); 647 648 final IntegerArgument numSearchThreads = new IntegerArgument(null, 649 ARG_NUM_SEARCH_THREADS, false, 1, null, 650 INFO_MANAGE_ACCT_ARG_DESC_NUM_SEARCH_THREADS.get(getToolName()), 1, 651 Integer.MAX_VALUE, 1); 652 numSearchThreads.addLongIdentifier("num-search-threads"); 653 numSearchThreads.setArgumentGroupName( 654 INFO_MANAGE_ACCT_ARG_GROUP_PERFORMANCE.get()); 655 parser.addArgument(numSearchThreads); 656 657 final IntegerArgument ratePerSecond = new IntegerArgument('r', 658 ARG_RATE_PER_SECOND, false, 1, null, 659 INFO_MANAGE_ACCT_ARG_DESC_RATE_PER_SECOND.get( 660 ARG_VARIABLE_RATE_DATA), 661 1, Integer.MAX_VALUE); 662 ratePerSecond.addLongIdentifier("rate-per-second"); 663 ratePerSecond.setArgumentGroupName( 664 INFO_MANAGE_ACCT_ARG_GROUP_PERFORMANCE.get()); 665 parser.addArgument(ratePerSecond); 666 667 final FileArgument variableRateData = new FileArgument(null, 668 ARG_VARIABLE_RATE_DATA, false, 1, null, 669 INFO_MANAGE_ACCT_ARG_DESC_VARIABLE_RATE_DATA.get( 670 ARG_RATE_PER_SECOND), 671 true, true, true, false); 672 variableRateData.addLongIdentifier("variable-rate-data"); 673 variableRateData.setArgumentGroupName( 674 INFO_MANAGE_ACCT_ARG_GROUP_PERFORMANCE.get()); 675 parser.addArgument(variableRateData); 676 677 final FileArgument generateSampleRateFile = new FileArgument(null, 678 ARG_GENERATE_SAMPLE_RATE_FILE, false, 1, null, 679 INFO_MANAGE_ACCT_ARG_DESC_GENERATE_SAMPLE_RATE_FILE.get( 680 ARG_VARIABLE_RATE_DATA), 681 false, true, true, false); 682 generateSampleRateFile.addLongIdentifier("generate-sample-rate-file"); 683 generateSampleRateFile.setArgumentGroupName( 684 INFO_MANAGE_ACCT_ARG_GROUP_PERFORMANCE.get()); 685 generateSampleRateFile.setUsageArgument(true); 686 parser.addArgument(generateSampleRateFile); 687 688 689 // Define the global arguments tht pertain to the reject file. 690 final FileArgument rejectFile = new FileArgument('R', ARG_REJECT_FILE, 691 false, 1, null, INFO_MANAGE_ACCT_ARG_DESC_REJECT_FILE.get(), 692 false, true, true, false); 693 rejectFile.addLongIdentifier("reject-file"); 694 parser.addArgument(rejectFile); 695 696 final BooleanArgument appendToRejectFile = new BooleanArgument(null, 697 ARG_APPEND_TO_REJECT_FILE, 1, 698 INFO_MANAGE_ACCT_ARG_DESC_APPEND_TO_REJECT_FILE.get( 699 rejectFile.getIdentifierString())); 700 appendToRejectFile.addLongIdentifier("append-to-reject-file"); 701 parser.addArgument(appendToRejectFile); 702 703 parser.addDependentArgumentSet(appendToRejectFile, rejectFile); 704 705 706 // Define the argument used to suppress result operations without values. 707 final BooleanArgument suppressEmptyResultOperations = 708 new BooleanArgument(null, ARG_SUPPRESS_EMPTY_RESULT_OPERATIONS, 709 1, 710 INFO_MANAGE_ACCT_ARG_DESC_SUPPRESS_EMPTY_RESULT_OPERATIONS.get( 711 getToolName())); 712 parser.addArgument(suppressEmptyResultOperations); 713 714 715 // Define the subcommand used to retrieve all state information for a user. 716 createSubCommand(GET_ALL, 717 INFO_MANAGE_ACCT_SC_GET_ALL_EXAMPLE.get(EXAMPLE_TARGET_USER_DN)); 718 719 720 // Define the subcommand used to retrieve the password policy DN for a user. 721 createSubCommand(GET_PASSWORD_POLICY_DN, 722 INFO_MANAGE_ACCT_SC_GET_POLICY_DN_EXAMPLE.get(EXAMPLE_TARGET_USER_DN)); 723 724 725 // Define the subcommand to determine whether the account is usable. 726 createSubCommand(GET_ACCOUNT_IS_USABLE, 727 INFO_MANAGE_ACCT_SC_GET_IS_USABLE_EXAMPLE.get(EXAMPLE_TARGET_USER_DN)); 728 729 730 // Define the subcommand to retrieve the set of password policy state 731 // account usability notice messages. 732 createSubCommand(GET_ACCOUNT_USABILITY_NOTICES, 733 INFO_MANAGE_ACCT_SC_GET_USABILITY_NOTICES_EXAMPLE.get( 734 EXAMPLE_TARGET_USER_DN)); 735 736 737 // Define the subcommand to retrieve the set of password policy state 738 // account usability warning messages. 739 createSubCommand(GET_ACCOUNT_USABILITY_WARNINGS, 740 INFO_MANAGE_ACCT_SC_GET_USABILITY_WARNINGS_EXAMPLE.get( 741 EXAMPLE_TARGET_USER_DN)); 742 743 744 // Define the subcommand to retrieve the set of password policy state 745 // account usability error messages. 746 createSubCommand(GET_ACCOUNT_USABILITY_ERRORS, 747 INFO_MANAGE_ACCT_SC_GET_USABILITY_ERRORS_EXAMPLE.get( 748 EXAMPLE_TARGET_USER_DN)); 749 750 751 // Define the subcommand to retrieve the password changed time for a user. 752 createSubCommand(GET_PASSWORD_CHANGED_TIME, 753 INFO_MANAGE_ACCT_SC_GET_PW_CHANGED_TIME_EXAMPLE.get( 754 EXAMPLE_TARGET_USER_DN)); 755 756 757 // Define the subcommand to set the password changed time for a user. 758 final ArgumentParser setPWChangedTimeParser = 759 createSubCommandParser(SET_PASSWORD_CHANGED_TIME); 760 761 final TimestampArgument setPWChangedTimeValueArg = new TimestampArgument( 762 'O', "passwordChangedTime", false, 1, null, 763 INFO_MANAGE_ACCT_SC_SET_PW_CHANGED_TIME_ARG_VALUE.get()); 764 setPWChangedTimeValueArg.addLongIdentifier("operationValue"); 765 setPWChangedTimeValueArg.addLongIdentifier("password-changed-time"); 766 setPWChangedTimeValueArg.addLongIdentifier("operation-value"); 767 setPWChangedTimeParser.addArgument(setPWChangedTimeValueArg); 768 769 createSubCommand(SET_PASSWORD_CHANGED_TIME, setPWChangedTimeParser, 770 createSubCommandExample(SET_PASSWORD_CHANGED_TIME, 771 INFO_MANAGE_ACCT_SC_SET_PW_CHANGED_TIME_EXAMPLE.get( 772 EXAMPLE_TARGET_USER_DN, currentGeneralizedTime), 773 "--passwordChangedTime", currentGeneralizedTime)); 774 775 776 // Define the subcommand to clear the password changed time for a user. 777 createSubCommand(CLEAR_PASSWORD_CHANGED_TIME, 778 INFO_MANAGE_ACCT_SC_CLEAR_PW_CHANGED_TIME_EXAMPLE.get( 779 EXAMPLE_TARGET_USER_DN)); 780 781 782 // Define the subcommand to determine whether a user account is disabled. 783 createSubCommand(GET_ACCOUNT_IS_DISABLED, 784 INFO_MANAGE_ACCT_SC_GET_IS_DISABLED_EXAMPLE.get( 785 EXAMPLE_TARGET_USER_DN)); 786 787 788 // Define the subcommand to specify whether a user's account is disabled. 789 final ArgumentParser setAcctDisabledParser = 790 createSubCommandParser(SET_ACCOUNT_IS_DISABLED); 791 792 final BooleanValueArgument setAcctDisabledValueArg = 793 new BooleanValueArgument('O', "accountIsDisabled", true, null, 794 INFO_MANAGE_ACCT_SC_SET_IS_DISABLED_ARG_VALUE.get()); 795 setAcctDisabledValueArg.addLongIdentifier("operationValue"); 796 setAcctDisabledValueArg.addLongIdentifier("account-is-disabled"); 797 setAcctDisabledValueArg.addLongIdentifier("operation-value"); 798 setAcctDisabledParser.addArgument(setAcctDisabledValueArg); 799 800 createSubCommand(SET_ACCOUNT_IS_DISABLED, setAcctDisabledParser, 801 createSubCommandExample(SET_ACCOUNT_IS_DISABLED, 802 INFO_MANAGE_ACCT_SC_SET_IS_DISABLED_EXAMPLE.get( 803 EXAMPLE_TARGET_USER_DN), 804 "--accountIsDisabled", "true")); 805 806 807 // Define the subcommand to clear the account disabled state. 808 createSubCommand(CLEAR_ACCOUNT_IS_DISABLED, 809 INFO_MANAGE_ACCT_SC_CLEAR_IS_DISABLED_EXAMPLE.get( 810 EXAMPLE_TARGET_USER_DN)); 811 812 813 // Define the subcommand to retrieve the account activation time for a user. 814 createSubCommand(GET_ACCOUNT_ACTIVATION_TIME, 815 INFO_MANAGE_ACCT_SC_GET_ACCT_ACT_TIME_EXAMPLE.get( 816 EXAMPLE_TARGET_USER_DN)); 817 818 819 // Define the subcommand to set the account activation time for a user. 820 final ArgumentParser setAcctActivationTimeParser = 821 createSubCommandParser(SET_ACCOUNT_ACTIVATION_TIME); 822 823 final TimestampArgument setAcctActivationTimeValueArg = 824 new TimestampArgument('O', "accountActivationTime", false, 1, null, 825 INFO_MANAGE_ACCT_SC_SET_ACCT_ACT_TIME_ARG_VALUE.get()); 826 setAcctActivationTimeValueArg.addLongIdentifier("operationValue"); 827 setAcctActivationTimeValueArg.addLongIdentifier("account-activation-time"); 828 setAcctActivationTimeValueArg.addLongIdentifier("operation-value"); 829 setAcctActivationTimeParser.addArgument(setAcctActivationTimeValueArg); 830 831 createSubCommand(SET_ACCOUNT_ACTIVATION_TIME, setAcctActivationTimeParser, 832 createSubCommandExample(SET_ACCOUNT_ACTIVATION_TIME, 833 INFO_MANAGE_ACCT_SC_SET_ACCT_ACT_TIME_EXAMPLE.get( 834 EXAMPLE_TARGET_USER_DN, currentGeneralizedTime), 835 "--accountActivationTime", currentGeneralizedTime)); 836 837 838 // Define the subcommand to clear the account activation time for a user. 839 createSubCommand(CLEAR_ACCOUNT_ACTIVATION_TIME, 840 INFO_MANAGE_ACCT_SC_CLEAR_ACCT_ACT_TIME_EXAMPLE.get( 841 EXAMPLE_TARGET_USER_DN)); 842 843 844 // Define the subcommand to retrieve the length of time until a user's 845 // account is activated. 846 createSubCommand(GET_SECONDS_UNTIL_ACCOUNT_ACTIVATION, 847 INFO_MANAGE_ACCT_SC_GET_SECONDS_UNTIL_ACCT_ACT_EXAMPLE.get( 848 EXAMPLE_TARGET_USER_DN)); 849 850 851 // Define the subcommand to determine whether a user's account is not yet 852 // active. 853 createSubCommand(GET_ACCOUNT_IS_NOT_YET_ACTIVE, 854 INFO_MANAGE_ACCT_SC_GET_ACCT_NOT_YET_ACTIVE_EXAMPLE.get( 855 EXAMPLE_TARGET_USER_DN)); 856 857 858 // Define the subcommand to retrieve the account expiration time for a user. 859 createSubCommand(GET_ACCOUNT_EXPIRATION_TIME, 860 INFO_MANAGE_ACCT_SC_GET_ACCT_EXP_TIME_EXAMPLE.get( 861 EXAMPLE_TARGET_USER_DN)); 862 863 864 // Define the subcommand to set the account expiration time for a user. 865 final ArgumentParser setAcctExpirationTimeParser = 866 createSubCommandParser(SET_ACCOUNT_EXPIRATION_TIME); 867 868 final TimestampArgument setAcctExpirationTimeValueArg = 869 new TimestampArgument('O', "accountExpirationTime", false, 1, null, 870 INFO_MANAGE_ACCT_SC_SET_ACCT_EXP_TIME_ARG_VALUE.get()); 871 setAcctExpirationTimeValueArg.addLongIdentifier("operationValue"); 872 setAcctExpirationTimeValueArg.addLongIdentifier("account-expiration-time"); 873 setAcctExpirationTimeValueArg.addLongIdentifier("operation-value"); 874 setAcctExpirationTimeParser.addArgument(setAcctExpirationTimeValueArg); 875 876 createSubCommand(SET_ACCOUNT_EXPIRATION_TIME, setAcctExpirationTimeParser, 877 createSubCommandExample(SET_ACCOUNT_EXPIRATION_TIME, 878 INFO_MANAGE_ACCT_SC_SET_ACCT_EXP_TIME_EXAMPLE.get( 879 EXAMPLE_TARGET_USER_DN, currentGeneralizedTime), 880 "--accountExpirationTime", currentGeneralizedTime)); 881 882 883 // Define the subcommand to clear the account expiration time for a user. 884 createSubCommand(CLEAR_ACCOUNT_EXPIRATION_TIME, 885 INFO_MANAGE_ACCT_SC_CLEAR_ACCT_EXP_TIME_EXAMPLE.get( 886 EXAMPLE_TARGET_USER_DN)); 887 888 889 // Define the subcommand to retrieve the length of time until a user's 890 // account is expired. 891 createSubCommand(GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION, 892 INFO_MANAGE_ACCT_SC_GET_SECONDS_UNTIL_ACCT_EXP_EXAMPLE.get( 893 EXAMPLE_TARGET_USER_DN)); 894 895 896 // Define the subcommand to determine whether a user's account is expired. 897 createSubCommand(GET_ACCOUNT_IS_EXPIRED, 898 INFO_MANAGE_ACCT_SC_GET_ACCT_IS_EXPIRED_EXAMPLE.get( 899 EXAMPLE_TARGET_USER_DN)); 900 901 902 // Define the subcommand to retrieve a user's password expiration warned 903 // time. 904 createSubCommand(GET_PASSWORD_EXPIRATION_WARNED_TIME, 905 INFO_MANAGE_ACCT_SC_GET_PW_EXP_WARNED_TIME_EXAMPLE.get( 906 EXAMPLE_TARGET_USER_DN)); 907 908 909 // Define the subcommand to set a user's password expiration warned time. 910 final ArgumentParser setPWExpWarnedTimeParser = 911 createSubCommandParser(SET_PASSWORD_EXPIRATION_WARNED_TIME); 912 913 final TimestampArgument setPWExpWarnedTimeValueArg = 914 new TimestampArgument('O', "passwordExpirationWarnedTime", false, 1, 915 null, INFO_MANAGE_ACCT_SC_SET_PW_EXP_WARNED_TIME_ARG_VALUE.get()); 916 setPWExpWarnedTimeValueArg.addLongIdentifier("operationValue"); 917 setPWExpWarnedTimeValueArg.addLongIdentifier( 918 "password-expiration-warned-time"); 919 setPWExpWarnedTimeValueArg.addLongIdentifier("operation-value"); 920 setPWExpWarnedTimeParser.addArgument(setPWExpWarnedTimeValueArg); 921 922 createSubCommand(SET_PASSWORD_EXPIRATION_WARNED_TIME, 923 setPWExpWarnedTimeParser, 924 createSubCommandExample(SET_PASSWORD_EXPIRATION_WARNED_TIME, 925 INFO_MANAGE_ACCT_SC_SET_PW_EXP_WARNED_TIME_EXAMPLE.get( 926 EXAMPLE_TARGET_USER_DN, currentGeneralizedTime), 927 "--passwordExpirationWarnedTime", currentGeneralizedTime)); 928 929 930 // Define the subcommand to clear a user's password expiration warned time. 931 createSubCommand(CLEAR_PASSWORD_EXPIRATION_WARNED_TIME, 932 INFO_MANAGE_ACCT_SC_CLEAR_PW_EXP_WARNED_TIME_EXAMPLE.get( 933 EXAMPLE_TARGET_USER_DN)); 934 935 936 // Define the subcommand to get the number of seconds until a user is 937 // eligible to receive a password expiration warning. 938 createSubCommand(GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING, 939 INFO_MANAGE_ACCT_SC_GET_SECONDS_UNTIL_PW_EXP_WARNING_EXAMPLE.get( 940 EXAMPLE_TARGET_USER_DN)); 941 942 943 // Define the subcommand to retrieve a user's password expiration time. 944 createSubCommand(GET_PASSWORD_EXPIRATION_TIME, 945 INFO_MANAGE_ACCT_SC_GET_PW_EXP_TIME_EXAMPLE.get( 946 EXAMPLE_TARGET_USER_DN)); 947 948 949 // Define the subcommand to get the number of seconds until a user's 950 // password expires. 951 createSubCommand(GET_SECONDS_UNTIL_PASSWORD_EXPIRATION, 952 INFO_MANAGE_ACCT_SC_GET_SECONDS_UNTIL_PW_EXP_EXAMPLE.get( 953 EXAMPLE_TARGET_USER_DN)); 954 955 956 // Define the subcommand to determine whether a user's password is expired. 957 createSubCommand(GET_PASSWORD_IS_EXPIRED, 958 INFO_MANAGE_ACCT_SC_GET_PW_IS_EXPIRED_EXAMPLE.get( 959 EXAMPLE_TARGET_USER_DN)); 960 961 962 // Define the subcommand to determine whether an account is failure locked. 963 createSubCommand(GET_ACCOUNT_IS_FAILURE_LOCKED, 964 INFO_MANAGE_ACCT_SC_GET_ACCT_FAILURE_LOCKED_EXAMPLE.get( 965 EXAMPLE_TARGET_USER_DN)); 966 967 968 // Define the subcommand to specify whether an account is failure locked. 969 final ArgumentParser setIsFailureLockedParser = 970 createSubCommandParser(SET_ACCOUNT_IS_FAILURE_LOCKED); 971 972 final BooleanValueArgument setIsFailureLockedValueArg = 973 new BooleanValueArgument('O', "accountIsFailureLocked", true, null, 974 INFO_MANAGE_ACCT_SC_SET_ACCT_FAILURE_LOCKED_ARG_VALUE.get()); 975 setIsFailureLockedValueArg.addLongIdentifier("operationValue"); 976 setIsFailureLockedValueArg.addLongIdentifier("account-is-failure-locked"); 977 setIsFailureLockedValueArg.addLongIdentifier("operation-value"); 978 setIsFailureLockedParser.addArgument(setIsFailureLockedValueArg); 979 980 createSubCommand(SET_ACCOUNT_IS_FAILURE_LOCKED, setIsFailureLockedParser, 981 createSubCommandExample(SET_ACCOUNT_IS_FAILURE_LOCKED, 982 INFO_MANAGE_ACCT_SC_SET_ACCT_FAILURE_LOCKED_EXAMPLE.get( 983 EXAMPLE_TARGET_USER_DN), 984 "--accountIsFailureLocked", "true")); 985 986 987 // Define the subcommand to get the time an account was failure locked. 988 createSubCommand(GET_FAILURE_LOCKOUT_TIME, 989 INFO_MANAGE_ACCT_SC_GET_FAILURE_LOCKED_TIME_EXAMPLE.get( 990 EXAMPLE_TARGET_USER_DN)); 991 992 993 // Define the subcommand to get the length of time until a failure-locked 994 // account will be automatically unlocked. 995 createSubCommand(GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK, 996 INFO_MANAGE_ACCT_SC_GET_SECONDS_UNTIL_FAILURE_UNLOCK_EXAMPLE.get( 997 EXAMPLE_TARGET_USER_DN)); 998 999 1000 // Define the subcommand to determine the authentication failure times. 1001 createSubCommand(GET_AUTHENTICATION_FAILURE_TIMES, 1002 INFO_MANAGE_ACCT_SC_GET_AUTH_FAILURE_TIMES_EXAMPLE.get( 1003 EXAMPLE_TARGET_USER_DN)); 1004 1005 1006 // Define the subcommand to add values to the set of authentication failure 1007 // times. 1008 final ArgumentParser addAuthFailureTimeParser = 1009 createSubCommandParser(ADD_AUTHENTICATION_FAILURE_TIME); 1010 1011 final TimestampArgument addAuthFailureTimeValueArg = 1012 new TimestampArgument('O', "authenticationFailureTime", false, 0, null, 1013 INFO_MANAGE_ACCT_SC_ADD_AUTH_FAILURE_TIME_ARG_VALUE.get()); 1014 addAuthFailureTimeValueArg.addLongIdentifier("operationValue"); 1015 addAuthFailureTimeValueArg.addLongIdentifier( 1016 "authentication-failure-time"); 1017 addAuthFailureTimeValueArg.addLongIdentifier("operation-value"); 1018 addAuthFailureTimeParser.addArgument(addAuthFailureTimeValueArg); 1019 1020 createSubCommand(ADD_AUTHENTICATION_FAILURE_TIME, addAuthFailureTimeParser, 1021 createSubCommandExample(ADD_AUTHENTICATION_FAILURE_TIME, 1022 INFO_MANAGE_ACCT_SC_ADD_AUTH_FAILURE_TIME_EXAMPLE.get( 1023 EXAMPLE_TARGET_USER_DN))); 1024 1025 1026 // Define the subcommand to replace the authentication failure times. 1027 final ArgumentParser setAuthFailureTimesParser = 1028 createSubCommandParser(SET_AUTHENTICATION_FAILURE_TIMES); 1029 1030 final TimestampArgument setAuthFailureTimesValueArg = 1031 new TimestampArgument('O', "authenticationFailureTime", false, 0, null, 1032 INFO_MANAGE_ACCT_SC_SET_AUTH_FAILURE_TIMES_ARG_VALUE.get()); 1033 setAuthFailureTimesValueArg.addLongIdentifier("operationValue"); 1034 setAuthFailureTimesValueArg.addLongIdentifier( 1035 "authentication-failure-time"); 1036 setAuthFailureTimesValueArg.addLongIdentifier("operation-value"); 1037 setAuthFailureTimesParser.addArgument(setAuthFailureTimesValueArg); 1038 1039 createSubCommand(SET_AUTHENTICATION_FAILURE_TIMES, 1040 setAuthFailureTimesParser, 1041 createSubCommandExample(SET_AUTHENTICATION_FAILURE_TIMES, 1042 INFO_MANAGE_ACCT_SC_SET_AUTH_FAILURE_TIMES_EXAMPLE.get( 1043 EXAMPLE_TARGET_USER_DN, olderGeneralizedTime, 1044 currentGeneralizedTime), 1045 "--authenticationFailureTime", olderGeneralizedTime, 1046 "--authenticationFailureTime", currentGeneralizedTime)); 1047 1048 1049 // Define the subcommand to clear the authentication failure times. 1050 createSubCommand(CLEAR_AUTHENTICATION_FAILURE_TIMES, 1051 INFO_MANAGE_ACCT_SC_CLEAR_AUTH_FAILURE_TIMES_EXAMPLE.get( 1052 EXAMPLE_TARGET_USER_DN)); 1053 1054 1055 // Define the subcommand to get the remaining authentication failure count. 1056 createSubCommand(GET_REMAINING_AUTHENTICATION_FAILURE_COUNT, 1057 INFO_MANAGE_ACCT_SC_GET_REMAINING_FAILURE_COUNT_EXAMPLE.get( 1058 EXAMPLE_TARGET_USER_DN)); 1059 1060 1061 // Define the subcommand to determine whether the account is idle locked. 1062 createSubCommand(GET_ACCOUNT_IS_IDLE_LOCKED, 1063 INFO_MANAGE_ACCT_SC_GET_ACCT_IDLE_LOCKED_EXAMPLE.get( 1064 EXAMPLE_TARGET_USER_DN)); 1065 1066 1067 // Define the subcommand to get the length of time until the account is 1068 // idle locked. 1069 createSubCommand(GET_SECONDS_UNTIL_IDLE_LOCKOUT, 1070 INFO_MANAGE_ACCT_SC_GET_SECONDS_UNTIL_IDLE_LOCKOUT_EXAMPLE.get( 1071 EXAMPLE_TARGET_USER_DN)); 1072 1073 1074 // Define the subcommand to get the idle lockout time for an account. 1075 createSubCommand(GET_IDLE_LOCKOUT_TIME, 1076 INFO_MANAGE_ACCT_SC_GET_IDLE_LOCKOUT_TIME_EXAMPLE.get( 1077 EXAMPLE_TARGET_USER_DN)); 1078 1079 1080 // Define the subcommand to determine whether a user's password has been 1081 // reset. 1082 createSubCommand(GET_MUST_CHANGE_PASSWORD, 1083 INFO_MANAGE_ACCT_SC_GET_MUST_CHANGE_PW_EXAMPLE.get( 1084 EXAMPLE_TARGET_USER_DN)); 1085 1086 1087 // Define the subcommand to specify whether a user's password has been 1088 // reset. 1089 final ArgumentParser setPWIsResetParser = 1090 createSubCommandParser(SET_MUST_CHANGE_PASSWORD); 1091 1092 final BooleanValueArgument setPWIsResetValueArg = 1093 new BooleanValueArgument('O', "mustChangePassword", true, null, 1094 INFO_MANAGE_ACCT_SC_SET_MUST_CHANGE_PW_ARG_VALUE.get()); 1095 setPWIsResetValueArg.addLongIdentifier("passwordIsReset"); 1096 setPWIsResetValueArg.addLongIdentifier("operationValue"); 1097 setPWIsResetValueArg.addLongIdentifier("must-change-password"); 1098 setPWIsResetValueArg.addLongIdentifier("password-is-reset"); 1099 setPWIsResetValueArg.addLongIdentifier("operation-value"); 1100 setPWIsResetParser.addArgument(setPWIsResetValueArg); 1101 1102 createSubCommand(SET_MUST_CHANGE_PASSWORD, setPWIsResetParser, 1103 createSubCommandExample(SET_MUST_CHANGE_PASSWORD, 1104 INFO_MANAGE_ACCT_SC_SET_MUST_CHANGE_PW_EXAMPLE.get( 1105 EXAMPLE_TARGET_USER_DN), 1106 "--mustChangePassword", "true")); 1107 1108 1109 // Define the subcommand to clear the password reset state information. 1110 createSubCommand(CLEAR_MUST_CHANGE_PASSWORD, 1111 INFO_MANAGE_ACCT_SC_CLEAR_MUST_CHANGE_PW_EXAMPLE.get( 1112 EXAMPLE_TARGET_USER_DN)); 1113 1114 1115 // Define the subcommand to determine whether the account is reset locked. 1116 createSubCommand(GET_ACCOUNT_IS_PASSWORD_RESET_LOCKED, 1117 INFO_MANAGE_ACCT_SC_GET_ACCT_IS_RESET_LOCKED_EXAMPLE.get( 1118 EXAMPLE_TARGET_USER_DN)); 1119 1120 1121 // Define the subcommand to get the length of time until the password is 1122 // reset locked. 1123 createSubCommand(GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT, 1124 INFO_MANAGE_ACCT_SC_GET_SECONDS_UNTIL_RESET_LOCKOUT_EXAMPLE.get( 1125 EXAMPLE_TARGET_USER_DN)); 1126 1127 1128 // Define the subcommand to get the password reset lockout time. 1129 createSubCommand(GET_PASSWORD_RESET_LOCKOUT_TIME, 1130 INFO_MANAGE_ACCT_SC_GET_RESET_LOCKOUT_TIME_EXAMPLE.get( 1131 EXAMPLE_TARGET_USER_DN)); 1132 1133 1134 // Define the subcommand to get the last login time. 1135 createSubCommand(GET_LAST_LOGIN_TIME, 1136 INFO_MANAGE_ACCT_SC_GET_LAST_LOGIN_TIME_EXAMPLE.get( 1137 EXAMPLE_TARGET_USER_DN)); 1138 1139 1140 // Define the subcommand to set the last login time. 1141 final ArgumentParser setLastLoginTimeParser = 1142 createSubCommandParser(SET_LAST_LOGIN_TIME); 1143 1144 final TimestampArgument setLastLoginTimeValueArg = new TimestampArgument( 1145 'O', "lastLoginTime", false, 1, null, 1146 INFO_MANAGE_ACCT_SC_SET_LAST_LOGIN_TIME_ARG_VALUE.get()); 1147 setLastLoginTimeValueArg.addLongIdentifier("operationValue"); 1148 setLastLoginTimeValueArg.addLongIdentifier("last-login-time"); 1149 setLastLoginTimeValueArg.addLongIdentifier("operation-value"); 1150 setLastLoginTimeParser.addArgument(setLastLoginTimeValueArg); 1151 1152 createSubCommand(SET_LAST_LOGIN_TIME, setLastLoginTimeParser, 1153 createSubCommandExample(SET_LAST_LOGIN_TIME, 1154 INFO_MANAGE_ACCT_SC_SET_LAST_LOGIN_TIME_EXAMPLE.get( 1155 EXAMPLE_TARGET_USER_DN, currentGeneralizedTime), 1156 "--lastLoginTime", currentGeneralizedTime)); 1157 1158 1159 // Define the subcommand to clear the last login time. 1160 createSubCommand(CLEAR_LAST_LOGIN_TIME, 1161 INFO_MANAGE_ACCT_SC_CLEAR_LAST_LOGIN_TIME_EXAMPLE.get( 1162 EXAMPLE_TARGET_USER_DN)); 1163 1164 1165 // Define the subcommand to get the last login IP address. 1166 createSubCommand(GET_LAST_LOGIN_IP_ADDRESS, 1167 INFO_MANAGE_ACCT_SC_GET_LAST_LOGIN_IP_EXAMPLE.get( 1168 EXAMPLE_TARGET_USER_DN)); 1169 1170 1171 // Define the subcommand to set the last login IP address. 1172 final ArgumentParser setLastLoginIPParser = 1173 createSubCommandParser(SET_LAST_LOGIN_IP_ADDRESS); 1174 1175 final StringArgument setLastLoginIPValueArg = new StringArgument('O', 1176 "lastLoginIPAddress", true, 1, null, 1177 INFO_MANAGE_ACCT_SC_SET_LAST_LOGIN_IP_ARG_VALUE.get()); 1178 setLastLoginIPValueArg.addLongIdentifier("operationValue"); 1179 setLastLoginIPValueArg.addLongIdentifier("last-login-ip-address"); 1180 setLastLoginIPValueArg.addLongIdentifier("operation-value"); 1181 setLastLoginIPValueArg.addValueValidator( 1182 new IPAddressArgumentValueValidator()); 1183 setLastLoginIPParser.addArgument(setLastLoginIPValueArg); 1184 1185 1186 createSubCommand(SET_LAST_LOGIN_IP_ADDRESS, setLastLoginIPParser, 1187 createSubCommandExample(SET_LAST_LOGIN_IP_ADDRESS, 1188 INFO_MANAGE_ACCT_SC_SET_LAST_LOGIN_IP_EXAMPLE.get( 1189 EXAMPLE_TARGET_USER_DN, "1.2.3.4"), 1190 "--lastLoginIPAddress", "1.2.3.4")); 1191 1192 1193 // Define the subcommand to clear the last login IP address. 1194 createSubCommand(CLEAR_LAST_LOGIN_IP_ADDRESS, 1195 INFO_MANAGE_ACCT_SC_CLEAR_LAST_LOGIN_IP_EXAMPLE.get( 1196 EXAMPLE_TARGET_USER_DN)); 1197 1198 1199 // Define the subcommand to get the grace login use times. 1200 createSubCommand(GET_GRACE_LOGIN_USE_TIMES, 1201 INFO_MANAGE_ACCT_SC_GET_GRACE_LOGIN_TIMES_EXAMPLE.get( 1202 EXAMPLE_TARGET_USER_DN)); 1203 1204 1205 // Define the subcommand to add values to the set of grace login use times. 1206 final ArgumentParser addGraceLoginTimeParser = 1207 createSubCommandParser(ADD_GRACE_LOGIN_USE_TIME); 1208 1209 final TimestampArgument addGraceLoginTimeValueArg = 1210 new TimestampArgument('O', "graceLoginUseTime", false, 0, null, 1211 INFO_MANAGE_ACCT_SC_ADD_GRACE_LOGIN_TIME_ARG_VALUE.get()); 1212 addGraceLoginTimeValueArg.addLongIdentifier("operationValue"); 1213 addGraceLoginTimeValueArg.addLongIdentifier("grace-login-use-time"); 1214 addGraceLoginTimeValueArg.addLongIdentifier("operation-value"); 1215 addGraceLoginTimeParser.addArgument(addGraceLoginTimeValueArg); 1216 1217 createSubCommand(ADD_GRACE_LOGIN_USE_TIME, addGraceLoginTimeParser, 1218 createSubCommandExample(ADD_GRACE_LOGIN_USE_TIME, 1219 INFO_MANAGE_ACCT_SC_ADD_GRACE_LOGIN_TIME_EXAMPLE.get( 1220 EXAMPLE_TARGET_USER_DN))); 1221 1222 1223 // Define the subcommand to replace the set of grace login use times. 1224 final ArgumentParser setGraceLoginTimesParser = 1225 createSubCommandParser(SET_GRACE_LOGIN_USE_TIMES); 1226 1227 final TimestampArgument setGraceLoginTimesValueArg = 1228 new TimestampArgument('O', "graceLoginUseTime", false, 0, null, 1229 INFO_MANAGE_ACCT_SC_SET_GRACE_LOGIN_TIMES_ARG_VALUE.get()); 1230 setGraceLoginTimesValueArg.addLongIdentifier("operationValue"); 1231 setGraceLoginTimesValueArg.addLongIdentifier("grace-login-use-time"); 1232 setGraceLoginTimesValueArg.addLongIdentifier("operation-value"); 1233 setGraceLoginTimesParser.addArgument(setGraceLoginTimesValueArg); 1234 1235 createSubCommand(SET_GRACE_LOGIN_USE_TIMES, setGraceLoginTimesParser, 1236 createSubCommandExample(SET_GRACE_LOGIN_USE_TIMES, 1237 INFO_MANAGE_ACCT_SC_SET_GRACE_LOGIN_TIMES_EXAMPLE.get( 1238 EXAMPLE_TARGET_USER_DN, olderGeneralizedTime, 1239 currentGeneralizedTime), 1240 "--graceLoginUseTime", olderGeneralizedTime, 1241 "--graceLoginUseTime", currentGeneralizedTime)); 1242 1243 1244 // Define the subcommand to clear the grace login use times. 1245 createSubCommand(CLEAR_GRACE_LOGIN_USE_TIMES, 1246 INFO_MANAGE_ACCT_SC_CLEAR_GRACE_LOGIN_TIMES_EXAMPLE.get( 1247 EXAMPLE_TARGET_USER_DN)); 1248 1249 1250 // Define the subcommand to get the remaining grace login count. 1251 createSubCommand(GET_REMAINING_GRACE_LOGIN_COUNT, 1252 INFO_MANAGE_ACCT_SC_GET_REMAINING_GRACE_LOGIN_COUNT_EXAMPLE.get( 1253 EXAMPLE_TARGET_USER_DN)); 1254 1255 1256 // Define the subcommand to get the password changed by required time value. 1257 createSubCommand(GET_PASSWORD_CHANGED_BY_REQUIRED_TIME, 1258 INFO_MANAGE_ACCT_SC_GET_PW_CHANGED_BY_REQ_TIME_EXAMPLE.get( 1259 EXAMPLE_TARGET_USER_DN)); 1260 1261 1262 // Define the subcommand to set the password changed by required time value. 1263 final ArgumentParser setPWChangedByReqTimeParser = 1264 createSubCommandParser(SET_PASSWORD_CHANGED_BY_REQUIRED_TIME); 1265 1266 final TimestampArgument setPWChangedByReqTimeValueArg = 1267 new TimestampArgument('O', "passwordChangedByRequiredTime", false, 1, 1268 null, 1269 INFO_MANAGE_ACCT_SC_SET_PW_CHANGED_BY_REQ_TIME_ARG_VALUE.get()); 1270 setPWChangedByReqTimeValueArg.addLongIdentifier("operationValue"); 1271 setPWChangedByReqTimeValueArg.addLongIdentifier( 1272 "password-changed-by-required-time"); 1273 setPWChangedByReqTimeValueArg.addLongIdentifier("operation-value"); 1274 setPWChangedByReqTimeParser.addArgument( 1275 setPWChangedByReqTimeValueArg); 1276 1277 createSubCommand(SET_PASSWORD_CHANGED_BY_REQUIRED_TIME, 1278 setPWChangedByReqTimeParser, 1279 createSubCommandExample(SET_PASSWORD_CHANGED_BY_REQUIRED_TIME, 1280 INFO_MANAGE_ACCT_SC_SET_PW_CHANGED_BY_REQ_TIME_EXAMPLE.get( 1281 EXAMPLE_TARGET_USER_DN))); 1282 1283 1284 // Define the subcommand to clear the password changed by required time 1285 // value. 1286 createSubCommand(CLEAR_PASSWORD_CHANGED_BY_REQUIRED_TIME, 1287 INFO_MANAGE_ACCT_SC_CLEAR_PW_CHANGED_BY_REQ_TIME_EXAMPLE.get( 1288 EXAMPLE_TARGET_USER_DN)); 1289 1290 1291 // Define the subcommand to get the length of time until the required change 1292 // time. 1293 createSubCommand(GET_SECONDS_UNTIL_REQUIRED_PASSWORD_CHANGE_TIME, 1294 INFO_MANAGE_ACCT_SC_GET_SECS_UNTIL_REQ_CHANGE_TIME_EXAMPLE.get( 1295 EXAMPLE_TARGET_USER_DN)); 1296 1297 1298 // Define the subcommand to get the password history count. 1299 createSubCommand(GET_PASSWORD_HISTORY_COUNT, 1300 INFO_MANAGE_ACCT_SC_GET_PW_HISTORY_COUNT_EXAMPLE.get( 1301 EXAMPLE_TARGET_USER_DN)); 1302 1303 1304 // Define the subcommand to clear a user's password history. 1305 createSubCommand(CLEAR_PASSWORD_HISTORY, 1306 INFO_MANAGE_ACCT_SC_CLEAR_PW_HISTORY_EXAMPLE.get( 1307 EXAMPLE_TARGET_USER_DN)); 1308 1309 1310 // Define the subcommand to determine whether a user has a retired password. 1311 createSubCommand(GET_HAS_RETIRED_PASSWORD, 1312 INFO_MANAGE_ACCT_SC_GET_HAS_RETIRED_PW_EXAMPLE.get( 1313 EXAMPLE_TARGET_USER_DN)); 1314 1315 1316 // Define the subcommand to retrieve the time that a user's former password 1317 // was retired. 1318 createSubCommand(GET_PASSWORD_RETIRED_TIME, 1319 INFO_MANAGE_ACCT_SC_GET_PW_RETIRED_TIME_EXAMPLE.get( 1320 EXAMPLE_TARGET_USER_DN)); 1321 1322 1323 // Define the subcommand to retrieve the retired password expiration time. 1324 createSubCommand(GET_RETIRED_PASSWORD_EXPIRATION_TIME, 1325 INFO_MANAGE_ACCT_SC_GET_RETIRED_PW_EXP_TIME_EXAMPLE.get( 1326 EXAMPLE_TARGET_USER_DN)); 1327 1328 1329 // Define the subcommand to purge a retired password. 1330 createSubCommand(CLEAR_RETIRED_PASSWORD, 1331 INFO_MANAGE_ACCT_SC_PURGE_RETIRED_PW_EXAMPLE.get( 1332 EXAMPLE_TARGET_USER_DN)); 1333 1334 1335 // Define the subcommand to get the available SASL mechanisms for a user. 1336 createSubCommand(GET_AVAILABLE_SASL_MECHANISMS, 1337 INFO_MANAGE_ACCT_SC_GET_AVAILABLE_SASL_MECHS_EXAMPLE.get( 1338 EXAMPLE_TARGET_USER_DN)); 1339 1340 1341 // Define the subcommand to get the available OTP delivery mechanisms for a 1342 // user. 1343 createSubCommand(GET_AVAILABLE_OTP_DELIVERY_MECHANISMS, 1344 INFO_MANAGE_ACCT_SC_GET_AVAILABLE_OTP_MECHS_EXAMPLE.get( 1345 EXAMPLE_TARGET_USER_DN)); 1346 1347 1348 // Define the subcommand to determine whether a user has at least one TOTP 1349 // shared secret. 1350 createSubCommand(GET_HAS_TOTP_SHARED_SECRET, 1351 INFO_MANAGE_ACCT_SC_GET_HAS_TOTP_SHARED_SECRET_EXAMPLE.get( 1352 EXAMPLE_TARGET_USER_DN)); 1353 1354 1355 // Define the subcommand to add a value to the set of TOTP shared secrets 1356 // for a user. 1357 final ArgumentParser addTOTPSharedSecretParser = 1358 createSubCommandParser(ADD_TOTP_SHARED_SECRET); 1359 1360 final StringArgument addTOTPSharedSecretValueArg = 1361 new StringArgument('O', "totpSharedSecret", true, 0, null, 1362 INFO_MANAGE_ACCT_SC_ADD_YUBIKEY_ID_ARG_VALUE.get()); 1363 addTOTPSharedSecretValueArg.addLongIdentifier("operationValue"); 1364 addTOTPSharedSecretValueArg.addLongIdentifier("totp-shared-secret"); 1365 addTOTPSharedSecretValueArg.addLongIdentifier("operation-value"); 1366 addTOTPSharedSecretParser.addArgument( 1367 addTOTPSharedSecretValueArg); 1368 1369 createSubCommand(ADD_TOTP_SHARED_SECRET, addTOTPSharedSecretParser, 1370 createSubCommandExample(ADD_TOTP_SHARED_SECRET, 1371 INFO_MANAGE_ACCT_SC_ADD_TOTP_SHARED_SECRET_EXAMPLE.get( 1372 "abcdefghijklmnop", EXAMPLE_TARGET_USER_DN), 1373 "--totpSharedSecret", "abcdefghijklmnop")); 1374 1375 1376 // Define the subcommand to remove a value from the set of TOTP shared 1377 // secrets for a user. 1378 final ArgumentParser removeTOTPSharedSecretParser = 1379 createSubCommandParser(REMOVE_TOTP_SHARED_SECRET); 1380 1381 final StringArgument removeTOTPSharedSecretValueArg = 1382 new StringArgument('O', "totpSharedSecret", true, 0, null, 1383 INFO_MANAGE_ACCT_SC_REMOVE_YUBIKEY_ID_ARG_VALUE.get()); 1384 removeTOTPSharedSecretValueArg.addLongIdentifier("operationValue"); 1385 removeTOTPSharedSecretValueArg.addLongIdentifier("totp-shared-secret"); 1386 removeTOTPSharedSecretValueArg.addLongIdentifier( 1387 "operation-value"); 1388 removeTOTPSharedSecretParser.addArgument( 1389 removeTOTPSharedSecretValueArg); 1390 1391 createSubCommand(REMOVE_TOTP_SHARED_SECRET, removeTOTPSharedSecretParser, 1392 createSubCommandExample(REMOVE_TOTP_SHARED_SECRET, 1393 INFO_MANAGE_ACCT_SC_REMOVE_TOTP_SHARED_SECRET_EXAMPLE.get( 1394 "abcdefghijklmnop", EXAMPLE_TARGET_USER_DN), 1395 "--totpSharedSecret", "abcdefghijklmnop")); 1396 1397 1398 // Define the subcommand to replace set of TOTP shared secrets for a user. 1399 final ArgumentParser setTOTPSharedSecretsParser = 1400 createSubCommandParser(SET_TOTP_SHARED_SECRETS); 1401 1402 final StringArgument setTOTPSharedSecretsValueArg = 1403 new StringArgument('O', "totpSharedSecret", true, 0, null, 1404 INFO_MANAGE_ACCT_SC_SET_TOTP_SHARED_SECRETS_ARG_VALUE.get()); 1405 setTOTPSharedSecretsValueArg.addLongIdentifier("operationValue"); 1406 setTOTPSharedSecretsValueArg.addLongIdentifier("totp-shared-secret"); 1407 setTOTPSharedSecretsValueArg.addLongIdentifier( 1408 "operation-value"); 1409 setTOTPSharedSecretsParser.addArgument( 1410 setTOTPSharedSecretsValueArg); 1411 1412 createSubCommand(SET_TOTP_SHARED_SECRETS, 1413 setTOTPSharedSecretsParser, 1414 createSubCommandExample(SET_TOTP_SHARED_SECRETS, 1415 INFO_MANAGE_ACCT_SC_SET_TOTP_SHARED_SECRETS_EXAMPLE.get( 1416 EXAMPLE_TARGET_USER_DN, "abcdefghijklmnop"), 1417 "--totpSharedSecret", "abcdefghijklmnop")); 1418 1419 1420 // Define the subcommand to clear the set of TOTP shared secrets for a user. 1421 createSubCommand(CLEAR_TOTP_SHARED_SECRETS, 1422 INFO_MANAGE_ACCT_SC_CLEAR_TOTP_SHARED_SECRETS_EXAMPLE.get( 1423 EXAMPLE_TARGET_USER_DN)); 1424 1425 1426 // Define the subcommand to determine whether a user has at least one 1427 // registered YubiKey OTP device public ID. 1428 createSubCommand(GET_HAS_REGISTERED_YUBIKEY_PUBLIC_ID, 1429 INFO_MANAGE_ACCT_SC_GET_HAS_YUBIKEY_ID_EXAMPLE.get( 1430 EXAMPLE_TARGET_USER_DN)); 1431 1432 1433 // Define the subcommand to get the set of registered YubiKey OTP device 1434 // public IDs for a user. 1435 createSubCommand(GET_REGISTERED_YUBIKEY_PUBLIC_IDS, 1436 INFO_MANAGE_ACCT_SC_GET_YUBIKEY_IDS_EXAMPLE.get( 1437 EXAMPLE_TARGET_USER_DN)); 1438 1439 1440 // Define the subcommand to add a value to the set of registered YubiKey OTP 1441 // device public IDs for a user. 1442 final ArgumentParser addRegisteredYubiKeyPublicIDParser = 1443 createSubCommandParser(ADD_REGISTERED_YUBIKEY_PUBLIC_ID); 1444 1445 final StringArgument addRegisteredYubiKeyPublicIDValueArg = 1446 new StringArgument('O', "publicID", true, 0, null, 1447 INFO_MANAGE_ACCT_SC_ADD_YUBIKEY_ID_ARG_VALUE.get()); 1448 addRegisteredYubiKeyPublicIDValueArg.addLongIdentifier("operationValue"); 1449 addRegisteredYubiKeyPublicIDValueArg.addLongIdentifier("public-id"); 1450 addRegisteredYubiKeyPublicIDValueArg.addLongIdentifier("operation-value"); 1451 addRegisteredYubiKeyPublicIDParser.addArgument( 1452 addRegisteredYubiKeyPublicIDValueArg); 1453 1454 createSubCommand(ADD_REGISTERED_YUBIKEY_PUBLIC_ID, 1455 addRegisteredYubiKeyPublicIDParser, 1456 createSubCommandExample(ADD_REGISTERED_YUBIKEY_PUBLIC_ID, 1457 INFO_MANAGE_ACCT_SC_ADD_YUBIKEY_ID_EXAMPLE.get( 1458 "abcdefghijkl", EXAMPLE_TARGET_USER_DN), 1459 "--publicID", "abcdefghijkl")); 1460 1461 1462 // Define the subcommand to remove a value from the set of registered 1463 // YubiKey OTP device public IDs for a user. 1464 final ArgumentParser removeRegisteredYubiKeyPublicIDParser = 1465 createSubCommandParser(REMOVE_REGISTERED_YUBIKEY_PUBLIC_ID); 1466 1467 final StringArgument removeRegisteredYubiKeyPublicIDValueArg = 1468 new StringArgument('O', "publicID", true, 0, null, 1469 INFO_MANAGE_ACCT_SC_REMOVE_YUBIKEY_ID_ARG_VALUE.get()); 1470 removeRegisteredYubiKeyPublicIDValueArg.addLongIdentifier("operationValue"); 1471 removeRegisteredYubiKeyPublicIDValueArg.addLongIdentifier("public-id"); 1472 removeRegisteredYubiKeyPublicIDValueArg.addLongIdentifier( 1473 "operation-value"); 1474 removeRegisteredYubiKeyPublicIDParser.addArgument( 1475 removeRegisteredYubiKeyPublicIDValueArg); 1476 1477 createSubCommand(REMOVE_REGISTERED_YUBIKEY_PUBLIC_ID, 1478 removeRegisteredYubiKeyPublicIDParser, 1479 createSubCommandExample(REMOVE_REGISTERED_YUBIKEY_PUBLIC_ID, 1480 INFO_MANAGE_ACCT_SC_REMOVE_YUBIKEY_ID_EXAMPLE.get( 1481 "abcdefghijkl", EXAMPLE_TARGET_USER_DN), 1482 "--publicID", "abcdefghijkl")); 1483 1484 1485 // Define the subcommand to replace set of registered YubiKey OTP device 1486 // public IDs for a user. 1487 final ArgumentParser setRegisteredYubiKeyPublicIDParser = 1488 createSubCommandParser(SET_REGISTERED_YUBIKEY_PUBLIC_IDS); 1489 1490 final StringArgument setRegisteredYubiKeyPublicIDValueArg = 1491 new StringArgument('O', "publicID", true, 0, null, 1492 INFO_MANAGE_ACCT_SC_SET_YUBIKEY_IDS_ARG_VALUE.get()); 1493 setRegisteredYubiKeyPublicIDValueArg.addLongIdentifier("operationValue"); 1494 setRegisteredYubiKeyPublicIDValueArg.addLongIdentifier("public-id"); 1495 setRegisteredYubiKeyPublicIDValueArg.addLongIdentifier( 1496 "operation-value"); 1497 setRegisteredYubiKeyPublicIDParser.addArgument( 1498 setRegisteredYubiKeyPublicIDValueArg); 1499 1500 createSubCommand(SET_REGISTERED_YUBIKEY_PUBLIC_IDS, 1501 setRegisteredYubiKeyPublicIDParser, 1502 createSubCommandExample(SET_REGISTERED_YUBIKEY_PUBLIC_IDS, 1503 INFO_MANAGE_ACCT_SC_SET_YUBIKEY_IDS_EXAMPLE.get( 1504 EXAMPLE_TARGET_USER_DN, "abcdefghijkl"), 1505 "--publicID", "abcdefghijkl")); 1506 1507 1508 // Define the subcommand to clear the set of registered YubiKey OTP device 1509 // public IDs for a user. 1510 createSubCommand(CLEAR_REGISTERED_YUBIKEY_PUBLIC_IDS, 1511 INFO_MANAGE_ACCT_SC_CLEAR_YUBIKEY_IDS_EXAMPLE.get( 1512 EXAMPLE_TARGET_USER_DN)); 1513 } 1514 1515 1516 1517 /** 1518 * Creates an argument parser for the provided subcommand type. It will not 1519 * have any arguments associated with it. 1520 * 1521 * @param type The subcommand type for which to create the argument parser. 1522 * 1523 * @return The created argument parser. 1524 * 1525 * @throws ArgumentException If a problem is encountered while creating the 1526 * argument parser. 1527 */ 1528 private static ArgumentParser createSubCommandParser( 1529 final ManageAccountSubCommandType type) 1530 throws ArgumentException 1531 { 1532 return new ArgumentParser(type.getPrimaryName(), type.getDescription()); 1533 } 1534 1535 1536 1537 /** 1538 * Generates an example usage map for a specified subcommand. 1539 * 1540 * @param t The subcommand type. 1541 * @param description The description to use for the example. 1542 * @param args The set of arguments to include in the example, 1543 * excluding the subcommand name and the arguments used 1544 * to connect and authenticate to the server. This may 1545 * be empty if no additional arguments are needed. 1546 * 1547 * @return The generated example usage map. 1548 */ 1549 private static LinkedHashMap<String[],String> createSubCommandExample( 1550 final ManageAccountSubCommandType t, 1551 final String description, final String... args) 1552 { 1553 final LinkedHashMap<String[], String> examples = 1554 new LinkedHashMap<String[], String>(1); 1555 createSubCommandExample(examples, t, description, args); 1556 return examples; 1557 } 1558 1559 1560 1561 /** 1562 * Adds an example for a specified subcommand to the given map. 1563 * 1564 * @param examples The map to which the example should be added. 1565 * @param t The subcommand type. 1566 * @param description The description to use for the example. 1567 * @param args The set of arguments to include in the example, 1568 * excluding the subcommand name and the arguments used 1569 * to connect and authenticate to the server. This may 1570 * be empty if no additional arguments are needed. 1571 */ 1572 private static void createSubCommandExample( 1573 final LinkedHashMap<String[], String> examples, 1574 final ManageAccountSubCommandType t, final String description, 1575 final String... args) 1576 { 1577 final ArrayList<String> argList = new ArrayList<String>(10 + args.length); 1578 argList.add(t.getPrimaryName()); 1579 argList.add("--hostname"); 1580 argList.add("server.example.com"); 1581 argList.add("--port"); 1582 argList.add("389"); 1583 argList.add("--bindDN"); 1584 argList.add("uid=admin,dc=example,dc=com"); 1585 argList.add("--promptForBindPassword"); 1586 argList.add("--targetDN"); 1587 argList.add("uid=jdoe,ou=People,dc=example,dc=com"); 1588 1589 if (args.length > 0) 1590 { 1591 argList.addAll(Arrays.asList(args)); 1592 } 1593 1594 final String[] argArray = new String[argList.size()]; 1595 argList.toArray(argArray); 1596 1597 examples.put(argArray, description); 1598 } 1599 1600 1601 1602 /** 1603 * Creates a subcommand with the provided information. 1604 * 1605 * @param subcommandType The subcommand type. 1606 * @param exampleDescription The description to use for the 1607 * automatically-generated example. 1608 * 1609 * @throws ArgumentException If a problem is encountered while creating the 1610 * subcommand. 1611 */ 1612 private void createSubCommand( 1613 final ManageAccountSubCommandType subcommandType, 1614 final String exampleDescription) 1615 throws ArgumentException 1616 { 1617 final ArgumentParser subcommandParser = 1618 createSubCommandParser(subcommandType); 1619 1620 final LinkedHashMap<String[],String> examples = 1621 createSubCommandExample(subcommandType, exampleDescription); 1622 1623 createSubCommand(subcommandType, subcommandParser, examples); 1624 } 1625 1626 1627 1628 /** 1629 * Creates a subcommand with the provided information. 1630 * 1631 * @param subcommandType The subcommand type. 1632 * @param subcommandParser The argument parser for the subcommand-specific 1633 * arguments. 1634 * @param examples The example usages for the subcommand. 1635 * 1636 * @throws ArgumentException If a problem is encountered while creating the 1637 * subcommand. 1638 */ 1639 private void createSubCommand( 1640 final ManageAccountSubCommandType subcommandType, 1641 final ArgumentParser subcommandParser, 1642 final LinkedHashMap<String[],String> examples) 1643 throws ArgumentException 1644 { 1645 final SubCommand subCommand = new SubCommand( 1646 subcommandType.getPrimaryName(), subcommandType.getDescription(), 1647 subcommandParser, examples); 1648 1649 for (final String alternateName : subcommandType.getAlternateNames()) 1650 { 1651 subCommand.addName(alternateName); 1652 } 1653 1654 parser.addSubCommand(subCommand); 1655 } 1656 1657 1658 1659 /** 1660 * {@inheritDoc} 1661 */ 1662 @Override() 1663 public LDAPConnectionOptions getConnectionOptions() 1664 { 1665 return connectionOptions; 1666 } 1667 1668 1669 1670 /** 1671 * {@inheritDoc} 1672 */ 1673 @Override() 1674 public ResultCode doToolProcessing() 1675 { 1676 // If we should just generate a sample rate data file, then do that now. 1677 final FileArgument generateSampleRateFile = 1678 parser.getFileArgument(ARG_GENERATE_SAMPLE_RATE_FILE); 1679 if (generateSampleRateFile.isPresent()) 1680 { 1681 try 1682 { 1683 RateAdjustor.writeSampleVariableRateFile( 1684 generateSampleRateFile.getValue()); 1685 return ResultCode.SUCCESS; 1686 } 1687 catch (final Exception e) 1688 { 1689 Debug.debugException(e); 1690 wrapErr(0, WRAP_COLUMN, 1691 ERR_MANAGE_ACCT_CANNOT_GENERATE_SAMPLE_RATE_FILE.get( 1692 generateSampleRateFile.getValue().getAbsolutePath(), 1693 StaticUtils.getExceptionMessage(e))); 1694 return ResultCode.LOCAL_ERROR; 1695 } 1696 } 1697 1698 1699 // If we need to create a fixed-rate barrier and/or use a variable rate 1700 // definition, then set that up. 1701 final IntegerArgument ratePerSecond = 1702 parser.getIntegerArgument(ARG_RATE_PER_SECOND); 1703 final FileArgument variableRateData = 1704 parser.getFileArgument(ARG_VARIABLE_RATE_DATA); 1705 if (ratePerSecond.isPresent() || variableRateData.isPresent()) 1706 { 1707 if (ratePerSecond.isPresent()) 1708 { 1709 rateLimiter = new FixedRateBarrier(1000L, ratePerSecond.getValue()); 1710 } 1711 else 1712 { 1713 rateLimiter = new FixedRateBarrier(1000L, Integer.MAX_VALUE); 1714 } 1715 1716 if (variableRateData.isPresent()) 1717 { 1718 try 1719 { 1720 rateAdjustor = RateAdjustor.newInstance(rateLimiter, 1721 ratePerSecond.getValue(), variableRateData.getValue()); 1722 } 1723 catch (final Exception e) 1724 { 1725 Debug.debugException(e); 1726 wrapErr(0, WRAP_COLUMN, 1727 ERR_MANAGE_ACCT_CANNOT_CREATE_RATE_ADJUSTOR.get( 1728 variableRateData.getValue().getAbsolutePath(), 1729 StaticUtils.getExceptionMessage(e))); 1730 return ResultCode.PARAM_ERROR; 1731 } 1732 } 1733 } 1734 1735 1736 // Create the connection pool to use for all processing. 1737 final LDAPConnectionPool pool; 1738 final int numSearchThreads = 1739 parser.getIntegerArgument(ARG_NUM_SEARCH_THREADS).getValue(); 1740 try 1741 { 1742 final int numOperationThreads = 1743 parser.getIntegerArgument(ARG_NUM_THREADS).getValue(); 1744 pool = getConnectionPool(numOperationThreads, 1745 (numOperationThreads + numSearchThreads)); 1746 1747 // Explicitly disable automatic retry, since it probably won't work 1748 // reliably for extended operations anyway. We'll handle retry manually. 1749 pool.setRetryFailedOperationsDueToInvalidConnections(false); 1750 1751 // Set a maximum connection age of 30 minutes. 1752 pool.setMaxConnectionAgeMillis(1800000L); 1753 } 1754 catch (final LDAPException le) 1755 { 1756 Debug.debugException(le); 1757 1758 wrapErr(0, WRAP_COLUMN, 1759 ERR_MANAGE_ACCT_CANNOT_CREATE_CONNECTION_POOL.get(getToolName(), 1760 le.getMessage())); 1761 return le.getResultCode(); 1762 } 1763 1764 1765 try 1766 { 1767 // Create the output writer. This should always succeed. 1768 outputWriter = new LDIFWriter(getOut()); 1769 1770 1771 1772 // Create the reject writer if appropriate. 1773 final FileArgument rejectFile = parser.getFileArgument(ARG_REJECT_FILE); 1774 if (rejectFile.isPresent()) 1775 { 1776 final BooleanArgument appendToRejectFile = 1777 parser.getBooleanArgument(ARG_APPEND_TO_REJECT_FILE); 1778 1779 try 1780 { 1781 rejectWriter = new LDIFWriter(new FileOutputStream( 1782 rejectFile.getValue(), appendToRejectFile.isPresent())); 1783 } 1784 catch (final Exception e) 1785 { 1786 Debug.debugException(e); 1787 wrapErr(0, WRAP_COLUMN, 1788 ERR_MANAGE_ACCT_CANNOT_CREATE_REJECT_WRITER.get( 1789 rejectFile.getValue().getAbsolutePath(), 1790 StaticUtils.getExceptionMessage(e))); 1791 return ResultCode.LOCAL_ERROR; 1792 } 1793 } 1794 1795 1796 // Create the processor that will be used to actually perform the 1797 // manage-account operation processing for each entry. 1798 final ManageAccountProcessor processor; 1799 try 1800 { 1801 processor = new ManageAccountProcessor(this, pool, rateLimiter, 1802 outputWriter, rejectWriter); 1803 } 1804 catch (final LDAPException le) 1805 { 1806 Debug.debugException(le); 1807 wrapErr(0, WRAP_COLUMN, 1808 ERR_MANAGE_ACCT_CANNOT_CREATE_PROCESSOR.get( 1809 StaticUtils.getExceptionMessage(le))); 1810 return le.getResultCode(); 1811 } 1812 1813 1814 // If we should use a rate adjustor, then start it now. 1815 if (rateAdjustor != null) 1816 { 1817 rateAdjustor.start(); 1818 } 1819 1820 1821 // If any targetDN values were provided, then process them now. 1822 final DNArgument targetDN = parser.getDNArgument(ARG_TARGET_DN); 1823 if (targetDN.isPresent()) 1824 { 1825 for (final DN dn : targetDN.getValues()) 1826 { 1827 if (cancelRequested()) 1828 { 1829 return ResultCode.USER_CANCELED; 1830 } 1831 1832 processor.process(dn.toString()); 1833 } 1834 } 1835 1836 1837 // If any DN input files were specified, then process them now. 1838 final FileArgument dnInputFile = 1839 parser.getFileArgument(ARG_DN_INPUT_FILE); 1840 if (dnInputFile.isPresent()) 1841 { 1842 for (final File f : dnInputFile.getValues()) 1843 { 1844 DNFileReader reader = null; 1845 try 1846 { 1847 reader = new DNFileReader(f); 1848 while (true) 1849 { 1850 if (cancelRequested()) 1851 { 1852 return ResultCode.USER_CANCELED; 1853 } 1854 1855 final DN dn; 1856 try 1857 { 1858 dn = reader.readDN(); 1859 } 1860 catch (final LDAPException le) 1861 { 1862 Debug.debugException(le); 1863 processor.handleMessage(le.getMessage(), true); 1864 continue; 1865 } 1866 1867 if (dn == null) 1868 { 1869 break; 1870 } 1871 1872 processor.process(dn.toString()); 1873 } 1874 } 1875 catch (final Exception e) 1876 { 1877 Debug.debugException(e); 1878 processor.handleMessage( 1879 ERR_MANAGE_ACCT_ERROR_READING_DN_FILE.get( 1880 f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), 1881 true); 1882 } 1883 finally 1884 { 1885 if (reader != null) 1886 { 1887 try 1888 { 1889 reader.close(); 1890 } 1891 catch (final Exception e2) 1892 { 1893 Debug.debugException(e2); 1894 } 1895 } 1896 } 1897 } 1898 } 1899 1900 1901 // If any target filters were specified, then process them now. 1902 final FilterArgument targetFilter = 1903 parser.getFilterArgument(ARG_TARGET_FILTER); 1904 if (targetFilter.isPresent()) 1905 { 1906 searchProcessor = 1907 new ManageAccountSearchProcessor(this, processor, pool); 1908 for (final Filter f : targetFilter.getValues()) 1909 { 1910 searchProcessor.processFilter(f); 1911 } 1912 } 1913 1914 1915 // If any filter input files were specified, then process them now. 1916 final FileArgument filterInputFile = 1917 parser.getFileArgument(ARG_FILTER_INPUT_FILE); 1918 if (filterInputFile.isPresent()) 1919 { 1920 if (searchProcessor == null) 1921 { 1922 searchProcessor = 1923 new ManageAccountSearchProcessor(this, processor, pool); 1924 } 1925 1926 for (final File f : filterInputFile.getValues()) 1927 { 1928 FilterFileReader reader = null; 1929 try 1930 { 1931 reader = new FilterFileReader(f); 1932 while (true) 1933 { 1934 if (cancelRequested()) 1935 { 1936 return ResultCode.USER_CANCELED; 1937 } 1938 1939 final Filter filter; 1940 try 1941 { 1942 filter = reader.readFilter(); 1943 } 1944 catch (final LDAPException le) 1945 { 1946 Debug.debugException(le); 1947 processor.handleMessage(le.getMessage(), true); 1948 continue; 1949 } 1950 1951 if (filter == null) 1952 { 1953 break; 1954 } 1955 1956 searchProcessor.processFilter(filter); 1957 } 1958 } 1959 catch (final Exception e) 1960 { 1961 Debug.debugException(e); 1962 processor.handleMessage( 1963 ERR_MANAGE_ACCT_ERROR_READING_FILTER_FILE.get( 1964 f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), 1965 true); 1966 } 1967 finally 1968 { 1969 if (reader != null) 1970 { 1971 try 1972 { 1973 reader.close(); 1974 } 1975 catch (final Exception e2) 1976 { 1977 Debug.debugException(e2); 1978 } 1979 } 1980 } 1981 } 1982 } 1983 1984 1985 // If any target user IDs were specified, then process them now. 1986 final StringArgument targetUserID = 1987 parser.getStringArgument(ARG_TARGET_USER_ID); 1988 if (targetUserID.isPresent()) 1989 { 1990 if (searchProcessor == null) 1991 { 1992 searchProcessor = 1993 new ManageAccountSearchProcessor(this, processor, pool); 1994 } 1995 1996 for (final String userID : targetUserID.getValues()) 1997 { 1998 searchProcessor.processUserID(userID); 1999 } 2000 } 2001 2002 2003 // If any user ID input files were specified, then process them now. 2004 final FileArgument userIDInputFile = 2005 parser.getFileArgument(ARG_USER_ID_INPUT_FILE); 2006 if (userIDInputFile.isPresent()) 2007 { 2008 if (searchProcessor == null) 2009 { 2010 searchProcessor = 2011 new ManageAccountSearchProcessor(this, processor, pool); 2012 } 2013 2014 for (final File f : userIDInputFile.getValues()) 2015 { 2016 BufferedReader reader = null; 2017 try 2018 { 2019 reader = new BufferedReader(new FileReader(f)); 2020 while (true) 2021 { 2022 if (cancelRequested()) 2023 { 2024 return ResultCode.USER_CANCELED; 2025 } 2026 2027 final String line = reader.readLine(); 2028 if (line == null) 2029 { 2030 break; 2031 } 2032 2033 if ((line.length() == 0) || line.startsWith("#")) 2034 { 2035 continue; 2036 } 2037 2038 searchProcessor.processUserID(line.trim()); 2039 } 2040 } 2041 catch (final Exception e) 2042 { 2043 Debug.debugException(e); 2044 processor.handleMessage( 2045 ERR_MANAGE_ACCT_ERROR_READING_USER_ID_FILE.get( 2046 f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), 2047 true); 2048 } 2049 finally 2050 { 2051 if (reader != null) 2052 { 2053 try 2054 { 2055 reader.close(); 2056 } 2057 catch (final Exception e2) 2058 { 2059 Debug.debugException(e2); 2060 } 2061 } 2062 } 2063 } 2064 } 2065 2066 2067 allFiltersProvided.set(true); 2068 if (searchProcessor != null) 2069 { 2070 searchProcessor.waitForCompletion(); 2071 } 2072 2073 allDNsProvided.set(true); 2074 processor.waitForCompletion(); 2075 } 2076 finally 2077 { 2078 pool.close(); 2079 2080 if (rejectWriter != null) 2081 { 2082 try 2083 { 2084 rejectWriter.close(); 2085 } 2086 catch (final Exception e) 2087 { 2088 Debug.debugException(e); 2089 } 2090 } 2091 } 2092 2093 2094 // If we've gotten here, then we can consider the command successful, even 2095 // if some of the operations failed. 2096 return ResultCode.SUCCESS; 2097 } 2098 2099 2100 2101 /** 2102 * Retrieves the argument parser for this tool. 2103 * 2104 * @return The argument parser for this tool. 2105 */ 2106 ArgumentParser getArgumentParser() 2107 { 2108 return parser; 2109 } 2110 2111 2112 2113 /** 2114 * Indicates whether the tool should cancel its processing. 2115 * 2116 * @return {@code true} if the tool should cancel its processing, or 2117 * {@code false} if not. 2118 */ 2119 boolean cancelRequested() 2120 { 2121 return cancelRequested.get(); 2122 } 2123 2124 2125 2126 /** 2127 * Indicates whether the manage-account processor has been provided with all 2128 * of the DNs of all of the entries to process. 2129 * 2130 * @return {@code true} if the manage-account processor has been provided 2131 * with all of the DNs of all of the entries to process, or 2132 * {@code false} if not. 2133 */ 2134 boolean allDNsProvided() 2135 { 2136 return allDNsProvided.get(); 2137 } 2138 2139 2140 2141 /** 2142 * Indicates whether the manage-account search processor has been provided 2143 * with all of the filters to use to identify entries to process. 2144 * 2145 * @return {@code true} if the manage-account search processor has been 2146 * provided with all of the filters to use to identify entries to 2147 * process, or {@code false} if not. 2148 */ 2149 boolean allFiltersProvided() 2150 { 2151 return allFiltersProvided.get(); 2152 } 2153 2154 2155 2156 /** 2157 * {@inheritDoc} 2158 */ 2159 @Override() 2160 protected boolean registerShutdownHook() 2161 { 2162 return true; 2163 } 2164 2165 2166 2167 /** 2168 * {@inheritDoc} 2169 */ 2170 @Override() 2171 protected void doShutdownHookProcessing(final ResultCode resultCode) 2172 { 2173 cancelRequested.set(true); 2174 2175 if (rateLimiter != null) 2176 { 2177 rateLimiter.shutdownRequested(); 2178 } 2179 2180 if (searchProcessor != null) 2181 { 2182 searchProcessor.cancelSearches(); 2183 } 2184 } 2185 2186 2187 2188 /** 2189 * Performs any processing that may be necessary in response to the provided 2190 * unsolicited notification that has been received from the server. 2191 * 2192 * @param connection The connection on which the unsolicited notification 2193 * was received. 2194 * @param notification The unsolicited notification that has been received 2195 * from the server. 2196 */ 2197 public void handleUnsolicitedNotification(final LDAPConnection connection, 2198 final ExtendedResult notification) 2199 { 2200 final String message = NOTE_MANAGE_ACCT_UNSOLICITED_NOTIFICATION.get( 2201 String.valueOf(connection), String.valueOf(notification)); 2202 if (outputWriter == null) 2203 { 2204 err(); 2205 err("* " + message); 2206 err(); 2207 } 2208 else 2209 { 2210 try 2211 { 2212 outputWriter.writeComment(message, true, true); 2213 outputWriter.flush(); 2214 } 2215 catch (final Exception e) 2216 { 2217 // We can't really do anything about this. 2218 Debug.debugException(e); 2219 } 2220 } 2221 } 2222 2223 2224 2225 /** 2226 * {@inheritDoc} 2227 */ 2228 @Override() 2229 public LinkedHashMap<String[],String> getExampleUsages() 2230 { 2231 final LinkedHashMap<String[],String> examples = 2232 new LinkedHashMap<String[],String>(4); 2233 2234 createSubCommandExample(examples, GET_ALL, 2235 INFO_MANAGE_ACCT_SC_GET_ALL_EXAMPLE.get(EXAMPLE_TARGET_USER_DN)); 2236 2237 createSubCommandExample(examples, GET_ACCOUNT_USABILITY_ERRORS, 2238 INFO_MANAGE_ACCT_SC_GET_USABILITY_ERRORS_EXAMPLE.get( 2239 EXAMPLE_TARGET_USER_DN)); 2240 2241 createSubCommandExample(examples, SET_ACCOUNT_IS_DISABLED, 2242 INFO_MANAGE_ACCT_SC_SET_IS_DISABLED_EXAMPLE.get( 2243 EXAMPLE_TARGET_USER_DN), 2244 "--accountIsDisabled", "true"); 2245 2246 createSubCommandExample(examples, CLEAR_AUTHENTICATION_FAILURE_TIMES, 2247 INFO_MANAGE_ACCT_SC_CLEAR_AUTH_FAILURE_TIMES_EXAMPLE.get( 2248 EXAMPLE_TARGET_USER_DN)); 2249 2250 return examples; 2251 } 2252}