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
 *
10
 *   '$Author: tao $'
11
 *     '$Date: 2014-03-14 15:33:14 -0700 (Fri, 14 Mar 2014) $'
12
 * '$Revision: 8704 $'
13
 *
14
 * This program is free software; you can redistribute it and/or modify
15
 * it under the terms of the GNU General Public License as published by
16
 * the Free Software Foundation; either version 2 of the License, or
17
 * (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU General Public License
25
 * along with this program; if not, write to the Free Software
26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27
 */
28

    
29
package edu.ucsb.nceas.metacat;
30

    
31
import java.net.ConnectException;
32
import javax.naming.AuthenticationException;
33
import javax.naming.Context;
34
import javax.naming.NamingEnumeration;
35
import javax.naming.NamingException;
36
import javax.naming.SizeLimitExceededException;
37
import javax.naming.directory.Attribute;
38
import javax.naming.directory.Attributes;
39
import javax.naming.directory.DirContext;
40
import javax.naming.directory.InitialDirContext;
41
import javax.naming.directory.SearchResult;
42
import javax.naming.directory.SearchControls;
43
import javax.naming.ReferralException;
44
import javax.naming.ldap.InitialLdapContext;
45
import javax.naming.ldap.LdapContext;
46
import javax.naming.ldap.StartTlsRequest;
47
import javax.naming.ldap.StartTlsResponse;
48
import javax.net.ssl.SSLSession;
49

    
50
import org.apache.log4j.Logger;
51

    
52
import edu.ucsb.nceas.metacat.properties.PropertyService;
53
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
54

    
55
import java.io.IOException;
56
import java.lang.InstantiationException;
57
import java.net.URLDecoder;
58
import java.util.Iterator;
59
import java.util.HashMap;
60
import java.util.Hashtable;
61
import java.util.Enumeration;
62
import java.util.Set;
63
import java.util.Vector;
64

    
65
/**
66
 * An implementation of the AuthInterface interface that allows Metacat to use
67
 * the LDAP protocol for directory services. The LDAP authentication service is
68
 * used to determine if a user is authenticated, and whether they are a member
69
 * of a particular group.
70
 */
71
public class AuthLdap implements AuthInterface {
72
	private String ldapUrl;
73
	private String ldapsUrl;
74
	private String ldapBase;
75
	private String referral;
76
	private String ldapConnectTimeLimit;
77
	private int ldapSearchTimeLimit;
78
	private int ldapSearchCountLimit;
79
	private String currentReferralInfo;
80
	Hashtable<String, String> env = new Hashtable<String, String>(11);
81
	private Context rContext;
82
	private String userName;
83
	private String userPassword;
84
	ReferralException refExc;
85

    
86
	private static Logger logMetacat = Logger.getLogger(AuthLdap.class);
87

    
88
	/**
89
	 * Construct an AuthLdap
90
	 */
91
	public AuthLdap() throws InstantiationException {
92
		// Read LDAP URI for directory service information
93
		try {
94
			this.ldapUrl = PropertyService.getProperty("auth.url");
95
			this.ldapsUrl = PropertyService.getProperty("auth.surl");
96
			this.ldapBase = PropertyService.getProperty("auth.base");
97
			this.referral = PropertyService.getProperty("ldap.referral");
98
			this.ldapConnectTimeLimit = PropertyService
99
					.getProperty("ldap.connectTimeLimit");
100
			this.ldapSearchTimeLimit = Integer.parseInt(PropertyService
101
					.getProperty("ldap.searchTimeLimit"));
102
			this.ldapSearchCountLimit = Integer.parseInt(PropertyService
103
					.getProperty("ldap.searchCountLimit"));
104
		} catch (PropertyNotFoundException pnfe) {
105
			throw new InstantiationException(
106
					"Could not instantiate AuthLdap.  Property not found: "
107
							+ pnfe.getMessage());
108
		} catch (NumberFormatException nfe) {
109
			throw new InstantiationException(
110
					"Could not instantiate AuthLdap.  Bad number format when converting properties: "
111
							+ nfe.getMessage());
112
		}
113

    
114
		// Store referral info for use in building group DNs in getGroups()
115
		this.currentReferralInfo = "";
116
	}
117

    
118
	/**
119
	 * Determine if a user/password are valid according to the authentication
120
	 * service.
121
	 * 
122
	 * @param user
123
	 *            the name of the principal to authenticate
124
	 * @param password
125
	 *            the password to use for authentication
126
	 * @returns boolean true if authentication successful, false otherwise
127
	 */
128
	public boolean authenticate(String user, String password) throws ConnectException {
129
		String ldapUrl = this.ldapUrl;
130
		String ldapsUrl = this.ldapsUrl;
131
		String ldapBase = this.ldapBase;
132
		boolean authenticated = false;
133
		String identifier = user;
134

    
135
		// get uid here.
136
		if (user.indexOf(",") == -1) {
137
			throw new ConnectException("Invalid LDAP user credential: " + user
138
					+ ".  Missing ','");
139
		}
140
		String uid = user.substring(0, user.indexOf(","));
141
		user = user.substring(user.indexOf(","), user.length());
142

    
143
		logMetacat.debug("AuthLdap.authenticate - identifier: " + identifier + 
144
				", uid: " + uid +", user: " + user);
145

    
146
		try {
147
			// Check the usename as passed in
148
			logMetacat.info("AuthLdap.authenticate - Calling ldapAuthenticate" +
149
				" with user as identifier: " + identifier);
150

    
151
			authenticated = ldapAuthenticate(identifier, password, (new Boolean(
152
					PropertyService.getProperty("ldap.onlySecureConnection")))
153
					.booleanValue());
154
			// if not found, try looking up a valid DN then auth again
155
			if (!authenticated) {
156
				logMetacat.info("AuthLdap.authenticate - Not Authenticated");
157
				logMetacat.info("AuthLdap.authenticate - Looking up DN for: " + identifier);
158
				identifier = getIdentifyingName(identifier, ldapUrl, ldapBase);
159
				if (identifier == null) {
160
					logMetacat.info("AuthLdap.authenticate - No DN found from getIdentifyingName");
161
					return authenticated;
162
				}
163

    
164
				logMetacat.info("AuthLdap.authenticate - DN found from getIdentifyingName: " + identifier);
165
				String decoded = URLDecoder.decode(identifier);
166
				logMetacat.info("AuthLdap.authenticate - DN decoded: " + decoded);
167
				identifier = decoded;
168
				String refUrl = "";
169
				String refBase = "";
170
				if (identifier.startsWith("ldap")) {
171
					logMetacat.debug("AuthLdap.authenticate - identifier starts with \"ldap\"");
172

    
173
					refUrl = identifier.substring(0, identifier.lastIndexOf("/") + 1);
174
					int position = identifier.indexOf(",");
175
					int position2 = identifier.indexOf(",", position + 1);
176

    
177
					refBase = identifier.substring(position2 + 1);
178
					identifier = identifier.substring(identifier.lastIndexOf("/") + 1);
179

    
180
					logMetacat.info("AuthLdap.authenticate - Calling ldapAuthenticate: " +
181
						"with user as identifier: " + identifier + " and refUrl as: " + 
182
						refUrl + " and refBase as: " + refBase);
183

    
184
					authenticated = ldapAuthenticate(identifier, password, refUrl,
185
							refBase, (new Boolean(PropertyService
186
									.getProperty("ldap.onlySecureReferalsConnection")))
187
									.booleanValue());
188
				} else {
189
					logMetacat.info("AuthLdap.authenticate - identifier doesnt start with ldap");
190
					identifier = identifier + "," + ldapBase;
191

    
192
					logMetacat.info("AuthLdap.authenticate - Calling ldapAuthenticate" + 
193
							"with user as identifier: " + identifier);
194

    
195
					authenticated = ldapAuthenticate(identifier, password, (new Boolean(
196
							PropertyService.getProperty("ldap.onlySecureConnection")))
197
							.booleanValue());
198
				}
199
			}
200
		} catch (NullPointerException npe) {
201
			logMetacat.error("AuthLdap.authenticate - NullPointerException while authenticating in "
202
					+ "AuthLdap.authenticate: " + npe);
203
			npe.printStackTrace();
204

    
205
			throw new ConnectException("AuthLdap.authenticate - NullPointerException while authenticating in "
206
					+ "AuthLdap.authenticate: " + npe);
207
		} catch (NamingException ne) {
208
			logMetacat.error("AuthLdap.authenticate - Naming exception while authenticating in "
209
					+ "AuthLdap.authenticate: " + ne);
210
			ne.printStackTrace();
211
		} catch (PropertyNotFoundException pnfe) {
212
			logMetacat.error("AuthLdap.authenticate - Property exception while authenticating in "
213
					+ "AuthLdap.authenticate: " + pnfe.getMessage());
214
		}
215

    
216
		return authenticated;
217
	}
218

    
219
	/**
220
	 * Connect to the LDAP directory and do the authentication using the
221
	 * username and password as passed into the routine.
222
	 * 
223
	 * @param identifier
224
	 *            the distinguished name to check against LDAP
225
	 * @param password
226
	 *            the password for authentication
227
	 */
228
	private boolean ldapAuthenticate(String identifier, String password,
229
			boolean secureConnectionOnly) throws ConnectException, NamingException,
230
			NullPointerException {
231
		return ldapAuthenticate(identifier, password, this.ldapsUrl, this.ldapBase,
232
				secureConnectionOnly);
233
	}
234

    
235
	/**
236
	 * Connect to the LDAP directory and do the authentication using the
237
	 * username and password as passed into the routine.
238
	 * 
239
	 * @param identifier
240
	 *            the distinguished name to check against LDAP
241
	 * @param password
242
	 *            the password for authentication
243
	 */
244

    
245
	private boolean ldapAuthenticate(String dn, String password, String rootServer,
246
			String rootBase, boolean secureConnectionOnly) {
247

    
248
		boolean authenticated = false;
249

    
250
		String server = "";
251
		String userDN = "";
252
		logMetacat.info("AuthLdap.ldapAuthenticate - dn is: " + dn);
253

    
254
		int position = dn.lastIndexOf("/");
255
		logMetacat.debug("AuthLdap.ldapAuthenticate - position is: " + position);
256
		if (position == -1) {
257
			server = rootServer;
258
			if (dn.indexOf(userDN) < 0) {
259
				userDN = dn + "," + rootBase;
260
			} else {
261
				userDN = dn;
262
			}
263
			logMetacat.info("AuthLdap.ldapAuthenticate - userDN is: " + userDN);
264

    
265
		} else {
266
			server = dn.substring(0, position + 1);
267
			userDN = dn.substring(position + 1);
268
			logMetacat.info("AuthLdap.ldapAuthenticate - server is: " + server);
269
			logMetacat.info("AuthLdap.ldapAuthenticate - userDN is: " + userDN);
270
		}
271

    
272
		logMetacat.warn("AuthLdap.ldapAuthenticate - Trying to authenticate: " + 
273
				userDN + " Using server: " + server);
274

    
275
		try {
276
			Hashtable<String, String> env = new Hashtable<String, String>();
277
			env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
278
			env.put(Context.PROVIDER_URL, server);
279
			env.put(Context.REFERRAL, "throw");
280
			
281
			try {
282
				authenticated = authenticateTLS(env, userDN, password);
283
			} catch (AuthenticationException ee) {
284
			    logMetacat.info("AuthLdap.ldapAuthenticate - failed to login : "+ee.getMessage());
285
			    String aliasedDn = null;
286
			    try {
287
			        aliasedDn = getAliasedDnTLS(userDN, env);
288
			        if(aliasedDn != null) {
289
			            logMetacat.warn("AuthLdap.ldapAuthenticate - an aliased object " + aliasedDn + " was found for the DN "+userDN+". We will try to authenticate this new DN "+aliasedDn+".");
290
			            authenticated = authenticateTLS(env, aliasedDn, password);
291
			        }
292
			    } catch (NamingException e) {
293
			        logMetacat.error("AuthLdap.ldapAuthenticate - NamingException "+e.getMessage()+" happend when the ldap server authenticated the aliased object "+aliasedDn);
294
			    } catch (IOException e) {
295
			        logMetacat.error("AuthLdap.ldapAuthenticate - IOException "+e.getMessage()+" happend when the ldap server authenticated the aliased object "+aliasedDn);
296
			    } catch (AuthTLSException e) {
297
			        logMetacat.error("AuthLdap.ldapAuthenticate - AuthTLSException "+e.getMessage()+" happend when the ldap server authenticated the aliased object "+aliasedDn);
298
			    }
299
			} catch (AuthTLSException ate) {
300
				logMetacat.info("AuthLdap.ldapAuthenticate - error while negotiating TLS: "
301
						+ ate.getMessage());
302
				if (secureConnectionOnly) {
303
					return authenticated;
304
				} else {
305
				    try {
306
                        authenticated = authenticateNonTLS(env, userDN, password);
307
                    } catch (AuthenticationException ae) {
308
                        logMetacat.warn("Authentication exception for (nonTLS): " + ae.getMessage());
309
                        String aliasedDn = null;
310
                        try {
311
                            aliasedDn = getAliasedDnNonTLS(userDN, env);
312
                            if(aliasedDn != null) {
313
                                logMetacat.warn("AuthLdap.ldapAuthenticate(NonTLS) - an aliased object " + aliasedDn + " was found for the DN "+userDN+". We will try to authenticate this new DN "+aliasedDn+" again.");
314
                                authenticated = authenticateNonTLS(env, aliasedDn, password);
315
                            }
316
                            
317
                        } catch (NamingException e) {
318
                            logMetacat.error("AuthLdap.ldapAuthenticate(NonTLS) - NamingException "+e.getMessage()+" happend when the ldap server authenticated the aliased object "+aliasedDn);
319
                        } catch (IOException e) {
320
                            logMetacat.error("AuthLdap.ldapAuthenticate(NonTLS) - IOException "+e.getMessage()+" happend when the ldap server authenticated the aliased object "+aliasedDn);
321
                        } 
322
                    }
323

    
324
				}
325
			}
326
		} catch (AuthenticationException ae) {
327
			logMetacat.warn("Authentication exception: " + ae.getMessage());
328
			authenticated = false;
329
		} catch (javax.naming.InvalidNameException ine) {
330
			logMetacat.error("AuthLdap.ldapAuthenticate - An invalid DN was provided: " + ine.getMessage());
331
		} catch (NamingException ne) {
332
			logMetacat.warn("AuthLdap.ldapAuthenticate - Caught NamingException in login: " + ne.getClass().getName());
333
			logMetacat.info(ne.toString() + "  " + ne.getRootCause());
334
		}
335

    
336
		return authenticated;
337
	}
338
	
339
	
340
	/*
341
	 * Get the aliased dn through a TLS connection. The null will be returned if there is no real name associated with the alias
342
	 */
343
	private String getAliasedDnTLS(String alias, Hashtable<String, String> env) throws NamingException, IOException {
344
	    boolean useTLS = true;
345
	    return getAliasedDn(alias, env, useTLS);
346
	}
347
	
348
	/*
349
     * Get the aliased dn through a non-TLS connection. The null will be returned if there is no real name associated with the alias
350
     */
351
    private String getAliasedDnNonTLS(String alias, Hashtable<String, String> env) throws NamingException, IOException {
352
        boolean useTLS = false;
353
        return getAliasedDn(alias, env, useTLS);
354
    }
355
	
356
	/*
357
	 * Get the aliasedDN (the real DN) for a specified an alias name
358
	 */
359
	private String getAliasedDn(String alias, Hashtable<String, String> env, boolean useTLS) throws NamingException, IOException  {
360
	    String aliasedDn = null;
361
	    if(env != null) {
362
	        env.put(Context.REFERRAL, "ignore");
363
	    }
364
        LdapContext sctx = new InitialLdapContext(env, null);
365
        StartTlsResponse tls = null;
366
        if(useTLS) {
367
            tls = (StartTlsResponse) sctx.extendedOperation(new StartTlsRequest());
368
            // Open a TLS connection (over the existing LDAP association) and get details
369
            // of the negotiated TLS session: cipher suite, peer certificate, etc.
370
            SSLSession session = tls.negotiate();
371
        }
372
        SearchControls ctls = new SearchControls();
373
        ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
374
        String filter = "(objectClass=*)";
375
        NamingEnumeration answer  = sctx.search(alias, filter, ctls);
376
        while(answer.hasMore()) {
377
            SearchResult result = (SearchResult) answer.next();
378
            if(!result.isRelative()) {
379
                //if is not relative, this will be alias.
380
                aliasedDn = result.getNameInNamespace();
381
                break;
382
            }
383
        }
384
        if(useTLS && tls != null) {
385
            tls.close();
386
        }
387
        sctx.close();
388
        return aliasedDn;
389
	    
390
	}
391
	
392
	private boolean authenticateTLS(Hashtable<String, String> env, String userDN, String password)
393
			throws AuthTLSException, AuthenticationException{	
394
		logMetacat.info("AuthLdap.authenticateTLS - Trying to authenticate with TLS");
395
		try {
396
			LdapContext ctx = null;
397
			double startTime;
398
			double stopTime;
399
			startTime = System.currentTimeMillis();
400
			ctx = new InitialLdapContext(env, null);
401
			// Start up TLS here so that we don't pass our jewels in
402
			// cleartext
403
			StartTlsResponse tls = 
404
				(StartTlsResponse) ctx.extendedOperation(new StartTlsRequest());
405
			// tls.setHostnameVerifier(new SampleVerifier());
406
			SSLSession sess = tls.negotiate();
407
			ctx.addToEnvironment(Context.SECURITY_AUTHENTICATION, "simple");
408
			ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, userDN);
409
			ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, password);
410
			ctx.reconnect(null);
411
			stopTime = System.currentTimeMillis();
412
			logMetacat.info("AuthLdap.authenticateTLS - Connection time thru "
413
					+ ldapsUrl + " was: " + (stopTime - startTime) / 1000 + " seconds.");
414
		} catch (AuthenticationException ae) {
415
            logMetacat.warn("AuthLdap.authenticateTLS - Authentication exception: " + ae.getMessage());
416
            throw ae;
417
            
418
		} catch (NamingException ne) {
419
			throw new AuthTLSException("AuthLdap.authenticateTLS - Naming error when athenticating via TLS: " + ne.getMessage());
420
		} catch (IOException ioe) {
421
			throw new AuthTLSException("AuthLdap.authenticateTLS - I/O error when athenticating via TLS: " + ioe.getMessage());
422
		}
423
		return true;
424
	}
