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
52 5030 daigle
import edu.ucsb.nceas.metacat.properties.PropertyService;
53 4080 daigle
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
54
55 5157 daigle
import java.io.IOException;
56 4080 daigle
import java.lang.InstantiationException;
57 1988 jones
import java.net.URLDecoder;
58 503 bojilova
import java.util.Iterator;
59
import java.util.HashMap;
60
import java.util.Hashtable;
61 730 bojilova
import java.util.Enumeration;
62 503 bojilova
import java.util.Set;
63
import java.util.Vector;
64
65
/**
66 4629 daigle
 * An implementation of the AuthInterface interface that allows Metacat to use
67
 * the LDAP protocol for directory services. The LDAP authentication service is
68
 * used to determine if a user is authenticated, and whether they are a member
69
 * of a particular group.
70 503 bojilova
 */
71 3155 cjones
public class AuthLdap implements AuthInterface {
72 4629 daigle
	private String ldapUrl;
73
	private String ldapsUrl;
74
	private String ldapBase;
75
	private String referral;
76
	private String ldapConnectTimeLimit;
77
	private int ldapSearchTimeLimit;
78
	private int ldapSearchCountLimit;
79
	private String currentReferralInfo;
80 5158 daigle
	Hashtable<String, String> env = new Hashtable<String, String>(11);
81 4629 daigle
	private Context rContext;
82
	private String userName;
83
	private String userPassword;
84
	ReferralException refExc;
85 503 bojilova
86 4629 daigle
	private static Logger logMetacat = Logger.getLogger(AuthLdap.class);
87
88
	/**
89 4080 daigle
	 * Construct an AuthLdap
90
	 */
91
	public AuthLdap() throws InstantiationException {
92
		// Read LDAP URI for directory service information
93
		try {
94 4587 daigle
			this.ldapUrl = PropertyService.getProperty("auth.url");
95
			this.ldapsUrl = PropertyService.getProperty("auth.surl");
96 4729 daigle
			this.ldapBase = PropertyService.getProperty("auth.base");
97 4080 daigle
			this.referral = PropertyService.getProperty("ldap.referral");
98
			this.ldapConnectTimeLimit = PropertyService
99
					.getProperty("ldap.connectTimeLimit");
100
			this.ldapSearchTimeLimit = Integer.parseInt(PropertyService
101
					.getProperty("ldap.searchTimeLimit"));
102
			this.ldapSearchCountLimit = Integer.parseInt(PropertyService
103
					.getProperty("ldap.searchCountLimit"));
104
		} catch (PropertyNotFoundException pnfe) {
105
			throw new InstantiationException(
106
					"Could not instantiate AuthLdap.  Property not found: "
107
							+ pnfe.getMessage());
108
		} catch (NumberFormatException nfe) {
109
			throw new InstantiationException(
110
					"Could not instantiate AuthLdap.  Bad number format when converting properties: "
111
							+ nfe.getMessage());
112
		}
113 728 bojilova
114 4080 daigle
		// Store referral info for use in building group DNs in getGroups()
115
		this.currentReferralInfo = "";
116
	}
117
118 4629 daigle
	/**
119 4080 daigle
	 * Determine if a user/password are valid according to the authentication
120
	 * service.
121
	 *
122
	 * @param user
123
	 *            the name of the principal to authenticate
124
	 * @param password
125
	 *            the password to use for authentication
126
	 * @returns boolean true if authentication successful, false otherwise
127
	 */
128 4629 daigle
	public boolean authenticate(String user, String password) throws ConnectException {
129
		String ldapUrl = this.ldapUrl;
130
		String ldapsUrl = this.ldapsUrl;
131
		String ldapBase = this.ldapBase;
132
		boolean authenticated = false;
133
		String identifier = user;
134 3022 sgarg
135 4629 daigle
		// get uid here.
136
		if (user.indexOf(",") == -1) {
137
			throw new ConnectException("Invalid LDAP user credential: " + user
138
					+ ".  Missing ','");
139
		}
140
		String uid = user.substring(0, user.indexOf(","));
141
		user = user.substring(user.indexOf(","), user.length());
142 3022 sgarg
143 5157 daigle
		logMetacat.debug("AuthLdap.authenticate - identifier: " + identifier +
144
				", uid: " + uid +", user: " + user);
145 3022 sgarg
146 4629 daigle
		try {
147
			// Check the usename as passed in
148 5157 daigle
			logMetacat.info("AuthLdap.authenticate - Calling ldapAuthenticate" +
149
				" with user as identifier: " + identifier);
150 3022 sgarg
151 4629 daigle
			authenticated = ldapAuthenticate(identifier, password, (new Boolean(
152
					PropertyService.getProperty("ldap.onlySecureConnection")))
153
					.booleanValue());
154
			// if not found, try looking up a valid DN then auth again
155
			if (!authenticated) {
156 5157 daigle
				logMetacat.info("AuthLdap.authenticate - Not Authenticated");
157
				logMetacat.info("AuthLdap.authenticate - Looking up DN for: " + identifier);
158 4629 daigle
				identifier = getIdentifyingName(identifier, ldapUrl, ldapBase);
159
				if (identifier == null) {
160 5157 daigle
					logMetacat.info("AuthLdap.authenticate - No DN found from getIdentifyingName");
161 4629 daigle
					return authenticated;
162
				}
163 503 bojilova
164 5157 daigle
				logMetacat.info("AuthLdap.authenticate - DN found from getIdentifyingName: " + identifier);
165 4629 daigle
				String decoded = URLDecoder.decode(identifier);
166 5157 daigle
				logMetacat.info("AuthLdap.authenticate - DN decoded: " + decoded);
167 4629 daigle
				identifier = decoded;
168
				String refUrl = "";
169
				String refBase = "";
170
				if (identifier.startsWith("ldap")) {
171 5157 daigle
					logMetacat.debug("AuthLdap.authenticate - identifier starts with \"ldap\"");
172 1005 jones
173 4629 daigle
					refUrl = identifier.substring(0, identifier.lastIndexOf("/") + 1);
174
					int position = identifier.indexOf(",");
175
					int position2 = identifier.indexOf(",", position + 1);
176 2058 sgarg
177 4629 daigle
					refBase = identifier.substring(position2 + 1);
178
					identifier = identifier.substring(identifier.lastIndexOf("/") + 1);
179 3022 sgarg
180 5157 daigle
					logMetacat.info("AuthLdap.authenticate - Calling ldapAuthenticate: " +
181
						"with user as identifier: " + identifier + " and refUrl as: " +
182
						refUrl + " and refBase as: " + refBase);
183 934 tao
184 4629 daigle
					authenticated = ldapAuthenticate(identifier, password, refUrl,
185
							refBase, (new Boolean(PropertyService
186
									.getProperty("ldap.onlySecureReferalsConnection")))
187
									.booleanValue());
188
				} else {
189 5157 daigle
					logMetacat.info("AuthLdap.authenticate - identifier doesnt start with ldap");
190 4629 daigle
					identifier = identifier + "," + ldapBase;
191 852 jones
192 5157 daigle
					logMetacat.info("AuthLdap.authenticate - Calling ldapAuthenticate" +
193
							"with user as identifier: " + identifier);
194 3022 sgarg
195 4629 daigle
					authenticated = ldapAuthenticate(identifier, password, (new Boolean(
196
							PropertyService.getProperty("ldap.onlySecureConnection")))
197
							.booleanValue());
198
				}
199
			}
200 5157 daigle
		} catch (NullPointerException npe) {
201
			logMetacat.error("AuthLdap.authenticate - NullPointerException while authenticating in "
202
					+ "AuthLdap.authenticate: " + npe);
203
			npe.printStackTrace();
204 4080 daigle
205 5157 daigle
			throw new ConnectException("AuthLdap.authenticate - NullPointerException while authenticating in "
206
					+ "AuthLdap.authenticate: " + npe);
207
		} catch (NamingException ne) {
208
			logMetacat.error("AuthLdap.authenticate - Naming exception while authenticating in "
209
					+ "AuthLdap.authenticate: " + ne);
210
			ne.printStackTrace();
211
		} catch (PropertyNotFoundException pnfe) {
212
			logMetacat.error("AuthLdap.authenticate - Property exception while authenticating in "
213
					+ "AuthLdap.authenticate: " + pnfe.getMessage());
214 4629 daigle
		}
215 723 bojilova
216 4629 daigle
		return authenticated;
217
	}
218 2058 sgarg
219 4629 daigle
	/**
220
	 * Connect to the LDAP directory and do the authentication using the
221
	 * username and password as passed into the routine.
222
	 *
223
	 * @param identifier
224
	 *            the distinguished name to check against LDAP
225
	 * @param password
226
	 *            the password for authentication
227
	 */
228
	private boolean ldapAuthenticate(String identifier, String password,
229
			boolean secureConnectionOnly) throws ConnectException, NamingException,
230
			NullPointerException {
231
		return ldapAuthenticate(identifier, password, this.ldapsUrl, this.ldapBase,
232
				secureConnectionOnly);
233
	}
234 723 bojilova
235 4629 daigle
	/**
236
	 * Connect to the LDAP directory and do the authentication using the
237
	 * username and password as passed into the routine.
238
	 *
239
	 * @param identifier
240
	 *            the distinguished name to check against LDAP
241
	 * @param password
242
	 *            the password for authentication
243
	 */
244 723 bojilova
245 4629 daigle
	private boolean ldapAuthenticate(String dn, String password, String rootServer,
246
			String rootBase, boolean secureConnectionOnly) {
247 2058 sgarg
248 4629 daigle
		boolean authenticated = false;
249 2058 sgarg
250 4629 daigle
		String server = "";
251
		String userDN = "";
252 5157 daigle
		logMetacat.info("AuthLdap.ldapAuthenticate - dn is: " + dn);
253 2058 sgarg
254 4629 daigle
		int position = dn.lastIndexOf("/");
255 5157 daigle
		logMetacat.debug("AuthLdap.ldapAuthenticate - position is: " + position);
256 4629 daigle
		if (position == -1) {
257
			server = rootServer;
258
			if (dn.indexOf(userDN) < 0) {
259
				userDN = dn + "," + rootBase;
260
			} else {
261
				userDN = dn;
262
			}
263 5157 daigle
			logMetacat.info("AuthLdap.ldapAuthenticate - userDN is: " + userDN);
264 2116 sgarg
265 4629 daigle
		} else {
266
			server = dn.substring(0, position + 1);
267
			userDN = dn.substring(position + 1);
268 5157 daigle
			logMetacat.info("AuthLdap.ldapAuthenticate - server is: " + server);
269
			logMetacat.info("AuthLdap.ldapAuthenticate - userDN is: " + userDN);
270 4629 daigle
		}
271 2130 sgarg
272 5157 daigle
		logMetacat.warn("AuthLdap.ldapAuthenticate - Trying to authenticate: " +
273
				userDN + " Using server: " + server);
274 2058 sgarg
275 4629 daigle
		try {
276 5158 daigle
			Hashtable<String, String> env = new Hashtable<String, String>();
277 4629 daigle
			env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
278
			env.put(Context.PROVIDER_URL, server);
279
			env.put(Context.REFERRAL, "throw");
280 5158 daigle
281 4629 daigle
			try {
282 5158 daigle
				authenticated = authenticateTLS(env, userDN, password);
283 8461 tao
			} catch (AuthenticationException ee) {
284
			    logMetacat.info("AuthLdap.ldapAuthenticate - failed to login : "+ee.getMessage());
285
			    String aliasedDn = null;
286
			    try {
287
			        aliasedDn = getAliasedDnTLS(userDN, env);
288
			        if(aliasedDn != null) {
289
			            logMetacat.warn("AuthLdap.ldapAuthenticate - an aliased object " + aliasedDn + " was found for the DN "+userDN+". We will try to authenticate this new DN "+aliasedDn+".");
290
			            authenticated = authenticateTLS(env, aliasedDn, password);
291
			        }
292
			    } catch (NamingException e) {
293
			        logMetacat.error("AuthLdap.ldapAuthenticate - NamingException "+e.getMessage()+" happend when the ldap server authenticated the aliased object "+aliasedDn);
294
			    } catch (IOException e) {
295
			        logMetacat.error("AuthLdap.ldapAuthenticate - IOException "+e.getMessage()+" happend when the ldap server authenticated the aliased object "+aliasedDn);
296
			    } catch (AuthTLSException e) {
297
			        logMetacat.error("AuthLdap.ldapAuthenticate - AuthTLSException "+e.getMessage()+" happend when the ldap server authenticated the aliased object "+aliasedDn);
298
			    }
299 5158 daigle
			} catch (AuthTLSException ate) {
300
				logMetacat.info("AuthLdap.ldapAuthenticate - error while negotiating TLS: "
301
						+ ate.getMessage());
302 4629 daigle
				if (secureConnectionOnly) {
303
					return authenticated;
304 8461 tao
				} else {
305
				    try {
306
                        authenticated = authenticateNonTLS(env, userDN, password);
307
                    } catch (AuthenticationException ae) {
308
                        logMetacat.warn("Authentication exception for (nonTLS): " + ae.getMessage());
309
                        String aliasedDn = null;
310
                        try {
311
                            aliasedDn = getAliasedDnNonTLS(userDN, env);
312
                            if(aliasedDn != null) {
313
                                logMetacat.warn("AuthLdap.ldapAuthenticate(NonTLS) - an aliased object " + aliasedDn + " was found for the DN "+userDN+". We will try to authenticate this new DN "+aliasedDn+" again.");
314
                                authenticated = authenticateNonTLS(env, aliasedDn, password);
315
                            }
316
317
                        } catch (NamingException e) {
318
                            logMetacat.error("AuthLdap.ldapAuthenticate(NonTLS) - NamingException "+e.getMessage()+" happend when the ldap server authenticated the aliased object "+aliasedDn);
319
                        } catch (IOException e) {
320
                            logMetacat.error("AuthLdap.ldapAuthenticate(NonTLS) - IOException "+e.getMessage()+" happend when the ldap server authenticated the aliased object "+aliasedDn);
321
                        }
322
                    }
323 723 bojilova
324 4629 daigle
				}
325
			}
326
		} catch (AuthenticationException ae) {
327 5157 daigle
			logMetacat.warn("Authentication exception: " + ae.getMessage());
328 4629 daigle
			authenticated = false;
329
		} catch (javax.naming.InvalidNameException ine) {
330 5157 daigle
			logMetacat.error("AuthLdap.ldapAuthenticate - An invalid DN was provided: " + ine.getMessage());
331
		} catch (NamingException ne) {
332
			logMetacat.warn("AuthLdap.ldapAuthenticate - Caught NamingException in login: " + ne.getClass().getName());
333
			logMetacat.info(ne.toString() + "  " + ne.getRootCause());
334 4629 daigle
		}
335 503 bojilova
336 4629 daigle
		return authenticated;
337
	}
338 5158 daigle
339 8460 tao
340 8459 tao
	/*
341 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
342 8460 tao
	 */
343
	private String getAliasedDnTLS(String alias, Hashtable<String, String> env) throws NamingException, IOException {
344
	    boolean useTLS = true;
345
	    return getAliasedDn(alias, env, useTLS);
346
	}
347
348
	/*
349 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
350 8460 tao
     */
351
    private String getAliasedDnNonTLS(String alias, Hashtable<String, String> env) throws NamingException, IOException {
352
        boolean useTLS = false;
353
        return getAliasedDn(alias, env, useTLS);
354
    }
355
356
	/*
357 8459 tao
	 * Get the aliasedDN (the real DN) for a specified an alias name
358
	 */
359 8461 tao
	private String getAliasedDn(String alias, Hashtable<String, String> env, boolean useTLS) throws NamingException, IOException  {
360 8459 tao
	    String aliasedDn = null;
361 8460 tao
        LdapContext sctx = new InitialLdapContext(env, null);
362
        StartTlsResponse tls = null;
363
        if(useTLS) {
364
            tls = (StartTlsResponse) sctx.extendedOperation(new StartTlsRequest());
365
            // Open a TLS connection (over the existing LDAP association) and get details
366
            // of the negotiated TLS session: cipher suite, peer certificate, etc.
367
            SSLSession session = tls.negotiate();
368
        }
369 8459 tao
        SearchControls ctls = new SearchControls();
370
        ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
371
        String filter = "(objectClass=*)";
372
        NamingEnumeration answer  = sctx.search(alias, filter, ctls);
373
        while(answer.hasMore()) {
374
            SearchResult result = (SearchResult) answer.next();
375
            if(!result.isRelative()) {
376
                //if is not relative, this will be alias.
377
                aliasedDn = result.getNameInNamespace();
378
                break;
379
            }
380
        }
381 8460 tao
        if(useTLS && tls != null) {
382
            tls.close();
383
        }
384
        sctx.close();
385 8459 tao
        return aliasedDn;
386
387
	}
388 8460 tao
389 5158 daigle
	private boolean authenticateTLS(Hashtable<String, String> env, String userDN, String password)
390 8461 tao
			throws AuthTLSException, AuthenticationException{
391 5158 daigle
		logMetacat.info("AuthLdap.authenticateTLS - Trying to authenticate with TLS");
392
		try {
393
			LdapContext ctx = null;
394
			double startTime;
395
			double stopTime;
396
			startTime = System.currentTimeMillis();
397
			ctx = new InitialLdapContext(env, null);
398
			// Start up TLS here so that we don't pass our jewels in
399
			// cleartext
400
			StartTlsResponse tls =
401
				(StartTlsResponse) ctx.extendedOperation(new StartTlsRequest());
402
			// tls.setHostnameVerifier(new SampleVerifier());
403
			SSLSession sess = tls.negotiate();
404
			ctx.addToEnvironment(Context.SECURITY_AUTHENTICATION, "simple");
405
			ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, userDN);
406
			ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, password);
407
			ctx.reconnect(null);
408
			stopTime = System.currentTimeMillis();
409
			logMetacat.info("AuthLdap.authenticateTLS - Connection time thru "
410
					+ ldapsUrl + " was: " + (stopTime - startTime) / 1000 + " seconds.");
411 8461 tao
		} catch (AuthenticationException ae) {
412
            logMetacat.warn("AuthLdap.authenticateTLS - Authentication exception: " + ae.getMessage());
413
            throw ae;
414
415 5158 daigle
		} catch (NamingException ne) {
416
			throw new AuthTLSException("AuthLdap.authenticateTLS - Naming error when athenticating via TLS: " + ne.getMessage());
417
		} catch (IOException ioe) {
418
			throw new AuthTLSException("AuthLdap.authenticateTLS - I/O error when athenticating via TLS: " + ioe.getMessage());
419
		}
