Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: An implementation of the AuthInterface interface that
4
 *             allows Metacat to use the LDAP protocol for
5
 *             directory services
6
 *  Copyright: 2000 Regents of the University of California and the
7
 *             National Center for Ecological Analysis and Synthesis
8
 *    Authors: Matt Jones
9
 *
10
 *   '$Author: tao $'
11
 *     '$Date: 2013-12-23 13:29:03 -0800 (Mon, 23 Dec 2013) $'
12
 * '$Revision: 8460 $'
13
 *
14
 * This program is free software; you can redistribute it and/or modify
15
 * it under the terms of the GNU General Public License as published by
16
 * the Free Software Foundation; either version 2 of the License, or
17
 * (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU General Public License
25
 * along with this program; if not, write to the Free Software
26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27
 */
28

    
29
package edu.ucsb.nceas.metacat;
30

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

    
50
import org.apache.log4j.Logger;
51

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
216
		return authenticated;
217
	}
218

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

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

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

    
248
		boolean authenticated = false;
249

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

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

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

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

    
275
		try {
276
			Hashtable<String, String> env = new Hashtable<String, String>();
277
			env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
278
			env.put(Context.PROVIDER_URL, server);
279
			env.put(Context.REFERRAL, "throw");
280
			
281
			try {
282
				authenticated = authenticateTLS(env, userDN, password);
283
			} catch (AuthTLSException ate) {
284
				logMetacat.info("AuthLdap.ldapAuthenticate - error while negotiating TLS: "
285
						+ ate.getMessage());
286

    
287
				if (secureConnectionOnly) {
288
					return authenticated;
289

    
290
				} else {
291
					authenticated = authenticateNonTLS(env, userDN, password);
292
				}
293
			}
294
		} catch (AuthenticationException ae) {
295
			logMetacat.warn("Authentication exception: " + ae.getMessage());
296
			authenticated = false;
297
		} catch (javax.naming.InvalidNameException ine) {
298
			logMetacat.error("AuthLdap.ldapAuthenticate - An invalid DN was provided: " + ine.getMessage());
299
		} catch (NamingException ne) {
300
			logMetacat.warn("AuthLdap.ldapAuthenticate - Caught NamingException in login: " + ne.getClass().getName());
301
			logMetacat.info(ne.toString() + "  " + ne.getRootCause());
302
		}
303

    
304
		return authenticated;
305
	}
306
	
307
	
308
	/*
309
	 * Get the aliased dn through a TLS connection
310
	 */
311
	private String getAliasedDnTLS(String alias, Hashtable<String, String> env) throws NamingException, IOException {
312
	    boolean useTLS = true;
313
	    return getAliasedDn(alias, env, useTLS);
314
	}
315
	
316
	/*
317
     * Get the aliased dn through a non-TLS connection
318
     */
319
    private String getAliasedDnNonTLS(String alias, Hashtable<String, String> env) throws NamingException, IOException {
320
        boolean useTLS = false;
321
        return getAliasedDn(alias, env, useTLS);
322
    }
323
	
324
	/*
325
	 * Get the aliasedDN (the real DN) for a specified an alias name
326
	 */
327
	public String getAliasedDn(String alias, Hashtable<String, String> env, boolean useTLS) throws NamingException, IOException  {
328
	    String aliasedDn = null;
329
        LdapContext sctx = new InitialLdapContext(env, null);
330
        StartTlsResponse tls = null;
331
        if(useTLS) {
332
            tls = (StartTlsResponse) sctx.extendedOperation(new StartTlsRequest());
333
            // Open a TLS connection (over the existing LDAP association) and get details
334
            // of the negotiated TLS session: cipher suite, peer certificate, etc.
335
            SSLSession session = tls.negotiate();
336
        }
337
        SearchControls ctls = new SearchControls();
338
        ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
339
        String filter = "(objectClass=*)";
340
        NamingEnumeration answer  = sctx.search(alias, filter, ctls);
341
        while(answer.hasMore()) {
342
            SearchResult result = (SearchResult) answer.next();
343
            if(!result.isRelative()) {
344
                //if is not relative, this will be alias.
345
                aliasedDn = result.getNameInNamespace();
346
                break;
347
            }
348
        }
349
        if(useTLS && tls != null) {
350
            tls.close();
351
        }
352
        sctx.close();
353
        return aliasedDn;
354
	    
355
	}
356
	
357
	private boolean authenticateTLS(Hashtable<String, String> env, String userDN, String password)
358
			throws AuthTLSException{	
359
		logMetacat.info("AuthLdap.authenticateTLS - Trying to authenticate with TLS");
360
		try {
361
			LdapContext ctx = null;
362
			double startTime;
363
			double stopTime;
364
			startTime = System.currentTimeMillis();
365
			ctx = new InitialLdapContext(env, null);
366
			// Start up TLS here so that we don't pass our jewels in
367
			// cleartext
368
			StartTlsResponse tls = 
369
				(StartTlsResponse) ctx.extendedOperation(new StartTlsRequest());
370
			// tls.setHostnameVerifier(new SampleVerifier());
371
			SSLSession sess = tls.negotiate();
372
			ctx.addToEnvironment(Context.SECURITY_AUTHENTICATION, "simple");
373
			ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, userDN);
374
			ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, password);
375
			ctx.reconnect(null);
376
			stopTime = System.currentTimeMillis();
377
			logMetacat.info("AuthLdap.authenticateTLS - Connection time thru "
378
					+ ldapsUrl + " was: " + (stopTime - startTime) / 1000 + " seconds.");
379
		} catch (NamingException ne) {
380
			throw new AuthTLSException("AuthLdap.authenticateTLS - Naming error when athenticating via TLS: " + ne.getMessage());
381
		} catch (IOException ioe) {
382
			throw new AuthTLSException("AuthLdap.authenticateTLS - I/O error when athenticating via TLS: " + ioe.getMessage());
383
		}
384
		return true;
385
	}
386
	
387
	private boolean authenticateNonTLS(Hashtable<String, String> env, String userDN, String password) 