425
	
426
	private boolean authenticateNonTLS(Hashtable<String, String> env, String userDN, String password) 
427
			throws NamingException {
428
		LdapContext ctx = null;
429
		double startTime;
430
		double stopTime;
431
		
432
		logMetacat.info("AuthLdap.authenticateNonTLS - Trying to authenticate without TLS");
433
		//env.put(Context.SECURITY_AUTHENTICATION, "simple");
434
		//env.put(Context.SECURITY_PRINCIPAL, userDN);
435
		//env.put(Context.SECURITY_CREDENTIALS, password);
436

    
437
		startTime = System.currentTimeMillis();
438
		ctx = new InitialLdapContext(env, null);
439
		ctx.addToEnvironment(Context.SECURITY_AUTHENTICATION, "simple");
440
        ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, userDN);
441
        ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, password);
442
        ctx.reconnect(null);
443
		stopTime = System.currentTimeMillis();
444
		logMetacat.info("AuthLdap.authenticateNonTLS - Connection time thru " + ldapsUrl + " was: "
445
				+ (stopTime - startTime) / 1000 + " seconds.");
446

    
447
		return true;
448
	}
449

    
450
	/**
451
	 * Get the identifying name for a given userid or name. This is the name
452
	 * that is used in conjunction withthe LDAP BaseDN to create a distinguished
453
	 * name (dn) for the record
454
	 * 
455
	 * @param user
456
	 *            the user for which the identifying name is requested
457
	 * @returns String the identifying name for the user, or null if not found
458
	 */
