KickJava   Java API By Example, From Geeks To Geeks.

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


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 authentications
33  * against an LDAP directory server. It will find the user's entry based on a
34  * login ID, attempt to bind as that user, and optionally verify whether that
35  * user is a member of a static group, dynamic group, or role.
36  *
37  *
38  * @author Neil A. Wilson
39  */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

154   public static final String JavaDoc STAT_TRACKER_SUCCESSFUL_AUTHENTICATIONS =
155        "Successful Authentications";
156
157
158
159   /**
160    * The name of the stat tracker that will be used to accumulate the number of
161    * attempted authentications.
162    */

163   public static final String JavaDoc STAT_TRACKER_TOTAL_AUTHENTICATIONS =
164        "Total Authentication Attempts";
165
166
167
168   /**
169    * The set of attributes to retrieve if there aren't any attributes to
170    * retrieve.
171    */

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

523   public AuthRateJobClass()
524   {
525     super();
526   }
527
528
529
530   /**
531    * Returns the user-friendly name that is to be used for this job class in the
532    * administrative interface.
533    *
534    * @return The user-friendly name for this job class.
535    */

536   public String JavaDoc getJobName()
537   {
538     return "LDAP Auth Rate";
539   }
540
541
542
543   /**
544    * Returns a description of this job that can be seen in the administrative
545    * interface.
546    *
547    * @return A description of this job class.
548    */

549   public String JavaDoc getJobDescription()
550   {
551     return "This job performs repeated authentications against an LDAP " +
552       "directory server, optionally including a lookup to verify that the " +
553       "user is a member of an indicated group or role.";
554   }
555
556
557
558   /**
559    * Retrieves the name of the category in which this job class exists. This is
560    * used to help arrange the job classes in the administrative interface.
561    *
562    * @return The name of the category in which this job class exists.
563    */

564   public String JavaDoc getJobCategoryName()
565   {
566     return "LDAP";
567   }
568
569
570
571   /**
572    * Returns the set of parameters whose value may be specified by the end user.
573    *
574    * @return The set of configurable parameters for this job class.
575    */

576   public ParameterList getParameterStubs()
577   {
578     Parameter[] parameterArray = new Parameter[]
579     {
580       placeholder,
581       hostParameter,
582       portParameter,
583       bindDNParameter,
584       bindPWParameter,
585       placeholder,
586       searchBaseParameter,
587       loginDataFileParameter,
588       loginIDValueParameter,
589       loginPasswordParameter,
590       readPassFromAttrParameter,
591       loginIDParameter,
592       membershipDNParameter,
593       placeholder,
594       warmUpParameter,
595       coolDownParameter,
596       timeLimitParameter,
597       delayParameter,
598       placeholder,
599       useSSLParameter,
600       blindTrustParameter,
601       keyStoreParameter,
602       keyPWParameter,
603       trustStoreParameter,
604       trustPWParameter,
605       placeholder,
606       iterationsParameter,
607       ignoreInvCredParameter,
608       shareConnsParameter
609     };
610
611     return new ParameterList(parameterArray);
612   }
613
614
615
616   /**
617    * Retrieves the set of stat trackers that will be maintained by this job
618    * class. The stat trackers returned by this method do not have to actually
619    * contain any statistics -- the display name and stat tracker class should
620    * be the only information that callers of this method should rely upon. Note
621    * that this list can be different from the list of statistics actually
622    * collected by the job in some cases (e.g., if the job may not return all the
623    * stat trackers it advertises in all cases, or if the job may return stat
624    * trackers that it did not advertise), but it is a possibility that only the
625    * stat trackers returned by this method will be accessible for some features
626    * in the SLAMD server.
627    *
628    * @param clientID The client ID that should be used for the
629    * returned stat trackers.
630    * @param threadID The thread ID that should be used for the
631    * returned stat trackers.
632    * @param collectionInterval The collection interval that should be used for
633    * the returned stat trackers.
634    *
635    * @return The set of stat trackers that will be maintained by this job
636    * class.
637    */