420
		return true;
421
	}
422
423
	private boolean authenticateNonTLS(Hashtable<String, String> env, String userDN, String password)
424
			throws NamingException {
425
		LdapContext ctx = null;
426
		double startTime;
427
		double stopTime;
428
429
		logMetacat.info("AuthLdap.authenticateNonTLS - Trying to authenticate without TLS");
430
		env.put(Context.SECURITY_AUTHENTICATION, "simple");
431
		env.put(Context.SECURITY_PRINCIPAL, userDN);
432
		env.put(Context.SECURITY_CREDENTIALS, password);
433 2679 sgarg
434 5158 daigle
		startTime = System.currentTimeMillis();
435
		ctx = new InitialLdapContext(env, null);
436
		stopTime = System.currentTimeMillis();
437
		logMetacat.info("AuthLdap.authenticateNonTLS - Connection time thru " + ldapsUrl + " was: "
438
				+ (stopTime - startTime) / 1000 + " seconds.");
439
440
		return true;
441
	}
442
443 4629 daigle
	/**
444
	 * Get the identifying name for a given userid or name. This is the name
445
	 * that is used in conjunction withthe LDAP BaseDN to create a distinguished
446
	 * name (dn) for the record
447
	 *
448
	 * @param user
449
	 *            the user for which the identifying name is requested
450
	 * @returns String the identifying name for the user, or null if not found
451
	 */
