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-07-05 09:38:34 -0700 (Thu, 05 Jul 2001) $'
13
 * '$Revision: 788 $'
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.NamingEnumeration;
37
import javax.naming.NamingException;
38
import javax.naming.InitialContext;
39
import javax.naming.directory.Attribute;
40
import javax.naming.directory.Attributes;
41
import javax.naming.directory.BasicAttribute;
42
import javax.naming.directory.BasicAttributes;
43
import javax.naming.directory.DirContext;
44
import javax.naming.directory.InitialDirContext;
45
import javax.naming.directory.SearchResult;
46
import javax.naming.directory.SearchControls;
47
import javax.naming.ldap.*;
48
import java.util.Iterator;
49
import java.util.HashMap;
50
import java.util.Hashtable;
51
import java.util.Enumeration;
52
import java.util.Set;
53
import java.util.Vector;
54

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

    
68
  /** 
69
   * Construct an AuthLdap
70
   */
71
  public AuthLdap() {
72

    
73
    // Read LDAP URI for directory service information
74
    this.ldapUrl = MetaCatUtil.getOption("ldapurl");
75
    this.ldapsUrl = MetaCatUtil.getOption("ldapsurl");
76
    this.ldapBase = MetaCatUtil.getOption("ldapbase");
77
    //this.ldapUrl = "ldap://dev.nceas.ucsb.edu:636/";
78
    //this.ldapBase = "o=NCEAS,dc=ecoinformatics,dc=org";
79
  }
80

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

    
102
    try {
103

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

    
116
        if (identifier != null && !password.equals("")) {
117
          // Now that we have the dn, we can authenticate, so
118
          // authenticate this time when opening the DirContext
119
System.out.println(ldapsUrl + identifier + "," + ldapBase); 
120
          env.put(Context.PROVIDER_URL, ldapsUrl + ldapBase);
121
          if ( !ldapsUrl.equals(ldapUrl) ) {
122
            // ldap is set on default port 389
123
            // ldaps is set on second port - 636 by default
124
            env.put(Context.SECURITY_PROTOCOL, "ssl");
125
          }
126
          env.put(Context.SECURITY_AUTHENTICATION, "simple");
127
          env.put(Context.SECURITY_PRINCIPAL, identifier + "," + ldapBase);
128
          env.put(Context.SECURITY_CREDENTIALS, password);
129
          // If our auth credentials are invalid, an exception will be thrown
130
          DirContext ctx = null;
131
          try {
132
            double startTime = System.currentTimeMillis();
133
            ctx = new InitialDirContext(env);
134
//            // StartTLS support from LDAPv3 with X.509 cert and with JSDKv1.4+
135
//            LdapContext ctx = new InitialLdapContext(env, null);
136
//            StartTlsResponse tls =
137
//              (StartTlsResponse)ctx.extendedOperation(new StartTlsRequest());
138
//            tls.negotiate();
139

    
140
            double stopTime = System.currentTimeMillis();
141
            System.out.println("Connection time thru " + ldapsUrl + " was: " +
142
                               (stopTime-startTime)/1000 + " seconds.");
143
            authenticated = true;
144
//            tls.close();
145
            ctx.close();
146
            this.ldapUrl = ldapUrl;
147
            this.ldapBase = ldapBase;
148
         //   break;
149
          } catch (AuthenticationException ae) {
150
            authenticated = false;
151
//            if ( tls != null ) {
152
//              tls.close();
153
//            }
154
            if ( ctx != null ) {
155
              ctx.close();
156
            }
157
          }
158
        } else { 
159
          util.debugMessage("User not found");
160
        }
161
//      } /* while ( enum.hasMore() ) */
162

    
163
    } catch (NullPointerException e) {
164
      util.debugMessage("NullPointerException b' password is null");
165
      util.debugMessage("NullPointerException while authenticating in " + 
166
                        "AuthLdap.authenticate: " + e);
167
      throw new ConnectException(
168
      "NullPointerException while authenticating in " + 
169
                        "AuthLdap.authenticate: " + e);
170
    } catch (NamingException e) {
171
      util.debugMessage("Naming exception while authenticating in " + 
172
                        "AuthLdap.authenticate: " + e);
173
      //throw new ConnectException(
174
      //"Naming exception while authenticating in " + 
175
      //                  "AuthLdap.authenticate: " + e);
176
       e.printStackTrace();
177
    } catch (Exception e) {
178
      System.out.println(e.getMessage());
179
    }
