Project

General

Profile

1 503 bojilova
/**
2
 *  '$RCSfile$'
3
 *    Purpose: An implementation of the AuthInterface interface that
4
 *             allows Metacat to use the LDAP protocol for
5
 *             directory services
6
 *  Copyright: 2000 Regents of the University of California and the
7
 *             National Center for Ecological Analysis and Synthesis
8
 *    Authors: Matt Jones
9
 *
10
 *   '$Author$'
11
 *     '$Date$'
12
 * '$Revision$'
13 669 jones
 *
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 503 bojilova
 */
28
29
package edu.ucsb.nceas.metacat;
30
31
import java.net.ConnectException;
32
import javax.naming.AuthenticationException;
33
import javax.naming.Context;
34 787 bojilova
import javax.naming.NamingEnumeration;
35
import javax.naming.NamingException;
36 873 jones
import javax.naming.SizeLimitExceededException;
37 503 bojilova
import javax.naming.directory.Attribute;
38
import javax.naming.directory.Attributes;
39 504 jones
import javax.naming.directory.DirContext;
40
import javax.naming.directory.InitialDirContext;
41
import javax.naming.directory.SearchResult;
42 723 bojilova
import javax.naming.directory.SearchControls;
43 868 berkley
import javax.naming.ReferralException;
44 3022 sgarg
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 2666 sgarg
50
import org.apache.log4j.Logger;
51 9441 tao
import org.apache.commons.lang.StringEscapeUtils;
52 2666 sgarg
53 5030 daigle
import edu.ucsb.nceas.metacat.properties.PropertyService;
54 4080 daigle
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
55
56 5157 daigle
import java.io.IOException;
57 4080 daigle
import java.lang.InstantiationException;
58 1988 jones
import java.net.URLDecoder;
59 503 bojilova
import java.util.Iterator;
60
import java.util.HashMap;
61
import java.util.Hashtable;
62 730 bojilova
import java.util.Enumeration;
63 503 bojilova
import java.util.Set;
64
import java.util.Vector;
65
66
/**
67 4629 daigle
 * 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 503 bojilova
 */