452
	private String getIdentifyingName(String user, String ldapUrl, String ldapBase)
453
			throws NamingException {
454 2679 sgarg
455 4629 daigle
		String identifier = null;
456
		Hashtable env = new Hashtable();
457
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
458
		env.put(Context.REFERRAL, "throw");
459
		env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
460
		try {
461
			int position = user.indexOf(",");
462
			String uid = user.substring(user.indexOf("=") + 1, position);
463 5167 daigle
			logMetacat.info("AuthLdap.getIdentifyingName - uid is: " + uid);
464 4629 daigle
			String org = user.substring(user.indexOf("=", position + 1) + 1, user
465
					.indexOf(",", position + 1));
466 5167 daigle
			logMetacat.info("AuthLdap.getIdentifyingName - org is: " + org);
467 2697 sgarg
468 4629 daigle
			DirContext sctx = new InitialDirContext(env);
469
			SearchControls ctls = new SearchControls();
470
			ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
471
			String filter = "(&(uid=" + uid + ")(o=" + org + "))";
472 5167 daigle
			logMetacat.warn("AuthLdap.getIdentifyingName - Searching for DNs with following filter: " + filter);
473 2679 sgarg
474 4629 daigle
			for (boolean moreReferrals = true; moreReferrals;) {
475
				try {
476
					// Perform the search
477 5629 berkley
478 4629 daigle
					NamingEnumeration answer = sctx.search("", filter, ctls);
479 2679 sgarg
480 4629 daigle
					// Return the answer
481
					while (answer.hasMore()) {
482
						SearchResult sr = (SearchResult) answer.next();
483
						identifier = sr.getName();
484
						return identifier;
485
					}
486
					// The search completes with no more referrals
487
					moreReferrals = false;
488
				} catch (ReferralException e) {
489 5167 daigle
					logMetacat.info("AuthLdap.getIdentifyingName - Got referral: " + e.getReferralInfo());
490 4629 daigle
					// Point to the new context from the referral
491
					if (moreReferrals) {
492 5292 leinfelder
						// try following referral, skip if error
493
						boolean referralError = true;
494
						while (referralError) {
495
							try {
496
								sctx = (DirContext) e.getReferralContext();
497
								referralError = false;
498
							}
499
							catch (NamingException ne) {
500
								logMetacat.error("NamingException when getting referral contex. Skipping this referral. " + ne.getMessage());
501
								e.skipReferral();
502
								referralError = true;
503
							}
504
						}
505 4629 daigle
					}
506 5292 leinfelder
				}
507 4629 daigle
			}
508
		} catch (NamingException e) {
509 5167 daigle
			logMetacat.error("AuthLdap.getIdentifyingName - Naming exception while getting dn: " + e);
510 4629 daigle
			throw new NamingException("Naming exception in AuthLdap.getIdentifyingName: "
511
					+ e);
512
		}
513
		return identifier;
514
	}
515 2679 sgarg
516 4629 daigle
	/**
517
	 * Get all users from the authentication service
518
	 *
519
	 * @param user
520
	 *            the user for authenticating against the service
521
	 * @param password
522
	 *            the password for authenticating against the service
523
	 * @returns string array of all of the user names
524
	 */