388
			throws NamingException {
389
		LdapContext ctx = null;
390
		double startTime;
391
		double stopTime;
392
		
393
		logMetacat.info("AuthLdap.authenticateNonTLS - Trying to authenticate without TLS");
394
		env.put(Context.SECURITY_AUTHENTICATION, "simple");
395
		env.put(Context.SECURITY_PRINCIPAL, userDN);
396
		env.put(Context.SECURITY_CREDENTIALS, password);
397

    
398
		startTime = System.currentTimeMillis();
399
		ctx = new InitialLdapContext(env, null);
400
		stopTime = System.currentTimeMillis();
401
		logMetacat.info("AuthLdap.authenticateNonTLS - Connection time thru " + ldapsUrl + " was: "
402
				+ (stopTime - startTime) / 1000 + " seconds.");
403

    
404
		return true;
405
	}
406

    
407
	/**
408
	 * Get the identifying name for a given userid or name. This is the name
409
	 * that is used in conjunction withthe LDAP BaseDN to create a distinguished
410
	 * name (dn) for the record
411
	 * 
412
	 * @param user
413
	 *            the user for which the identifying name is requested
414
	 * @returns String the identifying name for the user, or null if not found
415
	 */
416
	private String getIdentifyingName(String user, String ldapUrl, String ldapBase)
417
			throws NamingException {
418

    
419
		String identifier = null;
420
		Hashtable env = new Hashtable();
421
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
422
		env.put(Context.REFERRAL, "throw");
423
		env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
424
		try {
425
			int position = user.indexOf(",");
426
			String uid = user.substring(user.indexOf("=") + 1, position);
427
			logMetacat.info("AuthLdap.getIdentifyingName - uid is: " + uid);
428
			String org = user.substring(user.indexOf("=", position + 1) + 1, user
429
					.indexOf(",", position + 1));
430
			logMetacat.info("AuthLdap.getIdentifyingName - org is: " + org);
431

    
432
			DirContext sctx = new InitialDirContext(env);
433
			SearchControls ctls = new SearchControls();
434
			ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
435
			String filter = "(&(uid=" + uid + ")(o=" + org + "))";
436
			logMetacat.warn("AuthLdap.getIdentifyingName - Searching for DNs with following filter: " + filter);
437

    
438
			for (boolean moreReferrals = true; moreReferrals;) {
439
				try {
440
					// Perform the search
441
				    
442
					NamingEnumeration answer = sctx.search("", filter, ctls);
443

    
444
					// Return the answer
445
					while (answer.hasMore()) {
446
						SearchResult sr = (SearchResult) answer.next();
447
						identifier = sr.getName();
448
						return identifier;
449
					}
450
					// The search completes with no more referrals
451
					moreReferrals = false;
452
				} catch (ReferralException e) {
453
					logMetacat.info("AuthLdap.getIdentifyingName - Got referral: " + e.getReferralInfo());
454
					// Point to the new context from the referral
455
					if (moreReferrals) {
456
						// try following referral, skip if error
457
						boolean referralError = true;
458
						while (referralError) {
459
							try {
460
								sctx = (DirContext) e.getReferralContext();
461
								referralError = false;
462
							}
463
							catch (NamingException ne) {
464
								logMetacat.error("NamingException when getting referral contex. Skipping this referral. " + ne.getMessage());
465
								e.skipReferral();
466
								referralError = true;
467
							}
468
						}
469
					}
470
				}				
471
			}
472
		} catch (NamingException e) {
473
			logMetacat.error("AuthLdap.getIdentifyingName - Naming exception while getting dn: " + e);
474
			throw new NamingException("Naming exception in AuthLdap.getIdentifyingName: "
475
					+ e);
476
		}
477
		return identifier;
478
	}
479

    
480
	/**
481
	 * Get all users from the authentication service
482
	 * 
483
	 * @param user
484
	 *            the user for authenticating against the service
485
	 * @param password
486
	 *            the password for authenticating against the service
487
	 * @returns string array of all of the user names
488
	 */
489
	public String[][] getUsers(String user, String password) throws ConnectException {
490
		String[][] users = null;
491

    
492
		// Identify service provider to use
493
		Hashtable env = new Hashtable(11);
494
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
495
		env.put(Context.REFERRAL, referral);
496
		env.put(Context.PROVIDER_URL, ldapUrl);
497
		env.put("com.sun.jndi.ldap.connect.timeout", ldapConnectTimeLimit);
498

    
499
		try {
500

    
501
			// Create the initial directory context
502
			DirContext ctx = new InitialDirContext(env);
503

    
504
			// Specify the attributes to match.
505
			// Users are objects that have the attribute
506
			// objectclass=InetOrgPerson.
507
			SearchControls ctls = new SearchControls();
508
			String[] attrIDs = { "dn", "cn", "o", "ou", "mail" };
509
			ctls.setReturningAttributes(attrIDs);
510
			ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
511
			ctls.setTimeLimit(ldapSearchTimeLimit);
512
			// ctls.setCountLimit(1000);
513
			String filter = "(objectClass=inetOrgPerson)";
514
			NamingEnumeration namingEnum = ctx.search(ldapBase, filter, ctls);
515

    
516
			// Store the users in a vector
517
			Vector uvec = new Vector();
518
			Vector uname = new Vector();
519
			Vector uorg = new Vector();
520
			Vector uou = new Vector();
521
			Vector umail = new Vector();
522
			Attributes tempAttr = null;
523
			try {
524
				while (namingEnum.hasMore()) {
525
					SearchResult sr = (SearchResult) namingEnum.next();
526
					tempAttr = sr.getAttributes();
527

    
528
					if ((tempAttr.get("cn") + "").startsWith("cn: ")) {
529
						uname.add((tempAttr.get("cn") + "").substring(4));
530
					} else {
531
						uname.add(tempAttr.get("cn") + "");
532
					}
533

    
534
					if ((tempAttr.get("o") + "").startsWith("o: ")) {
535
						uorg.add((tempAttr.get("o") + "").substring(3));
536
					} else {
537
						uorg.add(tempAttr.get("o") + "");
538
					}
539

    
540
					if ((tempAttr.get("ou") + "").startsWith("ou: ")) {
541
						uou.add((tempAttr.get("ou") + "").substring(4));
542
					} else {
543
						uou.add(tempAttr.get("ou") + "");
544
					}
545

    
546
					if ((tempAttr.get("mail") + "").startsWith("mail: ")) {
547
						umail.add((tempAttr.get("mail") + "").substring(6));
548
					} else {
549
						umail.add(tempAttr.get("mail") + "");
550
					}
551

    
552
					uvec.add(sr.getName() + "," + ldapBase);
553
				}
554
			} catch (SizeLimitExceededException slee) {
555
				logMetacat.error("AuthLdap.getUsers - LDAP Server size limit exceeded. "
556
						+ "Returning incomplete record set.");
557
			}
558

    
559
			// initialize users[]; fill users[]
560
			users = new String[uvec.size()][5];
561
			for (int i = 0; i < uvec.size(); i++) {
562
				users[i][0] = (String) uvec.elementAt(i);
563
				users[i][1] = (String) uname.elementAt(i);
564
				users[i][2] = (String) uorg.elementAt(i);
565
				users[i][3] = (String) uorg.elementAt(i);
566
				users[i][4] = (String) umail.elementAt(i);
567
			}
568

    
569
			// Close the context when we're done
570
			ctx.close();
571

    
572
		} catch (NamingException e) {
573
			logMetacat.error("AuthLdap.getUsers - Problem getting users in AuthLdap.getUsers:" + e);
574
			// e.printStackTrace(System.err);
575
			/*
576
			 * throw new ConnectException( "Problem getting users in
577
			 * AuthLdap.getUsers:" + e);
578
			 */
579
		}
580

    
581
		return users;
582
	}