72 3155 cjones
public class AuthLdap implements AuthInterface {
73 4629 daigle
	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 5158 daigle
	Hashtable<String, String> env = new Hashtable<String, String>(11);
82 4629 daigle
	private Context rContext;
83
	private String userName;
84
	private String userPassword;
85
	ReferralException refExc;
86 503 bojilova
87 4629 daigle
	private static Logger logMetacat = Logger.getLogger(AuthLdap.class);
88
89
	/**
90 4080 daigle
	 * Construct an AuthLdap
91
	 */
92
	public AuthLdap() throws InstantiationException {
93
		// Read LDAP URI for directory service information
94
		try {
95 4587 daigle
			this.ldapUrl = PropertyService.getProperty("auth.url");
96
			this.ldapsUrl = PropertyService.getProperty("auth.surl");
97 4729 daigle
			this.ldapBase = PropertyService.getProperty("auth.base");
98 4080 daigle
			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 728 bojilova
115 4080 daigle
		// Store referral info for use in building group DNs in getGroups()
116
		this.currentReferralInfo = "";
117
	}
118
119 4629 daigle
	/**
120 4080 daigle
	 * 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 4629 daigle
	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 3022 sgarg
136 4629 daigle
		// 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 3022 sgarg
144 5157 daigle
		logMetacat.debug("AuthLdap.authenticate - identifier: " + identifier +
145
				", uid: " + uid +", user: " + user);
146 3022 sgarg
147 4629 daigle
		try {
148
			// Check the usename as passed in
149 5157 daigle
			logMetacat.info("AuthLdap.authenticate - Calling ldapAuthenticate" +
150
				" with user as identifier: " + identifier);
151 3022 sgarg
152 4629 daigle
			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 5157 daigle
				logMetacat.info("AuthLdap.authenticate - Not Authenticated");
158
				logMetacat.info("AuthLdap.authenticate - Looking up DN for: " + identifier);
159 4629 daigle
				identifier = getIdentifyingName(identifier, ldapUrl, ldapBase);
160
				if (identifier == null) {
161 5157 daigle
					logMetacat.info("AuthLdap.authenticate - No DN found from getIdentifyingName");
162 4629 daigle
					return authenticated;
163
				}
164 503 bojilova
165 5157 daigle
				logMetacat.info("AuthLdap.authenticate - DN found from getIdentifyingName: " + identifier);
166 4629 daigle
				String decoded = URLDecoder.decode(identifier);
167 5157 daigle
				logMetacat.info("AuthLdap.authenticate - DN decoded: " + decoded);
168 4629 daigle
				identifier = decoded;
169
				String refUrl = "";
170
				String refBase = "";
171
				if (identifier.startsWith("ldap")) {
172 5157 daigle
					logMetacat.debug("AuthLdap.authenticate - identifier starts with \"ldap\"");
173 1005 jones
174 4629 daigle
					refUrl = identifier.substring(0, identifier.lastIndexOf("/") + 1);
175
					int position = identifier.indexOf(",");
176
					int position2 = identifier.indexOf(",", position + 1);
177 2058 sgarg
178 4629 daigle
					refBase = identifier.substring(position2 + 1);
179
					identifier = identifier.substring(identifier.lastIndexOf("/") + 1);
180 3022 sgarg
181 5157 daigle
					logMetacat.info("AuthLdap.authenticate - Calling ldapAuthenticate: " +
182
						"with user as identifier: " + identifier + " and refUrl as: " +
183
						refUrl + " and refBase as: " + refBase);
184 934 tao
185 4629 daigle
					authenticated = ldapAuthenticate(identifier, password, refUrl,
186
							refBase, (new Boolean(PropertyService
187
									.getProperty("ldap.onlySecureReferalsConnection")))
188
									.booleanValue());
189
				} else {
190 5157 daigle
					logMetacat.info("AuthLdap.authenticate - identifier doesnt start with ldap");
191 4629 daigle
					identifier = identifier + "," + ldapBase;
192 852 jones
193 5157 daigle
					logMetacat.info("AuthLdap.authenticate - Calling ldapAuthenticate" +
194
							"with user as identifier: " + identifier);
195 3022 sgarg
196 4629 daigle
					authenticated = ldapAuthenticate(identifier, password, (new Boolean(
197
							PropertyService.getProperty("ldap.onlySecureConnection")))
198
							.booleanValue());
199
				}
200
			}
201 5157 daigle
		} catch (NullPointerException npe) {
202
			logMetacat.error("AuthLdap.authenticate - NullPointerException while authenticating in "
203
					+ "AuthLdap.authenticate: " + npe);
204
			npe.printStackTrace();
205 4080 daigle
206 5157 daigle
			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 4629 daigle
		}
216 723 bojilova
217 4629 daigle
		return authenticated;
218
	}
219 2058 sgarg
220 4629 daigle
	/**
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 723 bojilova
236 4629 daigle
	/**
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 723 bojilova
246 4629 daigle
	private boolean ldapAuthenticate(String dn, String password, String rootServer,
247
			String rootBase, boolean secureConnectionOnly) {
248 2058 sgarg
249 4629 daigle
		boolean authenticated = false;
250 2058 sgarg
251 4629 daigle
		String server = "";
252
		String userDN = "";
253 5157 daigle
		logMetacat.info("AuthLdap.ldapAuthenticate - dn is: " + dn);
254 2058 sgarg
255 4629 daigle
		int position = dn.lastIndexOf("/");
256 5157 daigle
		logMetacat.debug("AuthLdap.ldapAuthenticate - position is: " + position);
257 4629 daigle
		if (position == -1) {
258
			server = rootServer;
259
			if (dn.indexOf(userDN) < 0) {
260
				userDN = dn + "," + rootBase;
261
			} else {
262
				userDN = dn;
263
			}
264 5157 daigle
			logMetacat.info("AuthLdap.ldapAuthenticate - userDN is: " + userDN);
265 2116 sgarg
266 4629 daigle
		} else {
267
			server = dn.substring(0, position + 1);
268
			userDN = dn.substring(position + 1);
269 5157 daigle
			logMetacat.info("AuthLdap.ldapAuthenticate - server is: " + server);
270
			logMetacat.info("AuthLdap.ldapAuthenticate - userDN is: " + userDN);
271 4629 daigle
		}
272 2130 sgarg
273 5157 daigle
		logMetacat.warn("AuthLdap.ldapAuthenticate - Trying to authenticate: " +
274
				userDN + " Using server: " + server);
275 2058 sgarg
276 4629 daigle
		try {
277 5158 daigle
			Hashtable<String, String> env = new Hashtable<String, String>();
278 4629 daigle
			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 5158 daigle
282 4629 daigle
			try {
283 5158 daigle
				authenticated = authenticateTLS(env, userDN, password);
284 8461 tao
			} 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 5158 daigle
			} catch (AuthTLSException ate) {
301
				logMetacat.info("AuthLdap.ldapAuthenticate - error while negotiating TLS: "
302
						+ ate.getMessage());
303 4629 daigle
				if (secureConnectionOnly) {
304
					return authenticated;
305 8461 tao
				} 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 723 bojilova
325 4629 daigle
				}
326
			}
327
		} catch (AuthenticationException ae) {
328 5157 daigle
			logMetacat.warn("Authentication exception: " + ae.getMessage());
329 4629 daigle
			authenticated = false;
330
		} catch (javax.naming.InvalidNameException ine) {
331 5157 daigle
			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 4629 daigle
		}
336 503 bojilova
337 4629 daigle
		return authenticated;
338
	}
339 5158 daigle
340 8460 tao
341 8459 tao
	/*
342 8463 tao
	 * Get the aliased dn through a TLS connection. The null will be returned if there is no real name associated with the alias
343 8460 tao
	 */
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 8463 tao
     * 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 8460 tao
     */
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 8459 tao
	 * Get the aliasedDN (the real DN) for a specified an alias name
359
	 */
360 8461 tao
	private String getAliasedDn(String alias, Hashtable<String, String> env, boolean useTLS) throws NamingException, IOException  {
361 8459 tao
	    String aliasedDn = null;
362 8650 tao
	    if(env != null) {
363
	        env.put(Context.REFERRAL, "ignore");
364
	    }
365 8460 tao
        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 8459 tao
        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 8460 tao
        if(useTLS && tls != null) {
386
            tls.close();
387
        }
388
        sctx.close();
389 8459 tao
        return aliasedDn;
390
391
	}
392 8460 tao
393 5158 daigle
	private boolean authenticateTLS(Hashtable<String, String> env, String userDN, String password)
394 8461 tao
			throws AuthTLSException, AuthenticationException{
395 5158 daigle
		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 8461 tao
		} catch (AuthenticationException ae) {
416
            logMetacat.warn("AuthLdap.authenticateTLS - Authentication exception: " + ae.getMessage());
417
            throw ae;
418
419 5158 daigle
		} 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 8703 tao
		//env.put(Context.SECURITY_AUTHENTICATION, "simple");
435
		//env.put(Context.SECURITY_PRINCIPAL, userDN);
436
		//env.put(Context.SECURITY_CREDENTIALS, password);
437 2679 sgarg
438 5158 daigle
		startTime = System.currentTimeMillis();
439
		ctx = new InitialLdapContext(env, null);
440 8703 tao
		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 5158 daigle
		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 4629 daigle
	/**
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 2679 sgarg
463 4629 daigle
		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 5167 daigle
			logMetacat.info("AuthLdap.getIdentifyingName - uid is: " + uid);
472 4629 daigle
			String org = user.substring(user.indexOf("=", position + 1) + 1, user
473
					.indexOf(",", position + 1));
474 5167 daigle
			logMetacat.info("AuthLdap.getIdentifyingName - org is: " + org);
475 2697 sgarg
476 4629 daigle
			DirContext sctx = new InitialDirContext(env);
477
			SearchControls ctls = new SearchControls();
478
			ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
479
			String filter = "(&(uid=" + uid + ")(o=" + org + "))";
480 5167 daigle
			logMetacat.warn("AuthLdap.getIdentifyingName - Searching for DNs with following filter: " + filter);
481 2679 sgarg
482 4629 daigle
			for (boolean moreReferrals = true; moreReferrals;) {
483
				try {
484
					// Perform the search
485 5629 berkley
486 4629 daigle
					NamingEnumeration answer = sctx.search("", filter, ctls);
487 2679 sgarg
488 4629 daigle
					// 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 5167 daigle
					logMetacat.info("AuthLdap.getIdentifyingName - Got referral: " + e.getReferralInfo());
498 4629 daigle
					// Point to the new context from the referral
499
					if (moreReferrals) {
500 5292 leinfelder
						// 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 4629 daigle
					}
514 5292 leinfelder
				}
515 4629 daigle
			}
516
		} catch (NamingException e) {
517 5167 daigle
			logMetacat.error("AuthLdap.getIdentifyingName - Naming exception while getting dn: " + e);
518 4629 daigle
			throw new NamingException("Naming exception in AuthLdap.getIdentifyingName: "
519
					+ e);
520
		}
521
		return identifier;
522
	}
523 2679 sgarg
524 4629 daigle
	/**
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 2679 sgarg
536 4629 daigle
		// 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 2679 sgarg
543 4629 daigle
		try {
544 2679 sgarg
545 4629 daigle
			// Create the initial directory context
546
			DirContext ctx = new InitialDirContext(env);
547 2679 sgarg
548 4629 daigle
			// 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 723 bojilova
560 4629 daigle
			// 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 723 bojilova
572 4629 daigle
					if ((tempAttr.get("cn") + "").startsWith("cn: ")) {
573
						uname.add((tempAttr.get("cn") + "").substring(4));
574
					} else {
575
						uname.add(tempAttr.get("cn") + "");
576
					}
577 723 bojilova
578 4629 daigle
					if ((tempAttr.get("o") + "").startsWith("o: ")) {
579
						uorg.add((tempAttr.get("o") + "").substring(3));
580
					} else {
581
						uorg.add(tempAttr.get("o") + "");
582
					}
583 723 bojilova
584 4629 daigle
					if ((tempAttr.get("ou") + "").startsWith("ou: ")) {
585
						uou.add((tempAttr.get("ou") + "").substring(4));
586
					} else {
587
						uou.add(tempAttr.get("ou") + "");
588
					}
589 723 bojilova
590 4629 daigle
					if ((tempAttr.get("mail") + "").startsWith("mail: ")) {
591
						umail.add((tempAttr.get("mail") + "").substring(6));
592
					} else {
593
						umail.add(tempAttr.get("mail") + "");
594
					}
595 723 bojilova
596 4629 daigle
					uvec.add(sr.getName() + "," + ldapBase);
597
				}
598
			} catch (SizeLimitExceededException slee) {
599 5167 daigle
				logMetacat.error("AuthLdap.getUsers - LDAP Server size limit exceeded. "
600 4629 daigle
						+ "Returning incomplete record set.");
601
			}
602 723 bojilova
603 4629 daigle
			// 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 723 bojilova
613 4629 daigle
			// Close the context when we're done
614
			ctx.close();
615 723 bojilova
616 4629 daigle
		} catch (NamingException e) {
617 5167 daigle
			logMetacat.error("AuthLdap.getUsers - Problem getting users in AuthLdap.getUsers:" + e);
618 4629 daigle
			// e.printStackTrace(System.err);
619
			/*
620
			 * throw new ConnectException( "Problem getting users in
621
			 * AuthLdap.getUsers:" + e);
622
			 */
623
		}
624 723 bojilova
625 4629 daigle
		return users;
626
	}