459
	private String getIdentifyingName(String user, String ldapUrl, String ldapBase)
460
			throws NamingException {
461

    
462
		String identifier = null;
463
		Hashtable env = new Hashtable();
464
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
465
		env.put(Context.REFERRAL, "throw");
466
		env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
467
		try {
468
			int position = user.indexOf(",");
469
			String uid = user.substring(user.indexOf("=") + 1, position);
470
			logMetacat.info("AuthLdap.getIdentifyingName - uid is: " + uid);
471
			String org = user.substring(user.indexOf("=", position + 1) + 1, user
472
					.indexOf(",", position + 1));
473
			logMetacat.info("AuthLdap.getIdentifyingName - org is: " + org);
474

    
475
			DirContext sctx = new InitialDirContext(env);
476
			SearchControls ctls = new SearchControls();
477
			ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
478
			String filter = "(&(uid=" + uid + ")(o=" + org + "))";
479
			logMetacat.warn("AuthLdap.getIdentifyingName - Searching for DNs with following filter: " + filter);
480

    
481
			for (boolean moreReferrals = true; moreReferrals;) {
482
				try {
483
					// Perform the search
484
				    
485
					NamingEnumeration answer = sctx.search("", filter, ctls);
486

    
487
					// Return the answer
488
					while (answer.hasMore()) {
489
						SearchResult sr = (SearchResult) answer.next();
490
						identifier = sr.getName();
491
						return identifier;
492
					}
493
					// The search completes with no more referrals
494
					moreReferrals = false;
495
				} catch (ReferralException e) {
496
					logMetacat.info("AuthLdap.getIdentifyingName - Got referral: " + e.getReferralInfo());
497
					// Point to the new context from the referral
498
					if (moreReferrals) {
499
						// try following referral, skip if error
500
						boolean referralError = true;
501
						while (referralError) {
502
							try {
503
								sctx = (DirContext) e.getReferralContext();
504
								referralError = false;
505
							}
506
							catch (NamingException ne) {
507
								logMetacat.error("NamingException when getting referral contex. Skipping this referral. " + ne.getMessage());
508
								e.skipReferral();
509
								referralError = true;
510
							}
511
						}
512
					}
513
				}				
514
			}
515
		} catch (NamingException e) {
516
			logMetacat.error("AuthLdap.getIdentifyingName - Naming exception while getting dn: " + e);
517
			throw new NamingException("Naming exception in AuthLdap.getIdentifyingName: "
518
					+ e);
519
		}
520
		return identifier;
521
	}
522

    
523
	/**
524
	 * Get all users from the authentication service
525
	 * 
526
	 * @param user
527
	 *            the user for authenticating against the service
528
	 * @param password
529
	 *            the password for authenticating against the service
530
	 * @returns string array of all of the user names
531
	 */
