KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > slamd > example > DigestMD5AuthRateJobClass


1 /*
2  * Sun Public License
3  *
4  * The contents of this file are subject to the Sun Public License Version
5  * 1.0 (the "License"). You may not use this file except in compliance with
6  * the License. A copy of the License is available at http://www.sun.com/
7  *
8  * The Original Code is the SLAMD Distributed Load Generation Engine.
9  * The Initial Developer of the Original Code is Neil A. Wilson.
10  * Portions created by Neil A. Wilson are Copyright (C) 2004.
11  * Some preexisting portions Copyright (C) 2002-2004 Sun Microsystems, Inc.
12  * All Rights Reserved.
13  *
14  * Contributor(s): Neil A. Wilson
15  */

16 package com.sun.slamd.example;
17
18
19
20 import java.io.*;
21 import java.security.*;
22 import java.util.*;
23 import netscape.ldap.*;
24 import netscape.ldap.factory.*;
25 import com.sun.slamd.job.*;
26 import com.sun.slamd.parameter.*;
27 import com.sun.slamd.stat.*;
28
29
30
31 /**
32  * This class defines a SLAMD job that repeatedly performs SASL DIGEST-MD5
33  * authentications against an LDAP directory server. It will find the user's
34  * entry based on a login ID, attempt to bind as that user using the SASL
35  * DIGEST-MD5 mechanism, and optionally verify whether that user is a member of
36  * a static group, dynamic group, or role.
37  *
38  *
39  * @author Neil A. Wilson
40  */