627 503 bojilova
628 4629 daigle
	/**
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 503 bojilova
640 8650 tao
		logMetacat.info("AuthLdap.getUserInfo - get the user info for user  "+user);
641 4629 daigle
		// Identify service provider to use
642
		Hashtable env = new Hashtable(11);
643 8650 tao
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
644 4629 daigle
		env.put(Context.PROVIDER_URL, ldapUrl);
645 8463 tao
		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 8651 tao
		logMetacat.info("AuthLdap.getUserInfo - the aliased dn for "+user+" is "+realName);
652 8463 tao
		if(realName != null) {
653
		    //the the user is an alias name. we need to use the the real name
654
		    user = realName;
655
		}
656 2058 sgarg
657 4629 daigle
		try {
658 991 tao
659 4629 daigle
			// Create the initial directory context
660 8650 tao
		    env.put(Context.REFERRAL, referral);
661 4629 daigle
			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 2058 sgarg
672 4629 daigle
			String filter = null;
673 991 tao
674 8556 tao
			/*if (user.indexOf("o=") > 0) {
675 4629 daigle
				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 8556 tao
			}*/
681 4629 daigle
			filter = "(&(" + user.substring(0, user.indexOf(",")) + "))";
682 503 bojilova
683 4629 daigle
			NamingEnumeration namingEnum = ctx.search(user, filter, ctls);