525
	public String[][] getUsers(String user, String password) throws ConnectException {
526
		String[][] users = null;
527 2679 sgarg
528 4629 daigle
		// Identify service provider to use
529
		Hashtable env = new Hashtable(11);
530
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
531
		env.put(Context.REFERRAL, referral);
532
		env.put(Context.PROVIDER_URL, ldapUrl);
533
		env.put("com.sun.jndi.ldap.connect.timeout", ldapConnectTimeLimit);
534 2679 sgarg
535 4629 daigle
		try {
536 2679 sgarg
537 4629 daigle
			// Create the initial directory context
538
			DirContext ctx = new InitialDirContext(env);
539 2679 sgarg
540 4629 daigle
			// Specify the attributes to match.
541
			// Users are objects that have the attribute
542
			// objectclass=InetOrgPerson.
543
			SearchControls ctls = new SearchControls();
544
			String[] attrIDs = { "dn", "cn", "o", "ou", "mail" };
545
			ctls.setReturningAttributes(attrIDs);
546
			ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
547
			ctls.setTimeLimit(ldapSearchTimeLimit);
548
			// ctls.setCountLimit(1000);
549
			String filter = "(objectClass=inetOrgPerson)";
550
			NamingEnumeration namingEnum = ctx.search(ldapBase, filter, ctls);
551 723 bojilova
552 4629 daigle
			// Store the users in a vector
553
			Vector uvec = new Vector();
554
			Vector uname = new Vector();
555
			Vector uorg = new Vector();
556
			Vector uou = new Vector();
557
			Vector umail = new Vector();
558
			Attributes tempAttr = null;
559
			try {
560
				while (namingEnum.hasMore()) {
561
					SearchResult sr = (SearchResult) namingEnum.next();
562
					tempAttr = sr.getAttributes();
563 723 bojilova
564 4629 daigle
					if ((tempAttr.get("cn") + "").startsWith("cn: ")) {
565
						uname.add((tempAttr.get("cn") + "").substring(4));
566
					} else {
567
						uname.add(tempAttr.get("cn") + "");
568
					}
569 723 bojilova
570 4629 daigle
					if ((tempAttr.get("o") + "").startsWith("o: ")) {
571
						uorg.add((tempAttr.get("o") + "").substring(3));
572
					} else {
573
						uorg.add(tempAttr.get("o") + "");
574
					}
575 723 bojilova
576 4629 daigle
					if ((tempAttr.get("ou") + "").startsWith("ou: ")) {
577
						uou.add((tempAttr.get("ou") + "").substring(4));
578
					} else {
579
						uou.add(tempAttr.get("ou") + "");
580
					}
581 723 bojilova
582 4629 daigle
					if ((tempAttr.get("mail") + "").startsWith("mail: ")) {
583
						umail.add((tempAttr.get("mail") + "").substring(6));
584
					} else {
585
						umail.add(tempAttr.get("mail") + "");
586
					}
587 723 bojilova
588 4629 daigle
					uvec.add(sr.getName() + "," + ldapBase);
589
				}
590
			} catch (SizeLimitExceededException slee) {
591 5167 daigle
				logMetacat.error("AuthLdap.getUsers - LDAP Server size limit exceeded. "
592 4629 daigle
						+ "Returning incomplete record set.");
593
			}
594 723 bojilova
595 4629 daigle
			// initialize users[]; fill users[]
596
			users = new String[uvec.size()][5];
597
			for (int i = 0; i < uvec.size(); i++) {
598
				users[i][0] = (String) uvec.elementAt(i);
599
				users[i][1] = (String) uname.elementAt(i);
600
				users[i][2] = (String) uorg.elementAt(i);
601
				users[i][3] = (String) uorg.elementAt(i);
602
				users[i][4] = (String) umail.elementAt(i);
603
			}
604 723 bojilova
605 4629 daigle
			// Close the context when we're done
606
			ctx.close();
607 723 bojilova
608 4629 daigle
		} catch (NamingException e) {
609 5167 daigle
			logMetacat.error("AuthLdap.getUsers - Problem getting users in AuthLdap.getUsers:" + e);
610 4629 daigle
			// e.printStackTrace(System.err);
611
			/*
612
			 * throw new ConnectException( "Problem getting users in
613
			 * AuthLdap.getUsers:" + e);
614
			 */
615
		}
616 723 bojilova
617 4629 daigle
		return users;
618
	}
619 503 bojilova
620 4629 daigle
	/**
621
	 * Get all users from the authentication service
622
	 *
623
	 * @param user
624
	 *            the user for authenticating against the service
625
	 * @param password
626
	 *            the password for authenticating against the service
627
	 * @returns string array of all of the user names
628
	 */
629
	public String[] getUserInfo(String user, String password) throws ConnectException {
630
		String[] userinfo = new String[3];
631 503 bojilova
632 4629 daigle
		// Identify service provider to use
633
		Hashtable env = new Hashtable(11);
634
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
635
		env.put(Context.REFERRAL, referral);
636
		env.put(Context.PROVIDER_URL, ldapUrl);
637 8463 tao
		String realName = null;
638
		try {
639
		    realName = getAliasedDnNonTLS(user,env);
640
		} catch(Exception e) {
641
		    logMetacat.warn("AuthLdap.getUserInfo - can't get the alias name for the user "+user+" since "+e.getMessage());
642
		}
643
644
		if(realName != null) {
645
		    //the the user is an alias name. we need to use the the real name
646
		    user = realName;
647
		}
648 2058 sgarg
649 4629 daigle
		try {
650 991 tao
651 4629 daigle
			// Create the initial directory context
652
			DirContext ctx = new InitialDirContext(env);
653
			// Specify the attributes to match.
654
			// Users are objects that have the attribute
655
			// objectclass=InetOrgPerson.
656
			SearchControls ctls = new SearchControls();
657
			String[] attrIDs = { "cn", "o", "mail" };
658
			ctls.setReturningAttributes(attrIDs);
659
			ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
660
			// ctls.setCountLimit(1000);
661
			// create the filter based on the uid
662 2058 sgarg
663 4629 daigle
			String filter = null;
664 991 tao
665 4629 daigle
			if (user.indexOf("o=") > 0) {
666
				String tempStr = user.substring(user.indexOf("o="));
667
				filter = "(&(" + user.substring(0, user.indexOf(",")) + ")("
668
						+ tempStr.substring(0, tempStr.indexOf(",")) + "))";
669
			} else {
670
				filter = "(&(" + user.substring(0, user.indexOf(",")) + "))";
671
			}
672
			filter = "(&(" + user.substring(0, user.indexOf(",")) + "))";
673 503 bojilova
674 4629 daigle
			NamingEnumeration namingEnum = ctx.search(user, filter, ctls);
675 503 bojilova
676 4629 daigle
			Attributes tempAttr = null;
677
			try {
678
				while (namingEnum.hasMore()) {
679
					SearchResult sr = (SearchResult) namingEnum.next();
680
					tempAttr = sr.getAttributes();
681 2058 sgarg
682 4629 daigle
					if ((tempAttr.get("cn") + "").startsWith("cn: ")) {
683
						userinfo[0] = (tempAttr.get("cn") + "").substring(4);
684
					} else {
685
						userinfo[0] = (tempAttr.get("cn") + "");
686
					}
687 503 bojilova
688 4629 daigle
					if ((tempAttr.get("o") + "").startsWith("o: ")) {
689
						userinfo[1] = (tempAttr.get("o") + "").substring(3);
690
					} else {
691
						userinfo[1] = (tempAttr.get("o") + "");
692
					}
693 2058 sgarg
694 4629 daigle
					if ((tempAttr.get("mail") + "").startsWith("mail: ")) {
695
						userinfo[2] = (tempAttr.get("mail") + "").substring(6);
696
					} else {
697
						userinfo[2] = (tempAttr.get("mail") + "");
698
					}
699
				}
700
			} catch (SizeLimitExceededException slee) {
701 5167 daigle
				logMetacat.error("AuthLdap.getUserInfo - LDAP Server size limit exceeded. "
702 4629 daigle
						+ "Returning incomplete record set.");
703
			}
704 2058 sgarg
705 4629 daigle
			// Close the context when we're done
706
			ctx.close();
707 2058 sgarg
708 4629 daigle
		} catch (NamingException e) {
709 5167 daigle
			logMetacat.error("AuthLdap.getUserInfo - Problem getting users:" + e);
710 4629 daigle
			// e.printStackTrace(System.err);
711
			throw new ConnectException("Problem getting users in AuthLdap.getUsers:" + e);
712
		}
713 2058 sgarg
714 4629 daigle
		return userinfo;
715
	}
716 503 bojilova
717 4629 daigle
	/**
718
	 * Get the users for a particular group from the authentication service
719
	 *
720
	 * @param user
721
	 *            the user for authenticating against the service
722
	 * @param password
723
	 *            the password for authenticating against the service
724
	 * @param group
725
	 *            the group whose user list should be returned
726
	 * @returns string array of the user names belonging to the group
727
	 */
728
	public String[] getUsers(String user, String password, String group)
729
			throws ConnectException {
730
		String[] users = null;
731 503 bojilova
732 4629 daigle
		// Identify service provider to use
733
		Hashtable env = new Hashtable(11);
734
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
735
		env.put(Context.REFERRAL, referral);
736
		env.put(Context.PROVIDER_URL, ldapUrl);
737 504 jones
738 4629 daigle
		try {
739 2129 sgarg
740 4629 daigle
			// Create the initial directory context
741
			DirContext ctx = new InitialDirContext(env);
742 504 jones
743 4629 daigle
			// Specify the ids of the attributes to return
744
			String[] attrIDs = { "uniqueMember" };
745 504 jones
746 4629 daigle
			Attributes answer = ctx.getAttributes(group, attrIDs);
747 730 bojilova
748 4629 daigle
			Vector uvec = new Vector();
749
			try {
750
				for (NamingEnumeration ae = answer.getAll(); ae.hasMore();) {
751
					Attribute attr = (Attribute) ae.next();
752
					for (NamingEnumeration e = attr.getAll(); e.hasMore(); uvec.add(e
753
							.next())) {
754
						;
755
					}
756
				}
757
			} catch (SizeLimitExceededException slee) {
758 5167 daigle
				logMetacat.error("AuthLdap.getUsers - LDAP Server size limit exceeded. "
759 4629 daigle
						+ "Returning incomplete record set.");
760
			}
761 2058 sgarg
762 4629 daigle
			// initialize users[]; fill users[]
763
			users = new String[uvec.size()];
764
			for (int i = 0; i < uvec.size(); i++) {
765
				users[i] = (String) uvec.elementAt(i);
766
			}
767 730 bojilova
768 4629 daigle
			// Close the context when we're done
769
			ctx.close();
770 730 bojilova
771 4629 daigle
		} catch (NamingException e) {
772 5167 daigle
			logMetacat.error("AuthLdap.getUsers - Problem getting users for a group in "
773 4629 daigle
					+ "AuthLdap.getUsers:" + e);
774
			/*
775
			 * throw new ConnectException( "Problem getting users for a group in
776
			 * AuthLdap.getUsers:" + e);
777
			 */
778
		}
779 2121 sgarg
780 4629 daigle
		return users;
781
	}
