Project

General

Profile

1 503 bojilova
/**
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$'
12
 *     '$Date$'
13
 * '$Revision$'
14 669 jones
 *
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 503 bojilova
 */
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 730 bojilova
import javax.naming.InitialContext;
37 503 bojilova
import javax.naming.directory.Attribute;
38
import javax.naming.directory.Attributes;
39 504 jones
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 723 bojilova
import javax.naming.directory.SearchControls;
45 503 bojilova
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 730 bojilova
import java.util.Enumeration;
51 503 bojilova
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 515 jones
public class AuthLdap implements AuthInterface {
61 728 bojilova
62
  private MetaCatUtil util;
63
  private String ldapUrl;
64
  private String ldapBase;
65 503 bojilova
66 728 bojilova
  /**
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 503 bojilova
  /**
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 730 bojilova
    String ldapUrl = this.ldapUrl;
89
    String ldapBase = this.ldapBase;
90 503 bojilova
    boolean authenticated = false;
91 730 bojilova
92 503 bojilova
    // 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 730 bojilova
//    env.put(Context.SECURITY_AUTHENTICATION, "simple");
97
//    env.put(Context.SECURITY_PRINCIPAL, user);
98 503 bojilova
99
    try {
100
101 730 bojilova
      /*
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 503 bojilova
114 740 bojilova
        if (identifier != null && !password.equals("")) {
115 730 bojilova
          // 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 740 bojilova
          //env.put(Context.SECURITY_PROTOCOL, "ssl");
119 730 bojilova
          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 740 bojilova
//System.out.println("User NOT FOUND");
140 730 bojilova
        }
141
      } /* while ( enum.hasMore() ) */
142 504 jones
143 740 bojilova
    } catch (NullPointerException e) {
144
      util.debugMessage("NullPointerException b' password is null");
145
      util.debugMessage("NullPointerException while authenticating in " +
146
                        "AuthLdap.authenticate: " + e);
147
      throw new ConnectException(
148
      "NullPointerException while authenticating in " +
149
                        "AuthLdap.authenticate: " + e);
150 503 bojilova
    } catch (NamingException e) {
151 675 berkley
      util.debugMessage("Naming exception while authenticating in " +
152
                        "AuthLdap.authenticate: " + e);
153 723 bojilova
      throw new ConnectException(
154
      "Naming exception while authenticating in " +
155
                        "AuthLdap.authenticate: " + e);
156 730 bojilova
    } catch (Exception e) {
157
      System.out.println(e.getMessage());
158 503 bojilova
    }
159
160
    return authenticated;
161
  }
162
163
  /**
164 730 bojilova
   * Get the identifying name for a given userid or name.  This is the name
165
   * that is used in conjunction withthe LDAP BaseDN to create a
166
   * distinguished name (dn) for the record
167
   *
168
   * @param user the user for which the identifying name is requested
169
   * @returns String the identifying name for the user,
170
   *          or null if not found
171
   */
172
  private String getIdentifyingName(String user, String ldapUrl, String ldapBase)
173
         throws NamingException