532
	public String[][] getUsers(String user, String password) throws ConnectException {
533
		String[][] users = null;
534

    
535
		// Identify service provider to use
536
		Hashtable env = new Hashtable(11);
537
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
538
		env.put(Context.REFERRAL, referral);
539
		env.put(Context.PROVIDER_URL, ldapUrl);
540
		env.put("com.sun.jndi.ldap.connect.timeout", ldapConnectTimeLimit);
541

    
542
		try {
543

    
544
			// Create the initial directory context
545
			DirContext ctx = new InitialDirContext(env);
546

    
547
			// Specify the attributes to match.
548
			// Users are objects that have the attribute
549
			// objectclass=InetOrgPerson.
550
			SearchControls ctls = new SearchControls();
551
			String[] attrIDs = { "dn", "cn", "o", "ou", "mail" };
552
			ctls.setReturningAttributes(attrIDs);
553
			ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
554
			ctls.setTimeLimit(ldapSearchTimeLimit);
555
			// ctls.setCountLimit(1000);
556
			String filter = "(objectClass=inetOrgPerson)";
557
			NamingEnumeration namingEnum = ctx.search(ldapBase, filter, ctls);
558

    
559
			// Store the users in a vector
560
			Vector uvec = new Vector();
561
			Vector uname = new Vector();
562
			Vector uorg = new Vector();
563
			Vector uou = new Vector();
564
			Vector umail = new Vector();
565
			Attributes tempAttr = null;
566
			try {
567
				while (namingEnum.hasMore()) {
568
					SearchResult sr = (SearchResult) namingEnum.next();
569
					tempAttr = sr.getAttributes();
570

    
571
					if ((tempAttr.get("cn") + "").startsWith("cn: ")) {
572
						uname.add((tempAttr.get("cn") + "").substring(4));
573
					} else {
574
						uname.add(tempAttr.get("cn") + "");
575
					}
576

    
577
					if ((tempAttr.get("o") + "").startsWith("o: ")) {
578
						uorg.add((tempAttr.get("o") + "").substring(3));
579
					} else {
580
						uorg.add(tempAttr.get("o") + "");
581
					}
582

    
583
					if ((tempAttr.get("ou") + "").startsWith("ou: ")) {
584
						uou.add((tempAttr.get("ou") + "").substring(4));
585
					} else {
586
						uou.add(tempAttr.get("ou") + "");
587
					}
588

    
589
					if ((tempAttr.get("mail") + "").startsWith("mail: ")) {
590
						umail.add((tempAttr.get("mail") + "").substring(6));
591
					} else {
592
						umail.add(tempAttr.get("mail") + "");
593
					}
594

    
595
					uvec.add(sr.getName() + "," + ldapBase);
596
				}
597
			} catch (SizeLimitExceededException slee) {
598
				logMetacat.error("AuthLdap.getUsers - LDAP Server size limit exceeded. "
599
						+ "Returning incomplete record set.");
600
			}
601

    
602
			// initialize users[]; fill users[]
603
			users = new String[uvec.size()][5];
604
			for (int i = 0; i < uvec.size(); i++) {
605
				users[i][0] = (String) uvec.elementAt(i);
606
				users[i][1] = (String) uname.elementAt(i);
607
				users[i][2] = (String) uorg.elementAt(i);
608
				users[i][3] = (String) uorg.elementAt(i);
609
				users[i][4] = (String) umail.elementAt(i);
610
			}
611

    
612
			// Close the context when we're done
613
			ctx.close();
614

    
615
		} catch (NamingException e) {
616
			logMetacat.error("AuthLdap.getUsers - Problem getting users in AuthLdap.getUsers:" + e);
617
			// e.printStackTrace(System.err);
618
			/*
619
			 * throw new ConnectException( "Problem getting users in
620
			 * AuthLdap.getUsers:" + e);
621
			 */
622
		}
623

    
624
		return users;
625
	}
626

    
627
	/**
628
	 * Get all users from the authentication service
629
	 * 
630
	 * @param user
631
	 *            the user for authenticating against the service
632
	 * @param password
633
	 *            the password for authenticating against the service
634
	 * @returns string array of all of the user names
635
	 */
636
	public String[] getUserInfo(String user, String password) throws ConnectException {
637
		String[] userinfo = new String[3];
638

    
639
		logMetacat.info("AuthLdap.getUserInfo - get the user info for user  "+user);
640
		// Identify service provider to use
641
		Hashtable env = new Hashtable(11);
642
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");	
643
		env.put(Context.PROVIDER_URL, ldapUrl);
644
		String realName = null;
645
		try {
646
		    realName = getAliasedDnNonTLS(user,env);
647
		} catch(Exception e) {
648
		    logMetacat.warn("AuthLdap.getUserInfo - can't get the alias name for the user "+user+" since "+e.getMessage());
649
		}
650
		logMetacat.info("AuthLdap.getUserInfo - the aliased dn for "+user+" is "+realName);
651
		if(realName != null) {
652
		    //the the user is an alias name. we need to use the the real name
653
		    user = realName;
654
		}
655

    
656
		try {
657

    
658
			// Create the initial directory context
659
		    env.put(Context.REFERRAL, referral);
660
			DirContext ctx = new InitialDirContext(env);
661
			// Specify the attributes to match.
662
			// Users are objects that have the attribute
663
			// objectclass=InetOrgPerson.
664
			SearchControls ctls = new SearchControls();
665
			String[] attrIDs = { "cn", "o", "mail" };
666
			ctls.setReturningAttributes(attrIDs);
667
			ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
668
			// ctls.setCountLimit(1000);
669
			// create the filter based on the uid
670

    
671
			String filter = null;
672

    
673
			/*if (user.indexOf("o=") > 0) {
674
				String tempStr = user.substring(user.indexOf("o="));
675
				filter = "(&(" + user.substring(0, user.indexOf(",")) + ")("
676
						+ tempStr.substring(0, tempStr.indexOf(",")) + "))";
677
			} else {
678
				filter = "(&(" + user.substring(0, user.indexOf(",")) + "))";
679
			}*/
680
			filter = "(&(" + user.substring(0, user.indexOf(",")) + "))";
681

    
682
			NamingEnumeration namingEnum = ctx.search(user, filter, ctls);
683

    
684
			Attributes tempAttr = null;
685
			try {
686
				while (namingEnum.hasMore()) {
687
					SearchResult sr = (SearchResult) namingEnum.next();
688
					tempAttr = sr.getAttributes();
689

    
690
					if ((tempAttr.get("cn") + "").startsWith("cn: ")) {
691
						userinfo[0] = (tempAttr.get("cn") + "").substring(4);
692
					} else {
693
						userinfo[0] = (tempAttr.get("cn") + "");
694
					}
695

    
696
					if ((tempAttr.get("o") + "").startsWith("o: ")) {
697
						userinfo[1] = (tempAttr.get("o") + "").substring(3);
698
					} else {
699
						userinfo[1] = (tempAttr.get("o") + "");
700
					}
701

    
702
					if ((tempAttr.get("mail") + "").startsWith("mail: ")) {
703
						userinfo[2] = (tempAttr.get("mail") + "").substring(6);
704
					} else {
705
						userinfo[2] = (tempAttr.get("mail") + "");
706
					}
707
				}
708
			} catch (SizeLimitExceededException slee) {
709
				logMetacat.error("AuthLdap.getUserInfo - LDAP Server size limit exceeded. "
710
						+ "Returning incomplete record set.");
711
			}
712

    
713
			// Close the context when we're done
714
			ctx.close();
715

    
716
		} catch (NamingException e) {
717
			logMetacat.error("AuthLdap.getUserInfo - Problem getting users:" + e);
718
			// e.printStackTrace(System.err);
719
			throw new ConnectException("Problem getting users in AuthLdap.getUsers:" + e);
720
		}
721

    
722
		return userinfo;
723
	}
724

    
725
	/**
726
	 * Get the users for a particular group from the authentication service
727
	 * 
728
	 * @param user
729
	 *            the user for authenticating against the service
730
	 * @param password
731
	 *            the password for authenticating against the service
732
	 * @param group
733
	 *            the group whose user list should be returned
734
	 * @returns string array of the user names belonging to the group
735
	 */
736
	public String[] getUsers(String user, String password, String group)