583

    
584
	/**
585
	 * Get all users from the authentication service
586
	 * 
587
	 * @param user
588
	 *            the user for authenticating against the service
589
	 * @param password
590
	 *            the password for authenticating against the service
591
	 * @returns string array of all of the user names
592
	 */
593
	public String[] getUserInfo(String user, String password) throws ConnectException {
594
		String[] userinfo = new String[3];
595

    
596
		// Identify service provider to use
597
		Hashtable env = new Hashtable(11);
598
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
599
		env.put(Context.REFERRAL, referral);
600
		env.put(Context.PROVIDER_URL, ldapUrl);
601

    
602
		try {
603

    
604
			// Create the initial directory context
605
			DirContext ctx = new InitialDirContext(env);
606
			// Specify the attributes to match.
607
			// Users are objects that have the attribute
608
			// objectclass=InetOrgPerson.
609
			SearchControls ctls = new SearchControls();
610
			String[] attrIDs = { "cn", "o", "mail" };
611
			ctls.setReturningAttributes(attrIDs);
612
			ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
613
			// ctls.setCountLimit(1000);
614
			// create the filter based on the uid
615

    
616
			String filter = null;
617

    
618
			if (user.indexOf("o=") > 0) {
619
				String tempStr = user.substring(user.indexOf("o="));
620
				filter = "(&(" + user.substring(0, user.indexOf(",")) + ")("
621
						+ tempStr.substring(0, tempStr.indexOf(",")) + "))";
622
			} else {
623
				filter = "(&(" + user.substring(0, user.indexOf(",")) + "))";
624
			}
625
			filter = "(&(" + user.substring(0, user.indexOf(",")) + "))";
626

    
627
			NamingEnumeration namingEnum = ctx.search(user, filter, ctls);
628

    
629
			Attributes tempAttr = null;
630
			try {
631
				while (namingEnum.hasMore()) {
632
					SearchResult sr = (SearchResult) namingEnum.next();
633
					tempAttr = sr.getAttributes();
634

    
635
					if ((tempAttr.get("cn") + "").startsWith("cn: ")) {
636
						userinfo[0] = (tempAttr.get("cn") + "").substring(4);
637
					} else {
638
						userinfo[0] = (tempAttr.get("cn") + "");
639
					}
640

    
641
					if ((tempAttr.get("o") + "").startsWith("o: ")) {
642
						userinfo[1] = (tempAttr.get("o") + "").substring(3);
643
					} else {
644
						userinfo[1] = (tempAttr.get("o") + "");
645
					}
646

    
647
					if ((tempAttr.get("mail") + "").startsWith("mail: ")) {
648
						userinfo[2] = (tempAttr.get("mail") + "").substring(6);
649
					} else {
650
						userinfo[2] = (tempAttr.get("mail") + "");
651
					}
652
				}
653
			} catch (SizeLimitExceededException slee) {
654
				logMetacat.error("AuthLdap.getUserInfo - LDAP Server size limit exceeded. "
655
						+ "Returning incomplete record set.");
656
			}
657

    
658
			// Close the context when we're done
659
			ctx.close();
660

    
661
		} catch (NamingException e) {
662
			logMetacat.error("AuthLdap.getUserInfo - Problem getting users:" + e);
663
			// e.printStackTrace(System.err);
664
			throw new ConnectException("Problem getting users in AuthLdap.getUsers:" + e);
665
		}
666

    
667
		return userinfo;
668
	}
669

    
670
	/**
671
	 * Get the users for a particular group from the authentication service
672
	 * 
673
	 * @param user
674
	 *            the user for authenticating against the service
675
	 * @param password
676
	 *            the password for authenticating against the service
677
	 * @param group
678
	 *            the group whose user list should be returned
679
	 * @returns string array of the user names belonging to the group
680
	 */
681
	public String[] getUsers(String user, String password, String group)
682
			throws ConnectException {
683
		String[] users = null;
684

    
685
		// Identify service provider to use
686
		Hashtable env = new Hashtable(11);
687
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
688
		env.put(Context.REFERRAL, referral);
689
		env.put(Context.PROVIDER_URL, ldapUrl);
690

    
691
		try {
692

    
693
			// Create the initial directory context
694
			DirContext ctx = new InitialDirContext(env);
695

    
696
			// Specify the ids of the attributes to return
697
			String[] attrIDs = { "uniqueMember" };
698

    
699
			Attributes answer = ctx.getAttributes(group, attrIDs);
700

    
701
			Vector uvec = new Vector();
702
			try {
703
				for (NamingEnumeration ae = answer.getAll(); ae.hasMore();) {
704
					Attribute attr = (Attribute) ae.next();
705
					for (NamingEnumeration e = attr.getAll(); e.hasMore(); uvec.add(e
706
							.next())) {
707
						;
708
					}
709
				}
710
			} catch (SizeLimitExceededException slee) {
711
				logMetacat.error("AuthLdap.getUsers - LDAP Server size limit exceeded. "
712
						+ "Returning incomplete record set.");
713
			}
714

    
715
			// initialize users[]; fill users[]
716
			users = new String[uvec.size()];
717
			for (int i = 0; i < uvec.size(); i++) {
718
				users[i] = (String) uvec.elementAt(i);
719
			}
720

    
721
			// Close the context when we're done
722
			ctx.close();
723

    
724
		} catch (NamingException e) {
725
			logMetacat.error("AuthLdap.getUsers - Problem getting users for a group in "
726
					+ "AuthLdap.getUsers:" + e);
727
			/*
728
			 * throw new ConnectException( "Problem getting users for a group in
729
			 * AuthLdap.getUsers:" + e);
730
			 */
731
		}
732

    
733
		return users;
734
	}