174
  {
175
    String identifier = null;
176
177
    // Identify service provider to use
178
    Hashtable env = new Hashtable(11);
179
    env.put(Context.INITIAL_CONTEXT_FACTORY,
180
            "com.sun.jndi.ldap.LdapCtxFactory");
181
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
182
//    env.put(Context.SECURITY_AUTHENTICATION, "EXTERNAL");
183
//    env.put(Context.SECURITY_PROTOCOL, "ssl");
184
185
    try {
186
187
      // Bind to the LDAP server, in order to search for the right
188
      // distinguished name (dn) based on userid (uid) or common name (cn)
189
      DirContext ctx = new InitialDirContext(env);
190
191
      SearchControls ctls = new SearchControls();
192
      ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
193
194
      // Search for the user id or name using the uid, then cn and sn attributes
195
      // If we find a record, determine the dn for the record
196
      util.debugMessage("\nStarting search phase...\n");
197
198
      String filter = "(uid=" + user + ")";
199
      NamingEnumeration answer = ctx.search("", filter, ctls);
200
      if (answer.hasMore()) {
201
        SearchResult sr = (SearchResult)answer.next();
202
        identifier = sr.getName();
203
        if ( !sr.isRelative() ) {
204
          this.ldapUrl = identifier.substring(0,identifier.lastIndexOf("/")+1);
205
          this.ldapBase = identifier.substring(identifier.indexOf(",")+1);
206
          identifier = identifier.substring(identifier.lastIndexOf("/")+1,
207
                                            identifier.indexOf(","));
208
        }
209
        util.debugMessage("Found: " + identifier);
210
      } else {
211
        //Attributes matchAttrs2 = new BasicAttributes(true);
212
        //matchAttrs2.put(new BasicAttribute("cn", user));
213
        //NamingEnumeration answer2 = ctx.search("", matchAttrs2);
214
        filter = "(cn=" + user + ")";
215
        NamingEnumeration answer2 = ctx.search("", filter, ctls);
216
        if (answer2.hasMore()) {
217
          SearchResult sr = (SearchResult)answer2.next();
218
          identifier = sr.getName();
219
          if ( !sr.isRelative() ) {
220
            this.ldapUrl = identifier.substring(0,identifier.lastIndexOf("/")+1);
221
            this.ldapBase = identifier.substring(identifier.indexOf(",")+1);
222
            identifier = identifier.substring(identifier.lastIndexOf("/")+1,
223
                                              identifier.indexOf(","));
224
          }
225
          util.debugMessage("Found: " + identifier);
226
        } else {
227
          //Attributes matchAttrs3 = new BasicAttributes(true);
228
          //matchAttrs3.put(new BasicAttribute("sn", user));
229
          //NamingEnumeration answer3 = ctx.search("", matchAttrs3);
230
          filter = "(sn=" + user + ")";
231
          NamingEnumeration answer3 = ctx.search("", filter, ctls);
232
          if (answer3.hasMore()) {
233
            SearchResult sr = (SearchResult)answer3.next();
234
            identifier = sr.getName();
235
            if ( !sr.isRelative() ) {
236
              this.ldapUrl = identifier.substring(0,identifier.lastIndexOf("/")+1);
237
              this.ldapBase = identifier.substring(identifier.indexOf(",")+1);
238
              identifier = identifier.substring(identifier.lastIndexOf("/")+1,
239
                                                identifier.indexOf(","));
240
            }
241
            util.debugMessage("Found: " + identifier);
242
          }
243
        }
244
      }
245
      // Close the context when we're done the initial search
246
      ctx.close();
247
    } catch (NamingException e) {
248
      util.debugMessage("Naming exception while getting dn: " + e);
249
      throw new NamingException(
250
      "Naming exception in AuthLdap.getIdentifyingName: " + e);
251
    }
252
253
//System.out.println("context: " + identifier);
254
    return identifier;
255
  }
256
257
  /**
258 503 bojilova
   * Get all users from the authentication service
259
   */
260 514 jones
  public String[] getUsers(String user, String password)
261
         throws ConnectException
262 503 bojilova
  {
263 723 bojilova
    String[] users = null;
264
265
    // Identify service provider to use
266
    Hashtable env = new Hashtable(11);
267
    env.put(Context.INITIAL_CONTEXT_FACTORY,
268
            "com.sun.jndi.ldap.LdapCtxFactory");
269
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
270
271
    try {
272
273 730 bojilova
      //// Get the dn for this uid or cn
274
      //String identifier = getIdentifyingName(user);
275
      //if (identifier != null) {
276
      //  env.put(Context.SECURITY_AUTHENTICATION, "simple");
277
      //  env.put(Context.SECURITY_PRINCIPAL, identifier + "," + ldapBase);
278
      //  env.put(Context.SECURITY_CREDENTIALS, password);
279 723 bojilova
280
        // Create the initial directory context
281
        DirContext ctx = new InitialDirContext(env);
282
283
        // Specify the ids of the attributes to return
284
        String[] attrIDs = {"uid"};
285
286 726 bojilova
        // Specify the attributes to match.
287
        // Users are objects that have the attribute objectclass=InetOrgPerson.
288
        Attributes matchAttrs = new BasicAttributes(true); // ignore case
289
        matchAttrs.put(new BasicAttribute("objectclass", "inetOrgPerson"));
290
291 723 bojilova
        // Search for objects in the current context
292 726 bojilova
        NamingEnumeration enum = ctx.search("", matchAttrs, attrIDs);
293 723 bojilova
294
        // Print the users
295
        Vector uvec = new Vector();
296
        while (enum.hasMore()) {
297
          SearchResult sr = (SearchResult)enum.next();
298
          Attributes attrs = sr.getAttributes();
299
          NamingEnumeration enum1 = attrs.getAll(); // only "uid" attr
300
          while (enum1.hasMore()) {
301
            Attribute attr = (Attribute)enum1.next();
302
            uvec.add(attr.get());
303
          }
304
        }
305
306
        // initialize users[]; fill users[]
307
        users = new String[uvec.size()];
308
        for (int i=0; i < uvec.size(); i++) {
309
          users[i] = (String)uvec.elementAt(i);
310
        }
311
312
        // Close the context when we're done
313
        ctx.close();
314 730 bojilova
      //} else {
315
      //  util.debugMessage("User not found!");
316
      //}
317 723 bojilova
318
    } catch (NamingException e) {
319
      System.err.println("Problem getting users in AuthLdap.getUsers:" + e);
320
      throw new ConnectException(
321 728 bojilova
      "Problem getting users in AuthLdap.getUsers:" + e);
322 723 bojilova
    }
323
324
    return users;
325 503 bojilova
  }
