001: // ========================================================================
002: // Copyright 1996-2005 Mort Bay Consulting Pty. Ltd.
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: // http://www.apache.org/licenses/LICENSE-2.0
008: // Unless required by applicable law or agreed to in writing, software
009: // distributed under the License is distributed on an "AS IS" BASIS,
010: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011: // See the License for the specific language governing permissions and
012: // limitations under the License.
013: // ========================================================================
014:
015: package org.mortbay.jetty.security;
016:
017: import java.io.IOException;
018: import java.io.PrintStream;
019: import java.security.Principal;
020: import java.util.HashMap;
021: import java.util.HashSet;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.Map;
025: import java.util.Properties;
026: import java.util.StringTokenizer;
027:
028: import org.mortbay.jetty.Request;
029: import org.mortbay.jetty.Response;
030: import org.mortbay.log.Log;
031: import org.mortbay.resource.Resource;
032:
033: /* ------------------------------------------------------------ */
034: /** HashMapped User Realm.
035: *
036: * An implementation of UserRealm that stores users and roles in-memory in
037: * HashMaps.
038: * <P>
039: * Typically these maps are populated by calling the load() method or passing
040: * a properties resource to the constructor. The format of the properties
041: * file is: <PRE>
042: * username: password [,rolename ...]
043: * </PRE>
044: * Passwords may be clear text, obfuscated or checksummed. The class
045: * com.mortbay.Util.Password should be used to generate obfuscated
046: * passwords or password checksums.
047: *
048: * If DIGEST Authentication is used, the password must be in a recoverable
049: * format, either plain text or OBF:.
050: *
051: * The HashUserRealm also implements SSORealm but provides no implementation
052: * of SSORealm. Instead setSSORealm may be used to provide a delegate
053: * SSORealm implementation.
054: *
055: * @see Password
056: * @author Greg Wilkins (gregw)
057: */
058: public class HashUserRealm implements UserRealm, SSORealm {
059:
060: /** HttpContext Attribute to set to activate SSO.
061: */
062: public static final String __SSO = "org.mortbay.http.SSO";
063:
064: /* ------------------------------------------------------------ */
065: private String _realmName;
066: private String _config;
067: protected HashMap _users = new HashMap();
068: protected HashMap _roles = new HashMap(7);
069: private SSORealm _ssoRealm;
070:
071: /* ------------------------------------------------------------ */
072: /** Constructor.
073: */
074: public HashUserRealm() {
075: }
076:
077: /* ------------------------------------------------------------ */
078: /** Constructor.
079: * @param name Realm Name
080: */
081: public HashUserRealm(String name) {
082: _realmName = name;
083: }
084:
085: /* ------------------------------------------------------------ */
086: /** Constructor.
087: * @param name Realm name
088: * @param config Filename or url of user properties file.
089: */
090: public HashUserRealm(String name, String config) throws IOException {
091: _realmName = name;
092: setConfig(config);
093: }
094:
095: public String getConfig() {
096: return _config;
097: }
098:
099: /* ------------------------------------------------------------ */
100: /** Load realm users from properties file.
101: * The property file maps usernames to password specs followed by
102: * an optional comma separated list of role names.
103: *
104: * @param config Filename or url of user properties file.
105: * @exception IOException
106: */
107: public void setConfig(String config) throws IOException {
108: _config = config;
109: _users.clear();
110: _roles.clear();
111:
112: if (Log.isDebugEnabled())
113: Log.debug("Load " + this + " from " + config);
114: Properties properties = new Properties();
115: Resource resource = Resource.newResource(config);
116: properties.load(resource.getInputStream());
117:
118: Iterator iter = properties.entrySet().iterator();
119: while (iter.hasNext()) {
120: Map.Entry entry = (Map.Entry) iter.next();
121:
122: String username = entry.getKey().toString().trim();
123: String credentials = entry.getValue().toString().trim();
124: String roles = null;
125: int c = credentials.indexOf(',');
126: if (c > 0) {
127: roles = credentials.substring(c + 1).trim();
128: credentials = credentials.substring(0, c).trim();
129: }
130:
131: if (username != null && username.length() > 0
132: && credentials != null && credentials.length() > 0) {
133: put(username, credentials);
134: if (roles != null && roles.length() > 0) {
135: StringTokenizer tok = new StringTokenizer(roles,
136: ", ");
137: while (tok.hasMoreTokens())
138: addUserToRole(username, tok.nextToken());
139: }
140: }
141: }
142: }
143:
144: /* ------------------------------------------------------------ */
145: /**
146: * @param name The realm name
147: */
148: public void setName(String name) {
149: _realmName = name;
150: }
151:
152: /* ------------------------------------------------------------ */
153: /**
154: * @return The realm name.
155: */
156: public String getName() {
157: return _realmName;
158: }
159:
160: /* ------------------------------------------------------------ */
161: public Principal getPrincipal(String username) {
162: return (Principal) _users.get(username);
163: }
164:
165: /* ------------------------------------------------------------ */
166: public Principal authenticate(String username, Object credentials,
167: Request request) {
168: KnownUser user;
169: synchronized (this ) {
170: user = (KnownUser) _users.get(username);
171: }
172: if (user == null)
173: return null;
174:
175: if (user.authenticate(credentials))
176: return user;
177:
178: return null;
179: }
180:
181: /* ------------------------------------------------------------ */
182: public void disassociate(Principal user) {
183: }
184:
185: /* ------------------------------------------------------------ */
186: public Principal pushRole(Principal user, String role) {
187: if (user == null)
188: user = new User();
189:
190: return new WrappedUser(user, role);
191: }
192:
193: /* ------------------------------------------------------------ */
194: public Principal popRole(Principal user) {
195: WrappedUser wu = (WrappedUser) user;
196: return wu.getUserPrincipal();
197: }
198:
199: /* ------------------------------------------------------------ */
200: /** Put user into realm.
201: * @param name User name
202: * @param credentials String password, Password or UserPrinciple
203: * instance.
204: * @return Old UserPrinciple value or null
205: */
206: public synchronized Object put(Object name, Object credentials) {
207: if (credentials instanceof Principal)
208: return _users.put(name.toString(), credentials);
209:
210: if (credentials instanceof Password)
211: return _users.put(name, new KnownUser(name.toString(),
212: (Password) credentials));
213: if (credentials != null)
214: return _users.put(name, new KnownUser(name.toString(),
215: Credential.getCredential(credentials.toString())));
216: return null;
217: }
218:
219: /* ------------------------------------------------------------ */
220: /** Add a user to a role.
221: * @param userName
222: * @param roleName
223: */
224: public synchronized void addUserToRole(String userName,
225: String roleName) {
226: HashSet userSet = (HashSet) _roles.get(roleName);
227: if (userSet == null) {
228: userSet = new HashSet(11);
229: _roles.put(roleName, userSet);
230: }
231: userSet.add(userName);
232: }
233:
234: /* -------------------------------------------------------- */
235: public boolean reauthenticate(Principal user) {
236: return ((User) user).isAuthenticated();
237: }
238:
239: /* ------------------------------------------------------------ */
240: /** Check if a user is in a role.
241: * @param user The user, which must be from this realm
242: * @param roleName
243: * @return True if the user can act in the role.
244: */
245: public synchronized boolean isUserInRole(Principal user,
246: String roleName) {
247: if (user instanceof WrappedUser)
248: return ((WrappedUser) user).isUserInRole(roleName);
249:
250: if (user == null || !(user instanceof User)
251: || ((User) user).getUserRealm() != this )
252: return false;
253:
254: HashSet userSet = (HashSet) _roles.get(roleName);
255: return userSet != null && userSet.contains(user.getName());
256: }
257:
258: /* ------------------------------------------------------------ */
259: public void logout(Principal user) {
260: }
261:
262: /* ------------------------------------------------------------ */
263: public String toString() {
264: return "Realm[" + _realmName + "]==" + _users.keySet();
265: }
266:
267: /* ------------------------------------------------------------ */
268: public void dump(PrintStream out) {
269: out.println(this + ":");
270: out.println(super .toString());
271: out.println(_roles);
272: }
273:
274: /* ------------------------------------------------------------ */
275: /**
276: * @return The SSORealm to delegate single sign on requests to.
277: */
278: public SSORealm getSSORealm() {
279: return _ssoRealm;
280: }
281:
282: /* ------------------------------------------------------------ */
283: /** Set the SSORealm.
284: * A SSORealm implementation may be set to enable support for SSO.
285: * @param ssoRealm The SSORealm to delegate single sign on requests to.
286: */
287: public void setSSORealm(SSORealm ssoRealm) {
288: _ssoRealm = ssoRealm;
289: }
290:
291: /* ------------------------------------------------------------ */
292: public Credential getSingleSignOn(Request request, Response response) {
293: if (_ssoRealm != null)
294: return _ssoRealm.getSingleSignOn(request, response);
295: return null;
296: }
297:
298: /* ------------------------------------------------------------ */
299: public void setSingleSignOn(Request request, Response response,
300: Principal principal, Credential credential) {
301: if (_ssoRealm != null)
302: _ssoRealm.setSingleSignOn(request, response, principal,
303: credential);
304: }
305:
306: /* ------------------------------------------------------------ */
307: public void clearSingleSignOn(String username) {
308: if (_ssoRealm != null)
309: _ssoRealm.clearSingleSignOn(username);
310: }
311:
312: /* ------------------------------------------------------------ */
313: /* ------------------------------------------------------------ */
314: /* ------------------------------------------------------------ */
315: private class User implements Principal {
316: List roles = null;
317:
318: /* ------------------------------------------------------------ */
319: private UserRealm getUserRealm() {
320: return HashUserRealm.this ;
321: }
322:
323: public String getName() {
324: return "Anonymous";
325: }
326:
327: public boolean isAuthenticated() {
328: return false;
329: }
330:
331: public String toString() {
332: return getName();
333: }
334: }
335:
336: /* ------------------------------------------------------------ */
337: /* ------------------------------------------------------------ */
338: /* ------------------------------------------------------------ */
339: private class KnownUser extends User {
340: private String _userName;
341: private Credential _cred;
342:
343: /* -------------------------------------------------------- */
344: KnownUser(String name, Credential credential) {
345: _userName = name;
346: _cred = credential;
347: }
348:
349: /* -------------------------------------------------------- */
350: boolean authenticate(Object credentials) {
351: return _cred != null && _cred.check(credentials);
352: }
353:
354: /* ------------------------------------------------------------ */
355: public String getName() {
356: return _userName;
357: }
358:
359: /* -------------------------------------------------------- */
360: public boolean isAuthenticated() {
361: return true;
362: }
363: }
364:
365: /* ------------------------------------------------------------ */
366: /* ------------------------------------------------------------ */
367: /* ------------------------------------------------------------ */
368: private class WrappedUser extends User {
369: private Principal user;
370: private String role;
371:
372: WrappedUser(Principal user, String role) {
373: this .user = user;
374: this .role = role;
375: }
376:
377: Principal getUserPrincipal() {
378: return user;
379: }
380:
381: public String getName() {
382: return "role:" + role;
383: }
384:
385: public boolean isAuthenticated() {
386: return true;
387: }
388:
389: public boolean isUserInRole(String role) {
390: return this.role.equals(role);
391: }
392: }
393: }
|