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 17:27:09 -0700 (Wed, 14 Apr 2004) $'
13
 * '$Revision: 2129 $'
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
    // Using 'ignore' here instead of 'follow' as 'ignore' seems
840
    // to do the job better. 'follow' was not bringing up the UCNRS
841
    // and PISCO tree whereas 'ignore' brings up the tree.
842

    
843
    env.put(Context.REFERRAL, "ignore");
844
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
845

    
846
    try {
847

    
848
      // Create the initial directory context
849
      DirContext ctx = new InitialDirContext(env);
850

    
851
      // Specify the ids of the attributes to return
852
      String[] attrIDs = {
853
          "o", "ref"};
854
      SearchControls ctls = new SearchControls();
855
      ctls.setReturningAttributes(attrIDs);
856
      ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
857

    
858
      // Specify the attributes to match.
859
      // Subtrees from the main server are found as objects with attribute
860
      // objectclass=organization or objectclass=referral to the subtree
861
      // resided on other server.
862
      String filter = "(|(objectclass=organization)(objectclass=referral))";
863

    
864
      // Search for objects in the current context
865
      NamingEnumeration enum = ctx.search("", filter, ctls);
866

    
867
      // Print the subtrees' <ldapURL, baseDN>
868
      while (enum.hasMore()) {
869

    
870
        SearchResult sr = (SearchResult) enum.next();
871

    
872
        Attributes attrs = sr.getAttributes();
873
        NamingEnumeration enum1 = attrs.getAll(); // "dc" and "ref" attrs
874

    
875
        if (enum1.hasMore()) {
876
          Attribute attr = (Attribute) enum1.next();
877
          String attrValue = (String) attr.get();
878
          String attrName = (String) attr.getID();
879

    
880
          if (enum1.hasMore()) {
881
            attr = (Attribute) enum1.next();
882
            String refValue = (String) attr.get();
883
            String refName = (String) attr.getID();
884
            if (ldapBase.startsWith(refName + "=" + refValue)) {
885
              trees.put(ldapBase,
886
                        attrValue.substring(0, attrValue.lastIndexOf("/") + 1));
887
            }
888
            else {
889
              // this is a referral - so organization name is appended in
890
              // front of the ldapbase.... later it is stripped out
891
              // in getPrincipals
892
              trees.put("[" + refName + "=" + refValue + "]" +
893
                        attrValue.substring(attrValue.lastIndexOf("/") + 1,
894
                                            attrValue.length()),
895
                        attrValue.substring(0, attrValue.lastIndexOf("/") + 1));
896

    
897
              // trees.put(refName + "=" + refValue + "," + ldapBase,
898
              //           attrValue.substring(0, attrValue.lastIndexOf("/") + 1));
899
            }
900

    
901
          }
902
          else if (ldapBase.startsWith(attrName + "=" + attrValue)) {
903
            trees.put(ldapBase, ldapUrl);
904
          }
905
          else {
906
            if (sr.isRelative()) {
907
              trees.put(attrName + "=" + attrValue + "," + ldapBase, ldapUrl);
908
            } else {
909
              String referenceURL = sr.getName();
910
              referenceURL = referenceURL.substring(0,
911
                  referenceURL.lastIndexOf("/") + 1);
912
              trees.put(attrName + "=" + attrValue + "," + ldapBase,
913
                        referenceURL);
914
            }
915

    
916
          }
917
        }
918
      }
919

    
920
      // Close the context when we're done
921
      ctx.close();
922

    
923
    }
924
    catch (NamingException e) {
925
      util.debugMessage("Problem getting subtrees in AuthLdap.getSubtrees:"
926
                        + e, 30);
927
      throw new ConnectException(
928
          "Problem getting subtrees in AuthLdap.getSubtrees:" + e);
929
    }
930

    
931
    return trees;
932
  }
933

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

    
945
    out.append("<?xml version=\"1.0\" encoding=\"US-ASCII\"?>\n");
946
    out.append("<principals>\n");
947

    
948
    /*
949
     * get all subtrees first in the current dir context
950
     * and then the Metacat users under them
951
     */
952
    Hashtable subtrees = getSubtrees(user, password, this.ldapUrl,
953
                                     this.ldapBase);
954

    
955
    Enumeration enum = subtrees.keys();