782 2121 sgarg
783 4629 daigle
	/**
784
	 * Get all groups from the authentication service
785
	 *
786
	 * @param user
787
	 *            the user for authenticating against the service
788
	 * @param password
789
	 *            the password for authenticating against the service
790
	 * @returns string array of the group names
791
	 */
792
	public String[][] getGroups(String user, String password) throws ConnectException {
793
		return getGroups(user, password, null);
794
	}
795 2121 sgarg
796 4629 daigle
	/**
797
	 * Get the groups for a particular user from the authentication service
798
	 *
799
	 * @param user
800
	 *            the user for authenticating against the service
801
	 * @param password
802
	 *            the password for authenticating against the service
803
	 * @param foruser
804
	 *            the user whose group list should be returned
805
	 * @returns string array of the group names
806
	 */
807
	public String[][] getGroups(String user, String password, String foruser)
808
			throws ConnectException {
809 2121 sgarg
810 5167 daigle
		logMetacat.debug("AuthLdap.getGroups - getGroups() called.");
811 2129 sgarg
812 4629 daigle
		// create vectors to store group and dscription values returned from the
813
		// ldap servers
814
		Vector gvec = new Vector();
815
		Vector desc = new Vector();
816
		Attributes tempAttr = null;
817
		Attributes rsrAttr = null;
818 2058 sgarg
819 4629 daigle
		// DURING getGroups(), DO WE NOT BIND USING userName AND userPassword??
820
		// NEED TO FIX THIS ...
821
		userName = user;
822
		userPassword = password;
823
		// Identify service provider to use
824
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
825
		env.put(Context.REFERRAL, "throw");
826
		env.put(Context.PROVIDER_URL, ldapUrl);
827
		env.put("com.sun.jndi.ldap.connect.timeout", ldapConnectTimeLimit);
828 8463 tao
		String realName = null;
829
		try {
830
            realName = getAliasedDnNonTLS(foruser,env);
831
        } catch(Exception e) {
832
            logMetacat.warn("AuthLdap.getGroups - can't get the alias name for the user "+user+" since "+e.getMessage());
833
        }
834
835
        if(realName != null) {
836
            //the the user is an alias name. we need to use the the real name
837
            foruser = realName;
838
        }
839 4629 daigle
		// Iterate through the referrals, handling NamingExceptions in the
840
		// outer catch statement, ReferralExceptions in the inner catch
841
		// statement
842
		try { // outer try
843 730 bojilova
844 4629 daigle
			// Create the initial directory context
845
			DirContext ctx = new InitialDirContext(env);
846 730 bojilova
847 4629 daigle
			// Specify the attributes to match.
848
			// Groups are objects with attribute objectclass=groupofuniquenames.
849
			// and have attribute uniquemember: uid=foruser,ldapbase.
850
			SearchControls ctls = new SearchControls();
851
			// Specify the ids of the attributes to return
852
			String[] attrIDs = { "cn", "o", "description" };
853
			ctls.setReturningAttributes(attrIDs);
854
			// set the ldap search scope
855
			ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
856
			// set a 10 second time limit on searches to limit non-responding
857
			// servers
858
			ctls.setTimeLimit(ldapSearchTimeLimit);
859
			// return at most 20000 entries
860
			ctls.setCountLimit(ldapSearchCountLimit);
861 504 jones
862 4629 daigle
			// build the ldap search filter that represents the "group" concept
863
			String filter = null;
864
			String gfilter = "(objectClass=groupOfUniqueNames)";
865
			if (null == foruser) {
866
				filter = gfilter;
867
			} else {
868
				filter = "(& " + gfilter + "(uniqueMember=" + foruser + "))";
869
			}
870 5167 daigle
			logMetacat.info("AuthLdap.getGroups - group filter is: " + filter);
871 504 jones
872 4629 daigle
			// now, search and iterate through the referrals
873
			for (boolean moreReferrals = true; moreReferrals;) {
874
				try { // inner try
875 2058 sgarg
876 4629 daigle
					NamingEnumeration namingEnum = ctx.search(ldapBase, filter, ctls);
877 2058 sgarg
878 4629 daigle
					// Print the groups
879
					while (namingEnum.hasMore()) {
880
						SearchResult sr = (SearchResult) namingEnum.next();
881 730 bojilova
882 4629 daigle
						tempAttr = sr.getAttributes();
883 730 bojilova
884 4629 daigle
						if ((tempAttr.get("description") + "")
885
								.startsWith("description: ")) {
886
							desc.add((tempAttr.get("description") + "").substring(13));
887
						} else {
888
							desc.add(tempAttr.get("description") + "");
889
						}
890 2058 sgarg
891 4629 daigle
						// check for an absolute URL value or an answer value
892
						// relative
893
						// to the target context
894
						if (!sr.getName().startsWith("ldap") && sr.isRelative()) {
895 5167 daigle
							logMetacat.debug("AuthLdap.getGroups - Search result entry is relative ...");
896 4629 daigle
							gvec.add(sr.getName() + "," + ldapBase);
897 5167 daigle
							logMetacat.info("AuthLdap.getGroups - group " + sr.getName() + "," + ldapBase
898 4629 daigle
									+ " added to the group vector");
899
						} else {
900 5167 daigle
							logMetacat.debug("AuthLdap.getGroups - Search result entry is absolute ...");
901 2058 sgarg
902 4629 daigle
							// search the top level directory for referral
903
							// objects and match
904
							// that of the search result's absolute URL. This
905
							// will let us
906
							// rebuild the group name from the search result,
907
							// referral point
908
							// in the top directory tree, and ldapBase.
909 2058 sgarg
910 4629 daigle
							// configure a new directory search first
911
							Hashtable envHash = new Hashtable(11);
912
							// Identify service provider to use
913
							envHash.put(Context.INITIAL_CONTEXT_FACTORY,
914
									"com.sun.jndi.ldap.LdapCtxFactory");
915
							envHash.put(Context.REFERRAL, "ignore");
916
							envHash.put(Context.PROVIDER_URL, ldapUrl);
917
							envHash.put("com.sun.jndi.ldap.connect.timeout",
918
									ldapConnectTimeLimit);
919 725 bojilova
920 4629 daigle
							try {
921
								// Create the initial directory context
922
								DirContext DirCtx = new InitialDirContext(envHash);
923 2058 sgarg
924 4629 daigle
								SearchControls searchCtls = new SearchControls();
925
								// Specify the ids of the attributes to return
926
								String[] attrNames = { "o" };
927
								searchCtls.setReturningAttributes(attrNames);
928
								// set the ldap search scope - only look for top
929
								// level referrals
930
								searchCtls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
931
								// set a time limit on searches to limit
932
								// non-responding servers
933
								searchCtls.setTimeLimit(ldapSearchTimeLimit);
934
								// return the configured number of entries
935
								searchCtls.setCountLimit(ldapSearchCountLimit);
936 503 bojilova
937 4629 daigle
								// Specify the attributes to match.
938
								// build the ldap search filter to match
939
								// referral entries that
940
								// match the search result
941
								String rFilter = "(&(objectClass=referral)(ref="
942
										+ currentReferralInfo.substring(0,
943
												currentReferralInfo.indexOf("?")) + "))";
944 5167 daigle
								logMetacat.debug("AuthLdap.getGroups - rFilter is: " + rFilter);
945 503 bojilova
946 4629 daigle
								NamingEnumeration rNamingEnum = DirCtx.search(ldapBase,
947
										rFilter, searchCtls);
948 2058 sgarg
949 4629 daigle
								while (rNamingEnum.hasMore()) {
950
									SearchResult rsr = (SearchResult) rNamingEnum.next();
951
									rsrAttr = rsr.getAttributes();
952 5167 daigle
									logMetacat.debug("AuthLdap.getGroups - referral search result is: "
953 4629 daigle
											+ rsr.toString());
954 725 bojilova
955 4629 daigle
									// add the returned groups to the group
956
									// vector. Test the
957
									// syntax of the returned attributes -
958
									// sometimes they are
959
									// preceded with the attribute id and a
960
									// colon
961
									if ((tempAttr.get("cn") + "").startsWith("cn: ")) {
962
										gvec.add("cn="
963
												+ (tempAttr.get("cn") + "").substring(4)
964
												+ "," + "o="
965
												+ (rsrAttr.get("o") + "").substring(3)
966
												+ "," + ldapBase);
967 5167 daigle
										logMetacat.info("AuthLdap.getGroups - group "
968 4629 daigle
												+ (tempAttr.get("cn") + "").substring(4)
969
												+ "," + "o="
970
												+ (rsrAttr.get("o") + "").substring(3)
971
												+ "," + ldapBase
972
												+ " added to the group vector");
973
									} else {
974
										gvec.add("cn=" + tempAttr.get("cn") + "," + "o="
975
												+ rsrAttr.get("o") + "," + ldapBase);
976 5167 daigle
										logMetacat.info("AuthLdap.getGroups - group " + "cn="
977 4629 daigle
												+ tempAttr.get("cn") + "," + "o="
978
												+ rsrAttr.get("o") + "," + ldapBase
979
												+ " added to the group vector");
980
									}
981
								}
982 723 bojilova
983 4629 daigle
							} catch (NamingException nameEx) {
984 5167 daigle
								logMetacat.debug("AuthLdap.getGroups - Caught naming exception: ");
985 4629 daigle
								nameEx.printStackTrace(System.err);
986
							}
987
						}
988
					}// end while
989 725 bojilova
990 4629 daigle
					moreReferrals = false;
991
992
				} catch (ReferralException re) {
993
994
					logMetacat
995 5167 daigle
							.info("AuthLdap.getGroups -  caught referral exception: "
996 4629 daigle
									+ re.getReferralInfo());
997
					this.currentReferralInfo = (String) re.getReferralInfo();
998
999
					// set moreReferrals to true and set the referral context
1000
					moreReferrals = true;
1001 5293 leinfelder
1002
					// try following referral, skip if error
1003
					boolean referralError = true;
1004
					while (referralError) {
1005
						try {
1006
							ctx = (DirContext) re.getReferralContext();
1007
							referralError = false;
1008
						}
1009
						catch (NamingException ne) {
1010
							logMetacat.error("NamingException when getting referral contex. Skipping this referral. " + ne.getMessage());
1011
							re.skipReferral();
1012
							referralError = true;
1013
						}
1014
					}
1015 4629 daigle
1016
				}// end inner try
1017
			}// end for
1018
1019
			// close the context now that all initial and referral
1020
			// searches are processed
1021
			ctx.close();
1022
1023
		} catch (NamingException e) {
1024
1025
			// naming exceptions get logged, groups are returned
1026 5167 daigle
			logMetacat.info("AuthLdap.getGroups - caught naming exception: ");
1027 4629 daigle
			e.printStackTrace(System.err);
1028
1029
		} finally {
1030
			// once all referrals are followed, report and return the groups
1031
			// found
1032 5167 daigle
			logMetacat.warn("AuthLdap.getGroups - The user is in the following groups: " + gvec.toString());
1033 4629 daigle
			// build and return the groups array
1034
			String groups[][] = new String[gvec.size()][2];
1035
			for (int i = 0; i < gvec.size(); i++) {
1036
				groups[i][0] = (String) gvec.elementAt(i);
1037
				groups[i][1] = (String) desc.elementAt(i);
1038
			}
1039
			return groups;
1040
		}// end outer try
1041
	}
