Java tutorial
// ======================================================================== // $Id: HashUserRealm.java,v 1.29 2005/08/13 00:01:24 gregwilkins Exp $ // Copyright 1996-2004 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ======================================================================== package org.openqa.jetty.http; import java.io.Externalizable; import java.io.IOException; import java.io.PrintStream; import java.security.Principal; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.StringTokenizer; import org.apache.commons.logging.Log; import org.openqa.jetty.log.LogFactory; import org.openqa.jetty.util.Credential; import org.openqa.jetty.util.Password; import org.openqa.jetty.util.Resource; /* ------------------------------------------------------------ */ /** HashMapped User Realm. * * An implementation of UserRealm that stores users and roles in-memory in * HashMaps. * <P> * Typically these maps are populated by calling the load() method or passing * a properties resource to the constructor. The format of the properties * file is: <PRE> * username: password [,rolename ...] * </PRE> * Passwords may be clear text, obfuscated or checksummed. The class * com.mortbay.Util.Password should be used to generate obfuscated * passwords or password checksums. * * If DIGEST Authentication is used, the password must be in a recoverable * format, either plain text or OBF:. * * The HashUserRealm also implements SSORealm but provides no implementation * of SSORealm. Instead setSSORealm may be used to provide a delegate * SSORealm implementation. * * @see Password * @version $Id: HashUserRealm.java,v 1.29 2005/08/13 00:01:24 gregwilkins Exp $ * @author Greg Wilkins (gregw) */ public class HashUserRealm extends HashMap implements UserRealm, SSORealm, Externalizable { private static Log log = LogFactory.getLog(HashUserRealm.class); /** HttpContext Attribute to set to activate SSO. */ public static final String __SSO = "org.openqa.jetty.http.SSO"; /* ------------------------------------------------------------ */ private String _realmName; private String _config; protected HashMap _roles = new HashMap(7); private SSORealm _ssoRealm; /* ------------------------------------------------------------ */ /** Constructor. */ public HashUserRealm() { } /* ------------------------------------------------------------ */ /** Constructor. * @param name Realm Name */ public HashUserRealm(String name) { _realmName = name; } /* ------------------------------------------------------------ */ /** Constructor. * @param name Realm name * @param config Filename or url of user properties file. */ public HashUserRealm(String name, String config) throws IOException { _realmName = name; load(config); } /* ------------------------------------------------------------ */ public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException { out.writeObject(_realmName); out.writeObject(_config); } /* ------------------------------------------------------------ */ public void readExternal(java.io.ObjectInput in) throws java.io.IOException, ClassNotFoundException { _realmName = (String) in.readObject(); _config = (String) in.readObject(); if (_config != null) load(_config); } /* ------------------------------------------------------------ */ /** Load realm users from properties file. * The property file maps usernames to password specs followed by * an optional comma separated list of role names. * * @param config Filename or url of user properties file. * @exception IOException */ public void load(String config) throws IOException { _config = config; if (log.isDebugEnabled()) log.debug("Load " + this + " from " + config); Properties properties = new Properties(); Resource resource = Resource.newResource(config); properties.load(resource.getInputStream()); Iterator iter = properties.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); String username = entry.getKey().toString().trim(); String credentials = entry.getValue().toString().trim(); String roles = null; int c = credentials.indexOf(','); if (c > 0) { roles = credentials.substring(c + 1).trim(); credentials = credentials.substring(0, c).trim(); } if (username != null && username.length() > 0 && credentials != null && credentials.length() > 0) { put(username, credentials); if (roles != null && roles.length() > 0) { StringTokenizer tok = new StringTokenizer(roles, ", "); while (tok.hasMoreTokens()) addUserToRole(username, tok.nextToken()); } } } } /* ------------------------------------------------------------ */ /** * @param name The realm name */ public void setName(String name) { _realmName = name; } /* ------------------------------------------------------------ */ /** * @return The realm name. */ public String getName() { return _realmName; } /* ------------------------------------------------------------ */ public Principal getPrincipal(String username) { return (Principal) super.get(username); } /* ------------------------------------------------------------ */ public Principal authenticate(String username, Object credentials, HttpRequest request) { KnownUser user; synchronized (this) { user = (KnownUser) super.get(username); } if (user == null) return null; if (user.authenticate(credentials)) return user; return null; } /* ------------------------------------------------------------ */ public void disassociate(Principal user) { } /* ------------------------------------------------------------ */ public Principal pushRole(Principal user, String role) { if (user == null) user = new User(); return new WrappedUser(user, role); } /* ------------------------------------------------------------ */ public Principal popRole(Principal user) { WrappedUser wu = (WrappedUser) user; return wu.getUserPrincipal(); } /* ------------------------------------------------------------ */ /** Put user into realm. * @param name User name * @param credentials String password, Password or UserPrinciple * instance. * @return Old UserPrinciple value or null */ public synchronized Object put(Object name, Object credentials) { if (credentials instanceof Principal) return super.put(name.toString(), credentials); if (credentials instanceof Password) return super.put(name, new KnownUser(name.toString(), (Password) credentials)); if (credentials != null) return super.put(name, new KnownUser(name.toString(), Credential.getCredential(credentials.toString()))); return null; } /* ------------------------------------------------------------ */ /** Add a user to a role. * @param userName * @param roleName */ public synchronized void addUserToRole(String userName, String roleName) { HashSet userSet = (HashSet) _roles.get(roleName); if (userSet == null) { userSet = new HashSet(11); _roles.put(roleName, userSet); } userSet.add(userName); } /* -------------------------------------------------------- */ public boolean reauthenticate(Principal user) { return ((User) user).isAuthenticated(); } /* ------------------------------------------------------------ */ /** Check if a user is in a role. * @param user The user, which must be from this realm * @param roleName * @return True if the user can act in the role. */ public synchronized boolean isUserInRole(Principal user, String roleName) { if (user instanceof WrappedUser) return ((WrappedUser) user).isUserInRole(roleName); if (user == null || ((User) user).getUserRealm() != this) return false; HashSet userSet = (HashSet) _roles.get(roleName); return userSet != null && userSet.contains(user.getName()); } /* ------------------------------------------------------------ */ public void logout(Principal user) { } /* ------------------------------------------------------------ */ public String toString() { return "Realm[" + _realmName + "]"; } /* ------------------------------------------------------------ */ public void dump(PrintStream out) { out.println(this + ":"); out.println(super.toString()); out.println(_roles); } /* ------------------------------------------------------------ */ /** * @return The SSORealm to delegate single sign on requests to. */ public SSORealm getSSORealm() { return _ssoRealm; } /* ------------------------------------------------------------ */ /** Set the SSORealm. * A SSORealm implementation may be set to enable support for SSO. * @param ssoRealm The SSORealm to delegate single sign on requests to. */ public void setSSORealm(SSORealm ssoRealm) { _ssoRealm = ssoRealm; } /* ------------------------------------------------------------ */ public Credential getSingleSignOn(HttpRequest request, HttpResponse response) { if (_ssoRealm != null) return _ssoRealm.getSingleSignOn(request, response); return null; } /* ------------------------------------------------------------ */ public void setSingleSignOn(HttpRequest request, HttpResponse response, Principal principal, Credential credential) { if (_ssoRealm != null) _ssoRealm.setSingleSignOn(request, response, principal, credential); } /* ------------------------------------------------------------ */ public void clearSingleSignOn(String username) { if (_ssoRealm != null) _ssoRealm.clearSingleSignOn(username); } /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ private class User implements Principal { List roles = null; /* ------------------------------------------------------------ */ private UserRealm getUserRealm() { return HashUserRealm.this; } public String getName() { return "Anonymous"; } public boolean isAuthenticated() { return false; } public String toString() { return getName(); } } /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ private class KnownUser extends User { private String _userName; private Credential _cred; /* -------------------------------------------------------- */ KnownUser(String name, Credential credential) { _userName = name; _cred = credential; } /* -------------------------------------------------------- */ boolean authenticate(Object credentials) { return _cred != null && _cred.check(credentials); } /* ------------------------------------------------------------ */ public String getName() { return _userName; } /* -------------------------------------------------------- */ public boolean isAuthenticated() { return true; } } /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ private class WrappedUser extends User { private Principal user; private String role; WrappedUser(Principal user, String role) { this.user = user; this.role = role; } Principal getUserPrincipal() { return user; } public String getName() { return "role:" + role; } public boolean isAuthenticated() { return true; } public boolean isUserInRole(String role) { return this.role.equals(role); } } }