684 503 bojilova
685 4629 daigle
			Attributes tempAttr = null;
686
			try {
687
				while (namingEnum.hasMore()) {
688
					SearchResult sr = (SearchResult) namingEnum.next();
689
					tempAttr = sr.getAttributes();
690 2058 sgarg
691 4629 daigle
					if ((tempAttr.get("cn") + "").startsWith("cn: ")) {
692
						userinfo[0] = (tempAttr.get("cn") + "").substring(4);
693
					} else {
694
						userinfo[0] = (tempAttr.get("cn") + "");
695
					}
696 503 bojilova
697 4629 daigle
					if ((tempAttr.get("o") + "").startsWith("o: ")) {
698
						userinfo[1] = (tempAttr.get("o") + "").substring(3);
699
					} else {
700
						userinfo[1] = (tempAttr.get("o") + "");
701
					}
702 2058 sgarg
703 4629 daigle
					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 5167 daigle
				logMetacat.error("AuthLdap.getUserInfo - LDAP Server size limit exceeded. "
711 4629 daigle
						+ "Returning incomplete record set.");
712
			}
713 2058 sgarg
714 4629 daigle
			// Close the context when we're done
715
			ctx.close();
716 2058 sgarg
717 4629 daigle
		} catch (NamingException e) {
718 5167 daigle
			logMetacat.error("AuthLdap.getUserInfo - Problem getting users:" + e);
719 4629 daigle
			// e.printStackTrace(System.err);
720
			throw new ConnectException("Problem getting users in AuthLdap.getUsers:" + e);
721
		}
