Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: An implementation of the AuthInterface interface that
4
 *             allows Metacat to use the LDAP protocol for
5
 *             directory services
6
 *  Copyright: 2000 Regents of the University of California and the
7
 *             National Center for Ecological Analysis and Synthesis
8
 *    Authors: Matt Jones
9
 *    Release: @release@
10
 *
11
 *   '$Author: sgarg $'
12
 *     '$Date: 2004-04-14 11:27:10 -0700 (Wed, 14 Apr 2004) $'
13
 * '$Revision: 2121 $'
14
 *
15
 * This program is free software; you can redistribute it and/or modify
16
 * it under the terms of the GNU General Public License as published by
17
 * the Free Software Foundation; either version 2 of the License, or
18
 * (at your option) any later version.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 * GNU General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU General Public License
26
 * along with this program; if not, write to the Free Software
27
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28
 */
29

    
30
package edu.ucsb.nceas.metacat;
31

    
32
import java.net.ConnectException;
33
import javax.naming.AuthenticationException;
34
import javax.naming.Context;
35
import javax.naming.NamingEnumeration;
36
import javax.naming.NamingException;
37
import javax.naming.SizeLimitExceededException;
38
import javax.naming.InitialContext;
39
import javax.naming.directory.InvalidSearchFilterException;
40
import javax.naming.directory.Attribute;
41
import javax.naming.directory.Attributes;
42
import javax.naming.directory.BasicAttribute;
43
import javax.naming.directory.BasicAttributes;
44
import javax.naming.directory.DirContext;
45
import javax.naming.directory.InitialDirContext;
46
import javax.naming.directory.SearchResult;
47
import javax.naming.directory.SearchControls;
48
import javax.naming.ReferralException;
49
import javax.naming.ldap.*;
50
import java.net.URLDecoder;
51
import java.util.Iterator;
52
import java.util.HashMap;
53
import java.util.Hashtable;
54
import java.util.Enumeration;
55
import java.util.Set;
56
import java.util.Vector;
57

    
58
/**
59
 * An implementation of the AuthInterface interface that
60
 * allows Metacat to use the LDAP protocol for directory services.
61
 * The LDAP authentication service is used to determine if a user
62
 * is authenticated, and whether they are a member of a particular group.
63
 */