326
327
  /**
328
   * Get the users for a particular group from the authentication service
329
   */
330 514 jones
  public String[] getUsers(String user, String password, String group)
331
         throws ConnectException
332 503 bojilova
  {
333 723 bojilova
    String[] users = null;
334
335
    // Identify service provider to use
336
    Hashtable env = new Hashtable(11);
337
    env.put(Context.INITIAL_CONTEXT_FACTORY,
338
            "com.sun.jndi.ldap.LdapCtxFactory");
339
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
340
341
    try {
342
343 730 bojilova
      //// Get the dn for this uid or cn
344
      //String identifier = getIdentifyingName(user);
345
      //if (identifier != null) {
346
      //  env.put(Context.SECURITY_AUTHENTICATION, "simple");
347
      //  env.put(Context.SECURITY_PRINCIPAL, identifier + "," + ldapBase);
348
      //  env.put(Context.SECURITY_CREDENTIALS, password);
349 723 bojilova
350
        // Create the initial directory context
351
        DirContext ctx = new InitialDirContext(env);
352
353
        // Specify the ids of the attributes to return
354 726 bojilova
        String[] attrIDs = {"uniquemember"};
355 723 bojilova
356
        // Specify the attributes to match.
357 726 bojilova
        // Groups are objects with attribute objectclass=groupofuniquenames.
358 723 bojilova
        Attributes matchAttrs = new BasicAttributes(true); // ignore case
359 726 bojilova
        matchAttrs.put(new BasicAttribute("objectclass", "groupofuniquenames"));
360
        matchAttrs.put(new BasicAttribute("cn", group));
361 723 bojilova
362
        // Search for objects in the current context
363
        NamingEnumeration enum = ctx.search("", matchAttrs, attrIDs);
364
365
        // Print the users
366
        Vector uvec = new Vector();
367
        while (enum.hasMore()) {
368
          SearchResult sr = (SearchResult)enum.next();
369
          Attributes attrs = sr.getAttributes();
370 728 bojilova
          // return all attributes (only "uniquemember" attr)
371
          NamingEnumeration enum1 = attrs.getAll();
372 723 bojilova
          while (enum1.hasMore()) {
373
            Attribute attr = (Attribute)enum1.next();
374 726 bojilova
            // return all values of that attribute
375
            NamingEnumeration enum2 = attr.getAll();
376
            while (enum2.hasMore()) {
377 728 bojilova
              // get DN of a member
378
              String memberDN = (String)enum2.next();
379
              try {
380
                // we actually need RDN of the member
381
                // try to get RDN (UID) of the member in case of a user
382
                String memberID = getUserID(memberDN);
383
                if ( memberID != null ) {
384
                  uvec.add(memberID);
385
                // CURRENTLY WE DON'T SUPPORT SUBGROUPING, THUS
386
                // IGNORE SUBGROUPS AS MEMBERS OF THE GROUP
387
                // // this is a group, not user
388
                // // try to get RDN (CN) of the group
389
                // } else {
390
                //   memberID = getGroupID(memberDN);
391
                //   uvec.add(memberID);
392
                }
393
              } catch (NamingException ne) {}
394 726 bojilova
            }
395 723 bojilova
          }
396
        }
397
398
        // initialize users[]; fill users[]
399
        users = new String[uvec.size()];
400
        for (int i=0; i < uvec.size(); i++) {
401
          users[i] = (String)uvec.elementAt(i);
402
        }
403
404
        // Close the context when we're done
405
        ctx.close();
406 730 bojilova
      //} else {
407
      //  util.debugMessage("User not found!");
408
      //}
409 723 bojilova
410
    } catch (NamingException e) {
411 728 bojilova
      System.err.println("Problem getting users for a group in AuthLdap.getUsers:" + e);
412 723 bojilova
      throw new ConnectException(
413 728 bojilova
      "Problem getting users for a group in AuthLdap.getUsers:" + e);
414 723 bojilova
    }
415
416
    return users;
417 503 bojilova
  }
418
419
  /**
420 728 bojilova
   * Get UID by DN of a member
421
   */