180

    
181
    return authenticated;
182
  }
183

    
184
  /**
185
   * Get the identifying name for a given userid or name.  This is the name
186
   * that is used in conjunction withthe LDAP BaseDN to create a
187
   * distinguished name (dn) for the record
188
   *
189
   * @param user the user for which the identifying name is requested
190
   * @returns String the identifying name for the user, 
191
   *          or null if not found
192
   */
193
  private String getIdentifyingName(String user, String ldapUrl, String ldapBase) 
194
         throws NamingException
195
  {
196
    String identifier = null;
197

    
198
    // Identify service provider to use
199
    Hashtable env = new Hashtable(11);
200
    env.put(Context.INITIAL_CONTEXT_FACTORY,
201
            "com.sun.jndi.ldap.LdapCtxFactory");
202
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
203
//    non-secure LDAP context; dn are publicly readable
204
//    env.put(Context.SECURITY_PROTOCOL, "ssl");
205

    
206
    try {
207

    
208
      // Bind to the LDAP server, in order to search for the right
209
      // distinguished name (dn) based on userid (uid) or common name (cn)
210
      DirContext ctx = new InitialDirContext(env);
211

    
212
      SearchControls ctls = new SearchControls();
213
      ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
214

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

    
219
      String filter = "(uid=" + user + ")";
220
      NamingEnumeration answer = ctx.search("", filter, ctls);
221
      if (answer.hasMore()) {
222
        SearchResult sr = (SearchResult)answer.next();
223
        identifier = sr.getName();
224
        if ( !sr.isRelative() ) { 
225
          this.ldapUrl = identifier.substring(0,identifier.lastIndexOf("/")+1);
226
          this.ldapBase = identifier.substring(identifier.indexOf(",")+1);
227
          identifier = identifier.substring(identifier.lastIndexOf("/")+1,
228
                                            identifier.indexOf(","));
229
        }
230
        util.debugMessage("Found: " + identifier);
231
      } else {
232
        //Attributes matchAttrs2 = new BasicAttributes(true);
233
        //matchAttrs2.put(new BasicAttribute("cn", user));
234
        //NamingEnumeration answer2 = ctx.search("", matchAttrs2);
235
        filter = "(cn=" + user + ")";
236
        NamingEnumeration answer2 = ctx.search("", filter, ctls);
237
        if (answer2.hasMore()) {
238
          SearchResult sr = (SearchResult)answer2.next();
239
          identifier = sr.getName();
240
          if ( !sr.isRelative() ) { 
241
            this.ldapUrl = identifier.substring(0,identifier.lastIndexOf("/")+1);
242
            this.ldapBase = identifier.substring(identifier.indexOf(",")+1);
243
            identifier = identifier.substring(identifier.lastIndexOf("/")+1,
244
                                              identifier.indexOf(","));
245
          }
246
          util.debugMessage("Found: " + identifier);
247
        } else {
248
          //Attributes matchAttrs3 = new BasicAttributes(true);
249
          //matchAttrs3.put(new BasicAttribute("sn", user));
250
          //NamingEnumeration answer3 = ctx.search("", matchAttrs3);
251
          filter = "(sn=" + user + ")";
252
          NamingEnumeration answer3 = ctx.search("", filter, ctls);
253
          if (answer3.hasMore()) {
254
            SearchResult sr = (SearchResult)answer3.next();
255
            identifier = sr.getName();
256
            if ( !sr.isRelative() ) { 
257
              this.ldapUrl = identifier.substring(0,identifier.lastIndexOf("/")+1);
258
              this.ldapBase = identifier.substring(identifier.indexOf(",")+1);
259
              identifier = identifier.substring(identifier.lastIndexOf("/")+1,
260
                                                identifier.indexOf(","));
261
            }
262
            util.debugMessage("Found: " + identifier);
263
          }
264
        }
265
      }
266
      // Close the context when we're done the initial search
267
      ctx.close();
268
    } catch (NamingException e) {
269
      util.debugMessage("Naming exception while getting dn: " + e);
270
      throw new NamingException(
271
      "Naming exception in AuthLdap.getIdentifyingName: " + e);
272
    }
273
    
274
//System.out.println("context: " + identifier);
275
    return identifier;
276
  }
