Source Code Cross Referenced for JNDIRealm.java in  » Web-Server » Rimfaxe-Web-Server » org » apache » catalina » realm » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Web Server » Rimfaxe Web Server » org.apache.catalina.realm 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/JNDIRealm.java,v 1.8 2002/06/11 15:32:28 remm Exp $
0003:         * $Revision: 1.8 $
0004:         * $Date: 2002/06/11 15:32:28 $
0005:         *
0006:         * ====================================================================
0007:         * The Apache Software License, Version 1.1
0008:         *
0009:         * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
0010:         * reserved.
0011:         *
0012:         * Redistribution and use in source and binary forms, with or without
0013:         * modification, are permitted provided that the following conditions
0014:         * are met:
0015:         *
0016:         * 1. Redistributions of source code must retain the above copyright
0017:         *    notice, this list of conditions and the following disclaimer.
0018:         *
0019:         * 2. Redistributions in binary form must reproduce the above copyright
0020:         *    notice, this list of conditions and the following disclaimer in
0021:         *    the documentation and/or other materials provided with the
0022:         *    distribution.
0023:         *
0024:         * 3. The end-user documentation included with the redistribution, if
0025:         *    any, must include the following acknowlegement:
0026:         *       "This product includes software developed by the
0027:         *        Apache Software Foundation (http://www.apache.org/)."
0028:         *    Alternately, this acknowlegement may appear in the software itself,
0029:         *    if and wherever such third-party acknowlegements normally appear.
0030:         *
0031:         * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
0032:         *    Foundation" must not be used to endorse or promote products derived
0033:         *    from this software without prior written permission. For written
0034:         *    permission, please contact apache@apache.org.
0035:         *
0036:         * 5. Products derived from this software may not be called "Apache"
0037:         *    nor may "Apache" appear in their names without prior written
0038:         *    permission of the Apache Group.
0039:         *
0040:         * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0041:         * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0042:         * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0043:         * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0044:         * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0045:         * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0046:         * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0047:         * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0048:         * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0049:         * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0050:         * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0051:         * SUCH DAMAGE.
0052:         * ====================================================================
0053:         *
0054:         * This software consists of voluntary contributions made by many
0055:         * individuals on behalf of the Apache Software Foundation.  For more
0056:         * information on the Apache Software Foundation, please see
0057:         * <http://www.apache.org/>.
0058:         *
0059:         * [Additional notices, if required by prior licensing conditions]
0060:         *
0061:         */
0062:
0063:        package org.apache.catalina.realm;
0064:
0065:        import java.security.Principal;
0066:        import java.text.MessageFormat;
0067:        import java.util.ArrayList;
0068:        import java.util.Hashtable;
0069:        import java.util.List;
0070:        import javax.naming.Context;
0071:        import javax.naming.NameNotFoundException;
0072:        import javax.naming.NamingEnumeration;
0073:        import javax.naming.NamingException;
0074:        import javax.naming.NameParser;
0075:        import javax.naming.Name;
0076:        import javax.naming.AuthenticationException;
0077:        import javax.naming.directory.Attribute;
0078:        import javax.naming.directory.Attributes;
0079:        import javax.naming.directory.DirContext;
0080:        import javax.naming.directory.InitialDirContext;
0081:        import javax.naming.directory.SearchControls;
0082:        import javax.naming.directory.SearchResult;
0083:        import org.apache.catalina.LifecycleException;
0084:        import org.apache.catalina.Realm;
0085:        import org.apache.catalina.util.StringManager;
0086:
0087:        /**
0088:         * <p>Implementation of <strong>Realm</strong> that works with a directory
0089:         * server accessed via the Java Naming and Directory Interface (JNDI) APIs.
0090:         * The following constraints are imposed on the data structure in the
0091:         * underlying directory server:</p>
0092:         * <ul>
0093:         *
0094:         * <li>Each user that can be authenticated is represented by an individual
0095:         *     element in the top level <code>DirContext</code> that is accessed
0096:         *     via the <code>connectionURL</code> property.</li>
0097:         *
0098:         * <li>Each user element has a distinguished name that can be formed by
0099:         *     substituting the presented username into a pattern configured by the
0100:         *     <code>userPattern</code> property.</li>
0101:         *
0102:         * <li>Alternatively, if the <code>userPattern</code> property is not 
0103:         *     specified, a unique element can be located by searching the directory
0104:         *     context. In this case:
0105:         *     <ul>
0106:         *     <li>The <code>userSearch</code> pattern specifies the search filter
0107:         *         after substitution of the username.</li>
0108:         *     <li>The <code>userBase</code> property can be set to the element that
0109:         *         is the base of the subtree containing users.  If not specified,
0110:         *         the search base is the top-level context.</li>
0111:         *     <li>The <code>userSubtree</code> property can be set to
0112:         *         <code>true</code> if you wish to search the entire subtree of the
0113:         *         directory context.  The default value of <code>false</code>
0114:         *         requests a search of only the current level.</li>
0115:         *    </ul>
0116:         * </li>
0117:         * 
0118:         * <li>The user may be authenticated by binding to the directory with the
0119:         *      username and password presented. This method is used when the
0120:         *      <code>userPassword</code> property is not specified.</li>
0121:         *
0122:         * <li>The user may be authenticated by retrieving the value of an attribute
0123:         *     from the directory and comparing it explicitly with the value presented
0124:         *     by the user. This method is used when the <code>userPassword</code>
0125:         *     property is specified, in which case:
0126:         *     <ul>
0127:         *     <li>The element for this user must contain an attribute named by the
0128:         *         <code>userPassword</code> property.
0129:         *     <li>The value of the user password attribute is either a cleartext
0130:         *         String, or the result of passing a cleartext String through the
0131:         *         <code>RealmBase.digest()</code> method (using the standard digest
0132:         *         support included in <code>RealmBase</code>).
0133:         *     <li>The user is considered to be authenticated if the presented
0134:         *         credentials (after being passed through
0135:         *         <code>RealmBase.digest()</code>) are equal to the retrieved value
0136:         *         for the user password attribute.</li>
0137:         *     </ul></li>
0138:         *
0139:         * <li>Each group of users that has been assigned a particular role may be
0140:         *     represented by an individual element in the top level
0141:         *     <code>DirContext</code> that is accessed via the
0142:         *     <code>connectionURL</code> property.  This element has the following
0143:         *     characteristics:
0144:         *     <ul>
0145:         *     <li>The set of all possible groups of interest can be selected by a
0146:         *         search pattern configured by the <code>roleSearch</code>
0147:         *         property.</li>
0148:         *     <li>The <code>roleSearch</code> pattern optionally includes pattern
0149:         *         replacements "{0}" for the distinguished name, and/or "{1}" for
0150:         *         the username, of the authenticated user for which roles will be
0151:         *         retrieved.</li>
0152:         *     <li>The <code>roleBase</code> property can be set to the element that
0153:         *         is the base of the search for matching roles.  If not specified,
0154:         *         the entire context will be searched.</li>
0155:         *     <li>The <code>roleSubtree</code> property can be set to
0156:         *         <code>true</code> if you wish to search the entire subtree of the
0157:         *         directory context.  The default value of <code>false</code>
0158:         *         requests a search of only the current level.</li>
0159:         *     <li>The element includes an attribute (whose name is configured by
0160:         *         the <code>roleName</code> property) containing the name of the
0161:         *         role represented by this element.</li>
0162:         *     </ul></li>
0163:         *
0164:         * <li>In addition, roles may be represented by the values of an attribute
0165:         * in the user's element whose name is configured by the
0166:         * <code>userRoleName</code> property.</li>
0167:         *
0168:         * <li>Note that the standard <code>&lt;security-role-ref&gt;</code> element in
0169:         *     the web application deployment descriptor allows applications to refer
0170:         *     to roles programmatically by names other than those used in the
0171:         *     directory server itself.</li>
0172:         * </ul>
0173:         *
0174:         * <p><strong>TODO</strong> - Support connection pooling (including message
0175:         * format objects) so that <code>authenticate()</code> does not have to be
0176:         * synchronized.</p>
0177:         *
0178:         * @author John Holman
0179:         * @author Craig R. McClanahan
0180:         * @version $Revision: 1.8 $ $Date: 2002/06/11 15:32:28 $
0181:         */
0182:
0183:        public class JNDIRealm extends RealmBase {
0184:
0185:            // ----------------------------------------------------- Instance Variables
0186:
0187:            /**
0188:             * The connection username for the server we will contact.
0189:             */
0190:            protected String connectionName = null;
0191:
0192:            /**
0193:             * The connection password for the server we will contact.
0194:             */
0195:            protected String connectionPassword = null;
0196:
0197:            /**
0198:             * The connection URL for the server we will contact.
0199:             */
0200:            protected String connectionURL = null;
0201:
0202:            /**
0203:             * The directory context linking us to our directory server.
0204:             */
0205:            protected DirContext context = null;
0206:
0207:            /**
0208:             * The JNDI context factory used to acquire our InitialContext.  By
0209:             * default, assumes use of an LDAP server using the standard JNDI LDAP
0210:             * provider.
0211:             */
0212:            protected String contextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
0213:
0214:            /**
0215:             * Descriptive information about this Realm implementation.
0216:             */
0217:            protected static final String info = "org.apache.catalina.realm.JNDIRealm/1.0";
0218:
0219:            /**
0220:             * Descriptive information about this Realm implementation.
0221:             */
0222:            protected static final String name = "JNDIRealm";
0223:
0224:            /**
0225:             * The base element for user searches.
0226:             */
0227:            protected String userBase = "";
0228:
0229:            /**
0230:             * The message format used to search for a user, with "{0}" marking
0231:             * the spot where the username goes.
0232:             */
0233:            protected String userSearch = null;
0234:
0235:            /**
0236:             * The MessageFormat object associated with the current
0237:             * <code>userSearch</code>.
0238:             */
0239:            protected MessageFormat userSearchFormat = null;
0240:
0241:            /**
0242:             * Should we search the entire subtree for matching users?
0243:             */
0244:            protected boolean userSubtree = false;
0245:
0246:            /**
0247:             * The attribute name used to retrieve the user password.
0248:             */
0249:            protected String userPassword = null;
0250:
0251:            /**
0252:             * The message format used to form the distinguished name of a
0253:             * user, with "{0}" marking the spot where the specified username
0254:             * goes.  
0255:             */
0256:            protected String userPattern = null;
0257:
0258:            /**
0259:             * The MessageFormat object associated with the current
0260:             * <code>userPattern</code>.
0261:             */
0262:            protected MessageFormat userPatternFormat = null;
0263:
0264:            /**
0265:             * The base element for role searches.
0266:             */
0267:            protected String roleBase = "";
0268:
0269:            /**
0270:             * The MessageFormat object associated with the current
0271:             * <code>roleSearch</code>.
0272:             */
0273:            protected MessageFormat roleFormat = null;
0274:
0275:            /**
0276:             * The name of an attribute in the user's entry containing
0277:             * roles for that user
0278:             */
0279:            protected String userRoleName = null;
0280:
0281:            /**
0282:             * The name of the attribute containing roles held elsewhere
0283:             */
0284:            protected String roleName = null;
0285:
0286:            /**
0287:             * The message format used to select roles for a user, with "{0}" marking
0288:             * the spot where the distinguished name of the user goes.
0289:             */
0290:            protected String roleSearch = null;
0291:
0292:            /**
0293:             * Should we search the entire subtree for matching memberships?
0294:             */
0295:            protected boolean roleSubtree = false;
0296:
0297:            // ------------------------------------------------------------- Properties
0298:
0299:            /**
0300:             * Return the connection username for this Realm.
0301:             */
0302:            public String getConnectionName() {
0303:
0304:                return (this .connectionName);
0305:
0306:            }
0307:
0308:            /**
0309:             * Set the connection username for this Realm.
0310:             *
0311:             * @param connectionName The new connection username
0312:             */
0313:            public void setConnectionName(String connectionName) {
0314:
0315:                this .connectionName = connectionName;
0316:
0317:            }
0318:
0319:            /**
0320:             * Return the connection password for this Realm.
0321:             */
0322:            public String getConnectionPassword() {
0323:
0324:                return (this .connectionPassword);
0325:
0326:            }
0327:
0328:            /**
0329:             * Set the connection password for this Realm.
0330:             *
0331:             * @param connectionPassword The new connection password
0332:             */
0333:            public void setConnectionPassword(String connectionPassword) {
0334:
0335:                this .connectionPassword = connectionPassword;
0336:
0337:            }
0338:
0339:            /**
0340:             * Return the connection URL for this Realm.
0341:             */
0342:            public String getConnectionURL() {
0343:
0344:                return (this .connectionURL);
0345:
0346:            }
0347:
0348:            /**
0349:             * Set the connection URL for this Realm.
0350:             *
0351:             * @param connectionURL The new connection URL
0352:             */
0353:            public void setConnectionURL(String connectionURL) {
0354:
0355:                this .connectionURL = connectionURL;
0356:
0357:            }
0358:
0359:            /**
0360:             * Return the JNDI context factory for this Realm.
0361:             */
0362:            public String getContextFactory() {
0363:
0364:                return (this .contextFactory);
0365:
0366:            }
0367:
0368:            /**
0369:             * Set the JNDI context factory for this Realm.
0370:             *
0371:             * @param contextFactory The new context factory
0372:             */
0373:            public void setContextFactory(String contextFactory) {
0374:
0375:                this .contextFactory = contextFactory;
0376:
0377:            }
0378:
0379:            /**
0380:             * Return the base element for user searches.
0381:             */
0382:            public String getUserBase() {
0383:
0384:                return (this .userBase);
0385:
0386:            }
0387:
0388:            /**
0389:             * Set the base element for user searches.
0390:             *
0391:             * @param userBase The new base element
0392:             */
0393:            public void setUserBase(String userBase) {
0394:
0395:                this .userBase = userBase;
0396:
0397:            }
0398:
0399:            /**
0400:             * Return the message format pattern for selecting users in this Realm.
0401:             */
0402:            public String getUserSearch() {
0403:
0404:                return (this .userSearch);
0405:
0406:            }
0407:
0408:            /**
0409:             * Set the message format pattern for selecting users in this Realm.
0410:             *
0411:             * @param userSearch The new user search pattern
0412:             */
0413:            public void setUserSearch(String userSearch) {
0414:
0415:                this .userSearch = userSearch;
0416:                if (userSearch == null)
0417:                    userSearchFormat = null;
0418:                else
0419:                    userSearchFormat = new MessageFormat(userSearch);
0420:
0421:            }
0422:
0423:            /**
0424:             * Return the "search subtree for users" flag.
0425:             */
0426:            public boolean getUserSubtree() {
0427:
0428:                return (this .userSubtree);
0429:
0430:            }
0431:
0432:            /**
0433:             * Set the "search subtree for users" flag.
0434:             *
0435:             * @param userSubtree The new search flag
0436:             */
0437:            public void setUserSubtree(boolean userSubtree) {
0438:
0439:                this .userSubtree = userSubtree;
0440:
0441:            }
0442:
0443:            /**
0444:             * Return the user role name attribute name for this Realm.
0445:             */
0446:            public String getUserRoleName() {
0447:
0448:                return userRoleName;
0449:            }
0450:
0451:            /**
0452:             * Set the user role name attribute name for this Realm.
0453:             *
0454:             * @param userRoleName The new userRole name attribute name
0455:             */
0456:            public void setUserRoleName(String userRoleName) {
0457:
0458:                this .userRoleName = userRoleName;
0459:
0460:            }
0461:
0462:            /**
0463:             * Return the base element for role searches.
0464:             */
0465:            public String getRoleBase() {
0466:
0467:                return (this .roleBase);
0468:
0469:            }
0470:
0471:            /**
0472:             * Set the base element for role searches.
0473:             *
0474:             * @param roleBase The new base element
0475:             */
0476:            public void setRoleBase(String roleBase) {
0477:
0478:                this .roleBase = roleBase;
0479:
0480:            }
0481:
0482:            /**
0483:             * Return the role name attribute name for this Realm.
0484:             */
0485:            public String getRoleName() {
0486:
0487:                return (this .roleName);
0488:
0489:            }
0490:
0491:            /**
0492:             * Set the role name attribute name for this Realm.
0493:             *
0494:             * @param roleName The new role name attribute name
0495:             */
0496:            public void setRoleName(String roleName) {
0497:
0498:                this .roleName = roleName;
0499:
0500:            }
0501:
0502:            /**
0503:             * Return the message format pattern for selecting roles in this Realm.
0504:             */
0505:            public String getRoleSearch() {
0506:
0507:                return (this .roleSearch);
0508:
0509:            }
0510:
0511:            /**
0512:             * Set the message format pattern for selecting roles in this Realm.
0513:             *
0514:             * @param roleSearch The new role search pattern
0515:             */
0516:            public void setRoleSearch(String roleSearch) {
0517:
0518:                this .roleSearch = roleSearch;
0519:                if (roleSearch == null)
0520:                    roleFormat = null;
0521:                else
0522:                    roleFormat = new MessageFormat(roleSearch);
0523:
0524:            }
0525:
0526:            /**
0527:             * Return the "search subtree for roles" flag.
0528:             */
0529:            public boolean getRoleSubtree() {
0530:
0531:                return (this .roleSubtree);
0532:
0533:            }
0534:
0535:            /**
0536:             * Set the "search subtree for roles" flag.
0537:             *
0538:             * @param roleSubtree The new search flag
0539:             */
0540:            public void setRoleSubtree(boolean roleSubtree) {
0541:
0542:                this .roleSubtree = roleSubtree;
0543:
0544:            }
0545:
0546:            /**
0547:             * Return the password attribute used to retrieve the user password.
0548:             */
0549:            public String getUserPassword() {
0550:
0551:                return (this .userPassword);
0552:
0553:            }
0554:
0555:            /**
0556:             * Set the password attribute used to retrieve the user password.
0557:             *
0558:             * @param userPassword The new password attribute
0559:             */
0560:            public void setUserPassword(String userPassword) {
0561:
0562:                this .userPassword = userPassword;
0563:
0564:            }
0565:
0566:            /**
0567:             * Return the message format pattern for selecting users in this Realm.
0568:             */
0569:            public String getUserPattern() {
0570:
0571:                return (this .userPattern);
0572:
0573:            }
0574:
0575:            /**
0576:             * Set the message format pattern for selecting users in this Realm.
0577:             *
0578:             * @param userPattern The new user pattern
0579:             */
0580:            public void setUserPattern(String userPattern) {
0581:
0582:                this .userPattern = userPattern;
0583:                if (userPattern == null)
0584:                    userPatternFormat = null;
0585:                else
0586:                    userPatternFormat = new MessageFormat(userPattern);
0587:
0588:            }
0589:
0590:            // ---------------------------------------------------------- Realm Methods
0591:
0592:            /**
0593:             * Return the Principal associated with the specified username and
0594:             * credentials, if there is one; otherwise return <code>null</code>.
0595:             *
0596:             * If there are any errors with the JDBC connection, executing
0597:             * the query or anything we return null (don't authenticate). This
0598:             * event is also logged, and the connection will be closed so that
0599:             * a subsequent request will automatically re-open it.
0600:             *
0601:             * @param username Username of the Principal to look up
0602:             * @param credentials Password or other credentials to use in
0603:             *  authenticating this username
0604:             */
0605:            public Principal authenticate(String username, String credentials) {
0606:
0607:                DirContext context = null;
0608:
0609:                try {
0610:
0611:                    // Ensure that we have a directory context available
0612:                    context = open();
0613:
0614:                    // Authenticate the specified username if possible
0615:                    Principal principal = authenticate(context, username,
0616:                            credentials);
0617:
0618:                    // Release this context
0619:                    release(context);
0620:
0621:                    // Return the authenticated Principal (if any)
0622:                    return (principal);
0623:
0624:                } catch (NamingException e) {
0625:
0626:                    // Log the problem for posterity
0627:                    log(sm.getString("jndiRealm.exception"), e);
0628:
0629:                    // Close the connection so that it gets reopened next time
0630:                    if (context != null)
0631:                        close(context);
0632:
0633:                    // Return "not authenticated" for this request
0634:                    return (null);
0635:
0636:                }
0637:
0638:            }
0639:
0640:            // -------------------------------------------------------- Package Methods
0641:
0642:            // ------------------------------------------------------ Protected Methods
0643:
0644:            /**
0645:             * Return the Principal associated with the specified username and
0646:             * credentials, if there is one; otherwise return <code>null</code>.
0647:             *
0648:             * @param context The directory context
0649:             * @param username Username of the Principal to look up
0650:             * @param credentials Password or other credentials to use in
0651:             *  authenticating this username
0652:             *
0653:             * @exception NamingException if a directory server error occurs
0654:             */
0655:            public synchronized Principal authenticate(DirContext context,
0656:                    String username, String credentials) throws NamingException {
0657:
0658:                if (username == null || username.equals("")
0659:                        || credentials == null || credentials.equals(""))
0660:                    return (null);
0661:
0662:                // Retrieve user information
0663:                User user = getUser(context, username);
0664:                if (user == null)
0665:                    return (null);
0666:
0667:                // Check the user's credentials
0668:                if (!checkCredentials(context, user, credentials))
0669:                    return (null);
0670:
0671:                // Search for additional roles
0672:                List roles = getRoles(context, user);
0673:
0674:                // Create and return a suitable Principal for this user
0675:                return (new GenericPrincipal(this , username, credentials, roles));
0676:
0677:            }
0678:
0679:            /**
0680:             * Return a User object containing information about the user
0681:             * with the specified username, if found in the directory;
0682:             * otherwise return <code>null</code>.
0683:             *
0684:             * If the <code>userPassword</code> configuration attribute is
0685:             * specified, the value of that attribute is retrieved from the
0686:             * user's directory entry. If the <code>userRoleName</code>
0687:             * configuration attribute is specified, all values of that
0688:             * attribute are retrieved from the directory entry.
0689:             *
0690:             * @param context The directory context
0691:             * @param username Username to be looked up
0692:             *
0693:             * @exception NamingException if a directory server error occurs
0694:             */
0695:            protected User getUser(DirContext context, String username)
0696:                    throws NamingException {
0697:
0698:                User user = null;
0699:
0700:                // Get attributes to retrieve from user entry
0701:                ArrayList list = new ArrayList();
0702:                if (userPassword != null)
0703:                    list.add(userPassword);
0704:                if (userRoleName != null)
0705:                    list.add(userRoleName);
0706:                String[] attrIds = new String[list.size()];
0707:                list.toArray(attrIds);
0708:
0709:                // Use pattern or search for user entry
0710:                if (userPatternFormat != null) {
0711:                    user = getUserByPattern(context, username, attrIds);
0712:                } else {
0713:                    user = getUserBySearch(context, username, attrIds);
0714:                }
0715:
0716:                return user;
0717:            }
0718:
0719:            /**
0720:             * Use the <code>UserPattern</code> configuration attribute to
0721:             * locate the directory entry for the user with the specified
0722:             * username and return a User object; otherwise return
0723:             * <code>null</code>.
0724:             *
0725:             * @param context The directory context
0726:             * @param username The username
0727:             * @param attrIds String[]containing names of attributes to
0728:             * retrieve.
0729:             *
0730:             * @exception NamingException if a directory server error occurs
0731:             */
0732:            protected User getUserByPattern(DirContext context,
0733:                    String username, String[] attrIds) throws NamingException {
0734:
0735:                if (debug >= 2)
0736:                    log("lookupUser(" + username + ")");
0737:
0738:                if (username == null || userPatternFormat == null)
0739:                    return (null);
0740:
0741:                // Form the dn from the user pattern
0742:                String dn = userPatternFormat.format(new String[] { username });
0743:                if (debug >= 3) {
0744:                    log("  dn=" + dn);
0745:                }
0746:
0747:                // Return if no attributes to retrieve
0748:                if (attrIds == null || attrIds.length == 0)
0749:                    return new User(username, dn, null, null);
0750:
0751:                // Get required attributes from user entry
0752:                Attributes attrs = null;
0753:                try {
0754:                    attrs = context.getAttributes(dn, attrIds);
0755:                } catch (NameNotFoundException e) {
0756:                    return (null);
0757:                }
0758:                if (attrs == null)
0759:                    return (null);
0760:
0761:                // Retrieve value of userPassword
0762:                String password = null;
0763:                if (userPassword != null)
0764:                    password = getAttributeValue(userPassword, attrs);
0765:
0766:                // Retrieve values of userRoleName attribute
0767:                ArrayList roles = null;
0768:                if (userRoleName != null)
0769:                    roles = addAttributeValues(userRoleName, attrs, roles);
0770:
0771:                return new User(username, dn, password, roles);
0772:            }
0773:
0774:            /**
0775:             * Search the directory to return a User object containing
0776:             * information about the user with the specified username, if
0777:             * found in the directory; otherwise return <code>null</code>.
0778:             *
0779:             * @param context The directory context
0780:             * @param username The username
0781:             * @param attrIds String[]containing names of attributes to retrieve.
0782:             *
0783:             * @exception NamingException if a directory server error occurs
0784:             */
0785:            protected User getUserBySearch(DirContext context, String username,
0786:                    String[] attrIds) throws NamingException {
0787:
0788:                if (username == null || userSearchFormat == null)
0789:                    return (null);
0790:
0791:                // Form the search filter
0792:                String filter = userSearchFormat
0793:                        .format(new String[] { username });
0794:
0795:                // Set up the search controls
0796:                SearchControls constraints = new SearchControls();
0797:
0798:                if (userSubtree) {
0799:                    constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
0800:                } else {
0801:                    constraints.setSearchScope(SearchControls.ONELEVEL_SCOPE);
0802:                }
0803:
0804:                // Specify the attributes to be retrieved
0805:                if (attrIds == null)
0806:                    attrIds = new String[0];
0807:                constraints.setReturningAttributes(attrIds);
0808:
0809:                if (debug > 3) {
0810:                    log("  Searching for " + username);
0811:                    log("  base: " + userBase + "  filter: " + filter);
0812:                }
0813:
0814:                NamingEnumeration results = context.search(userBase, filter,
0815:                        constraints);
0816:
0817:                // Fail if no entries found
0818:                if (results == null || !results.hasMore()) {
0819:                    if (debug > 2) {
0820:                        log("  username not found");
0821:                    }
0822:                    return (null);
0823:                }
0824:
0825:                // Get result for the first entry found
0826:                SearchResult result = (SearchResult) results.next();
0827:
0828:                // Check no further entries were found
0829:                if (results.hasMore()) {
0830:                    log("username " + username + " has multiple entries");
0831:                    return (null);
0832:                }
0833:
0834:                // Get the entry's distinguished name
0835:                NameParser parser = context.getNameParser("");
0836:                Name contextName = parser.parse(context.getNameInNamespace());
0837:                Name baseName = parser.parse(userBase);
0838:                Name entryName = parser.parse(result.getName());
0839:                Name name = contextName.addAll(baseName);
0840:                name = name.addAll(entryName);
0841:                String dn = name.toString();
0842:
0843:                if (debug > 2)
0844:                    log("  entry found for " + username + " with dn " + dn);
0845:
0846:                // Get the entry's attributes
0847:                Attributes attrs = result.getAttributes();
0848:                if (attrs == null)
0849:                    return null;
0850:
0851:                // Retrieve value of userPassword
0852:                String password = null;
0853:                if (userPassword != null)
0854:                    password = getAttributeValue(userPassword, attrs);
0855:
0856:                // Retrieve values of userRoleName attribute
0857:                ArrayList roles = null;
0858:                if (userRoleName != null)
0859:                    roles = addAttributeValues(userRoleName, attrs, roles);
0860:
0861:                return new User(username, dn, password, roles);
0862:            }
0863:
0864:            /**
0865:             * Check whether the given User can be authenticated with the
0866:             * given credentials. If the <code>userPassword</code>
0867:             * configuration attribute is specified, the credentials
0868:             * previously retrieved from the directory are compared explicitly
0869:             * with those presented by the user. Otherwise the presented
0870:             * credentials are checked by binding to the directory as the
0871:             * user.
0872:             *
0873:             * @param context The directory context
0874:             * @param user The User to be authenticated
0875:             * @param credentials The credentials presented by the user
0876:             *
0877:             * @exception NamingException if a directory server error occurs
0878:             */
0879:            protected boolean checkCredentials(DirContext context, User user,
0880:                    String credentials) throws NamingException {
0881:
0882:                boolean validated = false;
0883:
0884:                if (userPassword == null) {
0885:                    validated = bindAsUser(context, user, credentials);
0886:                } else {
0887:                    validated = compareCredentials(context, user, credentials);
0888:                }
0889:
0890:                if (debug >= 2) {
0891:                    if (validated) {
0892:                        log(sm.getString("jndiRealm.authenticateSuccess",
0893:                                user.username));
0894:                    } else {
0895:                        log(sm.getString("jndiRealm.authenticateFailure",
0896:                                user.username));
0897:                    }
0898:                }
0899:                return (validated);
0900:            }
0901:
0902:            /**
0903:             * Check whether the credentials presented by the user match those
0904:             * retrieved from the directory.
0905:             *
0906:             * @param context The directory context
0907:             * @param user The User to be authenticated
0908:             * @param credentials Authentication credentials
0909:             *
0910:             * @exception NamingException if a directory server error occurs
0911:             */
0912:            protected boolean compareCredentials(DirContext context, User info,
0913:                    String credentials) throws NamingException {
0914:
0915:                if (info == null || credentials == null)
0916:                    return (false);
0917:
0918:                String password = info.password;
0919:                if (password == null)
0920:                    return (false);
0921:
0922:                // Validate the credentials specified by the user
0923:                if (debug >= 3)
0924:                    log("  validating credentials");
0925:
0926:                boolean validated = false;
0927:                if (hasMessageDigest()) {
0928:                    // Hex hashes should be compared case-insensitive
0929:                    validated = (digest(credentials).equalsIgnoreCase(password));
0930:                } else
0931:                    validated = (digest(credentials).equals(password));
0932:                return (validated);
0933:
0934:            }
0935:
0936:            /**
0937:             * Check credentials by binding to the directory as the user
0938:             *
0939:             * @param context The directory context
0940:             * @param user The User to be authenticated
0941:             * @param credentials Authentication credentials
0942:             *
0943:             * @exception NamingException if a directory server error occurs
0944:             */
0945:            protected boolean bindAsUser(DirContext context, User user,
0946:                    String credentials) throws NamingException {
0947:                Attributes attr;
0948:
0949:                if (credentials == null || user == null)
0950:                    return (false);
0951:
0952:                String dn = user.dn;
0953:                if (dn == null)
0954:                    return (false);
0955:
0956:                // Validate the credentials specified by the user
0957:                if (debug >= 3) {
0958:                    log("  validating credentials by binding as the user");
0959:                }
0960:
0961:                // Set up security environment to bind as the user
0962:                context.addToEnvironment(Context.SECURITY_PRINCIPAL, dn);
0963:                context.addToEnvironment(Context.SECURITY_CREDENTIALS,
0964:                        credentials);
0965:
0966:                // Elicit an LDAP bind operation
0967:                boolean validated = false;
0968:                try {
0969:                    if (debug > 2) {
0970:                        log("  binding as " + dn);
0971:                    }
0972:                    attr = context.getAttributes("", null);
0973:                    validated = true;
0974:                } catch (AuthenticationException e) {
0975:                    if (debug > 2) {
0976:                        log("  bind attempt failed");
0977:                    }
0978:                }
0979:
0980:                // Restore the original security environment
0981:                if (connectionName != null) {
0982:                    context.addToEnvironment(Context.SECURITY_PRINCIPAL,
0983:                            connectionName);
0984:                } else {
0985:                    context.removeFromEnvironment(Context.SECURITY_PRINCIPAL);
0986:                }
0987:
0988:                if (connectionPassword != null) {
0989:                    context.addToEnvironment(Context.SECURITY_CREDENTIALS,
0990:                            connectionPassword);
0991:                } else {
0992:                    context.removeFromEnvironment(Context.SECURITY_CREDENTIALS);
0993:                }
0994:
0995:                return (validated);
0996:            }
0997:
0998:            /**
0999:             * Return a List of roles associated with the given User.  Any
1000:             * roles present in the user's directory entry are supplemented by
1001:             * a directory search. If no roles are associated with this user,
1002:             * a zero-length List is returned.
1003:             *
1004:             * @param context The directory context we are searching
1005:             * @param user The User to be checked
1006:             *
1007:             * @exception NamingException if a directory server error occurs
1008:             */
1009:            protected List getRoles(DirContext context, User user)
1010:                    throws NamingException {
1011:
1012:                if (user == null)
1013:                    return (null);
1014:
1015:                String dn = user.dn;
1016:                String username = user.username;
1017:
1018:                if (dn == null || username == null)
1019:                    return (null);
1020:
1021:                if (debug >= 2)
1022:                    log("  getRoles(" + dn + ")");
1023:
1024:                // Start with roles retrieved from the user entry
1025:                ArrayList list = user.roles;
1026:                if (list == null) {
1027:                    list = new ArrayList();
1028:                }
1029:
1030:                // Are we configured to do role searches?
1031:                if ((roleFormat == null) || (roleName == null))
1032:                    return (list);
1033:
1034:                // Set up parameters for an appropriate search
1035:                String filter = roleFormat
1036:                        .format(new String[] { dn, username });
1037:                SearchControls controls = new SearchControls();
1038:                if (roleSubtree)
1039:                    controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
1040:                else
1041:                    controls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
1042:                controls.setReturningAttributes(new String[] { roleName });
1043:
1044:                // Perform the configured search and process the results
1045:                if (debug >= 3) {
1046:                    log("  Searching role base '" + roleBase
1047:                            + "' for attribute '" + roleName + "'");
1048:                    log("  With filter expression '" + filter + "'");
1049:                }
1050:                NamingEnumeration results = context.search(roleBase, filter,
1051:                        controls);
1052:                if (results == null)
1053:                    return (list); // Should never happen, but just in case ...
1054:                while (results.hasMore()) {
1055:                    SearchResult result = (SearchResult) results.next();
1056:                    Attributes attrs = result.getAttributes();
1057:                    if (attrs == null)
1058:                        continue;
1059:                    list = addAttributeValues(roleName, attrs, list);
1060:                }
1061:
1062:                // Return the augmented list of roles
1063:                if (debug >= 2) {
1064:                    log("  Returning " + list.size() + " roles");
1065:                    for (int i = 0; i < list.size(); i++)
1066:                        log("  Found role " + list.get(i));
1067:                }
1068:
1069:                return (list);
1070:            }
1071:
1072:            /**
1073:             * Return a String representing the value of the specified attribute.
1074:             *
1075:             * @param attrId Attribute name
1076:             * @param attrs Attributes containing the required value
1077:             *
1078:             * @exception NamingException if a directory server error occurs
1079:             */
1080:            private String getAttributeValue(String attrId, Attributes attrs)
1081:                    throws NamingException {
1082:
1083:                if (debug >= 3)
1084:                    log("  retrieving attribute " + attrId);
1085:
1086:                if (attrId == null || attrs == null)
1087:                    return null;
1088:
1089:                Attribute attr = attrs.get(attrId);
1090:                if (attr == null)
1091:                    return (null);
1092:                Object value = attr.get();
1093:                if (value == null)
1094:                    return (null);
1095:                String valueString = null;
1096:                if (value instanceof  byte[])
1097:                    valueString = new String((byte[]) value);
1098:                else
1099:                    valueString = value.toString();
1100:
1101:                return valueString;
1102:            }
1103:
1104:            /**
1105:             * Add values of a specified attribute to a list
1106:             *
1107:             * @param attrId Attribute name
1108:             * @param attrs Attributes containing the new values
1109:             * @param values ArrayList containing values found so far
1110:             *
1111:             * @exception NamingException if a directory server error occurs
1112:             */
1113:            private ArrayList addAttributeValues(String attrId,
1114:                    Attributes attrs, ArrayList values) throws NamingException {
1115:
1116:                if (debug >= 3)
1117:                    log("  retrieving values for attribute " + attrId);
1118:                if (attrId == null || attrs == null)
1119:                    return null;
1120:                if (values == null)
1121:                    values = new ArrayList();
1122:                Attribute attr = attrs.get(attrId);
1123:                if (attr == null)
1124:                    return (null);
1125:                NamingEnumeration e = attr.getAll();
1126:                while (e.hasMore()) {
1127:                    String value = (String) e.next();
1128:                    values.add(value);
1129:                }
1130:                return values;
1131:            }
1132:
1133:            /**
1134:             * Close any open connection to the directory server for this Realm.
1135:             *
1136:             * @param context The directory context to be closed
1137:             */
1138:            protected void close(DirContext context) {
1139:
1140:                // Do nothing if there is no opened connection
1141:                if (context == null)
1142:                    return;
1143:
1144:                // Close our opened connection
1145:                try {
1146:                    if (debug >= 1)
1147:                        log("Closing directory context");
1148:                    context.close();
1149:                } catch (NamingException e) {
1150:                    log(sm.getString("jndiRealm.close"), e);
1151:                }
1152:                this .context = null;
1153:
1154:            }
1155:
1156:            /**
1157:             * Return a short name for this Realm implementation.
1158:             */
1159:            protected String getName() {
1160:
1161:                return (this .name);
1162:
1163:            }
1164:
1165:            /**
1166:             * Return the password associated with the given principal's user name.
1167:             */
1168:            protected String getPassword(String username) {
1169:
1170:                return (null);
1171:
1172:            }
1173:
1174:            /**
1175:             * Return the Principal associated with the given user name.
1176:             */
1177:            protected Principal getPrincipal(String username) {
1178:
1179:                return (null);
1180:
1181:            }
1182:
1183:            /**
1184:             * Open (if necessary) and return a connection to the configured
1185:             * directory server for this Realm.
1186:             *
1187:             * @exception NamingException if a directory server error occurs
1188:             */
1189:            protected DirContext open() throws NamingException {
1190:
1191:                // Do nothing if there is a directory server connection already open
1192:                if (context != null)
1193:                    return (context);
1194:
1195:                // Establish a connection and retrieve the initial context
1196:                if (debug >= 1)
1197:                    log("Connecting to URL " + connectionURL);
1198:                Hashtable env = new Hashtable();
1199:                env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory);
1200:                if (connectionName != null)
1201:                    env.put(Context.SECURITY_PRINCIPAL, connectionName);
1202:                if (connectionPassword != null)
1203:                    env.put(Context.SECURITY_CREDENTIALS, connectionPassword);
1204:                if (connectionURL != null)
1205:                    env.put(Context.PROVIDER_URL, connectionURL);
1206:                context = new InitialDirContext(env);
1207:                return (context);
1208:
1209:            }
1210:
1211:            /**
1212:             * Release our use of this connection so that it can be recycled.
1213:             *
1214:             * @param context The directory context to release
1215:             */
1216:            protected void release(DirContext context) {
1217:
1218:                ; // NO-OP since we are not pooling anything
1219:
1220:            }
1221:
1222:            // ------------------------------------------------------ Lifecycle Methods
1223:
1224:            /**
1225:             * Prepare for active use of the public methods of this Component.
1226:             *
1227:             * @exception LifecycleException if this component detects a fatal error
1228:             *  that prevents it from being started
1229:             */
1230:            public void start() throws LifecycleException {
1231:
1232:                // Validate that we can open our connection
1233:                try {
1234:                    open();
1235:                } catch (NamingException e) {
1236:                    throw new LifecycleException(
1237:                            sm.getString("jndiRealm.open"), e);
1238:                }
1239:
1240:                // Perform normal superclass initialization
1241:                super .start();
1242:
1243:            }
1244:
1245:            /**
1246:             * Gracefully shut down active use of the public methods of this Component.
1247:             *
1248:             * @exception LifecycleException if this component detects a fatal error
1249:             *  that needs to be reported
1250:             */
1251:            public void stop() throws LifecycleException {
1252:
1253:                // Perform normal superclass finalization
1254:                super .stop();
1255:
1256:                // Close any open directory server connection
1257:                close(this .context);
1258:
1259:            }
1260:
1261:        }
1262:
1263:        // ------------------------------------------------------ Private Classes
1264:
1265:        /**
1266:         * A private class representing a User
1267:         */
1268:        class User {
1269:            String username = null;
1270:            String dn = null;
1271:            String password = null;
1272:            ArrayList roles = null;
1273:
1274:            User(String username, String dn, String password, ArrayList roles) {
1275:                this.username = username;
1276:                this.dn = dn;
1277:                this.password = password;
1278:                this.roles = roles;
1279:            }
1280:
1281:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.