1042
1043
	/**
1044
	 * Get attributes describing a user or group
1045
	 *
1046
	 * @param foruser
1047
	 *            the user for which the attribute list is requested
1048
	 * @returns HashMap a map of attribute name to a Vector of values
1049
	 */
1050
	public HashMap<String, Vector<String>> getAttributes(String foruser)
1051
			throws ConnectException {
1052
		return getAttributes(null, null, foruser);
1053
	}
1054
1055
	/**
1056
	 * Get attributes describing a user or group
1057
	 *
1058
	 * @param user
1059
	 *            the user for authenticating against the service
1060
	 * @param password
1061
	 *            the password for authenticating against the service
1062
	 * @param foruser
1063
	 *            the user whose attributes should be returned
1064
	 * @returns HashMap a map of attribute name to a Vector of values
1065
	 */
1066
	public HashMap<String, Vector<String>> getAttributes(String user, String password,
1067
			String foruser) throws ConnectException {
1068
		HashMap<String, Vector<String>> attributes = new HashMap<String, Vector<String>>();
1069
		String ldapUrl = this.ldapUrl;
1070
		String ldapBase = this.ldapBase;
1071
		String userident = foruser;
1072
1073
		// Identify service provider to use
1074
		Hashtable env = new Hashtable(11);
1075
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
1076
		env.put(Context.REFERRAL, referral);
1077
		env.put(Context.PROVIDER_URL, ldapUrl);
1078
1079
		try {
1080
1081
			// Create the initial directory context
1082
			DirContext ctx = new InitialDirContext(env);
1083
1084
			// Ask for all attributes of the user
1085
			// Attributes attrs = ctx.getAttributes(userident);
1086
			Attributes attrs = ctx.getAttributes(foruser);
1087
1088
			// Print all of the attributes
1089
			NamingEnumeration en = attrs.getAll();
1090
			while (en.hasMore()) {
1091
				Attribute att = (Attribute) en.next();
1092
				Vector<String> values = new Vector();
1093
				String attName = att.getID();
1094
				NamingEnumeration attvalues = att.getAll();
1095
				while (attvalues.hasMore()) {
1096 6037 jones
				    try {
1097
				        String value = (String) attvalues.next();
1098
				        values.add(value);
1099
				    } catch (ClassCastException cce) {
1100
				        logMetacat.debug("Could not cast LDAP attribute (" +
1101
				                attName + ") to a String value, so skipping.");
1102
				    }
1103 4629 daigle
				}
1104
				attributes.put(attName, values);
1105
			}
1106
1107
			// Close the context when we're done
1108
			ctx.close();
1109
		} catch (NamingException e) {
1110 5167 daigle
			logMetacat.error("AuthLdap.getAttributes - Problem getting attributes:"
1111 4629 daigle
					+ e);
1112
			throw new ConnectException(
1113
					"Problem getting attributes in AuthLdap.getAttributes:" + e);
1114
		}
1115
1116
		return attributes;
1117
	}
1118
1119
	/**
1120
	 * Get list of all subtrees holding Metacat's groups and users starting from
1121
	 * the Metacat LDAP root, i.e.
1122
	 * ldap://dev.nceas.ucsb.edu/dc=ecoinformatics,dc=org
1123
	 */