735

    
736
	/**
737
	 * Get all groups from the authentication service
738
	 * 
739
	 * @param user
740
	 *            the user for authenticating against the service
741
	 * @param password
742
	 *            the password for authenticating against the service
743
	 * @returns string array of the group names
744
	 */
745
	public String[][] getGroups(String user, String password) throws ConnectException {
746
		return getGroups(user, password, null);
747
	}
748

    
749
	/**
750
	 * Get the groups for a particular user from the authentication service
751
	 * 
752
	 * @param user
753
	 *            the user for authenticating against the service
754
	 * @param password
755
	 *            the password for authenticating against the service
756
	 * @param foruser
757
	 *            the user whose group list should be returned
758
	 * @returns string array of the group names
759
	 */
760
	public String[][] getGroups(String user, String password, String foruser)
761
			throws ConnectException {
762

    
763
		logMetacat.debug("AuthLdap.getGroups - getGroups() called.");
764

    
765
		// create vectors to store group and dscription values returned from the
766
		// ldap servers
767
		Vector gvec = new Vector();
768
		Vector desc = new Vector();
769
		Attributes tempAttr = null;
770
		Attributes rsrAttr = null;
771

    
772
		// DURING getGroups(), DO WE NOT BIND USING userName AND userPassword??
773
		// NEED TO FIX THIS ...
774
		userName = user;
775
		userPassword = password;
776
		// Identify service provider to use
777
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
778
		env.put(Context.REFERRAL, "throw");
779
		env.put(Context.PROVIDER_URL, ldapUrl);
780
		env.put("com.sun.jndi.ldap.connect.timeout", ldapConnectTimeLimit);
781

    
782
		// Iterate through the referrals, handling NamingExceptions in the
783
		// outer catch statement, ReferralExceptions in the inner catch
784
		// statement
785
		try { // outer try
786

    
787
			// Create the initial directory context
788
			DirContext ctx = new InitialDirContext(env);
789

    
790
			// Specify the attributes to match.
791
			// Groups are objects with attribute objectclass=groupofuniquenames.
792
			// and have attribute uniquemember: uid=foruser,ldapbase.
793
			SearchControls ctls = new SearchControls();
794
			// Specify the ids of the attributes to return
795
			String[] attrIDs = { "cn", "o", "description" };
796
			ctls.setReturningAttributes(attrIDs);
797
			// set the ldap search scope
798
			ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
799
			// set a 10 second time limit on searches to limit non-responding
800
			// servers
801
			ctls.setTimeLimit(ldapSearchTimeLimit);
802
			// return at most 20000 entries
803
			ctls.setCountLimit(ldapSearchCountLimit);
804

    
805
			// build the ldap search filter that represents the "group" concept
806
			String filter = null;
807
			String gfilter = "(objectClass=groupOfUniqueNames)";
808
			if (null == foruser) {
809
				filter = gfilter;
810
			} else {
811
				filter = "(& " + gfilter + "(uniqueMember=" + foruser + "))";
812
			}
813
			logMetacat.info("AuthLdap.getGroups - group filter is: " + filter);
814

    
815
			// now, search and iterate through the referrals
816
			for (boolean moreReferrals = true; moreReferrals;) {
817
				try { // inner try
818

    
819
					NamingEnumeration namingEnum = ctx.search(ldapBase, filter, ctls);
820

    
821
					// Print the groups
822
					while (namingEnum.hasMore()) {
823
						SearchResult sr = (SearchResult) namingEnum.next();
824

    
825
						tempAttr = sr.getAttributes();
826

    
827
						if ((tempAttr.get("description") + "")
828
								.startsWith("description: ")) {
829
							desc.add((tempAttr.get("description") + "").substring(13));
830
						} else {
831
							desc.add(tempAttr.get("description") + "");
832
						}
833

    
834
						// check for an absolute URL value or an answer value
835
						// relative
836
						// to the target context
837
						if (!sr.getName().startsWith("ldap") && sr.isRelative()) {
838
							logMetacat.debug("AuthLdap.getGroups - Search result entry is relative ...");
839
							gvec.add(sr.getName() + "," + ldapBase);
840
							logMetacat.info("AuthLdap.getGroups - group " + sr.getName() + "," + ldapBase
841
									+ " added to the group vector");
842
						} else {
843
							logMetacat.debug("AuthLdap.getGroups - Search result entry is absolute ...");
844

    
845
							// search the top level directory for referral
846
							// objects and match
847
							// that of the search result's absolute URL. This
848
							// will let us
849
							// rebuild the group name from the search result,
850
							// referral point
851
							// in the top directory tree, and ldapBase.
852

    
853
							// configure a new directory search first
854
							Hashtable envHash = new Hashtable(11);
855
							// Identify service provider to use
856
							envHash.put(Context.INITIAL_CONTEXT_FACTORY,
857
									"com.sun.jndi.ldap.LdapCtxFactory");
858
							envHash.put(Context.REFERRAL, "ignore");
859
							envHash.put(Context.PROVIDER_URL, ldapUrl);
860
							envHash.put("com.sun.jndi.ldap.connect.timeout",
861
									ldapConnectTimeLimit);
862

    
863
							try {
864
								// Create the initial directory context
865
								DirContext DirCtx = new InitialDirContext(envHash);
866

    
867
								SearchControls searchCtls = new SearchControls();
868
								// Specify the ids of the attributes to return
869
								String[] attrNames = { "o" };
870
								searchCtls.setReturningAttributes(attrNames);
871
								// set the ldap search scope - only look for top
872
								// level referrals
873
								searchCtls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
874
								// set a time limit on searches to limit
875
								// non-responding servers
876
								searchCtls.setTimeLimit(ldapSearchTimeLimit);
877
								// return the configured number of entries
878
								searchCtls.setCountLimit(ldapSearchCountLimit);
879

    
880
								// Specify the attributes to match.
881
								// build the ldap search filter to match
882
								// referral entries that
883
								// match the search result
884
								String rFilter = "(&(objectClass=referral)(ref="
885
										+ currentReferralInfo.substring(0,
886
												currentReferralInfo.indexOf("?")) + "))";
887
								logMetacat.debug("AuthLdap.getGroups - rFilter is: " + rFilter);
888

    
889
								NamingEnumeration rNamingEnum = DirCtx.search(ldapBase,
890
										rFilter, searchCtls);
891

    
892
								while (rNamingEnum.hasMore()) {
893
									SearchResult rsr = (SearchResult) rNamingEnum.next();
894
									rsrAttr = rsr.getAttributes();
895
									logMetacat.debug("AuthLdap.getGroups - referral search result is: "
896
											+ rsr.toString());
897

    
898
									// add the returned groups to the group
899
									// vector. Test the
900
									// syntax of the returned attributes -
901
									// sometimes they are
902
									// preceded with the attribute id and a
903
									// colon
904
									if ((tempAttr.get("cn") + "").startsWith("cn: ")) {
905
										gvec.add("cn="
906
												+ (tempAttr.get("cn") + "").substring(4)
907
												+ "," + "o="
908
												+ (rsrAttr.get("o") + "").substring(3)
909
												+ "," + ldapBase);
910
										logMetacat.info("AuthLdap.getGroups - group "
911
												+ (tempAttr.get("cn") + "").substring(4)
912
												+ "," + "o="
913
												+ (rsrAttr.get("o") + "").substring(3)
914
												+ "," + ldapBase
915
												+ " added to the group vector");
916
									} else {
917
										gvec.add("cn=" + tempAttr.get("cn") + "," + "o="
918
												+ rsrAttr.get("o") + "," + ldapBase);
919
										logMetacat.info("AuthLdap.getGroups - group " + "cn="
920
												+ tempAttr.get("cn") + "," + "o="
921
												+ rsrAttr.get("o") + "," + ldapBase
922
												+ " added to the group vector");
923
									}
924
								}
925

    
926
							} catch (NamingException nameEx) {
927
								logMetacat.debug("AuthLdap.getGroups - Caught naming exception: ");
928
								nameEx.printStackTrace(System.err);
929
							}
930
						}
931
					}// end while
932

    
933
					moreReferrals = false;
934

    
935
				} catch (ReferralException re) {
936

    
937
					logMetacat
938
							.info("AuthLdap.getGroups -  caught referral exception: "
939
									+ re.getReferralInfo());
940
					this.currentReferralInfo = (String) re.getReferralInfo();
941

    
942
					// set moreReferrals to true and set the referral context
943
					moreReferrals = true;
944
					
945
					// try following referral, skip if error
946
					boolean referralError = true;
947
					while (referralError) {
948
						try {
949
							ctx = (DirContext) re.getReferralContext();
950
							referralError = false;
951
						}
952
						catch (NamingException ne) {
953
							logMetacat.error("NamingException when getting referral contex. Skipping this referral. " + ne.getMessage());
954
							re.skipReferral();
955
							referralError = true;
956
						}
957
					}
958

    
959
				}// end inner try
960
			}// end for
961

    
962
			// close the context now that all initial and referral
963
			// searches are processed
964
			ctx.close();
965

    
966
		} catch (NamingException e) {
967

    
968
			// naming exceptions get logged, groups are returned
969
			logMetacat.info("AuthLdap.getGroups - caught naming exception: ");
970
			e.printStackTrace(System.err);
971

    
972
		} finally {
973
			// once all referrals are followed, report and return the groups
974
			// found
975
			logMetacat.warn("AuthLdap.getGroups - The user is in the following groups: " + gvec.toString());
976
			// build and return the groups array
977
			String groups[][] = new String[gvec.size()][2];
978
			for (int i = 0; i < gvec.size(); i++) {
979
				groups[i][0] = (String) gvec.elementAt(i);
980
				groups[i][1] = (String) desc.elementAt(i);
981
			}
982
			return groups;
983
		}// end outer try
984
	}