422
  private String getUserID(String dn)
423
         throws NamingException
424
  {
425
    String[] users = null;
426
427
    // Identify service provider to use
428
    Hashtable env = new Hashtable(11);
429
    env.put(Context.INITIAL_CONTEXT_FACTORY,
430
            "com.sun.jndi.ldap.LdapCtxFactory");
431
    env.put(Context.PROVIDER_URL, ldapUrl); // + ldapBase);
432
433
    try {
434
435
        // Create the initial directory context
436
        DirContext ctx = new InitialDirContext(env);
437
438
        // Specify the ids of the attributes to return
439
        String[] attrIDs = {"uid"};
440
441
        // Ask for "uid" attributes of the user
442
        Attributes attrs = ctx.getAttributes(dn, attrIDs);
443
444
        // Print all of the attributes (only "uid" attr)
445
        Vector uvec = new Vector();
446
        NamingEnumeration en = attrs.getAll();
447
        while (en.hasMore()) {
448
          Attribute att = (Attribute)en.next();
449
          Vector values = new Vector();
450
          String attName = att.getID();
451
          NamingEnumeration attvalues = att.getAll();
452
          while (attvalues.hasMore()) {
453
            String value = (String)attvalues.next();
454
            values.add(value);
455
          }
456
          uvec.add(values.elementAt(0));
457
        }
458
459
        // initialize users[]; fill users[]
460
        users = new String[uvec.size()];
461
        for (int i=0; i < uvec.size(); i++) {
462
          users[i] = (String)uvec.elementAt(i);
463
        }
464
465
        // Close the context when we're done
466
        ctx.close();
467
468
    } catch (NamingException ne) {
469
      System.err.println("Problem getting userID by \"dn\" in AuthLdap.getUserID:" + ne);
470
      throw ne;
471
    }
472
473
    if ( users.length > 0 ) {
474
      return users[0];
475
    }
476
    return null;
477
  }
478
479
  /**
480
   * Get CN by DN of a member
481
   */
482
  private String getGroupID(String dn)
483
         throws NamingException
484
  {
485
    String[] groups = null;
486
487
    // Identify service provider to use
488
    Hashtable env = new Hashtable(11);
489
    env.put(Context.INITIAL_CONTEXT_FACTORY,
490
            "com.sun.jndi.ldap.LdapCtxFactory");
491
    env.put(Context.PROVIDER_URL, ldapUrl); // + ldapBase);
492
493
    try {
494
495
        // Create the initial directory context
496
        DirContext ctx = new InitialDirContext(env);
497
498
        // Specify the ids of the attributes to return
499
        String[] attrIDs = {"cn"};
500
501
        // Ask for "uid" attributes of the user
502
        Attributes attrs = ctx.getAttributes(dn, attrIDs);
503
504
        // Print all of the attributes (only "cn" attr)
505
        Vector uvec = new Vector();
506
        NamingEnumeration en = attrs.getAll();
507
        while (en.hasMore()) {
508
          Attribute att = (Attribute)en.next();
509
          Vector values = new Vector();
510
          String attName = att.getID();
511
          NamingEnumeration attvalues = att.getAll();
512
          while (attvalues.hasMore()) {
513
            String value = (String)attvalues.next();
514
            values.add(value);
515
          }
516
          uvec.add(values.elementAt(0));
517
        }
518
519
        // initialize users[]; fill users[]
520
        groups = new String[uvec.size()];
521
        for (int i=0; i < uvec.size(); i++) {
522
          groups[i] = (String)uvec.elementAt(i);
523
        }
524
525
        // Close the context when we're done
526
        ctx.close();
527
528
    } catch (NamingException ne) {
529
      System.err.println("Problem getting groupID by \"dn\" in AuthLdap.getGroupID:" + ne);
530
      throw ne;
531
    }
532
533
    if ( groups.length > 0 ) {
534
      return groups[0];
535
    }
536
    return null;
537
  }
538
539
  /**
540 503 bojilova
   * Get all groups from the authentication service
541
   */
542 514 jones
  public String[] getGroups(String user, String password)
543
         throws ConnectException
