001: /*
002: * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/UserDatabaseRealm.java,v 1.8 2002/06/09 02:19:43 remm Exp $
003: * $Revision: 1.8 $
004: * $Date: 2002/06/09 02:19:43 $
005: *
006: * ====================================================================
007: *
008: * The Apache Software License, Version 1.1
009: *
010: * Copyright (c) 2002 The Apache Software Foundation. All rights
011: * reserved.
012: *
013: * Redistribution and use in source and binary forms, with or without
014: * modification, are permitted provided that the following conditions
015: * are met:
016: *
017: * 1. Redistributions of source code must retain the above copyright
018: * notice, this list of conditions and the following disclaimer.
019: *
020: * 2. Redistributions in binary form must reproduce the above copyright
021: * notice, this list of conditions and the following disclaimer in
022: * the documentation and/or other materials provided with the
023: * distribution.
024: *
025: * 3. The end-user documentation included with the redistribution, if
026: * any, must include the following acknowlegement:
027: * "This product includes software developed by the
028: * Apache Software Foundation (http://www.apache.org/)."
029: * Alternately, this acknowlegement may appear in the software itself,
030: * if and wherever such third-party acknowlegements normally appear.
031: *
032: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
033: * Foundation" must not be used to endorse or promote products derived
034: * from this software without prior written permission. For written
035: * permission, please contact apache@apache.org.
036: *
037: * 5. Products derived from this software may not be called "Apache"
038: * nor may "Apache" appear in their names without prior written
039: * permission of the Apache Group.
040: *
041: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
042: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
043: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
044: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
045: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
046: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
047: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
048: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
049: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
050: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
051: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
052: * SUCH DAMAGE.
053: * ====================================================================
054: *
055: * This software consists of voluntary contributions made by many
056: * individuals on behalf of the Apache Software Foundation. For more
057: * information on the Apache Software Foundation, please see
058: * <http://www.apache.org/>.
059: *
060: * [Additional notices, if required by prior licensing conditions]
061: *
062: */
063:
064: package org.apache.catalina.realm;
065:
066: import java.security.Principal;
067: import java.util.ArrayList;
068: import java.util.Iterator;
069: import javax.naming.Context;
070: import javax.naming.InitialContext;
071: import org.apache.catalina.Container;
072: import org.apache.catalina.Lifecycle;
073: import org.apache.catalina.LifecycleEvent;
074: import org.apache.catalina.LifecycleException;
075: import org.apache.catalina.LifecycleListener;
076: import org.apache.catalina.Engine;
077: import org.apache.catalina.Group;
078: import org.apache.catalina.Logger;
079: import org.apache.catalina.Realm;
080: import org.apache.catalina.Role;
081: import org.apache.catalina.Server;
082: import org.apache.catalina.ServerFactory;
083: import org.apache.catalina.User;
084: import org.apache.catalina.UserDatabase;
085: import org.apache.catalina.core.StandardServer;
086: import org.apache.catalina.util.LifecycleSupport;
087: import org.apache.catalina.util.StringManager;
088: import org.apache.commons.digester.Digester;
089:
090: /**
091: * <p>Implementation of {@link Realm} that is based on an implementation of
092: * {@link UserDatabase} made available through the global JNDI resources
093: * configured for this instance of Catalina. Set the <code>resourceName</code>
094: * parameter to the global JNDI resources name for the configured instance
095: * of <code>UserDatabase</code> that we should consult.</p>
096: *
097: * @author Craig R. McClanahan
098: * @version $Revision: 1.8 $ $Date: 2002/06/09 02:19:43 $
099: * @since 4.1
100: */
101:
102: public class UserDatabaseRealm extends RealmBase {
103:
104: // ----------------------------------------------------- Instance Variables
105:
106: /**
107: * The <code>UserDatabase</code> we will use to authenticate users
108: * and identify associated roles.
109: */
110: protected UserDatabase database = null;
111:
112: /**
113: * Descriptive information about this Realm implementation.
114: */
115: protected final String info = "org.apache.catalina.realm.UserDatabaseRealm/1.0";
116:
117: /**
118: * Descriptive information about this Realm implementation.
119: */
120: protected static final String name = "UserDatabaseRealm";
121:
122: /**
123: * The global JNDI name of the <code>UserDatabase</code> resource
124: * we will be utilizing.
125: */
126: protected String resourceName = "UserDatabase";
127:
128: /**
129: * The string manager for this package.
130: */
131: private static StringManager sm = StringManager
132: .getManager(Constants.Package);
133:
134: // ------------------------------------------------------------- Properties
135:
136: /**
137: * Return descriptive information about this Realm implementation and
138: * the corresponding version number, in the format
139: * <code><description>/<version></code>.
140: */
141: public String getInfo() {
142:
143: return info;
144:
145: }
146:
147: /**
148: * Return the global JNDI name of the <code>UserDatabase</code> resource
149: * we will be using.
150: */
151: public String getResourceName() {
152:
153: return resourceName;
154:
155: }
156:
157: /**
158: * Set the global JNDI name of the <code>UserDatabase</code> resource
159: * we will be using.
160: *
161: * @param resourceName The new global JNDI name
162: */
163: public void setResourceName(String resourceName) {
164:
165: this .resourceName = resourceName;
166:
167: }
168:
169: // --------------------------------------------------------- Public Methods
170:
171: /**
172: * Return the Principal associated with the specified username and
173: * credentials, if there is one; otherwise return <code>null</code>.
174: *
175: * @param username Username of the Principal to look up
176: * @param credentials Password or other credentials to use in
177: * authenticating this username
178: */
179: public Principal authenticate(String username, String credentials) {
180:
181: // Does a user with this username exist?
182: User user = database.findUser(username);
183: if (user == null) {
184: return (null);
185: }
186:
187: // Do the credentials specified by the user match?
188: // FIXME - Update all realms to support encoded passwords
189: boolean validated = false;
190: if (hasMessageDigest()) {
191: // Hex hashes should be compared case-insensitive
192: validated = (digest(credentials).equalsIgnoreCase(user
193: .getPassword()));
194: } else {
195: validated = (digest(credentials).equals(user.getPassword()));
196: }
197: if (!validated) {
198: if (debug >= 2) {
199: log(sm.getString(
200: "userDatabaseRealm.authenticateFailure",
201: username));
202: }
203: return (null);
204: }
205:
206: // Construct a GenericPrincipal that represents this user
207: if (debug >= 2) {
208: log(sm.getString("userDatabaseRealm.authenticateSuccess",
209: username));
210: }
211: ArrayList combined = new ArrayList();
212: Iterator roles = user.getRoles();
213: while (roles.hasNext()) {
214: Role role = (Role) roles.next();
215: String rolename = role.getRolename();
216: if (!combined.contains(rolename)) {
217: combined.add(rolename);
218: }
219: }
220: Iterator groups = user.getGroups();
221: while (groups.hasNext()) {
222: Group group = (Group) groups.next();
223: roles = group.getRoles();
224: while (roles.hasNext()) {
225: Role role = (Role) roles.next();
226: String rolename = role.getRolename();
227: if (!combined.contains(rolename)) {
228: combined.add(rolename);
229: }
230: }
231: }
232: return (new GenericPrincipal(this , user.getUsername(), user
233: .getPassword(), combined));
234:
235: }
236:
237: // ------------------------------------------------------ Protected Methods
238:
239: /**
240: * Return a short name for this Realm implementation.
241: */
242: protected String getName() {
243:
244: return (this .name);
245:
246: }
247:
248: /**
249: * Return the password associated with the given principal's user name.
250: */
251: protected String getPassword(String username) {
252:
253: return (null);
254:
255: }
256:
257: /**
258: * Return the Principal associated with the given user name.
259: */
260: protected Principal getPrincipal(String username) {
261:
262: return (null);
263:
264: }
265:
266: // ------------------------------------------------------ Lifecycle Methods
267:
268: /**
269: * Prepare for active use of the public methods of this Component.
270: *
271: * @exception LifecycleException if this component detects a fatal error
272: * that prevents it from being started
273: */
274: public synchronized void start() throws LifecycleException {
275:
276: try {
277: StandardServer server = (StandardServer) ServerFactory
278: .getServer();
279: Context context = server.getGlobalNamingContext();
280: database = (UserDatabase) context.lookup(resourceName);
281: } catch (Throwable e) {
282: e.printStackTrace();
283: log(sm.getString("userDatabaseRealm.lookup", resourceName),
284: e);
285: database = null;
286: }
287: if (database == null) {
288: throw new LifecycleException(sm.getString(
289: "userDatabaseRealm.noDatabase", resourceName));
290: }
291:
292: // Perform normal superclass initialization
293: super .start();
294:
295: }
296:
297: /**
298: * Gracefully shut down active use of the public methods of this Component.
299: *
300: * @exception LifecycleException if this component detects a fatal error
301: * that needs to be reported
302: */
303: public synchronized void stop() throws LifecycleException {
304:
305: // Perform normal superclass finalization
306: super .stop();
307:
308: // Release reference to our user database
309: database = null;
310:
311: }
312:
313: }
|