001: package com.sabre.security.jndi;
002:
003: import java.security.Principal;
004: import java.security.MessageDigest;
005: import java.security.NoSuchAlgorithmException;
006: import java.text.MessageFormat;
007: import java.util.*;
008: import javax.security.auth.Subject;
009: import javax.naming.directory.*;
010: import javax.naming.*;
011:
012: import org.apache.log4j.Logger;
013: import org.apache.commons.beanutils.BeanUtils;
014: import com.sabre.security.jndi.util.Base64;
015: import com.sabre.security.jndi.util.HexUtils;
016:
017: public class JNDIAuthenticatorImpl implements JNDIAuthenticator {
018:
019: /**
020: * Debug level
021: */
022: private int debug = 10;
023: /**
024: * Logger.
025: */
026: public static final Logger log = Logger
027: .getLogger(JNDIAuthenticatorImpl.class);
028: /**
029: * Should we search the entire subtree for matching users?
030: */
031: private boolean userSubtree;
032: /**
033: * Should we search the entire subtree for matching memberships?
034: */
035: private boolean roleSubtree;
036: /**
037: * Descriptive information about this Realm implementation.
038: */
039: protected static final String info = "org.apache.catalina.realm.JNDIRealm/1.0";
040: /**
041: * The JNDI context factory used to acquire our InitialContext. By
042: * default, assumes use of an LDAP server using the standard JNDI LDAP
043: * provider.
044: */
045: protected String contextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
046: /**
047: * The type of authentication to use
048: */
049: private String authentication;
050: /**
051: * The connection username for the server we will contact.
052: */
053: private String connectionUser;
054: /**
055: * The connection password for the server we will contact.
056: */
057: private String connectionPassword;
058: /**
059: * The connection URL for the server we will contact.
060: */
061: private String connectionURL;
062: /**
063: * The protocol that will be used in the communication with the directory server.
064: */
065: private String protocol;
066: /**
067: * How should we handle referrals? Microsoft Active Directory can't handle
068: * the default case, so an application authenticating against AD must
069: * set referrals to "follow".
070: */
071: private String referrals;
072: /**
073: * The base element for user searches.
074: */
075: private String userBase = "";
076: /**
077: * The message format used to search for a user, with "{0}" marking
078: * the spot where the username goes.
079: */
080: private String userSearch;
081: /**
082: * The attribute name used to retrieve the user password.
083: */
084: private String userPassword;
085: /**
086: * The message format used to form the distinguished name of a
087: * user, with "{0}" marking the spot where the specified username
088: * goes.
089: */
090: private String userPattern;
091: /**
092: * The base element for role searches.
093: */
094: private String roleBase = "";
095: /**
096: * The name of an attribute in the user's entry containing
097: * roles for that user
098: */
099: private String userRoleName;
100: /**
101: * The name of the attribute containing roles held elsewhere
102: */
103: private String roleName;
104: /**
105: * The directory context linking us to our directory server.
106: */
107: protected DirContext context;
108: /**
109: * The MessageDigest
110: */
111: private MessageDigest messageDigest;
112: /**
113: * The MessageFormat object associated with the current
114: * <code>userSearch</code>.
115: */
116: protected MessageFormat userSearchFormat;
117: /**
118: * The MessageFormat object associated with the current
119: * <code>userPattern</code>.
120: */
121: protected MessageFormat userPatternFormat;
122: /**
123: * The MessageFormat object associated with the current
124: * <code>roleSearch</code>.
125: */
126: protected MessageFormat roleFormat;
127:
128: public void setDigest(String algorithm)
129: throws NoSuchAlgorithmException {
130: messageDigest = MessageDigest.getInstance(algorithm);
131: }
132:
133: public void setDebug(String debug) {
134: this .debug = Integer.parseInt(debug);
135: }
136:
137: public void setUserSubtree(String userSubtree) {
138: this .userSubtree = Boolean.getBoolean(userSubtree);
139: }
140:
141: public void setRoleSubtree(String roleSubtree) {
142: this .roleSubtree = Boolean.getBoolean(roleSubtree);
143: }
144:
145: public void setContextFactory(String contextFactory) {
146: this .contextFactory = contextFactory;
147: }
148:
149: public void setAuthentication(String authentication) {
150: this .authentication = authentication;
151: }
152:
153: public void setConnectionUser(String connectionUser) {
154: this .connectionUser = connectionUser;
155: }
156:
157: public void setConnectionPassword(String connectionPassword) {
158: this .connectionPassword = connectionPassword;
159: }
160:
161: public void setConnectionURL(String connectionURL) {
162: this .connectionURL = connectionURL;
163: }
164:
165: public void setProtocol(String protocol) {
166: this .protocol = protocol;
167: }
168:
169: public void setReferrals(String referrals) {
170: this .referrals = referrals;
171: }
172:
173: public void setUserBase(String userBase) {
174: this .userBase = userBase;
175: }
176:
177: public void setUserSearch(String userSearch) {
178: this .userSearch = userSearch;
179: if (userSearch == null) {
180: userSearchFormat = null;
181: } else {
182: userSearchFormat = new MessageFormat(userSearch);
183: }
184: }
185:
186: public void setUserPassword(String userPassword) {
187: this .userPassword = userPassword;
188: }
189:
190: public void setUserPattern(String userPattern) {
191: this .userPattern = userPattern;
192: if (userPattern == null) {
193: userPatternFormat = null;
194: } else {
195: userPatternFormat = new MessageFormat(userPattern);
196: }
197: }
198:
199: public void setRoleBase(String roleBase) {
200: this .roleBase = roleBase;
201: }
202:
203: public void setUserRoleName(String userRoleName) {
204: this .userRoleName = userRoleName;
205: }
206:
207: public void setRoleName(String roleName) {
208: this .roleName = roleName;
209: }
210:
211: public void setRoleSearch(String roleSearch) {
212: if (roleSearch == null) {
213: roleFormat = null;
214: } else {
215: roleFormat = new MessageFormat(roleSearch);
216: }
217: }
218:
219: public void logMap(Map options) {
220: for (Iterator iterator = options.keySet().iterator(); iterator
221: .hasNext();) {
222: Object key = iterator.next();
223: log.debug("option: " + key + "=" + options.get(key));
224: }
225: }
226:
227: /**
228: * Return the Principal associated with the specified username and
229: * credentials, if there is one; otherwise return <code>null</code>.
230: * <p/>
231: * If there are any errors with the JDBC connection, executing
232: * the query or anything we return null (don't authenticate). This
233: * event is also logged, and the connection will be closed so that
234: * a subsequent request will automatically re-open it.
235: *
236: * @param username Username of the Principal to look up
237: * @param credentials Password or other credentials to use in
238: * authenticating this username
239: */
240: public synchronized Subject authenticate(String username,
241: String credentials) throws AuthenticationException {
242:
243: openConnectionCheckCredentials(username, credentials);
244: return getSubject(username, credentials);
245:
246: }
247:
248: private void openConnectionCheckCredentials(String username,
249: String credentials) throws AuthenticationException {
250:
251: try {
252: if (isAnonymousConnection()) {
253:
254: log.debug("Anonymous connection");
255: open();
256: checkCredentials(username, credentials);
257:
258: } else if (isFixedUserConnection()) {
259:
260: log.debug("Fixed user connection");
261: open(connectionUser, connectionPassword);
262: checkCredentials(username, credentials);
263:
264: } else {
265:
266: if (userPattern != null) {
267: String formattedUsername = MessageFormat.format(
268: userPattern, new Object[] { username });
269: log.debug("Connection with " + formattedUsername
270: + " user");
271: open(formattedUsername, credentials);
272: }
273:
274: }
275: } finally {
276: closeContext();
277: }
278:
279: }
280:
281: public void setOptions(Map options) {
282: try {
283: BeanUtils.copyProperties(this , options);
284: if (this .debug >= 2) {
285: logMap(options);
286: }
287: } catch (Exception e) {
288: // Don't care about not assignable fields
289: }
290:
291: }
292:
293: private Subject getSubject(final String username, String credentials)
294: throws AuthenticationException {
295: if (username == null || username.equals("")
296: || credentials == null || credentials.equals("")) {
297: throw new AuthenticationException(
298: JNDIAuthenticator.MESSAGE_AUTHENTICATION_FAILED_KEY);
299: }
300: Subject subject = new Subject();
301: Principal principal = new Principal() {
302:
303: public String getName() {
304: return username;
305: }
306: };
307: subject.getPrincipals().add(principal);
308: return subject;
309: }
310:
311: /**
312: * Return a User object containing information about the user
313: * with the specified username, if found in the directory;
314: * otherwise return <code>null</code>.
315: * <p/>
316: * If the <code>userPassword</code> configuration attribute is
317: * specified, the value of that attribute is retrieved from the
318: * user's directory entry. If the <code>userRoleName</code>
319: * configuration attribute is specified, all values of that
320: * attribute are retrieved from the directory entry.
321: *
322: * @param username Username to be looked up
323: * @throws javax.naming.NamingException if a directory server error occurs
324: */
325: protected User getUser(String username) throws NamingException {
326:
327: User user = null;
328:
329: // Get attributes to retrieve from user entry
330: ArrayList list = new ArrayList();
331: if (userPassword != null) {
332: list.add(userPassword);
333: }
334: if (userRoleName != null) {
335: list.add(userRoleName);
336: }
337: String[] attrIds = new String[list.size()];
338: list.toArray(attrIds);
339:
340: // Use pattern or search for user entry
341: if (userPatternFormat != null) {
342: log("Finding user by pattern.");
343: user = getUserByPattern(username, attrIds);
344: } else {
345: log("Finding user by search. Subtree is " + userSubtree);
346: user = getUserBySearch(username, attrIds);
347: }
348:
349: return user;
350: }
351:
352: /**
353: * Use the <code>UserPattern</code> configuration attribute to
354: * locate the directory entry for the user with the specified
355: * username and return a User object; otherwise return
356: * <code>null</code>.
357: *
358: * @param username The username
359: * @param attrIds String[]containing names of attributes to
360: * retrieve.
361: * @throws javax.naming.NamingException if a directory server error occurs
362: */
363: protected User getUserByPattern(String username, String[] attrIds)
364: throws NamingException {
365:
366: if (debug >= 2) {
367: log("lookupUser(" + username + ")");
368: }
369:
370: if (username == null || userPatternFormat == null)
371: return null;
372:
373: // Form the dn from the user pattern
374: String dn = userPatternFormat.format(new String[] { username });
375: if (debug >= 3) {
376: log(" dn=" + dn);
377: }
378:
379: // Return if no attributes to retrieve
380: if (attrIds == null || attrIds.length == 0) {
381: return new User(username, dn, null, null);
382: }
383:
384: // Get required attributes from user entry
385: Attributes attrs = null;
386: try {
387: attrs = context.getAttributes(dn, attrIds);
388: } catch (NameNotFoundException e) {
389: return null;
390: }
391: if (attrs == null)
392: return null;
393:
394: // Retrieve value of userPassword
395: String password = null;
396: if (userPassword != null) {
397: password = getAttributeValue(userPassword, attrs);
398: }
399:
400: // Retrieve values of userRoleName attribute
401: List roles = null;
402: if (userRoleName != null) {
403: roles = addAttributeValues(userRoleName, attrs, roles);
404: }
405:
406: return new User(username, dn, password, roles);
407: }
408:
409: /**
410: * Search the directory to return a User object containing
411: * information about the user with the specified username, if
412: * found in the directory; otherwise return <code>null</code>.
413: *
414: * @param username The username
415: * @param attrIds String[]containing names of attributes to retrieve.
416: * @throws javax.naming.NamingException if a directory server error occurs
417: */
418: protected User getUserBySearch(String username, String[] attrIds)
419: throws NamingException {
420:
421: if (username == null || userSearchFormat == null) {
422: if (username == null) {
423: log("getUserBySearch impossible - username is null.");
424: }
425: if (userSearchFormat == null) {
426: log("getUserBySearch impossible - userSearchFormat is null.");
427: }
428: return null;
429: }
430:
431: // Form the search filter
432: String filter = userSearchFormat
433: .format(new String[] { username });
434:
435: // Set up the search controls
436: SearchControls constraints = new SearchControls();
437:
438: if (userSubtree) {
439: constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
440: } else {
441: constraints.setSearchScope(SearchControls.ONELEVEL_SCOPE);
442: }
443:
444: // Specify the attributes to be retrieved
445: if (attrIds == null) {
446: attrIds = new String[0];
447: }
448: constraints.setReturningAttributes(attrIds);
449:
450: if (debug > 3) {
451: log(" Searching for " + username);
452: log(" base: " + userBase + " filter: " + filter);
453: }
454:
455: NamingEnumeration results = context.search(userBase, filter,
456: constraints);
457:
458: // Fail if no entries found
459: if (results == null || !results.hasMore()) {
460: if (debug > 2) {
461: log(" username not found");
462: }
463: return null;
464: }
465:
466: // Get result for the first entry found
467: SearchResult result = (SearchResult) results.next();
468:
469: // Check no further entries were found
470: if (results.hasMore()) {
471: log("username " + username + " has multiple entries");
472: return null;
473: }
474:
475: // Get the entry's distinguished name
476: NameParser parser = context.getNameParser("");
477: Name contextName = parser.parse(context.getNameInNamespace());
478: Name baseName = parser.parse(userBase);
479: Name entryName = parser.parse(result.getName());
480: Name name = contextName.addAll(baseName);
481: name = name.addAll(entryName);
482: String dn = name.toString();
483:
484: if (debug > 2) {
485: log(" entry found for " + username + " with dn " + dn);
486: }
487:
488: // Get the entry's attributes
489: Attributes attrs = result.getAttributes();
490: if (attrs == null) {
491: return null;
492: }
493:
494: // Retrieve value of userPassword
495: String password = null;
496: if (userPassword != null) {
497: password = getAttributeValue(userPassword, attrs);
498: }
499:
500: // Retrieve values of userRoleName attribute
501: List roles = null;
502: if (userRoleName != null) {
503: roles = addAttributeValues(userRoleName, attrs, roles);
504: }
505:
506: return new User(username, dn, password, roles);
507: }
508:
509: public boolean isAnonymousConnection() {
510: return userPattern == null && connectionUser == null;
511: }
512:
513: /**
514: * Check credentials by binding to the directory as the user
515: *
516: * @param user The User to be authenticated
517: * @param credentials Authentication credentials
518: * @throws javax.naming.NamingException if a directory server error occurs
519: */
520: protected boolean bindAsUser(User user, String credentials)
521: throws NamingException {
522:
523: if (credentials == null || user == null) {
524: return false;
525: }
526:
527: String dn = user.dn;
528: if (dn == null) {
529: return false;
530: }
531:
532: // Validate the credentials
533: if (debug >= 3) {
534: log(" validating credentials by binding as the user");
535: }
536:
537: // Set up security environment to bind as the user
538: context.addToEnvironment(Context.SECURITY_PRINCIPAL, dn);
539: context.addToEnvironment(Context.SECURITY_CREDENTIALS,
540: credentials);
541:
542: // Elicit an LDAP bind operation
543: boolean validated = false;
544: try {
545: if (debug > 2) {
546: log(" binding as " + dn);
547: }
548: context.getAttributes("", null);
549: validated = true;
550: } catch (javax.naming.AuthenticationException e) {
551: if (debug > 2) {
552: log(" bind attempt failed");
553: }
554: }
555:
556: // Restore the original security environment
557: if (connectionUser != null) {
558: context.addToEnvironment(Context.SECURITY_PRINCIPAL,
559: connectionUser);
560: } else {
561: context.removeFromEnvironment(Context.SECURITY_PRINCIPAL);
562: }
563:
564: if (connectionPassword != null) {
565: context.addToEnvironment(Context.SECURITY_CREDENTIALS,
566: connectionPassword);
567: } else {
568: context.removeFromEnvironment(Context.SECURITY_CREDENTIALS);
569: }
570:
571: return validated;
572: }
573:
574: /**
575: * Return a List of roles associated with the given User. Any
576: * roles present in the user's directory entry are supplemented by
577: * a directory search. If no roles are associated with this user,
578: * a zero-length List is returned.
579: *
580: * @param user The User to be checked
581: * @throws javax.naming.NamingException if a directory server error occurs
582: */
583: public List getRoles(User user) throws NamingException {
584:
585: if (user == null)
586: return null;
587:
588: String dn = user.dn;
589: String username = user.username;
590:
591: if (dn == null || username == null)
592: return null;
593:
594: if (debug >= 2) {
595: log(" getRoles(" + dn + ")");
596: }
597:
598: // Start with roles retrieved from the user entry
599: List list = user.roles;
600: if (list == null) {
601: list = new ArrayList();
602: }
603:
604: // Are we configured to do role searches?
605: if (roleFormat == null || roleName == null)
606: return list;
607:
608: // Set up parameters for an appropriate search
609: String filter = roleFormat
610: .format(new String[] { dn, username });
611: SearchControls controls = new SearchControls();
612: if (roleSubtree) {
613: controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
614: } else {
615: controls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
616: }
617: controls.setReturningAttributes(new String[] { roleName });
618:
619: // Perform the configured search and process the results
620: if (debug >= 3) {
621: log(" Searching role base '" + roleBase
622: + "' for attribute '" + roleName + "'");
623: log(" With filter expression '" + filter + "'");
624: }
625: NamingEnumeration results = context.search(roleBase, filter,
626: controls);
627: if (results == null) {
628: return list; // Should never happen, but just in case ...
629: }
630: while (results.hasMore()) {
631: SearchResult result = (SearchResult) results.next();
632: Attributes attrs = result.getAttributes();
633: if (attrs == null) {
634: continue;
635: }
636: list = addAttributeValues(roleName, attrs, list);
637: }
638:
639: // Return the augmented list of roles
640: if (debug >= 2) {
641: log(" Returning " + list.size() + " roles");
642: for (int i = 0; i < list.size(); i++) {
643: log(" Found role " + list.get(i));
644: }
645: }
646:
647: return list;
648: }
649:
650: /**
651: * Return a String representing the value of the specified attribute.
652: *
653: * @param attrId Attribute name
654: * @param attrs Attributes containing the required value
655: * @throws javax.naming.NamingException if a directory server error occurs
656: */
657: private String getAttributeValue(String attrId, Attributes attrs)
658: throws NamingException {
659:
660: if (debug >= 3) {
661: log(" retrieving attribute " + attrId);
662: }
663:
664: if (attrId == null || attrs == null) {
665: return null;
666: }
667:
668: Attribute attr = attrs.get(attrId);
669: if (attr == null)
670: return null;
671:
672: Object value = attr.get();
673: if (value == null)
674: return null;
675: String valueString = null;
676: if (value instanceof byte[]) {
677: valueString = new String((byte[]) value);
678: } else {
679: valueString = value.toString();
680: }
681:
682: return valueString;
683: }
684:
685: /**
686: * Add values of a specified attribute to a list
687: *
688: * @param attrId Attribute name
689: * @param attrs Attributes containing the new values
690: * @param values ArrayList containing values found so far
691: * @throws javax.naming.NamingException if a directory server error occurs
692: */
693: private List addAttributeValues(String attrId, Attributes attrs,
694: List values) throws NamingException {
695:
696: if (debug >= 3) {
697: log(" retrieving values for attribute " + attrId);
698: }
699: if (attrId == null || attrs == null) {
700: return null;
701: }
702: if (values == null) {
703: values = new ArrayList();
704: }
705: Attribute attr = attrs.get(attrId);
706: if (attr == null) {
707: return null;
708: }
709: NamingEnumeration e = attr.getAll();
710: while (e.hasMore()) {
711: String value = (String) e.next();
712: values.add(value);
713: }
714: return values;
715: }
716:
717: /**
718: * Create our directory context configuration.
719: *
720: * @return java.util.Hashtable the configuration for the directory context.
721: */
722: protected Hashtable getDirectoryContextEnvironment(String username,
723: String credentials) {
724:
725: Hashtable env = new Hashtable();
726:
727: setAttributeIfValueNotNull(env, Context.PROVIDER_URL,
728: connectionURL);
729: setAttributeIfValueNotNull(env,
730: Context.INITIAL_CONTEXT_FACTORY, contextFactory);
731: setAttributeIfValueNotNull(env, Context.SECURITY_PRINCIPAL,
732: username);
733: setAttributeIfValueNotNull(env, Context.SECURITY_CREDENTIALS,
734: credentials);
735: setAttributeIfValueNotNull(env,
736: Context.SECURITY_AUTHENTICATION, authentication);
737: setAttributeIfValueNotNull(env, Context.SECURITY_PROTOCOL,
738: protocol);
739: setAttributeIfValueNotNull(env, Context.REFERRAL, referrals);
740:
741: return env;
742: }
743:
744: private void setAttributeIfValueNotNull(Hashtable env,
745: String attribute, String value) {
746: if (value != null)
747: env.put(attribute, value);
748: }
749:
750: /**
751: * Check whether the given User can be authenticated with the
752: * given credentials. If the <code>userPassword</code>
753: * configuration attribute is specified, the credentials
754: * previously retrieved from the directory are compared explicitly
755: * with those presented by the user. Otherwise the presented
756: * credentials are checked by binding to the directory as the
757: * user.
758: *
759: * @param userName The UserName to be authenticated
760: * @param credentials The credentials presented by the user
761: * @throws com.sabre.security.jndi.AuthenticationException if a directory server error occurs
762: * if authentication fails
763: */
764: public void checkCredentials(String userName, String credentials)
765: throws com.sabre.security.jndi.AuthenticationException {
766:
767: boolean validated = false;
768: try {
769: User user = this .getUser(userName);
770:
771: if (userPassword == null) {
772: validated = bindAsUser(user, credentials);
773: if (user != null) {
774: log("bindAsUser(user, credentials) '"
775: + user.username + "'");
776: } else {
777: log("bindAsUser(user, credentials)");
778: }
779: } else {
780: validated = compareCredentials(user, credentials);
781: if (user != null) {
782: log("compareCredentials(user, credentials) '"
783: + user.username + "'");
784: } else {
785: log("compareCredentials(user, credentials)");
786: }
787: }
788:
789: if (debug >= 2) {
790: if (user != null) {
791: log("jndiRealm.authenticate"
792: + (validated ? "Success" : "Failure" + " "
793: + user.username));
794: } else {
795: log("jndiRealm.authenticate"
796: + (validated ? "Success" : "Failure"));
797: }
798: }
799: } catch (CommunicationException ex) {
800: log("jndiRealm.exception", ex);
801: closeContext();
802: throw new com.sabre.security.jndi.AuthenticationException(
803: JNDIAuthenticator.MESSAGE_COMMUNICATION_ERROR_KEY);
804: } catch (NamingException ne) {
805: throw new com.sabre.security.jndi.AuthenticationException(
806: JNDIAuthenticator.MESSAGE_AUTHENTICATION_FAILED_KEY);
807: }
808: if (!validated) {
809: throw new com.sabre.security.jndi.AuthenticationException(
810: JNDIAuthenticator.MESSAGE_AUTHENTICATION_FAILED_KEY);
811: }
812: }
813:
814: /**
815: * Check whether the credentials presented by the user match those
816: * retrieved from the directory.
817: *
818: * @param info The User to be authenticated
819: * @param credentials Authentication credentials
820: * @throws javax.naming.NamingException if a directory server error occurs
821: */
822: protected boolean compareCredentials(User info, String credentials)
823: throws NamingException {
824:
825: if (info == null || credentials == null) {
826: return false;
827: }
828:
829: String password = info.password;
830: if (password == null) {
831: return false;
832: }
833:
834: // Validate the credentials specified by the user
835: if (debug >= 3) {
836: log(" validating credentials");
837: }
838:
839: boolean validated = false;
840: if (hasMessageDigest()) {
841: // Hex hashes should be compared case-insensitive
842: if (Base64.isBase64(password.substring(5))) {
843: password = HexUtils.convert(Base64.decode(password
844: .substring(5).getBytes()));
845: }
846: validated = digest(credentials).equalsIgnoreCase(password);
847: } else {
848: validated = digest(credentials).equals(password);
849: }
850: return validated;
851: }
852:
853: protected String digest(String credentials) {
854: // If no MessageDigest instance is specified, return unchanged
855: if (!hasMessageDigest()) {
856: return credentials;
857: }
858:
859: // Digest the user credentials and return as hexadecimal
860: synchronized (this ) {
861: try {
862: messageDigest.reset();
863: messageDigest.update(credentials.getBytes());
864: return HexUtils.convert(messageDigest.digest());
865: } catch (Exception e) {
866: log("realmBase.digest", e);
867: return credentials;
868: }
869: }
870: }
871:
872: /**
873: * Close any open connection to the directory server for this Realm.
874: */
875: public void closeContext() {
876:
877: // Do nothing if there is no opened connection
878: if (context == null) {
879: return;
880: }
881:
882: // Close our opened connection
883: try {
884: if (debug >= 1) {
885: log("Closing directory context");
886: }
887: context.close();
888: } catch (NamingException e) {
889: log("jndiRealm.close", e);
890: }
891: // this.context = null;
892:
893: }
894:
895: /**
896: * Open (if necessary) and return a connection to the configured
897: * directory server for this Realm.
898: *
899: * @throws com.sabre.security.jndi.AuthenticationException if a directory server error occurs
900: */
901: public void open()
902: throws com.sabre.security.jndi.AuthenticationException {
903:
904: open(null, null);
905:
906: }
907:
908: public void open(String username, String credentials)
909: throws com.sabre.security.jndi.AuthenticationException {
910:
911: try {
912:
913: // Ensure that we have a directory context available
914: context = new InitialDirContext(
915: getDirectoryContextEnvironment(username,
916: credentials));
917:
918: } catch (NamingException e) {
919:
920: try {
921:
922: // log the first exception.
923: log("jndiRealm.exception", e);
924:
925: // Try connecting once more.
926: context = new InitialDirContext(
927: getDirectoryContextEnvironment(username,
928: credentials));
929:
930: } catch (CommunicationException ex) {
931: log("jndiRealm.exception", ex);
932: closeContext();
933: throw new com.sabre.security.jndi.AuthenticationException(
934: JNDIAuthenticator.MESSAGE_COMMUNICATION_ERROR_KEY);
935: } catch (NamingException ne) {
936: throw new com.sabre.security.jndi.AuthenticationException(
937: JNDIAuthenticator.MESSAGE_AUTHENTICATION_FAILED_KEY);
938: }
939: }
940:
941: }
942:
943: public boolean isFixedUserConnection() {
944: return connectionUser != null && connectionPassword != null;
945: }
946:
947: private boolean hasMessageDigest() {
948: return messageDigest != null;
949: }
950:
951: private void log(String s) {
952: log.info(s);
953: }
954:
955: private void log(String s, Throwable ex) {
956: log.info(s, ex);
957: }
958:
959: }
|