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: bojilova $'
12
 *     '$Date: 2001-04-17 09:32:07 -0700 (Tue, 17 Apr 2001) $'
13
 * '$Revision: 730 $'
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

    
34
import javax.naming.AuthenticationException;
35
import javax.naming.Context;
36
import javax.naming.InitialContext;
37
import javax.naming.directory.Attribute;
38
import javax.naming.directory.Attributes;
39
import javax.naming.directory.BasicAttribute;
40
import javax.naming.directory.BasicAttributes;
41
import javax.naming.directory.DirContext;
42
import javax.naming.directory.InitialDirContext;
43
import javax.naming.directory.SearchResult;
44
import javax.naming.directory.SearchControls;
45
import javax.naming.NamingEnumeration;
46
import javax.naming.NamingException;
47
import java.util.Iterator;
48
import java.util.HashMap;
49
import java.util.Hashtable;
50
import java.util.Enumeration;
51
import java.util.Set;
52
import java.util.Vector;
53

    
54
/**
55
 * An implementation of the AuthInterface interface that
56
 * allows Metacat to use the LDAP protocol for directory services.
57
 * The LDAP authentication service is used to determine if a user 
58
 * is authenticated, and whether they are a member of a particular group.
59
 */
60
public class AuthLdap implements AuthInterface {
61
  
62
  private MetaCatUtil util;
63
  private String ldapUrl;
64
  private String ldapBase;
65

    
66
  /** 
67
   * Construct an AuthLdap
68
   */
69
  public AuthLdap() {
70

    
71
    // Read LDAP URI for directory service information
72
    this.util = new MetaCatUtil();
73
    this.ldapUrl = util.getOption("ldapurl");
74
    this.ldapBase = util.getOption("ldapbase");
75
  }
76

    
77
  /**
78
   * Determine if a user/password are valid according to the authentication
79
   * service.
80
   *
81
   * @param user the name of the principal to authenticate
82
   * @param password the password to use for authentication
83
   * @returns boolean true if authentication successful, false otherwise
84
   */
85
  public boolean authenticate(String user, String password)
86
                    throws ConnectException
87
  {
88
    String ldapUrl = this.ldapUrl;
89
    String ldapBase = this.ldapBase;
90
    boolean authenticated = false;
91
    
92
    // Identify service provider to use
93
    Hashtable env = new Hashtable(11);
94
    env.put(Context.INITIAL_CONTEXT_FACTORY, 
95
            "com.sun.jndi.ldap.LdapCtxFactory");
96
//    env.put(Context.SECURITY_AUTHENTICATION, "simple");
97
//    env.put(Context.SECURITY_PRINCIPAL, user);
98

    
99
    try {
100

    
101
      /*
102
       * get all subtrees first in the current dir context 
103
       * and then the dn for this uid or cn
104
       */
105
      Hashtable subtrees = getSubtrees(user,password,ldapUrl,ldapBase);
106
    
107
      Enumeration enum = subtrees.keys();
108
      while ( enum.hasMoreElements() ) {
109
        ldapBase = (String)enum.nextElement();
110
        ldapUrl = (String)subtrees.get(ldapBase);
111
System.out.println(ldapUrl + ldapBase); 
112
        String identifier = getIdentifyingName(user,ldapUrl,ldapBase);
113

    
114
        if (identifier != null) {
115
          // Now that we have the dn, we can authenticate, so
116
          // authenticate this time when opening the DirContext
117
          env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
118
//        env.put(Context.SECURITY_PROTOCOL, "ssl");
119
          env.put(Context.SECURITY_AUTHENTICATION, "simple");
120
          env.put(Context.SECURITY_PRINCIPAL, identifier + "," + ldapBase);
121
          env.put(Context.SECURITY_CREDENTIALS, password);
122
          // If our auth credentials are invalid, an exception will be thrown
123
          DirContext ctx = null;
124
          try {
125
            ctx = new InitialDirContext(env);
126
            authenticated = true;
127
            ctx.close();
128
            this.ldapUrl = ldapUrl;
129
            this.ldapBase = ldapBase;
130
            break;
131
          } catch (AuthenticationException ae) {
132
            authenticated = false;
133
            if ( ctx != null ) {
134
              ctx.close();
135
            }
136
          }
137
        } else { 
138
          util.debugMessage("User not found");
139
//System.out.println("NOT FOUND HERE");
140
        }
141
      } /* while ( enum.hasMore() ) */
142

    
143
    } catch (NamingException e) {
144
      util.debugMessage("Naming exception while authenticating in " + 
145
                        "AuthLdap.authenticate: " + e);
146
      throw new ConnectException(
147
      "Naming exception while authenticating in " + 
148
                        "AuthLdap.authenticate: " + e);
149
    } catch (Exception e) {
150
      System.out.println(e.getMessage());
151
    }
152

    
153
    return authenticated;
154
  }
155

    
156
  /**
157
   * Get the identifying name for a given userid or name.  This is the name
158
   * that is used in conjunction withthe LDAP BaseDN to create a
159
   * distinguished name (dn) for the record
160
   *
161
   * @param user the user for which the identifying name is requested
162
   * @returns String the identifying name for the user, 
163
   *          or null if not found
164
   */
165
  private String getIdentifyingName(String user, String ldapUrl, String ldapBase) 
166
         throws NamingException
167
  {
168
    String identifier = null;
169

    
170
    // Identify service provider to use
171
    Hashtable env = new Hashtable(11);
172
    env.put(Context.INITIAL_CONTEXT_FACTORY,
173
            "com.sun.jndi.ldap.LdapCtxFactory");
174
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
175
//    env.put(Context.SECURITY_AUTHENTICATION, "EXTERNAL");
176
//    env.put(Context.SECURITY_PROTOCOL, "ssl");
177

    
178
    try {
179

    
180
      // Bind to the LDAP server, in order to search for the right
181
      // distinguished name (dn) based on userid (uid) or common name (cn)
182
      DirContext ctx = new InitialDirContext(env);
183

    
184
      SearchControls ctls = new SearchControls();
185
      ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
186

    
187
      // Search for the user id or name using the uid, then cn and sn attributes
188
      // If we find a record, determine the dn for the record
189
      util.debugMessage("\nStarting search phase...\n");
190

    
191
      String filter = "(uid=" + user + ")";
192
      NamingEnumeration answer = ctx.search("", filter, ctls);
193
      if (answer.hasMore()) {
194
        SearchResult sr = (SearchResult)answer.next();
195
        identifier = sr.getName();
196
        if ( !sr.isRelative() ) { 
197
          this.ldapUrl = identifier.substring(0,identifier.lastIndexOf("/")+1);
198
          this.ldapBase = identifier.substring(identifier.indexOf(",")+1);
199
          identifier = identifier.substring(identifier.lastIndexOf("/")+1,
200
                                            identifier.indexOf(","));
201
        }
202
        util.debugMessage("Found: " + identifier);
203
      } else {
204
        //Attributes matchAttrs2 = new BasicAttributes(true);
205
        //matchAttrs2.put(new BasicAttribute("cn", user));
206
        //NamingEnumeration answer2 = ctx.search("", matchAttrs2);
207
        filter = "(cn=" + user + ")";
208
        NamingEnumeration answer2 = ctx.search("", filter, ctls);
209
        if (answer2.hasMore()) {
210
          SearchResult sr = (SearchResult)answer2.next();
211
          identifier = sr.getName();
212
          if ( !sr.isRelative() ) { 
213
            this.ldapUrl = identifier.substring(0,identifier.lastIndexOf("/")+1);
214
            this.ldapBase = identifier.substring(identifier.indexOf(",")+1);
215
            identifier = identifier.substring(identifier.lastIndexOf("/")+1,
216
                                              identifier.indexOf(","));
217
          }
218
          util.debugMessage("Found: " + identifier);
219
        } else {
220
          //Attributes matchAttrs3 = new BasicAttributes(true);
221
          //matchAttrs3.put(new BasicAttribute("sn", user));
222
          //NamingEnumeration answer3 = ctx.search("", matchAttrs3);
223
          filter = "(sn=" + user + ")";
224
          NamingEnumeration answer3 = ctx.search("", filter, ctls);
225
          if (answer3.hasMore()) {
226
            SearchResult sr = (SearchResult)answer3.next();
227
            identifier = sr.getName();
228
            if ( !sr.isRelative() ) { 
229
              this.ldapUrl = identifier.substring(0,identifier.lastIndexOf("/")+1);
230
              this.ldapBase = identifier.substring(identifier.indexOf(",")+1);
231
              identifier = identifier.substring(identifier.lastIndexOf("/")+1,
232
                                                identifier.indexOf(","));
233
            }
234
            util.debugMessage("Found: " + identifier);
235
          }
236
        }
237
      }
238
      // Close the context when we're done the initial search
239
      ctx.close();
240
    } catch (NamingException e) {
241
      util.debugMessage("Naming exception while getting dn: " + e);
242
      throw new NamingException(
243
      "Naming exception in AuthLdap.getIdentifyingName: " + e);
244
    }
245
    
246
//System.out.println("context: " + identifier);
247
    return identifier;
248
  }
249

    
250
  /**
251
   * Get all users from the authentication service
252
   */
253
  public String[] getUsers(String user, String password) 
254
         throws ConnectException
255
  {
256
    String[] users = null;
257

    
258
    // Identify service provider to use
259
    Hashtable env = new Hashtable(11);
260
    env.put(Context.INITIAL_CONTEXT_FACTORY, 
261
            "com.sun.jndi.ldap.LdapCtxFactory");
262
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
263

    
264
    try {
265

    
266
      //// Get the dn for this uid or cn 
267
      //String identifier = getIdentifyingName(user);
268
      //if (identifier != null) {
269
      //  env.put(Context.SECURITY_AUTHENTICATION, "simple");
270
      //  env.put(Context.SECURITY_PRINCIPAL, identifier + "," + ldapBase);
271
      //  env.put(Context.SECURITY_CREDENTIALS, password);
272

    
273
        // Create the initial directory context
274
        DirContext ctx = new InitialDirContext(env);
275

    
276
        // Specify the ids of the attributes to return
277
        String[] attrIDs = {"uid"};
278

    
279
        // Specify the attributes to match.
280
        // Users are objects that have the attribute objectclass=InetOrgPerson.
281
        Attributes matchAttrs = new BasicAttributes(true); // ignore case
282
        matchAttrs.put(new BasicAttribute("objectclass", "inetOrgPerson"));
283

    
284
        // Search for objects in the current context
285
        NamingEnumeration enum = ctx.search("", matchAttrs, attrIDs);
286

    
287
        // Print the users
288
        Vector uvec = new Vector();
289
        while (enum.hasMore()) {
290
          SearchResult sr = (SearchResult)enum.next();
291
          Attributes attrs = sr.getAttributes();
292
          NamingEnumeration enum1 = attrs.getAll(); // only "uid" attr
293
          while (enum1.hasMore()) {
294
            Attribute attr = (Attribute)enum1.next();
295
            uvec.add(attr.get());
296
          }
297
        }
298

    
299
        // initialize users[]; fill users[]
300
        users = new String[uvec.size()];
301
        for (int i=0; i < uvec.size(); i++) {
302
          users[i] = (String)uvec.elementAt(i); 
303
        }
304

    
305
        // Close the context when we're done
306
        ctx.close();
307
      //} else {
308
      //  util.debugMessage("User not found!");
309
      //}
310

    
311
    } catch (NamingException e) {
312
      System.err.println("Problem getting users in AuthLdap.getUsers:" + e);
313
      throw new ConnectException(
314
      "Problem getting users in AuthLdap.getUsers:" + e);
315
    }
316

    
317
    return users;
318
  }
319

    
320
  /**
321
   * Get the users for a particular group from the authentication service
322
   */
323
  public String[] getUsers(String user, String password, String group) 
324
         throws ConnectException
325
  {
326
    String[] users = null;
327

    
328
    // Identify service provider to use
329
    Hashtable env = new Hashtable(11);
330
    env.put(Context.INITIAL_CONTEXT_FACTORY, 
331
            "com.sun.jndi.ldap.LdapCtxFactory");
332
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
333

    
334
    try {
335

    
336
      //// Get the dn for this uid or cn 
337
      //String identifier = getIdentifyingName(user);
338
      //if (identifier != null) {
339
      //  env.put(Context.SECURITY_AUTHENTICATION, "simple");
340
      //  env.put(Context.SECURITY_PRINCIPAL, identifier + "," + ldapBase);
341
      //  env.put(Context.SECURITY_CREDENTIALS, password);
342

    
343
        // Create the initial directory context
344
        DirContext ctx = new InitialDirContext(env);
345

    
346
        // Specify the ids of the attributes to return
347
        String[] attrIDs = {"uniquemember"};
348

    
349
        // Specify the attributes to match.
350
        // Groups are objects with attribute objectclass=groupofuniquenames.
351
        Attributes matchAttrs = new BasicAttributes(true); // ignore case
352
        matchAttrs.put(new BasicAttribute("objectclass", "groupofuniquenames"));
353
        matchAttrs.put(new BasicAttribute("cn", group));
354

    
355
        // Search for objects in the current context
356
        NamingEnumeration enum = ctx.search("", matchAttrs, attrIDs);
357

    
358
        // Print the users
359
        Vector uvec = new Vector();
360
        while (enum.hasMore()) {
361
          SearchResult sr = (SearchResult)enum.next();
362
          Attributes attrs = sr.getAttributes();
363
          // return all attributes (only "uniquemember" attr)
364
          NamingEnumeration enum1 = attrs.getAll();
365
          while (enum1.hasMore()) {
366
            Attribute attr = (Attribute)enum1.next();
367
            // return all values of that attribute
368
            NamingEnumeration enum2 = attr.getAll();
369
            while (enum2.hasMore()) {
370
              // get DN of a member
371
              String memberDN = (String)enum2.next();
372
              try {
373
                // we actually need RDN of the member
374
                // try to get RDN (UID) of the member in case of a user
375
                String memberID = getUserID(memberDN);
376
                if ( memberID != null ) {
377
                  uvec.add(memberID);
378
                // CURRENTLY WE DON'T SUPPORT SUBGROUPING, THUS
379
                // IGNORE SUBGROUPS AS MEMBERS OF THE GROUP
380
                // // this is a group, not user
381
                // // try to get RDN (CN) of the group
382
                // } else {
383
                //   memberID = getGroupID(memberDN);
384
                //   uvec.add(memberID);
385
                }
386
              } catch (NamingException ne) {}
387
            }
388
          }
389
        }
390

    
391
        // initialize users[]; fill users[]
392
        users = new String[uvec.size()];
393
        for (int i=0; i < uvec.size(); i++) {
394
          users[i] = (String)uvec.elementAt(i); 
395
        }
396

    
397
        // Close the context when we're done
398
        ctx.close();
399
      //} else {
400
      //  util.debugMessage("User not found!");
401
      //}
402

    
403
    } catch (NamingException e) {
404
      System.err.println("Problem getting users for a group in AuthLdap.getUsers:" + e);
405
      throw new ConnectException(
406
      "Problem getting users for a group in AuthLdap.getUsers:" + e);
407
    }
408

    
409
    return users;
410
  }
411

    
412
  /**
413
   * Get UID by DN of a member
414
   */
415
  private String getUserID(String dn) 
416
         throws NamingException
417
  {
418
    String[] users = null;
419

    
420
    // Identify service provider to use
421
    Hashtable env = new Hashtable(11);
422
    env.put(Context.INITIAL_CONTEXT_FACTORY, 
423
            "com.sun.jndi.ldap.LdapCtxFactory");
424
    env.put(Context.PROVIDER_URL, ldapUrl); // + ldapBase);
425

    
426
    try {
427

    
428
        // Create the initial directory context
429
        DirContext ctx = new InitialDirContext(env);
430

    
431
        // Specify the ids of the attributes to return
432
        String[] attrIDs = {"uid"};
433

    
434
        // Ask for "uid" attributes of the user 
435
        Attributes attrs = ctx.getAttributes(dn, attrIDs);
436

    
437
        // Print all of the attributes (only "uid" attr)
438
        Vector uvec = new Vector();
439
        NamingEnumeration en = attrs.getAll();
440
        while (en.hasMore()) {
441
          Attribute att = (Attribute)en.next();
442
          Vector values = new Vector();
443
          String attName = att.getID();
444
          NamingEnumeration attvalues = att.getAll();
445
          while (attvalues.hasMore()) {
446
            String value = (String)attvalues.next();
447
            values.add(value);
448
          }
449
          uvec.add(values.elementAt(0));
450
        }
451

    
452
        // initialize users[]; fill users[]
453
        users = new String[uvec.size()];
454
        for (int i=0; i < uvec.size(); i++) {
455
          users[i] = (String)uvec.elementAt(i); 
456
        }
457

    
458
        // Close the context when we're done
459
        ctx.close();
460

    
461
    } catch (NamingException ne) {
462
      System.err.println("Problem getting userID by \"dn\" in AuthLdap.getUserID:" + ne);
463
      throw ne;
464
    }
465

    
466
    if ( users.length > 0 ) {
467
      return users[0];
468
    }
469
    return null;
470
  }
471

    
472
  /**
473
   * Get CN by DN of a member
474
   */
475
  private String getGroupID(String dn) 
476
         throws NamingException
477
  {
478
    String[] groups = null;
479

    
480
    // Identify service provider to use
481
    Hashtable env = new Hashtable(11);
482
    env.put(Context.INITIAL_CONTEXT_FACTORY, 
483
            "com.sun.jndi.ldap.LdapCtxFactory");
484
    env.put(Context.PROVIDER_URL, ldapUrl); // + ldapBase);
485

    
486
    try {
487

    
488
        // Create the initial directory context
489
        DirContext ctx = new InitialDirContext(env);
490

    
491
        // Specify the ids of the attributes to return
492
        String[] attrIDs = {"cn"};
493

    
494
        // Ask for "uid" attributes of the user 
495
        Attributes attrs = ctx.getAttributes(dn, attrIDs);
496

    
497
        // Print all of the attributes (only "cn" attr)
498
        Vector uvec = new Vector();
499
        NamingEnumeration en = attrs.getAll();
500
        while (en.hasMore()) {
501
          Attribute att = (Attribute)en.next();
502
          Vector values = new Vector();
503
          String attName = att.getID();
504
          NamingEnumeration attvalues = att.getAll();
505
          while (attvalues.hasMore()) {
506
            String value = (String)attvalues.next();
507
            values.add(value);
508
          }
509
          uvec.add(values.elementAt(0));
510
        }
511

    
512
        // initialize users[]; fill users[]
513
        groups = new String[uvec.size()];
514
        for (int i=0; i < uvec.size(); i++) {
515
          groups[i] = (String)uvec.elementAt(i); 
516
        }
517

    
518
        // Close the context when we're done
519
        ctx.close();
520

    
521
    } catch (NamingException ne) {
522
      System.err.println("Problem getting groupID by \"dn\" in AuthLdap.getGroupID:" + ne);
523
      throw ne;
524
    }
525

    
526
    if ( groups.length > 0 ) {
527
      return groups[0];
528
    }
529
    return null;
530
  }
531

    
532
  /**
533
   * Get all groups from the authentication service
534
   */
535
  public String[] getGroups(String user, String password) 
536
         throws ConnectException
537
  {
538
    String[] groups = null;
539

    
540
    // Identify service provider to use
541
    Hashtable env = new Hashtable(11);
542
    env.put(Context.INITIAL_CONTEXT_FACTORY, 
543
            "com.sun.jndi.ldap.LdapCtxFactory");
544
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
545

    
546
    try {
547

    
548
      //// Get the dn for this uid or cn 
549
      //String identifier = getIdentifyingName(user);
550
      //if (identifier != null) {
551
      //  env.put(Context.SECURITY_AUTHENTICATION, "simple");
552
      //  env.put(Context.SECURITY_PRINCIPAL, identifier + "," + ldapBase);
553
      //  env.put(Context.SECURITY_CREDENTIALS, password);
554

    
555
        // Create the initial directory context
556
        DirContext ctx = new InitialDirContext(env);
557

    
558
        // Specify the ids of the attributes to return
559
        String[] attrIDs = {"cn"};
560

    
561
        // Specify the attributes to match.
562
        // Groups are objects with attribute objectclass=groupofuniquenames.
563
        Attributes matchAttrs = new BasicAttributes(true); // ignore case
564
        matchAttrs.put(new BasicAttribute("objectclass", "groupofuniquenames"));
565

    
566
        // Search for objects in the current context
567
        NamingEnumeration enum = ctx.search("", matchAttrs, attrIDs);
568

    
569
        // Print the users
570
        Vector uvec = new Vector();
571
        while (enum.hasMore()) {
572
          SearchResult sr = (SearchResult)enum.next();
573
          Attributes attrs = sr.getAttributes();
574
          NamingEnumeration enum1 = attrs.getAll(); // only "cn" attr
575
          while (enum1.hasMore()) {
576
            Attribute attr = (Attribute)enum1.next();
577
            uvec.add(attr.get());
578
          }
579
        }
580

    
581
        // initialize groups[] and fill it
582
        groups = new String[uvec.size()];
583
        for (int i=0; i < uvec.size(); i++) {
584
          groups[i] = (String)uvec.elementAt(i); 
585
        }
586

    
587
        // Close the context when we're done
588
        ctx.close();
589
      //} else {
590
      //  util.debugMessage("User not found!");
591
      //}
592

    
593
    } catch (NamingException e) {
594
      System.err.println("Problem getting groups in AuthLdap.getGroups:" + e);
595
      throw new ConnectException(
596
      "Problem getting groups in AuthLdap.getGroups:" + e);
597
    }
598

    
599
    return groups;
600
  }
601

    
602
  /**
603
   * Get the groups for a particular user from the authentication service
604
   */
605
  public String[] getGroups(String user, String password, String foruser) 
606
         throws ConnectException
607
  {
608
    String[] groups = null;
609

    
610
    // Identify service provider to use
611
    Hashtable env = new Hashtable(11);
612
    env.put(Context.INITIAL_CONTEXT_FACTORY, 
613
            "com.sun.jndi.ldap.LdapCtxFactory");
614
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
615

    
616
    try {
617

    
618
      //// Get the dn for this uid or cn 
619
      //String identifier = getIdentifyingName(user);
620
      //if (identifier != null) {
621
      //  env.put(Context.SECURITY_AUTHENTICATION, "simple");
622
      //  env.put(Context.SECURITY_PRINCIPAL, identifier + "," + ldapBase);
623
      //  env.put(Context.SECURITY_CREDENTIALS, password);
624

    
625
        // Create the initial directory context
626
        DirContext ctx = new InitialDirContext(env);
627

    
628
        // Specify the ids of the attributes to return
629
        String[] attrIDs = {"cn"};
630

    
631
        // Specify the attributes to match.
632
        // Groups are objects with attribute objectclass=groupofuniquenames.
633
        // and have attribute uniquemember=foruser,ldapbase.
634
        Attributes matchAttrs = new BasicAttributes(true); // ignore case
635
        matchAttrs.put(new BasicAttribute("objectclass", "groupofuniquenames"));
636
        matchAttrs.put(new BasicAttribute("uniquemember",foruser+","+ldapBase));
637

    
638
        // Search for objects in the current context
639
        NamingEnumeration enum = ctx.search("", matchAttrs, attrIDs);
640

    
641
        // Print the users
642
        Vector uvec = new Vector();
643
        while (enum.hasMore()) {
644
          SearchResult sr = (SearchResult)enum.next();
645
          Attributes attrs = sr.getAttributes();
646
          NamingEnumeration enum1 = attrs.getAll(); // only "cn" attr
647
          while (enum1.hasMore()) {
648
            Attribute attr = (Attribute)enum1.next();
649
            uvec.add(attr.get());
650
          }
651
        }
652

    
653
        // initialize groups[] and fill it
654
        groups = new String[uvec.size()];
655
        for (int i=0; i < uvec.size(); i++) {
656
          groups[i] = (String)uvec.elementAt(i); 
657
        }
658

    
659
        // Close the context when we're done
660
        ctx.close();
661
      //} else {
662
      //  util.debugMessage("User not found!");
663
      //}
664

    
665
    } catch (NamingException e) {
666
      System.err.println("Problem getting groups in AuthLdap.getGroups:" + e);
667
      throw new ConnectException(
668
      "Problem getting groups for a user in AuthLdap.getGroups:" + e);
669
    }
670

    
671
    return groups;
672
  }
673

    
674
  /**
675
   * Get attributes describing a user or group
676
   *
677
   * @param user the user for which the attribute list is requested
678
   * @returns HashMap a map of attribute name to a Vector of values
679
   */
680
  public HashMap getAttributes(String foruser) 
681
         throws ConnectException
682
  {
683
    return getAttributes(null, null, foruser);
684
  }
685

    
686
  /**
687
   * Get attributes describing a user or group
688
   *
689
   * @param user the user for which the attribute list is requested
690
   * @param authuser the user for authenticating against the service
691
   * @param password the password for authenticating against the service
692
   * @returns HashMap a map of attribute name to a Vector of values
693
   */
694
  public HashMap getAttributes(String user, String password, String foruser) 
695
         throws ConnectException
696
  {
697
    HashMap attributes = new HashMap();
698

    
699
    // Identify service provider to use
700
    Hashtable env = new Hashtable(11);
701
    env.put(Context.INITIAL_CONTEXT_FACTORY, 
702
        "com.sun.jndi.ldap.LdapCtxFactory");
703
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
704

    
705
    // Authentication information
706
 
707
    try {
708
  
709
      if ((user != null) && (password != null)) {
710
        String identifier = getIdentifyingName(user,this.ldapUrl,this.ldapBase);
711
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
712
        env.put(Context.SECURITY_PRINCIPAL, identifier + "," + ldapBase);
713
        env.put(Context.SECURITY_CREDENTIALS, password);
714
      }
715

    
716
      // Create the initial directory context
717
      DirContext ctx = new InitialDirContext(env);
718
        
719
      // Find out the identifying attribute for the user
720
      String userident = getIdentifyingName(foruser,this.ldapUrl,this.ldapBase);
721

    
722
      // Ask for all attributes of the user 
723
      Attributes attrs = ctx.getAttributes(userident);
724
 
725
      // Print all of the attributes
726
      NamingEnumeration en = attrs.getAll();
727
      while (en.hasMore()) {
728
        Attribute att = (Attribute)en.next();
729
        Vector values = new Vector();
730
        String attName = att.getID();
731
        NamingEnumeration attvalues = att.getAll();
732
        while (attvalues.hasMore()) {
733
          String value = (String)attvalues.next();
734
          values.add(value);
735
        }
736
        attributes.put(attName, values);
737
      }
738
  
739
      // Close the context when we're done
740
      ctx.close();
741
    } catch (NamingException e) {
742
      System.err.println("Problem getting attributes in AuthLdap.getAttributes:" 
743
                          + e);
744
      throw new ConnectException(
745
      "Problem getting attributes in AuthLdap.getAttributes:" + e);
746
    }
747

    
748
    return attributes;
749
  }
750

    
751
  /**
752
   * Get list of all subtrees holding Metacat's groups and users
753
   * starting from the Metacat LDAP root, 
754
   * i.e. ldap://dev.nceas.ucsb.edu/dc=ecoinformatics,dc=org
755
   */
756
  private Hashtable getSubtrees(String user, String password,
757
                                String ldapUrl, String ldapBase)
758
                throws ConnectException
759
  {
760
    Hashtable trees = new Hashtable();
761

    
762
    // Identify service provider to use
763
    Hashtable env = new Hashtable(11);
764
    env.put(Context.INITIAL_CONTEXT_FACTORY, 
765
            "com.sun.jndi.ldap.LdapCtxFactory");
766
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
767

    
768
    try {
769

    
770
      //if ( this.authenticate(user, password) ) {
771

    
772
        // Create the initial directory context
773
        DirContext ctx = new InitialDirContext(env);
774

    
775
        // Specify the ids of the attributes to return
776
        String[] attrIDs = {"o","ref"};
777
        SearchControls ctls = new SearchControls();
778
        ctls.setReturningAttributes(attrIDs);
779
        ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
780
          
781
        // Specify the attributes to match.
782
        // Subtrees from the main server are found as objects with attribute
783
        // objectclass=organization or objectclass=referral to the subtree
784
        // resided on other server.
785
        String filter = "(|(objectclass=organization)(objectclass=referral))";
786

    
787
        // Search for objects in the current context
788
        NamingEnumeration enum = ctx.search("", filter, ctls);
789

    
790
        // Print the subtrees' <ldapURL, baseDN>
791
        while (enum.hasMore()) {
792
          SearchResult sr = (SearchResult)enum.next();
793
          Attributes attrs = sr.getAttributes();
794
          NamingEnumeration enum1 = attrs.getAll(); // "dc" and "ref" attrs
795
          if (enum1.hasMore()) {
796
            Attribute attr = (Attribute)enum1.next();
797
            String attrValue = (String)attr.get();
798
            String attrName = (String)attr.getID();
799
 //System.out.println(attrName + "=" + attrValue);
800
            if ( enum1.hasMore() ) {
801
              attr = (Attribute)enum1.next();
802
              String refValue = (String)attr.get();
803
              String refName = (String)attr.getID();
804
 //System.out.println(refName + "=" + refValue);
805
              if ( ldapBase.startsWith(refName + "=" + refValue) ) {
806
                trees.put(ldapBase,
807
                          attrValue.substring(0,attrValue.lastIndexOf("/")+1) );
808
              } else {
809
                trees.put(refName + "=" + refValue + "," + ldapBase,
810
                          attrValue.substring(0,attrValue.lastIndexOf("/")+1) );
811
              }
812
 //System.out.println("REFERRAL:" + attrValue);
813
            } else if ( ldapBase.startsWith(attrName + "=" + attrValue) ) {
814
                trees.put(ldapBase, ldapUrl);
815
            } else {              
816
                trees.put(attrName + "=" + attrValue + "," + ldapBase, ldapUrl);
817
 //System.out.println(ldapUrl + attrName + "=" + attrValue + "," + ldapBase);
818
            }
819
          }
820
        }
821

    
822
        // Close the context when we're done
823
        ctx.close();
824
      //} else {
825
      //  System.out.println("Not authenticated user: " + user + "@" + ldapUrl + ldapBase);
826
      //}
827

    
828
    } catch (NamingException e) {
829
      System.err.println("Problem getting subtrees in AuthLdap.getSubtrees:" + e);
830
      throw new ConnectException(
831
      "Problem getting subtrees in AuthLdap.getSubtrees:" + e);
832
    }
833

    
834
//System.out.println("number of subtrees:" + trees.size());
835
    return trees;
836
  }
837

    
838
  /**
839
   * Get all groups and users from authentication scheme.
840
   * The output is formatted in XML.
841
   * @param user the user which requests the information
842
   * @param password the user's password
843
   */
844
  public String getPrincipals(String user, String password)
845
                throws ConnectException
846
  {
847
    StringBuffer out = new StringBuffer();
848
    Vector usersIn = new Vector();
849
    
850
    //String ldapUrl = "ldap://dev.nceas.ucsb.edu/";
851
    //String ldapBase = "dc=ecoinformatics,dc=org";
852
    //String ldapUrl = "ldap://ldap.nceas.ucsb.edu/";
853
    //String ldapBase = "o=NCEAS,c=US";
854

    
855
    out.append("<?xml version=\"1.0\"?>\n");
856
    out.append("<principals>\n");
857
    
858
    /*
859
     * get all subtrees first in the current dir context 
860
     * and then the Metacat users under them
861
     */
862
    Hashtable subtrees = getSubtrees(user,password,this.ldapUrl,this.ldapBase);
863
    
864
    Enumeration enum = subtrees.keys();
865
    while ( enum.hasMoreElements() ) {
866
      this.ldapBase = (String)enum.nextElement();
867
      this.ldapUrl = (String)subtrees.get(ldapBase);
868
      
869
      out.append("  <authSystem URI=\"" + 
870
                 this.ldapUrl + this.ldapBase + "\">\n");
871

    
872
      // get all groups for directory context
873
      String[] groups = getGroups(user, password);
874

    
875
      // for the groups and users that belong to them
876
      if ( groups.length > 0 ) {
877
        for (int i=0; i < groups.length; i++ ) {
878
          out.append("    <group>\n");
879
          out.append("      <groupname>" + groups[i] + "<groupname>\n");
880
          String[] usersForGroup = getUsers(user,password,groups[i]);
881
          for (int j=0; j < usersForGroup.length; j++ ) {
882
            usersIn.addElement(usersForGroup[j]);
883
            out.append("      <user>\n");
884
            out.append("        <username>" + usersForGroup[j] + "<username>\n");
885
            out.append("      </user>\n");
886
          }
887
          out.append("    </group>\n");
888
        }
889
      }
890
      // for the users not belonging to any group
891
      String[] users = getUsers(user, password);
892
      for (int j=0; j < users.length; j++ ) {
893
        if ( !usersIn.contains(users[j]) ) {
894
          out.append("    <user>\n");
895
          out.append("      <username>" + users[j] + "<username>\n");
896
          out.append("    </user>\n");
897
        }
898
      }
899
    
900
      out.append("  </authSystem>\n");
901
      if ( !usersIn.isEmpty() ) {
902
        usersIn.removeAllElements();
903
        usersIn.trimToSize();
904
      }
905
    
906
    }
907
    out.append("</principals>");
908
    return out.toString();
909
  }
910

    
911
  /**
912
   * Test method for the class
913
   */
914
  public static void main(String[] args) {
915

    
916
    // Provide a user, such as: "Matt Jones", or "jones"
917
    String user = args[0];
918
    String password = args[1];
919

    
920
    AuthLdap authservice = new AuthLdap();
921

    
922
    boolean isValid = false;
923
    try {
924
      isValid = authservice.authenticate(user, password);
925
      if (isValid) {
926
        System.out.println("Authentication successful for: " + user );
927
        System.out.println(" ");
928
        
929
      } else {
930
        System.out.println("Authentication failed for: " + user);
931
      }
932

    
933
      if (isValid) {
934
        //String group = args[2];
935
        HashMap userInfo = authservice.getAttributes(user, password, user);
936
        // Print all of the attributes
937
        Iterator attList = (Iterator)(((Set)userInfo.keySet()).iterator());
938
        while (attList.hasNext()) {
939
          String att = (String)attList.next();
940
          Vector values = (Vector)userInfo.get(att);
941
          Iterator attvalues = values.iterator();
942
          while (attvalues.hasNext()) {
943
            String value = (String)attvalues.next();
944
          //  System.out.println(att + ": " + value);
945
          }
946
        }
947

    
948
      }
949

    
950
/*
951
      // get the whole list of users
952
      if (isValid) {
953
        String[] users = authservice.getUsers(user, password);
954
        for (int i=0; i < users.length; i++) {
955
          System.out.println(users[i]);          
956
        }
957
        System.out.println("Total " + users.length + " users.");
958
      }
959
*/
960
/*
961
      // get the whole list of users for a group
962
      if (isValid) {
963
        String group = args[2];
964
        String[] users = authservice.getUsers(user, password, group);
965
        for (int i=0; i < users.length; i++) {
966
          System.out.println(users[i]);          
967
        }
968
      }
969
*/
970
      // get the whole list groups and users in XML format
971
      if (isValid) {
972
        authservice = new AuthLdap();
973
        String out = authservice.getPrincipals(user, password);
974
        java.io.File f = new java.io.File("principals.txt");
975
        java.io.FileWriter fw = new java.io.FileWriter(f);
976
        java.io.BufferedWriter buff = new java.io.BufferedWriter(fw);
977
        buff.write(out);
978
        buff.flush();
979
        buff.close();
980
        fw.close();
981
      }
982

    
983
    } catch (ConnectException ce) {
984
      System.err.println(ce.getMessage());
985
    } catch (java.io.IOException ioe) {
986
      System.err.println("I/O Error writing to file principals.txt");
987
    }
988
  }
989
}
(6-6/43)