277

    
278
  /**
279
   * Get all users from the authentication service
280
   */
281
  public String[] getUsers(String user, String password) 
282
         throws ConnectException
283
  {
284
    String[] users = null;
285

    
286
    // Identify service provider to use
287
    Hashtable env = new Hashtable(11);
288
    env.put(Context.INITIAL_CONTEXT_FACTORY, 
289
            "com.sun.jndi.ldap.LdapCtxFactory");
290
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
291

    
292
    try {
293

    
294
        // Create the initial directory context
295
        DirContext ctx = new InitialDirContext(env);
296

    
297
        // Specify the ids of the attributes to return
298
        String[] attrIDs = {"uid"};
299

    
300
        // Specify the attributes to match.
301
        // Users are objects that have the attribute objectclass=InetOrgPerson.
302
        Attributes matchAttrs = new BasicAttributes(true); // ignore case
303
        matchAttrs.put(new BasicAttribute("objectclass", "inetOrgPerson"));
304

    
305
        // Search for objects in the current context
306
        NamingEnumeration enum = ctx.search("", matchAttrs, attrIDs);
307

    
308
        // Print the users
309
        Vector uvec = new Vector();
310
        while (enum.hasMore()) {
311
          SearchResult sr = (SearchResult)enum.next();
312
          Attributes attrs = sr.getAttributes();
313
          NamingEnumeration enum1 = attrs.getAll(); // only "uid" attr
314
          while (enum1.hasMore()) {
315
            Attribute attr = (Attribute)enum1.next();
316
            uvec.add(attr.get());
317
          }
318
        }
319

    
320
        // initialize users[]; fill users[]
321
        users = new String[uvec.size()];
322
        for (int i=0; i < uvec.size(); i++) {
323
          users[i] = (String)uvec.elementAt(i); 
324
        }
325

    
326
        // Close the context when we're done
327
        ctx.close();
328

    
329
    } catch (NamingException e) {
330
      System.err.println("Problem getting users in AuthLdap.getUsers:" + e);
331
      throw new ConnectException(
332
      "Problem getting users in AuthLdap.getUsers:" + e);
333
    }
334

    
335
    return users;
336
  }
337

    
338
  /**
339
   * Get the users for a particular group from the authentication service
340
   */
341
  public String[] getUsers(String user, String password, String group) 
342
         throws ConnectException