737
			throws ConnectException {
738
		String[] users = null;
739

    
740
		// Identify service provider to use
741
		Hashtable env = new Hashtable(11);
742
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
743
		env.put(Context.REFERRAL, referral);
744
		env.put(Context.PROVIDER_URL, ldapUrl);
745

    
746
		try {
747

    
748
			// Create the initial directory context
749
			DirContext ctx = new InitialDirContext(env);
750

    
751
			// Specify the ids of the attributes to return
752
			String[] attrIDs = { "uniqueMember" };
753

    
754
			Attributes answer = ctx.getAttributes(group, attrIDs);
755

    
756
			Vector uvec = new Vector();
757
			try {
758
				for (NamingEnumeration ae = answer.getAll(); ae.hasMore();) {
759
					Attribute attr = (Attribute) ae.next();
760
					for (NamingEnumeration e = attr.getAll(); e.hasMore(); uvec.add(e
761
							.next())) {
762
						;
763
					}
764
				}
765
			} catch (SizeLimitExceededException slee) {
766
				logMetacat.error("AuthLdap.getUsers - LDAP Server size limit exceeded. "
767
						+ "Returning incomplete record set.");
768
			}
769

    
770
			// initialize users[]; fill users[]
771
			users = new String[uvec.size()];
772
			for (int i = 0; i < uvec.size(); i++) {
773
				users[i] = (String) uvec.elementAt(i);
774
			}
775

    
776
			// Close the context when we're done
777
			ctx.close();
778

    
779
		} catch (NamingException e) {
780
			logMetacat.error("AuthLdap.getUsers - Problem getting users for a group in "
781
					+ "AuthLdap.getUsers:" + e);
782
			/*
783
			 * throw new ConnectException( "Problem getting users for a group in
784
			 * AuthLdap.getUsers:" + e);
785
			 */
786
		}
787

    
788
		return users;
789
	}
790

    
791
	/**
792
	 * Get all groups from the authentication service
793
	 * 
794
	 * @param user
795
	 *            the user for authenticating against the service
796
	 * @param password
797
	 *            the password for authenticating against the service
798
	 * @returns string array of the group names
799
	 */
800
	public String[][] getGroups(String user, String password) throws ConnectException {
801
		return getGroups(user, password, null);
802
	}
803

    
804
	/**
805
	 * Get the groups for a particular user from the authentication service
806
	 * 
807
	 * @param user
808
	 *            the user for authenticating against the service
809
	 * @param password
810
	 *            the password for authenticating against the service
811
	 * @param foruser
812
	 *            the user whose group list should be returned
813
	 * @returns string array of the group names
814
	 */
815
	public String[][] getGroups(String user, String password, String foruser)
816
			throws ConnectException {
817

    
818
		logMetacat.debug("AuthLdap.getGroups - getGroups() called.");
819

    
820
		// create vectors to store group and dscription values returned from the
821
		// ldap servers
822
		Vector gvec = new Vector();
823
		Vector desc = new Vector();
824
		Attributes tempAttr = null;
825
		Attributes rsrAttr = null;
826

    
827
		// DURING getGroups(), DO WE NOT BIND USING userName AND userPassword??
828
		// NEED TO FIX THIS ...
829
		userName = user;
830
		userPassword = password;
831
		// Identify service provider to use
832
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
833
		env.put(Context.REFERRAL, "throw");
834
		env.put(Context.PROVIDER_URL, ldapUrl);
835
		env.put("com.sun.jndi.ldap.connect.timeout", ldapConnectTimeLimit);
836
		/*String realName = null;
837
		try {
838
            realName = getAliasedDnNonTLS(foruser,env);
839
        } catch(Exception e) {
840
            logMetacat.warn("AuthLdap.getGroups - can't get the alias name for the user "+user+" since "+e.getMessage());
841
        }
842
        
843
        if(realName != null) {
844
            //the the user is an alias name. we need to use the the real name
845
            foruser = realName;
846
        }*/
847
		// Iterate through the referrals, handling NamingExceptions in the
848
		// outer catch statement, ReferralExceptions in the inner catch
849
		// statement
850
		try { // outer try
851

    
852
			// Create the initial directory context
853
			DirContext ctx = new InitialDirContext(env);
854

    
855
			// Specify the attributes to match.
856
			// Groups are objects with attribute objectclass=groupofuniquenames.
857
			// and have attribute uniquemember: uid=foruser,ldapbase.
858
			SearchControls ctls = new SearchControls();
859
			// Specify the ids of the attributes to return
860
			String[] attrIDs = { "cn", "o", "description" };
861
			ctls.setReturningAttributes(attrIDs);
862
			// set the ldap search scope
863
			ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
864
			// set a 10 second time limit on searches to limit non-responding
865
			// servers
866
			ctls.setTimeLimit(ldapSearchTimeLimit);
867
			// return at most 20000 entries
868
			ctls.setCountLimit(ldapSearchCountLimit);
869

    
870
			// build the ldap search filter that represents the "group" concept
871
			String filter = null;
872
			String gfilter = "(objectClass=groupOfUniqueNames)";
873
			if (null == foruser) {
874
				filter = gfilter;
875
			} else {
876
				filter = "(& " + gfilter + "(uniqueMember=" + foruser + "))";
877
			}
878
			logMetacat.info("AuthLdap.getGroups - group filter is: " + filter);
879

    
880
			// now, search and iterate through the referrals
881
			for (boolean moreReferrals = true; moreReferrals;) {
882
				try { // inner try
883

    
884
					NamingEnumeration namingEnum = ctx.search(ldapBase, filter, ctls);
885

    
886
					// Print the groups
887
					while (namingEnum.hasMore()) {
888
						SearchResult sr = (SearchResult) namingEnum.next();
889

    
890
						tempAttr = sr.getAttributes();
891

    
892
						if ((tempAttr.get("description") + "")
893
								.startsWith("description: ")) {
894
							desc.add((tempAttr.get("description") + "").substring(13));
895
						} else {
896
							desc.add(tempAttr.get("description") + "");
897
						}
898

    
899
						// check for an absolute URL value or an answer value
900
						// relative
901
						// to the target context
902
						if (!sr.getName().startsWith("ldap") && sr.isRelative()) {
903
							logMetacat.debug("AuthLdap.getGroups - Search result entry is relative ...");
904
							gvec.add(sr.getName() + "," + ldapBase);
905
							logMetacat.info("AuthLdap.getGroups - group " + sr.getName() + "," + ldapBase
906
									+ " added to the group vector");
907
						} else {
908
							logMetacat.debug("AuthLdap.getGroups - Search result entry is absolute ...");
909

    
910
							// search the top level directory for referral
911
							// objects and match
912
							// that of the search result's absolute URL. This
913
							// will let us
914
							// rebuild the group name from the search result,
915
							// referral point
916
							// in the top directory tree, and ldapBase.
917

    
918
							// configure a new directory search first
919
							Hashtable envHash = new Hashtable(11);
920
							// Identify service provider to use
921
							envHash.put(Context.INITIAL_CONTEXT_FACTORY,
922
									"com.sun.jndi.ldap.LdapCtxFactory");
923
							envHash.put(Context.REFERRAL, "ignore");
924
							envHash.put(Context.PROVIDER_URL, ldapUrl);
925
							envHash.put("com.sun.jndi.ldap.connect.timeout",
926
									ldapConnectTimeLimit);
927

    
928
							try {
929
								// Create the initial directory context
930
								DirContext DirCtx = new InitialDirContext(envHash);
931

    
932
								SearchControls searchCtls = new SearchControls();
933
								// Specify the ids of the attributes to return
934
								String[] attrNames = { "o" };
935
								searchCtls.setReturningAttributes(attrNames);
936
								// set the ldap search scope - only look for top
937
								// level referrals
938
								searchCtls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
939
								// set a time limit on searches to limit
940
								// non-responding servers
941
								searchCtls.setTimeLimit(ldapSearchTimeLimit);
942
								// return the configured number of entries
943
								searchCtls.setCountLimit(ldapSearchCountLimit);
944

    
945
								// Specify the attributes to match.
946
								// build the ldap search filter to match
947
								// referral entries that
948
								// match the search result
949
								String rFilter = "(&(objectClass=referral)(ref="
950
										+ currentReferralInfo.substring(0,
951
												currentReferralInfo.indexOf("?")) + "))";
952
								logMetacat.debug("AuthLdap.getGroups - rFilter is: " + rFilter);
953

    
954
								NamingEnumeration rNamingEnum = DirCtx.search(ldapBase,
955
										rFilter, searchCtls);
956

    
957
								while (rNamingEnum.hasMore()) {
958
									SearchResult rsr = (SearchResult) rNamingEnum.next();
959
									rsrAttr = rsr.getAttributes();
960
									logMetacat.debug("AuthLdap.getGroups - referral search result is: "
961
											+ rsr.toString());
962

    
963
									// add the returned groups to the group
964
									// vector. Test the
965
									// syntax of the returned attributes -
966
									// sometimes they are
967
									// preceded with the attribute id and a
968
									// colon
969
									if ((tempAttr.get("cn") + "").startsWith("cn: ")) {
970
										gvec.add("cn="
971
												+ (tempAttr.get("cn") + "").substring(4)
972
												+ "," + "o="
973
												+ (rsrAttr.get("o") + "").substring(3)
974
												+ "," + ldapBase);
975
										logMetacat.info("AuthLdap.getGroups - group "
976
												+ (tempAttr.get("cn") + "").substring(4)
977
												+ "," + "o="
978
												+ (rsrAttr.get("o") + "").substring(3)
979
												+ "," + ldapBase
980
												+ " added to the group vector");
981
									} else {
982
										gvec.add("cn=" + tempAttr.get("cn") + "," + "o="
983
												+ rsrAttr.get("o") + "," + ldapBase);
984
										logMetacat.info("AuthLdap.getGroups - group " + "cn="
985
												+ tempAttr.get("cn") + "," + "o="
986
												+ rsrAttr.get("o") + "," + ldapBase
987
												+ " added to the group vector");
988
									}
989
								}
990

    
991
							} catch (NamingException nameEx) {
992
								logMetacat.debug("AuthLdap.getGroups - Caught naming exception: ");
993
								nameEx.printStackTrace(System.err);
994
							}
995
						}
996
					}// end while
997

    
998
					moreReferrals = false;
999

    
1000
				} catch (ReferralException re) {
1001

    
1002
					logMetacat
1003
							.info("AuthLdap.getGroups -  caught referral exception: "
1004
									+ re.getReferralInfo());
1005
					this.currentReferralInfo = (String) re.getReferralInfo();
1006

    
1007
					// set moreReferrals to true and set the referral context
1008
					moreReferrals = true;
1009
					
1010
					// try following referral, skip if error
1011
					boolean referralError = true;
1012
					while (referralError) {
1013
						try {
1014
							ctx = (DirContext) re.getReferralContext();
1015
							referralError = false;
1016
						}
1017
						catch (NamingException ne) {
1018
							logMetacat.error("NamingException when getting referral contex. Skipping this referral. " + ne.getMessage());
1019
							re.skipReferral();
1020
							referralError = true;
1021
						}
1022
					}
1023

    
1024
				}// end inner try
1025
			}// end for
1026

    
1027
			// close the context now that all initial and referral
1028
			// searches are processed
1029
			ctx.close();
1030

    
1031
		} catch (NamingException e) {
1032

    
1033
			// naming exceptions get logged, groups are returned
1034
			logMetacat.info("AuthLdap.getGroups - caught naming exception: ");
1035
			e.printStackTrace(System.err);
1036

    
1037
		} finally {
1038
			// once all referrals are followed, report and return the groups
1039
			// found
1040
			logMetacat.warn("AuthLdap.getGroups - The user is in the following groups: " + gvec.toString());
1041
			// build and return the groups array
1042
			String groups[][] = new String[gvec.size()][2];
1043
			for (int i = 0; i < gvec.size(); i++) {
1044
				groups[i][0] = (String) gvec.elementAt(i);
1045
				groups[i][1] = (String) desc.elementAt(i);
1046
			}
1047
			return groups;
1048
		}// end outer try
1049
	}