985

    
986
	/**
987
	 * Get attributes describing a user or group
988
	 * 
989
	 * @param foruser
990
	 *            the user for which the attribute list is requested
991
	 * @returns HashMap a map of attribute name to a Vector of values
992
	 */
993
	public HashMap<String, Vector<String>> getAttributes(String foruser)
994
			throws ConnectException {
995
		return getAttributes(null, null, foruser);
996
	}
997

    
998
	/**
999
	 * Get attributes describing a user or group
1000
	 * 
1001
	 * @param user
1002
	 *            the user for authenticating against the service
1003
	 * @param password
1004
	 *            the password for authenticating against the service
1005
	 * @param foruser
1006
	 *            the user whose attributes should be returned
1007
	 * @returns HashMap a map of attribute name to a Vector of values
1008
	 */
1009
	public HashMap<String, Vector<String>> getAttributes(String user, String password,
1010
			String foruser) throws ConnectException {
1011
		HashMap<String, Vector<String>> attributes = new HashMap<String, Vector<String>>();
1012
		String ldapUrl = this.ldapUrl;
1013
		String ldapBase = this.ldapBase;
1014
		String userident = foruser;
1015

    
1016
		// Identify service provider to use
1017
		Hashtable env = new Hashtable(11);
1018
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
1019
		env.put(Context.REFERRAL, referral);
1020
		env.put(Context.PROVIDER_URL, ldapUrl);
1021

    
1022
		try {
1023

    
1024
			// Create the initial directory context
1025
			DirContext ctx = new InitialDirContext(env);
1026

    
1027
			// Ask for all attributes of the user
1028
			// Attributes attrs = ctx.getAttributes(userident);
1029
			Attributes attrs = ctx.getAttributes(foruser);
1030

    
1031
			// Print all of the attributes
1032
			NamingEnumeration en = attrs.getAll();
1033
			while (en.hasMore()) {
1034
				Attribute att = (Attribute) en.next();
1035
				Vector<String> values = new Vector();
1036
				String attName = att.getID();
1037
				NamingEnumeration attvalues = att.getAll();
1038
				while (attvalues.hasMore()) {
1039
				    try {
1040
				        String value = (String) attvalues.next();
1041
				        values.add(value);
1042
				    } catch (ClassCastException cce) {
1043
				        logMetacat.debug("Could not cast LDAP attribute (" +
1044
				                attName + ") to a String value, so skipping.");
1045
				    }
1046
				}
1047
				attributes.put(attName, values);
1048
			}
1049

    
1050
			// Close the context when we're done
1051
			ctx.close();
1052
		} catch (NamingException e) {
1053
			logMetacat.error("AuthLdap.getAttributes - Problem getting attributes:"
1054
					+ e);
1055
			throw new ConnectException(
1056
					"Problem getting attributes in AuthLdap.getAttributes:" + e);
1057
		}
1058

    
1059
		return attributes;
1060
	}
