001: /*
002: * Copyright 2002,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.catalina.realm;
018:
019: import java.security.Principal;
020: import java.util.ArrayList;
021: import java.util.Iterator;
022:
023: import javax.naming.Context;
024:
025: import org.apache.catalina.Group;
026: import org.apache.catalina.LifecycleException;
027: import org.apache.catalina.Role;
028: import org.apache.catalina.ServerFactory;
029: import org.apache.catalina.User;
030: import org.apache.catalina.UserDatabase;
031: import org.apache.catalina.core.StandardServer;
032: import org.apache.catalina.util.StringManager;
033:
034: /**
035: * <p>Implementation of {@link Realm} that is based on an implementation of
036: * {@link UserDatabase} made available through the global JNDI resources
037: * configured for this instance of Catalina. Set the <code>resourceName</code>
038: * parameter to the global JNDI resources name for the configured instance
039: * of <code>UserDatabase</code> that we should consult.</p>
040: *
041: * @author Craig R. McClanahan
042: * @version $Revision: 1.5 $ $Date: 2004/02/27 22:03:03 $
043: * @since 4.1
044: */
045:
046: public class UserDatabaseRealm extends RealmBase {
047:
048: // ----------------------------------------------------- Instance Variables
049:
050: /**
051: * The <code>UserDatabase</code> we will use to authenticate users
052: * and identify associated roles.
053: */
054: protected UserDatabase database = null;
055:
056: /**
057: * Descriptive information about this Realm implementation.
058: */
059: protected final String info = "org.apache.catalina.realm.UserDatabaseRealm/1.0";
060:
061: /**
062: * Descriptive information about this Realm implementation.
063: */
064: protected static final String name = "UserDatabaseRealm";
065:
066: /**
067: * The global JNDI name of the <code>UserDatabase</code> resource
068: * we will be utilizing.
069: */
070: protected String resourceName = "UserDatabase";
071:
072: /**
073: * The string manager for this package.
074: */
075: private static StringManager sm = StringManager
076: .getManager(Constants.Package);
077:
078: // ------------------------------------------------------------- Properties
079:
080: /**
081: * Return descriptive information about this Realm implementation and
082: * the corresponding version number, in the format
083: * <code><description>/<version></code>.
084: */
085: public String getInfo() {
086:
087: return info;
088:
089: }
090:
091: /**
092: * Return the global JNDI name of the <code>UserDatabase</code> resource
093: * we will be using.
094: */
095: public String getResourceName() {
096:
097: return resourceName;
098:
099: }
100:
101: /**
102: * Set the global JNDI name of the <code>UserDatabase</code> resource
103: * we will be using.
104: *
105: * @param resourceName The new global JNDI name
106: */
107: public void setResourceName(String resourceName) {
108:
109: this .resourceName = resourceName;
110:
111: }
112:
113: // --------------------------------------------------------- Public Methods
114:
115: /**
116: * Return the Principal associated with the specified username and
117: * credentials, if there is one; otherwise return <code>null</code>.
118: *
119: * @param username Username of the Principal to look up
120: * @param credentials Password or other credentials to use in
121: * authenticating this username
122: */
123: public Principal authenticate(String username, String credentials) {
124:
125: // Does a user with this username exist?
126: User user = database.findUser(username);
127: if (user == null) {
128: return (null);
129: }
130:
131: // Do the credentials specified by the user match?
132: // FIXME - Update all realms to support encoded passwords
133: boolean validated = false;
134: if (hasMessageDigest()) {
135: // Hex hashes should be compared case-insensitive
136: validated = (digest(credentials).equalsIgnoreCase(user
137: .getPassword()));
138: } else {
139: validated = (digest(credentials).equals(user.getPassword()));
140: }
141: if (!validated) {
142: if (debug >= 2) {
143: log(sm.getString(
144: "userDatabaseRealm.authenticateFailure",
145: username));
146: }
147: return (null);
148: }
149:
150: // Construct a GenericPrincipal that represents this user
151: if (debug >= 2) {
152: log(sm.getString("userDatabaseRealm.authenticateSuccess",
153: username));
154: }
155: ArrayList combined = new ArrayList();
156: Iterator roles = user.getRoles();
157: while (roles.hasNext()) {
158: Role role = (Role) roles.next();
159: String rolename = role.getRolename();
160: if (!combined.contains(rolename)) {
161: combined.add(rolename);
162: }
163: }
164: Iterator groups = user.getGroups();
165: while (groups.hasNext()) {
166: Group group = (Group) groups.next();
167: roles = group.getRoles();
168: while (roles.hasNext()) {
169: Role role = (Role) roles.next();
170: String rolename = role.getRolename();
171: if (!combined.contains(rolename)) {
172: combined.add(rolename);
173: }
174: }
175: }
176: return (new GenericPrincipal(this , user.getUsername(), user
177: .getPassword(), combined));
178:
179: }
180:
181: // ------------------------------------------------------ Protected Methods
182:
183: /**
184: * Return a short name for this Realm implementation.
185: */
186: protected String getName() {
187:
188: return (name);
189:
190: }
191:
192: /**
193: * Return the password associated with the given principal's user name.
194: */
195: protected String getPassword(String username) {
196:
197: User user = database.findUser(username);
198:
199: if (user == null) {
200: return null;
201: }
202:
203: return (user.getPassword());
204:
205: }
206:
207: /**
208: * Return the Principal associated with the given user name.
209: */
210: protected Principal getPrincipal(String username) {
211:
212: return (database.findUser(username));
213:
214: }
215:
216: // ------------------------------------------------------ Lifecycle Methods
217:
218: /**
219: * Prepare for active use of the public methods of this Component.
220: *
221: * @exception LifecycleException if this component detects a fatal error
222: * that prevents it from being started
223: */
224: public synchronized void start() throws LifecycleException {
225:
226: try {
227: StandardServer server = (StandardServer) ServerFactory
228: .getServer();
229: Context context = server.getGlobalNamingContext();
230: database = (UserDatabase) context.lookup(resourceName);
231: } catch (Throwable e) {
232: e.printStackTrace();
233: log(sm.getString("userDatabaseRealm.lookup", resourceName),
234: e);
235: database = null;
236: }
237: if (database == null) {
238: throw new LifecycleException(sm.getString(
239: "userDatabaseRealm.noDatabase", resourceName));
240: }
241:
242: // Perform normal superclass initialization
243: super .start();
244:
245: }
246:
247: /**
248: * Gracefully shut down active use of the public methods of this Component.
249: *
250: * @exception LifecycleException if this component detects a fatal error
251: * that needs to be reported
252: */
253: public synchronized void stop() throws LifecycleException {
254:
255: // Perform normal superclass finalization
256: super .stop();
257:
258: // Release reference to our user database
259: database = null;
260:
261: }
262:
263: }
|