1050

    
1051
	/**
1052
	 * Get attributes describing a user or group
1053
	 * 
1054
	 * @param foruser
1055
	 *            the user for which the attribute list is requested
1056
	 * @returns HashMap a map of attribute name to a Vector of values
1057
	 */
1058
	public HashMap<String, Vector<String>> getAttributes(String foruser)
1059
			throws ConnectException {
1060
		return getAttributes(null, null, foruser);
1061
	}
1062

    
1063
	/**
1064
	 * Get attributes describing a user or group
1065
	 * 
1066
	 * @param user
1067
	 *            the user for authenticating against the service
1068
	 * @param password
1069
	 *            the password for authenticating against the service
1070
	 * @param foruser
1071
	 *            the user whose attributes should be returned
1072
	 * @returns HashMap a map of attribute name to a Vector of values
1073
	 */
1074
	public HashMap<String, Vector<String>> getAttributes(String user, String password,
1075
			String foruser) throws ConnectException {
1076
		HashMap<String, Vector<String>> attributes = new HashMap<String, Vector<String>>();
1077
		String ldapUrl = this.ldapUrl;
1078
		String ldapBase = this.ldapBase;
1079
		String userident = foruser;
1080

    
1081
		// Identify service provider to use
1082
		Hashtable env = new Hashtable(11);
1083
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
1084
		env.put(Context.REFERRAL, referral);
1085
		env.put(Context.PROVIDER_URL, ldapUrl);
1086

    
1087
		try {
1088

    
1089
			// Create the initial directory context
1090
			DirContext ctx = new InitialDirContext(env);
1091

    
1092
			// Ask for all attributes of the user
1093
			// Attributes attrs = ctx.getAttributes(userident);
1094
			Attributes attrs = ctx.getAttributes(foruser);
1095

    
1096
			// Print all of the attributes
1097
			NamingEnumeration en = attrs.getAll();
1098
			while (en.hasMore()) {
1099
				Attribute att = (Attribute) en.next();
1100
				Vector<String> values = new Vector();
1101
				String attName = att.getID();
1102
				NamingEnumeration attvalues = att.getAll();
1103
				while (attvalues.hasMore()) {
1104
				    try {
1105
				        String value = (String) attvalues.next();
1106
				        values.add(value);
1107
				    } catch (ClassCastException cce) {
1108
				        logMetacat.debug("Could not cast LDAP attribute (" +
1109
				                attName + ") to a String value, so skipping.");
1110
				    }
1111
				}
1112
				attributes.put(attName, values);
1113
			}
1114

    
1115
			// Close the context when we're done
1116
			ctx.close();
1117
		} catch (NamingException e) {
1118
			logMetacat.error("AuthLdap.getAttributes - Problem getting attributes:"
1119
					+ e);
1120
			throw new ConnectException(
1121
					"Problem getting attributes in AuthLdap.getAttributes:" + e);
1122
		}
1123

    
1124
		return attributes;
1125
	}
1126

    
1127
	/**
1128
	 * Get list of all subtrees holding Metacat's groups and users starting from
1129
	 * the Metacat LDAP root, i.e.
1130
	 * ldap://dev.nceas.ucsb.edu/dc=ecoinformatics,dc=org
1131
	 */