638   public StatTracker[] getStatTrackerStubs(String JavaDoc clientID, String JavaDoc threadID,
639                                            int collectionInterval)
640   {
641     return new StatTracker[]
642     {
643       new IncrementalTracker(clientID, threadID,
644                              STAT_TRACKER_AUTHENTICATION_ATTEMPTS,
645                              collectionInterval),
646       new IncrementalTracker(clientID, threadID,
647                              STAT_TRACKER_SUCCESSFUL_AUTHENTICATIONS,
648                              collectionInterval),
649       new IncrementalTracker(clientID, threadID,
650                              STAT_TRACKER_FAILED_AUTHENTICATIONS,
651                              collectionInterval),
652       new TimeTracker(clientID, threadID, STAT_TRACKER_AUTHENTICATION_TIME,
653                       collectionInterval)
654     };
655   }
656
657
658
659   /**
660    * Retrieves the set of stat trackers that are maintained by this job class.
661    *
662    * @return The set of stat trackers for this job class.
663    */

664   public StatTracker[] getStatTrackers()
665   {
666     return new StatTracker[]
667     {
668       attemptCounter,
669       successCounter,
670       failureCounter,
671       totalAuths,
672       authTimer
673     };
674   }
675
676
677
678   /**
679    * Provides a means of validating the information used to schedule the job,
680    * including the scheduling information and list of parameters.
681    *
682    * @param numClients The number of clients that should be used to
683    * run the job.
684    * @param threadsPerClient The number of threads that should be created on
685    * each client to run the job.
686    * @param threadStartupDelay The delay in milliseconds that should be used
687    * when starting the client threads.
688    * @param startTime The time that the job should start running.
689    * @param stopTime The time that the job should stop running.
690    * @param duration The maximum length of time in seconds that the
691    * job should be allowed to run.
692    * @param collectionInterval The collection interval that should be used
693    * when gathering statistics for the job.
694    * @param parameters The set of parameters provided to this job that
695    * can be used to customize its behavior.
696    *
697    * @throws InvalidValueException If the provided information is not
698    * appropriate for running this job.
699    */

700   public void validateJobInfo(int numClients, int threadsPerClient,
701                               int threadStartupDelay, Date startTime,
702                               Date stopTime, int duration,
703                               int collectionInterval, ParameterList parameters)
704          throws InvalidValueException
705   {
706     FileURLParameter loginDataURLParameter =
707          parameters.getFileURLParameter(loginDataFileParameter.getName());
708     if ((loginDataURLParameter == null) ||
709         (! loginDataURLParameter.hasValue()))
710     {
711       StringParameter loginValueParameter =
712            parameters.getStringParameter(loginIDValueParameter.getName());
713       PasswordParameter loginPWParameter =
714            parameters.getPasswordParameter(loginPasswordParameter.getName());
715       StringParameter pwAttrParameter =
716            parameters.getStringParameter(readPassFromAttrParameter.getName());
717
718       if ((loginValueParameter == null) ||
719           (! loginValueParameter.hasValue()))
720       {
721         throw new InvalidValueException("If no login data file is provided, " +
722                                         "then you must provide a login ID " +
723                                         "value.");
724       }
725
726       if (((loginPWParameter == null) || (! loginPWParameter.hasValue())) &&
727           ((pwAttrParameter == null) || (! pwAttrParameter.hasValue())))
728       {
729         throw new InvalidValueException("If no login data file is provided, " +
730                                         "then you must provide a password " +
731                                         "or the name of an attribute from " +
732                                         "which to read the password.");
733       }
734     }
735   }
736
737
738
739   /**
740    * Indicates whether this job class implements logic that makes it possible to
741    * test the validity of job parameters before scheduling the job for execution
742    * (e.g., to see if the server is reachable using the information provided).
743    *
744    * @return <CODE>true</CODE> if this job provides a means of testing the job
745    * parameters, or <CODE>false</CODE> if not.
746    */

747   public boolean providesParameterTest()
748   {
749     return true;
750   }
751
752
753
754   /**
755    * Provides a means of testing the provided job parameters to determine
756    * whether they are valid (e.g., to see if the server is reachable) before
757    * scheduling the job for execution. This method will be executed by the
758    * SLAMD server system itself and not by any of the clients.
759    *
760    * @param parameters The job parameters to be tested.
761    * @param outputMessages The lines of output that were generated as part of
762    * the testing process. Each line of output should
763    * be added to this list as a separate string, and
764    * empty strings (but not <CODE>null</CODE> values)
765    * are allowed to provide separation between
766    * different messages. No formatting should be
767    * provided for these messages, however, since they
768    * may be displayed in either an HTML or plain text
769    * interface.
770    *
771    * @return <CODE>true</CODE> if the test completed successfully, or
772    * <CODE>false</CODE> if not. Note that even if the test did not
773    * complete successfully, the user will be presented with a warning
774    * but will still be allowed to schedule the job using the provided
775    * parameters. This is necessary because the parameters may still be
776    * valid even if the server couldn't validate them at the time the
777    * job was scheduled (e.g., if the server wasn't running or could not
778    * be reached by the SLAMD server even though it could be by the
779    * clients).
780    */

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

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