1124
	private Hashtable getSubtrees(String user, String password, String ldapUrl,
1125
			String ldapBase) throws ConnectException {
1126 5157 daigle
		logMetacat.debug("AuthLdap.getSubtrees - getting subtrees for user: " + user +
1127
				", ldapUrl: " + ldapUrl + ", ldapBase: " + ldapBase);
1128 4629 daigle
		Hashtable trees = new Hashtable();
1129
1130
		// Identify service provider to use
1131
		Hashtable env = new Hashtable(11);
1132
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
1133
		// env.put(Context.REFERRAL, referral);
1134
		// Using 'ignore' here instead of 'follow' as 'ignore' seems
1135
		// to do the job better. 'follow' was not bringing up the UCNRS
1136
		// and PISCO tree whereas 'ignore' brings up the tree.
1137
1138
		env.put(Context.REFERRAL, "ignore");
1139
		env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
1140
1141
		try {
1142
1143
			// Create the initial directory context
1144
			DirContext ctx = new InitialDirContext(env);
1145
1146
			// Specify the ids of the attributes to return
1147
			String[] attrIDs = { "o", "ref" };
1148
			SearchControls ctls = new SearchControls();
1149
			ctls.setReturningAttributes(attrIDs);
1150
			ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
1151
1152
			// Specify the attributes to match.
1153
			// Subtrees from the main server are found as objects with attribute
1154
			// objectclass=organization or objectclass=referral to the subtree
1155
			// resided on other server.
1156
			String filter = "(|(objectclass=organization)(objectclass=referral))";
1157
1158
			// Search for objects in the current context
1159
			NamingEnumeration namingEnum = ctx.search("", filter, ctls);
1160
1161
			// Print the subtrees' <ldapURL, baseDN>
1162
			while (namingEnum.hasMore()) {
1163
1164
				SearchResult sr = (SearchResult) namingEnum.next();
1165 5157 daigle
				logMetacat.debug("AuthLdap.getSubtrees - search result: " + sr.toString());
1166 4629 daigle
1167
				Attributes attrs = sr.getAttributes();
1168
				NamingEnumeration enum1 = attrs.getAll(); // "dc" and "ref"
1169
															// attrs
1170
1171
				if (enum1.hasMore()) {
1172
					Attribute attr = (Attribute) enum1.next();
1173
					String attrValue = (String) attr.get();
1174
					String attrName = (String) attr.getID();
1175
1176
					if (enum1.hasMore()) {
1177
						attr = (Attribute) enum1.next();
1178
						String refValue = (String) attr.get();
1179
						String refName = (String) attr.getID();
1180
						if (ldapBase.startsWith(refName + "=" + refValue)) {
1181
							trees.put(ldapBase, attrValue.substring(0, attrValue
1182
									.lastIndexOf("/") + 1));
1183
						} else {
1184
							// this is a referral - so organization name is
1185 5157 daigle
							// appended in front of the ldapbase.... later it is
1186
							// stripped out in getPrincipals
1187
							trees.put("[" + refName + "=" + refValue + "]" +
1188
									attrValue.substring(attrValue.lastIndexOf("/") + 1,
1189 4629 daigle
											attrValue.length()), attrValue.substring(0,
1190 5157 daigle
													attrValue.lastIndexOf("/") + 1));
1191 4629 daigle
1192
							// trees.put(refName + "=" + refValue + "," +
1193 5157 daigle
							// ldapBase, attrValue.substring(0, attrValue.lastIndexOf("/")
1194 4629 daigle
							// + 1));
1195
						}
1196
1197
					} else if (ldapBase.startsWith(attrName + "=" + attrValue)) {
1198
						trees.put(ldapBase, ldapUrl);
1199
					} else {
1200
						if (sr.isRelative()) {
1201
							trees.put(attrName + "=" + attrValue + "," + ldapBase,
1202
									ldapUrl);
1203
						} else {
1204
							String referenceURL = sr.getName();
1205
							referenceURL = referenceURL.substring(0, referenceURL
1206
									.lastIndexOf("/") + 1);
1207
							trees.put(attrName + "=" + attrValue + "," + ldapBase,
1208
									referenceURL);
1209
						}
1210
1211
					}
1212
				}
1213
			}
1214
1215
			// Close the context when we're done
1216
			ctx.close();
1217
1218
		} catch (NamingException e) {
1219 5157 daigle
			logMetacat.error("AuthLdap.getSubtrees - Problem getting subtrees in AuthLdap.getSubtrees:" + e);
1220 4629 daigle
			throw new ConnectException(
1221
					"Problem getting subtrees in AuthLdap.getSubtrees:" + e);
1222
		}
1223
1224
		return trees;
1225
	}
1226
1227
	/**
1228
	 * Get all groups and users from authentication scheme. The output is
1229
	 * formatted in XML.
1230
	 *
1231
	 * @param user
1232
	 *            the user which requests the information
1233
	 * @param password
1234
	 *            the user's password
1235
	 */
1236
	public String getPrincipals(String user, String password) throws ConnectException {
1237
		StringBuffer out = new StringBuffer();
1238
1239
		out.append("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n");
1240
		out.append("<principals>\n");
1241
1242
		/*
1243
		 * get all subtrees first in the current dir context and then the
1244
		 * Metacat users under them
1245
		 */
1246
		Hashtable subtrees = getSubtrees(user, password, this.ldapUrl, this.ldapBase);
1247
1248
		Enumeration keyEnum = subtrees.keys();
1249
		while (keyEnum.hasMoreElements()) {
1250
			this.ldapBase = (String) keyEnum.nextElement();
1251
			this.ldapUrl = (String) subtrees.get(ldapBase);
1252 5157 daigle
			logMetacat.info("AuthLdap.getPrincipals - ldapBase: " + ldapBase +
1253
					", ldapUrl: " + ldapUrl);
1254 4629 daigle
			/*
1255
			 * code to get the organization name from ldapBase
1256
			 */
1257
			String orgName = this.ldapBase;
1258
			if (orgName.startsWith("[")) {
1259
				// if orgName starts with [ then it is a referral URL...
1260 5157 daigle
				// (see code in getSubtress) hence orgName can be retrieved by
1261
				// getting the string between 'o=' and ']' also the string between
1262
				// [ and ] needs to be striped out from this.ldapBase
1263 4629 daigle
				this.ldapBase = orgName.substring(orgName.indexOf("]") + 1);
1264
				if (orgName != null && orgName.indexOf("o=") > -1) {
1265
					orgName = orgName.substring(orgName.indexOf("o=") + 2);
1266
					orgName = orgName.substring(0, orgName.indexOf("]"));
1267
				}
1268
			} else {
1269
				// else it is not referral
1270
				// hence orgName can be retrieved by getting the string between
1271
				// 'o=' and ','
1272
				if (orgName != null && orgName.indexOf("o=") > -1) {
1273
					orgName = orgName.substring(orgName.indexOf("o=") + 2);
1274
					if (orgName.indexOf(",") > -1) {
1275
						orgName = orgName.substring(0, orgName.indexOf(","));
1276
					}
1277
				}
1278
			}
1279 5157 daigle
			logMetacat.info("AuthLdap.getPrincipals - org name is  " + orgName);
1280 4629 daigle
			out.append("  <authSystem URI=\"" + this.ldapUrl + this.ldapBase
1281
					+ "\" organization=\"" + orgName + "\">\n");
1282
1283
			// get all groups for directory context
1284
			String[][] groups = getGroups(user, password);
1285 5157 daigle
			logMetacat.debug("AuthLdap.getPrincipals - after getting groups " + groups);
1286 4629 daigle
			String[][] users = getUsers(user, password);
1287 5157 daigle
			logMetacat.debug("AuthLdap.getPrincipals - after getting users " + users);
1288 4629 daigle
			int userIndex = 0;
1289
1290
			// for the groups and users that belong to them
1291
			if (groups != null && users != null && groups.length > 0) {
1292
				for (int i = 0; i < groups.length; i++) {
1293
					out.append("    <group>\n");
1294
					out.append("      <groupname>" + groups[i][0] + "</groupname>\n");
1295
					out.append("      <description>" + groups[i][1] + "</description>\n");
1296
					String[] usersForGroup = getUsers(user, password, groups[i][0]);
1297
					for (int j = 0; j < usersForGroup.length; j++) {
1298
						userIndex = searchUser(usersForGroup[j], users);
1299
						out.append("      <user>\n");
1300
1301
						if (userIndex < 0) {
1302
							out.append("        <username>" + usersForGroup[j]
1303
									+ "</username>\n");
1304
						} else {
1305
							out.append("        <username>" + users[userIndex][0]
1306
									+ "</username>\n");
1307
							out.append("        <name>" + users[userIndex][1]
1308
									+ "</name>\n");
1309
							out.append("        <organization>" + users[userIndex][2]
1310
									+ "</organization>\n");
1311
							if (users[userIndex][3].compareTo("null") != 0) {
1312
								out.append("      <organizationUnitName>"
1313
										+ users[userIndex][3]
1314
										+ "</organizationUnitName>\n");
1315
							}
1316
							out.append("        <email>" + users[userIndex][4]
1317
									+ "</email>\n");
1318
						}
1319
1320
						out.append("      </user>\n");
1321
					}
1322
					out.append("    </group>\n");
1323
				}
1324
			}
1325
1326
			if (users != null) {
1327
				// for the users not belonging to any grou8p
1328
				for (int j = 0; j < users.length; j++) {
1329
					out.append("    <user>\n");
1330
					out.append("      <username>" + users[j][0] + "</username>\n");
1331
					out.append("      <name>" + users[j][1] + "</name>\n");
1332
					out
1333
							.append("      <organization>" + users[j][2]
1334
									+ "</organization>\n");
1335
					if (users[j][3].compareTo("null") != 0) {
1336
						out.append("      <organizationUnitName>" + users[j][3]
1337
								+ "</organizationUnitName>\n");
1338
					}
1339
					out.append("      <email>" + users[j][4] + "</email>\n");
1340
					out.append("    </user>\n");
1341
				}
1342
			}
1343
1344
			out.append("  </authSystem>\n");
1345
		}
1346
		out.append("</principals>");
1347
		return out.toString();
1348
	}