64
public class AuthLdap
65
    implements AuthInterface, Runnable {
66
  private MetaCatUtil util = new MetaCatUtil();
67
  private String ldapUrl;
68
  private String ldapsUrl;
69
  private String ldapBase;
70
  private String referral;
71
  private Context referralContext;
72
  Hashtable env = new Hashtable(11);
73
  private Context rContext;
74
  private String userName;
75
  private String userPassword;
76
  ReferralException refExc;
77
  //String uid=null;
78

    
79
  /**
80
   * Construct an AuthLdap
81
   */
82
  public AuthLdap() {
83
    // Read LDAP URI for directory service information
84
    this.ldapUrl = MetaCatUtil.getOption("ldapurl");
85
    this.ldapsUrl = MetaCatUtil.getOption("ldapsurl");
86
    this.ldapBase = MetaCatUtil.getOption("ldapbase");
87
    this.referral = MetaCatUtil.getOption("referral");
88
  }
89

    
90
  /**
91
   * Determine if a user/password are valid according to the authentication
92
   * service.
93
   *
94
   * @param user the name of the principal to authenticate
95
   * @param password the password to use for authentication
96
   * @returns boolean true if authentication successful, false otherwise
97
   */
98
  public boolean authenticate(String user, String password) throws
99
      ConnectException {
100
    String ldapUrl = this.ldapUrl;
101
    String ldapsUrl = this.ldapsUrl;
102
    String ldapBase = this.ldapBase;
103
    boolean authenticated = false;
104
    String identifier = user;
105
    //get uid here.
106
    //uid=user.substring(0, user.indexOf(","));
107

    
108
    try {
109
      // Check the usename as passed in
110
      authenticated = ldapAuthenticate(identifier, password);
111
      // if not found, try looking up a valid DN then auth again
112
      if (!authenticated) {
113
        MetaCatUtil.debugMessage("Looking up DN for: " + identifier, 35);
114
        identifier = getIdentifyingName(identifier, ldapUrl, ldapBase);
115
        MetaCatUtil.debugMessage("DN found: " + identifier, 35);
116
        String decoded = URLDecoder.decode(identifier);
117
        MetaCatUtil.debugMessage("DN decoded: " + decoded, 35);
118
        identifier = decoded;
119
        String refUrl = "";
120
        String refBase = "";
121
        if (identifier.startsWith("ldap")) {
122
          refUrl = identifier.substring(0,
123
                                        identifier.lastIndexOf("/") + 1);
124
          MetaCatUtil.debugMessage("Ref ldapUrl: " + refUrl, 35);
125
          int position = identifier.indexOf(",");
126
          int position2 = identifier.indexOf(",", position + 1);
127
          refBase = identifier.substring(position2 + 1);
128
          MetaCatUtil.debugMessage("Ref ldapBase: " + refBase, 35);
129
          identifier = identifier.substring(
130
              identifier.lastIndexOf("/") + 1);
131
          MetaCatUtil.debugMessage("Trying: " + identifier, 35);
132
          authenticated = ldapAuthenticate(identifier, password,
133
                                           refUrl, refBase);
134
        }
135
        else {
136
          identifier = identifier + "," + ldapBase;
137
          MetaCatUtil.debugMessage("Trying: " + identifier, 35);
138
          authenticated = ldapAuthenticate(identifier, password);
139
        }
140
        //authenticated = ldapAuthenticate(identifier, password);
141
      }
142

    
143
    }
144
    catch (NullPointerException e) {
145
      util.debugMessage("NullPointerException b' password is null", 30);
146
      util.debugMessage("NullPointerException while authenticating in " +
147
                        "AuthLdap.authenticate: " + e, 30);
148
      throw new ConnectException(
149
          "NullPointerException while authenticating in " +
150
          "AuthLdap.authenticate: " + e);
151
    }
152
    catch (NamingException e) {
153
      util.debugMessage("Naming exception while authenticating in " +
154
                        "AuthLdap.authenticate: " + e, 30);
155
      e.printStackTrace();
156
    }
157
    catch (Exception e) {
158
      util.debugMessage(e.getMessage(), 30);
159
    }
160
    return authenticated;
161
  }
162

    
163
  /**
164
   * Connect to the LDAP directory and do the authentication using the
165
   * username and password as passed into the routine.
166
   *
167
   * @param identifier the distinguished name to check against LDAP
168
   * @param password the password for authentication
169
   */
170
  private boolean ldapAuthenticate(String identifier, String password) throws
171
      ConnectException, NamingException, NullPointerException {
172
    return ldapAuthenticate(identifier, password,
173
                            this.ldapsUrl, this.ldapBase);
174
  }
175

    
176
  /**
177
   * Connect to the LDAP directory and do the authentication using the
178
   * username and password as passed into the routine.
179
   *
180
   * @param identifier the distinguished name to check against LDAP
181
   * @param password the password for authentication
182
   */
183
  private boolean ldapAuthenticate(String identifier, String password,
184
                                   String directoryUrl, String searchBase) throws
185
      ConnectException, NamingException, NullPointerException {
186
    double totStartTime = System.currentTimeMillis();
187
    boolean authenticated = false;
188
    if (identifier != null && !password.equals("")) {
189

    
190
      //Pass the username and password to run() method
191
      userName = identifier;
192
      userPassword = password;
193
      // Identify service provider to use
194
      Hashtable env = new Hashtable(11);
195
      env.put(Context.INITIAL_CONTEXT_FACTORY,
196
              "com.sun.jndi.ldap.LdapCtxFactory");
197
      env.put(Context.REFERRAL, "throw");
198
      env.put(Context.PROVIDER_URL, directoryUrl + searchBase);
199
      util.debugMessage("PROVIDER_URL set to: " + directoryUrl + searchBase, 35);
200
      if (!ldapsUrl.equals(ldapUrl)) {
201
        // ldap is set on default port 389
202
        // ldaps is set on second port - 636 by default
203
        //env.put(Context.SECURITY_PROTOCOL, "ssl");
204
      }
205
      env.put(Context.SECURITY_AUTHENTICATION, "simple");
206
      env.put(Context.SECURITY_PRINCIPAL, identifier);
207
      env.put(Context.SECURITY_CREDENTIALS, password);
208
      // If our auth credentials are invalid, an exception will be thrown
209
      DirContext ctx = null;
210
      try {
211
        double startTime = System.currentTimeMillis();
212
        //Here to check the authorization
213
        ctx = new InitialDirContext(env);
214
        double stopTime = System.currentTimeMillis();
215
        util.debugMessage("Connection time thru " + ldapsUrl + " was: " +
216
                          (stopTime - startTime) / 1000 + " seconds.", 35);
217
        authenticated = true;
218
        //tls.close();
219
        ctx.close();
220
        this.ldapUrl = ldapUrl;
221
        this.ldapBase = ldapBase;
222
        //break;
223
      }
224
      catch (AuthenticationException ae) {
225
        authenticated = false;
226
        if (ctx != null) {
227
          ctx.close();
228
        }
229
      }
230
      catch (javax.naming.InvalidNameException ine) {
231
        util.debugMessage("An invalid DN was provided!", 30);
232
      }
233
      catch (javax.naming.ReferralException re) {
234
        util.debugMessage("referral during authentication", 30);
235
        util.debugMessage("Referral information: " + re.getReferralInfo(), 30);
236
        try {
237
          refExc = re;
238

    
239
          Thread t = new Thread(this);
240
          t.start();
241
          Thread.sleep(5000); //this is a manual override of ldap's
242
          //hideously long time out period.
243
          util.debugMessage("Awake after 5 seconds.", 35);
244
          if (referralContext == null) {
245
            t.interrupt();
246
            authenticated = false;
247
          }
248
          else {
249
            authenticated = true;
250
          }
251
        }
252
        catch (Exception e) {
253
          authenticated = false;
254
        }
255
      }
256
    }
257
    else {
258
      util.debugMessage("User not found", 30);
259
    }
260
    double totStopTime = System.currentTimeMillis();
261
    util.debugMessage("total ldap authentication time: " +
262
                      (totStopTime - totStartTime) / 1000 + " seconds", 35);
263
    return authenticated;
264
  }
265

    
266
  /**
267
   * Get the identifying name for a given userid or name.  This is the name
268
   * that is used in conjunction withthe LDAP BaseDN to create a
269
   * distinguished name (dn) for the record
270
   *
271
   * @param user the user for which the identifying name is requested
272
   * @returns String the identifying name for the user,
273
   *          or null if not found
274
   */
275
  private String getIdentifyingName(String user, String ldapUrl,
276
                                    String ldapBase) throws NamingException {
277
    String identifier = null;
278
    // Identify service provider to use
279
    Hashtable env = new Hashtable(11);
280
    env.put(Context.INITIAL_CONTEXT_FACTORY,
281
            "com.sun.jndi.ldap.LdapCtxFactory");
282
    util.debugMessage("setting referrals to: " + referral, 35);
283
    env.put(Context.REFERRAL, referral);
284
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
285
    //    non-secure LDAP context; dn are publicly readable
286
    try {
287

    
288
      // Bind to the LDAP server, in order to search for the right
289
      // distinguished name (dn) based on userid (uid) or common name (cn)
290
      DirContext ctx = new InitialDirContext(env);
291
      SearchControls ctls = new SearchControls();
292
      ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
293
      // Search for the user id or name using the uid, then cn and sn
294
      //attributes
295
      // If we find a record, determine the dn for the record
296
      // The following blocks need to be refactored into a subroutine
297
      // they have a ridiculous amount of redundancy
298

    
299
      // Parse out the uid and org components and look up the real DN
300
      // This assumes a dn like "uid=x,o=y,dc=someinst,dc=org"
301
      int position = user.indexOf(",");
302
      String comp1 = user.substring(0, position);
303
      MetaCatUtil.debugMessage("First comp is: " + comp1, 35);
304
      String comp2 = user.substring(position + 1,
305
                                    user.indexOf(",", position + 1));
306
      MetaCatUtil.debugMessage("Second comp is: " + comp2, 35);
307

    
308
      //String filter = "(&(" + comp1 + "))";
309
      String filter = "(&(" + comp1 + ")(" + comp2 + "))";
310
      MetaCatUtil.debugMessage("Filter is: " + filter, 35);
311
      MetaCatUtil.debugMessage("Provider URL is: " + ldapUrl + ldapBase, 35);
312
      NamingEnumeration answer;
313
      try {
314
        util.debugMessage("Trying search 1: " + filter, 35);
315
        answer = ctx.search("", filter, ctls);
316
        util.debugMessage("Search 1 complete", 35);
317
        if (answer == null) {
318
          util.debugMessage("Search 1 answer is null.", 35);
319
        }
320
        if (answer.hasMore()) {
321
          util.debugMessage("Search 1 has answers.", 35);
322
          SearchResult sr = (SearchResult) answer.next();
323
          identifier = sr.getName();
324
          util.debugMessage("Originally Found: " + identifier, 35);
325
          return identifier;
326
        }
327
      }
328
      catch (InvalidSearchFilterException e) {
329
        util.debugMessage("Invalid Filter exception thrown (if1)", 35);
330
      }
331

    
332
      // That failed, so check if it is just a username
333
      filter = "(" + user + ")";
334
      try {
335
        MetaCatUtil.debugMessage("Trying again: " + filter, 35);
336
        answer = ctx.search("", filter, ctls);
337
        if (answer.hasMore()) {
338
          SearchResult sr = (SearchResult) answer.next();
339
          identifier = sr.getName();
340
          if (!sr.isRelative()) {
341
            this.ldapUrl = identifier.substring(0,
342
                                                identifier.lastIndexOf("/") + 1);
343
            this.ldapBase = identifier.substring(identifier.indexOf(",") + 1);
344
            identifier = identifier.substring(identifier.lastIndexOf("/") + 1,
345
                                              identifier.indexOf(","));
346
          }
347
          util.debugMessage("Found: " + identifier, 35);
348
          return identifier;
349
        }
350
      }
351
      catch (InvalidSearchFilterException e) {}
352

    
353
      // Maybe its a user id (uid)
354
      filter = "(uid=" + user + ")";
355
      MetaCatUtil.debugMessage("Trying again: " + filter, 35);
356
      answer = ctx.search("", filter, ctls);
357
      if (answer.hasMore()) {
358
        SearchResult sr = (SearchResult) answer.next();
359
        identifier = sr.getName();
360
        if (!sr.isRelative()) {
361
          this.ldapUrl = identifier.substring(0,
362
                                              identifier.lastIndexOf("/") + 1);
363
          this.ldapBase = identifier.substring(identifier.indexOf(",") + 1);
364
          identifier = identifier.substring(identifier.lastIndexOf("/") + 1,
365
                                            identifier.indexOf(","));
366
        }
367
        util.debugMessage("Found: " + identifier, 35);
368
      }
369
      else {
370

    
371
        // maybe its just a common name
372
        filter = "(cn=" + user + ")";
373
        MetaCatUtil.debugMessage("Trying again: " + filter, 35);
374
        NamingEnumeration answer2 = ctx.search("", filter, ctls);
375
        if (answer2.hasMore()) {
376
          SearchResult sr = (SearchResult) answer2.next();
377
          identifier = sr.getName();
378
          if (!sr.isRelative()) {
379
            this.ldapUrl = identifier.substring(0,
380
                                                identifier.lastIndexOf("/") + 1);
381
            this.ldapBase = identifier.substring(identifier.indexOf(",") + 1);
382
            identifier = identifier.substring(identifier.lastIndexOf("/") + 1,
383
                                              identifier.indexOf(","));
384
          }
385
          util.debugMessage("Found: " + identifier, 35);
386
        }
387
        else {
388

    
389
          // ok, last resort, is it a surname?
390
          filter = "(sn=" + user + ")";
391
          MetaCatUtil.debugMessage("Trying again: " + filter, 35);
392
          NamingEnumeration answer3 = ctx.search("", filter, ctls);
393
          if (answer3.hasMore()) {
394
            SearchResult sr = (SearchResult) answer3.next();
395
            identifier = sr.getName();
396
            if (!sr.isRelative()) {
397
              this.ldapUrl = identifier.substring(0,
398
                                                  identifier.lastIndexOf("/") +
399
                                                  1);
400
              this.ldapBase = identifier.substring(identifier.indexOf(",") + 1);
401
              identifier = identifier.substring(identifier.lastIndexOf("/") + 1,
402
                                                identifier.indexOf(","));
403
            }
404
            util.debugMessage("Found: " + identifier, 35);
405
          }
406
        }
407
      }
408
      // Close the context when we're done the initial search
409
      ctx.close();
410
    }
411
    catch (NamingException e) {
412
      util.debugMessage("Naming exception while getting dn: " + e, 35);
413
      throw new NamingException(
414
          "Naming exception in AuthLdap.getIdentifyingName: " + e);
415
    }
416
    MetaCatUtil.debugMessage("Returning found identifier as: " + identifier, 35);
417
    return identifier;
418
  }
419

    
420
  /**
421
   * Get all users from the authentication service
422
   *
423
   * @param user the user for authenticating against the service
424
   * @param password the password for authenticating against the service
425
   * @returns string array of all of the user names
426
   */
427
  public String[][] getUsers(String user, String password) throws
428
      ConnectException {
429
    String[][] users = null;
430

    
431
    // Identify service provider to use
432
    Hashtable env = new Hashtable(11);
433
    env.put(Context.INITIAL_CONTEXT_FACTORY,
434
            "com.sun.jndi.ldap.LdapCtxFactory");
435
    env.put(Context.REFERRAL, referral);
436
    env.put(Context.PROVIDER_URL, ldapUrl);
437

    
438
    try {
439

    
440
      // Create the initial directory context
441
      DirContext ctx = new InitialDirContext(env);
442

    
443
      // Specify the attributes to match.
444
      // Users are objects that have the attribute objectclass=InetOrgPerson.
445
      SearchControls ctls = new SearchControls();
446
      String[] attrIDs = {
447
          "dn", "cn", "o", "mail"};
448
      ctls.setReturningAttributes(attrIDs);
449
      ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
450
      //ctls.setCountLimit(1000);
451
      String filter = "(objectClass=inetOrgPerson)";
452
      NamingEnumeration enum = ctx.search(ldapBase, filter, ctls);
453

    
454
      // Store the users in a vector
455
      Vector uvec = new Vector();
456
      Vector uname = new Vector();
457
      Vector uorg = new Vector();
458
      Vector umail = new Vector();
459
      Attributes tempAttr = null;
460
      try {
461
        while (enum.hasMore()) {
462
          SearchResult sr = (SearchResult) enum.next();
463
          tempAttr = sr.getAttributes();
464

    
465
          if ( (tempAttr.get("cn") + "").startsWith("cn: ")) {
466
            uname.add( (tempAttr.get("cn") + "").substring(4));
467
          }
468
          else {
469
            uname.add(tempAttr.get("cn") + "");
470
          }
471

    
472
          if ( (tempAttr.get("o") + "").startsWith("o: ")) {
473
            uorg.add( (tempAttr.get("o") + "").substring(3));
474
          }
475
          else {
476
            uorg.add(tempAttr.get("o") + "");
477
          }
478

    
479
          if ( (tempAttr.get("mail") + "").startsWith("mail: ")) {
480
            umail.add( (tempAttr.get("mail") + "").substring(6));
481
          }
482
          else {
483
            umail.add(tempAttr.get("mail") + "");
484
          }
485

    
486
          uvec.add(sr.getName() + "," + ldapBase);
487
        }
488
      }
489
      catch (SizeLimitExceededException slee) {
490
        util.debugMessage("LDAP Server size limit exceeded. " +
491
                          "Returning incomplete record set.", 35);
492
      }
493

    
494
      // initialize users[]; fill users[]
495
      users = new String[uvec.size()][4];
496
      for (int i = 0; i < uvec.size(); i++) {
497
        users[i][0] = (String) uvec.elementAt(i);
498
        users[i][1] = (String) uname.elementAt(i);
499
        users[i][2] = (String) uorg.elementAt(i);
500
        users[i][3] = (String) umail.elementAt(i);
501
      }
502

    
503
      // Close the context when we're done
504
      ctx.close();
505

    
506
    }
507
    catch (NamingException e) {
508
      util.debugMessage("Problem getting users in AuthLdap.getUsers:" + e, 35);
509
      //e.printStackTrace(System.err);
510
      throw new ConnectException(
511
          "Problem getting users in AuthLdap.getUsers:" + e);
512
    }
513

    
514
    return users;
515
  }
516

    
517
  /**
518
   * Get the users for a particular group from the authentication service
519
   *
520
   * @param user the user for authenticating against the service
521
   * @param password the password for authenticating against the service
522
   * @param group the group whose user list should be returned
523
   * @returns string array of the user names belonging to the group
524
   */
525
  public String[] getUsers(String user, String password, String group) throws
526
      ConnectException {
527
    String[] users = null;
528

    
529
    // Identify service provider to use
530
    Hashtable env = new Hashtable(11);
531
    env.put(Context.INITIAL_CONTEXT_FACTORY,
532
            "com.sun.jndi.ldap.LdapCtxFactory");
533
    env.put(Context.REFERRAL, referral);
534
    env.put(Context.PROVIDER_URL, ldapUrl);
535

    
536
    try {
537

    
538
      // Create the initial directory context
539
      DirContext ctx = new InitialDirContext(env);
540

    
541
      // Specify the ids of the attributes to return
542
      String[] attrIDs = {
543
          "uniqueMember"};
544

    
545
      Attributes answer = ctx.getAttributes(group, attrIDs);
546

    
547
      Vector uvec = new Vector();
548
      try {
549
        for (NamingEnumeration ae = answer.getAll(); ae.hasMore(); ) {
550
          Attribute attr = (Attribute) ae.next();
551
          for (NamingEnumeration e = attr.getAll();
552
               e.hasMore();
553
               uvec.add(e.next())
554
               ) {
555
            ;
556
          }
557
        }
558
      }
559
      catch (SizeLimitExceededException slee) {
560
        util.debugMessage("LDAP Server size limit exceeded. " +
561
                          "Returning incomplete record set.", 35);
562
      }
563

    
564
      // initialize users[]; fill users[]
565
      users = new String[uvec.size()];
566
      for (int i = 0; i < uvec.size(); i++) {
567
        users[i] = (String) uvec.elementAt(i);
568
      }
569

    
570
      // Close the context when we're done
571
      ctx.close();
572

    
573
    }
574
    catch (NamingException e) {
575
      util.debugMessage("Problem getting users for a group in " +
576
                        "AuthLdap.getUsers:" + e, 30);
577
      throw new ConnectException(
578
          "Problem getting users for a group in AuthLdap.getUsers:" + e);
579
    }
580

    
581
    return users;
582
  }
583

    
584
  /**
585
   * Get all groups from the authentication service
586
   *
587
   * @param user the user for authenticating against the service
588
   * @param password the password for authenticating against the service
589
   * @returns string array of the group names
590
   */
591
  public String[][] getGroups(String user, String password) throws
592
      ConnectException {
593
    return getGroups(user, password, null);
594
  }
595

    
596
  /**
597
   * Get the groups for a particular user from the authentication service
598
   *
599
   * @param user the user for authenticating against the service
600
   * @param password the password for authenticating against the service
601
   * @param foruser the user whose group list should be returned
602
   * @returns string array of the group names
603
   */
604
  public String[][] getGroups(String user, String password, String foruser) throws
605
      ConnectException {
606
    Vector gvec = new Vector();
607
    Vector desc = new Vector();
608
    Attributes tempAttr = null;
609

    
610
    //Pass the username and password to run() method
611
    userName = user;
612
    userPassword = password;
613
    // Identify service provider to use
614
    env.put(Context.INITIAL_CONTEXT_FACTORY,
615
            "com.sun.jndi.ldap.LdapCtxFactory");
616
    env.put(Context.REFERRAL, "throw");
617
    env.put(Context.PROVIDER_URL, ldapUrl);
618
    try {
619
      // Create the initial directory context
620
      DirContext ctx = new InitialDirContext(env);
621
      // Specify the ids of the attributes to return
622
      String[] attrIDs = {
623
          "cn", "o", "description"};
624
      // Specify the attributes to match.
625
      // Groups are objects with attribute objectclass=groupofuniquenames.
626
      // and have attribute uniquemember: uid=foruser,ldapbase.
627
      SearchControls ctls = new SearchControls();
628
      ctls.setReturningAttributes(attrIDs);
629
      ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
630

    
631
      String filter = null;
632
      String gfilter = "(objectClass=groupOfUniqueNames)";
633
      if (null == foruser) {
634
        filter = gfilter;
635
      }
636
      else {
637
        filter = "(& " + gfilter + "(uniqueMember=" + foruser + "))";
638
      }
639
      MetaCatUtil.debugMessage("searching for groups: " + filter, 35);
640
      NamingEnumeration enum = ctx.search(ldapBase, filter, ctls);
641

    
642
      // Print the groups
643
      MetaCatUtil.debugMessage("getting group results.", 50);
644
      while (enum.hasMore()) {
645
        SearchResult sr = (SearchResult) enum.next();
646
        tempAttr = sr.getAttributes();
647

    
648
        if ( (tempAttr.get("description") + "").startsWith("description: ")) {
649
          desc.add( (tempAttr.get("description") + "").substring(13));
650
        }
651
        else {
652
          desc.add(tempAttr.get("description") + "");
653
        }
654

    
655
        gvec.add(sr.getName() + "," + ldapBase);
656
        MetaCatUtil.debugMessage("group " + sr.getName() +
657
                                 " added to Group vector", 35);
658
      }
659
      // Close the context when we're done
660
      ctx.close();
661

    
662
    }
663
    catch (ReferralException re) {
664
      refExc = re;
665
      Thread t = new Thread(new GetGroup());
666
      util.debugMessage("Starting thread...", 50);
667
      t.start();
668
      util.debugMessage("sleeping for 5 seconds.", 50);
669
      try {
670
        Thread.sleep(5000);
671
      }
672
      catch (InterruptedException ie) {
673
        MetaCatUtil.debugMessage("main thread interrupted: " + ie.getMessage(),
674
                                 30);
675
      }
676
      //this is a manual override of jndi's hideously long time
677
      //out period.
678
      util.debugMessage("Awake after 5 seconds.", 40);
679
      if (referralContext == null) {
680
        util.debugMessage("thread timed out...returning groups: " +
681
                          gvec.toString(), 35);
682
        String groups[][] = new String[gvec.size()][2];
683
        for (int i = 0; i < gvec.size(); i++) {
684
          groups[i][0] = (String) gvec.elementAt(i);
685
          groups[i][1] = (String) desc.elementAt(i);
686
        }
687
        t.interrupt();
688
        return groups;
689
      }
690
      DirContext dc = (DirContext) referralContext;
691
      String[] attrIDs = {
692
          "cn", "o", "description"};
693
      // Specify the attributes to match.
694
      // Groups are objects with attribute objectclass=groupofuniquenames.
695
      // and have attribute uniquemember: uid=foruser,ldapbase.
696
      SearchControls ctls = new SearchControls();
697
      ctls.setReturningAttributes(attrIDs);
698
      ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
699

    
700
      String filter = null;
701
      String gfilter = "(objectClass=groupOfUniqueNames)";
702
      if (null == foruser) {
703
        filter = gfilter;
704
      }
705
      else {
706
        filter = "(& " + gfilter + "(uniqueMember=" + foruser + "))";
707
      }
708

    
709
      try {
710
        NamingEnumeration enum = dc.search(ldapBase, filter, ctls);
711
        // Print the groups
712
        while (enum.hasMore()) {
713
          SearchResult sr = (SearchResult) enum.next();
714
          tempAttr = sr.getAttributes();
715

    
716
          if ( (tempAttr.get("description") + "").startsWith("description: ")) {
717
            desc.add( (tempAttr.get("description") + "").substring(13));
718
          }
719
          else {
720
            desc.add(tempAttr.get("description") + "");
721
          }
722

    
723
          gvec.add(sr.getName() + "," + ldapBase);
724
        }
725

    
726
        referralContext.close();
727
        dc.close();
728
      }
729
      catch (NamingException ne) {
730
        MetaCatUtil.debugMessage("Naming Exception in AuthLdap.getGroups" +
731
                                 ne.getExplanation() + ne.getMessage(), 30);
732
      }
733
    }
734
    catch (NamingException e) {
735
      e.printStackTrace(System.err);
736
      String groups[][] = new String[gvec.size()][2];
737
      for (int i = 0; i < gvec.size(); i++) {
738
        groups[i][0] = (String) gvec.elementAt(i);
739
        groups[i][1] = (String) desc.elementAt(i);
740
      }
741
      return groups;
742
      /*throw new ConnectException(
743
             "Problem getting groups for a user in AuthLdap.getGroups:" + e);*/
744
    }
745

    
746
    MetaCatUtil.debugMessage("The user is in the following groups: " +
747
                             gvec.toString(), 35);
748
    String groups[][] = new String[gvec.size()][2];
749
    for (int i = 0; i < gvec.size(); i++) {
750
      groups[i][0] = (String) gvec.elementAt(i);
751
      groups[i][1] = (String) desc.elementAt(i);
752
    }
753
    return groups;
754
  }
755

    
756
  /**
757
   * Get attributes describing a user or group
758
   *
759
   * @param foruser the user for which the attribute list is requested
760
   * @returns HashMap a map of attribute name to a Vector of values
761
   */
762
  public HashMap getAttributes(String foruser) throws ConnectException {
763
    return getAttributes(null, null, foruser);
764
  }
765

    
766
  /**
767
   * Get attributes describing a user or group
768
   *
769
   * @param user the user for authenticating against the service
770
   * @param password the password for authenticating against the service
771
   * @param foruser the user whose attributes should be returned
772
   * @returns HashMap a map of attribute name to a Vector of values
773
   */
774
  public HashMap getAttributes(String user, String password, String foruser) throws
775
      ConnectException {
776
    HashMap attributes = new HashMap();
777
    String ldapUrl = this.ldapUrl;
778
    String ldapBase = this.ldapBase;
779
    String userident = foruser;
780

    
781
    // Identify service provider to use
782
    Hashtable env = new Hashtable(11);
783
    env.put(Context.INITIAL_CONTEXT_FACTORY,
784
            "com.sun.jndi.ldap.LdapCtxFactory");
785
    env.put(Context.REFERRAL, referral);
786
    env.put(Context.PROVIDER_URL, ldapUrl);
787

    
788
    try {
789

    
790
      // Create the initial directory context
791
      DirContext ctx = new InitialDirContext(env);
792

    
793
      // Ask for all attributes of the user
794
      //Attributes attrs = ctx.getAttributes(userident);
795
      Attributes attrs = ctx.getAttributes(foruser);
796

    
797
      // Print all of the attributes
798
      NamingEnumeration en = attrs.getAll();
799
      while (en.hasMore()) {
800
        Attribute att = (Attribute) en.next();
801
        Vector values = new Vector();
802
        String attName = att.getID();
803
        NamingEnumeration attvalues = att.getAll();
804
        while (attvalues.hasMore()) {
805
          String value = (String) attvalues.next();
806
          values.add(value);
807
        }
808
        attributes.put(attName, values);
809
      }
810

    
811
      // Close the context when we're done
812
      ctx.close();
813
    }
814
    catch (NamingException e) {
815
      util.debugMessage("Problem getting attributes in " +
816
                        "AuthLdap.getAttributes:" + e, 35);
817
      throw new ConnectException(
818
          "Problem getting attributes in AuthLdap.getAttributes:" + e);
819
    }
820

    
821
    return attributes;
822
  }
823

    
824
  /**
825
   * Get list of all subtrees holding Metacat's groups and users
826
   * starting from the Metacat LDAP root,
827
   * i.e. ldap://dev.nceas.ucsb.edu/dc=ecoinformatics,dc=org
828
   */
829
  private Hashtable getSubtrees(String user, String password,
830
                                String ldapUrl, String ldapBase) throws
831
      ConnectException {
832
    Hashtable trees = new Hashtable();
833

    
834
    // Identify service provider to use
835
    Hashtable env = new Hashtable(11);
836
    env.put(Context.INITIAL_CONTEXT_FACTORY,
837
            "com.sun.jndi.ldap.LdapCtxFactory");
838
    env.put(Context.REFERRAL, referral);
839
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
840

    
841
    try {
842

    
843
      // Create the initial directory context
844
      DirContext ctx = new InitialDirContext(env);
845

    
846
      // Specify the ids of the attributes to return
847
      String[] attrIDs = {
848
          "o", "ref"};
849
      SearchControls ctls = new SearchControls();
850
      ctls.setReturningAttributes(attrIDs);
851
      ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
852

    
853
      // Specify the attributes to match.
854
      // Subtrees from the main server are found as objects with attribute
855
      // objectclass=organization or objectclass=referral to the subtree
856
      // resided on other server.
857
      String filter = "(|(objectclass=organization)(objectclass=referral))";
858

    
859
      // Search for objects in the current context
860
      NamingEnumeration enum = ctx.search("", filter, ctls);
861

    
862
      // Print the subtrees' <ldapURL, baseDN>
863
      while (enum.hasMore()) {
864

    
865
        SearchResult sr = (SearchResult) enum.next();
866

    
867
   //     util.debugMessage("SSSSSSSSSGGGGG: enum " + sr.toString() , 9);
868
   //     util.debugMessage("SSSSSSSSSGGGGG: enum " + sr.getName() , 9);
869
        Attributes attrs = sr.getAttributes();
870
        NamingEnumeration enum1 = attrs.getAll(); // "dc" and "ref" attrs
871

    
872
//        while (enum1.hasMore()) {
873
  //        Attribute attr = (Attribute) enum1.next();
874
    //      String attrValue = (String) attr.get();
875
     //     String attrName = (String) attr.getID();
876
     //   }
877

    
878
        if (enum1.hasMore()) {
879
          Attribute attr = (Attribute) enum1.next();
880
          String attrValue = (String) attr.get();
881
          String attrName = (String) attr.getID();
882

    
883
          if (enum1.hasMore()) {
884
            attr = (Attribute) enum1.next();
885
            String refValue = (String) attr.get();
886
            String refName = (String) attr.getID();
887
            if (ldapBase.startsWith(refName + "=" + refValue)) {
888
              trees.put(ldapBase,
889
                        attrValue.substring(0, attrValue.lastIndexOf("/") + 1));
890
            }
891
            else {
892
              trees.put(refName + "=" + refValue + "," + ldapBase,
893
                        attrValue.substring(0, attrValue.lastIndexOf("/") + 1));
894
            }
895

    
896
          }
897
          else if (ldapBase.startsWith(attrName + "=" + attrValue)) {
898
            trees.put(ldapBase, ldapUrl);
899
          }
900
          else {
901
            if(sr.isRelative()){
902
              trees.put(attrName + "=" + attrValue + "," + ldapBase, ldapUrl);
903
            } else {
904
              String referenceURL = sr.getName();
905
              referenceURL = referenceURL.substring(0, referenceURL.lastIndexOf("/") + 1);
906
              trees.put(attrName + "=" + attrValue + "," + ldapBase, referenceURL);
907
            }
908

    
909
          }
910
        }
911
      }
912

    
913
      // Close the context when we're done
914
      ctx.close();
915

    
916
    }
917
    catch (NamingException e) {
918
      util.debugMessage("Problem getting subtrees in AuthLdap.getSubtrees:"
919
                        + e, 30);
920
      throw new ConnectException(
921
          "Problem getting subtrees in AuthLdap.getSubtrees:" + e);
922
    }
923

    
924
  //  util.debugMessage("SSSSSSSSSGGGGG: trees: " + trees.toString() , 9);
925
    return trees;
926
  }
927

    
928
  /**
929
   * Get all groups and users from authentication scheme.
930
   * The output is formatted in XML.
931
   * @param user the user which requests the information
932
   * @param password the user's password
933
   */
934
  public String getPrincipals(String user, String password) throws
935
      ConnectException {
936
    StringBuffer out = new StringBuffer();
937
    Vector usersIn = new Vector();
938

    
939
    out.append("<?xml version=\"1.0\" encoding=\"US-ASCII\"?>\n");
940
    out.append("<principals>\n");
941

    
942
    /*
943
     * get all subtrees first in the current dir context
944
     * and then the Metacat users under them
945
     */
946
    Hashtable subtrees = getSubtrees(user, password, this.ldapUrl,
947
                                     this.ldapBase);
948

    
949
    Enumeration enum = subtrees.keys();
950
    while (enum.hasMoreElements()) {
951
      this.ldapBase = (String) enum.nextElement();
952
      this.ldapUrl = (String) subtrees.get(ldapBase);
953

    
954
      String orgName = this.ldapBase;
955
      if (orgName != null && orgName.indexOf("o=") > -1) {
956
        orgName = orgName.substring(orgName.indexOf("o=") + 2);
957
        orgName = orgName.substring(0, orgName.indexOf(","));
958
      }
959
      else {
960
        orgName = "";
961
      }
962

    
963
      out.append("  <authSystem URI=\"" +
964
                 this.ldapUrl + this.ldapBase + "\" organization=\"" + orgName +
965
                 "\">\n");
966

    
967
      // get all groups for directory context
968
      String[][] groups = getGroups(user, password);
969
      String[][] users = getUsers(user, password);
970
      int userIndex = 0;
971

    
972
      // for the groups and users that belong to them
973
      if (groups != null && groups.length > 0) {
974
        for (int i = 0; i < groups.length; i++) {
975
          out.append("    <group>\n");
976
          out.append("      <groupname>" + groups[i][0] + "</groupname>\n");
977
          out.append("      <description>" + groups[i][1] + "</description>\n");
978
          String[] usersForGroup = getUsers(user, password, groups[i][0]);
979
          for (int j = 0; j < usersForGroup.length; j++) {
980
            usersIn.addElement(usersForGroup[j]);
981

    
982
            userIndex = searchUser(usersForGroup[j], users);
983
            out.append("      <user>\n");
984

    
985
            if (userIndex < 0) {
986
              out.append("        <username>" + usersForGroup[j] +
987
                         "</username>\n");
988
            }
989
            else {
990
              out.append("      <username>" + users[userIndex][0] +
991
                         "</username>\n");
992
              out.append("      <name>" + users[userIndex][1] + "</name>\n");
993
              out.append("      <organization>" + users[userIndex][2] +
994
                         "</organization>\n");
995
              out.append("      <email>" + users[userIndex][3] + "</email>\n");
996
            }
997

    
998
            out.append("      </user>\n");
999
          }
1000
          out.append("    </group>\n");
1001
        }
1002
      }
1003

    
1004
      // for the users not belonging to any group
1005
      for (int j = 0; j < users.length; j++) {
1006
        if (!usersIn.contains(users[j][0])) {
1007
          out.append("    <user>\n");
1008
          out.append("      <username>" + users[j][0] + "</username>\n");
1009
          out.append("      <name>" + users[j][1] + "</name>\n");
1010
          out.append("      <organization>" + users[j][2] + "</organization>\n");
1011
          out.append("      <email>" + users[j][3] + "</email>\n");
1012
          out.append("    </user>\n");
1013
        }
1014
      }
1015

    
1016
      out.append("  </authSystem>\n");
1017
      if (!usersIn.isEmpty()) {
1018
        usersIn.removeAllElements();
1019
        usersIn.trimToSize();
1020
      }
1021

    
1022
    }
1023
    out.append("</principals>");
1024
    return out.toString();
1025
  }
1026

    
1027
  /**
1028
   * Method for getting index of user DN in User info array
1029
   */
1030
  int searchUser(String user, String userGroup[][]) {
1031
    for (int j = 0; j < userGroup.length; j++) {
1032
      if (user.compareTo(userGroup[j][0]) == 0) {
1033
        return j;
1034
      }
1035
    }
1036
    return -1;
1037
  }
1038

    
1039
  /**
1040
   * Test method for the class
1041
   */
1042
  public static void main(String[] args) {
1043

    
1044
    // Provide a user, such as: "Matt Jones", or "jones"
1045
    String user = args[0];
1046
    String password = args[1];
1047

    
1048
    MetaCatUtil.debugMessage("Creating session...", 20);
1049
    AuthLdap authservice = new AuthLdap();
1050
    MetaCatUtil.debugMessage("Session exists...", 20);
1051

    
1052
    boolean isValid = false;
1053
    try {
1054
      MetaCatUtil.debugMessage("Authenticating...", 20);
1055
      isValid = authservice.authenticate(user, password);
1056
      if (isValid) {
1057
        MetaCatUtil.debugMessage("Authentication successful for: " + user, 20);
1058
      }
1059
      else {
1060
        MetaCatUtil.debugMessage("Authentication failed for: " + user, 20);
1061
      }
1062

    
1063
      // Get attributes for the user
1064
      if (isValid) {
1065
        MetaCatUtil.debugMessage("\nGetting attributes for user....", 20);
1066
        HashMap userInfo = authservice.getAttributes(user, password, user);
1067
        // Print all of the attributes
1068
        Iterator attList = (Iterator) ( ( (Set) userInfo.keySet()).iterator());
1069
        while (attList.hasNext()) {
1070
          String att = (String) attList.next();
1071
          Vector values = (Vector) userInfo.get(att);
1072
          Iterator attvalues = values.iterator();
1073
          while (attvalues.hasNext()) {
1074
            String value = (String) attvalues.next();
1075
            MetaCatUtil.debugMessage(att + ": " + value, 20);
1076
          }
1077
        }
1078
      }
1079

    
1080
      // get the groups
1081
      if (isValid) {
1082
        MetaCatUtil.debugMessage("\nGetting all groups....", 20);
1083
        String[][] groups = authservice.getGroups(user, password);
1084
        MetaCatUtil.debugMessage("Groups found: " + groups.length, 20);
1085
        for (int i = 0; i < groups.length; i++) {
1086
          MetaCatUtil.debugMessage("Group " + i + ": " + groups[i][0], 20);
1087
        }
1088
      }
1089

    
1090
      // get the groups for the user
1091
      String savedGroup = null;
1092
      if (isValid) {
1093
        MetaCatUtil.debugMessage("\nGetting groups for user....", 20);
1094
        String[][] groups = authservice.getGroups(user, password, user);
1095
        MetaCatUtil.debugMessage("Groups found: " + groups.length, 20);
1096
        for (int i = 0; i < groups.length; i++) {
1097
          MetaCatUtil.debugMessage("Group " + i + ": " + groups[i][0], 20);
1098
          savedGroup = groups[i][0];
1099
        }
1100
      }
1101

    
1102
      // get the users for a group
1103
      if (isValid) {
1104
        MetaCatUtil.debugMessage("\nGetting users for group....", 20);
1105
        MetaCatUtil.debugMessage("Group: " + savedGroup, 20);
1106
        String[] users = authservice.getUsers(user, password, savedGroup);
1107
        MetaCatUtil.debugMessage("Users found: " + users.length, 20);
1108
        for (int i = 0; i < users.length; i++) {
1109
          MetaCatUtil.debugMessage("User " + i + ": " + users[i], 20);
1110
        }
1111
      }
1112

    
1113
      // get all users
1114
      if (isValid) {
1115
        MetaCatUtil.debugMessage("\nGetting all users ....", 20);
1116
        String[][] users = authservice.getUsers(user, password);
1117
        MetaCatUtil.debugMessage("Users found: " + users.length, 20);
1118

    
1119
      }
1120

    
1121
      // get the whole list groups and users in XML format
1122
      if (isValid) {
1123
        MetaCatUtil.debugMessage("\nTrying principals....", 20);
1124
        authservice = new AuthLdap();
1125
        String out = authservice.getPrincipals(user, password);
1126
        java.io.File f = new java.io.File("principals.xml");
1127
        java.io.FileWriter fw = new java.io.FileWriter(f);
1128
        java.io.BufferedWriter buff = new java.io.BufferedWriter(fw);
1129
        buff.write(out);
1130
        buff.flush();
1131
        buff.close();
1132
        fw.close();
1133
        MetaCatUtil.debugMessage("\nFinished getting principals.", 20);
1134
      }
1135

    
1136
    }
1137
    catch (ConnectException ce) {
1138
      MetaCatUtil.debugMessage(ce.getMessage(), 30);
1139
    }
1140
    catch (java.io.IOException ioe) {
1141
      MetaCatUtil.debugMessage("I/O Error writing to file principals.txt", 20);
1142
    }
1143
  }
1144

    
1145
  /**
1146
   * This method will be called by start a thread.
1147
   * It can handle if a referral exception happend.
1148
   */
1149
  public void run() {
1150
    referralContext = null;
1151
    DirContext refDirContext = null;
1152
    boolean moreReferrals = true;
1153
    String referralInfo = null;
1154
    //set a while loop is because we don't know if a referral excption contains
1155
    //another referral exception
1156
    while (moreReferrals) {
1157
      try {
1158
        //revise environment variable
1159
        referralInfo = (String) refExc.getReferralInfo();
1160
        util.debugMessage("Processing referral (pr0): ", 35);
1161
        util.debugMessage("PROVIDER_URL set to (pr1): " + referralInfo, 35);
1162
        //env.put(Context.PROVIDER_URL,referralInfo);
1163
        //env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
1164
        //env.put(Context.SECURITY_PRINCIPAL, userName);
1165
        //env.put(Context.SECURITY_CREDENTIALS, userPassword);
1166
        //env.put(Context.REFERRAL, "throw");
1167
        //util.debugMessage("Processing referral (pr1.info): " + userName,35);
1168
        //util.debugMessage("Processing referral (pr2)",35);
1169
        //rContext = refExc.getReferralContext(env);
1170
        rContext = refExc.getReferralContext();
1171
        util.debugMessage("Processing referral (pr3)", 35);
1172
        //casting the context to dircontext and it will create a
1173
        //autherntication or naming exception if DN and password is incorrect
1174
        referralContext = rContext;
1175
        refDirContext = (DirContext) rContext;
1176
        refDirContext.close();
1177
        //get context and jump out the while loop
1178
        moreReferrals = false;
1179
        util.debugMessage("Processing referral (pr4)", 35);
1180
      } //try
1181
      //if referral have another referral excption
1182
      catch (ReferralException re) {
1183
        util.debugMessage("GOT referral exception (re1): " + re.getMessage(),
1184
                          35);
1185
        util.debugMessage("RE details (re2): " + re.toString(true), 35);
1186
        //keep running in while loop
1187
        moreReferrals = true;
1188
        //assign refExc to new referral exception re
1189
        refExc = re;
1190
      }
1191
      //catch a authentication exception
1192
      catch (AuthenticationException ae) {
1193
        util.debugMessage("Error running referral handler thread (ae1): " +
1194
                          ae.getMessage(), 20);
1195
        //check if has another referral
1196
        moreReferrals = refExc.skipReferral();
1197
        //don't get the context
1198
        referralContext = null;
1199
      }
1200
      //catch a naming exception
1201
      catch (NamingException ne) {
1202
        util.debugMessage("Error running referral handler thread (ne1): " +
1203
                          ne.getMessage(), 20);
1204
        //check if has another referral
1205
        moreReferrals = refExc.skipReferral();
1206
        //don't get context
1207
        referralContext = null;
1208
      }
1209
    } //while
1210
  } //run()
1211

    
1212
  private class GetGroup
1213
      implements Runnable {
1214
    public void run() {
1215
      referralContext = null;
1216
      MetaCatUtil.debugMessage("getting groups context", 50);
1217
      DirContext refDirContext = null;
1218
      boolean moreReferrals = true;
1219
      //set a while loop is because we don't know if a referral excption
1220
      //contains another referral exception
1221
      while (moreReferrals) {
1222
        try {
1223
          //revise environment variable
1224
          String refInfo = null;
1225
          refInfo = (String) refExc.getReferralInfo();
1226
          if (refInfo != null) {
1227
            MetaCatUtil.debugMessage("Referral in thread to: " +
1228
                                     refInfo.toString(), 40);
1229
          }
1230
          else {
1231
            MetaCatUtil.debugMessage("getting refInfo Manually", 50);
1232
            refInfo = (String) refExc.getReferralContext().getEnvironment().
1233
                get(Context.PROVIDER_URL);
1234
          }
1235
          MetaCatUtil.debugMessage("refInfo: " + refInfo, 40);
1236

    
1237
          env.put(Context.INITIAL_CONTEXT_FACTORY,
1238
                  "com.sun.jndi.ldap.LdapCtxFactory");
1239
          env.put(Context.REFERRAL, "throw");
1240
          env.put(Context.PROVIDER_URL, refInfo);
1241

    
1242
          MetaCatUtil.debugMessage("creating referralContext", 40);
1243
          referralContext = new InitialDirContext(env);
1244
          MetaCatUtil.debugMessage("referralContext created", 40);
1245
          //get context and jump out the while loop
1246
          moreReferrals = false;
1247
        } //try
1248
        catch (ReferralException re) {
1249
          //keep running in while loop
1250
          moreReferrals = true;
1251
          //assign refExc to new referral exception re
1252
          refExc = re;
1253
        }
1254
        catch (AuthenticationException ae) {
1255
          util.debugMessage("Error running referral handler thread (ae2): " +
1256
                            ae.getMessage(), 50);
1257
          //check if has another referral
1258
          moreReferrals = refExc.skipReferral();
1259
          //don't get the context
1260
          referralContext = null;
1261
        }
1262
        catch (NamingException ne) {
1263
          util.debugMessage("Error running referral handler thread (ne2): " +
1264
                            ne.getMessage(), 50);
1265
          //check if has another referral
1266
          moreReferrals = refExc.skipReferral();
1267
          //don't get context
1268
          referralContext = null;
1269
        }
1270
      } //while
1271
    } //run()
1272
  }
1273
}
(12-12/61)