544 503 bojilova
  {
545 723 bojilova
    String[] groups = null;
546
547
    // Identify service provider to use
548
    Hashtable env = new Hashtable(11);
549
    env.put(Context.INITIAL_CONTEXT_FACTORY,
550
            "com.sun.jndi.ldap.LdapCtxFactory");
551
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
552
553
    try {
554
555 730 bojilova
      //// Get the dn for this uid or cn
556
      //String identifier = getIdentifyingName(user);
557
      //if (identifier != null) {
558
      //  env.put(Context.SECURITY_AUTHENTICATION, "simple");
559
      //  env.put(Context.SECURITY_PRINCIPAL, identifier + "," + ldapBase);
560
      //  env.put(Context.SECURITY_CREDENTIALS, password);
561 723 bojilova
562
        // Create the initial directory context
563
        DirContext ctx = new InitialDirContext(env);
564
565
        // Specify the ids of the attributes to return
566 726 bojilova
        String[] attrIDs = {"cn"};
567 723 bojilova
568 726 bojilova
        // Specify the attributes to match.
569
        // Groups are objects with attribute objectclass=groupofuniquenames.
570
        Attributes matchAttrs = new BasicAttributes(true); // ignore case
571
        matchAttrs.put(new BasicAttribute("objectclass", "groupofuniquenames"));
572
573 723 bojilova
        // Search for objects in the current context
574 726 bojilova
        NamingEnumeration enum = ctx.search("", matchAttrs, attrIDs);
575 723 bojilova
576
        // Print the users
577
        Vector uvec = new Vector();
578
        while (enum.hasMore()) {
579
          SearchResult sr = (SearchResult)enum.next();
580
          Attributes attrs = sr.getAttributes();
581 726 bojilova
          NamingEnumeration enum1 = attrs.getAll(); // only "cn" attr
582 723 bojilova
          while (enum1.hasMore()) {
583
            Attribute attr = (Attribute)enum1.next();
584
            uvec.add(attr.get());
585
          }
586
        }
587
588
        // initialize groups[] and fill it
589
        groups = new String[uvec.size()];
590
        for (int i=0; i < uvec.size(); i++) {
591
          groups[i] = (String)uvec.elementAt(i);
592
        }
593
594
        // Close the context when we're done
595
        ctx.close();
596 730 bojilova
      //} else {
597
      //  util.debugMessage("User not found!");
598
      //}
599 723 bojilova
600
    } catch (NamingException e) {
601
      System.err.println("Problem getting groups in AuthLdap.getGroups:" + e);
602
      throw new ConnectException(
603
      "Problem getting groups in AuthLdap.getGroups:" + e);
604
    }
605
606
    return groups;
607 503 bojilova
  }
608
609
  /**
610
   * Get the groups for a particular user from the authentication service
611
   */
612 514 jones
  public String[] getGroups(String user, String password, String foruser)
613
         throws ConnectException
614 503 bojilova
  {
615 723 bojilova
    String[] groups = null;
616
617
    // Identify service provider to use
618
    Hashtable env = new Hashtable(11);
619
    env.put(Context.INITIAL_CONTEXT_FACTORY,
620
            "com.sun.jndi.ldap.LdapCtxFactory");
621
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
622
623
    try {
624
625 730 bojilova
      //// Get the dn for this uid or cn
626
      //String identifier = getIdentifyingName(user);
627
      //if (identifier != null) {
628
      //  env.put(Context.SECURITY_AUTHENTICATION, "simple");
629
      //  env.put(Context.SECURITY_PRINCIPAL, identifier + "," + ldapBase);
630
      //  env.put(Context.SECURITY_CREDENTIALS, password);
631 723 bojilova
632
        // Create the initial directory context
633
        DirContext ctx = new InitialDirContext(env);
634
635
        // Specify the ids of the attributes to return
636 726 bojilova
        String[] attrIDs = {"cn"};
637 723 bojilova
638
        // Specify the attributes to match.
639 726 bojilova
        // Groups are objects with attribute objectclass=groupofuniquenames.
640
        // and have attribute uniquemember=foruser,ldapbase.
641 723 bojilova
        Attributes matchAttrs = new BasicAttributes(true); // ignore case
642 726 bojilova
        matchAttrs.put(new BasicAttribute("objectclass", "groupofuniquenames"));
643
        matchAttrs.put(new BasicAttribute("uniquemember",foruser+","+ldapBase));
644 723 bojilova
645
        // Search for objects in the current context
646
        NamingEnumeration enum = ctx.search("", matchAttrs, attrIDs);
647
648
        // Print the users
649
        Vector uvec = new Vector();
650
        while (enum.hasMore()) {
651
          SearchResult sr = (SearchResult)enum.next();
652
          Attributes attrs = sr.getAttributes();
653 728 bojilova
          NamingEnumeration enum1 = attrs.getAll(); // only "cn" attr
654 723 bojilova
          while (enum1.hasMore()) {
655
            Attribute attr = (Attribute)enum1.next();
656
            uvec.add(attr.get());
657
          }
658
        }
659
660
        // initialize groups[] and fill it
661
        groups = new String[uvec.size()];
662
        for (int i=0; i < uvec.size(); i++) {
663
          groups[i] = (String)uvec.elementAt(i);
664
        }
665
666
        // Close the context when we're done
667
        ctx.close();
668 730 bojilova
      //} else {
669
      //  util.debugMessage("User not found!");
670
      //}
671 723 bojilova
672
    } catch (NamingException e) {
673
      System.err.println("Problem getting groups in AuthLdap.getGroups:" + e);
674
      throw new ConnectException(
675 728 bojilova
      "Problem getting groups for a user in AuthLdap.getGroups:" + e);
676 723 bojilova
    }
677
678
    return groups;
679 503 bojilova
  }