722 2058 sgarg
723 4629 daigle
		return userinfo;
724
	}
725 503 bojilova
726 4629 daigle
	/**
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 503 bojilova
741 4629 daigle
		// 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 504 jones
747 4629 daigle
		try {
748 2129 sgarg
749 4629 daigle
			// Create the initial directory context
750
			DirContext ctx = new InitialDirContext(env);
751 504 jones
752 4629 daigle
			// Specify the ids of the attributes to return
753
			String[] attrIDs = { "uniqueMember" };
754 504 jones
755 4629 daigle
			Attributes answer = ctx.getAttributes(group, attrIDs);
756 730 bojilova
757 4629 daigle
			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 5167 daigle
				logMetacat.error("AuthLdap.getUsers - LDAP Server size limit exceeded. "
768 4629 daigle
						+ "Returning incomplete record set.");
769
			}
770 2058 sgarg
771 4629 daigle
			// 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 730 bojilova
777 4629 daigle
			// Close the context when we're done
778
			ctx.close();
779 730 bojilova
780 4629 daigle
		} catch (NamingException e) {
781 5167 daigle
			logMetacat.error("AuthLdap.getUsers - Problem getting users for a group in "
782 4629 daigle
					+ "AuthLdap.getUsers:" + e);
783
			/*
784
			 * throw new ConnectException( "Problem getting users for a group in
785
			 * AuthLdap.getUsers:" + e);
786
			 */
787
		}
788 2121 sgarg
789 4629 daigle
		return users;
790
	}
791 2121 sgarg
792 4629 daigle
	/**
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 2121 sgarg
805 4629 daigle
	/**
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 2121 sgarg
819 5167 daigle
		logMetacat.debug("AuthLdap.getGroups - getGroups() called.");
820 2129 sgarg
821 4629 daigle
		// 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 2058 sgarg
828 4629 daigle
		// 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 8704 tao
		/*String realName = null;
838 8463 tao
		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 8704 tao
        }*/
848 4629 daigle
		// Iterate through the referrals, handling NamingExceptions in the
849
		// outer catch statement, ReferralExceptions in the inner catch
850
		// statement
