All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.unboundid.ldap.sdk.unboundidds.tools.LDAPSearch Maven / Gradle / Ivy

Go to download

The UnboundID LDAP SDK for Java is a fast, comprehensive, and easy-to-use Java API for communicating with LDAP directory servers and performing related tasks like reading and writing LDIF, encoding and decoding data using base64 and ASN.1 BER, and performing secure communication. This package contains the Standard Edition of the LDAP SDK, which is a complete, general-purpose library for communicating with LDAPv3 directory servers.

There is a newer version: 7.0.1
Show newest version
/*
 * Copyright 2017-2023 Ping Identity Corporation
 * All Rights Reserved.
 */
/*
 * Copyright 2017-2023 Ping Identity Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * Copyright (C) 2017-2023 Ping Identity Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License (GPLv2 only)
 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see .
 */
package com.unboundid.ldap.sdk.unboundidds.tools;



import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.atomic.AtomicLong;
import java.util.zip.GZIPOutputStream;

import com.unboundid.asn1.ASN1OctetString;
import com.unboundid.ldap.sdk.Control;
import com.unboundid.ldap.sdk.DN;
import com.unboundid.ldap.sdk.DereferencePolicy;
import com.unboundid.ldap.sdk.ExtendedResult;
import com.unboundid.ldap.sdk.Filter;
import com.unboundid.ldap.sdk.LDAPConnectionOptions;
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPConnectionPool;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.LDAPSearchException;
import com.unboundid.ldap.sdk.LDAPURL;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.ldap.sdk.SearchRequest;
import com.unboundid.ldap.sdk.SearchResult;
import com.unboundid.ldap.sdk.SearchScope;
import com.unboundid.ldap.sdk.UnsolicitedNotificationHandler;
import com.unboundid.ldap.sdk.Version;
import com.unboundid.ldap.sdk.controls.AssertionRequestControl;
import com.unboundid.ldap.sdk.controls.AuthorizationIdentityRequestControl;
import com.unboundid.ldap.sdk.controls.DraftLDUPSubentriesRequestControl;
import com.unboundid.ldap.sdk.controls.ManageDsaITRequestControl;
import com.unboundid.ldap.sdk.controls.MatchedValuesFilter;
import com.unboundid.ldap.sdk.controls.MatchedValuesRequestControl;
import com.unboundid.ldap.sdk.controls.PersistentSearchChangeType;
import com.unboundid.ldap.sdk.controls.PersistentSearchRequestControl;
import com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV1RequestControl;
import com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV2RequestControl;
import com.unboundid.ldap.sdk.controls.RFC3672SubentriesRequestControl;
import com.unboundid.ldap.sdk.controls.ServerSideSortRequestControl;
import com.unboundid.ldap.sdk.controls.SimplePagedResultsControl;
import com.unboundid.ldap.sdk.controls.SortKey;
import com.unboundid.ldap.sdk.controls.VirtualListViewRequestControl;
import com.unboundid.ldap.sdk.persist.PersistUtils;
import com.unboundid.ldap.sdk.transformations.EntryTransformation;
import com.unboundid.ldap.sdk.transformations.ExcludeAttributeTransformation;
import com.unboundid.ldap.sdk.transformations.MoveSubtreeTransformation;
import com.unboundid.ldap.sdk.transformations.RedactAttributeTransformation;
import com.unboundid.ldap.sdk.transformations.RenameAttributeTransformation;
import com.unboundid.ldap.sdk.transformations.ScrambleAttributeTransformation;
import com.unboundid.ldap.sdk.unboundidds.controls.AccessLogFieldRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.AccountUsableRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.ExcludeBranchRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
            GenerateAccessTokenRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
            GetAuthorizationEntryRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
            GetBackendSetIDRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
            GetEffectiveRightsRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
            GetRecentLoginHistoryRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.GetServerIDRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
            GetUserResourceLimitsRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
            JSONFormattedControlDecodeBehavior;
import com.unboundid.ldap.sdk.unboundidds.controls.JSONFormattedRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.JSONFormattedResponseControl;
import com.unboundid.ldap.sdk.unboundidds.controls.JoinBaseDN;
import com.unboundid.ldap.sdk.unboundidds.controls.JoinRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.JoinRequestValue;
import com.unboundid.ldap.sdk.unboundidds.controls.JoinRule;
import com.unboundid.ldap.sdk.unboundidds.controls.
            MatchingEntryCountRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
            MatchingEntryCountRequestControlProperties;
import com.unboundid.ldap.sdk.unboundidds.controls.
            OperationPurposeRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
            OverrideSearchLimitsRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.PasswordPolicyRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
            PermitUnindexedSearchRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
            RealAttributesOnlyRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
            RejectUnindexedSearchRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
            ReturnConflictEntriesRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
            RouteToBackendSetRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.RouteToServerRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
            SoftDeletedEntryAccessRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
            SuppressOperationalAttributeUpdateRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.SuppressType;
import com.unboundid.ldap.sdk.unboundidds.controls.
            VirtualAttributesOnlyRequestControl;
import com.unboundid.ldap.sdk.unboundidds.extensions.
            StartAdministrativeSessionExtendedRequest;
import com.unboundid.ldap.sdk.unboundidds.extensions.
            StartAdministrativeSessionPostConnectProcessor;
import com.unboundid.ldif.LDIFWriter;
import com.unboundid.util.Debug;
import com.unboundid.util.FilterFileReader;
import com.unboundid.util.FixedRateBarrier;
import com.unboundid.util.LDAPCommandLineTool;
import com.unboundid.util.NotNull;
import com.unboundid.util.Nullable;
import com.unboundid.util.OutputFormat;
import com.unboundid.util.PassphraseEncryptedOutputStream;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.TeeOutputStream;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
import com.unboundid.util.args.ArgumentException;
import com.unboundid.util.args.ArgumentParser;
import com.unboundid.util.args.BooleanArgument;
import com.unboundid.util.args.BooleanValueArgument;
import com.unboundid.util.args.ControlArgument;
import com.unboundid.util.args.DNArgument;
import com.unboundid.util.args.FileArgument;
import com.unboundid.util.args.FilterArgument;
import com.unboundid.util.args.IntegerArgument;
import com.unboundid.util.args.ScopeArgument;
import com.unboundid.util.args.StringArgument;
import com.unboundid.util.json.JSONBoolean;
import com.unboundid.util.json.JSONNumber;
import com.unboundid.util.json.JSONObject;
import com.unboundid.util.json.JSONString;
import com.unboundid.util.json.JSONValue;

import static com.unboundid.ldap.sdk.unboundidds.tools.ToolMessages.*;