1564  public void initializeThread(String JavaDoc clientID, String JavaDoc threadID,
1565                               int collectionInterval, ParameterList parameters)
1566         throws UnableToRunException
1567  {
1568    // Seed the random number generator for this thread.
1569
random = new Random(parentRandom.nextLong());
1570
1571    // If we are not going to use shared connections, then create the
1572
// connections for use by this thread. Otherwise, just grab the shared
1573
// connections.
1574
if (useSharedConnections)
1575    {
1576      authConnection = sharedAuthConnection;
1577      bindConnection = sharedBindConnection;
1578    }
1579    else
1580    {
1581      if (useSSL)
1582      {
1583        if (blindTrust)
1584        {
1585          try
1586          {
1587            authConnection =
1588                 new LDAPConnection(new JSSEBlindTrustSocketFactory());
1589            bindConnection =
1590                 new LDAPConnection(new JSSEBlindTrustSocketFactory());
1591          }
1592          catch (LDAPException le)
1593          {
1594            throw new UnableToRunException(le.getMessage(), le);
1595          }
1596        }
1597        else
1598        {
1599          authConnection = new LDAPConnection(new JSSESocketFactory(null));
1600          bindConnection = new LDAPConnection(new JSSESocketFactory(null));
1601        }
1602      }
1603      else
1604      {
1605        authConnection = new LDAPConnection();
1606        bindConnection = new LDAPConnection();
1607      }
1608
1609      try
1610      {
1611        authConnection.connect(3, directoryHost, directoryPort, bindDN, bindPW);
1612        bindConnection.connect(3, directoryHost, directoryPort, "", "");
1613      }
1614      catch (Exception JavaDoc e)
1615      {
1616        throw new UnableToRunException("Unable to establish the connections " +
1617                                       "to the directory server: " + e, e);
1618      }
1619    }
1620
1621    // Initialize the constraints.
1622
authConstraints = authConnection.getConstraints();
1623    bindConstraints = bindConnection.getConstraints();
1624    authSearchConstraints = authConnection.getSearchConstraints();
1625    authConstraints.setTimeLimit(1000*timeLimit);
1626    bindConstraints.setTimeLimit(1000*timeLimit);
1627    authSearchConstraints.setTimeLimit(1000*timeLimit);
1628    authSearchConstraints.setServerTimeLimit(timeLimit);
1629
1630
1631    // Create the stat trackers.
1632
attemptCounter =
1633         new IncrementalTracker(clientID, threadID,
1634                                STAT_TRACKER_AUTHENTICATION_ATTEMPTS,
1635                                collectionInterval);
1636    successCounter =
1637         new IncrementalTracker(clientID, threadID,
1638                                STAT_TRACKER_SUCCESSFUL_AUTHENTICATIONS,
1639                                collectionInterval);
1640    failureCounter =
1641         new IncrementalTracker(clientID, threadID,
1642                                STAT_TRACKER_FAILED_AUTHENTICATIONS,
1643                                collectionInterval);
1644    totalAuths = new AccumulatingTracker(clientID, threadID,
1645                                         STAT_TRACKER_TOTAL_AUTHENTICATIONS,
1646                                         collectionInterval);
1647    authTimer = new TimeTracker(clientID, threadID,
1648                                STAT_TRACKER_AUTHENTICATION_TIME,
1649                                collectionInterval);
1650
1651
1652    // Enable real-time reporting of the data for these stat trackers.
1653
RealTimeStatReporter statReporter = getStatReporter();
1654    if (statReporter != null)
1655    {
1656      String JavaDoc jobID = getJobID();
1657      attemptCounter.enableRealTimeStats(statReporter, jobID);
1658      successCounter.enableRealTimeStats(statReporter, jobID);
1659      failureCounter.enableRealTimeStats(statReporter, jobID);
1660      totalAuths.enableRealTimeStats(statReporter, jobID);
1661      authTimer.enableRealTimeStats(statReporter, jobID);
1662    }
1663  }
1664
1665
1666
1667  /**
1668   * Performs the work of actually running the job. When this method completes,
1669   * the job will be done.
1670   */