1132
	private Hashtable getSubtrees(String user, String password, String ldapUrl,
1133
			String ldapBase) throws ConnectException {
1134
		logMetacat.debug("AuthLdap.getSubtrees - getting subtrees for user: " + user + 
1135
				", ldapUrl: " + ldapUrl + ", ldapBase: " + ldapBase);
1136
		Hashtable trees = new Hashtable();
1137

    
1138
		// Identify service provider to use
1139
		Hashtable env = new Hashtable(11);
1140
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
1141
		// env.put(Context.REFERRAL, referral);
1142
		// Using 'ignore' here instead of 'follow' as 'ignore' seems
1143
		// to do the job better. 'follow' was not bringing up the UCNRS
1144
		// and PISCO tree whereas 'ignore' brings up the tree.
1145

    
1146
		env.put(Context.REFERRAL, "ignore");
1147
		env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
1148

    
1149
		try {
1150

    
1151
			// Create the initial directory context
1152
			DirContext ctx = new InitialDirContext(env);
1153

    
1154
			// Specify the ids of the attributes to return
1155
			String[] attrIDs = { "o", "ref" };
1156
			SearchControls ctls = new SearchControls();
1157
			ctls.setReturningAttributes(attrIDs);
1158
			ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
1159

    
1160
			// Specify the attributes to match.
1161
			// Subtrees from the main server are found as objects with attribute
1162
			// objectclass=organization or objectclass=referral to the subtree
1163
			// resided on other server.
1164
			String filter = "(|(objectclass=organization)(objectclass=referral))";
1165

    
1166
			// Search for objects in the current context
1167
			NamingEnumeration namingEnum = ctx.search("", filter, ctls);
1168

    
1169
			// Print the subtrees' <ldapURL, baseDN>
1170
			while (namingEnum.hasMore()) {
1171

    
1172
				SearchResult sr = (SearchResult) namingEnum.next();
1173
				logMetacat.debug("AuthLdap.getSubtrees - search result: " + sr.toString());
1174

    
1175
				Attributes attrs = sr.getAttributes();
1176
				NamingEnumeration enum1 = attrs.getAll(); // "dc" and "ref"
1177
															// attrs
1178

    
1179
				if (enum1.hasMore()) {
1180
					Attribute attr = (Attribute) enum1.next();
1181
					String attrValue = (String) attr.get();
1182
					String attrName = (String) attr.getID();
1183

    
1184
					if (enum1.hasMore()) {
1185
						attr = (Attribute) enum1.next();
1186
						String refValue = (String) attr.get();
1187
						String refName = (String) attr.getID();
1188
						if (ldapBase.startsWith(refName + "=" + refValue)) {
1189
							trees.put(ldapBase, attrValue.substring(0, attrValue
1190
									.lastIndexOf("/") + 1));
1191
						} else {
1192
							// this is a referral - so organization name is
1193
							// appended in front of the ldapbase.... later it is 
1194
							// stripped out in getPrincipals
1195
							trees.put("[" + refName + "=" + refValue + "]" + 
1196
									attrValue.substring(attrValue.lastIndexOf("/") + 1,
1197
											attrValue.length()), attrValue.substring(0,
1198
													attrValue.lastIndexOf("/") + 1));
1199

    
1200
							// trees.put(refName + "=" + refValue + "," +
1201
							// ldapBase, attrValue.substring(0, attrValue.lastIndexOf("/")
1202
							// + 1));
1203
						}
1204

    
1205
					} else if (ldapBase.startsWith(attrName + "=" + attrValue)) {
1206
						trees.put(ldapBase, ldapUrl);
1207
					} else {
1208
						if (sr.isRelative()) {
1209
							trees.put(attrName + "=" + attrValue + "," + ldapBase,
1210
									ldapUrl);
1211
						} else {
1212
							String referenceURL = sr.getName();
1213
							referenceURL = referenceURL.substring(0, referenceURL
1214
									.lastIndexOf("/") + 1);
1215
							trees.put(attrName + "=" + attrValue + "," + ldapBase,
1216
									referenceURL);
1217
						}
1218

    
1219
					}
1220
				}
1221
			}
1222

    
1223
			// Close the context when we're done
1224
			ctx.close();
1225

    
1226
		} catch (NamingException e) {
1227
			logMetacat.error("AuthLdap.getSubtrees - Problem getting subtrees in AuthLdap.getSubtrees:" + e);
1228
			throw new ConnectException(
1229
					"Problem getting subtrees in AuthLdap.getSubtrees:" + e);
1230
		}
1231

    
1232
		return trees;
1233
	}
1234

    
1235
	/**
1236
	 * Get all groups and users from authentication scheme. The output is
1237
	 * formatted in XML.
1238
	 * 
1239
	 * @param user
1240
	 *            the user which requests the information
1241
	 * @param password
1242
	 *            the user's password
1243
	 */
1244
	public String getPrincipals(String user, String password) throws ConnectException {
1245
		StringBuffer out = new StringBuffer();
1246

    
1247
		out.append("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n");
1248
		out.append("<principals>\n");
1249

    
1250
		/*
1251
		 * get all subtrees first in the current dir context and then the
1252
		 * Metacat users under them
1253
		 */
1254
		Hashtable subtrees = getSubtrees(user, password, this.ldapUrl, this.ldapBase);
1255

    
1256
		Enumeration keyEnum = subtrees.keys();
1257
		while (keyEnum.hasMoreElements()) {
1258
			this.ldapBase = (String) keyEnum.nextElement();
1259
			this.ldapUrl = (String) subtrees.get(ldapBase);
1260
			logMetacat.info("AuthLdap.getPrincipals - ldapBase: " + ldapBase + 
1261
					", ldapUrl: " + ldapUrl);
1262
			/*
1263
			 * code to get the organization name from ldapBase
1264
			 */
1265
			String orgName = this.ldapBase;
1266
			if (orgName.startsWith("[")) {
1267
				// if orgName starts with [ then it is a referral URL...
1268
				// (see code in getSubtress) hence orgName can be retrieved by 
1269
				// getting the string between 'o=' and ']' also the string between 
1270
				// [ and ] needs to be striped out from this.ldapBase
1271
				this.ldapBase = orgName.substring(orgName.indexOf("]") + 1);
1272
				if (orgName != null && orgName.indexOf("o=") > -1) {
1273
					orgName = orgName.substring(orgName.indexOf("o=") + 2);
1274
					orgName = orgName.substring(0, orgName.indexOf("]"));
1275
				}
1276
			} else {
1277
				// else it is not referral
1278
				// hence orgName can be retrieved by getting the string between
1279
				// 'o=' and ','
1280
				if (orgName != null && orgName.indexOf("o=") > -1) {
1281
					orgName = orgName.substring(orgName.indexOf("o=") + 2);
1282
					if (orgName.indexOf(",") > -1) {
1283
						orgName = orgName.substring(0, orgName.indexOf(","));
1284
					}
1285
				}
1286
			}
1287
			logMetacat.info("AuthLdap.getPrincipals - org name is  " + orgName);
1288
			out.append("  <authSystem URI=\"" + this.ldapUrl + this.ldapBase
1289
					+ "\" organization=\"" + orgName + "\">\n");
1290

    
1291
			// get all groups for directory context
1292
			String[][] groups = getGroups(user, password);
1293
			logMetacat.debug("AuthLdap.getPrincipals - after getting groups " + groups);
1294
			String[][] users = getUsers(user, password);
1295
			logMetacat.debug("AuthLdap.getPrincipals - after getting users " + users);
1296
			int userIndex = 0;
1297

    
1298
			// for the groups and users that belong to them
1299
			if (groups != null && users != null && groups.length > 0) {
1300
				for (int i = 0; i < groups.length; i++) {
1301
					out.append("    <group>\n");
1302
					out.append("      <groupname>" + groups[i][0] + "</groupname>\n");
1303
					out.append("      <description>" + groups[i][1] + "</description>\n");
1304
					String[] usersForGroup = getUsers(user, password, groups[i][0]);
1305
					for (int j = 0; j < usersForGroup.length; j++) {
1306
						userIndex = searchUser(usersForGroup[j], users);
1307
						out.append("      <user>\n");
1308

    
1309
						if (userIndex < 0) {
1310
							out.append("        <username>" + usersForGroup[j]
1311
									+ "</username>\n");
1312
						} else {
1313
							out.append("        <username>" + users[userIndex][0]
1314
									+ "</username>\n");
1315
							out.append("        <name>" + users[userIndex][1]
1316
									+ "</name>\n");
1317
							out.append("        <organization>" + users[userIndex][2]
1318
									+ "</organization>\n");
1319
							if (users[userIndex][3].compareTo("null") != 0) {
1320
								out.append("      <organizationUnitName>"
1321
										+ users[userIndex][3]
1322
										+ "</organizationUnitName>\n");
1323
							}
1324
							out.append("        <email>" + users[userIndex][4]
1325
									+ "</email>\n");
1326
						}
1327

    
1328
						out.append("      </user>\n");
1329
					}
1330
					out.append("    </group>\n");
1331
				}
1332
			}
1333

    
1334
			if (users != null) {
1335
				// for the users not belonging to any grou8p
1336
				for (int j = 0; j < users.length; j++) {
1337
					out.append("    <user>\n");
1338
					out.append("      <username>" + users[j][0] + "</username>\n");
1339
					out.append("      <name>" + users[j][1] + "</name>\n");
1340
					out
1341
							.append("      <organization>" + users[j][2]
1342
									+ "</organization>\n");
1343
					if (users[j][3].compareTo("null") != 0) {
1344
						out.append("      <organizationUnitName>" + users[j][3]
1345
								+ "</organizationUnitName>\n");
1346
					}
1347
					out.append("      <email>" + users[j][4] + "</email>\n");
1348
					out.append("    </user>\n");
1349
				}
1350
			}
1351

    
1352
			out.append("  </authSystem>\n");
1353
		}
1354
		out.append("</principals>");
1355
		return out.toString();
1356
	}