956
    while (enum.hasMoreElements()) {
957
      this.ldapBase = (String) enum.nextElement();
958
      this.ldapUrl = (String) subtrees.get(ldapBase);
959

    
960

    
961
      /*
962
       * code to get the organization name from ldapBase
963
       */
964
      String orgName = this.ldapBase;
965
      if(orgName.startsWith("[")){
966
        // if orgName starts with [ then it is a referral URL...
967
        // (see code in getSubtress)
968
        // hence orgName can be retrieved  by getting the string between
969
        // 'o=' and ']'
970
        // also the string between [ and ] needs to be striped out from
971
        // this.ldapBase
972
        this.ldapBase = orgName.substring(orgName.indexOf("]") + 1);
973
        if (orgName != null && orgName.indexOf("o=") > -1) {
974
          orgName = orgName.substring(orgName.indexOf("o=") + 2);
975
          orgName = orgName.substring(0, orgName.indexOf("]"));
976
        }
977
      } else {
978
        // else it is not referral
979
        // hence orgName can be retrieved  by getting the string between
980
        // 'o=' and ','
981
        if (orgName != null && orgName.indexOf("o=") > -1) {
982
          orgName = orgName.substring(orgName.indexOf("o=") + 2);
983
          if (orgName.indexOf(",") > -1) {
984
            orgName = orgName.substring(0, orgName.indexOf(","));
985
          }
986
        }
987
      }
988

    
989
      out.append("  <authSystem URI=\"" +
990
                 this.ldapUrl + this.ldapBase + "\" organization=\"" + orgName +
991
                 "\">\n");
992

    
993
      // get all groups for directory context
994
      String[][] groups = getGroups(user, password);
995
      String[][] users = getUsers(user, password);
996
      int userIndex = 0;
997

    
998
      // for the groups and users that belong to them
999
      if (groups != null && groups.length > 0) {
1000
        for (int i = 0; i < groups.length; i++) {
1001
          out.append("    <group>\n");
1002
          out.append("      <groupname>" + groups[i][0] + "</groupname>\n");
1003
          out.append("      <description>" + groups[i][1] + "</description>\n");
1004
          String[] usersForGroup = getUsers(user, password, groups[i][0]);
1005
          for (int j = 0; j < usersForGroup.length; j++) {
1006
            usersIn.addElement(usersForGroup[j]);
1007

    
1008
            userIndex = searchUser(usersForGroup[j], users);
1009
            out.append("      <user>\n");
1010

    
1011
            if (userIndex < 0) {
1012
              out.append("        <username>" + usersForGroup[j] +
1013
                         "</username>\n");
1014
            }
1015
            else {
1016
              out.append("      <username>" + users[userIndex][0] +
1017
                         "</username>\n");
1018
              out.append("      <name>" + users[userIndex][1] + "</name>\n");
1019
              out.append("      <organization>" + users[userIndex][2] +
1020
                         "</organization>\n");
1021
              out.append("      <email>" + users[userIndex][3] + "</email>\n");
1022
            }
1023

    
1024
            out.append("      </user>\n");
1025
          }
1026
          out.append("    </group>\n");
1027
        }
1028
      }
1029

    
1030
      // for the users not belonging to any group
1031
      for (int j = 0; j < users.length; j++) {
1032
        if (!usersIn.contains(users[j][0])) {
1033
          out.append("    <user>\n");
1034
          out.append("      <username>" + users[j][0] + "</username>\n");
1035
          out.append("      <name>" + users[j][1] + "</name>\n");
1036
          out.append("      <organization>" + users[j][2] + "</organization>\n");
1037
          out.append("      <email>" + users[j][3] + "</email>\n");
1038
          out.append("    </user>\n");
1039
        }
1040
      }
1041

    
1042
      out.append("  </authSystem>\n");
1043
      if (!usersIn.isEmpty()) {
1044
        usersIn.removeAllElements();
1045
        usersIn.trimToSize();
1046
      }
1047

    
1048
    }
1049
    out.append("</principals>");
1050
    return out.toString();
1051
  }
1052

    
1053
  /**
1054
   * Method for getting index of user DN in User info array
1055
   */
1056
  int searchUser(String user, String userGroup[][]) {
1057
    for (int j = 0; j < userGroup.length; j++) {
1058
      if (user.compareTo(userGroup[j][0]) == 0) {
1059
        return j;
1060
      }
1061
    }
1062
    return -1;
1063
  }
1064

    
1065
  /**
1066
   * Test method for the class
1067
   */
