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: 2015-12-08 16:49:23 -0800 (Tue, 08 Dec 2015) $'
12
 * '$Revision: 9441 $'
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
import org.apache.commons.lang.StringEscapeUtils;
52

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
217
		return authenticated;
218
	}
219

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

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

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

    
249
		boolean authenticated = false;
250

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

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

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

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

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

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

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

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

    
448
		return true;
449
	}
450

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

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

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

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

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

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

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

    
543
		try {
544

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

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

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

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

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

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

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

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

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

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

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

    
625
		return users;
626
	}
627

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

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

    
657
		try {
658

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

    
672
			String filter = null;
673

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

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

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

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

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

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

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

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

    
723
		return userinfo;
724
	}
725

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

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

    
747
		try {
748

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

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

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

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

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

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

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

    
789
		return users;
790
	}
791

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

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

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

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

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

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

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

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

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

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

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

    
891
						tempAttr = sr.getAttributes();
892

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

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

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

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

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

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

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

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

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

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

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

    
999
					moreReferrals = false;
1000

    
1001
				} catch (ReferralException re) {
1002

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

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

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

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

    
1032
		} catch (NamingException e) {
1033

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

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

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

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

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

    
1088
		try {
1089

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

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

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

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

    
1125
		return attributes;
1126
	}
1127

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

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

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

    
1150
		try {
1151

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

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

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

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

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

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

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

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

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

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

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

    
1220
					}
1221
				}
1222
			}
1223

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

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

    
1233
		return trees;
1234
	}
1235

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

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

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

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

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

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

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

    
1331
						out.append("      </user>\n");
1332
					}
1333
					out.append("    </group>\n");
1334
				}
1335
			}
1336

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

    
1355
			out.append("  </authSystem>\n");
1356
		}
1357
		out.append("</principals>");
1358
		return out.toString();
1359
	}
1360

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

    
1373
	public void testCredentials(String dn, String password, String rootServer,
1374
			String rootBase) throws NamingException {
1375

    
1376
		String server = "";
1377
		String userDN = "";
1378
		logMetacat.debug("dn is: " + dn);
1379

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

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

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

    
1400
		// /* try {
1401
		LdapContext ctx = null;
1402

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

    
1410
		ctx = new InitialLdapContext(env, null);
1411

    
1412
	}
1413

    
1414
	/**
1415
	 * Test method for the class
1416
	 */
1417
	public static void main(String[] args) {
1418

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

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

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

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

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

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

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

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

    
1500
			}
1501

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

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

    
1528
	/**
1529
	 * This method will be called by start a thread. It can handle if a referral
1530
	 * exception happend.
1531
	 */
1532
}
(6-6/64)