1671  public void runJob()
1672  {
1673    // Determine the range of time for which we should collect statistics.
1674
long currentTime = System.currentTimeMillis();
1675    boolean collectingStats = false;
1676    long startCollectingTime = currentTime + (1000 * warmUpTime);
1677    long stopCollectingTime = Long.MAX_VALUE;
1678    if ((coolDownTime > 0) && (getShouldStopTime() > 0))
1679    {
1680      stopCollectingTime = getShouldStopTime() - (1000 * coolDownTime);
1681    }
1682
1683    // Define a variable that will be used to determine how long to sleep
1684
// between attempts.
1685
long authStartTime = 0;
1686
1687    // See if this thread should operate "infinitely" (i.e., not a fixed number
1688
// of iterations)
1689
boolean infinite = (iterations <= 0);
1690
1691    // Loop until it is time to stop.
1692
for (int i=0; ((! shouldStop()) && ((infinite || (i < iterations)))); i++)
1693    {
1694      currentTime = System.currentTimeMillis();
1695      if ((! collectingStats) && (currentTime >= startCollectingTime) &&
1696          (currentTime < stopCollectingTime))
1697      {
1698        // Start all the stat trackers.
1699
attemptCounter.startTracker();
1700        totalAuths.startTracker();
1701        successCounter.startTracker();
1702        failureCounter.startTracker();
1703        authTimer.startTracker();
1704        collectingStats = true;
1705      }
1706      else if ((collectingStats) && (currentTime >= stopCollectingTime))
1707      {
1708        attemptCounter.stopTracker();
1709        totalAuths.stopTracker();
1710        successCounter.stopTracker();
1711        failureCounter.stopTracker();
1712        authTimer.stopTracker();
1713        collectingStats = false;
1714      }
1715
1716      // See if we need to sleep before the next attempt
1717
if ((delay > 0) && (authStartTime > 0))
1718      {
1719        long now = System.currentTimeMillis();
1720        long sleepTime = delay - (now - authStartTime);
1721        if (sleepTime > 0)
1722        {
1723          try
1724          {
1725            Thread.sleep(sleepTime);
1726          } catch (InterruptedException JavaDoc ie) {}
1727
1728          if (shouldStop())
1729          {
1730            break;
1731          }
1732        }
1733      }
1734
1735      // Get a random user number and translate that to a login ID and password.
1736
String JavaDoc[] loginInfo = getLoginInfo();
1737      String JavaDoc loginID = loginInfo[0];
1738      String JavaDoc password = loginInfo[1];
1739
1740
1741      // Start the auth attempt timer now.
1742
if (delay > 0)
1743      {
1744        authStartTime = System.currentTimeMillis();
1745      }
1746
1747
1748      // Increment the number of authentication attempts and start the timer
1749
if (collectingStats)
1750      {
1751        attemptCounter.increment();
1752        totalAuths.increment();
1753        authTimer.startTimer();
1754      }
1755
1756      // First, issue a search to try to find the user's entry.
1757
String JavaDoc[] attrsToReturn;
1758      if ((membershipDN == null) || (membershipType != MEMBERSHIP_TYPE_ROLE))
1759      {
1760        if ((readPassFromAttr == null) || (readPassFromAttr.length() == 0))
1761        {
1762          attrsToReturn = NO_ATTRS;
1763        }
1764        else
1765        {
1766          attrsToReturn = new String JavaDoc[] { readPassFromAttr };
1767        }
1768      }
1769      else
1770      {
1771        if ((readPassFromAttr == null) || (readPassFromAttr.length() == 0))
1772        {
1773          attrsToReturn = new String JavaDoc[] { ROLE_ATTR };
1774        }
1775        else
1776        {
1777          attrsToReturn = new String JavaDoc[] { ROLE_ATTR, readPassFromAttr };
1778        }
1779      }
1780
1781      String JavaDoc filter = "(" + loginIDAttr + "=" + loginID + ")";
1782      LDAPSearchResults results;
1783      LDAPEntry userEntry = null;
1784      try
1785      {
1786        results = authConnection.search(searchBase, LDAPConnection.SCOPE_SUB,
1787                                        filter, attrsToReturn, false,
1788                                        authSearchConstraints);
1789        while (results.hasMoreElements())
1790        {
1791          Object JavaDoc element = results.nextElement();
1792          if (element instanceof LDAPEntry)
1793          {
1794            userEntry = (LDAPEntry) element;
1795          }
1796        }
1797      }
1798      catch (LDAPException le)
1799      {
1800        // The search failed, so update the failure counter and stop the timer.
1801
if (collectingStats)
1802        {
1803          failureCounter.increment();
1804          authTimer.stopTimer();
1805        }
1806        continue;
1807      }
1808
1809
1810      // Make sure that we got a user entry. If not, then it's a failure.
1811
if (userEntry == null)
1812      {
1813        if (collectingStats)
1814        {
1815          failureCounter.increment();
1816          authTimer.stopTimer();
1817        }
1818        continue;
1819      }
1820
1821
1822      // If we need to use the password from an attribute in the user's entry,
1823
// then get it.
1824
if ((readPassFromAttr != null) && (readPassFromAttr.length() > 0))
1825      {
1826        LDAPAttribute attr = userEntry.getAttribute(readPassFromAttr);
1827        if (attr == null)
1828        {
1829          if (collectingStats)
1830          {
1831            failureCounter.increment();
1832            authTimer.stopTimer();
1833          }
1834          continue;
1835        }
1836        else
1837        {
1838          String JavaDoc[] values = attr.getStringValueArray();
1839          if ((values == null) || (values.length == 0))
1840          {
1841            if (collectingStats)
1842            {
1843              failureCounter.increment();
1844              authTimer.stopTimer();
1845            }
1846            continue;
1847          }
1848          else
1849          {
1850            password = values[0];
1851          }
1852        }
1853      }
1854
1855
1856      // Perform a bind as the user to verify that the provided password is
1857
// valid.
1858
try
1859      {
1860        bindConnection.authenticate(3, userEntry.getDN(), password);
1861      }
1862      catch (LDAPException le)
1863      {
1864        if (! (ignoreInvalidCredentials &&
1865              (le.getLDAPResultCode() == LDAPException.INVALID_CREDENTIALS)))
1866        {
1867          if (collectingStats)
1868          {
1869            failureCounter.increment();
1870            authTimer.stopTimer();
1871          }
1872          continue;
1873        }
1874      }
1875
1876
1877      // If we are to check membership, then do so now.
1878
if (membershipDN != null)
1879      {
1880        if (isMember(userEntry))
1881        {
1882          if (collectingStats)
1883          {
1884            successCounter.increment();
1885            authTimer.stopTimer();
1886          }
1887        }
1888        else
1889        {
1890          if (collectingStats)
1891          {
1892            failureCounter.increment();
1893            authTimer.stopTimer();
1894          }
1895        }
1896      }
1897      else
1898      {
1899        if (collectingStats)
1900        {
1901          successCounter.increment();
1902          authTimer.stopTimer();
1903        }
1904      }
1905    }
1906
1907
1908
1909    // Stop all the stat trackers.
1910
if (collectingStats)
1911    {
1912      attemptCounter.stopTracker();
1913      totalAuths.stopTracker();
1914      successCounter.stopTracker();
1915      failureCounter.stopTracker();
1916      authTimer.stopTracker();
1917    }
1918
1919
1920    // Make sure that the thread-specific connections are closed.
1921
if (! useSharedConnections)
1922    {
1923      try
1924      {
1925        authConnection.disconnect();
1926      } catch (Exception JavaDoc e) {}
1927
1928      try
1929      {
1930        bindConnection.disconnect();
1931      } catch (Exception JavaDoc e) {}
1932    }
1933  }
1934
1935
1936
1937  /**
1938   * Attempts to force this thread to exit by closing the connections to the
1939   * directory server and setting them to <CODE>null</CODE>.
1940   */