851
		try { // outer try
852 730 bojilova
853 4629 daigle
			// Create the initial directory context
854
			DirContext ctx = new InitialDirContext(env);
855 730 bojilova
856 4629 daigle
			// 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 504 jones
871 4629 daigle
			// 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 5167 daigle
			logMetacat.info("AuthLdap.getGroups - group filter is: " + filter);
880 504 jones
881 4629 daigle
			// now, search and iterate through the referrals
882
			for (boolean moreReferrals = true; moreReferrals;) {
883
				try { // inner try
884 2058 sgarg
885 4629 daigle
					NamingEnumeration namingEnum = ctx.search(ldapBase, filter, ctls);
886 2058 sgarg
887 4629 daigle
					// Print the groups
888
					while (namingEnum.hasMore()) {
889
						SearchResult sr = (SearchResult) namingEnum.next();
890 730 bojilova
891 4629 daigle
						tempAttr = sr.getAttributes();
892 730 bojilova
893 4629 daigle
						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 2058 sgarg
900 4629 daigle
						// 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 5167 daigle
							logMetacat.debug("AuthLdap.getGroups - Search result entry is relative ...");
905 4629 daigle
							gvec.add(sr.getName() + "," + ldapBase);
906 5167 daigle
							logMetacat.info("AuthLdap.getGroups - group " + sr.getName() + "," + ldapBase
907 4629 daigle
									+ " added to the group vector");
908
						} else {
909 5167 daigle
							logMetacat.debug("AuthLdap.getGroups - Search result entry is absolute ...");
910 2058 sgarg
911 4629 daigle
							// 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 2058 sgarg
919 4629 daigle
							// 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 725 bojilova
929 4629 daigle
							try {
930
								// Create the initial directory context
931
								DirContext DirCtx = new InitialDirContext(envHash);
932 2058 sgarg
933 4629 daigle
								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 503 bojilova
946 4629 daigle
								// 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 5167 daigle
								logMetacat.debug("AuthLdap.getGroups - rFilter is: " + rFilter);
954 503 bojilova
955 4629 daigle
								NamingEnumeration rNamingEnum = DirCtx.search(ldapBase,
956
										rFilter, searchCtls);
957 2058 sgarg
958 4629 daigle
								while (rNamingEnum.hasMore()) {
959
									SearchResult rsr = (SearchResult) rNamingEnum.next();
960
									rsrAttr = rsr.getAttributes();
961 5167 daigle
									logMetacat.debug("AuthLdap.getGroups - referral search result is: "
962 4629 daigle
											+ rsr.toString());
963 725 bojilova
964 4629 daigle
									// 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 5167 daigle
										logMetacat.info("AuthLdap.getGroups - group "
977 4629 daigle
												+ (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 5167 daigle
										logMetacat.info("AuthLdap.getGroups - group " + "cn="
986 4629 daigle
												+ tempAttr.get("cn") + "," + "o="
987
												+ rsrAttr.get("o") + "," + ldapBase
988
												+ " added to the group vector");
989
									}
990
								}
991 723 bojilova
992 4629 daigle
							} catch (NamingException nameEx) {
993 5167 daigle
								logMetacat.debug("AuthLdap.getGroups - Caught naming exception: ");
994 4629 daigle
								nameEx.printStackTrace(System.err);
995
							}
996
						}
997
					}// end while
998 725 bojilova
999 4629 daigle
					moreReferrals = false;
1000
1001
				} catch (ReferralException re) {
1002
1003
					logMetacat
1004 5167 daigle
							.info("AuthLdap.getGroups -  caught referral exception: "
1005 4629 daigle
									+ re.getReferralInfo());
1006
					this.currentReferralInfo = (String) re.getReferralInfo();
1007
1008
					// set moreReferrals to true and set the referral context
1009
					moreReferrals = true;
1010 5293 leinfelder
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 4629 daigle
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 5167 daigle
			logMetacat.info("AuthLdap.getGroups - caught naming exception: ");
1036 4629 daigle
			e.printStackTrace(System.err);
1037
1038
		} finally {
1039
			// once all referrals are followed, report and return the groups
1040
			// found
1041 5167 daigle
			logMetacat.warn("AuthLdap.getGroups - The user is in the following groups: " + gvec.toString());
1042 4629 daigle
			// 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 6037 jones
				    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 4629 daigle
				}
1113
				attributes.put(attName, values);
1114
			}
1115
1116
			// Close the context when we're done
1117
			ctx.close();
1118
		} catch (NamingException e) {
1119 5167 daigle
			logMetacat.error("AuthLdap.getAttributes - Problem getting attributes:"
1120 4629 daigle
					+ 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 5157 daigle
		logMetacat.debug("AuthLdap.getSubtrees - getting subtrees for user: " + user +
1136
				", ldapUrl: " + ldapUrl + ", ldapBase: " + ldapBase);
1137 4629 daigle
		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 5157 daigle
				logMetacat.debug("AuthLdap.getSubtrees - search result: " + sr.toString());
1175 4629 daigle
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 5157 daigle
							// 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 4629 daigle
											attrValue.length()), attrValue.substring(0,
1199 5157 daigle
													attrValue.lastIndexOf("/") + 1));
1200 4629 daigle
1201
							// trees.put(refName + "=" + refValue + "," +
1202 5157 daigle
							// ldapBase, attrValue.substring(0, attrValue.lastIndexOf("/")
1203 4629 daigle
							// + 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 5157 daigle
			logMetacat.error("AuthLdap.getSubtrees - Problem getting subtrees in AuthLdap.getSubtrees:" + e);
1229 4629 daigle
			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 5157 daigle
			logMetacat.info("AuthLdap.getPrincipals - ldapBase: " + ldapBase +
1262
					", ldapUrl: " + ldapUrl);