1061

    
1062
	/**
1063
	 * Get list of all subtrees holding Metacat's groups and users starting from
1064
	 * the Metacat LDAP root, i.e.
1065
	 * ldap://dev.nceas.ucsb.edu/dc=ecoinformatics,dc=org
1066
	 */
1067
	private Hashtable getSubtrees(String user, String password, String ldapUrl,
1068
			String ldapBase) throws ConnectException {
1069
		logMetacat.debug("AuthLdap.getSubtrees - getting subtrees for user: " + user + 
1070
				", ldapUrl: " + ldapUrl + ", ldapBase: " + ldapBase);
1071
		Hashtable trees = new Hashtable();
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
		// Using 'ignore' here instead of 'follow' as 'ignore' seems
1078
		// to do the job better. 'follow' was not bringing up the UCNRS
1079
		// and PISCO tree whereas 'ignore' brings up the tree.
1080

    
1081
		env.put(Context.REFERRAL, "ignore");
1082
		env.put(Context.PROVIDER_URL, ldapUrl + ldapBase);
1083

    
1084
		try {
1085

    
1086
			// Create the initial directory context
1087
			DirContext ctx = new InitialDirContext(env);
1088

    
1089
			// Specify the ids of the attributes to return
1090
			String[] attrIDs = { "o", "ref" };
1091
			SearchControls ctls = new SearchControls();
1092
			ctls.setReturningAttributes(attrIDs);
1093
			ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
1094

    
1095
			// Specify the attributes to match.
1096
			// Subtrees from the main server are found as objects with attribute
1097
			// objectclass=organization or objectclass=referral to the subtree
1098
			// resided on other server.
1099
			String filter = "(|(objectclass=organization)(objectclass=referral))";
1100

    
1101
			// Search for objects in the current context
1102
			NamingEnumeration namingEnum = ctx.search("", filter, ctls);
1103

    
1104
			// Print the subtrees' <ldapURL, baseDN>
1105
			while (namingEnum.hasMore()) {
1106

    
1107
				SearchResult sr = (SearchResult) namingEnum.next();
1108
				logMetacat.debug("AuthLdap.getSubtrees - search result: " + sr.toString());
1109

    
1110
				Attributes attrs = sr.getAttributes();
1111
				NamingEnumeration enum1 = attrs.getAll(); // "dc" and "ref"
1112
															// attrs
1113

    
1114
				if (enum1.hasMore()) {
1115
					Attribute attr = (Attribute) enum1.next();
1116
					String attrValue = (String) attr.get();
1117
					String attrName = (String) attr.getID();
1118

    
1119
					if (enum1.hasMore()) {
1120
						attr = (Attribute) enum1.next();
1121
						String refValue = (String) attr.get();
1122
						String refName = (String) attr.getID();
1123
						if (ldapBase.startsWith(refName + "=" + refValue)) {
1124
							trees.put(ldapBase, attrValue.substring(0, attrValue
1125
									.lastIndexOf("/") + 1));
1126
						} else {
1127
							// this is a referral - so organization name is
1128
							// appended in front of the ldapbase.... later it is 
1129
							// stripped out in getPrincipals
1130
							trees.put("[" + refName + "=" + refValue + "]" + 
1131
									attrValue.substring(attrValue.lastIndexOf("/") + 1,
1132
											attrValue.length()), attrValue.substring(0,
1133
													attrValue.lastIndexOf("/") + 1));
1134

    
1135
							// trees.put(refName + "=" + refValue + "," +
1136
							// ldapBase, attrValue.substring(0, attrValue.lastIndexOf("/")
1137
							// + 1));
1138
						}
1139

    
1140
					} else if (ldapBase.startsWith(attrName + "=" + attrValue)) {
1141
						trees.put(ldapBase, ldapUrl);
1142
					} else {
1143
						if (sr.isRelative()) {
1144
							trees.put(attrName + "=" + attrValue + "," + ldapBase,
1145
									ldapUrl);
1146
						} else {
1147
							String referenceURL = sr.getName();
1148
							referenceURL = referenceURL.substring(0, referenceURL
1149
									.lastIndexOf("/") + 1);
1150
							trees.put(attrName + "=" + attrValue + "," + ldapBase,
1151
									referenceURL);
1152
						}
1153

    
1154
					}
1155
				}
1156
			}
1157

    
1158
			// Close the context when we're done
1159
			ctx.close();
1160

    
1161
		} catch (NamingException e) {
1162
			logMetacat.error("AuthLdap.getSubtrees - Problem getting subtrees in AuthLdap.getSubtrees:" + e);
1163
			throw new ConnectException(
1164
					"Problem getting subtrees in AuthLdap.getSubtrees:" + e);
1165
		}
1166

    
1167
		return trees;
1168
	}
1169

    
1170
	/**
1171
	 * Get all groups and users from authentication scheme. The output is
1172
	 * formatted in XML.
1173
	 * 
1174
	 * @param user
1175
	 *            the user which requests the information
1176
	 * @param password
1177
	 *            the user's password
1178
	 */