41 public class DigestMD5AuthRateJobClass
42        extends JobClass
43 {
44   /**
45    * The value used to indicate that no membership determination will be made.
46    */

47   public static final int MEMBERSHIP_TYPE_NONE = 0;
48
49
50
51   /**
52    * The value used to indicate that an attempt will be made to determine
53    * whether the user is a member of a static group.
54    */

55   public static final int MEMBERSHIP_TYPE_STATIC = 1;
56
57
58
59   /**
60    * The value used to indicate that an attempt will be made to determine
61    * whether the user is a member of a dynamic group.
62    */

63   public static final int MEMBERSHIP_TYPE_DYNAMIC = 2;
64
65
66
67   /**
68    * The value used to indicate that an attempt will be made to determine
69    * whether the user is a member of a role.
70    */

71   public static final int MEMBERSHIP_TYPE_ROLE = 3;
72
73
74
75   /**
76    * The default attribute used as the login ID.
77    */

78   public static final String JavaDoc DEFAULT_LOG_ID_ATTR = "uid";
79
80
81
82   /**
83    * The name of the LDAP attribute that contains the DNs of the roles to which
84    * a user belongs.
85    */

86   public static final String JavaDoc ROLE_ATTR = "nsRole";
87
88
89
90   /**
91    * The system property used to specify the location of the JSSE key store.
92    */

93   public static final String JavaDoc SSL_KEY_STORE_PROPERTY =
94        "javax.net.ssl.keyStore";
95
96
97
98   /**
99    * The system property used to specify the password for the JSSE key store.
100    */

101   public static final String JavaDoc SSL_KEY_PASSWORD_PROPERTY =
102        "javax.net.ssl.keyStorePassword";
103
104
105
106   /**
107    * The system property used to specify the location of the JSSE trust store.
108    */

109   public static final String JavaDoc SSL_TRUST_STORE_PROPERTY =
110        "javax.net.ssl.trustStore";
111
112
113
114   /**
115    * The system property used to specify the password for the JSSE trust store.
116    */

117   public static final String JavaDoc SSL_TRUST_PASSWORD_PROPERTY =
118        "javax.net.ssl.trustStorePassword";
119
120
121
122   /**
123    * The name of the stat tracker that will be used to count the number of
124    * authentication attempts.
125    */

126   public static final String JavaDoc STAT_TRACKER_AUTHENTICATION_ATTEMPTS =
127        "Authentication Attempts";
128
129
130
131
132   /**
133    * The name of the stat tracker that will be used to keep track of the time
134    * required to perform each authentication.
135    */

136   public static final String JavaDoc STAT_TRACKER_AUTHENTICATION_TIME =
137        "Authentication Time";
138
139
140
141
142   /**
143    * The name of the stat tracker that will be used to count the number of
144    * failed authentications.
145    */

146   public static final String JavaDoc STAT_TRACKER_FAILED_AUTHENTICATIONS =
147        "Failed Authentications";
148
149
150
151   /**
152    * The name of the stat tracker that will be used to count the number of
153    * successful authentications.
154    */

155   public static final String JavaDoc STAT_TRACKER_SUCCESSFUL_AUTHENTICATIONS =
156        "Successful Authentications";
157
158
159
160   /**
161    * The set of attributes to retrieve if there aren't any attributes to
162    * retrieve.
163    */

164   public static final String JavaDoc[] NO_ATTRS = new String JavaDoc[] { "1.1" };
165
166
167
168   // Indicates whether the client should blindly trust any SSL certificate.
169
static boolean blindTrust;
170
171   // Indicates whether bind failures because of invalid credentials will be
172
// ignored (so you don't actually have to know user passwords).
173
static boolean ignoreInvalidCredentials;
174
175   // Indicates whether login IDs/passwords are read from a data file or from
176
// parameters.
177
static boolean useDataFile;
178
179   // Indicates whether the login ID value should be interpreted as a range.
180
static boolean useLoginIDRange;
181
182   // Indicates whether the login ID value should be incremented sequentially.
183
static boolean useSequential;
184
185   // Indicate whether to use SSL when communicating with the directory server.
186
static boolean useSSL;
187
188   // Indicates whether all threads will used a shared set of connections or if
189
// each thread will have its own connection.
190
static boolean useSharedConnections;
191
192   // The time to keep working after stopping statistics collection.
193
static int coolDownTime;
194
195   // The port number of the directory server.
196
static int directoryPort;
197
198   // The maximum value to use in the range of login IDs.
199
static int loginIDMax;
200
201   // The minimum value to use in the range of login IDs.
202
static int loginIDMin;
203
204   // The maximum value to use in the range of login IDs.
205
static int loginIDSpan;
206
207   // The type of membership to check when performing an authentication.
208
static int membershipType;
209
210   // The next value that should be used for sequentially incrementing login IDs.
211
static int sequentialCounter;
212
213   // The maximum length of time that any single LDAP operation will be allowed
214
// to take before it is cancelled.
215
static int timeLimit;
216
217   // The time to start working before beginning statistics collection.
218
static int warmUpTime;
219
220   // The delay in milliseconds between authentication attempts.
221
static long delay;
222
223   // The LDAP connection that will be used for shared authentication operations.
224
static LDAPConnection sharedAuthConnection;
225
226   // The random number generator that will seed the thread-specific random
227
// number generators.
228
static Random parentRandom;
229
230   // The DN to use to bind to the directory when performing the search and
231
// modify operations.
232
static String JavaDoc bindDN;
233
234   // The password for the bind DN.
235
static String JavaDoc bindPW;
236
237   // The address of the directory server.
238
static String JavaDoc directoryHost;
239
240   // The name of the attribute that will be used to initially find the user's
241
// entry (the login ID attribute).
242
static String JavaDoc loginIDAttr;
243
244   // The text to include after the numeric part of the login ID.
245
static String JavaDoc loginIDFinal;
246
247   // The text to include before the numeric part of the login ID.
248
static String JavaDoc loginIDInitial;
249
250   // The password to use when authenticating.
251
static String JavaDoc loginPassword;
252
253   // The DN of the entry for which to determine membership.
254
static String JavaDoc membershipDN;
255
256   // The search base to use if dynamic group membership is to be determined.
257
static String JavaDoc membershipURLBase;
258
259   // The search filter to use if dynamic group membership is to be determined.
260
static String JavaDoc membershipURLFilter;
261
262   // The DN to use as the search base when trying to find user entries in the
263
// directory.
264
static String JavaDoc searchBase;
265
266   // The path of the JSSE key store to use for SSL.
267
static String JavaDoc sslKeyStore;
268
269   // The password used to access the JSSE key store.
270
static String JavaDoc sslKeyPassword;
271
272   // The path of the JSSE trust store to use for SSL.
273
static String JavaDoc sslTrustStore;
274
275   // The password used to access the JSSE trust store.
276
static String JavaDoc sslTrustPassword;
277
278   // The set of login IDs that will be used to authenticate.
279
static String JavaDoc[] loginIDs;
280
281   // The set of passwords associated with the login IDs.
282
static String JavaDoc[] loginPasswords;
283
284
285
286   // The parameter that indicates whether the client should trust any SSL cert.
287
BooleanParameter blindTrustParameter =
288     new BooleanParameter("blind_trust", "Blindly Trust Any Certificate",
289                          "Indicates whether the client should blindly trust " +
290                          "any certificate presented by the server, or " +
291                          "whether the key and trust stores should be used.",
292                          true);
293
294   // The parameter used to indicate whether invalid credential results are
295
// ignored.
296
BooleanParameter ignoreInvCredParameter =
297        new BooleanParameter("ignore_49", "Ignore Invalid Credentials Errors",
298                             "Indicates whether bind failures because of " +
299                             "invalid credentials (err=49). This makes it " +
300                             "possible to use this job without actually " +
301                             "know user passwords.", false);
302
303   // The parameter used to indicate whether connections are shared.
304
BooleanParameter shareConnsParameter =
305        new BooleanParameter("share_conns", "Share Connections between Threads",
306                             "Indicates whether the connections to the " +
307                             "directory server will be shared between threads " +
308                             "or if each client thread will have its own " +
309                             "connections.", true);
310
311   // The parameter that indicates whether the connection should use SSL
312
BooleanParameter useSSLParameter =
313     new BooleanParameter("usessl", "Use SSL",
314                          "Indicates whether SSL should be used for all " +
315                          "communication with the directory server", false);
316
317   // The parameter used to indicate the login ID/password file.
318
FileURLParameter loginDataFileParameter =
319        new FileURLParameter("login_data_file", "Login Data File URL",
320                             "The URL (FILE or HTTP) of the file containing " +
321                             "the login IDs and passwords to use for the " +
322                             "authentication.", null, false);
323
324   // The parmeter that specifies the cool-down time in seconds.
325
IntegerParameter coolDownParameter =
326        new IntegerParameter("cool_down", "Cool Down Time",
327                             "The time in seconds that the job should " +
328                             "continue searching after ending statistics " +
329                             "collection.", true, 0, true, 0, false, 0);
330
331   // The parameter that indicates the delay that should be used between each
332
// authentication attempt.
333
IntegerParameter delayParameter =
334        new IntegerParameter("delay", "Time Between Authentications (ms)",
335                             "Specifies the length of time in milliseconds " +
336                             "each thread should wait between authentication " +
337                             "attempts. Note that this delay will be " +
338                             "between the starts of consecutive attempts and " +
339                             "not between the end of one attempt and the " +
340                             "beginning of the next. If an authentication " +
341                             "takes longer than this length of time, then " +
342                             "there will be no delay.", true, 0, true, 0, false,
343                             0);
344
345   // The parameter used to indicate the port number for the directory server.
346
IntegerParameter portParameter =
347        new IntegerParameter("ldap_port", "Directory Server Port",
348                             "The port number for the directory server.", true,
349                             389, true, 1, true, 65535);
350
351   // The parameter used to indicate the maximum length of time that any single
352
// LDAP operation will be allowed to take.
353
IntegerParameter timeLimitParameter =
354        new IntegerParameter("time_limit", "Operation Time Limit",
355                             "The maximum length of time in seconds that any " +
356                             "single LDAP operation will be allowed to take " +
357                             "before it is cancelled.", true, 0, true, 0, false,
358                             0);
359
360   // The parmeter that specifies the cool-down time in seconds.
361
IntegerParameter warmUpParameter =
362        new IntegerParameter("warm_up", "Warm Up Time",
363                             "The time in seconds that the job should " +
364                             "search before beginning statistics collection.",
365                             true, 0, true, 0, false, 0);
366
367   // The parameter used to indicate the password for the bind DN.
368
PasswordParameter bindPWParameter =
369        new PasswordParameter("bindpw", "Directory Bind Password",
370                              "The password to use when binding to the " +
371                              "directory server to perform search and modify " +
372                              "operations.", false, "");
373
374   // The parameter used to indicate the password to use when authenticating to
375
// the directory.
376
PasswordParameter loginPasswordParameter =
377        new PasswordParameter("login_id_pw", "Login Password",
378                              "The password to use when authenticating to the " +
379                              "directory for user authentications.", false, "");
380
381   // The parameter that specifies the password for the SSL key store
382
PasswordParameter keyPWParameter =
383     new PasswordParameter("sslkeypw", "SSL Key Store Password",
384                           "The password for the JSSE key store", false, "");
385
386   // The parameter that specifies the password for the SSL key store
387
PasswordParameter trustPWParameter =
388     new PasswordParameter("ssltrustpw", "SSL Trust Store Password",
389                           "The password for the JSSE trust store", false, "");
390
391   // The placeholder parameter used as a spacer in the admin interface.
392
PlaceholderParameter placeholder = new PlaceholderParameter();
393
394   // The parameter used to indicate the bind DN.
395
StringParameter bindDNParameter =
396        new StringParameter("binddn", "Directory Bind DN",
397                            "The DN to use when binding to the directory " +
398                            "server to perform search and modify operations.",
399                            false, "");
400
401   // The parameter used to indicate the address of the directory server.
402
StringParameter hostParameter =
403        new StringParameter("ldap_host", "Directory Server Address",
404                            "The address for the directory server.", true, "");
405
406   // The parameter that specifies the location of the SSL key store
407
StringParameter keyStoreParameter =
408     new StringParameter("sslkeystore", "SSL Key Store",
409                         "The path to the JSSE key store to use for an " +
410                         "SSL-based connection", false, "");
411
412   // The parameter used to indicate the attribute to use for the login ID.
413
StringParameter loginIDParameter =
414        new StringParameter("login_id_attr", "Login ID Attribute",
415                            "The attribute to use as the login ID to find the " +
416                            "user's entry.", true, DEFAULT_LOG_ID_ATTR);
417
418   // The parameter used to indicate the login ID value or value pattern.
419
StringParameter loginIDValueParameter =
420        new StringParameter("login_id_value", "Login ID Value",
421                            "The text to use as the value of the login ID " +
422                            "attribute in search filters. The value may " +
423                            "contain a range of numbers in square brackets.",
424                            false, "");
425
426   // The parameter used to specify the DN of the entry in which to check whether
427
// the user is a member.
428
StringParameter membershipDNParameter =
429        new StringParameter("membership_dn", "Membership DN",
430                            "The DN of a static group, dynamic group, or role " +
431                            "for which to determine whether the user is a " +
432                            "member.", false, "");
433
434   // The parameter used to indicate the search base for the directory.
435
StringParameter searchBaseParameter =
436     new StringParameter("search_base", "User Search Base",
437                         "The DN in the directory server under which user " +
438                         "entries may be found.", true, "");
439
440   // The parameter that specifies the location of the SSL trust store
441
StringParameter trustStoreParameter =
442     new StringParameter("ssltruststore", "SSL Trust Store",
443                         "The path to the JSSE trust store to use for an " +
444                         "SSL-based connection", false, "");
445
446   // The stat tracker that will count the number of authentication attempts.
447
IncrementalTracker attemptCounter;
448
449   // The stat tracker that will count the number of failed authentications.
450
IncrementalTracker failureCounter;
451
452   // The stat tracker that will count the number of successful authentications.
453
IncrementalTracker successCounter;
454
455   // The LDAP connection that will be used for authentication operations by this
456
// thread.
457
LDAPConnection authConnection;
458
459   // The LDAP connection that will be used for bind operations by this thread.
460
LDAPConnection bindConnection;
461
462   // The set of constraints that will be used for non-search/bind operations.
463
LDAPConstraints authConstraints;
464
465   // The socket factory used to perform DIGEST-MD5 authentications.
466
LDAPDigestMD5SocketFactory socketFactory;
467
468   // The set of constraints that will be used for search operations.
469
LDAPSearchConstraints authSearchConstraints;
470
471   // The random number generator for this thread.
472
Random random;
473
474   // The stat tracker that will time each authentication.
475
TimeTracker authTimer;
476
477
478
479   /**
480    * Creates a new instance of this job thread. This constructor does not need
481    * to do anything other than invoke the constructor for the superclass.
482    */

483   public DigestMD5AuthRateJobClass()
484   {
485     super();
486   }
487
488
489
490   /**
491    * Returns the user-friendly name that is to be used for this job class in the
492    * administrative interface.
493    *
494    * @return The user-friendly name for this job class.
495    */

496   public String JavaDoc getJobName()
497   {
498     return "LDAP DIGEST-MD5 Auth Rate";
499   }
500
501
502
503   /**
504    * Returns a description of this job that can be seen in the administrative
505    * interface.
506    *
507    * @return A description of this job class.
508    */

509   public String JavaDoc getJobDescription()
510   {
511     return "This job performs repeated DIGEST-MD5 authentications against an " +
512       "LDAP directory server, optionally including a lookup to verify that " +
513       "the user is a member of an indicated group or role.";
514   }
515
516
517
518   /**
519    * Retrieves the name of the category in which this job class exists. This is
520    * used to help arrange the job classes in the administrative interface.
521    *
522    * @return The name of the category in which this job class exists.
523    */

524   public String JavaDoc getJobCategoryName()
525   {
526     return "LDAP";
527   }
528
529
530
531   /**
532    * Returns the set of parameters whose value may be specified by the end user.
533    *
534    * @return The set of configurable parameters for this job class.
535    */

536   public ParameterList getParameterStubs()
537   {
538     Parameter[] parameterArray = new Parameter[]
539     {
540       placeholder,
541       hostParameter,
542       portParameter,
543       bindDNParameter,
544       bindPWParameter,
545       placeholder,
546       searchBaseParameter,
547       loginDataFileParameter,
548       loginIDValueParameter,
549       loginPasswordParameter,
550       loginIDParameter,
551       membershipDNParameter,
552       placeholder,
553       warmUpParameter,
554       coolDownParameter,
555       timeLimitParameter,
556       delayParameter,
557       placeholder,
558       useSSLParameter,
559       blindTrustParameter,
560       keyStoreParameter,
561       keyPWParameter,
562       trustStoreParameter,
563       trustPWParameter,
564       ignoreInvCredParameter,
565       shareConnsParameter
566     };
567
568     return new ParameterList(parameterArray);
569   }
570
571
572
573   /**
574    * Retrieves the set of stat trackers that will be maintained by this job
575    * class. The stat trackers returned by this method do not have to actually
576    * contain any statistics -- the display name and stat tracker class should
577    * be the only information that callers of this method should rely upon. Note
578    * that this list can be different from the list of statistics actually
579    * collected by the job in some cases (e.g., if the job may not return all the
580    * stat trackers it advertises in all cases, or if the job may return stat
581    * trackers that it did not advertise), but it is a possibility that only the
582    * stat trackers returned by this method will be accessible for some features
583    * in the SLAMD server.
584    *
585    * @param clientID The client ID that should be used for the
586    * returned stat trackers.
587    * @param threadID The thread ID that should be used for the
588    * returned stat trackers.
589    * @param collectionInterval The collection interval that should be used for
590    * the returned stat trackers.
591    *
592    * @return The set of stat trackers that will be maintained by this job
593    * class.
594    */

595   public StatTracker[] getStatTrackerStubs(String JavaDoc clientID, String JavaDoc threadID,
596                                            int collectionInterval)
597   {
598     return new StatTracker[]
599     {
600       new IncrementalTracker(clientID, threadID,
601                              STAT_TRACKER_AUTHENTICATION_ATTEMPTS,
602                              collectionInterval),
603       new IncrementalTracker(clientID, threadID,
604                              STAT_TRACKER_SUCCESSFUL_AUTHENTICATIONS,
605                              collectionInterval),
606       new IncrementalTracker(clientID, threadID,
607                              STAT_TRACKER_FAILED_AUTHENTICATIONS,
608                              collectionInterval),
609       new TimeTracker(clientID, threadID, STAT_TRACKER_AUTHENTICATION_TIME,
610                       collectionInterval)
611     };
612   }
613
614
615
616   /**
617    * Retrieves the set of stat trackers that are maintained by this job class.
618    *
619    * @return The set of stat trackers for this job class.
620    */

621   public StatTracker[] getStatTrackers()
622   {
623     return new StatTracker[]
624     {
625       attemptCounter,
626       successCounter,
627       failureCounter,
628       authTimer
629     };
630   }
631
632
633
634   /**
635    * Provides a means of validating the information used to schedule the job,
636    * including the scheduling information and list of parameters.
637    *
638    * @param numClients The number of clients that should be used to
639    * run the job.
640    * @param threadsPerClient The number of threads that should be created on
641    * each client to run the job.
642    * @param threadStartupDelay The delay in milliseconds that should be used
643    * when starting the client threads.
644    * @param startTime The time that the job should start running.
645    * @param stopTime The time that the job should stop running.
646    * @param duration The maximum length of time in seconds that the
647    * job should be allowed to run.
648    * @param collectionInterval The collection interval that should be used
649    * when gathering statistics for the job.
650    * @param parameters The set of parameters provided to this job that
651    * can be used to customize its behavior.
652    *
653    * @throws InvalidValueException If the provided information is not
654    * appropriate for running this job.
655    */

656   public void validateJobInfo(int numClients, int threadsPerClient,
657                               int threadStartupDelay, Date startTime,
658                               Date stopTime, int duration,
659                               int collectionInterval, ParameterList parameters)
660          throws InvalidValueException
661   {
662     FileURLParameter loginDataURLParameter =
663          parameters.getFileURLParameter(loginDataFileParameter.getName());
664     if ((loginDataURLParameter == null) ||
665         (! loginDataURLParameter.hasValue()))
666     {
667       StringParameter loginValueParameter =
668            parameters.getStringParameter(loginIDValueParameter.getName());
669       PasswordParameter loginPWParameter =
670            parameters.getPasswordParameter(loginPasswordParameter.getName());
671
672       if ((loginValueParameter == null) ||
673           (! loginValueParameter.hasValue()) ||
674           (loginPWParameter == null) ||
675           (! loginPWParameter.hasValue()))
676       {
677         throw new InvalidValueException("You must specify either a login " +
678                                         "data file URL or a login ID value " +
679                                         "and password");
680       }
681     }
682   }
683
684
685
686   /**
687    * Indicates whether this job class implements logic that makes it possible to
688    * test the validity of job parameters before scheduling the job for execution
689    * (e.g., to see if the server is reachable using the information provided).
690    *
691    * @return <CODE>true</CODE> if this job provides a means of testing the job
692    * parameters, or <CODE>false</CODE> if not.
693    */

694   public boolean providesParameterTest()
695   {
696     return true;
697   }
698
699
700
701   /**
702    * Provides a means of testing the provided job parameters to determine
703    * whether they are valid (e.g., to see if the server is reachable) before
704    * scheduling the job for execution. This method will be executed by the
705    * SLAMD server system itself and not by any of the clients.
706    *
707    * @param parameters The job parameters to be tested.
708    * @param outputMessages The lines of output that were generated as part of
709    * the testing process. Each line of output should
710    * be added to this list as a separate string, and
711    * empty strings (but not <CODE>null</CODE> values)
712    * are allowed to provide separation between
713    * different messages. No formatting should be
714    * provided for these messages, however, since they
715    * may be displayed in either an HTML or plain text
716    * interface.
717    *
718    * @return <CODE>true</CODE> if the test completed successfully, or
719    * <CODE>false</CODE> if not. Note that even if the test did not
720    * complete successfully, the user will be presented with a warning
721    * but will still be allowed to schedule the job using the provided
722    * parameters. This is necessary because the parameters may still be
723    * valid even if the server couldn't validate them at the time the
724    * job was scheduled (e.g., if the server wasn't running or could not
725    * be reached by the SLAMD server even though it could be by the
726    * clients).
727    */

728   public boolean testJobParameters(ParameterList parameters,
729                                    ArrayList outputMessages)
730   {
731     // Get all the parameters that we might need to perform the test.
732
StringParameter hostParam =
733          parameters.getStringParameter(hostParameter.getName());
734     if ((hostParam == null) || (! hostParam.hasValue()))
735     {
736       outputMessages.add("ERROR: No directory server address was provided.");
737       return false;
738     }
739     String JavaDoc host = hostParam.getStringValue();
740
741
742     IntegerParameter portParam =
743          parameters.getIntegerParameter(portParameter.getName());
744     if ((portParam == null) || (! hostParam.hasValue()))
745     {
746       outputMessages.add("ERROR: No directory server port was provided.");
747       return false;
748     }
749     int port = portParam.getIntValue();
750
751
752     boolean useSSL = false;
753     BooleanParameter useSSLParam =
754          parameters.getBooleanParameter(useSSLParameter.getName());
755     if (useSSLParam != null)
756     {
757       useSSL = useSSLParam.getBooleanValue();
758     }
759
760
761     boolean blindTrust = true;
762     BooleanParameter blindTrustParam =
763          parameters.getBooleanParameter(blindTrustParameter.getName());
764     if (blindTrustParam != null)
765     {
766       blindTrust = blindTrustParam.getBooleanValue();
767     }
768
769
770     String JavaDoc keyStore = null;
771     StringParameter keyStoreParam =
772          parameters.getStringParameter(keyStoreParameter.getName());
773     if ((keyStoreParam != null) && keyStoreParam.hasValue())
774     {
775       keyStore = keyStoreParam.getStringValue();
776       File keyStoreFile = new File(keyStore);
777       if (useSSL && (! blindTrust) && (! keyStoreFile.exists()))
778       {
779         outputMessages.add("WARNING: Key store file \"" + keyStore +
780                            "\" not found on SLAMD server system. This test " +
781                            "will blindly trust any SSL certificate " +
782                            "presented by the directory server.");
783         outputMessages.add("");
784         blindTrust = true;
785       }
786       else
787       {
788         System.setProperty(SSL_KEY_STORE_PROPERTY, keyStore);
789       }
790     }
791
792
793     String JavaDoc keyStorePassword = "";
794     StringParameter keyPassParam =
795          parameters.getStringParameter(keyPWParameter.getName());
796     if ((keyPassParam != null) && keyPassParam.hasValue())
797     {
798       keyStorePassword = keyPassParam.getStringValue();
799       System.setProperty(SSL_KEY_PASSWORD_PROPERTY, keyStorePassword);
800     }
801
802
803     String JavaDoc trustStore = null;
804     StringParameter trustStoreParam =
805          parameters.getStringParameter(trustStoreParameter.getName());
806     if ((trustStoreParam != null) && trustStoreParam.hasValue())
807     {
808       trustStore = trustStoreParam.getStringValue();
809       File trustStoreFile = new File(trustStore);
810       if (useSSL && (! blindTrust) && (! trustStoreFile.exists()))
811       {
812         outputMessages.add("WARNING: trust store file \"" + trustStore +
813                            "\" not found on SLAMD server system. This test " +
814                            "will blindly trust any SSL certificate " +
815                            "presented by the directory server.");
816         outputMessages.add("");
817         blindTrust = true;
818       }
819       else
820       {
821         System.setProperty(SSL_TRUST_STORE_PROPERTY, trustStore);
822       }
823     }
824
825
826     String JavaDoc trustStorePassword = "";
827     StringParameter trustPassParam =
828          parameters.getStringParameter(trustPWParameter.getName());
829     if ((trustPassParam != null) && trustPassParam.hasValue())
830     {
831       trustStorePassword = trustPassParam.getStringValue();
832       System.setProperty(SSL_TRUST_PASSWORD_PROPERTY, trustStorePassword);
833     }
834
835
836     String JavaDoc bindDN = "";
837     StringParameter bindDNParam =
838          parameters.getStringParameter(bindDNParameter.getName());
839     if ((bindDNParam != null) && bindDNParam.hasValue())
840     {
841       bindDN = bindDNParam.getStringValue();
842     }
843
844
845     String JavaDoc bindPassword = "";
846     PasswordParameter bindPWParam =
847          parameters.getPasswordParameter(bindPWParameter.getName());
848     if ((bindPWParam != null) && bindPWParam.hasValue())
849     {
850       bindPassword = bindPWParam.getStringValue();
851     }
852
853
854     StringParameter baseDNParam =
855          parameters.getStringParameter(searchBaseParameter.getName());
856     if ((baseDNParam == null) || (! baseDNParam.hasValue()))
857     {
858       outputMessages.add("ERROR: No base DN was provided.");
859       return false;
860     }
861     String JavaDoc baseDN = baseDNParam.getStringValue();
862
863
864     // Create the LDAPConnection object that we will use to communicate with the
865
// directory server.
866
LDAPConnection conn;
867     if (useSSL)
868     {
869       if (blindTrust)
870       {
871         try
872         {
873           conn = new LDAPConnection(new JSSEBlindTrustSocketFactory());
874         }
875         catch (Exception JavaDoc e)
876         {
877           outputMessages.add("ERROR: Unable to instantiate the blind trust " +
878                              "socket factory for use in creating the SSL " +
879                              "connection: " + stackTraceToString(e));
880           return false;
881         }
882       }
883       else
884       {
885         conn = new LDAPConnection(new JSSESocketFactory(null));
886       }
887     }
888     else
889     {
890       conn = new LDAPConnection();
891     }
892
893
894     // Attempt to establish a connection to the directory server.
895
try
896     {
897       if (useSSL)
898       {
899         outputMessages.add("Attempting to establish an SSL-based connection " +
900                            "to " + host + ":" + port + "....");
901       }
902       else
903       {
904         outputMessages.add("Attempting to establish a connection to " + host +
905                            ":" + port + "....");
906       }
907       conn.connect(host, port);
908       outputMessages.add("Connected successfully.");
909       outputMessages.add("");
910     }
911     catch (Exception JavaDoc e)
912     {
913       outputMessages.add("ERROR: Unable to connect to the directory " +
914                          "server: " + stackTraceToString(e));
915       return false;
916     }
917
918
919     // Attempt to bind to the directory server using the bind DN and password.
920
try
921     {
922       outputMessages.add("Attempting to perform an LDAPv3 bind to the " +
923                          "directory server with a DN of '" + bindDN + "'....");
924       conn.bind(3, bindDN, bindPassword);
925       outputMessages.add("Bound successfully.");
926       outputMessages.add("");
927     }
928     catch (Exception JavaDoc e)
929     {
930       try
931       {
932         conn.disconnect();
933       } catch (Exception JavaDoc e2) {}
934
935       outputMessages.add("ERROR: Unable to bind to the directory server: " +
936                          stackTraceToString(e));
937       return false;
938     }
939
940
941     // Make sure that the entry specified as the base DN exists.
942
try
943     {
944       outputMessages.add("Checking to make sure that the base DN entry '" +
945                          baseDN + "' exists in the directory....");
946       LDAPEntry baseDNEntry = conn.read(baseDN, new String JavaDoc[] { "1.1" });
947       if (baseDNEntry == null)
948       {
949         try
950         {
951           conn.disconnect();
952         } catch (Exception JavaDoc e2) {}
953
954         outputMessages.add("ERROR: Unable to retrieve the base DN entry.");
955         return false;
956       }
957       else
958       {
959         outputMessages.add("Successfully read the base DN entry.");
960         outputMessages.add("");
961       }
962     }
963     catch (Exception JavaDoc e)
964     {
965       try
966       {
967         conn.disconnect();
968       } catch (Exception JavaDoc e2) {}
969
970       outputMessages.add("ERROR: Unable to retrieve the base DN entry: " +
971                          stackTraceToString(e));
972       return false;
973     }
974
975
976     // At this point, all tests have passed. Close the connection and return
977
// true.
978
try
979     {
980       conn.disconnect();
981     } catch (Exception JavaDoc e) {}
982
983     outputMessages.add("All tests completed successfully.");
984     return true;
985   }
986
987
988
989   /**
990    * Performs initialization for this job on each client immediately before each
991    * thread is created to actually run the job.
992    *
993    * @param clientID The ID assigned to the client running this job.
994    * @param parameters The set of parameters provided to this job that can be
995    * used to customize its behavior.
996    *
997    * @throws UnableToRunException If the client initialization could not be
998    * completed successfully and the job is unable
999    * to run.
1000   */

1001  public void initializeClient(String JavaDoc clientID, ParameterList parameters)
1002         throws UnableToRunException
1003  {
1004    // Get the directory server address
1005
hostParameter = parameters.getStringParameter(hostParameter.getName());
1006    if (hostParameter == null)
1007    {
1008      throw new UnableToRunException("No directory server host provided.");
1009    }
1010    else
1011    {
1012      directoryHost = hostParameter.getStringValue();
1013    }
1014
1015
1016    // Get the directory server port
1017
portParameter = parameters.getIntegerParameter(portParameter.getName());
1018    if (portParameter != null)
1019    {
1020      directoryPort = portParameter.getIntValue();
1021    }
1022
1023    // Get the DN to use to bind to the directory server.
1024
bindDNParameter = parameters.getStringParameter(bindDNParameter.getName());
1025    if (bindDNParameter == null)
1026    {
1027      bindDN = "";
1028    }
1029    else
1030    {
1031      bindDN = bindDNParameter.getStringValue();
1032    }
1033
1034    // Get the password to use to bind to the directory server.
1035
bindPWParameter =
1036         parameters.getPasswordParameter(bindPWParameter.getName());
1037    if (bindPWParameter == null)
1038    {
1039      bindPW = "";
1040    }
1041    else
1042    {
1043      bindPW = bindPWParameter.getStringValue();
1044    }
1045
1046    // Get the search base
1047
searchBaseParameter =
1048         parameters.getStringParameter(searchBaseParameter.getName());
1049    if (searchBaseParameter != null)
1050    {
1051      searchBase = searchBaseParameter.getStringValue();
1052    }
1053
1054
1055    // Get the data from the login ID file.
1056
useDataFile = false;
1057    loginDataFileParameter =
1058         parameters.getFileURLParameter(loginDataFileParameter.getName());
1059    if ((loginDataFileParameter != null) && (loginDataFileParameter.hasValue()))
1060    {
1061      String JavaDoc[] fileLines;
1062      try
1063      {
1064        fileLines = loginDataFileParameter.getNonBlankFileLines();
1065      }
1066      catch (Exception JavaDoc e)
1067      {
1068        throw new UnableToRunException("Unable to retrieve the login data " +
1069                                       "from the file: " + e, e);
1070      }
1071
1072      // Break the login data up into ID and passwords
1073
ArrayList loginIDList = new ArrayList(fileLines.length);
1074      ArrayList passwordList = new ArrayList(fileLines.length);
1075      for (int i=0; i < fileLines.length; i++)
1076      {
1077        try
1078        {
1079          StringTokenizer tokenizer = new StringTokenizer(fileLines[i], "\t");
1080          String JavaDoc loginID = tokenizer.nextToken();
1081          String JavaDoc password = tokenizer.nextToken();
1082          loginIDList.add(loginID);
1083          passwordList.add(password);
1084        } catch (Exception JavaDoc e) {}
1085      }
1086
1087      // Convert the lists into arrays and make sure that at least one login
1088
// ID/password has been provided.
1089
loginIDs = new String JavaDoc[loginIDList.size()];
1090      loginPasswords = new String JavaDoc[passwordList.size()];
1091      loginIDList.toArray(loginIDs);
1092      passwordList.toArray(loginPasswords);
1093      if (loginIDs.length == 0)
1094      {
1095        throw new UnableToRunException("No login IDs/passwords extracted from " +
1096                                       "the login data file.");
1097      }
1098
1099      useDataFile = true;
1100    }
1101    else
1102    {
1103      loginPasswordParameter =
1104           parameters.getPasswordParameter(loginPasswordParameter.getName());
1105      if ((loginPasswordParameter != null) &&
1106            (loginPasswordParameter.hasValue()))
1107      {
1108        loginPassword = loginPasswordParameter.getStringValue();
1109      }
1110
1111      loginIDValueParameter =
1112           parameters.getStringParameter(loginIDValueParameter.getName());
1113      useLoginIDRange = true;
1114      useSequential = false;
1115      String JavaDoc loginIDValue = loginIDValueParameter.getStringValue();
1116      try
1117      {
1118        int openPos = loginIDValue.indexOf('[');
1119        int closePos = loginIDValue.indexOf(']', openPos);
1120        loginIDInitial = loginIDValue.substring(0, openPos);
1121        loginIDFinal = loginIDValue.substring(closePos+1);
1122
1123        int dashPos = loginIDValue.indexOf('-', openPos);
1124        if (dashPos < 0)
1125        {
1126          dashPos = loginIDValue.indexOf(':', openPos);
1127          useSequential = true;
1128        }
1129        loginIDMin = Integer.parseInt(loginIDValue.substring(openPos+1,
1130                                                              dashPos));
1131        loginIDMax = Integer.parseInt(loginIDValue.substring(dashPos+1,
1132                                                              closePos));
1133        loginIDSpan = loginIDMax - loginIDMin + 1;
1134        sequentialCounter = loginIDMin;
1135      }
1136      catch (Exception JavaDoc e)
1137      {
1138        useLoginIDRange = false;
1139        loginIDInitial = loginIDValue;
1140      }
1141    }
1142
1143
1144    // Get the login ID attribute.
1145
loginIDParameter =
1146         parameters.getStringParameter(loginIDParameter.getName());
1147    if (loginIDParameter != null)
1148    {
1149      loginIDAttr = loginIDParameter.getStringValue();
1150    }
1151
1152    // Get the membership entry DN.
1153
membershipDNParameter =
1154         parameters.getStringParameter(membershipDNParameter.getName());
1155    if ((membershipDNParameter != null) && (membershipDNParameter.hasValue()))
1156    {
1157      membershipDN = membershipDNParameter.getStringValue();
1158    }
1159    else
1160    {
1161      membershipDN = null;
1162    }
1163
1164    // Get the warm up time.
1165
warmUpTime = 0;
1166    warmUpParameter = parameters.getIntegerParameter(warmUpParameter.getName());
1167    if (warmUpParameter != null)
1168    {
1169      warmUpTime = warmUpParameter.getIntValue();
1170    }
1171
1172    // Get the cool down time.
1173
coolDownTime = 0;
1174    coolDownParameter =
1175         parameters.getIntegerParameter(coolDownParameter.getName());
1176    if (coolDownParameter != null)
1177    {
1178      coolDownTime = coolDownParameter.getIntValue();
1179    }
1180
1181    // Get the max operation time limit.
1182
timeLimitParameter =
1183         parameters.getIntegerParameter(timeLimitParameter.getName());
1184    if (timeLimitParameter != null)
1185    {
1186      timeLimit = timeLimitParameter.getIntValue();
1187    }
1188
1189    // Get the delay between authentication attempts.
1190
delay = 0;
1191    delayParameter = parameters.getIntegerParameter(delayParameter.getName());
1192    if (delayParameter != null)
1193    {
1194      delay = delayParameter.getIntValue();
1195    }
1196
1197    // Get the flag indicating whether we should use SSL or not
1198
useSSL = false;
1199    useSSLParameter = parameters.getBooleanParameter(useSSLParameter.getName());
1200    if (useSSLParameter != null)
1201    {
1202      useSSL = useSSLParameter.getBooleanValue();
1203    }
1204
1205    // If we are to use SSL, then get all the other SSL-related info
1206
if (useSSL)
1207    {
1208      // Whether to blindly trust any SSL certificate.
1209
blindTrustParameter =
1210           parameters.getBooleanParameter(blindTrustParameter.getName());
1211      if (blindTrustParameter != null)
1212      {
1213        blindTrust = blindTrustParameter.getBooleanValue();
1214      }
1215
1216      // The location of the JSSE key store
1217
sslKeyStore = null;
1218      keyStoreParameter =
1219           parameters.getStringParameter(keyStoreParameter.getName());
1220      if ((keyStoreParameter != null) && (keyStoreParameter.hasValue()))
1221      {
1222        sslKeyStore = keyStoreParameter.getStringValue();
1223        System.setProperty(SSL_KEY_STORE_PROPERTY, sslKeyStore);
1224      }
1225
1226      // The JSSE key store password
1227
sslKeyPassword = null;
1228      keyPWParameter =
1229           parameters.getPasswordParameter(keyPWParameter.getName());
1230      if ((keyPWParameter != null) && (keyPWParameter.hasValue()))
1231      {
1232        sslKeyPassword = keyPWParameter.getStringValue();
1233        System.setProperty(SSL_KEY_PASSWORD_PROPERTY, sslKeyPassword);
1234      }
1235
1236      // The location of the JSSE trust store
1237
sslTrustStore = null;
1238      trustStoreParameter =
1239           parameters.getStringParameter(trustStoreParameter.getName());
1240      if ((trustStoreParameter != null) && (trustStoreParameter.hasValue()))
1241      {
1242        sslTrustStore = trustStoreParameter.getStringValue();
1243        System.setProperty(SSL_TRUST_STORE_PROPERTY, sslTrustStore);
1244      }
1245
1246      // The JSSE trust store password
1247
sslTrustPassword = null;
1248      trustPWParameter =
1249           parameters.getPasswordParameter(trustPWParameter.getName());
1250      if ((trustPWParameter != null) && (trustPWParameter.hasValue()))
1251      {
1252        sslTrustPassword = trustPWParameter.getStringValue();
1253        System.setProperty(SSL_TRUST_PASSWORD_PROPERTY, sslTrustPassword);
1254      }
1255    }
1256
1257
1258    // Get the indicator that specifies whether to ignore invalid credentials
1259
// errors.
1260
ignoreInvCredParameter =
1261         parameters.getBooleanParameter(ignoreInvCredParameter.getName());
1262    if (ignoreInvCredParameter != null)
1263    {
1264      ignoreInvalidCredentials = ignoreInvCredParameter.getBooleanValue();
1265    }
1266
1267    // Get the indicator that specifies whether to use shared connections.
1268
shareConnsParameter =
1269         parameters.getBooleanParameter(shareConnsParameter.getName());
1270    if (shareConnsParameter != null)
1271    {
1272      useSharedConnections = shareConnsParameter.getBooleanValue();
1273    }
1274
1275
1276    // If we are to use shared connections, then establish them now.
1277
if (useSharedConnections)
1278    {
1279      if (useSSL)
1280      {
1281        if (blindTrust)
1282        {
1283          try
1284          {
1285            sharedAuthConnection =
1286                 new LDAPConnection(new JSSEBlindTrustSocketFactory());
1287          }
1288          catch (LDAPException le)
1289          {
1290            throw new UnableToRunException(le.getMessage(), le);
1291          }
1292        }
1293        else
1294        {
1295          sharedAuthConnection = new LDAPConnection(new JSSESocketFactory(null));
1296        }
1297      }
1298      else
1299      {
1300        sharedAuthConnection = new LDAPConnection();
1301      }
1302
1303      try
1304      {
1305        sharedAuthConnection.connect(3, directoryHost, directoryPort, bindDN,
1306                                     bindPW);
1307      }
1308      catch (Exception JavaDoc e)
1309      {
1310        throw new UnableToRunException("Could not establish shared " +
1311                                       "connections to the directory: " + e,
1312                                       e);
1313      }
1314    }
1315
1316
1317    // If we are to perform membership determination, then figure out what
1318
// needs to be done.
1319
membershipType = MEMBERSHIP_TYPE_NONE;
1320    if (membershipDN != null)
1321    {
1322      // First, get a connection to the directory.
1323
LDAPConnection conn = null;
1324      if (useSharedConnections)
1325      {
1326        conn = sharedAuthConnection;
1327      }
1328      else
1329      {
1330        try
1331        {
1332          if (useSSL)
1333          {
1334            if (blindTrust)
1335            {
1336              conn = new LDAPConnection(new JSSEBlindTrustSocketFactory());
1337            }
1338            else
1339            {
1340              conn = new LDAPConnection(new JSSESocketFactory(null));
1341            }
1342          }
1343          else
1344          {
1345            conn = new LDAPConnection();
1346          }
1347          conn.connect(3, directoryHost, directoryPort, bindDN, bindPW);
1348        }
1349        catch (Exception JavaDoc e)
1350        {
1351          throw new UnableToRunException("Could not connect to directory " +
1352                                         "server " + directoryHost + ":" +
1353                                         directoryPort +
1354                                         " to retrieve membership entry.", e);
1355        }
1356      }
1357
1358      // Retrieve the membership DN entry.
1359
String JavaDoc[] attrsToReturn = new String JavaDoc[] { "objectClass", "memberURL" };
1360      LDAPEntry entry = null;
1361      try
1362      {
1363        entry = conn.read(membershipDN);
1364      }
1365      catch (Exception JavaDoc e) {}
1366
1367      if (entry == null)
1368      {
1369        try
1370        {
1371          conn.disconnect();
1372        } catch (Exception JavaDoc e) {}
1373        throw new UnableToRunException("Could not retrieve the membership " +
1374                                       "entry '" + membershipDN + "' from " +
1375                                       "directory " + directoryHost + ":" +
1376                                       directoryPort + ".");
1377      }
1378
1379      // Look at the entry's objectclasses to determine the kind of entry it is.
1380
LDAPAttribute ocAttr = entry.getAttribute("objectClass");
1381      String JavaDoc[] ocValues = null;
1382      if ((ocAttr == null) ||
1383          ((ocValues = ocAttr.getStringValueArray()) == null) ||
1384          (ocValues.length == 0))
1385      {
1386        try
1387        {
1388          conn.disconnect();
1389        } catch (Exception JavaDoc e) {}
1390        throw new UnableToRunException("Could not retrieve objectclass " +
1391                                       "values from '" + membershipDN + "'");
1392      }
1393
1394      for (int i=0; i < ocValues.length; i++)
1395      {
1396        if (ocValues[i].equalsIgnoreCase("groupOfNames") ||
1397            ocValues[i].equalsIgnoreCase("groupOfUniqueNames"))
1398        {
1399          membershipType = MEMBERSHIP_TYPE_STATIC;
1400          break;
1401        }
1402        else if (ocValues[i].equalsIgnoreCase("groupOfURLs"))
1403        {
1404          LDAPAttribute urlAttr = entry.getAttribute("memberURL");
1405          String JavaDoc[] urlValues = null;
1406          if ((urlAttr == null) ||
1407              ((urlValues = urlAttr.getStringValueArray()) == null) ||
1408               (urlValues.length == 0))
1409          {
1410            try
1411            {
1412              conn.disconnect();
1413            } catch (Exception JavaDoc e) {}
1414
1415            throw new UnableToRunException("Could not retrieve memberURL " +
1416                                           "from dynamic group entry " +
1417                                           membershipDN);
1418          }
1419
1420          try
1421          {
1422            LDAPUrl url = new LDAPUrl(urlValues[0]);
1423            membershipURLBase = LDAPDN.normalize(url.getDN());
1424            membershipURLFilter = url.getFilter();
1425          }
1426          catch (Exception JavaDoc e)
1427          {
1428            try
1429            {
1430              conn.disconnect();
1431            } catch (Exception JavaDoc e2) {}
1432
1433            throw new UnableToRunException("Could not interpret " +
1434                                           urlValues[0] + " as an LDAP URL", e);
1435          }
1436
1437          membershipType = MEMBERSHIP_TYPE_DYNAMIC;
1438          break;
1439        }
1440        else if (ocValues[i].toLowerCase().indexOf("role") >= 0)
1441        {
1442          membershipType = MEMBERSHIP_TYPE_ROLE;
1443          membershipDN = LDAPDN.normalize(membershipDN);
1444          break;
1445        }
1446      }
1447
1448      if (membershipType == MEMBERSHIP_TYPE_NONE)
1449      {
1450        throw new UnableToRunException("Could not determine the membership " +
1451                                       "type to check for entry " +
1452                                       membershipDN);
1453      }
1454
1455      if (! useSharedConnections)
1456      {
1457        try
1458        {
1459          conn.disconnect();
1460        } catch (Exception JavaDoc e) {}
1461      }
1462    }
1463
1464    // Seed the parent random number generator.
1465
parentRandom = new Random();
1466  }
1467
1468
1469
1470  /**
1471   * Initializes this job class with the information that it will use when
1472   * actually running the job. This will also initialize the stat trackers used
1473   * by the job.
1474   *
1475   * @param clientID The thread ID for this thread.
1476   * @param threadID The thread ID for this thread.
1477   * @param collectionInterval The collection interval to use for gathering
1478   * statistics while processing the job.
1479   * @param parameters The st of parameters that contain the
1480   * information used to customize the way this job
1481   * is processed.
1482   *
1483   * @throws UnableToRunException If a problem occurs that prevents the thread
1484   * from being able to run properly.
1485   */

1486  public void initializeThread(String JavaDoc clientID, String JavaDoc threadID,
1487                               int collectionInterval, ParameterList parameters)
1488         throws UnableToRunException
1489  {
1490    // Seed the random number generator for this thread.
1491
random = new Random(parentRandom.nextLong());
1492
1493    // If we are not going to use shared connections, then create the
1494
// connections for use by this thread. Otherwise, just grab the shared
1495
// connections.
1496
if (useSharedConnections)
1497    {
1498      authConnection = sharedAuthConnection;
1499    }
1500    else
1501    {
1502      if (useSSL)
1503      {
1504        if (blindTrust)
1505        {
1506          try
1507          {
1508            authConnection =
1509                 new LDAPConnection(new JSSEBlindTrustSocketFactory());
1510          }
1511          catch (LDAPException le)
1512          {
1513            throw new UnableToRunException(le.getMessage(), le);
1514          }
1515        }
1516        else
1517        {
1518          authConnection = new LDAPConnection(new JSSESocketFactory(null));
1519        }
1520      }
1521      else
1522      {
1523        authConnection = new LDAPConnection();
1524      }
1525
1526      try
1527      {
1528        authConnection.connect(3, directoryHost, directoryPort, bindDN, bindPW);
1529      }
1530      catch (Exception JavaDoc e)
1531      {
1532        throw new UnableToRunException("Unable to establish the connections " +
1533                                       "to the directory server: " + e, e);
1534      }
1535    }
1536
1537    try
1538    {
1539      socketFactory = new LDAPDigestMD5SocketFactory();
1540    }
1541    catch (Exception JavaDoc e)
1542    {
1543      throw new UnableToRunException("Could not create DIGEST-MD5 socket " +
1544                                     "factory -- " + e, e);
1545    }
1546
1547    if (useSSL)
1548    {
1549      if (blindTrust)
1550      {
1551        try
1552        {
1553          socketFactory.setAdditionalSocketFactory(
1554                             new JSSEBlindTrustSocketFactory());
1555        }
1556        catch (LDAPException le)
1557        {
1558          throw new UnableToRunException(le.getMessage(), le);
1559        }
1560      }
1561      else
1562      {
1563        socketFactory.setAdditionalSocketFactory(new JSSESocketFactory(null));
1564      }
1565    }
1566
1567    // Initialize the constraints.
1568
authConstraints = authConnection.getConstraints();
1569    authSearchConstraints = authConnection.getSearchConstraints();
1570    authConstraints.setTimeLimit(1000*timeLimit);
1571    authSearchConstraints.setTimeLimit(1000*timeLimit);
1572    authSearchConstraints.setServerTimeLimit(timeLimit);
1573
1574
1575    // Create the stat trackers.
1576
attemptCounter =
1577         new IncrementalTracker(clientID, threadID,
1578                                STAT_TRACKER_AUTHENTICATION_ATTEMPTS,
1579                                collectionInterval);
1580    successCounter =
1581         new IncrementalTracker(clientID, threadID,
1582                                STAT_TRACKER_SUCCESSFUL_AUTHENTICATIONS,
1583                                collectionInterval);
1584    failureCounter =
1585         new IncrementalTracker(clientID, threadID,
1586                                STAT_TRACKER_FAILED_AUTHENTICATIONS,
1587                                collectionInterval);
1588    authTimer = new TimeTracker(clientID, threadID,
1589                                STAT_TRACKER_AUTHENTICATION_TIME,
1590                                collectionInterval);
1591
1592
1593    // Enable real-time reporting of the data for these stat trackers.
1594
RealTimeStatReporter statReporter = getStatReporter();
1595    if (statReporter != null)
1596    {
1597      String JavaDoc jobID = getJobID();
1598      attemptCounter.enableRealTimeStats(statReporter, jobID);
1599      successCounter.enableRealTimeStats(statReporter, jobID);
1600      failureCounter.enableRealTimeStats(statReporter, jobID);
1601      authTimer.enableRealTimeStats(statReporter, jobID);
1602    }
1603  }
1604
1605
1606
1607  /**
1608   * Performs the work of actually running the job. When this method completes,
1609   * the job will be done.
1610   */

1611  public void runJob()
1612  {
1613    // Determine the range of time for which we should collect statistics.
1614
long currentTime = System.currentTimeMillis();
1615    boolean collectingStats = false;
1616    long startCollectingTime = currentTime + (1000 * warmUpTime);
1617    long stopCollectingTime = Long.MAX_VALUE;
1618    if ((coolDownTime > 0) && (getShouldStopTime() > 0))
1619    {
1620      stopCollectingTime = getShouldStopTime() - (1000 * coolDownTime);
1621    }
1622
1623    // Define a variable that will be used to determine how long to sleep
1624
// between attempts.
1625
long authStartTime = 0;
1626
1627
1628    // Loop until it is time to stop.
1629
while (! shouldStop())
1630    {
1631      currentTime = System.currentTimeMillis();
1632      if ((! collectingStats) && (currentTime >= startCollectingTime) &&
1633          (currentTime < stopCollectingTime))
1634      {
1635        // Start all the stat trackers.
1636
attemptCounter.startTracker();
1637        successCounter.startTracker();
1638        failureCounter.startTracker();
1639        authTimer.startTracker();
1640        collectingStats = true;
1641      }
1642      else if ((collectingStats) && (currentTime >= stopCollectingTime))
1643      {
1644        attemptCounter.stopTracker();
1645        successCounter.stopTracker();
1646        failureCounter.stopTracker();
1647        authTimer.stopTracker();
1648        collectingStats = false;
1649      }
1650
1651      // See if we need to sleep before the next attempt
1652
if ((delay > 0) && (authStartTime > 0))
1653      {
1654        long now = System.currentTimeMillis();
1655        long sleepTime = delay - (now - authStartTime);
1656        if (sleepTime > 0)
1657        {
1658          try
1659          {
1660            Thread.sleep(sleepTime);
1661          } catch (InterruptedException JavaDoc ie) {}
1662
1663          if (shouldStop())
1664          {
1665            break;
1666          }
1667        }
1668      }
1669
1670      // Get a random user number and translate that to a login ID and password.
1671
String JavaDoc[] loginInfo = getLoginInfo();
1672      String JavaDoc loginID = loginInfo[0];
1673      String JavaDoc password = loginInfo[1];
1674
1675
1676      // Start the auth attempt timer now.
1677
if (delay > 0)
1678      {
1679        authStartTime = System.currentTimeMillis();
1680      }
1681
1682
1683      // Increment the number of authentication attempts and start the timer
1684
if (collectingStats)
1685      {
1686        attemptCounter.increment();
1687        authTimer.startTimer();
1688      }
1689
1690      // First, issue a search to try to find the user's entry.
1691
String JavaDoc[] attrsToReturn;
1692      if ((membershipDN == null) || (membershipType != MEMBERSHIP_TYPE_ROLE))
1693      {
1694        attrsToReturn = NO_ATTRS;
1695      }
1696      else
1697      {
1698        attrsToReturn = new String JavaDoc[] { ROLE_ATTR };
1699      }
1700
1701      String JavaDoc filter = "(" + loginIDAttr + "=" + loginID + ")";
1702      LDAPSearchResults results;
1703      LDAPEntry userEntry = null;
1704      try
1705      {
1706        results = authConnection.search(searchBase, LDAPConnection.SCOPE_SUB,
1707                                        filter, attrsToReturn, false,
1708                                        authSearchConstraints);
1709        while (results.hasMoreElements())
1710        {
1711          Object JavaDoc element = results.nextElement();
1712          if (element instanceof LDAPEntry)
1713          {
1714            userEntry = (LDAPEntry) element;
1715          }
1716        }
1717      }
1718      catch (LDAPException le)
1719      {
1720        // The search failed, so update the failure counter and stop the timer.
1721
if (collectingStats)
1722        {
1723          failureCounter.increment();
1724          authTimer.stopTimer();
1725        }
1726        continue;
1727      }
1728
1729
1730      // Make sure that we got a user entry. If not, then it's a failure.
1731
if (userEntry == null)
1732      {
1733        if (collectingStats)
1734        {
1735          failureCounter.increment();
1736          authTimer.stopTimer();
1737        }
1738        continue;
1739      }
1740
1741
1742      // Perform a bind as the user to verify that the provided password is
1743
// valid.
1744
try
1745      {
1746        socketFactory.setAuthenticationInfo("dn:" + userEntry.getDN(),
1747                                            password);
1748        bindConnection = new LDAPConnection(socketFactory);
1749        bindConnection.connect(directoryHost, directoryPort);
1750        bindConnection.disconnect();
1751      }
1752      catch (LDAPException le)
1753      {
1754        if (! (ignoreInvalidCredentials &&
1755              (le.getLDAPResultCode() == LDAPException.INVALID_CREDENTIALS)))
1756        {
1757          if (collectingStats)
1758          {
1759            failureCounter.increment();
1760            authTimer.stopTimer();
1761          }
1762          continue;
1763        }
1764      }
1765
1766
1767      // If we are to check membership, then do so now.
1768
if (membershipDN != null)
1769      {
1770        if (isMember(userEntry))
1771        {
1772          if (collectingStats)
1773          {
1774            successCounter.increment();
1775            authTimer.stopTimer();
1776          }
1777        }
1778        else
1779        {
1780          if (collectingStats)
1781          {
1782            failureCounter.increment();
1783            authTimer.stopTimer();
1784          }
1785        }
1786      }
1787      else
1788      {
1789        if (collectingStats)
1790        {
1791          successCounter.increment();
1792          authTimer.stopTimer();
1793        }
1794      }
1795    }
1796
1797
1798
1799    // Stop all the stat trackers.
1800
if (collectingStats)
1801    {
1802      attemptCounter.stopTracker();
1803      successCounter.stopTracker();
1804      failureCounter.stopTracker();
1805      authTimer.stopTracker();
1806    }
1807
1808
1809    // Make sure that the thread-specific connections are closed.
1810
if (! useSharedConnections)
1811    {
1812      try
1813      {
1814        authConnection.disconnect();
1815      } catch (Exception JavaDoc e) {}
1816
1817      try
1818      {
1819        bindConnection.disconnect();
1820      } catch (Exception JavaDoc e) {}
1821    }
1822  }
1823
1824
1825
1826  /**
1827   * Attempts to force this thread to exit by closing the connections to the
1828   * directory server and setting them to <CODE>null</CODE>.
1829   */

1830  public void destroy()
1831  {
1832    if (authConnection != null)
1833    {
1834      try
1835      {
1836        authConnection.disconnect();
1837      } catch (Exception JavaDoc e) {}
1838
1839      authConnection = null;
1840    }
1841
1842    if (bindConnection != null)
1843    {
1844      try
1845      {
1846        bindConnection.disconnect();
1847      } catch (Exception JavaDoc e) {}
1848
1849      bindConnection = null;
1850    }
1851  }
1852
1853
1854
1855  /**
1856   * Performs any per-client finalization that should be done for this job. In
1857   * this case, if the job was using shared connections then those connections
1858   * will be closed.
1859   */

1860  public void finalizeClient()
1861  {
1862    // Make sure that the shared connections get closed properly.
1863
if (useSharedConnections)
1864    {
1865      try
1866      {
1867        sharedAuthConnection.disconnect();
1868      } catch (Exception JavaDoc e) {}
1869    }
1870  }
1871
1872
1873
1874  /**
1875   * Determines whether the provided user is a member of the membership DN.
1876   *
1877   * @param userEntry The user entry for which to make the determination.
1878   *
1879   * @return <CODE>true</CODE> if it is determined that the user is a member,
1880   * or <CODE>false</CODE> if the membership could not be determined.
1881   */

1882  public boolean isMember(LDAPEntry userEntry)
1883  {
1884    switch (membershipType)
1885    {
1886      case MEMBERSHIP_TYPE_STATIC:
1887        String JavaDoc userDN = userEntry.getDN();
1888        String JavaDoc filter = "(|(&(objectclass=groupOfNames)(member=" + userDN +
1889                        "))(&(objectClass=groupOfUniqueNames)(uniqueMember=" +
1890                        userDN + ")))";
1891        try
1892        {
1893          LDAPSearchResults results =
1894               authConnection.search(membershipDN, LDAPConnection.SCOPE_BASE,
1895                                     filter, NO_ATTRS, false);
1896          while (results.hasMoreElements())
1897          {
1898            Object JavaDoc element = results.nextElement();
1899            if (element instanceof LDAPEntry)
1900            {
1901              return true;
1902            }
1903          }
1904
1905          return false;
1906        }
1907        catch (Exception JavaDoc e)
1908        {
1909          return false;
1910        }
1911      case MEMBERSHIP_TYPE_DYNAMIC:
1912        userDN = LDAPDN.normalize(userEntry.getDN());
1913        if (! userDN.endsWith(membershipURLBase))
1914        {
1915          return false;
1916        }
1917
1918        try
1919        {
1920          LDAPSearchResults results =
1921               authConnection.search(userDN, LDAPConnection.SCOPE_BASE,
1922                                     membershipURLFilter, NO_ATTRS, false);
1923          while (results.hasMoreElements())
1924          {
1925            Object JavaDoc element = results.nextElement();
1926            if (element instanceof LDAPEntry)
1927            {
1928              return true;
1929            }
1930          }
1931
1932          return false;
1933        }
1934        catch (Exception JavaDoc e)
1935        {
1936          return false;
1937        }
1938      case MEMBERSHIP_TYPE_ROLE:
1939        LDAPAttribute roleAttr = userEntry.getAttribute(ROLE_ATTR);
1940        String JavaDoc[] roleValues = null;
1941        if ((roleAttr == null) ||
1942            ((roleValues = roleAttr.getStringValueArray()) == null) ||
1943            (roleValues.length == 0))
1944        {
1945          return false;
1946        }
1947
1948        for (int i=0; i < roleValues.length; i++)
1949        {
1950          String JavaDoc roleDN = LDAPDN.normalize(roleValues[i]);
1951          if (roleDN.equals(membershipDN))
1952          {
1953            return true;
1954          }
1955        }
1956
1957        return false;
1958    }
1959
1960
1961    return false;
1962  }
1963
1964
1965
1966  /**
1967   * Retrieves an array containing the login ID and password that should be
1968   * used to authenticate to the directory.
1969   *
1970   * @return An array containing the login ID and password.
1971   */

1972  public String JavaDoc[] getLoginInfo()
1973  {
1974    String JavaDoc[] loginInfo = new String JavaDoc[2];
1975
1976    if (useDataFile)
1977    {
1978      int slot = (random.nextInt() & 0x7FFFFFFF) % loginIDs.length;
1979      loginInfo[0] = loginIDs[slot];
1980      loginInfo[1] = loginPasswords[slot];
1981    }
1982    else
1983    {
1984      if (useLoginIDRange)
1985      {
1986        int value;
1987        if (useSequential)
1988        {
1989          value = sequentialCounter++;
1990          if (sequentialCounter > loginIDMax)
1991          {
1992            sequentialCounter = loginIDMin;
1993          }
1994        }
1995        else
1996        {
1997          value = ((random.nextInt() & 0x7FFFFFFF) % loginIDSpan) + loginIDMin;
1998        }
1999        loginInfo[0] = loginIDInitial + value + loginIDFinal;
2000        loginInfo[1] = loginPassword;
2001      }
2002      else
2003      {
2004        loginInfo[0] = loginIDInitial;
2005        loginInfo[1] = loginPassword;
2006      }
2007    }
2008
2009    return loginInfo;
2010  }
2011}
2012
2013
Popular Tags