343
  {
344
    String[] users = null;
345

    
346
    // Identify service provider to use
347
    Hashtable env = new Hashtable(11);
348
    env.put(Context.INITIAL_CONTEXT_FACTORY, 
349
            "com.sun.jndi.ldap.LdapCtxFactory");
350
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
351

    
352
    try {
353

    
354
        // Create the initial directory context
355
        DirContext ctx = new InitialDirContext(env);
356

    
357
        // Specify the ids of the attributes to return
358
        String[] attrIDs = {"uniquemember"};
359

    
360
        // Specify the attributes to match.
361
        // Groups are objects with attribute objectclass=groupofuniquenames.
362
        Attributes matchAttrs = new BasicAttributes(true); // ignore case
363
        matchAttrs.put(new BasicAttribute("objectclass", "groupofuniquenames"));
364
        matchAttrs.put(new BasicAttribute("cn", group));
365

    
366
        // Search for objects in the current context
367
        NamingEnumeration enum = ctx.search("", matchAttrs, attrIDs);
368

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

    
402
        // initialize users[]; fill users[]
403
        users = new String[uvec.size()];
404
        for (int i=0; i < uvec.size(); i++) {
405
          users[i] = (String)uvec.elementAt(i); 
406
        }
407

    
408
        // Close the context when we're done
409
        ctx.close();
410

    
411
    } catch (NamingException e) {
412
      System.err.println("Problem getting users for a group in AuthLdap.getUsers:" + e);
413
      throw new ConnectException(
414
      "Problem getting users for a group in AuthLdap.getUsers:" + e);
415
    }
416

    
417
    return users;
418
  }
419

    
420
  /**
421
   * Get UID by DN of a member
422
   */
423
  private String getUserID(String dn) 
424
         throws NamingException
425
  {
426
    String[] users = null;
427

    
428
    // Identify service provider to use
429
    Hashtable env = new Hashtable(11);
430
    env.put(Context.INITIAL_CONTEXT_FACTORY, 
431
            "com.sun.jndi.ldap.LdapCtxFactory");
432
    env.put(Context.PROVIDER_URL, ldapUrl); // + ldapBase);
433

    
434
    try {
435

    
436
        // Create the initial directory context
437
        DirContext ctx = new InitialDirContext(env);
438

    
439
        // Specify the ids of the attributes to return
440
        String[] attrIDs = {"uid"};
441

    
442
        // Ask for "uid" attributes of the user 
443
        Attributes attrs = ctx.getAttributes(dn, attrIDs);
444

    
445
        // Print all of the attributes (only "uid" attr)
446
        Vector uvec = new Vector();
447
        NamingEnumeration en = attrs.getAll();
448
        while (en.hasMore()) {
449
          Attribute att = (Attribute)en.next();
450
          Vector values = new Vector();
451
          String attName = att.getID();
452
          NamingEnumeration attvalues = att.getAll();
453
          while (attvalues.hasMore()) {
454
            String value = (String)attvalues.next();
455
            values.add(value);
456
          }
457
          uvec.add(values.elementAt(0));
458
        }
459

    
460
        // initialize users[]; fill users[]
461
        users = new String[uvec.size()];
462
        for (int i=0; i < uvec.size(); i++) {
463
          users[i] = (String)uvec.elementAt(i); 
464
        }
465

    
466
        // Close the context when we're done
467
        ctx.close();
468

    
469
    } catch (NamingException ne) {
470
      System.err.println("Problem getting userID by \"dn\" in AuthLdap.getUserID:" + ne);
471
      throw ne;
472
    }
473

    
474
    if ( users.length > 0 ) {
475
      return users[0];
476
    }
477
    return null;
478
  }
479

    
480
  /**
481
   * Get CN by DN of a member
482
   */
483
  private String getGroupID(String dn) 
484
         throws NamingException