1179
	public String getPrincipals(String user, String password) throws ConnectException {
1180
		StringBuffer out = new StringBuffer();
1181

    
1182
		out.append("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n");
1183
		out.append("<principals>\n");
1184

    
1185
		/*
1186
		 * get all subtrees first in the current dir context and then the
1187
		 * Metacat users under them
1188
		 */
1189
		Hashtable subtrees = getSubtrees(user, password, this.ldapUrl, this.ldapBase);
1190

    
1191
		Enumeration keyEnum = subtrees.keys();
1192
		while (keyEnum.hasMoreElements()) {
1193
			this.ldapBase = (String) keyEnum.nextElement();
1194
			this.ldapUrl = (String) subtrees.get(ldapBase);
1195
			logMetacat.info("AuthLdap.getPrincipals - ldapBase: " + ldapBase + 
1196
					", ldapUrl: " + ldapUrl);
1197
			/*
1198
			 * code to get the organization name from ldapBase
1199
			 */
1200
			String orgName = this.ldapBase;
1201
			if (orgName.startsWith("[")) {
1202
				// if orgName starts with [ then it is a referral URL...
1203
				// (see code in getSubtress) hence orgName can be retrieved by 
1204
				// getting the string between 'o=' and ']' also the string between 
1205
				// [ and ] needs to be striped out from this.ldapBase
1206
				this.ldapBase = orgName.substring(orgName.indexOf("]") + 1);
1207
				if (orgName != null && orgName.indexOf("o=") > -1) {
1208
					orgName = orgName.substring(orgName.indexOf("o=") + 2);
1209
					orgName = orgName.substring(0, orgName.indexOf("]"));
1210
				}
1211
			} else {
1212
				// else it is not referral
1213
				// hence orgName can be retrieved by getting the string between
1214
				// 'o=' and ','
1215
				if (orgName != null && orgName.indexOf("o=") > -1) {
1216
					orgName = orgName.substring(orgName.indexOf("o=") + 2);
1217
					if (orgName.indexOf(",") > -1) {
1218
						orgName = orgName.substring(0, orgName.indexOf(","));
1219
					}
1220
				}
1221
			}
1222
			logMetacat.info("AuthLdap.getPrincipals - org name is  " + orgName);
1223
			out.append("  <authSystem URI=\"" + this.ldapUrl + this.ldapBase
1224
					+ "\" organization=\"" + orgName + "\">\n");
1225

    
1226
			// get all groups for directory context
1227
			String[][] groups = getGroups(user, password);
1228
			logMetacat.debug("AuthLdap.getPrincipals - after getting groups " + groups);
1229
			String[][] users = getUsers(user, password);
1230
			logMetacat.debug("AuthLdap.getPrincipals - after getting users " + users);
1231
			int userIndex = 0;
1232

    
1233
			// for the groups and users that belong to them
1234
			if (groups != null && users != null && groups.length > 0) {
1235
				for (int i = 0; i < groups.length; i++) {
1236
					out.append("    <group>\n");
1237
					out.append("      <groupname>" + groups[i][0] + "</groupname>\n");
1238
					out.append("      <description>" + groups[i][1] + "</description>\n");
1239
					String[] usersForGroup = getUsers(user, password, groups[i][0]);
1240
					for (int j = 0; j < usersForGroup.length; j++) {
1241
						userIndex = searchUser(usersForGroup[j], users);
1242
						out.append("      <user>\n");
1243

    
1244
						if (userIndex < 0) {
1245
							out.append("        <username>" + usersForGroup[j]
1246
									+ "</username>\n");
1247
						} else {
1248
							out.append("        <username>" + users[userIndex][0]
1249
									+ "</username>\n");
1250
							out.append("        <name>" + users[userIndex][1]
1251
									+ "</name>\n");
1252
							out.append("        <organization>" + users[userIndex][2]
1253
									+ "</organization>\n");
1254
							if (users[userIndex][3].compareTo("null") != 0) {
1255
								out.append("      <organizationUnitName>"
1256
										+ users[userIndex][3]
1257
										+ "</organizationUnitName>\n");
1258
							}
1259
							out.append("        <email>" + users[userIndex][4]
1260
									+ "</email>\n");
1261
						}
1262

    
1263
						out.append("      </user>\n");
1264
					}
1265
					out.append("    </group>\n");
1266
				}
1267
			}
1268

    
1269
			if (users != null) {
1270
				// for the users not belonging to any grou8p
1271
				for (int j = 0; j < users.length; j++) {
1272
					out.append("    <user>\n");
1273
					out.append("      <username>" + users[j][0] + "</username>\n");
1274
					out.append("      <name>" + users[j][1] + "</name>\n");
1275
					out
1276
							.append("      <organization>" + users[j][2]
1277
									+ "</organization>\n");
1278
					if (users[j][3].compareTo("null") != 0) {
1279
						out.append("      <organizationUnitName>" + users[j][3]
1280
								+ "</organizationUnitName>\n");
1281
					}
1282
					out.append("      <email>" + users[j][4] + "</email>\n");
1283
					out.append("    </user>\n");
1284
				}
1285
			}
1286

    
1287
			out.append("  </authSystem>\n");
1288
		}
1289
		out.append("</principals>");
1290
		return out.toString();
1291
	}
1292

    
1293
	/**
1294
	 * Method for getting index of user DN in User info array
1295
	 */
1296
	public static int searchUser(String user, String userGroup[][]) {
1297
		for (int j = 0; j < userGroup.length; j++) {
1298
			if (user.compareTo(userGroup[j][0]) == 0) {
1299
				return j;
1300
			}
1301
		}
1302
		return -1;
1303
	}
