/*
* Sun Public License
*
* The contents of this file are subject to the Sun Public License Version
* 1.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is available at http://www.sun.com/
*
* The Original Code is the SLAMD Distributed Load Generation Engine.
* The Initial Developer of the Original Code is Neil A. Wilson.
* Portions created by Neil A. Wilson are Copyright (C) 2004-2010.
* Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc.
* All Rights Reserved.
*
* Contributor(s): Neil A. Wilson
*/
package com.slamd.jobs;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Random;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.Filter;
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPConnectionOptions;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.Modification;
import com.unboundid.ldap.sdk.ModificationType;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.ldap.sdk.SearchResult;
import com.unboundid.ldap.sdk.SearchScope;
import com.unboundid.util.FixedRateBarrier;
import com.unboundid.util.ValuePattern;
import com.unboundid.util.ssl.SSLUtil;
import com.unboundid.util.ssl.TrustAllTrustManager;
import com.slamd.job.JobClass;
import com.slamd.job.UnableToRunException;
import com.slamd.parameter.BooleanParameter;
import com.slamd.parameter.IntegerParameter;
import com.slamd.parameter.InvalidValueException;
import com.slamd.parameter.MultiLineTextParameter;
import com.slamd.parameter.Parameter;
import com.slamd.parameter.ParameterList;
import com.slamd.parameter.PasswordParameter;
import com.slamd.parameter.PlaceholderParameter;
import com.slamd.parameter.StringParameter;
import com.slamd.stat.CategoricalTracker;
import com.slamd.stat.IncrementalTracker;
import com.slamd.stat.RealTimeStatReporter;
import com.slamd.stat.StatTracker;
import com.slamd.stat.TimeTracker;
/**
* This class defines a SLAMD job that simulates the load that some versions of
* Netegrity SiteMinder have been observed to place on an LDAP directory server.
* It uses a weighted access pattern. The load that it uses is based on the
* following (rather inefficient) sequence of events:
*
* <OL>
* <LI>Perform a subtree search from the directory suffix to find the user's
* entry based on a login ID.</LI>
* <LI>Perform a base-level search on the user's entry to retrieve the
* objectClass attribute.</LI>
* <LI>Perform a bind as the user. This is done on a different connection
* than all of the other steps.</LI>
* <LI>Perform a base-level search on the user's entry to retrieve a given
* user-specified attribute (attr1).</LI>
* <LI>Perform a base-level search on the user's entry to retrieve a second
* user-specified attribute (attr2).</LI>
* <LI>Perform a base-level search on the user's entry to retrieve the first
* attribute (attr1).</LI>
* <LI>Perform a modification on the user's entry.</LI>
* <LI>Perform a base-level search on the user's entry to retrieve the first
* attribute again.</LI>
* <LI>Perform a base-level search on the user's entry to retrieve the first
* attribute again.</LI>
* <LI>Perform a base-level search on the user's entry to retrieve a third
* attribute (attr3).</LI>
* </OL>
*
*
* @author Neil A. Wilson
*/
public class WeightedSiteMinderJobClass
extends JobClass
{
/**
* The set of characters that will be used to generate random values for the
* modifications.
*/
public static final char[] ALPHABET =
"abcdefghijklmnopqrstuvwxyz".toCharArray();
/**
* The default value for the first attribute to retrieve during the
* authentication process.
*/
public static final String DEFAULT_ATTR1 = "givenName";
/**
* The default value for the second attribute to retrieve during the
* authentication process.
*/
public static final String DEFAULT_ATTR2 = "sn";
/**
* The default value for the third attribute to retrieve during the
* authentication process.
*/
public static final String DEFAULT_ATTR3= "cn";
/**
* The default attribute used as the login ID.
*/
public static final String DEFAULT_LOG_ID_ATTR = "uid";
/**
* The name of the stat tracker that will be used to count the number of
* overall authentication attempts.
*/
public static final String STAT_TRACKER_OVERALL_AUTHENTICATION_ATTEMPTS =
"Overall Authentication Attempts";
/**
* The name of the stat tracker that will be used to count the number of
* authentication attempts based on the first user criteria.
*/
public static final String STAT_TRACKER_AUTHENTICATION_1_ATTEMPTS =
"Authentication 1 Attempts";
/**
* The name of the stat tracker that will be used to count the number of
* authentication attempts based on the second user criteria.
*/
public static final String STAT_TRACKER_AUTHENTICATION_2_ATTEMPTS =
"Authentication 2 Attempts";
/**
* The name of the stat tracker that will be used to keep track of the overall
* time required to perform each authentication.
*/
public static final String STAT_TRACKER_OVERALL_AUTHENTICATION_TIME =
"Overall Authentication Time (ms)";
/**
* The name of the stat tracker that will be used to keep track of the time
* required to perform each authentication based on the first user criteria.
*/
public static final String STAT_TRACKER_AUTHENTICATION_1_TIME =
"Authentication 1 Time (ms)";
/**
* The name of the stat tracker that will be used to keep track of the time
* required to perform each authentication based on the second user criteria.
*/
public static final String STAT_TRACKER_AUTHENTICATION_2_TIME =
"Authentication 2 Time (ms)";
/**
* The name of the stat tracker that will be used to count the number of
* overall failed authentications.
*/
public static final String STAT_TRACKER_OVERALL_FAILED_AUTHENTICATIONS =
"Overall Failed Authentications";
/**
* The name of the stat tracker that will be used to count the number of
* failed authentications based on the first user criteria.
*/
public static final String STAT_TRACKER_FAILED_AUTHENTICATIONS_1 =
"Failed Authentications 1";
/**
* The name of the stat tracker that will be used to count the number of
* failed authentications based on the second user criteria.
*/
public static final String STAT_TRACKER_FAILED_AUTHENTICATIONS_2 =
"Failed Authentications 2";
/**
* The name of the stat tracker that will be used to categorize the reasons
* for the failed auths.
*/
public static final String STAT_TRACKER_FAIL_REASON = "Failure Reason";
/**
* The name of the stat tracker that will be used to count the overall number
* of successful authentications.
*/
public static final String STAT_TRACKER_OVERALL_SUCCESSFUL_AUTHENTICATIONS =
"Overall Successful Authentications";
/**
* The name of the stat tracker that will be used to count the number of
* successful authentications based on the first user criteria.
*/
public static final String STAT_TRACKER_SUCCESSFUL_AUTHENTICATIONS_1 =
"Successful Authentications 1";
/**
* The name of the stat tracker that will be used to count the number of
* successful authentications based on the second user criteria.
*/
public static final String STAT_TRACKER_SUCCESSFUL_AUTHENTICATIONS_2 =
"Successful Authentications 2";
/**
* The default set of attributes to include in the modification.
*/
public static final String[] DEFAULT_ATTRS_TO_MODIFY = new String[]
{
"description"
};
// Indicates whether bind failures because of invalid credentials will be
// ignored (so you don't actually have to know user passwords).
private static boolean ignoreInvalidCredentials;
// Indicates whether the bind should be attempted or skipped.
private static boolean skipBind;
// Indicates whether all threads will used a shared set of connections or if
// each thread will have its own connection.
private static boolean useSharedConnections;
// Indicates whether to use SSL when communicating with the directory.
private static boolean useSSL;
// The search filter to use when searching on the first attribute.
private static Filter filter1;
// The search filter to use when searching on the second attribute.
private static Filter filter2;
// The search filter to use when searching on the third attribute.
private static Filter filter3;
// The rate limiter for this job.
private static FixedRateBarrier rateLimiter;
// The time to keep working after stopping statistics collection.
private static int coolDownTime;
// The port number of the directory server.
private static int directoryPort;
// The percentage of the time that the first login ID should be used.
private static int loginID1Percent;
// The maximum length of time that any single LDAP operation will be allowed
// to take before it is cancelled.
private static int timeLimit;
// The time to start working before beginning statistics collection.
private static int warmUpTime;
// The delay in milliseconds between authentication attempts.
private static long delay;
// The LDAP connection that will be used for shared authentication operations.
private static LDAPConnection sharedAuthConnection;
// The LDAP connection that will be used for shared bind operations.
private static LDAPConnection sharedBindConnection;
// The random number generator that will seed the thread-specific random
// number generators.
private static Random parentRandom;
// The DN to use to bind to the directory when performing the search and
// modify operations.
private static String bindDN;
// The password for the bind DN.
private static String bindPW;
// The address of the directory server.
private static String directoryHost;
// The name of the attribute that will be used to initially find the user's
// entry (the login ID attribute).
private static String loginIDAttr;
// The password to use when authenticating.
private static String loginPassword;
// The name of the first attribute to retrieve.
private static String searchAttr1;
// The name of the second attribute to retrieve.
private static String searchAttr2;
// The name of the third attribute to retrieve.
private static String searchAttr3;
// The DN to use as the search base when trying to find user entries in the
// directory.
private static String searchBase;
// The names of the attributes to alter in the modification.
private static String[] modAttrs;
// The set of attributes to return when retrieving the first attribute.
private static String[] returnAttrs1;
// The set of attributes to return when retrieving the second attribute.
private static String[] returnAttrs2;
// The set of attributes to return when retrieving the third attribute.
private static String[] returnAttrs3;
// The set of attributes to return when retrieving the set of object classes.
private static String[] returnAttrsOC;
// The value pattern to use to construct the first login ID pattern.
private static ValuePattern loginIDPattern1;
// The value pattern to use to construct the second login ID pattern.
private static ValuePattern loginIDPattern2;
// The parameter that indicates whether the client should trust any SSL cert.
private BooleanParameter blindTrustParameter =
new BooleanParameter("blind_trust", "Blindly Trust Any Certificate",
"Indicates whether the client should blindly trust " +
"any certificate presented by the server, or " +
"whether the key and trust stores should be used.",
true);
// The parameter used to indicate whether invalid credential results are
// ignored.
private BooleanParameter ignoreInvCredParameter =
new BooleanParameter("ignore_49", "Ignore Invalid Credentials Errors",
"Indicates whether bind failures because of " +
"invalid credentials (err=49). This makes it " +
"possible to use this job without actually " +
"know user passwords.", false);
// The parameter used to indicate whether connections are shared.
private BooleanParameter shareConnsParameter =
new BooleanParameter("share_conns", "Share Connections between Threads",
"Indicates whether the connections to the " +
"directory server will be shared between threads " +
"or if each client thread will have its own " +
"connections.", true);
// The parameter used to indicate whether to skip the bind operation.
private BooleanParameter skipBindParameter =
new BooleanParameter("skip_bind", "Skip Bind Operation",
"Indicates whether the bind attempt should be " +
"skipped as part of the authentication process.",
false);
// The parameter that indicates whether the connection should use SSL or not
private BooleanParameter useSSLParameter =
new BooleanParameter("usessl", "Use SSL",
"Indicates whether to use SSL to encrypt the " +
"communication with the directory server", false);
// The parameter that specifies the cool-down time in seconds.
private IntegerParameter coolDownParameter =
new IntegerParameter("cool_down", "Cool Down Time",
"The time in seconds that the job should " +
"continue searching after ending statistics " +
"collection.", true, 0, true, 0, false, 0);
// The parameter that indicates the delay that should be used between each
// authentication attempt.
private IntegerParameter delayParameter =
new IntegerParameter("delay", "Time Between Authentications (ms)",
"Specifies the length of time in milliseconds " +
"each thread should wait between authentication " +
"attempts. Note that this delay will be " +
"between the starts of consecutive attempts and " +
"not between the end of one attempt and the " +
"beginning of the next. If an authentication " +
"takes longer than this length of time, then " +
"there will be no delay.", true, 0, true, 0, false,
0);
// The parameter that specifies the maximum request rate.
private IntegerParameter maxRateParameter = new IntegerParameter("maxRate",
"Max Authentication Rate (Auths/Second/Client)",
"Specifies the maximum authentication rate (in auths per second per " +
"client) to attempt to maintain. If multiple clients are used, " +
"then each client will attempt to maintain this rate. A value " +
"less than or equal to zero indicates that the client should " +
"attempt to perform authentications as quickly as possible.",
true, -1);
// The parameter used to indicate the port number for the directory server.
private IntegerParameter portParameter =
new IntegerParameter("ldap_port", "Directory Server Port",
"The port number for the directory server.", true,
389, true, 1, true, 65535);
// The parameter that specifies the interval over which to enforce the maximum
// request rate.
private IntegerParameter rateLimitDurationParameter = new IntegerParameter(
"maxRateDuration", "Max Rate Enforcement Interval (Seconds)",
"Specifies the duration in seconds of the interval over which to " +
"attempt to maintain the configured maximum rate. A value of " +
"zero indicates that it should be equal to the statistics " +
"collection interval. Large values may allow more variation but " +
"may be more accurate over time. Small values can better " +
"ensure that the rate doesn't exceed the requested level but may " +
"be less able to achieve the desired rate.",
true, 0, true,0, false, 0);
// The parameter used to indicate the maximum length of time that any single
// LDAP operation will be allowed to take.
private IntegerParameter timeLimitParameter =
new IntegerParameter("time_limit", "Operation Time Limit",
"The maximum length of time in seconds that any " +
"single LDAP operation will be allowed to take " +
"before it is cancelled.", true, 0, true, 0, false,
0);
// The parameter that specifies the cool-down time in seconds.
private IntegerParameter warmUpParameter =
new IntegerParameter("warm_up", "Warm Up Time",
"The time in seconds that the job should " +
"search before beginning statistics collection.",
true, 0, true, 0, false, 0);
// The parameter that specifies the percentage of the time that the first user
// criteria will be used in the modification.
private IntegerParameter weightParameter =
new IntegerParameter("weight", "Login ID 1 Percentage",
"The percentage of the time that a login ID " +
"should be selected according to the value " +
"provided for the Login ID Value 1 parameter.",
true, 50, true, 0, true, 100);
// The parameter used to indicate the attributes to modify.
private MultiLineTextParameter modAttrsParameter =
new MultiLineTextParameter("mod_attrs", "Attributes to Modify",
"The set of attributes to modify.",
DEFAULT_ATTRS_TO_MODIFY, false);
// The parameter used to indicate the password for the bind DN.
private PasswordParameter bindPWParameter =
new PasswordParameter("bindpw", "Directory Bind Password",
"The password to use when binding to the " +
"directory server to perform search and modify " +
"operations.", false, "");
// The parameter that specifies the password for the SSL key store
private PasswordParameter keyPWParameter =
new PasswordParameter("sslkeypw", "SSL Key Store Password",
"The password for the JSSE key store", false, "");
// The parameter used to indicate the password to use when authenticating to
// the directory.
private PasswordParameter loginPasswordParameter =
new PasswordParameter("login_id_pw", "Login Password",
"The password to use when authenticating to the " +
"directory for user authentications.", false, "");
// The parameter that specifies the password for the SSL key store
private PasswordParameter trustPWParameter =
new PasswordParameter("ssltrustpw", "SSL Trust Store Password",
"The password for the JSSE trust store", false, "");
// The placeholder parameter used as a spacer in the admin interface.
private PlaceholderParameter placeholder = new PlaceholderParameter();
// The parameter used to indicate the first attribute to retrieve.
private StringParameter attr1Parameter =
new StringParameter("attr1", "First Attribute to Retrieve",
"The first attribute to retrieve from the user's " +
"entry as part of the authentication process.",
true, DEFAULT_ATTR1);
// The parameter used to indicate the first attribute to retrieve.
private StringParameter attr2Parameter =
new StringParameter("attr2", "Second Attribute to Retrieve",
"The second attribute to retrieve from the user's " +
"entry as part of the authentication process.",
true, DEFAULT_ATTR2);
// The parameter used to indicate the first attribute to retrieve.
private StringParameter attr3Parameter =
new StringParameter("attr3", "Third Attribute to Retrieve",
"The third attribute to retrieve from the user's " +
"entry as part of the authentication process.",
true, DEFAULT_ATTR3);
// The parameter used to indicate the bind DN.
private StringParameter bindDNParameter =
new StringParameter("binddn", "Directory Bind DN",
"The DN to use when binding to the directory " +
"server to perform search and modify operations.",
false, "");
// The parameter used to indicate the address of the directory server.
private StringParameter hostParameter =
new StringParameter("ldap_host", "Directory Server Address",
"The address for the directory server.", true, "");
// The parameter that specifies the location of the SSL key store
private StringParameter keyStoreParameter =
new StringParameter("sslkeystore", "SSL Key Store",
"The path to the JSSE key store to use for an " +
"SSL-based connection", false, "");
// The parameter used to indicate the attribute to use for the login ID.
private StringParameter loginIDParameter =
new StringParameter("login_id_attr", "Login ID Attribute",
"The attribute to use as the login ID to find the " +
"user's entry.", true, DEFAULT_LOG_ID_ATTR);
// The parameter used to indicate the first login ID value or value pattern.
private StringParameter loginIDValue1Parameter =
new StringParameter("login_id_value_1", "Login ID Value 1",
"The text to use as the value of the login ID " +
"attribute in search filters created using the " +
"first set of user criteria. The value may " +
"contain a range of numbers in square brackets.",
true, "");
// The parameter used to indicate the second login ID value or value pattern.
private StringParameter loginIDValue2Parameter =
new StringParameter("login_id_value_2", "Login ID Value 2",
"The text to use as the value of the login ID " +
"attribute in search filters created using the " +
"second set of user criteria. The value may " +
"contain a range of numbers in square brackets.",
true, "");
// The parameter used to indicate the search base for the directory.private
private StringParameter searchBaseParameter =
new StringParameter("search_base", "User Search Base",
"The DN in the directory server under which user " +
"entries may be found.", true, "");
// The parameter that specifies the location of the SSL trust store
private StringParameter trustStoreParameter =
new StringParameter("ssltruststore", "SSL Trust Store",
"The path to the JSSE trust store to use for an " +
"SSL-based connection", false, "");
// The stat tracker that will categorize the reasons for auth failures.
private CategoricalTracker failureReasonTracker;
// The stat trackers that will count the numbers of authentication attempts.
private IncrementalTracker overallAttemptCounter;
private IncrementalTracker attemptCounter1;
private IncrementalTracker attemptCounter2;
// The stat trackers that will count the numbers of failed authentications.
private IncrementalTracker overallFailureCounter;
private IncrementalTracker failureCounter1;
private IncrementalTracker failureCounter2;
// The stat trackers that will count the numbers of successful
// authentications.
private IncrementalTracker overallSuccessCounter;
private IncrementalTracker successCounter1;
private IncrementalTracker successCounter2;
// The LDAP connection that will be used for authentication operations by this
// thread.
private LDAPConnection authConnection;
// The LDAP connection that will be used for bind operations by this thread.
private LDAPConnection bindConnection;
// The random number generator for this thread.
private Random random;
// The stat trackers that will time each authentication.
private TimeTracker overallAuthTimer;
private TimeTracker authTimer1;
private TimeTracker authTimer2;
/**
* Creates a new instance of this job thread. This constructor does not need
* to do anything other than invoke the constructor for the superclass.
*/
public WeightedSiteMinderJobClass()
{
super();
}
/**
* {@inheritDoc}
*/
@Override()
public String getJobName()
{
return "LDAP Weighted SiteMinder Load Simulator";
}
/**
* {@inheritDoc}
*/
@Override()
public String getShortDescription()
{
return "Process a sequence of LDAP search, bind, and update operations";
}
/**
* {@inheritDoc}
*/
@Override()
public String[] getLongDescription()
{
return new String[]
{
"This job can be used to simulate the load observed when using some " +
"versions of Netegrity SiteMinder. That load consists of eight " +
"search, one bind, and one modify operation."
};
}
/**
* {@inheritDoc}
*/
@Override()
public String getJobCategoryName()
{
return "LDAP";
}
/**
* {@inheritDoc}
*/
@Override()
public ParameterList getParameterStubs()
{
Parameter[] parameterArray = new Parameter[]
{
placeholder,
hostParameter,
portParameter,
bindDNParameter,
bindPWParameter,
placeholder,
searchBaseParameter,
loginIDValue1Parameter,
loginIDValue2Parameter,
weightParameter,
loginPasswordParameter,
loginIDParameter,
placeholder,
attr1Parameter,
attr2Parameter,
attr3Parameter,
modAttrsParameter,
placeholder,
warmUpParameter,
coolDownParameter,
timeLimitParameter,
delayParameter,
maxRateParameter,
rateLimitDurationParameter,
placeholder,
useSSLParameter,
blindTrustParameter,
keyStoreParameter,
keyPWParameter,
trustStoreParameter,
trustPWParameter,
placeholder,
skipBindParameter,
ignoreInvCredParameter,
shareConnsParameter
};
return new ParameterList(parameterArray);
}
/**
* {@inheritDoc}
*/
@Override()
public StatTracker[] getStatTrackerStubs(String clientID, String threadID,
int collectionInterval)
{
return new StatTracker[]
{
new IncrementalTracker(clientID, threadID,
STAT_TRACKER_OVERALL_AUTHENTICATION_ATTEMPTS,
collectionInterval),
new IncrementalTracker(clientID, threadID,
STAT_TRACKER_AUTHENTICATION_1_ATTEMPTS,
collectionInterval),
new IncrementalTracker(clientID, threadID,
STAT_TRACKER_AUTHENTICATION_2_ATTEMPTS,
collectionInterval),
new IncrementalTracker(clientID, threadID,
STAT_TRACKER_OVERALL_SUCCESSFUL_AUTHENTICATIONS,
collectionInterval),
new IncrementalTracker(clientID, threadID,
STAT_TRACKER_SUCCESSFUL_AUTHENTICATIONS_1,
collectionInterval),
new IncrementalTracker(clientID, threadID,
STAT_TRACKER_SUCCESSFUL_AUTHENTICATIONS_2,
collectionInterval),
new IncrementalTracker(clientID, threadID,
STAT_TRACKER_OVERALL_FAILED_AUTHENTICATIONS,
collectionInterval),
new IncrementalTracker(clientID, threadID,
STAT_TRACKER_FAILED_AUTHENTICATIONS_1,
collectionInterval),
new IncrementalTracker(clientID, threadID,
STAT_TRACKER_FAILED_AUTHENTICATIONS_2,
collectionInterval),
new TimeTracker(clientID, threadID,
STAT_TRACKER_OVERALL_AUTHENTICATION_TIME,
collectionInterval),
new TimeTracker(clientID, threadID, STAT_TRACKER_AUTHENTICATION_1_TIME,
collectionInterval),
new TimeTracker(clientID, threadID, STAT_TRACKER_AUTHENTICATION_2_TIME,
collectionInterval),
new CategoricalTracker(clientID, threadID, STAT_TRACKER_FAIL_REASON,
collectionInterval)
};
}
/**
* {@inheritDoc}
*/
@Override()
public StatTracker[] getStatTrackers()
{
return new StatTracker[]
{
overallAttemptCounter,
attemptCounter1,
attemptCounter2,
overallSuccessCounter,
successCounter1,
successCounter2,
overallFailureCounter,
failureCounter1,
failureCounter2,
overallAuthTimer,
authTimer1,
authTimer2,
failureReasonTracker
};
}
/**
* {@inheritDoc}
*/
@Override()
public void validateJobInfo(int numClients, int threadsPerClient,
int threadStartupDelay, Date startTime,
Date stopTime, int duration,
int collectionInterval, ParameterList parameters)
throws InvalidValueException
{
// The login ID value parameters must be parseable as value patterns.
StringParameter p =
parameters.getStringParameter(loginIDValue1Parameter.getName());
if ((p != null) && p.hasValue())
{
try
{
new ValuePattern(p.getValue());
}
catch (ParseException pe)
{
throw new InvalidValueException("The value provided for the '" +
p.getDisplayName() + "' parameter is not a valid value " +
"pattern: " + pe.getMessage(), pe);
}
}
p = parameters.getStringParameter(loginIDValue2Parameter.getName());
if ((p != null) && p.hasValue())
{
try
{
new ValuePattern(p.getValue());
}
catch (ParseException pe)
{
throw new InvalidValueException("The value provided for the '" +
p.getDisplayName() + "' parameter is not a valid value " +
"pattern: " + pe.getMessage(), pe);
}
}
}
/**
* {@inheritDoc}
*/
@Override()
public boolean providesParameterTest()
{
return true;
}
/**
* {@inheritDoc}
*/
@Override()
public boolean testJobParameters(ParameterList parameters,
ArrayList<String> outputMessages)
{
// Get all the parameters that we might need to perform the test.
StringParameter hostParam =
parameters.getStringParameter(hostParameter.getName());
if ((hostParam == null) || (! hostParam.hasValue()))
{
outputMessages.add("ERROR: No directory server address was provided.");
return false;
}
String host = hostParam.getStringValue();
IntegerParameter portParam =
parameters.getIntegerParameter(portParameter.getName());
if ((portParam == null) || (! hostParam.hasValue()))
{
outputMessages.add("ERROR: No directory server port was provided.");
return false;
}
int port = portParam.getIntValue();
boolean useSSL = false;
BooleanParameter useSSLParam =
parameters.getBooleanParameter(useSSLParameter.getName());
if (useSSLParam != null)
{
useSSL = useSSLParam.getBooleanValue();
}
String bindDN = "";
StringParameter bindDNParam =
parameters.getStringParameter(bindDNParameter.getName());
if ((bindDNParam != null) && bindDNParam.hasValue())
{
bindDN = bindDNParam.getStringValue();
}
String bindPassword = "";
PasswordParameter bindPWParam =
parameters.getPasswordParameter(bindPWParameter.getName());
if ((bindPWParam != null) && bindPWParam.hasValue())
{
bindPassword = bindPWParam.getStringValue();
}
StringParameter baseDNParam =
parameters.getStringParameter(searchBaseParameter.getName());
if ((baseDNParam == null) || (! baseDNParam.hasValue()))
{
outputMessages.add("ERROR: No base DN was provided.");
return false;
}
String baseDN = baseDNParam.getStringValue();
// Create the LDAPConnection object that we will use to communicate with the
// directory server.
LDAPConnection conn;
if (useSSL)
{
try
{
SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager());
conn = new LDAPConnection(sslUtil.createSSLSocketFactory());
}
catch (Exception e)
{
outputMessages.add("ERROR: Unable to instantiate the blind trust " +
"socket factory for use in creating the SSL " +
"connection: " + stackTraceToString(e));
return false;
}
}
else
{
conn = new LDAPConnection();
}
// Attempt to establish a connection to the directory server.
try
{
if (useSSL)
{
outputMessages.add("Attempting to establish an SSL-based connection " +
"to " + host + ':' + port + "....");
}
else
{
outputMessages.add("Attempting to establish a connection to " + host +
':' + port + "....");
}
conn.connect(host, port, 10000);
outputMessages.add("Connected successfully.");
outputMessages.add("");
}
catch (Exception e)
{
outputMessages.add("ERROR: Unable to connect to the directory " +
"server: " + stackTraceToString(e));
return false;
}
// Attempt to bind to the directory server using the bind DN and password.
try
{
outputMessages.add("Attempting to perform an LDAPv3 bind to the " +
"directory server with a DN of '" + bindDN + "'....");
conn.bind(bindDN, bindPassword);
outputMessages.add("Bound successfully.");
outputMessages.add("");
}
catch (Exception e)
{
try
{
conn.close();
} catch (Exception e2) {}
outputMessages.add("ERROR: Unable to bind to the directory server: " +
stackTraceToString(e));
return false;
}
// Make sure that the entry specified as the base DN exists.
try
{
outputMessages.add("Checking to make sure that the base DN entry '" +
baseDN + "' exists in the directory....");
Entry baseDNEntry = conn.getEntry(baseDN, "1.1");
if (baseDNEntry == null)
{
try
{
conn.close();
} catch (Exception e2) {}
outputMessages.add("ERROR: Unable to retrieve the base DN entry.");
return false;
}
else
{
outputMessages.add("Successfully read the base DN entry.");
outputMessages.add("");
}
}
catch (Exception e)
{
try
{
conn.close();
} catch (Exception e2) {}
outputMessages.add("ERROR: Unable to retrieve the base DN entry: " +
stackTraceToString(e));
return false;
}
// At this point, all tests have passed. Close the connection and return
// true.
try
{
conn.close();
} catch (Exception e) {}
outputMessages.add("All tests completed successfully.");
return true;
}
/**
* {@inheritDoc}
*/
@Override()
public void initializeClient(String clientID, ParameterList parameters)
throws UnableToRunException
{
// Seed the parent random number generator.
parentRandom = new Random();
// Get the directory server address
hostParameter = parameters.getStringParameter(hostParameter.getName());
if (hostParameter == null)
{
throw new UnableToRunException("No directory server host provided.");
}
else
{
directoryHost = hostParameter.getStringValue();
}
// Get the directory server port
portParameter = parameters.getIntegerParameter(portParameter.getName());
if (portParameter != null)
{
directoryPort = portParameter.getIntValue();
}
// Get the DN to use to bind to the directory server.
bindDNParameter = parameters.getStringParameter(bindDNParameter.getName());
if (bindDNParameter == null)
{
bindDN = "";
}
else
{
bindDN = bindDNParameter.getStringValue();
}
// Get the password to use to bind to the directory server.
bindPWParameter =
parameters.getPasswordParameter(bindPWParameter.getName());
if (bindPWParameter == null)
{
bindPW = "";
}
else
{
bindPW = bindPWParameter.getStringValue();
}
// Get the search base
searchBaseParameter =
parameters.getStringParameter(searchBaseParameter.getName());
if (searchBaseParameter != null)
{
searchBase = searchBaseParameter.getStringValue();
}
// Get the password to use when authenticating to the directory.
loginPasswordParameter =
parameters.getPasswordParameter(loginPasswordParameter.getName());
if ((loginPasswordParameter != null) &&
(loginPasswordParameter.hasValue()))
{
loginPassword = loginPasswordParameter.getStringValue();
}
// Get the login ID value for the first user criteria.
loginIDValue1Parameter =
parameters.getStringParameter(loginIDValue1Parameter.getName());
try
{
loginIDPattern1 =
new ValuePattern(loginIDValue1Parameter.getStringValue());
}
catch (Exception e)
{
throw new UnableToRunException("Cannot parse login ID pattern 1: " +
stackTraceToString(e), e);
}
// Get the login ID value for the first user criteria.
loginIDValue2Parameter =
parameters.getStringParameter(loginIDValue2Parameter.getName());
try
{
loginIDPattern2 =
new ValuePattern(loginIDValue2Parameter.getStringValue());
}
catch (Exception e)
{
throw new UnableToRunException("Cannot parse login ID pattern 2: " +
stackTraceToString(e), e);
}
// Get the weight.
weightParameter = parameters.getIntegerParameter(weightParameter.getName());
if ((weightParameter != null) && (weightParameter.hasValue()))
{
loginID1Percent = weightParameter.getIntValue();
}
// Get the login ID attribute.
loginIDParameter =
parameters.getStringParameter(loginIDParameter.getName());
if (loginIDParameter != null)
{
loginIDAttr = loginIDParameter.getStringValue();
}
// Get the attributes to retrieve.
attr1Parameter = parameters.getStringParameter(attr1Parameter.getName());
if (attr1Parameter != null)
{
searchAttr1 = attr1Parameter.getStringValue();
filter1 = Filter.createPresenceFilter(searchAttr1);
returnAttrs1 = new String[] { searchAttr1 };
}
attr2Parameter = parameters.getStringParameter(attr2Parameter.getName());
if (attr2Parameter != null)
{
searchAttr2 = attr2Parameter.getStringValue();
filter2 = Filter.createPresenceFilter(searchAttr2);
returnAttrs2 = new String[] { searchAttr2 };
}
attr3Parameter = parameters.getStringParameter(attr3Parameter.getName());
if (attr3Parameter != null)
{
searchAttr3 = attr3Parameter.getStringValue();
filter3 = Filter.createPresenceFilter(searchAttr3);
returnAttrs3 = new String[] { searchAttr3 };
}
returnAttrsOC = new String[] { "objectClass" };
// Get the attributes to modify.
modAttrs = null;
modAttrsParameter =
parameters.getMultiLineTextParameter(modAttrsParameter.getName());
if ((modAttrsParameter != null) && (modAttrsParameter.hasValue()))
{
modAttrs = modAttrsParameter.getNonBlankLines();
}
// Determine whether to skip the bind attempt.
skipBind = false;
skipBindParameter =
parameters.getBooleanParameter(skipBindParameter.getName());
if (skipBindParameter != null)
{
skipBind = skipBindParameter.getBooleanValue();
}
// Get the warm up time.
warmUpTime = 0;
warmUpParameter = parameters.getIntegerParameter(warmUpParameter.getName());
if (warmUpParameter != null)
{
warmUpTime = warmUpParameter.getIntValue();
}
// Get the cool down time.
coolDownTime = 0;
coolDownParameter =
parameters.getIntegerParameter(coolDownParameter.getName());
if (coolDownParameter != null)
{
coolDownTime = coolDownParameter.getIntValue();
}
// Get the max operation time limit.
timeLimitParameter =
parameters.getIntegerParameter(timeLimitParameter.getName());
if (timeLimitParameter != null)
{
timeLimit = timeLimitParameter.getIntValue();
}
// Initialize the rate limiter.
rateLimiter = null;
maxRateParameter =
parameters.getIntegerParameter(maxRateParameter.getName());
if ((maxRateParameter != null) && maxRateParameter.hasValue())
{
int maxRate = maxRateParameter.getIntValue();
if (maxRate > 0)
{
int rateIntervalSeconds = 0;
rateLimitDurationParameter = parameters.getIntegerParameter(
rateLimitDurationParameter.getName());
if ((rateLimitDurationParameter != null) &&
rateLimitDurationParameter.hasValue())
{
rateIntervalSeconds = rateLimitDurationParameter.getIntValue();
}
if (rateIntervalSeconds <= 0)
{
rateIntervalSeconds = getClientSideJob().getCollectionInterval();
}
rateLimiter = new FixedRateBarrier(rateIntervalSeconds * 1000L,
maxRate * rateIntervalSeconds);
}
}
// Get the delay between authentication attempts.
delay = 0;
delayParameter = parameters.getIntegerParameter(delayParameter.getName());
if (delayParameter != null)
{
delay = delayParameter.getIntValue();
}
// Get the flag indicating whether we should use SSL or not
useSSL = false;
useSSLParameter = parameters.getBooleanParameter(useSSLParameter.getName());
if (useSSLParameter != null)
{
useSSL = useSSLParameter.getBooleanValue();
}
// Get the indicator that specifies whether to ignore invalid credentials
// errors.
ignoreInvCredParameter =
parameters.getBooleanParameter(ignoreInvCredParameter.getName());
if (ignoreInvCredParameter != null)
{
ignoreInvalidCredentials = ignoreInvCredParameter.getBooleanValue();
}
// Get the indicator that specifies whether to use shared connections.
shareConnsParameter =
parameters.getBooleanParameter(shareConnsParameter.getName());
if (shareConnsParameter != null)
{
useSharedConnections = shareConnsParameter.getBooleanValue();
}
// If we are to use shared connections, then establish them now.
if (useSharedConnections)
{
if (useSSL)
{
try
{
SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager());
sharedAuthConnection =
new LDAPConnection(sslUtil.createSSLSocketFactory());
sharedBindConnection =
new LDAPConnection(sslUtil.createSSLSocketFactory());
}
catch (Exception e)
{
throw new UnableToRunException(String.valueOf(e), e);
}
}
else
{
sharedAuthConnection = new LDAPConnection();
sharedBindConnection = new LDAPConnection();
}
try
{
sharedAuthConnection.connect(directoryHost, directoryPort, 10000);
sharedAuthConnection.bind(bindDN, bindPW);
sharedBindConnection.connect(directoryHost, directoryPort, 10000);
}
catch (Exception e)
{
throw new UnableToRunException("Could not establish shared " +
"connections to the directory: " + e,
e);
}
LDAPConnectionOptions opts = sharedAuthConnection.getConnectionOptions();
opts.setResponseTimeoutMillis(1000L * timeLimit);
sharedAuthConnection.setConnectionOptions(opts);
sharedBindConnection.setConnectionOptions(opts);
}
}
/**
* {@inheritDoc}
*/
@Override()
public void initializeThread(String clientID, String threadID,
int collectionInterval, ParameterList parameters)
throws UnableToRunException
{
// Seed the random number generator for this thread.
random = new Random(parentRandom.nextLong());
// If we are not going to use shared connections, then create the
// connections for use by this thread. Otherwise, just grab the shared
// connections.
if (useSharedConnections)
{
authConnection = sharedAuthConnection;
bindConnection = sharedBindConnection;
}
else
{
if (useSSL)
{
try
{
SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager());
authConnection =
new LDAPConnection(sslUtil.createSSLSocketFactory());
bindConnection =
new LDAPConnection(sslUtil.createSSLSocketFactory());
}
catch (Exception e)
{
throw new UnableToRunException(String.valueOf(e), e);
}
}
else
{
authConnection = new LDAPConnection();
bindConnection = new LDAPConnection();
}
try
{
authConnection.connect(directoryHost, directoryPort, 10000);
authConnection.bind(bindDN, bindPW);
bindConnection.connect(directoryHost, directoryPort, 10000);
}
catch (Exception e)
{
throw new UnableToRunException("Unable to establish the connections " +
"to the directory server: " + e, e);
}
LDAPConnectionOptions opts = authConnection.getConnectionOptions();
opts.setResponseTimeoutMillis(1000L * timeLimit);
authConnection.setConnectionOptions(opts);
bindConnection.setConnectionOptions(opts);
}
// Create the stat trackers.
overallAttemptCounter =
new IncrementalTracker(clientID, threadID,
STAT_TRACKER_OVERALL_AUTHENTICATION_ATTEMPTS,
collectionInterval);
attemptCounter1 =
new IncrementalTracker(clientID, threadID,
STAT_TRACKER_AUTHENTICATION_1_ATTEMPTS,
collectionInterval);
attemptCounter2 =
new IncrementalTracker(clientID, threadID,
STAT_TRACKER_AUTHENTICATION_2_ATTEMPTS,
collectionInterval);
overallSuccessCounter =
new IncrementalTracker(clientID, threadID,
STAT_TRACKER_OVERALL_SUCCESSFUL_AUTHENTICATIONS,
collectionInterval);
successCounter1 =
new IncrementalTracker(clientID, threadID,
STAT_TRACKER_SUCCESSFUL_AUTHENTICATIONS_1,
collectionInterval);
successCounter2 =
new IncrementalTracker(clientID, threadID,
STAT_TRACKER_SUCCESSFUL_AUTHENTICATIONS_2,
collectionInterval);
overallFailureCounter =
new IncrementalTracker(clientID, threadID,
STAT_TRACKER_OVERALL_FAILED_AUTHENTICATIONS,
collectionInterval);
failureCounter1 =
new IncrementalTracker(clientID, threadID,
STAT_TRACKER_FAILED_AUTHENTICATIONS_1,
collectionInterval);
failureCounter2 =
new IncrementalTracker(clientID, threadID,
STAT_TRACKER_FAILED_AUTHENTICATIONS_2,
collectionInterval);
overallAuthTimer = new TimeTracker(clientID, threadID,
STAT_TRACKER_OVERALL_AUTHENTICATION_TIME,
collectionInterval);
authTimer1 = new TimeTracker(clientID, threadID,
STAT_TRACKER_AUTHENTICATION_1_TIME,
collectionInterval);
authTimer2 = new TimeTracker(clientID, threadID,
STAT_TRACKER_AUTHENTICATION_2_TIME,
collectionInterval);
failureReasonTracker = new CategoricalTracker(clientID, threadID,
STAT_TRACKER_FAIL_REASON,
collectionInterval);
// Enable real-time reporting of the data for these stat trackers.
RealTimeStatReporter statReporter = getStatReporter();
if (statReporter != null)
{
String jobID = getJobID();
overallAttemptCounter.enableRealTimeStats(statReporter, jobID);
attemptCounter1.enableRealTimeStats(statReporter, jobID);
attemptCounter2.enableRealTimeStats(statReporter, jobID);
overallSuccessCounter.enableRealTimeStats(statReporter, jobID);
successCounter1.enableRealTimeStats(statReporter, jobID);
successCounter2.enableRealTimeStats(statReporter, jobID);
overallFailureCounter.enableRealTimeStats(statReporter, jobID);
failureCounter1.enableRealTimeStats(statReporter, jobID);
failureCounter2.enableRealTimeStats(statReporter, jobID);
overallAuthTimer.enableRealTimeStats(statReporter, jobID);
authTimer1.enableRealTimeStats(statReporter, jobID);
authTimer2.enableRealTimeStats(statReporter, jobID);
}
}
/**
* {@inheritDoc}
*/
@Override()
public void runJob()
{
// Determine the range of time for which we should collect statistics.
long currentTime = System.currentTimeMillis();
boolean collectingStats = false;
long startCollectingTime = currentTime + (1000 * warmUpTime);
long stopCollectingTime = Long.MAX_VALUE;
if ((coolDownTime > 0) && (getShouldStopTime() > 0))
{
stopCollectingTime = getShouldStopTime() - (1000 * coolDownTime);
}
// Define a variable that will be used to determine how long to sleep
// between attempts.
long authStartTime = 0;
// Loop until it is time to stop.
while (! shouldStop())
{
if (rateLimiter != null)
{
if (rateLimiter.await())
{
continue;
}
}
currentTime = System.currentTimeMillis();
if ((! collectingStats) && (currentTime >= startCollectingTime) &&
(currentTime < stopCollectingTime))
{
// Start all the stat trackers.
overallAttemptCounter.startTracker();
attemptCounter1.startTracker();
attemptCounter2.startTracker();
overallSuccessCounter.startTracker();
successCounter1.startTracker();
successCounter2.startTracker();
overallFailureCounter.startTracker();
failureCounter1.startTracker();
failureCounter2.startTracker();
overallAuthTimer.startTracker();
authTimer1.startTracker();
authTimer2.startTracker();
failureReasonTracker.startTracker();
collectingStats = true;
}
else if ((collectingStats) && (currentTime >= stopCollectingTime))
{
overallAttemptCounter.stopTracker();
attemptCounter1.stopTracker();
attemptCounter2.stopTracker();
overallSuccessCounter.stopTracker();
successCounter1.stopTracker();
successCounter2.stopTracker();
overallFailureCounter.stopTracker();
failureCounter1.stopTracker();
failureCounter2.stopTracker();
overallAuthTimer.stopTracker();
authTimer1.stopTracker();
authTimer2.stopTracker();
failureReasonTracker.stopTracker();
collectingStats = false;
}
// See if we need to sleep before the next attempt
if ((delay > 0) && (authStartTime > 0))
{
long now = System.currentTimeMillis();
long sleepTime = delay - (now - authStartTime);
if (sleepTime > 0)
{
try
{
Thread.sleep(sleepTime);
} catch (InterruptedException ie) {}
if (shouldStop())
{
break;
}
}
}
// Get a random number between 1 and 100 to use to determine which user
// criteria to use to attempt the authentication.
int weight = ((random.nextInt() & 0x7FFFFFFF) % 100);
if (weight < loginID1Percent)
{
// Get a random user number from the first range and translate that to a
// login ID and password.
String[] loginInfo = getLoginInfo1();
String loginID = loginInfo[0];
String password = loginInfo[1];
// Start the auth attempt timer now.
if (delay > 0)
{
authStartTime = System.currentTimeMillis();
}
// Increment the number of authentication attempts and start the timer
if (collectingStats)
{
overallAttemptCounter.increment();
attemptCounter1.increment();
overallAuthTimer.startTimer();
authTimer1.startTimer();
}
String failureReason = "Search 1";
try
{
// First, issue a search to try to find the user's entry.
String userDN = null;
Filter filter = Filter.createEqualityFilter(loginIDAttr, loginID);
SearchResult searchResult = authConnection.search(searchBase,
SearchScope.SUB, filter, returnAttrsOC);
userDN = searchResult.getSearchEntries().get(0).getDN();
// Make sure that we got a user DN. If not, then it's a failed
// attempt.
if (userDN == null)
{
if (collectingStats)
{
overallFailureCounter.increment();
failureCounter1.increment();
overallAuthTimer.stopTimer();
authTimer1.stopTimer();
failureReasonTracker.increment(failureReason);
}
continue;
}
// Now do a base-level search on the user's entry to retrieve the
// objectClass attribute.
failureReason = "Search 2";
filter = Filter.createPresenceFilter("objectClass");
authConnection.search(userDN, SearchScope.BASE, filter,
returnAttrsOC);
// Now bind as the user.
if (! skipBind)
{
failureReason = "Bind";
try
{
bindConnection.bind(userDN, password);
}
catch (LDAPException le)
{
if (le.getResultCode() == ResultCode.INVALID_CREDENTIALS)
{
if (! ignoreInvalidCredentials)
{
if (collectingStats)
{
overallFailureCounter.increment();
failureCounter1.increment();
overallAuthTimer.stopTimer();
authTimer1.stopTimer();
failureReasonTracker.increment(failureReason);
}
continue;
}
}
else
{
if (collectingStats)
{
overallFailureCounter.increment();
failureCounter1.increment();
overallAuthTimer.stopTimer();
authTimer1.stopTimer();
failureReasonTracker.increment(failureReason);
}
continue;
}
}
}
// Now retrieve the "attr1" attribute from the user's entry.
failureReason = "Search 3";
authConnection.search(userDN, SearchScope.BASE, filter1,
returnAttrs1);
// Retrieve the "attr2" attribute from the user's entry.
failureReason = "Search 4";
authConnection.search(userDN, SearchScope.BASE, filter2,
returnAttrs2);
// Retrieve the first attribute again.
failureReason = "Search 5";
authConnection.search(userDN, SearchScope.BASE, filter1,
returnAttrs1);
// Perform a modification on the entry
if ((modAttrs != null) && (modAttrs.length > 0))
{
failureReason = "Modify";
Modification[] mods = new Modification[modAttrs.length];
for (int i=0; i < modAttrs.length; i++)
{
mods[i] = new Modification(ModificationType.REPLACE, modAttrs[i],
getRandomString(80));
}
authConnection.modify(userDN, mods);
}
// Retrieve the first attribute again.
failureReason = "Search 6";
authConnection.search(userDN, SearchScope.BASE, filter1,
returnAttrs1);
// Retrieve the first attribute again.
failureReason = "Search 7";
authConnection.search(userDN, SearchScope.BASE, filter1,
returnAttrs1);
// Retrieve the third attribute.
failureReason = "Search 8";
authConnection.search(userDN, SearchScope.BASE, filter3,
returnAttrs3);
}
catch (Exception e)
{
if (collectingStats)
{
overallFailureCounter.increment();
failureCounter1.increment();
overallAuthTimer.stopTimer();
authTimer1.stopTimer();
failureReasonTracker.increment(failureReason);
}
continue;
}
// If we have gotten here, then everything is done and we can consider
// the authentication successful.
if (collectingStats)
{
overallSuccessCounter.increment();
successCounter1.increment();
overallAuthTimer.stopTimer();
authTimer1.stopTimer();
}
}
else
{
// Get a random user number from the second range and translate that to
// a login ID and password.
String[] loginInfo = getLoginInfo2();
String loginID = loginInfo[0];
String password = loginInfo[1];
// Start the auth attempt timer now.
if (delay > 0)
{
authStartTime = System.currentTimeMillis();
}
// Increment the number of authentication attempts and start the timer
if (collectingStats)
{
overallAttemptCounter.increment();
attemptCounter2.increment();
overallAuthTimer.startTimer();
authTimer2.startTimer();
}
String failureReason = "Search 1";
try
{
// First, issue a search to try to find the user's entry.
String userDN = null;
Filter filter = Filter.createEqualityFilter(loginIDAttr, loginID);
SearchResult searchResult = authConnection.search(searchBase,
SearchScope.SUB, filter, returnAttrsOC);
userDN = searchResult.getSearchEntries().get(0).getDN();
// Make sure that we got a user DN. If not, then it's a failed
// attempt.
if (userDN == null)
{
if (collectingStats)
{
overallFailureCounter.increment();
failureCounter2.increment();
overallAuthTimer.stopTimer();
authTimer2.stopTimer();
failureReasonTracker.increment(failureReason);
}
continue;
}
// Now do a base-level search on the user's entry to retrieve the
// objectClass attribute.
failureReason = "Search 2";
filter = Filter.createPresenceFilter("objectClass");
authConnection.search(userDN, SearchScope.BASE, filter,
returnAttrsOC);
// Now bind as the user.
if (! skipBind)
{
failureReason = "Bind";
try
{
bindConnection.bind(userDN, password);
}
catch (LDAPException le)
{
if (le.getResultCode() == ResultCode.INVALID_CREDENTIALS)
{
if (! ignoreInvalidCredentials)
{
if (collectingStats)
{
overallFailureCounter.increment();
failureCounter2.increment();
overallAuthTimer.stopTimer();
authTimer2.stopTimer();
failureReasonTracker.increment(failureReason);
}
continue;
}
}
else
{
if (collectingStats)
{
overallFailureCounter.increment();
failureCounter2.increment();
overallAuthTimer.stopTimer();
authTimer2.stopTimer();
failureReasonTracker.increment(failureReason);
}
continue;
}
}
}
// Now retrieve the "attr1" attribute from the user's entry.
failureReason = "Search 3";
authConnection.search(userDN, SearchScope.BASE, filter1,
returnAttrs1);
// Retrieve the "attr2" attribute from the user's entry.
failureReason = "Search 4";
authConnection.search(userDN, SearchScope.BASE, filter2,
returnAttrs2);
// Retrieve the first attribute again.
failureReason = "Search 5";
authConnection.search(userDN, SearchScope.BASE, filter1,
returnAttrs1);
// Perform a modification on the entry
if ((modAttrs != null) && (modAttrs.length > 0))
{
failureReason = "Modify";
Modification[] mods = new Modification[modAttrs.length];
for (int i=0; i < modAttrs.length; i++)
{
mods[i] = new Modification(ModificationType.REPLACE, modAttrs[i],
getRandomString(80));
}
authConnection.modify(userDN, mods);
}
// Retrieve the first attribute again.
failureReason = "Search 6";
authConnection.search(userDN, SearchScope.BASE, filter1,
returnAttrs1);
// Retrieve the first attribute again.
failureReason = "Search 7";
authConnection.search(userDN, SearchScope.BASE, filter1,
returnAttrs1);
// Retrieve the third attribute.
failureReason = "Search 8";
authConnection.search(userDN, SearchScope.BASE, filter3,
returnAttrs3);
}
catch (Exception e)
{
if (collectingStats)
{
overallFailureCounter.increment();
failureCounter2.increment();
overallAuthTimer.stopTimer();
authTimer2.stopTimer();
failureReasonTracker.increment(failureReason);
}
continue;
}
// If we have gotten here, then everything is done and we can consider
// the authentication successful.
if (collectingStats)
{
overallSuccessCounter.increment();
successCounter2.increment();
overallAuthTimer.stopTimer();
authTimer2.stopTimer();
}
}
}
// Stop all the stat trackers.
if (collectingStats)
{
overallAttemptCounter.stopTracker();
attemptCounter1.stopTracker();
attemptCounter2.stopTracker();
overallSuccessCounter.stopTracker();
successCounter1.stopTracker();
successCounter2.stopTracker();
overallFailureCounter.stopTracker();
failureCounter1.stopTracker();
failureCounter2.stopTracker();
overallAuthTimer.stopTracker();
authTimer1.stopTracker();
authTimer2.stopTracker();
failureReasonTracker.stopTracker();
}
// Close the connections to the directory server if appropriate.
if (! useSharedConnections)
{
try
{
authConnection.close();
} catch (Exception e) {}
try
{
bindConnection.close();
} catch (Exception e) {}
}
}
/**
* {@inheritDoc}
*/
@Override()
public void destroyThread()
{
if (authConnection != null)
{
try
{
authConnection.close();
} catch (Exception e) {}
authConnection = null;
}
if (bindConnection != null)
{
try
{
bindConnection.close();
} catch (Exception e) {}
bindConnection = null;
}
}
/**
* {@inheritDoc}
*/
@Override()
public void finalizeClient()
{
// Make sure that the shared connections get closed properly.
if (useSharedConnections)
{
try
{
sharedAuthConnection.close();
} catch (Exception e) {}
try
{
sharedBindConnection.close();
} catch (Exception e) {}
}
}
/**
* Retrieves an array containing the login ID and password that should be
* used to authenticate to the directory based on the first set of user
* criteria.
*
* @return An array containing the login ID and password.
*/
private static String[] getLoginInfo1()
{
return new String[]
{
loginIDPattern1.nextValue(),
loginPassword
};
}
/**
* Retrieves an array containing the login ID and password that should be
* used to authenticate to the directory based on the second set of user
* criteria.
*
* @return An array containing the login ID and password.
*/
private static String[] getLoginInfo2()
{
return new String[]
{
loginIDPattern2.nextValue(),
loginPassword
};
}
/**
* Retrieves a string of random characters of the specified length.
*
* @param length The number of characters to include in the string.
*
* @return The generated string of random characters.
*/
private String getRandomString(int length)
{
char[] returnArray = new char[length];
for (int i=0; i < returnArray.length; i++)
{
returnArray[i] = ALPHABET[Math.abs((random.nextInt()) & 0x7FFFFFFF) %
ALPHABET.length];
}
return new String(returnArray);
}
}