1357

    
1358
	/**
1359
	 * Method for getting index of user DN in User info array
1360
	 */
1361
	public static int searchUser(String user, String userGroup[][]) {
1362
		for (int j = 0; j < userGroup.length; j++) {
1363
			if (user.compareTo(userGroup[j][0]) == 0) {
1364
				return j;
1365
			}
1366
		}
1367
		return -1;
1368
	}
1369

    
1370
	public void testCredentials(String dn, String password, String rootServer,
1371
			String rootBase) throws NamingException {
1372

    
1373
		String server = "";
1374
		String userDN = "";
1375
		logMetacat.debug("dn is: " + dn);
1376

    
1377
		int position = dn.lastIndexOf("/");
1378
		logMetacat.debug("AuthLdap.testCredentials - position is: " + position);
1379
		if (position == -1) {
1380
			server = rootServer;
1381
			if (dn.indexOf(userDN) < 0) {
1382
				userDN = dn + "," + rootBase;
1383
			} else {
1384
				userDN = dn;
1385
			}
1386
			logMetacat.debug("AuthLdap.testCredentials - userDN is: " + userDN);
1387

    
1388
		} else {
1389
			server = dn.substring(0, position + 1);
1390
			userDN = dn.substring(position + 1);
1391
			logMetacat.debug("AuthLdap.testCredentials - server is: " + server);
1392
			logMetacat.debug("AuthLdap.testCredentials - userDN is: " + userDN);
1393
		}
1394

    
1395
		logMetacat.debug("AuthLdap.testCredentials - Trying to authenticate: " + userDN + " using server: " + server);
1396

    
1397
		// /* try {
1398
		LdapContext ctx = null;
1399

    
1400
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
1401
		env.put(Context.REFERRAL, "follow");
1402
		env.put(Context.SECURITY_AUTHENTICATION, "simple");
1403
		env.put(Context.SECURITY_PRINCIPAL, userDN);
1404
		env.put(Context.SECURITY_CREDENTIALS, password);
1405
		env.put(Context.PROVIDER_URL, rootServer);
1406

    
1407
		ctx = new InitialLdapContext(env, null);
1408

    
1409
	}
1410

    
1411
	/**
1412
	 * Test method for the class
1413
	 */
1414
	public static void main(String[] args) {
1415

    
1416
		// Provide a user, such as: "Matt Jones", or "jones"
1417
		String user = args[0];
1418
		String password = args[1];
1419
		String org = args[2];
1420

    
1421
		logMetacat.warn("AuthLdap.main - Creating session...");
1422
		AuthLdap authservice = null;
1423
		try {
1424
			authservice = new AuthLdap();
1425
		} catch (Exception e) {
1426
			logMetacat.error("AuthLdap.main - Could not instantiate AuthLdap: " + e.getMessage());
1427
			return;
1428
		}
1429
		logMetacat.warn("AuthLdap.main - Session exists...");
1430

    
1431
		boolean isValid = false;
1432
		try {
1433
			logMetacat.warn("AuthLdap.main - Authenticating...");
1434
			isValid = authservice.authenticate(user, password);
1435
			if (isValid) {
1436
				logMetacat.warn("AuthLdap.main - Authentication successful for: " + user);
1437
			} else {
1438
				logMetacat.warn("AuthLdap.main - Authentication failed for: " + user);
1439
			}
1440

    
1441
			// Get attributes for the user
1442
			if (isValid) {
1443
				logMetacat.info("AuthLdap.main - Getting attributes for user....");
1444
				HashMap userInfo = authservice.getAttributes(user, password, user);
1445
				// Print all of the attributes
1446
				Iterator attList = (Iterator) (((Set) userInfo.keySet()).iterator());
1447
				while (attList.hasNext()) {
1448
					String att = (String) attList.next();
1449
					Vector values = (Vector) userInfo.get(att);
1450
					Iterator attvalues = values.iterator();
1451
					while (attvalues.hasNext()) {
1452
						String value = (String) attvalues.next();
1453
						logMetacat.warn("AuthLdap.main - " + att + ": " + value);
1454
					}
1455
				}
1456
			}
1457

    
1458
			// get the groups
1459
			if (isValid) {
1460
				logMetacat.warn("AuthLdap.main - Getting all groups....");
1461
				String[][] groups = authservice.getGroups(user, password);
1462
				logMetacat.info("AuthLdap.main - Groups found: " + groups.length);
1463
				for (int i = 0; i < groups.length; i++) {
1464
					logMetacat.info("AuthLdap.main - Group " + i + ": " + groups[i][0]);
1465
				}
1466
			}
1467

    
1468
			// get the groups for the user
1469
			String savedGroup = null;
1470
			if (isValid) {
1471
				logMetacat.warn("AuthLdap.main - Getting groups for user....");
1472
				String[][] groups = authservice.getGroups(user, password, user);
1473
				logMetacat.info("AuthLdap.main - Groups found: " + groups.length);
1474
				for (int i = 0; i < groups.length; i++) {
1475
					logMetacat.info("AuthLdap.main - Group " + i + ": " + groups[i][0]);
1476
					savedGroup = groups[i][0];
1477
				}
1478
			}
1479

    
1480
			// get the users for a group
1481
			if (isValid) {
1482
				logMetacat.warn("AuthLdap.main - Getting users for group....");
1483
				logMetacat.info("AuthLdap.main - Group: " + savedGroup);
1484
				String[] users = authservice.getUsers(user, password, savedGroup);
1485
				logMetacat.info("AuthLdap.main - Users found: " + users.length);
1486
				for (int i = 0; i < users.length; i++) {
1487
					logMetacat.warn("AuthLdap.main - User " + i + ": " + users[i]);
1488
				}
1489
			}
1490

    
1491
			// get all users
1492
			if (isValid) {
1493
				logMetacat.warn("AuthLdap.main - Getting all users ....");
1494
				String[][] users = authservice.getUsers(user, password);
1495
				logMetacat.info("AuthLdap.main - Users found: " + users.length);
1496

    
1497
			}
1498

    
1499
			// get the whole list groups and users in XML format
1500
			if (isValid) {
1501
				logMetacat.warn("AuthLdap.main - Trying principals....");
1502
				authservice = new AuthLdap();
1503
				String out = authservice.getPrincipals(user, password);
1504
				java.io.File f = new java.io.File("principals.xml");
1505
				java.io.FileWriter fw = new java.io.FileWriter(f);
1506
				java.io.BufferedWriter buff = new java.io.BufferedWriter(fw);
1507
				buff.write(out);
1508
				buff.flush();
1509
				buff.close();
1510
				fw.close();
1511
				logMetacat.warn("AuthLdap.main - Finished getting principals.");
1512
			}
1513

    
1514
		} catch (ConnectException ce) {
1515
			logMetacat.error("AuthLdap.main - " + ce.getMessage());
1516
		} catch (java.io.IOException ioe) {
1517
			logMetacat.error("AuthLdap.main - I/O Error writing to file principals.txt: "
1518
					+ ioe.getMessage());
1519
		} catch (InstantiationException ie) {
1520
			logMetacat.error("AuthLdap.main - Instantiation error writing to file principals.txt: "
1521
					+ ie.getMessage());
1522
		}
1523
	}
1524

    
1525
	/**
1526
	 * This method will be called by start a thread. It can handle if a referral
1527
	 * exception happend.
1528
	 */
1529
}
(6-6/63)