1304

    
1305
	public void testCredentials(String dn, String password, String rootServer,
1306
			String rootBase) throws NamingException {
1307

    
1308
		String server = "";
1309
		String userDN = "";
1310
		logMetacat.debug("dn is: " + dn);
1311

    
1312
		int position = dn.lastIndexOf("/");
1313
		logMetacat.debug("AuthLdap.testCredentials - position is: " + position);
1314
		if (position == -1) {
1315
			server = rootServer;
1316
			if (dn.indexOf(userDN) < 0) {
1317
				userDN = dn + "," + rootBase;
1318
			} else {
1319
				userDN = dn;
1320
			}
1321
			logMetacat.debug("AuthLdap.testCredentials - userDN is: " + userDN);
1322

    
1323
		} else {
1324
			server = dn.substring(0, position + 1);
1325
			userDN = dn.substring(position + 1);
1326
			logMetacat.debug("AuthLdap.testCredentials - server is: " + server);
1327
			logMetacat.debug("AuthLdap.testCredentials - userDN is: " + userDN);
1328
		}
1329

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

    
1332
		// /* try {
1333
		LdapContext ctx = null;
1334

    
1335
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
1336
		env.put(Context.REFERRAL, "follow");
1337
		env.put(Context.SECURITY_AUTHENTICATION, "simple");
1338
		env.put(Context.SECURITY_PRINCIPAL, userDN);
1339
		env.put(Context.SECURITY_CREDENTIALS, password);
1340
		env.put(Context.PROVIDER_URL, rootServer);
1341

    
1342
		ctx = new InitialLdapContext(env, null);
1343

    
1344
	}
1345

    
1346
	/**
1347
	 * Test method for the class
1348
	 */
1349
	public static void main(String[] args) {
1350

    
1351
		// Provide a user, such as: "Matt Jones", or "jones"
1352
		String user = args[0];
1353
		String password = args[1];
1354
		String org = args[2];
1355

    
1356
		logMetacat.warn("AuthLdap.main - Creating session...");
1357
		AuthLdap authservice = null;
1358
		try {
1359
			authservice = new AuthLdap();
1360
		} catch (Exception e) {
1361
			logMetacat.error("AuthLdap.main - Could not instantiate AuthLdap: " + e.getMessage());
1362
			return;
1363
		}
1364
		logMetacat.warn("AuthLdap.main - Session exists...");
1365

    
1366
		boolean isValid = false;
1367
		try {
1368
			logMetacat.warn("AuthLdap.main - Authenticating...");
1369
			isValid = authservice.authenticate(user, password);
1370
			if (isValid) {
1371
				logMetacat.warn("AuthLdap.main - Authentication successful for: " + user);
1372
			} else {
1373
				logMetacat.warn("AuthLdap.main - Authentication failed for: " + user);
1374
			}
1375

    
1376
			// Get attributes for the user
1377
			if (isValid) {
1378
				logMetacat.info("AuthLdap.main - Getting attributes for user....");
1379
				HashMap userInfo = authservice.getAttributes(user, password, user);
1380
				// Print all of the attributes
1381
				Iterator attList = (Iterator) (((Set) userInfo.keySet()).iterator());
1382
				while (attList.hasNext()) {
1383
					String att = (String) attList.next();
1384
					Vector values = (Vector) userInfo.get(att);
1385
					Iterator attvalues = values.iterator();
1386
					while (attvalues.hasNext()) {
1387
						String value = (String) attvalues.next();
1388
						logMetacat.warn("AuthLdap.main - " + att + ": " + value);
1389
					}
1390
				}
1391
			}
1392

    
1393
			// get the groups
1394
			if (isValid) {
1395
				logMetacat.warn("AuthLdap.main - Getting all groups....");
1396
				String[][] groups = authservice.getGroups(user, password);
1397
				logMetacat.info("AuthLdap.main - Groups found: " + groups.length);
1398
				for (int i = 0; i < groups.length; i++) {
1399
					logMetacat.info("AuthLdap.main - Group " + i + ": " + groups[i][0]);
1400
				}
1401
			}
1402

    
1403
			// get the groups for the user
1404
			String savedGroup = null;
1405
			if (isValid) {
1406
				logMetacat.warn("AuthLdap.main - Getting groups for user....");
1407
				String[][] groups = authservice.getGroups(user, password, user);
1408
				logMetacat.info("AuthLdap.main - Groups found: " + groups.length);
1409
				for (int i = 0; i < groups.length; i++) {
1410
					logMetacat.info("AuthLdap.main - Group " + i + ": " + groups[i][0]);
1411
					savedGroup = groups[i][0];
1412
				}
1413
			}
1414

    
1415
			// get the users for a group
1416
			if (isValid) {
1417
				logMetacat.warn("AuthLdap.main - Getting users for group....");
1418
				logMetacat.info("AuthLdap.main - Group: " + savedGroup);
1419
				String[] users = authservice.getUsers(user, password, savedGroup);
1420
				logMetacat.info("AuthLdap.main - Users found: " + users.length);
1421
				for (int i = 0; i < users.length; i++) {
1422
					logMetacat.warn("AuthLdap.main - User " + i + ": " + users[i]);
1423
				}
1424
			}
1425

    
1426
			// get all users
1427
			if (isValid) {
1428
				logMetacat.warn("AuthLdap.main - Getting all users ....");
1429
				String[][] users = authservice.getUsers(user, password);
1430
				logMetacat.info("AuthLdap.main - Users found: " + users.length);
1431

    
1432
			}
1433

    
1434
			// get the whole list groups and users in XML format
1435
			if (isValid) {
1436
				logMetacat.warn("AuthLdap.main - Trying principals....");
1437
				authservice = new AuthLdap();
1438
				String out = authservice.getPrincipals(user, password);
1439
				java.io.File f = new java.io.File("principals.xml");
1440
				java.io.FileWriter fw = new java.io.FileWriter(f);
1441
				java.io.BufferedWriter buff = new java.io.BufferedWriter(fw);
1442
				buff.write(out);
1443
				buff.flush();
1444
				buff.close();
1445
				fw.close();
1446
				logMetacat.warn("AuthLdap.main - Finished getting principals.");
1447
			}
1448

    
1449
		} catch (ConnectException ce) {
1450
			logMetacat.error("AuthLdap.main - " + ce.getMessage());
1451
		} catch (java.io.IOException ioe) {
1452
			logMetacat.error("AuthLdap.main - I/O Error writing to file principals.txt: "
1453
					+ ioe.getMessage());
1454
		} catch (InstantiationException ie) {
1455
			logMetacat.error("AuthLdap.main - Instantiation error writing to file principals.txt: "
1456
					+ ie.getMessage());
1457
		}
1458
	}
1459

    
1460
	/**
1461
	 * This method will be called by start a thread. It can handle if a referral
1462
	 * exception happend.
1463
	 */
1464
}
(6-6/63)