1941  public void destroy()
1942  {
1943    if (authConnection != null)
1944    {
1945      try
1946      {
1947        authConnection.disconnect();
1948      } catch (Exception JavaDoc e) {}
1949
1950      authConnection = null;
1951    }
1952
1953    if (bindConnection != null)
1954    {
1955      try
1956      {
1957        bindConnection.disconnect();
1958      } catch (Exception JavaDoc e) {}
1959
1960      bindConnection = null;
1961    }
1962  }
1963
1964
1965
1966  /**
1967   * Performs any per-client finalization that should be done for this job. In
1968   * this case, if the job was using shared connections then those connections
1969   * will be closed.
1970   */

1971  public void finalizeClient()
1972  {
1973    // Make sure that the shared connections get closed properly.
1974
if (useSharedConnections)
1975    {
1976      try
1977      {
1978        sharedAuthConnection.disconnect();
1979      } catch (Exception JavaDoc e) {}
1980
1981      try
1982      {
1983        sharedBindConnection.disconnect();
1984      } catch (Exception JavaDoc e) {}
1985    }
1986  }
1987
1988
1989
1990  /**
1991   * Determines whether the provided user is a member of the membership DN.
1992   *
1993   * @param userEntry The user entry for which to make the determination.
1994   *
1995   * @return <CODE>true</CODE> if it is determined that the user is a member,
1996   * or <CODE>false</CODE> if the membership could not be determined.
1997   */