1068
  public static void main(String[] args) {
1069

    
1070
    // Provide a user, such as: "Matt Jones", or "jones"
1071
    String user = args[0];
1072
    String password = args[1];
1073

    
1074
    MetaCatUtil.debugMessage("Creating session...", 20);
1075
    AuthLdap authservice = new AuthLdap();
1076
    MetaCatUtil.debugMessage("Session exists...", 20);
1077

    
1078
    boolean isValid = false;
1079
    try {
1080
      MetaCatUtil.debugMessage("Authenticating...", 20);
1081
      isValid = authservice.authenticate(user, password);
1082
      if (isValid) {
1083
        MetaCatUtil.debugMessage("Authentication successful for: " + user, 20);
1084
      }
1085
      else {
1086
        MetaCatUtil.debugMessage("Authentication failed for: " + user, 20);
1087
      }
1088

    
1089
      // Get attributes for the user
1090
      if (isValid) {
1091
        MetaCatUtil.debugMessage("\nGetting attributes for user....", 20);
1092
        HashMap userInfo = authservice.getAttributes(user, password, user);
1093
        // Print all of the attributes
1094
        Iterator attList = (Iterator) ( ( (Set) userInfo.keySet()).iterator());
1095
        while (attList.hasNext()) {
1096
          String att = (String) attList.next();
1097
          Vector values = (Vector) userInfo.get(att);
1098
          Iterator attvalues = values.iterator();
1099
          while (attvalues.hasNext()) {
1100
            String value = (String) attvalues.next();
1101
            MetaCatUtil.debugMessage(att + ": " + value, 20);
1102
          }
1103
        }
1104
      }
1105

    
1106
      // get the groups
1107
      if (isValid) {
1108
        MetaCatUtil.debugMessage("\nGetting all groups....", 20);
1109
        String[][] groups = authservice.getGroups(user, password);
1110
        MetaCatUtil.debugMessage("Groups found: " + groups.length, 20);
1111
        for (int i = 0; i < groups.length; i++) {
1112
          MetaCatUtil.debugMessage("Group " + i + ": " + groups[i][0], 20);
1113
        }
1114
      }
1115

    
1116
      // get the groups for the user
1117
      String savedGroup = null;
1118
      if (isValid) {
1119
        MetaCatUtil.debugMessage("\nGetting groups for user....", 20);
1120
        String[][] groups = authservice.getGroups(user, password, user);
1121
        MetaCatUtil.debugMessage("Groups found: " + groups.length, 20);
1122
        for (int i = 0; i < groups.length; i++) {
1123
          MetaCatUtil.debugMessage("Group " + i + ": " + groups[i][0], 20);
1124
          savedGroup = groups[i][0];
1125
        }
1126
      }
1127

    
1128
      // get the users for a group
1129
      if (isValid) {
1130
        MetaCatUtil.debugMessage("\nGetting users for group....", 20);
1131
        MetaCatUtil.debugMessage("Group: " + savedGroup, 20);
1132
        String[] users = authservice.getUsers(user, password, savedGroup);
1133
        MetaCatUtil.debugMessage("Users found: " + users.length, 20);
1134
        for (int i = 0; i < users.length; i++) {
1135
          MetaCatUtil.debugMessage("User " + i + ": " + users[i], 20);
1136
        }
1137
      }
1138

    
1139
      // get all users
1140
      if (isValid) {
1141
        MetaCatUtil.debugMessage("\nGetting all users ....", 20);
1142
        String[][] users = authservice.getUsers(user, password);
1143
        MetaCatUtil.debugMessage("Users found: " + users.length, 20);
1144

    
1145
      }
1146

    
1147
      // get the whole list groups and users in XML format
1148
      if (isValid) {
1149
        MetaCatUtil.debugMessage("\nTrying principals....", 20);
1150
        authservice = new AuthLdap();
1151
        String out = authservice.getPrincipals(user, password);
1152
        java.io.File f = new java.io.File("principals.xml");
1153
        java.io.FileWriter fw = new java.io.FileWriter(f);
1154
        java.io.BufferedWriter buff = new java.io.BufferedWriter(fw);
1155
        buff.write(out);
1156
        buff.flush();
1157
        buff.close();
1158
        fw.close();
1159
        MetaCatUtil.debugMessage("\nFinished getting principals.", 20);
1160
      }
1161

    
1162
    }
1163
    catch (ConnectException ce) {
1164
      MetaCatUtil.debugMessage(ce.getMessage(), 30);
1165
    }
1166
    catch (java.io.IOException ioe) {
1167
      MetaCatUtil.debugMessage("I/O Error writing to file principals.txt", 20);
1168
    }
1169
  }
1170

    
1171
  /**
1172
   * This method will be called by start a thread.
1173
   * It can handle if a referral exception happend.
1174
   */