1263 4629 daigle
			/*
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 5157 daigle
				// (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 4629 daigle
				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 5157 daigle
			logMetacat.info("AuthLdap.getPrincipals - org name is  " + orgName);
1289 9441 tao
			orgName = StringEscapeUtils.escapeXml(orgName);
1290
			logMetacat.info("AuthLdap.getPrincipals - org name (after the xml escaping) is  " + orgName);
1291 4629 daigle
			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 5157 daigle
			logMetacat.debug("AuthLdap.getPrincipals - after getting groups " + groups);
1297 4629 daigle
			String[][] users = getUsers(user, password);
1298 5157 daigle
			logMetacat.debug("AuthLdap.getPrincipals - after getting users " + users);
1299 4629 daigle
			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 9441 tao
					out.append("      <groupname>" + StringEscapeUtils.escapeXml(groups[i][0]) + "</groupname>\n");
1306
					out.append("      <description>" + StringEscapeUtils.escapeXml(groups[i][1]) + "</description>\n");
1307 4629 daigle
					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 9441 tao
							out.append("        <username>" + StringEscapeUtils.escapeXml(usersForGroup[j])
1314 4629 daigle
									+ "</username>\n");
1315
						} else {
1316 9441 tao
							out.append("        <username>" + StringEscapeUtils.escapeXml(users[userIndex][0])
1317 4629 daigle
									+ "</username>\n");
1318 9441 tao
							out.append("        <name>" + StringEscapeUtils.escapeXml(users[userIndex][1])
1319 4629 daigle
									+ "</name>\n");
1320 9441 tao
							out.append("        <organization>" + StringEscapeUtils.escapeXml(users[userIndex][2])
1321 4629 daigle
									+ "</organization>\n");
1322
							if (users[userIndex][3].compareTo("null") != 0) {
1323
								out.append("      <organizationUnitName>"
1324 9441 tao
										+ StringEscapeUtils.escapeXml(users[userIndex][3])
1325 4629 daigle
										+ "</organizationUnitName>\n");
1326
							}
1327 9441 tao
							out.append("        <email>" + StringEscapeUtils.escapeXml(users[userIndex][4])
1328 4629 daigle
									+ "</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 9441 tao
					out.append("      <username>" + StringEscapeUtils.escapeXml(users[j][0]) + "</username>\n");
1342
					out.append("      <name>" + StringEscapeUtils.escapeXml(users[j][1]) + "</name>\n");
1343 4629 daigle
					out
1344 9441 tao
							.append("      <organization>" + StringEscapeUtils.escapeXml(users[j][2])
1345 4629 daigle
									+ "</organization>\n");
1346
					if (users[j][3].compareTo("null") != 0) {
1347 9441 tao
						out.append("      <organizationUnitName>" + StringEscapeUtils.escapeXml(users[j][3])
1348 4629 daigle
								+ "</organizationUnitName>\n");
1349
					}
1350 9441 tao
					out.append("      <email>" + StringEscapeUtils.escapeXml(users[j][4]) + "</email>\n");
1351 4629 daigle
					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 8431 tao
	public static int searchUser(String user, String userGroup[][]) {
1365 4629 daigle
		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 5167 daigle
		logMetacat.debug("AuthLdap.testCredentials - position is: " + position);
1382 4629 daigle
		if (position == -1) {
1383
			server = rootServer;
1384
			if (dn.indexOf(userDN) < 0) {
1385
				userDN = dn + "," + rootBase;
1386
			} else {
1387
				userDN = dn;
1388
			}
1389 5167 daigle
			logMetacat.debug("AuthLdap.testCredentials - userDN is: " + userDN);
1390 4629 daigle
1391
		} else {
1392
			server = dn.substring(0, position + 1);
1393
			userDN = dn.substring(position + 1);
1394 5167 daigle
			logMetacat.debug("AuthLdap.testCredentials - server is: " + server);
1395
			logMetacat.debug("AuthLdap.testCredentials - userDN is: " + userDN);
1396 4629 daigle
		}
1397
1398 5167 daigle
		logMetacat.debug("AuthLdap.testCredentials - Trying to authenticate: " + userDN + " using server: " + server);
1399 4629 daigle
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 4080 daigle
	 * Test method for the class
1416
	 */