/**
 * This class provides an implementation of an LDAP command-line tool that may
 * be used to issue searches to a directory server.  Matching entries will be
 * output in the LDAP data interchange format (LDIF), to standard output and/or
 * to a specified file.  This is a much more full-featured tool than the
 * {@link com.unboundid.ldap.sdk.examples.LDAPSearch} tool, and includes a
 * number of features only intended for use with Ping Identity, UnboundID, and
 * Nokia/Alcatel-Lucent 8661 server products.
 * 
*
* NOTE: This class, and other classes within the * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only * supported for use against Ping Identity, UnboundID, and * Nokia/Alcatel-Lucent 8661 server products. These classes provide support * for proprietary functionality or for external specifications that are not * considered stable or mature enough to be guaranteed to work in an * interoperable way with other types of LDAP servers. *
*/ @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) public final class LDAPSearch extends LDAPCommandLineTool implements UnsolicitedNotificationHandler { /** * The column at which to wrap long lines. */ private static int WRAP_COLUMN = StaticUtils.TERMINAL_WIDTH_COLUMNS - 1; // The set of arguments supported by this program. @Nullable private BooleanArgument accountUsable = null; @Nullable private BooleanArgument authorizationIdentity = null; @Nullable private BooleanArgument compressOutput = null; @Nullable private BooleanArgument continueOnError = null; @Nullable private BooleanArgument countEntries = null; @Nullable private BooleanArgument dontWrap = null; @Nullable private BooleanArgument draftLDUPSubentries = null; @Nullable private BooleanArgument dryRun = null; @Nullable private BooleanArgument encryptOutput = null; @Nullable private BooleanArgument followReferrals = null; @Nullable private BooleanArgument generateAccessToken = null; @Nullable private BooleanArgument getBackendSetID = null; @Nullable private BooleanArgument getServerID = null; @Nullable private BooleanArgument getRecentLoginHistory = null; @Nullable private BooleanArgument hideRedactedValueCount = null; @Nullable private BooleanArgument getUserResourceLimits = null; @Nullable private BooleanArgument includeReplicationConflictEntries = null; @Nullable private BooleanArgument joinRequireMatch = null; @Nullable private BooleanArgument manageDsaIT = null; @Nullable private BooleanArgument permitUnindexedSearch = null; @Nullable private BooleanArgument realAttributesOnly = null; @Nullable private BooleanArgument rejectUnindexedSearch = null; @Nullable private BooleanArgument requireMatch = null; @Nullable private BooleanArgument retryFailedOperations = null; @Nullable private BooleanArgument separateOutputFilePerSearch = null; @Nullable private BooleanArgument suppressBase64EncodedValueComments = null; @Nullable private BooleanArgument teeResultsToStandardOut = null; @Nullable private BooleanArgument useAdministrativeSession = null; @Nullable private BooleanArgument useJSONFormattedRequestControls = null; @Nullable private BooleanArgument usePasswordPolicyControl = null; @Nullable private BooleanArgument terse = null; @Nullable private BooleanArgument typesOnly = null; @Nullable private BooleanArgument verbose = null; @Nullable private BooleanArgument virtualAttributesOnly = null; @Nullable private BooleanValueArgument rfc3672Subentries = null; @Nullable private ControlArgument bindControl = null; @Nullable private ControlArgument searchControl = null; @Nullable private DNArgument baseDN = null; @Nullable private DNArgument excludeBranch = null; @Nullable private DNArgument moveSubtreeFrom = null; @Nullable private DNArgument moveSubtreeTo = null; @Nullable private DNArgument proxyV1As = null; @Nullable private FileArgument encryptionPassphraseFile = null; @Nullable private FileArgument filterFile = null; @Nullable private FileArgument ldapURLFile = null; @Nullable private FileArgument outputFile = null; @Nullable private FilterArgument assertionFilter = null; @Nullable private FilterArgument filter = null; @Nullable private FilterArgument joinFilter = null; @Nullable private FilterArgument matchedValuesFilter = null; @Nullable private IntegerArgument joinSizeLimit = null; @Nullable private IntegerArgument ratePerSecond = null; @Nullable private IntegerArgument scrambleRandomSeed = null; @Nullable private IntegerArgument simplePageSize = null; @Nullable private IntegerArgument sizeLimit = null; @Nullable private IntegerArgument timeLimitSeconds = null; @Nullable private IntegerArgument wrapColumn = null; @Nullable private ScopeArgument joinScope = null; @Nullable private ScopeArgument scope = null; @Nullable private StringArgument accessLogField = null; @Nullable private StringArgument dereferencePolicy = null; @Nullable private StringArgument excludeAttribute = null; @Nullable private StringArgument getAuthorizationEntryAttribute = null; @Nullable private StringArgument getEffectiveRightsAttribute = null; @Nullable private StringArgument getEffectiveRightsAuthzID = null; @Nullable private StringArgument includeSoftDeletedEntries = null; @Nullable private StringArgument joinBaseDN = null; @Nullable private StringArgument joinRequestedAttribute = null; @Nullable private StringArgument joinRule = null; @Nullable private StringArgument matchingEntryCountControl = null; @Nullable private StringArgument operationPurpose = null; @Nullable private StringArgument outputFormat = null; @Nullable private StringArgument overrideSearchLimit = null; @Nullable private StringArgument persistentSearch = null; @Nullable private StringArgument proxyAs = null; @Nullable private StringArgument redactAttribute = null; @Nullable private StringArgument renameAttributeFrom = null; @Nullable private StringArgument renameAttributeTo = null; @Nullable private StringArgument requestedAttribute = null; @Nullable private StringArgument routeToBackendSet = null; @Nullable private StringArgument routeToServer = null; @Nullable private StringArgument scrambleAttribute = null; @Nullable private StringArgument scrambleJSONField = null; @Nullable private StringArgument sortOrder = null; @Nullable private StringArgument suppressOperationalAttributeUpdates = null; @Nullable private StringArgument virtualListView = null; // The argument parser used by this tool. @Nullable private volatile ArgumentParser parser = null; // Controls that should be sent to the server but need special validation. @Nullable private volatile JoinRequestControl joinRequestControl = null; @NotNull private final List routeToBackendSetRequestControls = new ArrayList<>(10); @Nullable private volatile MatchedValuesRequestControl matchedValuesRequestControl = null; @Nullable private volatile MatchingEntryCountRequestControl matchingEntryCountRequestControl = null; @Nullable private volatile OverrideSearchLimitsRequestControl overrideSearchLimitsRequestControl = null; @Nullable private volatile PersistentSearchRequestControl persistentSearchRequestControl = null; @Nullable private volatile ServerSideSortRequestControl sortRequestControl = null; @Nullable private volatile VirtualListViewRequestControl vlvRequestControl = null; // Other values decoded from arguments. @Nullable private volatile DereferencePolicy derefPolicy = null; // The print streams used for standard output and error. @NotNull private final AtomicLong outputFileCounter = new AtomicLong(1); @Nullable private volatile PrintStream errStream = null; @Nullable private volatile PrintStream outStream = null; // The LDAP result writer for this tool. @NotNull private volatile LDAPResultWriter resultWriter; // The list of entry transformations to apply. @Nullable private volatile List entryTransformations = null; // The encryption passphrase to use if the output is to be encrypted. @Nullable private String encryptionPassphrase = null; /** * Runs this tool with the provided command-line arguments. It will use the * JVM-default streams for standard input, output, and error. * * @param args The command-line arguments to provide to this program. */ public static void main(@NotNull final String... args) { final ResultCode resultCode = main(System.out, System.err, args); if (resultCode != ResultCode.SUCCESS) { System.exit(Math.min(resultCode.intValue(), 255)); } } /** * Runs this tool with the provided streams and command-line arguments. * * @param out The output stream to use for standard output. If this is * {@code null}, then standard output will be suppressed. * @param err The output stream to use for standard error. If this is * {@code null}, then standard error will be suppressed. * @param args The command-line arguments provided to this program. * * @return The result code obtained when running the tool. Any result code * other than {@link ResultCode#SUCCESS} indicates an error. */ @NotNull() public static ResultCode main(@Nullable final OutputStream out, @Nullable final OutputStream err, @NotNull final String... args) { final LDAPSearch tool = new LDAPSearch(out, err); return tool.runTool(args); } /** * Creates a new instance of this tool with the provided streams. * * @param out The output stream to use for standard output. If this is * {@code null}, then standard output will be suppressed. * @param err The output stream to use for standard error. If this is * {@code null}, then standard error will be suppressed. */ public LDAPSearch(@Nullable final OutputStream out, @Nullable final OutputStream err) { super(out, err); resultWriter = new LDIFLDAPResultWriter(getOut(), WRAP_COLUMN); } /** * {@inheritDoc} */ @Override() @NotNull() public String getToolName() { return "ldapsearch"; } /** * {@inheritDoc} */ @Override() @NotNull() public String getToolDescription() { return INFO_LDAPSEARCH_TOOL_DESCRIPTION.get(); } /** * {@inheritDoc} */ @Override() @NotNull() public List getAdditionalDescriptionParagraphs() { return Arrays.asList( INFO_LDAPSEARCH_ADDITIONAL_DESCRIPTION_PARAGRAPH_1.get(), INFO_LDAPSEARCH_ADDITIONAL_DESCRIPTION_PARAGRAPH_2.get()); } /** * {@inheritDoc} */ @Override() @NotNull() public String getToolVersion() { return Version.NUMERIC_VERSION_STRING; } /** * {@inheritDoc} */ @Override() public int getMinTrailingArguments() { return 0; } /** * {@inheritDoc} */ @Override() public int getMaxTrailingArguments() { return -1; } /** * {@inheritDoc} */ @Override() @NotNull() public String getTrailingArgumentsPlaceholder() { return INFO_LDAPSEARCH_TRAILING_ARGS_PLACEHOLDER.get(); } /** * {@inheritDoc} */ @Override() public boolean supportsInteractiveMode() { return true; } /** * {@inheritDoc} */ @Override() public boolean defaultsToInteractiveMode() { return true; } /** * {@inheritDoc} */ @Override() public boolean supportsPropertiesFile() { return true; } /** * {@inheritDoc} */ @Override() protected boolean defaultToPromptForBindPassword() { return true; } /** * {@inheritDoc} */ @Override() protected boolean includeAlternateLongIdentifiers() { return true; } /** * {@inheritDoc} */ @Override() protected boolean supportsSSLDebugging() { return true; } /** * {@inheritDoc} */ @Override() @NotNull() protected Set getSuppressedShortIdentifiers() { return Collections.singleton('T'); } /** * {@inheritDoc} */ @Override() public void addNonLDAPArguments(@NotNull final ArgumentParser parser) throws ArgumentException { this.parser = parser; baseDN = new DNArgument('b', "baseDN", false, 1, null, INFO_LDAPSEARCH_ARG_DESCRIPTION_BASE_DN.get()); baseDN.addLongIdentifier("base-dn", true); baseDN.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get()); parser.addArgument(baseDN); scope = new ScopeArgument('s', "scope", false, null, INFO_LDAPSEARCH_ARG_DESCRIPTION_SCOPE.get(), SearchScope.SUB); scope.addLongIdentifier("searchScope", true); scope.addLongIdentifier("search-scope", true); scope.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get()); parser.addArgument(scope); sizeLimit = new IntegerArgument('z', "sizeLimit", false, 1, null, INFO_LDAPSEARCH_ARG_DESCRIPTION_SIZE_LIMIT.get(), 0, Integer.MAX_VALUE, 0); sizeLimit.addLongIdentifier("size-limit", true); sizeLimit.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get()); parser.addArgument(sizeLimit); timeLimitSeconds = new IntegerArgument('l', "timeLimitSeconds", false, 1, null, INFO_LDAPSEARCH_ARG_DESCRIPTION_TIME_LIMIT.get(), 0, Integer.MAX_VALUE, 0); timeLimitSeconds.addLongIdentifier("timeLimit", true); timeLimitSeconds.addLongIdentifier("time-limit-seconds", true); timeLimitSeconds.addLongIdentifier("time-limit", true); timeLimitSeconds.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get()); parser.addArgument(timeLimitSeconds); final Set derefAllowedValues = StaticUtils.setOf("never", "always", "search", "find"); dereferencePolicy = new StringArgument('a', "dereferencePolicy", false, 1, "{never|always|search|find}", INFO_LDAPSEARCH_ARG_DESCRIPTION_DEREFERENCE_POLICY.get(), derefAllowedValues, "never"); dereferencePolicy.addLongIdentifier("dereference-policy", true); dereferencePolicy.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_OPS.get()); parser.addArgument(dereferencePolicy); typesOnly = new BooleanArgument('A', "typesOnly", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_TYPES_ONLY.get()); typesOnly.addLongIdentifier("types-only", true); typesOnly.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get()); parser.addArgument(typesOnly); requestedAttribute = new StringArgument(null, "requestedAttribute", false, 0, INFO_PLACEHOLDER_ATTR.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_REQUESTED_ATTR.get()); requestedAttribute.addLongIdentifier("requested-attribute", true); requestedAttribute.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_OPS.get()); parser.addArgument(requestedAttribute); filter = new FilterArgument(null, "filter", false, 0, INFO_PLACEHOLDER_FILTER.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_FILTER.get()); filter.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get()); parser.addArgument(filter); filterFile = new FileArgument('f', "filterFile", false, 0, null, INFO_LDAPSEARCH_ARG_DESCRIPTION_FILTER_FILE.get(), true, true, true, false); filterFile.addLongIdentifier("filename", true); filterFile.addLongIdentifier("filter-file", true); filterFile.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get()); parser.addArgument(filterFile); ldapURLFile = new FileArgument(null, "ldapURLFile", false, 0, null, INFO_LDAPSEARCH_ARG_DESCRIPTION_LDAP_URL_FILE.get(), true, true, true, false); ldapURLFile.addLongIdentifier("ldap-url-file", true); ldapURLFile.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get()); parser.addArgument(ldapURLFile); followReferrals = new BooleanArgument(null, "followReferrals", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_FOLLOW_REFERRALS.get()); followReferrals.addLongIdentifier("follow-referrals", true); followReferrals.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get()); parser.addArgument(followReferrals); retryFailedOperations = new BooleanArgument(null, "retryFailedOperations", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_RETRY_FAILED_OPERATIONS.get()); retryFailedOperations.addLongIdentifier("retry-failed-operations", true); retryFailedOperations.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_OPS.get()); parser.addArgument(retryFailedOperations); continueOnError = new BooleanArgument('c', "continueOnError", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_CONTINUE_ON_ERROR.get()); continueOnError.addLongIdentifier("continue-on-error", true); continueOnError.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get()); parser.addArgument(continueOnError); ratePerSecond = new IntegerArgument('r', "ratePerSecond", false, 1, INFO_PLACEHOLDER_NUM.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_RATE_PER_SECOND.get(), 1, Integer.MAX_VALUE); ratePerSecond.addLongIdentifier("rate-per-second", true); ratePerSecond.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get()); parser.addArgument(ratePerSecond); useAdministrativeSession = new BooleanArgument(null, "useAdministrativeSession", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_USE_ADMIN_SESSION.get()); useAdministrativeSession.addLongIdentifier("use-administrative-session", true); useAdministrativeSession.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_OPS.get()); parser.addArgument(useAdministrativeSession); dryRun = new BooleanArgument('n', "dryRun", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_DRY_RUN.get()); dryRun.addLongIdentifier("dry-run", true); dryRun.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get()); parser.addArgument(dryRun); wrapColumn = new IntegerArgument(null, "wrapColumn", false, 1, null, INFO_LDAPSEARCH_ARG_DESCRIPTION_WRAP_COLUMN.get(), 0, Integer.MAX_VALUE); wrapColumn.addLongIdentifier("wrap-column", true); wrapColumn.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_DATA.get()); parser.addArgument(wrapColumn); dontWrap = new BooleanArgument('T', "dontWrap", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_DONT_WRAP.get()); dontWrap.addLongIdentifier("doNotWrap", true); dontWrap.addLongIdentifier("dont-wrap", true); dontWrap.addLongIdentifier("do-not-wrap", true); dontWrap.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_DATA.get()); parser.addArgument(dontWrap); suppressBase64EncodedValueComments = new BooleanArgument(null, "suppressBase64EncodedValueComments", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_SUPPRESS_BASE64_COMMENTS.get()); suppressBase64EncodedValueComments.addLongIdentifier( "suppress-base64-encoded-value-comments", true); suppressBase64EncodedValueComments.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_DATA.get()); parser.addArgument(suppressBase64EncodedValueComments); countEntries = new BooleanArgument(null, "countEntries", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_COUNT_ENTRIES.get()); countEntries.addLongIdentifier("count-entries", true); countEntries.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get()); countEntries.setHidden(true); parser.addArgument(countEntries); outputFile = new FileArgument(null, "outputFile", false, 1, null, INFO_LDAPSEARCH_ARG_DESCRIPTION_OUTPUT_FILE.get(), false, true, true, false); outputFile.addLongIdentifier("output-file", true); outputFile.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_DATA.get()); parser.addArgument(outputFile); compressOutput = new BooleanArgument(null, "compressOutput", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_COMPRESS_OUTPUT.get()); compressOutput.addLongIdentifier("compress-output", true); compressOutput.addLongIdentifier("compress", true); compressOutput.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_DATA.get()); parser.addArgument(compressOutput); encryptOutput = new BooleanArgument(null, "encryptOutput", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_ENCRYPT_OUTPUT.get()); encryptOutput.addLongIdentifier("encrypt-output", true); encryptOutput.addLongIdentifier("encrypt", true); encryptOutput.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_DATA.get()); parser.addArgument(encryptOutput); encryptionPassphraseFile = new FileArgument(null, "encryptionPassphraseFile", false, 1, null, INFO_LDAPSEARCH_ARG_DESCRIPTION_ENCRYPTION_PW_FILE.get(), true, true, true, false); encryptionPassphraseFile.addLongIdentifier("encryption-passphrase-file", true); encryptionPassphraseFile.addLongIdentifier("encryptionPasswordFile", true); encryptionPassphraseFile.addLongIdentifier("encryption-password-file", true); encryptionPassphraseFile.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_DATA.get()); parser.addArgument(encryptionPassphraseFile); separateOutputFilePerSearch = new BooleanArgument(null, "separateOutputFilePerSearch", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_SEPARATE_OUTPUT_FILES.get()); separateOutputFilePerSearch.addLongIdentifier( "separate-output-file-per-search", true); separateOutputFilePerSearch.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_DATA.get()); parser.addArgument(separateOutputFilePerSearch); teeResultsToStandardOut = new BooleanArgument(null, "teeResultsToStandardOut", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_TEE.get("outputFile")); teeResultsToStandardOut.addLongIdentifier( "tee-results-to-standard-out", true); teeResultsToStandardOut.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_DATA.get()); parser.addArgument(teeResultsToStandardOut); final Set outputFormatAllowedValues = StaticUtils.setOf("ldif", "json", "csv", "multi-valued-csv", "tab-delimited", "multi-valued-tab-delimited", "dns-only", "values-only"); outputFormat = new StringArgument(null, "outputFormat", false, 1, "{ldif|json|csv|multi-valued-csv|tab-delimited|" + "multi-valued-tab-delimited|dns-only|values-only}", INFO_LDAPSEARCH_ARG_DESCRIPTION_OUTPUT_FORMAT.get( requestedAttribute.getIdentifierString(), ldapURLFile.getIdentifierString()), outputFormatAllowedValues, "ldif"); outputFormat.addLongIdentifier("output-format", true); outputFormat.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_DATA.get()); parser.addArgument(outputFormat); requireMatch = new BooleanArgument(null, "requireMatch", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_REQUIRE_MATCH.get( getToolName(), String.valueOf(ResultCode.NO_RESULTS_RETURNED))); requireMatch.addLongIdentifier("require-match", true); requireMatch.addLongIdentifier("requireMatchingEntry", true); requireMatch.addLongIdentifier("require-matching-entry", true); requireMatch.addLongIdentifier("requireMatchingEntries", true); requireMatch.addLongIdentifier("require-matching-entries", true); requireMatch.addLongIdentifier("requireEntry", true); requireMatch.addLongIdentifier("require-entry", true); requireMatch.addLongIdentifier("requireEntries", true); requireMatch.addLongIdentifier("require-entries", true); requireMatch.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_DATA.get()); parser.addArgument(requireMatch); terse = new BooleanArgument(null, "terse", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_TERSE.get()); terse.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_DATA.get()); parser.addArgument(terse); verbose = new BooleanArgument('v', "verbose", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_VERBOSE.get()); verbose.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_DATA.get()); parser.addArgument(verbose); bindControl = new ControlArgument(null, "bindControl", false, 0, null, INFO_LDAPSEARCH_ARG_DESCRIPTION_BIND_CONTROL.get()); bindControl.addLongIdentifier("bind-control", true); bindControl.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(bindControl); searchControl = new ControlArgument('J', "control", false, 0, null, INFO_LDAPSEARCH_ARG_DESCRIPTION_SEARCH_CONTROL.get()); searchControl.addLongIdentifier("searchControl", true); searchControl.addLongIdentifier("search-control", true); searchControl.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(searchControl); accessLogField = new StringArgument(null, "accessLogField", false, 0, INFO_LDAPSEARCH_ARG_PLACEHOLDER_NAME_VALUE.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_ACCESS_LOG_FIELD.get()); accessLogField.addLongIdentifier("access-log-field", true); accessLogField.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(accessLogField); accountUsable = new BooleanArgument(null, "accountUsable", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_ACCOUNT_USABLE.get()); accountUsable.addLongIdentifier("account-usable", true); accountUsable.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(accountUsable); authorizationIdentity = new BooleanArgument('E', "authorizationIdentity", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_AUTHZ_IDENTITY.get()); authorizationIdentity.addLongIdentifier("reportAuthzID", true); authorizationIdentity.addLongIdentifier("authorization-identity", true); authorizationIdentity.addLongIdentifier("report-authzid", true); authorizationIdentity.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(authorizationIdentity); assertionFilter = new FilterArgument(null, "assertionFilter", false, 1, INFO_PLACEHOLDER_FILTER.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_ASSERTION_FILTER.get()); assertionFilter.addLongIdentifier("assertion-filter", true); assertionFilter.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(assertionFilter); excludeBranch = new DNArgument(null, "excludeBranch", false, 0, null, INFO_LDAPSEARCH_ARG_DESCRIPTION_EXCLUDE_BRANCH.get()); excludeBranch.addLongIdentifier("exclude-branch", true); excludeBranch.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(excludeBranch); generateAccessToken = new BooleanArgument(null, "generateAccessToken", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_GENERATE_ACCESS_TOKEN.get()); generateAccessToken.addLongIdentifier("generate-access-token", true); generateAccessToken.addLongIdentifier("requestAccessToken", true); generateAccessToken.addLongIdentifier("request-access-token", true); generateAccessToken.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(generateAccessToken); getAuthorizationEntryAttribute = new StringArgument(null, "getAuthorizationEntryAttribute", false, 0, INFO_PLACEHOLDER_ATTR.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_GET_AUTHZ_ENTRY_ATTR.get()); getAuthorizationEntryAttribute.addLongIdentifier( "get-authorization-entry-attribute", true); getAuthorizationEntryAttribute.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(getAuthorizationEntryAttribute); getBackendSetID = new BooleanArgument(null, "getBackendSetID", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_GET_BACKEND_SET_ID.get()); getBackendSetID.addLongIdentifier("get-backend-set-id", true); getBackendSetID.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(getBackendSetID); getEffectiveRightsAuthzID = new StringArgument('g', "getEffectiveRightsAuthzID", false, 1, INFO_PLACEHOLDER_AUTHZID.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_GET_EFFECTIVE_RIGHTS_AUTHZID.get( "getEffectiveRightsAttribute")); getEffectiveRightsAuthzID.addLongIdentifier( "get-effective-rights-authzid", true); getEffectiveRightsAuthzID.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(getEffectiveRightsAuthzID); getEffectiveRightsAttribute = new StringArgument('e', "getEffectiveRightsAttribute", false, 0, INFO_PLACEHOLDER_ATTR.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_GET_EFFECTIVE_RIGHTS_ATTR.get()); getEffectiveRightsAttribute.addLongIdentifier( "get-effective-rights-attribute", true); getEffectiveRightsAttribute.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(getEffectiveRightsAttribute); getRecentLoginHistory = new BooleanArgument(null, "getRecentLoginHistory", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_GET_RECENT_LOGIN_HISTORY.get()); getRecentLoginHistory.addLongIdentifier("get-recent-login-history", true); getRecentLoginHistory.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(getRecentLoginHistory); getServerID = new BooleanArgument(null, "getServerID", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_GET_SERVER_ID.get()); getServerID.addLongIdentifier("get-server-id", true); getServerID.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(getServerID); getUserResourceLimits = new BooleanArgument(null, "getUserResourceLimits", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_GET_USER_RESOURCE_LIMITS.get()); getUserResourceLimits.addLongIdentifier("get-user-resource-limits", true); getUserResourceLimits.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(getUserResourceLimits); includeReplicationConflictEntries = new BooleanArgument(null, "includeReplicationConflictEntries", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_INCLUDE_REPL_CONFLICTS.get()); includeReplicationConflictEntries.addLongIdentifier( "include-replication-conflict-entries", true); includeReplicationConflictEntries.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(includeReplicationConflictEntries); final Set softDeleteAllowedValues = StaticUtils.setOf( "with-non-deleted-entries", "without-non-deleted-entries", "deleted-entries-in-undeleted-form"); includeSoftDeletedEntries = new StringArgument(null, "includeSoftDeletedEntries", false, 1, "{with-non-deleted-entries|without-non-deleted-entries|" + "deleted-entries-in-undeleted-form}", INFO_LDAPSEARCH_ARG_DESCRIPTION_INCLUDE_SOFT_DELETED.get(), softDeleteAllowedValues); includeSoftDeletedEntries.addLongIdentifier( "include-soft-deleted-entries", true); includeSoftDeletedEntries.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(includeSoftDeletedEntries); draftLDUPSubentries = new BooleanArgument(null, "draftLDUPSubentries", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_INCLUDE_DRAFT_LDUP_SUBENTRIES.get()); draftLDUPSubentries.addLongIdentifier("draftIETFLDUPSubentries", true); draftLDUPSubentries.addLongIdentifier("includeSubentries", true); draftLDUPSubentries.addLongIdentifier("includeLDAPSubentries", true); draftLDUPSubentries.addLongIdentifier("draft-ldup-subentries", true); draftLDUPSubentries.addLongIdentifier("draft-ietf-ldup-subentries", true); draftLDUPSubentries.addLongIdentifier("include-subentries", true); draftLDUPSubentries.addLongIdentifier("include-ldap-subentries", true); draftLDUPSubentries.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(draftLDUPSubentries); rfc3672Subentries = new BooleanValueArgument(null, "rfc3672Subentries", false, INFO_LDAPSEARCH_ARG_PLACEHOLDER_INCLUDE_RFC_3672_SUBENTRIES.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_INCLUDE_RFC_3672_SUBENTRIES.get()); rfc3672Subentries.addLongIdentifier("rfc-3672-subentries", true); rfc3672Subentries.addLongIdentifier("rfc3672-subentries", true); rfc3672Subentries.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(rfc3672Subentries); joinRule = new StringArgument(null, "joinRule", false, 1, "{dn:sourceAttr|reverse-dn:targetAttr|equals:sourceAttr:targetAttr|" + "contains:sourceAttr:targetAttr }", INFO_LDAPSEARCH_ARG_DESCRIPTION_JOIN_RULE.get()); joinRule.addLongIdentifier("join-rule", true); joinRule.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(joinRule); joinBaseDN = new StringArgument(null, "joinBaseDN", false, 1, "{search-base|source-entry-dn|{dn}}", INFO_LDAPSEARCH_ARG_DESCRIPTION_JOIN_BASE_DN.get()); joinBaseDN.addLongIdentifier("join-base-dn", true); joinBaseDN.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(joinBaseDN); joinScope = new ScopeArgument(null, "joinScope", false, null, INFO_LDAPSEARCH_ARG_DESCRIPTION_JOIN_SCOPE.get()); joinScope.addLongIdentifier("join-scope", true); joinScope.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(joinScope); joinSizeLimit = new IntegerArgument(null, "joinSizeLimit", false, 1, INFO_PLACEHOLDER_NUM.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_JOIN_SIZE_LIMIT.get(), 0, Integer.MAX_VALUE); joinSizeLimit.addLongIdentifier("join-size-limit", true); joinSizeLimit.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(joinSizeLimit); joinFilter = new FilterArgument(null, "joinFilter", false, 1, null, INFO_LDAPSEARCH_ARG_DESCRIPTION_JOIN_FILTER.get()); joinFilter.addLongIdentifier("join-filter", true); joinFilter.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(joinFilter); joinRequestedAttribute = new StringArgument(null, "joinRequestedAttribute", false, 0, INFO_PLACEHOLDER_ATTR.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_JOIN_ATTR.get()); joinRequestedAttribute.addLongIdentifier("join-requested-attribute", true); joinRequestedAttribute.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(joinRequestedAttribute); joinRequireMatch = new BooleanArgument(null, "joinRequireMatch", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_JOIN_REQUIRE_MATCH.get()); joinRequireMatch.addLongIdentifier("join-require-match", true); joinRequireMatch.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(joinRequireMatch); manageDsaIT = new BooleanArgument(null, "manageDsaIT", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_MANAGE_DSA_IT.get()); manageDsaIT.addLongIdentifier("manage-dsa-it", true); manageDsaIT.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(manageDsaIT); matchedValuesFilter = new FilterArgument(null, "matchedValuesFilter", false, 0, INFO_PLACEHOLDER_FILTER.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_MATCHED_VALUES_FILTER.get()); matchedValuesFilter.addLongIdentifier("matched-values-filter", true); matchedValuesFilter.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(matchedValuesFilter); matchingEntryCountControl = new StringArgument(null, "matchingEntryCountControl", false, 1, "{examineCount=NNN[:alwaysExamine][:allowUnindexed]" + "[:skipResolvingExplodedIndexes]" + "[:fastShortCircuitThreshold=NNN]" + "[:slowShortCircuitThreshold=NNN][:extendedResponseData]" + "[:debug]}", INFO_LDAPSEARCH_ARG_DESCRIPTION_MATCHING_ENTRY_COUNT_CONTROL.get()); matchingEntryCountControl.addLongIdentifier("matchingEntryCount", true); matchingEntryCountControl.addLongIdentifier( "matching-entry-count-control", true); matchingEntryCountControl.addLongIdentifier("matching-entry-count", true); matchingEntryCountControl.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(matchingEntryCountControl); operationPurpose = new StringArgument(null, "operationPurpose", false, 1, INFO_PLACEHOLDER_PURPOSE.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_OPERATION_PURPOSE.get()); operationPurpose.addLongIdentifier("operation-purpose", true); operationPurpose.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(operationPurpose); overrideSearchLimit = new StringArgument(null, "overrideSearchLimit", false, 0, INFO_LDAPSEARCH_NAME_VALUE_PLACEHOLDER.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_OVERRIDE_SEARCH_LIMIT.get()); overrideSearchLimit.addLongIdentifier("overrideSearchLimits", true); overrideSearchLimit.addLongIdentifier("override-search-limit", true); overrideSearchLimit.addLongIdentifier("override-search-limits", true); overrideSearchLimit.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(overrideSearchLimit); persistentSearch = new StringArgument('C', "persistentSearch", false, 1, "ps[:changetype[:changesonly[:entrychgcontrols]]]", INFO_LDAPSEARCH_ARG_DESCRIPTION_PERSISTENT_SEARCH.get()); persistentSearch.addLongIdentifier("persistent-search", true); persistentSearch.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(persistentSearch); permitUnindexedSearch = new BooleanArgument(null, "permitUnindexedSearch", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_PERMIT_UNINDEXED_SEARCH.get()); permitUnindexedSearch.addLongIdentifier("permitUnindexedSearches", true); permitUnindexedSearch.addLongIdentifier("permitUnindexed", true); permitUnindexedSearch.addLongIdentifier("permitIfUnindexed", true); permitUnindexedSearch.addLongIdentifier("permit-unindexed-search", true); permitUnindexedSearch.addLongIdentifier("permit-unindexed-searches", true); permitUnindexedSearch.addLongIdentifier("permit-unindexed", true); permitUnindexedSearch.addLongIdentifier("permit-if-unindexed", true); permitUnindexedSearch.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(permitUnindexedSearch); proxyAs = new StringArgument('Y', "proxyAs", false, 1, INFO_PLACEHOLDER_AUTHZID.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_PROXY_AS.get()); proxyAs.addLongIdentifier("proxy-as", true); proxyAs.addLongIdentifier("proxyV2As", true); proxyAs.addLongIdentifier("proxy-v2-as", true); proxyAs.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(proxyAs); proxyV1As = new DNArgument(null, "proxyV1As", false, 1, null, INFO_LDAPSEARCH_ARG_DESCRIPTION_PROXY_V1_AS.get()); proxyV1As.addLongIdentifier("proxy-v1-as", true); proxyV1As.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(proxyV1As); rejectUnindexedSearch = new BooleanArgument(null, "rejectUnindexedSearch", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_REJECT_UNINDEXED_SEARCH.get()); rejectUnindexedSearch.addLongIdentifier("rejectUnindexedSearches", true); rejectUnindexedSearch.addLongIdentifier("rejectUnindexed", true); rejectUnindexedSearch.addLongIdentifier("rejectIfUnindexed", true); rejectUnindexedSearch.addLongIdentifier("reject-unindexed-search", true); rejectUnindexedSearch.addLongIdentifier("reject-unindexed-searches", true); rejectUnindexedSearch.addLongIdentifier("reject-unindexed", true); rejectUnindexedSearch.addLongIdentifier("reject-if-unindexed", true); rejectUnindexedSearch.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(rejectUnindexedSearch); routeToBackendSet = new StringArgument(null, "routeToBackendSet", false, 0, INFO_LDAPSEARCH_ARG_PLACEHOLDER_ROUTE_TO_BACKEND_SET.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_ROUTE_TO_BACKEND_SET.get()); routeToBackendSet.addLongIdentifier("route-to-backend-set", true); routeToBackendSet.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(routeToBackendSet); routeToServer = new StringArgument(null, "routeToServer", false, 1, INFO_LDAPSEARCH_ARG_PLACEHOLDER_ROUTE_TO_SERVER.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_ROUTE_TO_SERVER.get()); routeToServer.addLongIdentifier("route-to-server", true); routeToServer.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(routeToServer); final Set suppressOperationalAttributeUpdatesAllowedValues = StaticUtils.setOf("last-access-time", "last-login-time", "last-login-ip", "lastmod"); suppressOperationalAttributeUpdates = new StringArgument(null, "suppressOperationalAttributeUpdates", false, -1, INFO_PLACEHOLDER_ATTR.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_SUPPRESS_OP_ATTR_UPDATES.get(), suppressOperationalAttributeUpdatesAllowedValues); suppressOperationalAttributeUpdates.addLongIdentifier( "suppress-operational-attribute-updates", true); suppressOperationalAttributeUpdates.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(suppressOperationalAttributeUpdates); usePasswordPolicyControl = new BooleanArgument(null, "usePasswordPolicyControl", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_PASSWORD_POLICY.get()); usePasswordPolicyControl.addLongIdentifier("use-password-policy-control", true); usePasswordPolicyControl.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(usePasswordPolicyControl); realAttributesOnly = new BooleanArgument(null, "realAttributesOnly", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_REAL_ATTRS_ONLY.get()); realAttributesOnly.addLongIdentifier("real-attributes-only", true); realAttributesOnly.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(realAttributesOnly); sortOrder = new StringArgument('S', "sortOrder", false, 1, null, INFO_LDAPSEARCH_ARG_DESCRIPTION_SORT_ORDER.get()); sortOrder.addLongIdentifier("sort-order", true); sortOrder.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(sortOrder); simplePageSize = new IntegerArgument(null, "simplePageSize", false, 1, null, INFO_LDAPSEARCH_ARG_DESCRIPTION_PAGE_SIZE.get(), 1, Integer.MAX_VALUE); simplePageSize.addLongIdentifier("simple-page-size", true); simplePageSize.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(simplePageSize); virtualAttributesOnly = new BooleanArgument(null, "virtualAttributesOnly", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_VIRTUAL_ATTRS_ONLY.get()); virtualAttributesOnly.addLongIdentifier("virtual-attributes-only", true); virtualAttributesOnly.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(virtualAttributesOnly); virtualListView = new StringArgument('G', "virtualListView", false, 1, "{before:after:index:count | before:after:value}", INFO_LDAPSEARCH_ARG_DESCRIPTION_VLV.get("sortOrder")); virtualListView.addLongIdentifier("vlv", true); virtualListView.addLongIdentifier("virtual-list-view", true); virtualListView.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(virtualListView); useJSONFormattedRequestControls = new BooleanArgument(null, "useJSONFormattedRequestControls", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_USE_JSON_FORMATTED_CONTROLS.get()); useJSONFormattedRequestControls.addLongIdentifier( "use-json-formatted-request-controls", true); useJSONFormattedRequestControls.addLongIdentifier( "useJSONFormattedControls", true); useJSONFormattedRequestControls.addLongIdentifier( "use-json-formatted-controls", true); useJSONFormattedRequestControls.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get()); parser.addArgument(useJSONFormattedRequestControls); excludeAttribute = new StringArgument(null, "excludeAttribute", false, 0, INFO_PLACEHOLDER_ATTR.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_EXCLUDE_ATTRIBUTE.get()); excludeAttribute.addLongIdentifier("exclude-attribute", true); excludeAttribute.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_TRANSFORMATIONS.get()); parser.addArgument(excludeAttribute); redactAttribute = new StringArgument(null, "redactAttribute", false, 0, INFO_PLACEHOLDER_ATTR.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_REDACT_ATTRIBUTE.get()); redactAttribute.addLongIdentifier("redact-attribute", true); redactAttribute.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_TRANSFORMATIONS.get()); parser.addArgument(redactAttribute); hideRedactedValueCount = new BooleanArgument(null, "hideRedactedValueCount", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_HIDE_REDACTED_VALUE_COUNT.get()); hideRedactedValueCount.addLongIdentifier("hide-redacted-value-count", true); hideRedactedValueCount.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_TRANSFORMATIONS.get()); parser.addArgument(hideRedactedValueCount); scrambleAttribute = new StringArgument(null, "scrambleAttribute", false, 0, INFO_PLACEHOLDER_ATTR.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_SCRAMBLE_ATTRIBUTE.get()); scrambleAttribute.addLongIdentifier("scramble-attribute", true); scrambleAttribute.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_TRANSFORMATIONS.get()); parser.addArgument(scrambleAttribute); scrambleJSONField = new StringArgument(null, "scrambleJSONField", false, 0, INFO_PLACEHOLDER_FIELD_NAME.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_SCRAMBLE_JSON_FIELD.get()); scrambleJSONField.addLongIdentifier("scramble-json-field", true); scrambleJSONField.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_TRANSFORMATIONS.get()); parser.addArgument(scrambleJSONField); scrambleRandomSeed = new IntegerArgument(null, "scrambleRandomSeed", false, 1, null, INFO_LDAPSEARCH_ARG_DESCRIPTION_SCRAMBLE_RANDOM_SEED.get()); scrambleRandomSeed.addLongIdentifier("scramble-random-seed", true); scrambleRandomSeed.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_TRANSFORMATIONS.get()); parser.addArgument(scrambleRandomSeed); renameAttributeFrom = new StringArgument(null, "renameAttributeFrom", false, 0, INFO_PLACEHOLDER_ATTR.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_RENAME_ATTRIBUTE_FROM.get()); renameAttributeFrom.addLongIdentifier("rename-attribute-from", true); renameAttributeFrom.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_TRANSFORMATIONS.get()); parser.addArgument(renameAttributeFrom); renameAttributeTo = new StringArgument(null, "renameAttributeTo", false, 0, INFO_PLACEHOLDER_ATTR.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_RENAME_ATTRIBUTE_TO.get()); renameAttributeTo.addLongIdentifier("rename-attribute-to", true); renameAttributeTo.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_TRANSFORMATIONS.get()); parser.addArgument(renameAttributeTo); moveSubtreeFrom = new DNArgument(null, "moveSubtreeFrom", false, 0, INFO_PLACEHOLDER_ATTR.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_MOVE_SUBTREE_FROM.get()); moveSubtreeFrom.addLongIdentifier("move-subtree-from", true); moveSubtreeFrom.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_TRANSFORMATIONS.get()); parser.addArgument(moveSubtreeFrom); moveSubtreeTo = new DNArgument(null, "moveSubtreeTo", false, 0, INFO_PLACEHOLDER_ATTR.get(), INFO_LDAPSEARCH_ARG_DESCRIPTION_MOVE_SUBTREE_TO.get()); moveSubtreeTo.addLongIdentifier("move-subtree-to", true); moveSubtreeTo.setArgumentGroupName( INFO_LDAPSEARCH_ARG_GROUP_TRANSFORMATIONS.get()); parser.addArgument(moveSubtreeTo); // The "--scriptFriendly" argument is provided for compatibility with legacy // ldapsearch tools, but is not actually used by this tool. final BooleanArgument scriptFriendly = new BooleanArgument(null, "scriptFriendly", 1, INFO_LDAPSEARCH_ARG_DESCRIPTION_SCRIPT_FRIENDLY.get()); scriptFriendly.addLongIdentifier("script-friendly", true); scriptFriendly.setHidden(true); parser.addArgument(scriptFriendly); // The "-V" / "--ldapVersion" argument is provided for compatibility with // legacy ldapsearch tools, but is not actually used by this tool. final IntegerArgument ldapVersion = new IntegerArgument('V', "ldapVersion", false, 1, null, INFO_LDAPSEARCH_ARG_DESCRIPTION_LDAP_VERSION.get()); ldapVersion.addLongIdentifier("ldap-version", true); ldapVersion.setHidden(true); parser.addArgument(ldapVersion); // The baseDN and ldapURLFile arguments can't be used together. parser.addExclusiveArgumentSet(baseDN, ldapURLFile); // The scope and ldapURLFile arguments can't be used together. parser.addExclusiveArgumentSet(scope, ldapURLFile); // The requestedAttribute and ldapURLFile arguments can't be used together. parser.addExclusiveArgumentSet(requestedAttribute, ldapURLFile); // The filter and ldapURLFile arguments can't be used together. parser.addExclusiveArgumentSet(filter, ldapURLFile); // The filterFile and ldapURLFile arguments can't be used together. parser.addExclusiveArgumentSet(filterFile, ldapURLFile); // The followReferrals and manageDsaIT arguments can't be used together. parser.addExclusiveArgumentSet(followReferrals, manageDsaIT); // The persistent search argument can't be used with either the filterFile // or ldapURLFile arguments. parser.addExclusiveArgumentSet(persistentSearch, filterFile); parser.addExclusiveArgumentSet(persistentSearch, ldapURLFile); // The draft-ietf-ldup-subentry and RFC 3672 subentries controls cannot be // used together. parser.addExclusiveArgumentSet(draftLDUPSubentries, rfc3672Subentries); // The realAttributesOnly and virtualAttributesOnly arguments can't be used // together. parser.addExclusiveArgumentSet(realAttributesOnly, virtualAttributesOnly); // The simplePageSize and virtualListView arguments can't be used together. parser.addExclusiveArgumentSet(simplePageSize, virtualListView); // The terse and verbose arguments can't be used together. parser.addExclusiveArgumentSet(terse, verbose); // The getEffectiveRightsAttribute argument requires the // getEffectiveRightsAuthzID argument. parser.addDependentArgumentSet(getEffectiveRightsAttribute, getEffectiveRightsAuthzID); // The virtualListView argument requires the sortOrder argument. parser.addDependentArgumentSet(virtualListView, sortOrder); // The rejectUnindexedSearch and permitUnindexedSearch arguments can't be // used together. parser.addExclusiveArgumentSet(rejectUnindexedSearch, permitUnindexedSearch); // The separateOutputFilePerSearch argument requires the outputFile // argument. It also requires either the filter, filterFile or ldapURLFile // argument. parser.addDependentArgumentSet(separateOutputFilePerSearch, outputFile); parser.addDependentArgumentSet(separateOutputFilePerSearch, filter, filterFile, ldapURLFile); // The teeResultsToStandardOut argument requires the outputFile argument. parser.addDependentArgumentSet(teeResultsToStandardOut, outputFile); // The wrapColumn and dontWrap arguments must not be used together. parser.addExclusiveArgumentSet(wrapColumn, dontWrap); // All arguments that specifically pertain to join processing can only be // used if the joinRule argument is provided. parser.addDependentArgumentSet(joinBaseDN, joinRule); parser.addDependentArgumentSet(joinScope, joinRule); parser.addDependentArgumentSet(joinSizeLimit, joinRule); parser.addDependentArgumentSet(joinFilter, joinRule); parser.addDependentArgumentSet(joinRequestedAttribute, joinRule); parser.addDependentArgumentSet(joinRequireMatch, joinRule); // The countEntries argument must not be used in conjunction with the // filter, filterFile, LDAPURLFile, or persistentSearch arguments. parser.addExclusiveArgumentSet(countEntries, filter); parser.addExclusiveArgumentSet(countEntries, filterFile); parser.addExclusiveArgumentSet(countEntries, ldapURLFile); parser.addExclusiveArgumentSet(countEntries, persistentSearch); // The hideRedactedValueCount argument requires the redactAttribute // argument. parser.addDependentArgumentSet(hideRedactedValueCount, redactAttribute); // The scrambleJSONField and scrambleRandomSeed arguments require the // scrambleAttribute argument. parser.addDependentArgumentSet(scrambleJSONField, scrambleAttribute); parser.addDependentArgumentSet(scrambleRandomSeed, scrambleAttribute); // The renameAttributeFrom and renameAttributeTo arguments must be provided // together. parser.addDependentArgumentSet(renameAttributeFrom, renameAttributeTo); parser.addDependentArgumentSet(renameAttributeTo, renameAttributeFrom); // The moveSubtreeFrom and moveSubtreeTo arguments must be provided // together. parser.addDependentArgumentSet(moveSubtreeFrom, moveSubtreeTo); parser.addDependentArgumentSet(moveSubtreeTo, moveSubtreeFrom); // The compressOutput argument can only be used if an output file is // specified and results aren't going to be teed. parser.addDependentArgumentSet(compressOutput, outputFile); parser.addExclusiveArgumentSet(compressOutput, teeResultsToStandardOut); // The encryptOutput argument can only be used if an output file is // specified and results aren't going to be teed. parser.addDependentArgumentSet(encryptOutput, outputFile); parser.addExclusiveArgumentSet(encryptOutput, teeResultsToStandardOut); // The encryptionPassphraseFile argument can only be used if the // encryptOutput argument is also provided. parser.addDependentArgumentSet(encryptionPassphraseFile, encryptOutput); } /** * {@inheritDoc} */ @Override() @NotNull() protected List getBindControls() { final ArrayList bindControls = new ArrayList<>(10); if (bindControl.isPresent()) { bindControls.addAll(bindControl.getValues()); } if (authorizationIdentity.isPresent()) { bindControls.add(new AuthorizationIdentityRequestControl(false)); } if (generateAccessToken.isPresent()) { bindControls.add(new GenerateAccessTokenRequestControl()); } if (getAuthorizationEntryAttribute.isPresent()) { bindControls.add(new GetAuthorizationEntryRequestControl(true, true, getAuthorizationEntryAttribute.getValues())); } if (getRecentLoginHistory.isPresent()) { bindControls.add(new GetRecentLoginHistoryRequestControl()); } if (getUserResourceLimits.isPresent()) { bindControls.add(new GetUserResourceLimitsRequestControl()); } if (usePasswordPolicyControl.isPresent()) { bindControls.add(new PasswordPolicyRequestControl()); } if (suppressOperationalAttributeUpdates.isPresent()) { final EnumSet suppressTypes = EnumSet.noneOf(SuppressType.class); for (final String s : suppressOperationalAttributeUpdates.getValues()) { if (s.equalsIgnoreCase("last-access-time")) { suppressTypes.add(SuppressType.LAST_ACCESS_TIME); } else if (s.equalsIgnoreCase("last-login-time")) { suppressTypes.add(SuppressType.LAST_LOGIN_TIME); } else if (s.equalsIgnoreCase("last-login-ip")) { suppressTypes.add(SuppressType.LAST_LOGIN_IP); } } bindControls.add(new SuppressOperationalAttributeUpdateRequestControl( suppressTypes)); } if (useJSONFormattedRequestControls.isPresent()) { final JSONFormattedRequestControl jsonFormattedRequestControl = JSONFormattedRequestControl.createWithControls(true, bindControls); bindControls.clear(); bindControls.add(jsonFormattedRequestControl); } return bindControls; } /** * {@inheritDoc} */ @Override() protected boolean supportsMultipleServers() { // We will support providing information about multiple servers. This tool // will not communicate with multiple servers concurrently, but it can // accept information about multiple servers in the event that multiple // searches are to be performed and a server goes down in the middle of // those searches. In this case, we can resume processing on a // newly-created connection, possibly to a different server. return true; } /** * {@inheritDoc} */ @Override() public void doExtendedNonLDAPArgumentValidation() throws ArgumentException { // If wrapColumn was provided, then use its value. Otherwise, if dontWrap // was provided, then use that. if (wrapColumn.isPresent()) { final int wc = wrapColumn.getValue(); if (wc <= 0) { WRAP_COLUMN = Integer.MAX_VALUE; } else { WRAP_COLUMN = wc; } } else if (dontWrap.isPresent()) { WRAP_COLUMN = Integer.MAX_VALUE; } // If the ldapURLFile argument was provided, then there must not be any // trailing arguments. final List trailingArgs = parser.getTrailingArguments(); if (ldapURLFile.isPresent()) { if (! trailingArgs.isEmpty()) { throw new ArgumentException( ERR_LDAPSEARCH_TRAILING_ARGS_WITH_URL_FILE.get( ldapURLFile.getIdentifierString())); } } // If the filter or filterFile argument was provided, then there may // optionally be trailing arguments, but the first trailing argument must // not be a filter. if (filter.isPresent() || filterFile.isPresent()) { if (! trailingArgs.isEmpty()) { try { Filter.create(trailingArgs.get(0)); throw new ArgumentException( ERR_LDAPSEARCH_TRAILING_FILTER_WITH_FILTER_FILE.get( filterFile.getIdentifierString())); } catch (final LDAPException le) { // This is the normal condition. Not even worth debugging the // exception. } } } // If none of the ldapURLFile, filter, or filterFile arguments was provided, // then there must be at least one trailing argument, and the first trailing // argument must be a valid search filter. if (! (ldapURLFile.isPresent() || filter.isPresent() || filterFile.isPresent())) { if (trailingArgs.isEmpty()) { throw new ArgumentException(ERR_LDAPSEARCH_NO_TRAILING_ARGS.get( filterFile.getIdentifierString(), ldapURLFile.getIdentifierString())); } try { Filter.create(trailingArgs.get(0)); } catch (final Exception e) { Debug.debugException(e); throw new ArgumentException( ERR_LDAPSEARCH_FIRST_TRAILING_ARG_NOT_FILTER.get( trailingArgs.get(0)), e); } } // There should never be a case in which a trailing argument starts with a // dash, and it's probably an attempt to use a named argument but that was // inadvertently put after the filter. Warn about the problem, but don't // fail. for (final String s : trailingArgs) { if (s.startsWith("-")) { commentToErr(WARN_LDAPSEARCH_TRAILING_ARG_STARTS_WITH_DASH.get(s)); break; } } // If any matched values filters are specified, then validate them and // pre-create the matched values request control. if (matchedValuesFilter.isPresent()) { final List filterList = matchedValuesFilter.getValues(); final MatchedValuesFilter[] matchedValuesFilters = new MatchedValuesFilter[filterList.size()]; for (int i=0; i < matchedValuesFilters.length; i++) { try { matchedValuesFilters[i] = MatchedValuesFilter.create(filterList.get(i)); } catch (final Exception e) { Debug.debugException(e); throw new ArgumentException( ERR_LDAPSEARCH_INVALID_MATCHED_VALUES_FILTER.get( filterList.get(i).toString()), e); } } matchedValuesRequestControl = new MatchedValuesRequestControl(true, matchedValuesFilters); } // If we should use the matching entry count request control, then validate // the argument value and pre-create the control. if (matchingEntryCountControl.isPresent()) { final MatchingEntryCountRequestControlProperties properties = new MatchingEntryCountRequestControlProperties(); Integer examineCount = null; try { for (final String element : matchingEntryCountControl.getValue().toLowerCase().split(":")) { if (element.startsWith("examinecount=")) { examineCount = Integer.parseInt(element.substring(13)); } else if (element.equals("allowunindexed")) { properties.setProcessSearchIfUnindexed(true); } else if (element.equals("alwaysexamine")) { properties.setAlwaysExamineCandidates(true); } else if (element.equals("skipresolvingexplodedindexes")) { properties.setSkipResolvingExplodedIndexes(true); } else if (element.startsWith("fastshortcircuitthreshold=")) { properties.setFastShortCircuitThreshold( Long.parseLong(element.substring(26))); } else if (element.startsWith("slowshortcircuitthreshold=")) { properties.setSlowShortCircuitThreshold( Long.parseLong(element.substring(26))); } else if (element.equals("extendedresponsedata")) { properties.setIncludeExtendedResponseData(true); } else if (element.equals("debug")) { properties.setIncludeDebugInfo(true); } else { throw new ArgumentException( ERR_LDAPSEARCH_MATCHING_ENTRY_COUNT_INVALID_VALUE.get( matchingEntryCountControl.getIdentifierString())); } } } catch (final ArgumentException ae) { Debug.debugException(ae); throw ae; } catch (final Exception e) { Debug.debugException(e); throw new ArgumentException( ERR_LDAPSEARCH_MATCHING_ENTRY_COUNT_INVALID_VALUE.get( matchingEntryCountControl.getIdentifierString()), e); } if (examineCount == null) { throw new ArgumentException( ERR_LDAPSEARCH_MATCHING_ENTRY_COUNT_INVALID_VALUE.get( matchingEntryCountControl.getIdentifierString())); } else { properties.setMaxCandidatesToExamine(examineCount); } matchingEntryCountRequestControl = new MatchingEntryCountRequestControl(true, properties); } // If we should include the override search limits request control, then // validate the provided values. if (overrideSearchLimit.isPresent()) { final LinkedHashMap properties = new LinkedHashMap<>(StaticUtils.computeMapCapacity(10)); for (final String value : overrideSearchLimit.getValues()) { final int equalPos = value.indexOf('='); if (equalPos < 0) { throw new ArgumentException( ERR_LDAPSEARCH_OVERRIDE_LIMIT_NO_EQUAL.get( overrideSearchLimit.getIdentifierString())); } else if (equalPos == 0) { throw new ArgumentException( ERR_LDAPSEARCH_OVERRIDE_LIMIT_EMPTY_PROPERTY_NAME.get( overrideSearchLimit.getIdentifierString())); } final String propertyName = value.substring(0, equalPos); if (properties.containsKey(propertyName)) { throw new ArgumentException( ERR_LDAPSEARCH_OVERRIDE_LIMIT_DUPLICATE_PROPERTY_NAME.get( overrideSearchLimit.getIdentifierString(), propertyName)); } if (equalPos == (value.length() - 1)) { throw new ArgumentException( ERR_LDAPSEARCH_OVERRIDE_LIMIT_EMPTY_PROPERTY_VALUE.get( overrideSearchLimit.getIdentifierString(), propertyName)); } properties.put(propertyName, value.substring(equalPos+1)); } overrideSearchLimitsRequestControl = new OverrideSearchLimitsRequestControl(properties, false); } // If we should use the persistent search request control, then validate // the argument value and pre-create the control. if (persistentSearch.isPresent()) { boolean changesOnly = true; boolean returnECs = true; EnumSet changeTypes = EnumSet.allOf(PersistentSearchChangeType.class); try { final String[] elements = persistentSearch.getValue().toLowerCase().split(":"); if (elements.length == 0) { throw new ArgumentException( ERR_LDAPSEARCH_PERSISTENT_SEARCH_INVALID_VALUE.get( persistentSearch.getIdentifierString())); } final String header = StaticUtils.toLowerCase(elements[0]); if (! (header.equals("ps") || header.equals("persist") || header.equals("persistent") || header.equals("psearch") || header.equals("persistentsearch"))) { throw new ArgumentException( ERR_LDAPSEARCH_PERSISTENT_SEARCH_INVALID_VALUE.get( persistentSearch.getIdentifierString())); } if (elements.length > 1) { final String ctString = StaticUtils.toLowerCase(elements[1]); if (ctString.equals("any")) { changeTypes = EnumSet.allOf(PersistentSearchChangeType.class); } else { changeTypes.clear(); for (final String t : ctString.split(",")) { if (t.equals("add")) { changeTypes.add(PersistentSearchChangeType.ADD); } else if (t.equals("del") || t.equals("delete")) { changeTypes.add(PersistentSearchChangeType.DELETE); } else if (t.equals("mod") || t.equals("modify")) { changeTypes.add(PersistentSearchChangeType.MODIFY); } else if (t.equals("moddn") || t.equals("modrdn") || t.equals("modifydn") || t.equals("modifyrdn")) { changeTypes.add(PersistentSearchChangeType.MODIFY_DN); } else { throw new ArgumentException( ERR_LDAPSEARCH_PERSISTENT_SEARCH_INVALID_VALUE.get( persistentSearch.getIdentifierString())); } } } } if (elements.length > 2) { if (elements[2].equalsIgnoreCase("true") || elements[2].equals("1")) { changesOnly = true; } else if (elements[2].equalsIgnoreCase("false") || elements[2].equals("0")) { changesOnly = false; } else { throw new ArgumentException( ERR_LDAPSEARCH_PERSISTENT_SEARCH_INVALID_VALUE.get( persistentSearch.getIdentifierString())); } } if (elements.length > 3) { if (elements[3].equalsIgnoreCase("true") || elements[3].equals("1")) { returnECs = true; } else if (elements[3].equalsIgnoreCase("false") || elements[3].equals("0")) { returnECs = false; } else { throw new ArgumentException( ERR_LDAPSEARCH_PERSISTENT_SEARCH_INVALID_VALUE.get( persistentSearch.getIdentifierString())); } } } catch (final ArgumentException ae) { Debug.debugException(ae); throw ae; } catch (final Exception e) { Debug.debugException(e); throw new ArgumentException( ERR_LDAPSEARCH_PERSISTENT_SEARCH_INVALID_VALUE.get( persistentSearch.getIdentifierString()), e); } persistentSearchRequestControl = new PersistentSearchRequestControl( changeTypes, changesOnly, returnECs, true); } // If we should use the server-side sort request control, then validate the // sort order and pre-create the control. if (sortOrder.isPresent()) { final ArrayList sortKeyList = new ArrayList<>(5); final StringTokenizer tokenizer = new StringTokenizer(sortOrder.getValue(), ", "); while (tokenizer.hasMoreTokens()) { final String token = tokenizer.nextToken(); final boolean ascending; String attributeName; if (token.startsWith("-")) { ascending = false; attributeName = token.substring(1); } else if (token.startsWith("+")) { ascending = true; attributeName = token.substring(1); } else { ascending = true; attributeName = token; } final String matchingRuleID; final int colonPos = attributeName.indexOf(':'); if (colonPos >= 0) { matchingRuleID = attributeName.substring(colonPos+1); attributeName = attributeName.substring(0, colonPos); } else { matchingRuleID = null; } final StringBuilder invalidReason = new StringBuilder(); if (! PersistUtils.isValidLDAPName(attributeName, false, invalidReason)) { throw new ArgumentException( ERR_LDAPSEARCH_SORT_ORDER_INVALID_VALUE.get( sortOrder.getIdentifierString())); } sortKeyList.add( new SortKey(attributeName, matchingRuleID, (! ascending))); } if (sortKeyList.isEmpty()) { throw new ArgumentException( ERR_LDAPSEARCH_SORT_ORDER_INVALID_VALUE.get( sortOrder.getIdentifierString())); } final SortKey[] sortKeyArray = new SortKey[sortKeyList.size()]; sortKeyList.toArray(sortKeyArray); sortRequestControl = new ServerSideSortRequestControl(sortKeyArray); } // If we should use the virtual list view request control, then validate the // argument value and pre-create the control. if (virtualListView.isPresent()) { try { final String[] elements = virtualListView.getValue().split(":"); if (elements.length == 4) { vlvRequestControl = new VirtualListViewRequestControl( Integer.parseInt(elements[2]), Integer.parseInt(elements[0]), Integer.parseInt(elements[1]), Integer.parseInt(elements[3]), null); } else if (elements.length == 3) { vlvRequestControl = new VirtualListViewRequestControl(elements[2], Integer.parseInt(elements[0]), Integer.parseInt(elements[1]), null); } else { throw new ArgumentException( ERR_LDAPSEARCH_VLV_INVALID_VALUE.get( virtualListView.getIdentifierString())); } } catch (final ArgumentException ae) { Debug.debugException(ae); throw ae; } catch (final Exception e) { Debug.debugException(e); throw new ArgumentException( ERR_LDAPSEARCH_VLV_INVALID_VALUE.get( virtualListView.getIdentifierString()), e); } } // If we should use the LDAP join request control, then validate and // pre-create that control. if (joinRule.isPresent()) { final JoinRule rule; try { final String[] elements = joinRule.getValue().toLowerCase().split(":"); final String ruleName = StaticUtils.toLowerCase(elements[0]); if (ruleName.equals("dn")) { rule = JoinRule.createDNJoin(elements[1]); } else if (ruleName.equals("reverse-dn") || ruleName.equals("reversedn")) { rule = JoinRule.createReverseDNJoin(elements[1]); } else if (ruleName.equals("equals") || ruleName.equals("equality")) { rule = JoinRule.createEqualityJoin(elements[1], elements[2], false); } else if (ruleName.equals("contains") || ruleName.equals("substring")) { rule = JoinRule.createContainsJoin(elements[1], elements[2], false); } else { throw new ArgumentException( ERR_LDAPSEARCH_JOIN_RULE_INVALID_VALUE.get( joinRule.getIdentifierString())); } } catch (final ArgumentException ae) { Debug.debugException(ae); throw ae; } catch (final Exception e) { Debug.debugException(e); throw new ArgumentException( ERR_LDAPSEARCH_JOIN_RULE_INVALID_VALUE.get( joinRule.getIdentifierString()), e); } final JoinBaseDN joinBase; if (joinBaseDN.isPresent()) { final String s = StaticUtils.toLowerCase(joinBaseDN.getValue()); if (s.equals("search-base") || s.equals("search-base-dn")) { joinBase = JoinBaseDN.createUseSearchBaseDN(); } else if (s.equals("source-entry-dn") || s.equals("source-dn")) { joinBase = JoinBaseDN.createUseSourceEntryDN(); } else { try { final DN dn = new DN(joinBaseDN.getValue()); joinBase = JoinBaseDN.createUseCustomBaseDN(joinBaseDN.getValue()); } catch (final Exception e) { Debug.debugException(e); throw new ArgumentException( ERR_LDAPSEARCH_JOIN_BASE_DN_INVALID_VALUE.get( joinBaseDN.getIdentifierString()), e); } } } else { joinBase = JoinBaseDN.createUseSearchBaseDN(); } final String[] joinAttrs; if (joinRequestedAttribute.isPresent()) { final List valueList = joinRequestedAttribute.getValues(); joinAttrs = new String[valueList.size()]; valueList.toArray(joinAttrs); } else { joinAttrs = null; } joinRequestControl = new JoinRequestControl(new JoinRequestValue(rule, joinBase, joinScope.getValue(), DereferencePolicy.NEVER, joinSizeLimit.getValue(), joinFilter.getValue(), joinAttrs, joinRequireMatch.isPresent(), null)); } // If we should use the route to backend set request control, then validate // and pre-create those controls. if (routeToBackendSet.isPresent()) { final List values = routeToBackendSet.getValues(); final Map> idsByRP = new LinkedHashMap<>( StaticUtils.computeMapCapacity(values.size())); for (final String value : values) { final int colonPos = value.indexOf(':'); if (colonPos <= 0) { throw new ArgumentException( ERR_LDAPSEARCH_ROUTE_TO_BACKEND_SET_INVALID_FORMAT.get(value, routeToBackendSet.getIdentifierString())); } final String rpID = value.substring(0, colonPos); final String bsID = value.substring(colonPos+1); List idsForRP = idsByRP.get(rpID); if (idsForRP == null) { idsForRP = new ArrayList<>(values.size()); idsByRP.put(rpID, idsForRP); } idsForRP.add(bsID); } for (final Map.Entry> e : idsByRP.entrySet()) { final String rpID = e.getKey(); final List bsIDs = e.getValue(); routeToBackendSetRequestControls.add( RouteToBackendSetRequestControl.createAbsoluteRoutingRequest(true, rpID, bsIDs)); } } // Parse the dereference policy. final String derefStr = StaticUtils.toLowerCase(dereferencePolicy.getValue()); if (derefStr.equals("always")) { derefPolicy = DereferencePolicy.ALWAYS; } else if (derefStr.equals("search")) { derefPolicy = DereferencePolicy.SEARCHING; } else if (derefStr.equals("find")) { derefPolicy = DereferencePolicy.FINDING; } else { derefPolicy = DereferencePolicy.NEVER; } // If the --proxyAs argument was provided, then make sure its value is // properly formatted. if (proxyAs.isPresent()) { final String proxyAsValue = proxyAs.getValue(); final String lowerProxyAsValue = StaticUtils.toLowerCase(proxyAsValue); if (lowerProxyAsValue.startsWith("dn:")) { final String dnString = proxyAsValue.substring(3); if (! DN.isValidDN(dnString)) { throw new ArgumentException(ERR_LDAPSEARCH_PROXY_AS_DN_NOT_DN.get( proxyAs.getIdentifierString(), dnString)); } } else if (! lowerProxyAsValue.startsWith("u:")) { throw new ArgumentException( ERR_LDAPSEARCH_PROXY_AS_VALUE_MISSING_PREFIX.get( proxyAs.getIdentifierString())); } } // See if any entry transformations need to be applied. final ArrayList transformations = new ArrayList<>(5); if (excludeAttribute.isPresent()) { transformations.add(new ExcludeAttributeTransformation(null, excludeAttribute.getValues())); } if (redactAttribute.isPresent()) { transformations.add(new RedactAttributeTransformation(null, true, (! hideRedactedValueCount.isPresent()), redactAttribute.getValues())); } if (scrambleAttribute.isPresent()) { final Long randomSeed; if (scrambleRandomSeed.isPresent()) { randomSeed = scrambleRandomSeed.getValue().longValue(); } else { randomSeed = null; } transformations.add(new ScrambleAttributeTransformation(null, randomSeed, true, scrambleAttribute.getValues(), scrambleJSONField.getValues())); } if (renameAttributeFrom.isPresent()) { if (renameAttributeFrom.getNumOccurrences() != renameAttributeTo.getNumOccurrences()) { throw new ArgumentException( ERR_LDAPSEARCH_RENAME_ATTRIBUTE_MISMATCH.get()); } final Iterator sourceIterator = renameAttributeFrom.getValues().iterator(); final Iterator targetIterator = renameAttributeTo.getValues().iterator(); while (sourceIterator.hasNext()) { transformations.add(new RenameAttributeTransformation(null, sourceIterator.next(), targetIterator.next(), true)); } } if (moveSubtreeFrom.isPresent()) { if (moveSubtreeFrom.getNumOccurrences() != moveSubtreeTo.getNumOccurrences()) { throw new ArgumentException(ERR_LDAPSEARCH_MOVE_SUBTREE_MISMATCH.get()); } final Iterator sourceIterator = moveSubtreeFrom.getValues().iterator(); final Iterator targetIterator = moveSubtreeTo.getValues().iterator(); while (sourceIterator.hasNext()) { transformations.add(new MoveSubtreeTransformation(sourceIterator.next(), targetIterator.next())); } } if (! transformations.isEmpty()) { entryTransformations = transformations; } // Create the result writer. final String outputFormatStr = StaticUtils.toLowerCase(outputFormat.getValue()); if (outputFormatStr.equals("json")) { resultWriter = new JSONLDAPResultWriter(getOutStream()); } else if (outputFormatStr.equals("csv") || outputFormatStr.equals("multi-valued-csv") || outputFormatStr.equals("tab-delimited") || outputFormatStr.equals("multi-valued-tab-delimited")) { // These output formats cannot be used with the --ldapURLFile argument. if (ldapURLFile.isPresent()) { throw new ArgumentException( ERR_LDAPSEARCH_OUTPUT_FORMAT_NOT_SUPPORTED_WITH_URLS.get( outputFormat.getValue(), ldapURLFile.getIdentifierString())); } // These output formats require the requested attributes to be specified // via the --requestedAttribute argument rather than as unnamed trailing // arguments. final List requestedAttributes = requestedAttribute.getValues(); if ((requestedAttributes == null) || requestedAttributes.isEmpty()) { throw new ArgumentException( ERR_LDAPSEARCH_OUTPUT_FORMAT_REQUIRES_REQUESTED_ATTR_ARG.get( outputFormat.getValue(), requestedAttribute.getIdentifierString())); } switch (trailingArgs.size()) { case 0: // This is fine. break; case 1: // Make sure that the trailing argument is a filter rather than a // requested attribute. It's sufficient to ensure that neither the // filter nor filterFile argument was provided. if (filter.isPresent() || filterFile.isPresent()) { throw new ArgumentException( ERR_LDAPSEARCH_OUTPUT_FORMAT_REQUIRES_REQUESTED_ATTR_ARG.get( outputFormat.getValue(), requestedAttribute.getIdentifierString())); } break; default: throw new ArgumentException( ERR_LDAPSEARCH_OUTPUT_FORMAT_REQUIRES_REQUESTED_ATTR_ARG.get( outputFormat.getValue(), requestedAttribute.getIdentifierString())); } final OutputFormat format; final boolean includeAllValues; switch (outputFormatStr) { case "multi-valued-csv": format = OutputFormat.CSV; includeAllValues = true; break; case "tab-delimited": format = OutputFormat.TAB_DELIMITED_TEXT; includeAllValues = false; break; case "multi-valued-tab-delimited": format = OutputFormat.TAB_DELIMITED_TEXT; includeAllValues = true; break; case "csv": default: format = OutputFormat.CSV; includeAllValues = false; break; } resultWriter = new ColumnBasedLDAPResultWriter(getOutStream(), format, requestedAttributes, WRAP_COLUMN, includeAllValues); } else if (outputFormatStr.equals("dns-only")) { resultWriter = new DNsOnlyLDAPResultWriter(getOutStream()); } else if (outputFormatStr.equals("values-only")) { resultWriter = new ValuesOnlyLDAPResultWriter(getOutStream()); } else { resultWriter = new LDIFLDAPResultWriter(getOutStream(), WRAP_COLUMN); } } /** * {@inheritDoc} */ @Override() @NotNull() public LDAPConnectionOptions getConnectionOptions() { final LDAPConnectionOptions options = new LDAPConnectionOptions(); options.setUseSynchronousMode(true); options.setFollowReferrals(followReferrals.isPresent()); options.setUnsolicitedNotificationHandler(this); options.setResponseTimeoutMillis(0L); return options; } /** * {@inheritDoc} */ @Override() @NotNull() public ResultCode doToolProcessing() { // If we should encrypt the output, then get the encryption passphrase. if (encryptOutput.isPresent()) { if (encryptionPassphraseFile.isPresent()) { try { encryptionPassphrase = ToolUtils.readEncryptionPassphraseFromFile( encryptionPassphraseFile.getValue()); } catch (final LDAPException e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, e.getMessage()); return e.getResultCode(); } } else { try { encryptionPassphrase = ToolUtils.promptForEncryptionPassphrase(false, true, getOut(), getErr()); } catch (final LDAPException e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, e.getMessage()); return e.getResultCode(); } } } // If we should use an output file, then set that up now. Otherwise, write // the header to standard output. if (outputFile.isPresent()) { if (! separateOutputFilePerSearch.isPresent()) { try { OutputStream s = new FileOutputStream(outputFile.getValue()); if (encryptOutput.isPresent()) { s = new PassphraseEncryptedOutputStream(encryptionPassphrase, s); } if (compressOutput.isPresent()) { s = new GZIPOutputStream(s); } if (teeResultsToStandardOut.isPresent()) { outStream = new PrintStream(new TeeOutputStream(s, getOut())); } else { outStream = new PrintStream(s); } resultWriter.updateOutputStream(outStream); errStream = outStream; } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_LDAPSEARCH_CANNOT_OPEN_OUTPUT_FILE.get( outputFile.getValue().getAbsolutePath(), StaticUtils.getExceptionMessage(e))); return ResultCode.LOCAL_ERROR; } resultWriter.writeHeader(); } } else { resultWriter.writeHeader(); } // Examine the arguments to determine the sets of controls to use for each // type of request. final List searchControls; try { searchControls = getSearchControls(); } catch (final LDAPException e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, e.getMessage()); return e.getResultCode(); } // If appropriate, ensure that any search result entries that include // base64-encoded attribute values will also include comments that attempt // to provide a human-readable representation of that value. final boolean originalCommentAboutBase64EncodedValues = LDIFWriter.commentAboutBase64EncodedValues(); LDIFWriter.setCommentAboutBase64EncodedValues( ! suppressBase64EncodedValueComments.isPresent()); LDAPConnectionPool pool = null; try { // Create a connection pool that will be used to communicate with the // directory server. if (! dryRun.isPresent()) { try { final StartAdministrativeSessionPostConnectProcessor p; if (useAdministrativeSession.isPresent()) { p = new StartAdministrativeSessionPostConnectProcessor( new StartAdministrativeSessionExtendedRequest(getToolName(), true)); } else { p = null; } pool = getConnectionPool(1, 1, 0, p, null, true, new ReportBindResultLDAPConnectionPoolHealthCheck(this, true, false)); } catch (final LDAPException le) { // This shouldn't happen since the pool won't throw an exception if an // attempt to create an initial connection fails. Debug.debugException(le); commentToErr(ERR_LDAPSEARCH_CANNOT_CREATE_CONNECTION_POOL.get( StaticUtils.getExceptionMessage(le))); return le.getResultCode(); } if (retryFailedOperations.isPresent()) { pool.setRetryFailedOperationsDueToInvalidConnections(true); } } // If appropriate, create a rate limiter. final FixedRateBarrier rateLimiter; if (ratePerSecond.isPresent()) { rateLimiter = new FixedRateBarrier(1000L, ratePerSecond.getValue()); } else { rateLimiter = null; } // If one or more LDAP URL files are provided, then construct search // requests from those URLs. if (ldapURLFile.isPresent()) { return searchWithLDAPURLs(pool, rateLimiter, searchControls); } // Get the set of requested attributes, as a combination of the // requestedAttribute argument values and any trailing arguments. final ArrayList attrList = new ArrayList<>(10); if (requestedAttribute.isPresent()) { attrList.addAll(requestedAttribute.getValues()); } final List trailingArgs = parser.getTrailingArguments(); if (! trailingArgs.isEmpty()) { final Iterator trailingArgIterator = trailingArgs.iterator(); if (! (filter.isPresent() || filterFile.isPresent())) { trailingArgIterator.next(); } while (trailingArgIterator.hasNext()) { attrList.add(trailingArgIterator.next()); } } final String[] attributes = new String[attrList.size()]; attrList.toArray(attributes); // If either or both the filter or filterFile arguments are provided, then // use them to get the filters to process. Otherwise, the first trailing // argument should be a filter. ResultCode resultCode = ResultCode.SUCCESS; if (filter.isPresent() || filterFile.isPresent()) { if (filter.isPresent()) { for (final Filter f : filter.getValues()) { final ResultCode rc = searchWithFilter(pool, f, attributes, rateLimiter, searchControls); if (rc != ResultCode.SUCCESS) { if (resultCode == ResultCode.SUCCESS) { resultCode = rc; } if (! continueOnError.isPresent()) { return resultCode; } } } } if (filterFile.isPresent()) { final ResultCode rc = searchWithFilterFile(pool, attributes, rateLimiter, searchControls); if (rc != ResultCode.SUCCESS) { if (resultCode == ResultCode.SUCCESS) { resultCode = rc; } if (! continueOnError.isPresent()) { return resultCode; } } } } else { final Filter f; try { final String filterStr = parser.getTrailingArguments().iterator().next(); f = Filter.create(filterStr); } catch (final LDAPException le) { // This should never happen. Debug.debugException(le); displayResult(le.toLDAPResult()); return le.getResultCode(); } resultCode = searchWithFilter(pool, f, attributes, rateLimiter, searchControls); } return resultCode; } finally { if (pool != null) { try { pool.close(); } catch (final Exception e) { Debug.debugException(e); } } if (outStream != null) { try { outStream.close(); outStream = null; } catch (final Exception e) { Debug.debugException(e); } } if (errStream != null) { try { errStream.close(); errStream = null; } catch (final Exception e) { Debug.debugException(e); } } LDIFWriter.setCommentAboutBase64EncodedValues( originalCommentAboutBase64EncodedValues); } } /** * Processes a set of searches using LDAP URLs read from one or more files. * * @param pool The connection pool to use to communicate with the * directory server. * @param rateLimiter An optional fixed-rate barrier that can be used for * request rate limiting. * @param searchControls The set of controls to include in search requests. * * @return A result code indicating the result of the processing. */ @NotNull() private ResultCode searchWithLDAPURLs(@NotNull final LDAPConnectionPool pool, @Nullable final FixedRateBarrier rateLimiter, @NotNull final List searchControls) { ResultCode resultCode = ResultCode.SUCCESS; for (final File f : ldapURLFile.getValues()) { BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(f)); while (true) { final String line = reader.readLine(); if (line == null) { break; } if ((line.length() == 0) || line.startsWith("#")) { continue; } final LDAPURL url; try { url = new LDAPURL(line); } catch (final LDAPException le) { Debug.debugException(le); commentToErr(ERR_LDAPSEARCH_MALFORMED_LDAP_URL.get( f.getAbsolutePath(), line)); if (resultCode == ResultCode.SUCCESS) { resultCode = le.getResultCode(); } if (continueOnError.isPresent()) { continue; } else { return resultCode; } } final SearchRequest searchRequest = new SearchRequest( new LDAPSearchListener(resultWriter, entryTransformations), url.getBaseDN().toString(), url.getScope(), derefPolicy, sizeLimit.getValue(), timeLimitSeconds.getValue(), typesOnly.isPresent(), url.getFilter(), url.getAttributes()); final ResultCode rc = doSearch(pool, searchRequest, rateLimiter, searchControls); if (rc != ResultCode.SUCCESS) { if (resultCode == ResultCode.SUCCESS) { resultCode = rc; } if (! continueOnError.isPresent()) { return resultCode; } } } } catch (final IOException ioe) { commentToErr(ERR_LDAPSEARCH_CANNOT_READ_LDAP_URL_FILE.get( f.getAbsolutePath(), StaticUtils.getExceptionMessage(ioe))); return ResultCode.LOCAL_ERROR; } finally { if (reader != null) { try { reader.close(); } catch (final Exception e) { Debug.debugException(e); } } } } return resultCode; } /** * Processes a set of searches using filters read from one or more files. * * @param pool The connection pool to use to communicate with the * directory server. * @param attributes The set of attributes to request that the server * include in matching entries. * @param rateLimiter An optional fixed-rate barrier that can be used for * request rate limiting. * @param searchControls The set of controls to include in search requests. * * @return A result code indicating the result of the processing. */ @NotNull() private ResultCode searchWithFilterFile( @NotNull final LDAPConnectionPool pool, @NotNull final String[] attributes, @Nullable final FixedRateBarrier rateLimiter, @NotNull final List searchControls) { ResultCode resultCode = ResultCode.SUCCESS; for (final File f : filterFile.getValues()) { FilterFileReader reader = null; try { reader = new FilterFileReader(f); while (true) { final Filter searchFilter; try { searchFilter = reader.readFilter(); } catch (final LDAPException le) { Debug.debugException(le); commentToErr(ERR_LDAPSEARCH_MALFORMED_FILTER.get( f.getAbsolutePath(), le.getMessage())); if (resultCode == ResultCode.SUCCESS) { resultCode = le.getResultCode(); } if (continueOnError.isPresent()) { continue; } else { return resultCode; } } if (searchFilter == null) { break; } final ResultCode rc = searchWithFilter(pool, searchFilter, attributes, rateLimiter, searchControls); if (rc != ResultCode.SUCCESS) { if (resultCode == ResultCode.SUCCESS) { resultCode = rc; } if (! continueOnError.isPresent()) { return resultCode; } } } } catch (final IOException ioe) { Debug.debugException(ioe); commentToErr(ERR_LDAPSEARCH_CANNOT_READ_FILTER_FILE.get( f.getAbsolutePath(), StaticUtils.getExceptionMessage(ioe))); return ResultCode.LOCAL_ERROR; } finally { if (reader != null) { try { reader.close(); } catch (final Exception e) { Debug.debugException(e); } } } } return resultCode; } /** * Processes a search using the provided filter. * * @param pool The connection pool to use to communicate with the * directory server. * @param filter The filter to use for the search. * @param attributes The set of attributes to request that the server * include in matching entries. * @param rateLimiter An optional fixed-rate barrier that can be used for * request rate limiting. * @param searchControls The set of controls to include in search requests. * * @return A result code indicating the result of the processing. */ @NotNull() private ResultCode searchWithFilter(@NotNull final LDAPConnectionPool pool, @NotNull final Filter filter, @NotNull final String[] attributes, @Nullable final FixedRateBarrier rateLimiter, @NotNull final List searchControls) { final String baseDNString; if (baseDN.isPresent()) { baseDNString = baseDN.getStringValue(); } else { baseDNString = ""; } final SearchRequest searchRequest = new SearchRequest( new LDAPSearchListener(resultWriter, entryTransformations), baseDNString, scope.getValue(), derefPolicy, sizeLimit.getValue(), timeLimitSeconds.getValue(), typesOnly.isPresent(), filter, attributes); return doSearch(pool, searchRequest, rateLimiter, searchControls); } /** * Processes a search with the provided information. * * @param pool The connection pool to use to communicate with the * directory server. * @param searchRequest The search request to process. * @param rateLimiter An optional fixed-rate barrier that can be used for * request rate limiting. * @param searchControls The set of controls to include in search requests. * * @return A result code indicating the result of the processing. */ @NotNull() private ResultCode doSearch(@NotNull final LDAPConnectionPool pool, @NotNull final SearchRequest searchRequest, @Nullable final FixedRateBarrier rateLimiter, @NotNull final List searchControls) { if (separateOutputFilePerSearch.isPresent()) { try { final String path = outputFile.getValue().getAbsolutePath() + '.' + outputFileCounter.getAndIncrement(); OutputStream s = new FileOutputStream(path); if (encryptOutput.isPresent()) { s = new PassphraseEncryptedOutputStream(encryptionPassphrase, s); } if (compressOutput.isPresent()) { s = new GZIPOutputStream(s); } if (teeResultsToStandardOut.isPresent()) { outStream = new PrintStream(new TeeOutputStream(s, getOut())); } else { outStream = new PrintStream(s); } resultWriter.updateOutputStream(outStream); errStream = outStream; } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_LDAPSEARCH_CANNOT_OPEN_OUTPUT_FILE.get( outputFile.getValue().getAbsolutePath(), StaticUtils.getExceptionMessage(e))); return ResultCode.LOCAL_ERROR; } resultWriter.writeHeader(); } try { if (rateLimiter != null) { rateLimiter.await(); } ASN1OctetString pagedResultsCookie = null; boolean multiplePages = false; long totalEntries = 0; long totalReferences = 0; SearchResult searchResult; try { while (true) { searchRequest.setControls(searchControls); if (simplePageSize.isPresent()) { searchRequest.addControl(new SimplePagedResultsControl( simplePageSize.getValue(), pagedResultsCookie)); } if (dryRun.isPresent()) { searchResult = new SearchResult(-1, ResultCode.SUCCESS, INFO_LDAPSEARCH_DRY_RUN_REQUEST_NOT_SENT.get( dryRun.getIdentifierString(), String.valueOf(searchRequest)), null, null, 0, 0, null); break; } else { if (! terse.isPresent()) { if (verbose.isPresent() || persistentSearch.isPresent() || filterFile.isPresent() || ldapURLFile.isPresent() || (filter.isPresent() && (filter.getNumOccurrences() > 1))) { commentToOut(INFO_LDAPSEARCH_SENDING_SEARCH_REQUEST.get( String.valueOf(searchRequest))); } } searchResult = pool.search(searchRequest); } searchResult = handleJSONEncodedResponseControls(searchResult); if (searchResult.getEntryCount() > 0) { totalEntries += searchResult.getEntryCount(); } if (searchResult.getReferenceCount() > 0) { totalReferences += searchResult.getReferenceCount(); } if (simplePageSize.isPresent()) { final SimplePagedResultsControl pagedResultsControl; try { pagedResultsControl = SimplePagedResultsControl.get(searchResult); if (pagedResultsControl == null) { throw new LDAPSearchException(new SearchResult( searchResult.getMessageID(), ResultCode.CONTROL_NOT_FOUND, ERR_LDAPSEARCH_MISSING_PAGED_RESULTS_RESPONSE_CONTROL. get(), searchResult.getMatchedDN(), searchResult.getReferralURLs(), searchResult.getSearchEntries(), searchResult.getSearchReferences(), searchResult.getEntryCount(), searchResult.getReferenceCount(), searchResult.getResponseControls())); } if (pagedResultsControl.moreResultsToReturn()) { if (verbose.isPresent()) { commentToOut( INFO_LDAPSEARCH_INTERMEDIATE_PAGED_SEARCH_RESULT.get()); displayResult(searchResult); } multiplePages = true; pagedResultsCookie = pagedResultsControl.getCookie(); } else { break; } } catch (final LDAPException le) { Debug.debugException(le); throw new LDAPSearchException(new SearchResult( searchResult.getMessageID(), ResultCode.CONTROL_NOT_FOUND, ERR_LDAPSEARCH_CANNOT_DECODE_PAGED_RESULTS_RESPONSE_CONTROL. get(StaticUtils.getExceptionMessage(le)), searchResult.getMatchedDN(), searchResult.getReferralURLs(), searchResult.getSearchEntries(), searchResult.getSearchReferences(), searchResult.getEntryCount(), searchResult.getReferenceCount(), searchResult.getResponseControls())); } } else { break; } } } catch (final LDAPSearchException lse) { Debug.debugException(lse); searchResult = lse.toLDAPResult(); if (searchResult.getEntryCount() > 0) { totalEntries += searchResult.getEntryCount(); } if (searchResult.getReferenceCount() > 0) { totalReferences += searchResult.getReferenceCount(); } } if ((searchResult.getResultCode() != ResultCode.SUCCESS) || (searchResult.getDiagnosticMessage() != null) || (! terse.isPresent())) { displayResult(searchResult); } if (multiplePages && (! terse.isPresent())) { commentToOut(INFO_LDAPSEARCH_TOTAL_SEARCH_ENTRIES.get(totalEntries)); if (totalReferences > 0) { commentToOut(INFO_LDAPSEARCH_TOTAL_SEARCH_REFERENCES.get( totalReferences)); } } if (countEntries.isPresent()) { return ResultCode.valueOf((int) Math.min(totalEntries, 255)); } else if (requireMatch.isPresent() && (totalEntries == 0)) { return ResultCode.NO_RESULTS_RETURNED; } else { return searchResult.getResultCode(); } } finally { if (separateOutputFilePerSearch.isPresent()) { try { outStream.close(); } catch (final Exception e) { Debug.debugException(e); } outStream = null; errStream = null; } } } /** * Retrieves a list of the controls that should be used when processing search * operations. * * @return A list of the controls that should be used when processing search * operations. * * @throws LDAPException If a problem is encountered while generating the * controls for a search request. */ @NotNull() private List getSearchControls() throws LDAPException { final ArrayList controls = new ArrayList<>(10); if (searchControl.isPresent()) { controls.addAll(searchControl.getValues()); } if (joinRequestControl != null) { controls.add(joinRequestControl); } if (matchedValuesRequestControl != null) { controls.add(matchedValuesRequestControl); } if (matchingEntryCountRequestControl != null) { controls.add(matchingEntryCountRequestControl); } if (overrideSearchLimitsRequestControl != null) { controls.add(overrideSearchLimitsRequestControl); } if (persistentSearchRequestControl != null) { controls.add(persistentSearchRequestControl); } if (sortRequestControl != null) { controls.add(sortRequestControl); } if (vlvRequestControl != null) { controls.add(vlvRequestControl); } controls.addAll(routeToBackendSetRequestControls); if (accessLogField.isPresent()) { final Map fields = new LinkedHashMap<>(); for (final String nameValueStr : accessLogField.getValues()) { final int colonPos = nameValueStr.indexOf(':'); if (colonPos < 0) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_LDAPSEARCH_ACCESS_LOG_FIELD_NO_COLON.get( accessLogField.getIdentifierString(), nameValueStr)); } final String fieldName = nameValueStr.substring(0, colonPos); if (fields.containsKey(fieldName)) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_LDAPSEARCH_ACCESS_LOG_FIELD_DUPLICATE_FIELD.get( accessLogField.getIdentifierString(), fieldName)); } final String valueStr = nameValueStr.substring(colonPos + 1); if (valueStr.equalsIgnoreCase("true")) { fields.put(fieldName, JSONBoolean.TRUE); } else if (valueStr.equalsIgnoreCase("false")) { fields.put(fieldName, JSONBoolean.FALSE); } else { try { final BigDecimal d = new BigDecimal(valueStr); fields.put(fieldName, new JSONNumber(d)); } catch (final Exception e) { Debug.debugException(e); fields.put(fieldName, new JSONString(valueStr)); } } } controls.add(new AccessLogFieldRequestControl(false, new JSONObject(fields))); } if (accountUsable.isPresent()) { controls.add(new AccountUsableRequestControl(true)); } if (getBackendSetID.isPresent()) { controls.add(new GetBackendSetIDRequestControl(false)); } if (getServerID.isPresent()) { controls.add(new GetServerIDRequestControl(false)); } if (includeReplicationConflictEntries.isPresent()) { controls.add(new ReturnConflictEntriesRequestControl(true)); } if (includeSoftDeletedEntries.isPresent()) { final String valueStr = StaticUtils.toLowerCase(includeSoftDeletedEntries.getValue()); if (valueStr.equals("with-non-deleted-entries")) { controls.add(new SoftDeletedEntryAccessRequestControl(true, true, false)); } else if (valueStr.equals("without-non-deleted-entries")) { controls.add(new SoftDeletedEntryAccessRequestControl(true, false, false)); } else { controls.add(new SoftDeletedEntryAccessRequestControl(true, false, true)); } } if (draftLDUPSubentries.isPresent()) { controls.add(new DraftLDUPSubentriesRequestControl(true)); } if (rfc3672Subentries.isPresent()) { controls.add(new RFC3672SubentriesRequestControl( rfc3672Subentries.getValue())); } if (manageDsaIT.isPresent()) { controls.add(new ManageDsaITRequestControl(true)); } if (realAttributesOnly.isPresent()) { controls.add(new RealAttributesOnlyRequestControl(true)); } if (routeToServer.isPresent()) { controls.add(new RouteToServerRequestControl(false, routeToServer.getValue(), false, false, false)); } if (virtualAttributesOnly.isPresent()) { controls.add(new VirtualAttributesOnlyRequestControl(true)); } if (excludeBranch.isPresent()) { final ArrayList dns = new ArrayList<>(excludeBranch.getValues().size()); for (final DN dn : excludeBranch.getValues()) { dns.add(dn.toString()); } controls.add(new ExcludeBranchRequestControl(true, dns)); } if (assertionFilter.isPresent()) { controls.add(new AssertionRequestControl( assertionFilter.getValue(), true)); } if (getEffectiveRightsAuthzID.isPresent()) { final String[] attributes; if (getEffectiveRightsAttribute.isPresent()) { attributes = new String[getEffectiveRightsAttribute.getValues().size()]; for (int i=0; i < attributes.length; i++) { attributes[i] = getEffectiveRightsAttribute.getValues().get(i); } } else { attributes = StaticUtils.NO_STRINGS; } controls.add(new GetEffectiveRightsRequestControl(true, getEffectiveRightsAuthzID.getValue(), attributes)); } if (operationPurpose.isPresent()) { controls.add(new OperationPurposeRequestControl(true, "ldapsearch", Version.NUMERIC_VERSION_STRING, "LDAPSearch.getSearchControls", operationPurpose.getValue())); } if (proxyAs.isPresent()) { final String proxyAsValue = proxyAs.getValue(); final String lowerProxyAsValue = StaticUtils.toLowerCase(proxyAsValue); if (lowerProxyAsValue.startsWith("dn:")) { final String dnString = proxyAsValue.substring(3); if (! DN.isValidDN(dnString)) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_LDAPSEARCH_PROXY_AS_DN_NOT_DN.get( proxyAs.getIdentifierString(), dnString)); } } else if (! lowerProxyAsValue.startsWith("u:")) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_LDAPSEARCH_PROXY_AS_VALUE_MISSING_PREFIX.get( proxyAs.getIdentifierString())); } controls.add(new ProxiedAuthorizationV2RequestControl(proxyAsValue)); } if (proxyV1As.isPresent()) { controls.add(new ProxiedAuthorizationV1RequestControl( proxyV1As.getValue())); } if (suppressOperationalAttributeUpdates.isPresent()) { final EnumSet suppressTypes = EnumSet.noneOf(SuppressType.class); for (final String s : suppressOperationalAttributeUpdates.getValues()) { if (s.equalsIgnoreCase("last-access-time")) { suppressTypes.add(SuppressType.LAST_ACCESS_TIME); } else if (s.equalsIgnoreCase("last-login-time")) { suppressTypes.add(SuppressType.LAST_LOGIN_TIME); } else if (s.equalsIgnoreCase("last-login-ip")) { suppressTypes.add(SuppressType.LAST_LOGIN_IP); } } controls.add(new SuppressOperationalAttributeUpdateRequestControl( suppressTypes)); } if (rejectUnindexedSearch.isPresent()) { controls.add(new RejectUnindexedSearchRequestControl()); } if (permitUnindexedSearch.isPresent()) { controls.add(new PermitUnindexedSearchRequestControl()); } if (useJSONFormattedRequestControls.isPresent()) { final JSONFormattedRequestControl jsonFormattedRequestControl = JSONFormattedRequestControl.createWithControls(true, controls); controls.clear(); controls.add(jsonFormattedRequestControl); } return controls; } /** * Displays information about the provided result, including special * processing for a number of supported response controls. * * @param result The result to examine. */ private void displayResult(@NotNull final LDAPResult result) { resultWriter.writeResult(result); } /** * Writes the provided message to the output stream. * * @param message The message to be written. */ void writeOut(@NotNull final String message) { if (outStream == null) { out(message); } else { outStream.println(message); } } /** * Writes the provided message to the error stream. * * @param message The message to be written. */ private void writeErr(@NotNull final String message) { if (errStream == null) { err(message); } else { errStream.println(message); } } /** * Writes a line-wrapped, commented version of the provided message to * standard output. * * @param message The message to be written. */ private void commentToOut(@NotNull final String message) { if (terse.isPresent()) { return; } for (final String line : StaticUtils.wrapLine(message, (WRAP_COLUMN - 2))) { writeOut("# " + line); } } /** * Writes a line-wrapped, commented version of the provided message to * standard error. * * @param message The message to be written. */ private void commentToErr(@NotNull final String message) { for (final String line : StaticUtils.wrapLine(message, (WRAP_COLUMN - 2))) { writeErr("# " + line); } } /** * Retrieves the tool's output stream. * * @return The tool's output stream. */ @NotNull() PrintStream getOutStream() { if (outStream == null) { return getOut(); } else { return outStream; } } /** * Retrieves the tool's error stream. * * @return The tool's error stream. */ @NotNull() PrintStream getErrStream() { if (errStream == null) { return getErr(); } else { return errStream; } } /** * Sets the output handler that should be used by this tool This is primarily * intended for testing purposes. * * @param resultWriter The result writer that should be used by this tool. */ void setResultWriter(@NotNull final LDAPResultWriter resultWriter) { this.resultWriter = resultWriter; } /** * {@inheritDoc} */ @Override() public void handleUnsolicitedNotification( @NotNull final LDAPConnection connection, @NotNull final ExtendedResult notification) { resultWriter.writeUnsolicitedNotification(connection, notification); } /** * Examines the provided search result to see if it includes a JSONf-formatted * response control. If so, then its embedded controls will be extracted and * a new search result will be returned with those extracted controls instead * of the JSON-formatted response control. Otherwise, the provided search * result will be returned. * * @param searchResult The search result to be handled. It must not be * {@code null}. * * @return A new search result with the controls extracted from a * JSON-formatted response control, or the original search result if * it did not include a JSON-formatted response control. */ @NotNull() static SearchResult handleJSONEncodedResponseControls( @NotNull final SearchResult searchResult) { try { final JSONFormattedResponseControl jsonFormattedResponseControl = JSONFormattedResponseControl.get(searchResult); if (jsonFormattedResponseControl == null) { return searchResult; } final JSONFormattedControlDecodeBehavior decodeBehavior = new JSONFormattedControlDecodeBehavior(); decodeBehavior.setThrowOnUnparsableObject(false); decodeBehavior.setThrowOnInvalidCriticalControl(false); decodeBehavior.setThrowOnInvalidNonCriticalControl(false); decodeBehavior.setThrowOnInvalidNonCriticalControl(false); decodeBehavior.setAllowEmbeddedJSONFormattedControl(true); decodeBehavior.setStrict(false); final List decodedControls = jsonFormattedResponseControl.decodeEmbeddedControls( decodeBehavior, null); return new SearchResult(searchResult.getMessageID(), searchResult.getResultCode(), searchResult.getDiagnosticMessage(), searchResult.getMatchedDN(), searchResult.getReferralURLs(), searchResult.getSearchEntries(), searchResult.getSearchReferences(), searchResult.getEntryCount(), searchResult.getReferenceCount(), StaticUtils.toArray(decodedControls, Control.class)); } catch (final LDAPException e) { Debug.debugException(e); return searchResult; } } /** * {@inheritDoc} */ @Override() @NotNull() public LinkedHashMap getExampleUsages() { final LinkedHashMap examples = new LinkedHashMap<>(StaticUtils.computeMapCapacity(5)); String[] args = { "--hostname", "directory.example.com", "--port", "389", "--bindDN", "uid=jdoe,ou=People,dc=example,dc=com", "--bindPassword", "password", "--baseDN", "ou=People,dc=example,dc=com", "--scope", "sub", "(uid=jqpublic)", "givenName", "sn", "mail" }; examples.put(args, INFO_LDAPSEARCH_EXAMPLE_1.get()); args = new String[] { "--hostname", "directory.example.com", "--port", "636", "--useSSL", "--saslOption", "mech=PLAIN", "--saslOption", "authID=u:jdoe", "--bindPasswordFile", "/path/to/password/file", "--baseDN", "ou=People,dc=example,dc=com", "--scope", "sub", "--filterFile", "/path/to/filter/file", "--outputFile", "/path/to/base/output/file", "--separateOutputFilePerSearch", "--requestedAttribute", "*", "--requestedAttribute", "+" }; examples.put(args, INFO_LDAPSEARCH_EXAMPLE_2.get()); args = new String[] { "--hostname", "directory.example.com", "--port", "389", "--useStartTLS", "--trustStorePath", "/path/to/truststore/file", "--baseDN", "", "--scope", "base", "--outputFile", "/path/to/output/file", "--teeResultsToStandardOut", "(objectClass=*)", "*", "+" }; examples.put(args, INFO_LDAPSEARCH_EXAMPLE_3.get()); args = new String[] { "--hostname", "directory.example.com", "--port", "389", "--bindDN", "uid=admin,dc=example,dc=com", "--baseDN", "dc=example,dc=com", "--scope", "sub", "--outputFile", "/path/to/output/file", "--simplePageSize", "100", "(objectClass=*)", "*", "+" }; examples.put(args, INFO_LDAPSEARCH_EXAMPLE_4.get()); args = new String[] { "--hostname", "directory.example.com", "--port", "389", "--bindDN", "uid=admin,dc=example,dc=com", "--baseDN", "dc=example,dc=com", "--scope", "sub", "(&(givenName=John)(sn=Doe))", "debugsearchindex" }; examples.put(args, INFO_LDAPSEARCH_EXAMPLE_5.get()); return examples; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy