1 /* 2 * The Apache Software License, Version 1.1 3 * 4 * Copyright (c) 1999 The Apache Software Foundation. All rights 5 * reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 19 * 3. The end-user documentation included with the redistribution, if 20 * any, must include the following acknowlegement: 21 * "This product includes software developed by the 22 * Apache Software Foundation (http://www.apache.org/)." 23 * Alternately, this acknowlegement may appear in the software itself, 24 * if and wherever such third-party acknowlegements normally appear. 25 * 26 * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software 27 * Foundation" must not be used to endorse or promote products derived 28 * from this software without prior written permission. For written 29 * permission, please contact apache@apache.org. 30 * 31 * 5. Products derived from this software may not be called "Apache" 32 * nor may "Apache" appear in their names without prior written 33 * permission of the Apache Group. 34 * 35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 46 * SUCH DAMAGE. 47 * ==================================================================== 48 * 49 * This software consists of voluntary contributions made by many 50 * individuals on behalf of the Apache Software Foundation. For more 51 * information on the Apache Software Foundation, please see 52 * <http://www.apache.org/>. 53 * 54 * [Additional notices, if required by prior licensing conditions] 55 * 56 */ 57 58 59 package org.apache.tomcat.security.file; 60 61 62 import java.security.MessageDigest; 63 import java.security.NoSuchAlgorithmException; 64 import java.security.Principal; 65 import java.util.Enumeration; 66 import java.util.Hashtable; 67 68 69 /** 70 * In-memory representation of an individual user, to which specific roles 71 * may be assigned directly, or indirectly by virtue of membership in one 72 * or more groups. This class exhibits the following JavaBeans properties: 73 * <ul> 74 * <li><b>groups</b> - The set of groups this user is a member of. 75 * <li><b>name</b> - Username that uniquely (within a particular security 76 * domain) identifies this user. 77 * <li><b>password</b> - The password used to authenticate this user's 78 * identity. Internally, this value is stored in an encrypted fashion, 79 * and is not available in clear text. 80 * <li><b>roles</b> - The set of role names explicitly assigned to this user. 81 * </ul> 82 * 83 * @author Craig R. McClanahan 84 * @version $Revision: 1.2 $ $Date: 2000/02/26 02:32:15 $ 85 */ 86 87 final class FileRealmUser 88 implements Principal { 89 90 91 /** 92 * The database containing this user. 93 */ 94 private FileRealmDatabase database = null; 95 96 97 /** 98 * The set of groups this user is a member of, keyed by group name. 99 * Each element is an instance of FileRealmGroup. 100 */ 101 private Hashtable groups = new Hashtable(); 102 103 104 /** 105 * The username assigned to this user. 106 */ 107 private String name = null; 108 109 110 /** 111 * The (encrypted) password, stored as a byte array. 112 */ 113 private byte[] password = new byte[0]; 114 115 116 /** 117 * The set of roles assigned explicitly to this user, keyed by role name. 118 * The values are arbitrary. 119 */ 120 private Hashtable roles = new Hashtable(); 121 122 123 /** 124 * [Package Private] Create a new user with the specified username. 125 * It is assumed that the creating entity has ensured that this 126 * username is unique within this security realm. 127 * 128 * @param database FileRealmDatabase containing the new user 129 * @param name Username assigned to the new user 130 * @param password Cleartext password 131 */ 132 FileRealmUser(FileRealmDatabase database, String name, String password) { 133 134 super(); 135 this.database = database; 136 this.name = name; 137 setPassword(password); 138 database.addUser(this); 139 140 } 141 142 143 /** 144 * [Package Private] Create a new user with the specified username. 145 * It is assumed that the creating entity has ensured that this 146 * username is unique within this security realm. 147 * 148 * @param database FileRealmDatabase containing the new user 149 * @param name Username assigned to the new user 150 * @param password Encrypted password 151 */ 152 FileRealmUser(FileRealmDatabase database, String name, byte[] password) { 153 154 super(); 155 this.database = database; 156 this.name = name; 157 setPassword(password); 158 database.addUser(this); 159 160 } 161 162 163 /** 164 * Add this user as a member of the specified group. 165 * 166 * @param group Group this user is now a member of 167 */ 168 public void addGroup(FileRealmGroup group) { 169 170 group.addUser(this); 171 groups.put(group.getName(), group); 172 173 } 174 175 176 /** 177 * Add the explicit assignment of the specified role to this user. 178 * 179 * @param role The role being assigned to this group 180 */ 181 public void addRole(String role) { 182 183 database.addRole(role); 184 roles.put(role, role); 185 186 } 187 188 189 /** 190 * Can this user be authenticated with the specified password? 191 * 192 * @param password Password (cleartext) to be used for authentication 193 */ 194 public boolean authenticate(String password) { 195 196 return (MessageDigest.isEqual(this.password, encrypt(password))); 197 198 } 199 200 201 /** 202 * Remove this user from the database to which it belongs. 203 */ 204 public void destroy() { 205 206 database.remove(this); 207 208 } 209 210 211 /** 212 * [Private] Return the encrypted version of this cleartext password. 213 * 214 * @param password Cleartext password to be encrypted 215 */ 216 private byte[] encrypt(String password) { 217 218 if (password == null) 219 return (new byte[0]); 220 221 // Create a MessageDigest for use in performing the encryption 222 MessageDigest digest = null; 223 try { 224 digest = MessageDigest.getInstance("SHA"); 225 } catch (NoSuchAlgorithmException e) { 226 return (new byte[0]); 227 } 228 229 // Calculate the digest for the specified password 230 // XXX Obviously this does not deal with Unicode correctly 231 for (int i = 0; i < password.length(); i++) { 232 char ch = password.charAt(i); 233 digest.update((byte) (ch & 0x7f)); 234 } 235 return (digest.digest()); 236 237 } 238 239 240 /** 241 * Return an enumeration of the groups to which this user belongs. 242 * If this user is a member of no groups, an empty enumeration is 243 * returned. Each element in the enumeration is an instance of 244 * FileRealmGroup. 245 */ 246 public Enumeration getGroups() { 247 248 return (groups.elements()); 249 250 } 251 252 253 /** 254 * Return the username of this user. 255 */ 256 public String getName() { 257 258 return (name); 259 260 } 261 262 263 /** 264 * Return the encrypted version of the password. 265 */ 266 public byte[] getPassword() { 267 268 return (password); 269 270 } 271 272 273 /** 274 * Return an enumeration of the roles explicitly assigned to this user. 275 * If there are no assigned roles, an empty enumeration is returned. 276 */ 277 public Enumeration getRoles() { 278 279 return (roles.keys()); 280 281 } 282 283 284 /** 285 * Is this user a member of the specified group? 286 * 287 * @param group The group to be tested 288 */ 289 public boolean hasGroup(FileRealmGroup group) { 290 291 return (groups.get(group.getName()) != null); 292 293 } 294 295 296 /** 297 * Has this user been explicitly assigned the specified role? 298 * 299 * @param role The role to be tested 300 */ 301 public boolean hasRole(String role) { 302 303 return (roles.get(role) != null); 304 305 } 306 307 308 /** 309 * Remove this user from membership in the specified group. 310 * 311 * @param group Group from which to remove this user's membership. 312 */ 313 public void remove(FileRealmGroup group) { 314 315 groups.remove(group.getName()); 316 group.remove(this); 317 318 } 319 320 321 /** 322 * Remove the specified explicitly assigned role from this user. 323 * 324 * @param role Role to be removed 325 */ 326 public void remove(String role) { 327 328 roles.remove(role); 329 330 } 331 332 333 /** 334 * Set the password associated with this user. 335 * 336 * @param password Encrypted password to be stored 337 */ 338 public void setPassword(byte[] password) { 339 340 this.password = new byte[password.length]; 341 for (int i = 0; i < this.password.length; i++) 342 this.password[i] = password[i]; 343 344 } 345 346 347 /** 348 * Set the password associated with this user. This cleartext value 349 * will be immediately encrypted for storage. 350 * 351 * @param password Cleartext password to be stored 352 */ 353 public void setPassword(String password) { 354 355 this.password = encrypt(password); 356 357 } 358 359 360 }