1998  public boolean isMember(LDAPEntry userEntry)
1999  {
2000    switch (membershipType)
2001    {
2002      case MEMBERSHIP_TYPE_STATIC:
2003        String JavaDoc userDN = userEntry.getDN();
2004        String JavaDoc filter = "(|(&(objectclass=groupOfNames)(member=" + userDN +
2005                        "))(&(objectClass=groupOfUniqueNames)(uniqueMember=" +
2006                        userDN + ")))";
2007        try
2008        {
2009          LDAPSearchResults results =
2010               authConnection.search(membershipDN, LDAPConnection.SCOPE_BASE,
2011                                     filter, NO_ATTRS, false);
2012          while (results.hasMoreElements())
2013          {
2014            Object JavaDoc element = results.nextElement();
2015            if (element instanceof LDAPEntry)
2016            {
2017              return true;
2018            }
2019          }
2020
2021          return false;
2022        }
2023        catch (Exception JavaDoc e)
2024        {
2025          return false;
2026        }
2027      case MEMBERSHIP_TYPE_DYNAMIC:
2028        userDN = LDAPDN.normalize(userEntry.getDN());
2029        if (! userDN.endsWith(membershipURLBase))
2030        {
2031          return false;
2032        }
2033
2034        try
2035        {
2036          LDAPSearchResults results =
2037               authConnection.search(userDN, LDAPConnection.SCOPE_BASE,
2038                                     membershipURLFilter, NO_ATTRS, false);
2039          while (results.hasMoreElements())
2040          {
2041            Object JavaDoc element = results.nextElement();
2042            if (element instanceof LDAPEntry)
2043            {
2044              return true;
2045            }
2046          }
2047
2048          return false;
2049        }
2050        catch (Exception JavaDoc e)
2051        {
2052          return false;
2053        }
2054      case MEMBERSHIP_TYPE_ROLE:
2055        LDAPAttribute roleAttr = userEntry.getAttribute(ROLE_ATTR);
2056        String JavaDoc[] roleValues = null;
2057        if ((roleAttr == null) ||
2058            ((roleValues = roleAttr.getStringValueArray()) == null) ||
2059            (roleValues.length == 0))
2060        {
2061          return false;
2062        }
2063
2064        for (int i=0; i < roleValues.length; i++)
2065        {
2066          String JavaDoc roleDN = LDAPDN.normalize(roleValues[i]);
2067          if (roleDN.equals(membershipDN))
2068          {
2069            return true;
2070          }
2071        }
2072
2073        return false;
2074    }
2075
2076
2077    return false;
2078  }
2079
2080
2081
2082  /**
2083   * Retrieves an array containing the login ID and password that should be
2084   * used to authenticate to the directory.
2085   *
2086   * @return An array containing the login ID and password.
2087   */

2088  public String JavaDoc[] getLoginInfo()
2089  {
2090    String JavaDoc[] loginInfo = new String JavaDoc[2];
2091
2092    if (useDataFile)
2093    {
2094      int slot = (random.nextInt() & 0x7FFFFFFF) % loginIDs.length;
2095      loginInfo[0] = loginIDs[slot];
2096      loginInfo[1] = loginPasswords[slot];
2097    }
2098    else
2099    {
2100      if (useLoginIDRange)
2101      {
2102        int value;
2103        if (useSequential)
2104        {
2105          value = sequentialCounter++;
2106          if (sequentialCounter > loginIDMax)
2107          {
2108            sequentialCounter = loginIDMin;
2109          }
2110        }
2111        else
2112        {
2113          value = ((random.nextInt() & 0x7FFFFFFF) % loginIDSpan) + loginIDMin;
2114        }
2115        loginInfo[0] = loginIDInitial + value + loginIDFinal;
2116        loginInfo[1] = loginPassword;
2117      }
2118      else
2119      {
2120        loginInfo[0] = loginIDInitial;
2121        loginInfo[1] = loginPassword;
2122      }
2123    }
2124
2125    return loginInfo;
2126  }
2127}
2128
2129
Popular Tags