1417
	public static void main(String[] args) {
1418 871 jones
1419 4080 daigle
		// 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 871 jones
1424 5167 daigle
		logMetacat.warn("AuthLdap.main - Creating session...");
1425 4080 daigle
		AuthLdap authservice = null;
1426
		try {
1427
			authservice = new AuthLdap();
1428
		} catch (Exception e) {
1429 5167 daigle
			logMetacat.error("AuthLdap.main - Could not instantiate AuthLdap: " + e.getMessage());
1430 4080 daigle
			return;
1431
		}
1432 5167 daigle
		logMetacat.warn("AuthLdap.main - Session exists...");
1433 2058 sgarg
1434 4080 daigle
		boolean isValid = false;
1435
		try {
1436 5167 daigle
			logMetacat.warn("AuthLdap.main - Authenticating...");
1437 4080 daigle
			isValid = authservice.authenticate(user, password);
1438
			if (isValid) {
1439 5167 daigle
				logMetacat.warn("AuthLdap.main - Authentication successful for: " + user);
1440 4080 daigle
			} else {
1441 5167 daigle
				logMetacat.warn("AuthLdap.main - Authentication failed for: " + user);
1442 4080 daigle
			}
1443 873 jones
1444 4080 daigle
			// Get attributes for the user
1445
			if (isValid) {
1446 5167 daigle
				logMetacat.info("AuthLdap.main - Getting attributes for user....");
1447 4629 daigle
				HashMap userInfo = authservice.getAttributes(user, password, user);
1448 4080 daigle
				// Print all of the attributes
1449 4629 daigle
				Iterator attList = (Iterator) (((Set) userInfo.keySet()).iterator());
1450 4080 daigle
				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 5167 daigle
						logMetacat.warn("AuthLdap.main - " + att + ": " + value);
1457 4080 daigle
					}
1458
				}
1459
			}
1460 873 jones
1461 4080 daigle
			// get the groups
1462
			if (isValid) {
1463 5167 daigle
				logMetacat.warn("AuthLdap.main - Getting all groups....");
1464 4080 daigle
				String[][] groups = authservice.getGroups(user, password);
1465 5167 daigle
				logMetacat.info("AuthLdap.main - Groups found: " + groups.length);
1466 4080 daigle
				for (int i = 0; i < groups.length; i++) {
1467 5167 daigle
					logMetacat.info("AuthLdap.main - Group " + i + ": " + groups[i][0]);
1468 4080 daigle
				}
1469
			}
1470 2058 sgarg
1471 4080 daigle
			// get the groups for the user
1472
			String savedGroup = null;
1473
			if (isValid) {
1474 5167 daigle
				logMetacat.warn("AuthLdap.main - Getting groups for user....");
1475 4080 daigle
				String[][] groups = authservice.getGroups(user, password, user);
1476 5167 daigle
				logMetacat.info("AuthLdap.main - Groups found: " + groups.length);
1477 4080 daigle
				for (int i = 0; i < groups.length; i++) {
1478 5167 daigle
					logMetacat.info("AuthLdap.main - Group " + i + ": " + groups[i][0]);
1479 4080 daigle
					savedGroup = groups[i][0];
1480
				}
1481
			}
1482
1483
			// get the users for a group
1484
			if (isValid) {
1485 5167 daigle
				logMetacat.warn("AuthLdap.main - Getting users for group....");
1486
				logMetacat.info("AuthLdap.main - Group: " + savedGroup);
1487 4629 daigle
				String[] users = authservice.getUsers(user, password, savedGroup);
1488 5167 daigle
				logMetacat.info("AuthLdap.main - Users found: " + users.length);
1489 4080 daigle
				for (int i = 0; i < users.length; i++) {
1490 5167 daigle
					logMetacat.warn("AuthLdap.main - User " + i + ": " + users[i]);
1491 4080 daigle
				}
1492
			}
1493
1494
			// get all users
1495
			if (isValid) {
1496 5167 daigle
				logMetacat.warn("AuthLdap.main - Getting all users ....");
1497 4080 daigle
				String[][] users = authservice.getUsers(user, password);
1498 5167 daigle
				logMetacat.info("AuthLdap.main - Users found: " + users.length);
1499 4080 daigle
1500
			}
1501
1502
			// get the whole list groups and users in XML format
1503
			if (isValid) {
1504 5167 daigle
				logMetacat.warn("AuthLdap.main - Trying principals....");
1505 4080 daigle
				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 5167 daigle
				logMetacat.warn("AuthLdap.main - Finished getting principals.");
1515 4080 daigle
			}
1516
1517
		} catch (ConnectException ce) {
1518 5167 daigle
			logMetacat.error("AuthLdap.main - " + ce.getMessage());
1519 4080 daigle
		} catch (java.io.IOException ioe) {
1520 5167 daigle
			logMetacat.error("AuthLdap.main - I/O Error writing to file principals.txt: "
1521 4080 daigle
					+ ioe.getMessage());
1522
		} catch (InstantiationException ie) {
1523 5167 daigle
			logMetacat.error("AuthLdap.main - Instantiation error writing to file principals.txt: "
1524 4629 daigle
					+ ie.getMessage());
1525 4080 daigle
		}
1526
	}
1527
1528 4629 daigle
	/**
1529
	 * This method will be called by start a thread. It can handle if a referral
1530
	 * exception happend.
1531
	 */
1532 503 bojilova
}