1349
1350
	/**
1351
	 * Method for getting index of user DN in User info array
1352
	 */
1353 8431 tao
	public static int searchUser(String user, String userGroup[][]) {
1354 4629 daigle
		for (int j = 0; j < userGroup.length; j++) {
1355
			if (user.compareTo(userGroup[j][0]) == 0) {
1356
				return j;
1357
			}
1358
		}
1359
		return -1;
1360
	}
1361
1362
	public void testCredentials(String dn, String password, String rootServer,
1363
			String rootBase) throws NamingException {
1364
1365
		String server = "";
1366
		String userDN = "";
1367
		logMetacat.debug("dn is: " + dn);
1368
1369
		int position = dn.lastIndexOf("/");
1370 5167 daigle
		logMetacat.debug("AuthLdap.testCredentials - position is: " + position);
1371 4629 daigle
		if (position == -1) {
1372
			server = rootServer;
1373
			if (dn.indexOf(userDN) < 0) {
1374
				userDN = dn + "," + rootBase;
1375
			} else {
1376
				userDN = dn;
1377
			}
1378 5167 daigle
			logMetacat.debug("AuthLdap.testCredentials - userDN is: " + userDN);
1379 4629 daigle
1380
		} else {
1381
			server = dn.substring(0, position + 1);
1382
			userDN = dn.substring(position + 1);
1383 5167 daigle
			logMetacat.debug("AuthLdap.testCredentials - server is: " + server);
1384
			logMetacat.debug("AuthLdap.testCredentials - userDN is: " + userDN);
1385 4629 daigle
		}
1386
1387 5167 daigle
		logMetacat.debug("AuthLdap.testCredentials - Trying to authenticate: " + userDN + " using server: " + server);
1388 4629 daigle
1389
		// /* try {
1390
		LdapContext ctx = null;
1391
1392
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
1393
		env.put(Context.REFERRAL, "follow");
1394
		env.put(Context.SECURITY_AUTHENTICATION, "simple");
1395
		env.put(Context.SECURITY_PRINCIPAL, userDN);
1396
		env.put(Context.SECURITY_CREDENTIALS, password);
1397
		env.put(Context.PROVIDER_URL, rootServer);
1398
1399
		ctx = new InitialLdapContext(env, null);
1400
1401
	}
1402
1403
	/**
1404 4080 daigle
	 * Test method for the class
1405
	 */
1406
	public static void main(String[] args) {
1407 871 jones
1408 4080 daigle
		// Provide a user, such as: "Matt Jones", or "jones"
1409
		String user = args[0];
1410
		String password = args[1];
1411
		String org = args[2];
1412 871 jones
1413 5167 daigle
		logMetacat.warn("AuthLdap.main - Creating session...");
1414 4080 daigle
		AuthLdap authservice = null;
1415
		try {
1416
			authservice = new AuthLdap();
1417
		} catch (Exception e) {
1418 5167 daigle
			logMetacat.error("AuthLdap.main - Could not instantiate AuthLdap: " + e.getMessage());
1419 4080 daigle
			return;
1420
		}
1421 5167 daigle
		logMetacat.warn("AuthLdap.main - Session exists...");
1422 2058 sgarg
1423 4080 daigle
		boolean isValid = false;
1424
		try {
1425 5167 daigle
			logMetacat.warn("AuthLdap.main - Authenticating...");
1426 4080 daigle
			isValid = authservice.authenticate(user, password);
1427
			if (isValid) {
1428 5167 daigle
				logMetacat.warn("AuthLdap.main - Authentication successful for: " + user);
1429 4080 daigle
			} else {
1430 5167 daigle
				logMetacat.warn("AuthLdap.main - Authentication failed for: " + user);
1431 4080 daigle
			}
1432 873 jones
1433 4080 daigle
			// Get attributes for the user
1434
			if (isValid) {
1435 5167 daigle
				logMetacat.info("AuthLdap.main - Getting attributes for user....");
1436 4629 daigle
				HashMap userInfo = authservice.getAttributes(user, password, user);
1437 4080 daigle
				// Print all of the attributes
1438 4629 daigle
				Iterator attList = (Iterator) (((Set) userInfo.keySet()).iterator());
1439 4080 daigle
				while (attList.hasNext()) {
1440
					String att = (String) attList.next();
1441
					Vector values = (Vector) userInfo.get(att);
1442
					Iterator attvalues = values.iterator();
1443
					while (attvalues.hasNext()) {
1444
						String value = (String) attvalues.next();
1445 5167 daigle
						logMetacat.warn("AuthLdap.main - " + att + ": " + value);
1446 4080 daigle
					}
1447
				}
1448
			}
1449 873 jones
1450 4080 daigle
			// get the groups
1451
			if (isValid) {
1452 5167 daigle
				logMetacat.warn("AuthLdap.main - Getting all groups....");
1453 4080 daigle
				String[][] groups = authservice.getGroups(user, password);
1454 5167 daigle
				logMetacat.info("AuthLdap.main - Groups found: " + groups.length);
1455 4080 daigle
				for (int i = 0; i < groups.length; i++) {
1456 5167 daigle
					logMetacat.info("AuthLdap.main - Group " + i + ": " + groups[i][0]);
1457 4080 daigle
				}
1458
			}
1459 2058 sgarg
1460 4080 daigle
			// get the groups for the user
1461
			String savedGroup = null;
1462
			if (isValid) {
1463 5167 daigle
				logMetacat.warn("AuthLdap.main - Getting groups for user....");
1464 4080 daigle
				String[][] groups = authservice.getGroups(user, password, user);
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
					savedGroup = groups[i][0];
1469
				}
1470
			}
1471
1472
			// get the users for a group
1473
			if (isValid) {
1474 5167 daigle
				logMetacat.warn("AuthLdap.main - Getting users for group....");
1475
				logMetacat.info("AuthLdap.main - Group: " + savedGroup);
1476 4629 daigle
				String[] users = authservice.getUsers(user, password, savedGroup);
1477 5167 daigle
				logMetacat.info("AuthLdap.main - Users found: " + users.length);
1478 4080 daigle
				for (int i = 0; i < users.length; i++) {
1479 5167 daigle
					logMetacat.warn("AuthLdap.main - User " + i + ": " + users[i]);
1480 4080 daigle
				}
1481
			}
1482
1483
			// get all users
1484
			if (isValid) {
1485 5167 daigle
				logMetacat.warn("AuthLdap.main - Getting all users ....");
1486 4080 daigle
				String[][] users = authservice.getUsers(user, password);
1487 5167 daigle
				logMetacat.info("AuthLdap.main - Users found: " + users.length);
1488 4080 daigle
1489
			}
1490
1491
			// get the whole list groups and users in XML format
1492
			if (isValid) {
1493 5167 daigle
				logMetacat.warn("AuthLdap.main - Trying principals....");
1494 4080 daigle
				authservice = new AuthLdap();
1495
				String out = authservice.getPrincipals(user, password);
1496
				java.io.File f = new java.io.File("principals.xml");
1497
				java.io.FileWriter fw = new java.io.FileWriter(f);
1498
				java.io.BufferedWriter buff = new java.io.BufferedWriter(fw);
1499
				buff.write(out);
1500
				buff.flush();
1501
				buff.close();
1502
				fw.close();
1503 5167 daigle
				logMetacat.warn("AuthLdap.main - Finished getting principals.");
1504 4080 daigle
			}
1505
1506
		} catch (ConnectException ce) {
1507 5167 daigle
			logMetacat.error("AuthLdap.main - " + ce.getMessage());
1508 4080 daigle
		} catch (java.io.IOException ioe) {
1509 5167 daigle
			logMetacat.error("AuthLdap.main - I/O Error writing to file principals.txt: "
1510 4080 daigle
					+ ioe.getMessage());
1511
		} catch (InstantiationException ie) {
1512 5167 daigle
			logMetacat.error("AuthLdap.main - Instantiation error writing to file principals.txt: "
1513 4629 daigle
					+ ie.getMessage());
1514 4080 daigle
		}
1515
	}
1516
1517 4629 daigle
	/**
1518
	 * This method will be called by start a thread. It can handle if a referral
1519
	 * exception happend.
1520
	 */
1521 503 bojilova
}