680
681
  /**
682
   * Get attributes describing a user or group
683
   *
684
   * @param user the user for which the attribute list is requested
685
   * @returns HashMap a map of attribute name to a Vector of values
686
   */
687 514 jones
  public HashMap getAttributes(String foruser)
688 503 bojilova
         throws ConnectException
689
  {
690 514 jones
    return getAttributes(null, null, foruser);
691 503 bojilova
  }
692
693
  /**
694
   * Get attributes describing a user or group
695
   *
696
   * @param user the user for which the attribute list is requested
697
   * @param authuser the user for authenticating against the service
698
   * @param password the password for authenticating against the service
699
   * @returns HashMap a map of attribute name to a Vector of values
700
   */
701 514 jones
  public HashMap getAttributes(String user, String password, String foruser)
702 503 bojilova
         throws ConnectException
703
  {
704
    HashMap attributes = new HashMap();
705
706
    // Identify service provider to use
707
    Hashtable env = new Hashtable(11);
708
    env.put(Context.INITIAL_CONTEXT_FACTORY,
709
        "com.sun.jndi.ldap.LdapCtxFactory");
710
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
711
712
    // Authentication information
713
714
    try {
715
716 723 bojilova
      if ((user != null) && (password != null)) {
717 730 bojilova
        String identifier = getIdentifyingName(user,this.ldapUrl,this.ldapBase);
718 723 bojilova
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
719
        env.put(Context.SECURITY_PRINCIPAL, identifier + "," + ldapBase);
720
        env.put(Context.SECURITY_CREDENTIALS, password);
721
      }
722 504 jones
723 503 bojilova
      // Create the initial directory context
724
      DirContext ctx = new InitialDirContext(env);
725
726 723 bojilova
      // Find out the identifying attribute for the user
727 730 bojilova
      String userident = getIdentifyingName(foruser,this.ldapUrl,this.ldapBase);
728 723 bojilova
729 504 jones
      // Ask for all attributes of the user
730
      Attributes attrs = ctx.getAttributes(userident);
731 723 bojilova
732 503 bojilova
      // Print all of the attributes
733
      NamingEnumeration en = attrs.getAll();
734
      while (en.hasMore()) {
735
        Attribute att = (Attribute)en.next();
736
        Vector values = new Vector();
737
        String attName = att.getID();
738
        NamingEnumeration attvalues = att.getAll();
739
        while (attvalues.hasMore()) {
740
          String value = (String)attvalues.next();
741
          values.add(value);
742
        }
743
        attributes.put(attName, values);
744
      }
745
746
      // Close the context when we're done
747
      ctx.close();
748
    } catch (NamingException e) {
749 675 berkley
      System.err.println("Problem getting attributes in AuthLdap.getAttributes:"
750
                          + e);
751 723 bojilova
      throw new ConnectException(
752
      "Problem getting attributes in AuthLdap.getAttributes:" + e);
753 503 bojilova
    }
754
755
    return attributes;
756
  }
757
758
  /**
759 730 bojilova
   * Get list of all subtrees holding Metacat's groups and users
760
   * starting from the Metacat LDAP root,
761
   * i.e. ldap://dev.nceas.ucsb.edu/dc=ecoinformatics,dc=org
762 504 jones
   */
763 730 bojilova
  private Hashtable getSubtrees(String user, String password,
764
                                String ldapUrl, String ldapBase)
765
                throws ConnectException