485
  {
486
    String[] groups = null;
487

    
488
    // Identify service provider to use
489
    Hashtable env = new Hashtable(11);
490
    env.put(Context.INITIAL_CONTEXT_FACTORY, 
491
            "com.sun.jndi.ldap.LdapCtxFactory");
492
    env.put(Context.PROVIDER_URL, ldapUrl); // + ldapBase);
493

    
494
    try {
495

    
496
        // Create the initial directory context
497
        DirContext ctx = new InitialDirContext(env);
498

    
499
        // Specify the ids of the attributes to return
500
        String[] attrIDs = {"cn"};
501

    
502
        // Ask for "uid" attributes of the user 
503
        Attributes attrs = ctx.getAttributes(dn, attrIDs);
504

    
505
        // Print all of the attributes (only "cn" attr)
506
        Vector uvec = new Vector();
507
        NamingEnumeration en = attrs.getAll();
508
        while (en.hasMore()) {
509
          Attribute att = (Attribute)en.next();
510
          Vector values = new Vector();
511
          String attName = att.getID();
512
          NamingEnumeration attvalues = att.getAll();
513
          while (attvalues.hasMore()) {
514
            String value = (String)attvalues.next();
515
            values.add(value);
516
          }
517
          uvec.add(values.elementAt(0));
518
        }
519

    
520
        // initialize users[]; fill users[]
521
        groups = new String[uvec.size()];
522
        for (int i=0; i < uvec.size(); i++) {
523
          groups[i] = (String)uvec.elementAt(i); 
524
        }
525

    
526
        // Close the context when we're done
527
        ctx.close();
528

    
529
    } catch (NamingException ne) {
530
      System.err.println("Problem getting groupID by \"dn\" in AuthLdap.getGroupID:" + ne);
531
      throw ne;
532
    }
533

    
534
    if ( groups.length > 0 ) {
535
      return groups[0];
536
    }
537
    return null;
538
  }
539

    
540
  /**
541
   * Get all groups from the authentication service
542
   */
543
  public String[] getGroups(String user, String password) 
544
         throws ConnectException
545
  {
546
    String[] groups = null;
547

    
548
    // Identify service provider to use
549
    Hashtable env = new Hashtable(11);
550
    env.put(Context.INITIAL_CONTEXT_FACTORY, 
551
            "com.sun.jndi.ldap.LdapCtxFactory");
552
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
553

    
554
    try {
555

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

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

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

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

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

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

    
588
        // Close the context when we're done
589
        ctx.close();
590

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

    
597
    return groups;
598
  }
599

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

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

    
614
    try {
615

    
616
        // Create the initial directory context
617
        DirContext ctx = new InitialDirContext(env);
618

    
619
        // Specify the ids of the attributes to return
620
        String[] attrIDs = {"cn"};
621

    
622
        // Specify the attributes to match.
623
        // Groups are objects with attribute objectclass=groupofuniquenames.
624
        // and have attribute uniquemember=foruser,ldapbase.
625
        Attributes matchAttrs = new BasicAttributes(true); // ignore case
626
        matchAttrs.put(new BasicAttribute("objectclass", "groupofuniquenames"));
627
        matchAttrs.put(new BasicAttribute("uniquemember",foruser+","+ldapBase));
628

    
629
        // Search for objects in the current context
630
        NamingEnumeration enum = ctx.search("", matchAttrs, attrIDs);
631

    
632
        // Print the users
633
        Vector uvec = new Vector();
634
        while (enum.hasMore()) {
635
          SearchResult sr = (SearchResult)enum.next();
636
          Attributes attrs = sr.getAttributes();
637
          NamingEnumeration enum1 = attrs.getAll(); // only "cn" attr
638
          while (enum1.hasMore()) {
639
            Attribute attr = (Attribute)enum1.next();
640
            uvec.add(attr.get());
641
          }
642
        }
643

    
644
        // initialize groups[] and fill it
645
        groups = new String[uvec.size()];
646
        for (int i=0; i < uvec.size(); i++) {
647
          groups[i] = (String)uvec.elementAt(i); 
648
        }
649

    
650
        // Close the context when we're done
651
        ctx.close();
652

    
653
    } catch (NamingException e) {
654
      System.err.println("Problem getting groups in AuthLdap.getGroups:" + e);
655
      throw new ConnectException(
656
      "Problem getting groups for a user in AuthLdap.getGroups:" + e);
657
    }
658

    
659
    return groups;
660
  }
661

    
662
  /**
663
   * Get attributes describing a user or group
664
   *
665
   * @param user the user for which the attribute list is requested
666
   * @returns HashMap a map of attribute name to a Vector of values
667
   */
