Source code: org/apache/catalina/realm/UserDatabaseRealm.java
1 /*
2 * Copyright 2002,2004 The Apache Software Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18 package org.apache.catalina.realm;
19
20
21 import java.security.Principal;
22 import java.util.ArrayList;
23 import java.util.Iterator;
24 import java.util.List;
25
26 import javax.naming.Context;
27
28 import org.apache.catalina.Group;
29 import org.apache.catalina.LifecycleException;
30 import org.apache.catalina.Role;
31 import org.apache.catalina.ServerFactory;
32 import org.apache.catalina.User;
33 import org.apache.catalina.UserDatabase;
34 import org.apache.catalina.core.StandardServer;
35 import org.apache.catalina.users.MemoryUser;
36 import org.apache.catalina.util.StringManager;
37
38
39 /**
40 * <p>Implementation of {@link org.apache.catalina.Realm} that is based on an implementation of
41 * {@link UserDatabase} made available through the global JNDI resources
42 * configured for this instance of Catalina. Set the <code>resourceName</code>
43 * parameter to the global JNDI resources name for the configured instance
44 * of <code>UserDatabase</code> that we should consult.</p>
45 *
46 * @author Craig R. McClanahan
47 * @version $Revision: 304062 $ $Date: 2005-08-18 00:41:02 -0400 (Thu, 18 Aug 2005) $
48 * @since 4.1
49 */
50
51 public class UserDatabaseRealm
52 extends RealmBase {
53
54
55 // ----------------------------------------------------- Instance Variables
56
57
58 /**
59 * The <code>UserDatabase</code> we will use to authenticate users
60 * and identify associated roles.
61 */
62 protected UserDatabase database = null;
63
64
65 /**
66 * Descriptive information about this Realm implementation.
67 */
68 protected final String info =
69 "org.apache.catalina.realm.UserDatabaseRealm/1.0";
70
71
72 /**
73 * Descriptive information about this Realm implementation.
74 */
75 protected static final String name = "UserDatabaseRealm";
76
77
78 /**
79 * The global JNDI name of the <code>UserDatabase</code> resource
80 * we will be utilizing.
81 */
82 protected String resourceName = "UserDatabase";
83
84
85 /**
86 * The string manager for this package.
87 */
88 private static StringManager sm =
89 StringManager.getManager(Constants.Package);
90
91
92 // ------------------------------------------------------------- Properties
93
94
95 /**
96 * Return descriptive information about this Realm implementation and
97 * the corresponding version number, in the format
98 * <code><description>/<version></code>.
99 */
100 public String getInfo() {
101
102 return info;
103
104 }
105
106
107 /**
108 * Return the global JNDI name of the <code>UserDatabase</code> resource
109 * we will be using.
110 */
111 public String getResourceName() {
112
113 return resourceName;
114
115 }
116
117
118 /**
119 * Set the global JNDI name of the <code>UserDatabase</code> resource
120 * we will be using.
121 *
122 * @param resourceName The new global JNDI name
123 */
124 public void setResourceName(String resourceName) {
125
126 this.resourceName = resourceName;
127
128 }
129
130
131 // --------------------------------------------------------- Public Methods
132
133
134 /**
135 * Return <code>true</code> if the specified Principal has the specified
136 * security role, within the context of this Realm; otherwise return
137 * <code>false</code>. This implementation returns <code>true</code>
138 * if the <code>User</code> has the role, or if any <code>Group</code>
139 * that the <code>User</code> is a member of has the role.
140 *
141 * @param principal Principal for whom the role is to be checked
142 * @param role Security role to be checked
143 */
144 public boolean hasRole(Principal principal, String role) {
145 if( principal instanceof GenericPrincipal) {
146 GenericPrincipal gp = (GenericPrincipal)principal;
147 if(gp.getUserPrincipal() instanceof User) {
148 principal = gp.getUserPrincipal();
149 }
150 }
151 if(! (principal instanceof User) ) {
152 //Play nice with SSO and mixed Realms
153 return super.hasRole(principal, role);
154 }
155 if("*".equals(role)) {
156 return true;
157 } else if(role == null) {
158 return false;
159 }
160 User user = (User)principal;
161 Role dbrole = database.findRole(role);
162 if(dbrole == null) {
163 return false;
164 }
165 if(user.isInRole(dbrole)) {
166 return true;
167 }
168 Iterator groups = user.getGroups();
169 while(groups.hasNext()) {
170 Group group = (Group)groups.next();
171 if(group.isInRole(dbrole)) {
172 return true;
173 }
174 }
175 return false;
176 }
177
178 // ------------------------------------------------------ Protected Methods
179
180
181 /**
182 * Return a short name for this Realm implementation.
183 */
184 protected String getName() {
185
186 return (name);
187
188 }
189
190
191 /**
192 * Return the password associated with the given principal's user name.
193 */
194 protected String getPassword(String username) {
195
196 User user = database.findUser(username);
197
198 if (user == null) {
199 return null;
200 }
201
202 return (user.getPassword());
203
204 }
205
206
207 /**
208 * Return the Principal associated with the given user name.
209 */
210 protected Principal getPrincipal(String username) {
211
212 User user = database.findUser(username);
213 if(user == null) {
214 return null;
215 }
216
217 List roles = new ArrayList();
218 Iterator uroles = user.getRoles();
219 while(uroles.hasNext()) {
220 Role role = (Role)uroles.next();
221 roles.add(role.getName());
222 }
223 Iterator groups = user.getGroups();
224 while(groups.hasNext()) {
225 Group group = (Group)groups.next();
226 uroles = user.getRoles();
227 while(uroles.hasNext()) {
228 Role role = (Role)uroles.next();
229 roles.add(role.getName());
230 }
231 }
232 return new GenericPrincipal(this, username, user.getPassword(), roles, user);
233 }
234
235
236 // ------------------------------------------------------ Lifecycle Methods
237
238
239 /**
240 * Prepare for active use of the public methods of this Component.
241 *
242 * @exception LifecycleException if this component detects a fatal error
243 * that prevents it from being started
244 */
245 public synchronized void start() throws LifecycleException {
246
247 try {
248 StandardServer server = (StandardServer) ServerFactory.getServer();
249 Context context = server.getGlobalNamingContext();
250 database = (UserDatabase) context.lookup(resourceName);
251 } catch (Throwable e) {
252 containerLog.error(sm.getString("userDatabaseRealm.lookup",
253 resourceName),
254 e);
255 database = null;
256 }
257 if (database == null) {
258 throw new LifecycleException
259 (sm.getString("userDatabaseRealm.noDatabase", resourceName));
260 }
261
262 // Perform normal superclass initialization
263 super.start();
264
265 }
266
267
268 /**
269 * Gracefully shut down active use of the public methods of this Component.
270 *
271 * @exception LifecycleException if this component detects a fatal error
272 * that needs to be reported
273 */
274 public synchronized void stop() throws LifecycleException {
275
276 // Perform normal superclass finalization
277 super.stop();
278
279 // Release reference to our user database
280 database = null;
281
282 }
283
284
285 }