766 504 jones
  {
767 730 bojilova
    Hashtable trees = new Hashtable();
768 504 jones
769
    // Identify service provider to use
770
    Hashtable env = new Hashtable(11);
771 730 bojilova
    env.put(Context.INITIAL_CONTEXT_FACTORY,
772 504 jones
            "com.sun.jndi.ldap.LdapCtxFactory");
773
    env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
774
775
    try {
776
777 730 bojilova
      //if ( this.authenticate(user, password) ) {
778 504 jones
779 730 bojilova
        // Create the initial directory context
780
        DirContext ctx = new InitialDirContext(env);
781
782
        // Specify the ids of the attributes to return
783
        String[] attrIDs = {"o","ref"};
784
        SearchControls ctls = new SearchControls();
785
        ctls.setReturningAttributes(attrIDs);
786
        ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
787
788
        // Specify the attributes to match.
789
        // Subtrees from the main server are found as objects with attribute
790
        // objectclass=organization or objectclass=referral to the subtree
791
        // resided on other server.
792
        String filter = "(|(objectclass=organization)(objectclass=referral))";
793
794
        // Search for objects in the current context
795
        NamingEnumeration enum = ctx.search("", filter, ctls);
796
797
        // Print the subtrees' <ldapURL, baseDN>
798
        while (enum.hasMore()) {
799
          SearchResult sr = (SearchResult)enum.next();
800
          Attributes attrs = sr.getAttributes();
801
          NamingEnumeration enum1 = attrs.getAll(); // "dc" and "ref" attrs
802
          if (enum1.hasMore()) {
803
            Attribute attr = (Attribute)enum1.next();
804
            String attrValue = (String)attr.get();
805
            String attrName = (String)attr.getID();
806
 //System.out.println(attrName + "=" + attrValue);
807
            if ( enum1.hasMore() ) {
808
              attr = (Attribute)enum1.next();
809
              String refValue = (String)attr.get();
810
              String refName = (String)attr.getID();
811
 //System.out.println(refName + "=" + refValue);
812
              if ( ldapBase.startsWith(refName + "=" + refValue) ) {
813
                trees.put(ldapBase,
814
                          attrValue.substring(0,attrValue.lastIndexOf("/")+1) );
815
              } else {
816
                trees.put(refName + "=" + refValue + "," + ldapBase,
817
                          attrValue.substring(0,attrValue.lastIndexOf("/")+1) );
818
              }
819
 //System.out.println("REFERRAL:" + attrValue);
820
            } else if ( ldapBase.startsWith(attrName + "=" + attrValue) ) {
821
                trees.put(ldapBase, ldapUrl);
822
            } else {
823
                trees.put(attrName + "=" + attrValue + "," + ldapBase, ldapUrl);
824
 //System.out.println(ldapUrl + attrName + "=" + attrValue + "," + ldapBase);
825
            }
826 504 jones
          }
827
        }
828 730 bojilova
829
        // Close the context when we're done
830
        ctx.close();
831
      //} else {
832
      //  System.out.println("Not authenticated user: " + user + "@" + ldapUrl + ldapBase);
833
      //}
834
835 504 jones
    } catch (NamingException e) {
836 730 bojilova
      System.err.println("Problem getting subtrees in AuthLdap.getSubtrees:" + e);
837
      throw new ConnectException(
838
      "Problem getting subtrees in AuthLdap.getSubtrees:" + e);
839 504 jones
    }
840
841 730 bojilova
//System.out.println("number of subtrees:" + trees.size());
842
    return trees;
843 504 jones
  }
844
845
  /**
846 730 bojilova
   * Get all groups and users from authentication scheme.
847 725 bojilova
   * The output is formatted in XML.
848 730 bojilova
   * @param user the user which requests the information
849
   * @param password the user's password
850 725 bojilova
   */
851 730 bojilova
  public String getPrincipals(String user, String password)
852 725 bojilova
                throws ConnectException