668
  public HashMap getAttributes(String foruser) 
669
         throws ConnectException
670
  {
671
    return getAttributes(null, null, foruser);
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
   * @param authuser the user for authenticating against the service
679
   * @param password the password for authenticating against the service
680
   * @returns HashMap a map of attribute name to a Vector of values
681
   */
682
  public HashMap getAttributes(String user, String password, String foruser) 
683
         throws ConnectException
684
  {
685
    HashMap attributes = new HashMap();
686

    
687
    // Identify service provider to use
688
    Hashtable env = new Hashtable(11);
689
    env.put(Context.INITIAL_CONTEXT_FACTORY, 
690
        "com.sun.jndi.ldap.LdapCtxFactory");
691
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
692

    
693
    // Authentication information
694
 
695
    try {
696
      
697
      // NO NEED FOR AUTHENTICATION; ALL ATTRIBUTES READABLE EXCEPT userPassword
698
      //if ((user != null) && (password != null)) {
699
      //  String identifier = getIdentifyingName(user,this.ldapUrl,this.ldapBase);
700
      //  env.put(Context.SECURITY_AUTHENTICATION, "simple");
701
      //  env.put(Context.SECURITY_PRINCIPAL, identifier + "," + ldapBase);
702
      //  env.put(Context.SECURITY_CREDENTIALS, password);
703
      //}
704

    
705
      // Create the initial directory context
706
      DirContext ctx = new InitialDirContext(env);
707
        
708
      // Find out the identifying attribute for the user
709
      String userident = getIdentifyingName(foruser,this.ldapUrl,this.ldapBase);
710

    
711
      // Ask for all attributes of the user 
712
      Attributes attrs = ctx.getAttributes(userident);
713
 
714
      // Print all of the attributes
715
      NamingEnumeration en = attrs.getAll();
716
      while (en.hasMore()) {
717
        Attribute att = (Attribute)en.next();
718
        Vector values = new Vector();
719
        String attName = att.getID();
720
        NamingEnumeration attvalues = att.getAll();
721
        while (attvalues.hasMore()) {
722
          String value = (String)attvalues.next();
723
          values.add(value);
724
        }
725
        attributes.put(attName, values);
726
      }
727
  
728
      // Close the context when we're done
729
      ctx.close();
730
    } catch (NamingException e) {
731
      System.err.println("Problem getting attributes in AuthLdap.getAttributes:" 
732
                          + e);
733
      throw new ConnectException(
734
      "Problem getting attributes in AuthLdap.getAttributes:" + e);
735
    }
736

    
737
    return attributes;
738
  }
739

    
740
  /**
741
   * Get list of all subtrees holding Metacat's groups and users
742
   * starting from the Metacat LDAP root, 
743
   * i.e. ldap://dev.nceas.ucsb.edu/dc=ecoinformatics,dc=org
744
   */
745
  private Hashtable getSubtrees(String user, String password,
746
                                String ldapUrl, String ldapBase)
747
                throws ConnectException
748
  {
749
    Hashtable trees = new Hashtable();
750

    
751
    // Identify service provider to use
752
    Hashtable env = new Hashtable(11);
753
    env.put(Context.INITIAL_CONTEXT_FACTORY, 
754
            "com.sun.jndi.ldap.LdapCtxFactory");
755
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
756

    
757
    try {
758

    
759
        // Create the initial directory context
760
        DirContext ctx = new InitialDirContext(env);
761

    
762
        // Specify the ids of the attributes to return
763
        String[] attrIDs = {"o","ref"};
764
        SearchControls ctls = new SearchControls();
765
        ctls.setReturningAttributes(attrIDs);
766
        ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
767
          
768
        // Specify the attributes to match.
769
        // Subtrees from the main server are found as objects with attribute
770
        // objectclass=organization or objectclass=referral to the subtree
771
        // resided on other server.
772
        String filter = "(|(objectclass=organization)(objectclass=referral))";
773

    
774
        // Search for objects in the current context
775
        NamingEnumeration enum = ctx.search("", filter, ctls);
776

    
777
        // Print the subtrees' <ldapURL, baseDN>
778
        while (enum.hasMore()) {
779
          SearchResult sr = (SearchResult)enum.next();
780
          Attributes attrs = sr.getAttributes();
781
          NamingEnumeration enum1 = attrs.getAll(); // "dc" and "ref" attrs
782
          if (enum1.hasMore()) {
783
            Attribute attr = (Attribute)enum1.next();
784
            String attrValue = (String)attr.get();
785
            String attrName = (String)attr.getID();
786
 //System.out.println(attrName + "=" + attrValue);
787
            if ( enum1.hasMore() ) {
788
              attr = (Attribute)enum1.next();
789
              String refValue = (String)attr.get();
790
              String refName = (String)attr.getID();
791
 //System.out.println(refName + "=" + refValue);
792
              if ( ldapBase.startsWith(refName + "=" + refValue) ) {
793
                trees.put(ldapBase,
794
                          attrValue.substring(0,attrValue.lastIndexOf("/")+1) );
795
              } else {
796
                trees.put(refName + "=" + refValue + "," + ldapBase,
797
                          attrValue.substring(0,attrValue.lastIndexOf("/")+1) );
798
              }
799
 //System.out.println("REFERRAL:" + attrValue);
800
            } else if ( ldapBase.startsWith(attrName + "=" + attrValue) ) {
801
                trees.put(ldapBase, ldapUrl);
802
            } else {              
803
                trees.put(attrName + "=" + attrValue + "," + ldapBase, ldapUrl);
804
 //System.out.println(ldapUrl + attrName + "=" + attrValue + "," + ldapBase);
805
            }
806
          }
807
        }
808

    
809
        // Close the context when we're done
810
        ctx.close();
811

    
812
    } catch (NamingException e) {
813
      System.err.println("Problem getting subtrees in AuthLdap.getSubtrees:" + e);
814
      throw new ConnectException(
815
      "Problem getting subtrees in AuthLdap.getSubtrees:" + e);
816
    }
817

    
818
//System.out.println("number of subtrees:" + trees.size());
819
    return trees;
820
  }
821

    
822
  /**
823
   * Get all groups and users from authentication scheme.
824
   * The output is formatted in XML.
825
   * @param user the user which requests the information
826
   * @param password the user's password
827
   */
828
  public String getPrincipals(String user, String password)
829
                throws ConnectException
830
  {
831
    StringBuffer out = new StringBuffer();
832
    Vector usersIn = new Vector();
833
    
834
    //String ldapUrl = "ldap://dev.nceas.ucsb.edu/";
835
    //String ldapBase = "dc=ecoinformatics,dc=org";
836
    //String ldapUrl = "ldap://ldap.nceas.ucsb.edu/";
837
    //String ldapBase = "o=NCEAS,c=US";
838

    
839
    out.append("<?xml version=\"1.0\"?>\n");
840
    out.append("<principals>\n");
841
    
842
    /*
843
     * get all subtrees first in the current dir context 
844
     * and then the Metacat users under them
845
     */
846
    Hashtable subtrees = getSubtrees(user,password,this.ldapUrl,this.ldapBase);
847
    
848
    Enumeration enum = subtrees.keys();
849
    while ( enum.hasMoreElements() ) {
850
      this.ldapBase = (String)enum.nextElement();
851
      this.ldapUrl = (String)subtrees.get(ldapBase);
852
      
853
      out.append("  <authSystem URI=\"" + 
854
                 this.ldapUrl + this.ldapBase + "\">\n");
855

    
856
      // get all groups for directory context
857
      String[] groups = getGroups(user, password);
858

    
859
      // for the groups and users that belong to them
860
      if ( groups.length > 0 ) {
861
        for (int i=0; i < groups.length; i++ ) {
862
          out.append("    <group>\n");
863
          out.append("      <groupname>" + groups[i] + "<groupname>\n");
864
          String[] usersForGroup = getUsers(user,password,groups[i]);
865
          for (int j=0; j < usersForGroup.length; j++ ) {
866
            usersIn.addElement(usersForGroup[j]);
867
            out.append("      <user>\n");
868
            out.append("        <username>" + usersForGroup[j] + "<username>\n");
869
            out.append("      </user>\n");
870
          }
871
          out.append("    </group>\n");
872
        }
873
      }
874
      // for the users not belonging to any group
875
      String[] users = getUsers(user, password);
876
      for (int j=0; j < users.length; j++ ) {
877
        if ( !usersIn.contains(users[j]) ) {
878
          out.append("    <user>\n");
879
          out.append("      <username>" + users[j] + "<username>\n");
880
          out.append("    </user>\n");
881
        }
882
      }
883
    
884
      out.append("  </authSystem>\n");
885
      if ( !usersIn.isEmpty() ) {
886
        usersIn.removeAllElements();
887
        usersIn.trimToSize();
888
      }
889
    
890
    }
891
    out.append("</principals>");
892
    return out.toString();
893
  }
894

    
895
  /**
896
   * Test method for the class
897
   */
898
  public static void main(String[] args) {
899

    
900
    // Provide a user, such as: "Matt Jones", or "jones"
901
    String user = args[0];
902
    String password = args[1];
903

    
904
    AuthLdap authservice = new AuthLdap();
905

    
906
    boolean isValid = false;
907
    try {
908
      isValid = authservice.authenticate(user, password);
909
      if (isValid) {
910
        System.out.println("Authentication successful for: " + user );
911
        System.out.println(" ");
912
        
913
      } else {
914
        System.out.println("Authentication failed for: " + user);
915
      }
916

    
917
      if (isValid) {
918
        //String group = args[2];
919
        HashMap userInfo = authservice.getAttributes(user, password, user);
920
        // Print all of the attributes
921
        Iterator attList = (Iterator)(((Set)userInfo.keySet()).iterator());
922
        while (attList.hasNext()) {
923
          String att = (String)attList.next();
924
          Vector values = (Vector)userInfo.get(att);
925
          Iterator attvalues = values.iterator();
926
          while (attvalues.hasNext()) {
927
            String value = (String)attvalues.next();
928
            System.out.println(att + ": " + value);
929
          }
930
        }
931

    
932
      }
933

    
934
/*
935
      // get the whole list of users
936
      if (isValid) {
937
        String[] users = authservice.getUsers(user, password);
938
        for (int i=0; i < users.length; i++) {
939
          System.out.println(users[i]);          
940
        }
941
        System.out.println("Total " + users.length + " users.");
942
      }
943
*/
944
/*
945
      // get the whole list of users for a group
946
      if (isValid) {
947
        String group = args[2];
948
        String[] users = authservice.getUsers(user, password, group);
949
        for (int i=0; i < users.length; i++) {
950
          System.out.println(users[i]);          
951
        }
952
      }
953
*/
954
      // get the whole list groups and users in XML format
955
/*
956
      if (isValid) {
957
        authservice = new AuthLdap();
958
        String out = authservice.getPrincipals(user, password);
959
        java.io.File f = new java.io.File("principals.txt");
960
        java.io.FileWriter fw = new java.io.FileWriter(f);
961
        java.io.BufferedWriter buff = new java.io.BufferedWriter(fw);
962
        buff.write(out);
963
        buff.flush();
964
        buff.close();
965
        fw.close();
966
      }
967
*/
968
    } catch (ConnectException ce) {
969
      System.err.println(ce.getMessage());
970
    } catch (java.io.IOException ioe) {
971
      System.err.println("I/O Error writing to file principals.txt");
972
    }
973
  }
974
}
(6-6/43)