1175
  public void run() {
1176
    referralContext = null;
1177
    DirContext refDirContext = null;
1178
    boolean moreReferrals = true;
1179
    String referralInfo = null;
1180
    //set a while loop is because we don't know if a referral excption contains
1181
    //another referral exception
1182
    while (moreReferrals) {
1183
      try {
1184
        //revise environment variable
1185
        referralInfo = (String) refExc.getReferralInfo();
1186
        util.debugMessage("Processing referral (pr0): ", 35);
1187
        util.debugMessage("PROVIDER_URL set to (pr1): " + referralInfo, 35);
1188
        //env.put(Context.PROVIDER_URL,referralInfo);
1189
        //env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
1190
        //env.put(Context.SECURITY_PRINCIPAL, userName);
1191
        //env.put(Context.SECURITY_CREDENTIALS, userPassword);
1192
        //env.put(Context.REFERRAL, "throw");
1193
        //util.debugMessage("Processing referral (pr1.info): " + userName,35);
1194
        //util.debugMessage("Processing referral (pr2)",35);
1195
        //rContext = refExc.getReferralContext(env);
1196
        rContext = refExc.getReferralContext();
1197
        util.debugMessage("Processing referral (pr3)", 35);
1198
        //casting the context to dircontext and it will create a
1199
        //autherntication or naming exception if DN and password is incorrect
1200
        referralContext = rContext;
1201
        refDirContext = (DirContext) rContext;
1202
        refDirContext.close();
1203
        //get context and jump out the while loop
1204
        moreReferrals = false;
1205
        util.debugMessage("Processing referral (pr4)", 35);
1206
      } //try
1207
      //if referral have another referral excption
1208
      catch (ReferralException re) {
1209
        util.debugMessage("GOT referral exception (re1): " + re.getMessage(),
1210
                          35);
1211
        util.debugMessage("RE details (re2): " + re.toString(true), 35);
1212
        //keep running in while loop
1213
        moreReferrals = true;
1214
        //assign refExc to new referral exception re
1215
        refExc = re;
1216
      }
1217
      //catch a authentication exception
1218
      catch (AuthenticationException ae) {
1219
        util.debugMessage("Error running referral handler thread (ae1): " +
1220
                          ae.getMessage(), 20);
1221
        //check if has another referral
1222
        moreReferrals = refExc.skipReferral();
1223
        //don't get the context
1224
        referralContext = null;
1225
      }
1226
      //catch a naming exception
1227
      catch (NamingException ne) {
1228
        util.debugMessage("Error running referral handler thread (ne1): " +
1229
                          ne.getMessage(), 20);
1230
        //check if has another referral
1231
        moreReferrals = refExc.skipReferral();
1232
        //don't get context
1233
        referralContext = null;
1234
      }
1235
    } //while
1236
  } //run()
1237

    
1238
  private class GetGroup
1239
      implements Runnable {
1240
    public void run() {
1241
      referralContext = null;
1242
      MetaCatUtil.debugMessage("getting groups context", 50);
1243
      DirContext refDirContext = null;
1244
      boolean moreReferrals = true;
1245
      //set a while loop is because we don't know if a referral excption
1246
      //contains another referral exception
1247
      while (moreReferrals) {
1248
        try {
1249
          //revise environment variable
1250
          String refInfo = null;
1251
          refInfo = (String) refExc.getReferralInfo();
1252
          if (refInfo != null) {
1253
            MetaCatUtil.debugMessage("Referral in thread to: " +
1254
                                     refInfo.toString(), 40);
1255
          }
1256
          else {
1257
            MetaCatUtil.debugMessage("getting refInfo Manually", 50);
1258
            refInfo = (String) refExc.getReferralContext().getEnvironment().
1259
                get(Context.PROVIDER_URL);
1260
          }
1261
          MetaCatUtil.debugMessage("refInfo: " + refInfo, 40);
1262

    
1263
          env.put(Context.INITIAL_CONTEXT_FACTORY,
1264
                  "com.sun.jndi.ldap.LdapCtxFactory");
1265
          env.put(Context.REFERRAL, "throw");
1266
          env.put(Context.PROVIDER_URL, refInfo);
1267

    
1268
          MetaCatUtil.debugMessage("creating referralContext", 40);
1269
          referralContext = new InitialDirContext(env);
1270
          MetaCatUtil.debugMessage("referralContext created", 40);
1271
          //get context and jump out the while loop
1272
          moreReferrals = false;
1273
        } //try
1274
        catch (ReferralException re) {
1275
          //keep running in while loop
1276
          moreReferrals = true;
1277
          //assign refExc to new referral exception re
1278
          refExc = re;
1279
        }
1280
        catch (AuthenticationException ae) {
1281
          util.debugMessage("Error running referral handler thread (ae2): " +
1282
                            ae.getMessage(), 50);
1283
          //check if has another referral
1284
          moreReferrals = refExc.skipReferral();
1285
          //don't get the context
1286
          referralContext = null;
1287
        }
1288
        catch (NamingException ne) {
1289
          util.debugMessage("Error running referral handler thread (ne2): " +
1290
                            ne.getMessage(), 50);
1291
          //check if has another referral
1292
          moreReferrals = refExc.skipReferral();
1293
          //don't get context
1294
          referralContext = null;
1295
        }
1296
      } //while
1297
    } //run()
1298
  }
1299
}
(12-12/61)