853
  {
854
    StringBuffer out = new StringBuffer();
855 726 bojilova
    Vector usersIn = new Vector();
856 725 bojilova
857 730 bojilova
    //String ldapUrl = "ldap://dev.nceas.ucsb.edu/";
858
    //String ldapBase = "dc=ecoinformatics,dc=org";
859
    //String ldapUrl = "ldap://ldap.nceas.ucsb.edu/";
860
    //String ldapBase = "o=NCEAS,c=US";
861
862 725 bojilova
    out.append("<?xml version=\"1.0\"?>\n");
863 730 bojilova
    out.append("<principals>\n");
864 725 bojilova
865 730 bojilova
    /*
866
     * get all subtrees first in the current dir context
867
     * and then the Metacat users under them
868
     */
869
    Hashtable subtrees = getSubtrees(user,password,this.ldapUrl,this.ldapBase);
870
871
    Enumeration enum = subtrees.keys();
872
    while ( enum.hasMoreElements() ) {
873
      this.ldapBase = (String)enum.nextElement();
874
      this.ldapUrl = (String)subtrees.get(ldapBase);
875
876
      out.append("  <authSystem URI=\"" +
877
                 this.ldapUrl + this.ldapBase + "\">\n");
878
879
      // get all groups for directory context
880
      String[] groups = getGroups(user, password);
881
882
      // for the groups and users that belong to them
883
      if ( groups.length > 0 ) {
884
        for (int i=0; i < groups.length; i++ ) {
885
          out.append("    <group>\n");
886
          out.append("      <groupname>" + groups[i] + "<groupname>\n");
887
          String[] usersForGroup = getUsers(user,password,groups[i]);
888
          for (int j=0; j < usersForGroup.length; j++ ) {
889
            usersIn.addElement(usersForGroup[j]);
890
            out.append("      <user>\n");
891
            out.append("        <username>" + usersForGroup[j] + "<username>\n");
892
            out.append("      </user>\n");
893
          }
894
          out.append("    </group>\n");
895
        }
896
      }
897
      // for the users not belonging to any group
898
      String[] users = getUsers(user, password);
899
      for (int j=0; j < users.length; j++ ) {
900
        if ( !usersIn.contains(users[j]) ) {
901 725 bojilova
          out.append("    <user>\n");
902 730 bojilova
          out.append("      <username>" + users[j] + "<username>\n");
903 725 bojilova
          out.append("    </user>\n");
904
        }
905
      }
906 730 bojilova
907
      out.append("  </authSystem>\n");
908
      if ( !usersIn.isEmpty() ) {
909
        usersIn.removeAllElements();
910
        usersIn.trimToSize();
911 725 bojilova
      }
912 730 bojilova
913 725 bojilova
    }
914
    out.append("</principals>");
915
    return out.toString();
916
  }
917
918
  /**
919 503 bojilova
   * Test method for the class
920
   */
921
  public static void main(String[] args) {
922
923 504 jones
    // Provide a user, such as: "Matt Jones", or "jones"
924 503 bojilova
    String user = args[0];
925
    String password = args[1];
926
927
    AuthLdap authservice = new AuthLdap();
928
929
    boolean isValid = false;
930
    try {
931
      isValid = authservice.authenticate(user, password);
932
      if (isValid) {
933
        System.out.println("Authentication successful for: " + user );
934
        System.out.println(" ");
935 728 bojilova
936 503 bojilova
      } else {
937
        System.out.println("Authentication failed for: " + user);
938
      }
939 725 bojilova
940 503 bojilova
      if (isValid) {
941 726 bojilova
        //String group = args[2];
942 514 jones
        HashMap userInfo = authservice.getAttributes(user, password, user);
943 503 bojilova
        // Print all of the attributes
944
        Iterator attList = (Iterator)(((Set)userInfo.keySet()).iterator());
945
        while (attList.hasNext()) {
946
          String att = (String)attList.next();
947
          Vector values = (Vector)userInfo.get(att);
948
          Iterator attvalues = values.iterator();
949
          while (attvalues.hasNext()) {
950
            String value = (String)attvalues.next();
951 730 bojilova
          //  System.out.println(att + ": " + value);
952 503 bojilova
          }
953
        }
954 723 bojilova
955 503 bojilova
      }
956 725 bojilova
957
/*
958 723 bojilova
      // get the whole list of users
959
      if (isValid) {
960
        String[] users = authservice.getUsers(user, password);
961
        for (int i=0; i < users.length; i++) {
962
          System.out.println(users[i]);
963
        }
964 726 bojilova
        System.out.println("Total " + users.length + " users.");
965 723 bojilova
      }
966 725 bojilova
*/
967 723 bojilova
/*
968
      // get the whole list of users for a group
969
      if (isValid) {
970
        String group = args[2];
971
        String[] users = authservice.getUsers(user, password, group);
972
        for (int i=0; i < users.length; i++) {
973
          System.out.println(users[i]);
974
        }
975
      }
976
*/
977 726 bojilova
      // get the whole list groups and users in XML format
978 725 bojilova
      if (isValid) {
979 730 bojilova
        authservice = new AuthLdap();
980 725 bojilova
        String out = authservice.getPrincipals(user, password);
981
        java.io.File f = new java.io.File("principals.txt");
982
        java.io.FileWriter fw = new java.io.FileWriter(f);
983
        java.io.BufferedWriter buff = new java.io.BufferedWriter(fw);
984
        buff.write(out);
985
        buff.flush();
986
        buff.close();
987
        fw.close();
988
      }
989 726 bojilova
990 503 bojilova
    } catch (ConnectException ce) {
991 730 bojilova
      System.err.println(ce.getMessage());
992 725 bojilova
    } catch (java.io.IOException ioe) {
993
      System.err.println("I/O Error writing to file principals.txt");
994 503 bojilova
    }
995
  }
996
}