0001: /* ====================================================================
0002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
0003: *
0004: * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
0005: *
0006: * Redistribution and use in source and binary forms, with or without
0007: * modification, are permitted provided that the following conditions
0008: * are met:
0009: *
0010: * 1. Redistributions of source code must retain the above copyright
0011: * notice, this list of conditions and the following disclaimer.
0012: *
0013: * 2. Redistributions in binary form must reproduce the above copyright
0014: * notice, this list of conditions and the following disclaimer in
0015: * the documentation and/or other materials provided with the
0016: * distribution.
0017: *
0018: * 3. The end-user documentation included with the redistribution,
0019: * if any, must include the following acknowledgment:
0020: * "This product includes software developed by Jcorporate Ltd.
0021: * (http://www.jcorporate.com/)."
0022: * Alternately, this acknowledgment may appear in the software itself,
0023: * if and wherever such third-party acknowledgments normally appear.
0024: *
0025: * 4. "Jcorporate" and product names such as "Expresso" must
0026: * not be used to endorse or promote products derived from this
0027: * software without prior written permission. For written permission,
0028: * please contact info@jcorporate.com.
0029: *
0030: * 5. Products derived from this software may not be called "Expresso",
0031: * or other Jcorporate product names; nor may "Expresso" or other
0032: * Jcorporate product names appear in their name, without prior
0033: * written permission of Jcorporate Ltd.
0034: *
0035: * 6. No product derived from this software may compete in the same
0036: * market space, i.e. framework, without prior written permission
0037: * of Jcorporate Ltd. For written permission, please contact
0038: * partners@jcorporate.com.
0039: *
0040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
0044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
0046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0051: * SUCH DAMAGE.
0052: * ====================================================================
0053: *
0054: * This software consists of voluntary contributions made by many
0055: * individuals on behalf of the Jcorporate Ltd. Contributions back
0056: * to the project(s) are encouraged when you make modifications.
0057: * Please send them to support@jcorporate.com. For more information
0058: * on Jcorporate Ltd. and its products, please see
0059: * <http://www.jcorporate.com/>.
0060: *
0061: * Portions of this software are based upon other open source
0062: * products and are subject to their respective licenses.
0063: */
0064:
0065: package com.jcorporate.expresso.services.dbobj;
0066:
0067: import com.jcorporate.expresso.core.cache.Cache;
0068: import com.jcorporate.expresso.core.cache.CacheException;
0069: import com.jcorporate.expresso.core.cache.CacheManager;
0070: import com.jcorporate.expresso.core.cache.CacheSystem;
0071: import com.jcorporate.expresso.core.cache.CachedObject;
0072: import com.jcorporate.expresso.core.controller.ControllerRequest;
0073: import com.jcorporate.expresso.core.db.DBConnection;
0074: import com.jcorporate.expresso.core.db.DBException;
0075: import com.jcorporate.expresso.core.dbobj.DBField;
0076: import com.jcorporate.expresso.core.dbobj.SecuredDBObject;
0077: import com.jcorporate.expresso.core.dbobj.ValidValue;
0078: import com.jcorporate.expresso.core.logging.LogException;
0079: import com.jcorporate.expresso.core.misc.Base64;
0080: import com.jcorporate.expresso.core.misc.ConfigManager;
0081: import com.jcorporate.expresso.core.misc.ConfigurationException;
0082: import com.jcorporate.expresso.core.misc.DateTime;
0083: import com.jcorporate.expresso.core.misc.EMailSender;
0084: import com.jcorporate.expresso.core.misc.EventHandler;
0085: import com.jcorporate.expresso.core.misc.StringUtil;
0086: import com.jcorporate.expresso.core.security.CryptoManager;
0087: import com.jcorporate.expresso.core.security.User;
0088: import com.jcorporate.expresso.core.security.UserInfo;
0089: import com.jcorporate.expresso.kernel.exception.ChainedException;
0090: import com.jcorporate.expresso.kernel.util.FastStringBuffer;
0091: import org.apache.log4j.Logger;
0092:
0093: import java.util.Date;
0094: import java.util.Enumeration;
0095: import java.util.Hashtable;
0096: import java.util.Iterator;
0097: import java.util.Vector;
0098:
0099: /**
0100: * Default implementation of the UserInfo object. This is the class that comes
0101: * for managing users and security with Expresso.
0102: *
0103: * @author Michael Nash, adapted Larry Hamel, CodeGuild
0104: */
0105: public class DefaultUserInfo extends SecurityDBObject implements
0106: UserInfo {
0107:
0108: /**
0109: * Debugging information value
0110: */
0111: public static final String THIS_CLASS = DefaultUserInfo.class
0112: .getName();
0113:
0114: /**
0115: *
0116: */
0117: public static final String NAME_2_ID_CACHE_NAME = THIS_CLASS
0118: + ".nameToId";
0119:
0120: /**
0121: * Field name for the user id
0122: */
0123: public static final String EXPUID = "ExpUid";
0124:
0125: /**
0126: * Field name for the login name
0127: */
0128: public static final String LOGIN = "LoginName";
0129:
0130: /**
0131: * Field name for the password
0132: */
0133: public static final String PASSWORD = "Passwd";
0134:
0135: /**
0136: * Field name for user's email
0137: */
0138: public static final String EMAIL_ADDRESS = "EMail";
0139:
0140: /**
0141: * Field name for the registration domain id.
0142: */
0143: public static final String REGISTRATION_DOMAIN = "RegDomId";
0144:
0145: /**
0146: * Field name for account status
0147: */
0148: public static final String ACCOUNT_STATUS = "AccountStatus";
0149:
0150: /**
0151: * Field name for registration complete flag
0152: */
0153: public static final String IS_REG_COMPLETE = "RegComplete";
0154:
0155: /**
0156: * Field name for created date
0157: */
0158: public static final String CREATED_DATE = "CreateDate";
0159:
0160: /**
0161: * Field name for updated date
0162: */
0163: public static final String UPDATED_DATE = "UpdateDate";
0164:
0165: /**
0166: * Field name for validation code
0167: */
0168: public static final String VALIDATION_CODE = "EmailValCode";
0169:
0170: /**
0171: * Field name for full name.
0172: */
0173: public static final String FULL_NAME = "UserName";
0174:
0175: /**
0176: * Full name field length
0177: */
0178: public static final int FULL_NAME_LENGTH = 80;
0179:
0180: /**
0181: * Email address length
0182: */
0183: public static final int EMAIL_ADDRESS_LENGTH = 80;
0184:
0185: /**
0186: * Login name length
0187: */
0188: public static final int LOGIN_LENGTH = 30;
0189:
0190: /**
0191: * Password name length
0192: */
0193: public static final int PASSWORD_LENGTH = 30;
0194:
0195: /**
0196: * Validation code length
0197: */
0198: public static final int VALIDATION_CODE_LENGTH = 30;
0199:
0200: /**
0201: * The log4j Logger
0202: */
0203: private static Logger log = Logger.getLogger(DefaultUserInfo.class);
0204:
0205: /**
0206: * constants used to indicate one of two cases: whether checking for unique email/login name during add() or update()
0207: */
0208: private static final boolean IS_UPDATE = true;
0209: private static final boolean IS_ADD = false;
0210:
0211: /**
0212: * Sets the uid of the userinfo object
0213: *
0214: * @param uid the user id to set
0215: * @throws DBException upon error
0216: */
0217: public void setUid(String uid) throws DBException {
0218: StringUtil.assertNotBlank(uid, "Can't set a blank UID");
0219: setField(EXPUID, uid);
0220: } /* setUid(String) */
0221:
0222: /**
0223: * Sets the uid of the userinfo object
0224: *
0225: * @param uid the user id to set
0226: * @throws DBException upon error
0227: */
0228: public void setUid(int uid) throws DBException {
0229: setField(EXPUID, uid);
0230: }
0231:
0232: /**
0233: * Default constructor
0234: */
0235: public DefaultUserInfo() throws DBException {
0236: } /* DefaultUserInfo() */
0237:
0238: /**
0239: * Constructor with UID
0240: *
0241: * @param uid The User ID of the owner object
0242: * @throws DBException upon error
0243: */
0244: public DefaultUserInfo(int uid) throws DBException {
0245: super (uid);
0246: }
0247:
0248: /**
0249: * constructor for db transactions
0250: *
0251: * @param localConnection the DB connection which should be used, typically because of an ongoing transaction
0252: */
0253: public DefaultUserInfo(DBConnection localConnection)
0254: throws DBException {
0255: if (localConnection != null) {
0256: setConnection(localConnection);
0257: }
0258: }
0259:
0260: /**
0261: * For using DBObjects within Controllers. Initializes based upon the current
0262: * user and the requested db. [Of course this can be modified later]
0263: *
0264: * @param request - The controller request handed to you by the framework.
0265: */
0266: public DefaultUserInfo(ControllerRequest request)
0267: throws DBException {
0268: super (request);
0269: }
0270:
0271: /**
0272: * Override of add to check for duplicate emails.
0273: *
0274: * @throws DBException upon error
0275: */
0276: public void add() throws DBException {
0277:
0278: checkEmailAddrAlreadyUsed(IS_ADD);
0279:
0280: // At initial login, UserName == LoginName, Registation controllers can later modify this
0281: if (getField(FULL_NAME).equals("")) {
0282: setField(FULL_NAME, getField(LOGIN));
0283: }
0284: // If a User is added without a status, we set the AccountStatus to "I"
0285: // for security reasons
0286: if (getField(ACCOUNT_STATUS).equals("")) {
0287: setField(ACCOUNT_STATUS, "I");
0288: }
0289: // Set the registration domain id
0290: if (getRegistrationDomain().equals("")) {
0291: setRegistrationDomain("default");
0292: }
0293:
0294: RegistrationDomain rd = new RegistrationDomain();
0295: rd.setDataContext(getDataContext());
0296: rd.setField("Name", getRegistrationDomain());
0297:
0298: if (!rd.find()) {
0299: throw new DBException("Registration domain \""
0300: + getRegistrationDomain()
0301: + "\" has not been defined");
0302: }
0303:
0304: setField(REGISTRATION_DOMAIN, rd.getField(REGISTRATION_DOMAIN));
0305:
0306: // Check value of registration valid flag
0307: if (getField(IS_REG_COMPLETE).equals("")) {
0308: setField(IS_REG_COMPLETE, "N");
0309: }
0310: // We should always have a CreateDate
0311: if (getField(CREATED_DATE).equals("")) {
0312: setField(CREATED_DATE, DateTime.getDateTimeForDB(this
0313: .getDataContext()));
0314: }
0315: // We should always have a UpdateDate
0316: if (getField(UPDATED_DATE).equals("")) {
0317: setField(UPDATED_DATE, getField(CREATED_DATE));
0318: }
0319:
0320: super .add();
0321:
0322: User user = new User();
0323: user.setDataContext(this .getDataContext());
0324: user.addNotify(this );
0325:
0326: } /* add() */
0327:
0328: /**
0329: * Extends the checkAllRefs method to check for valid Registration Domain Id
0330: *
0331: * @throws DBException If a referential integrity violation is found
0332: */
0333: protected void checkAllRefs() throws DBException {
0334: checkRef(REGISTRATION_DOMAIN, new RegistrationDomain(),
0335: "Invalid "
0336: + getString(getMetaData().getDescription(
0337: REGISTRATION_DOMAIN)));
0338: } /* checkAllRefs() */
0339:
0340: /**
0341: * Override of deleteMethod() to notify UserListeners of deltion
0342: *
0343: * @throws DBException upon error
0344: */
0345: public void delete() throws DBException {
0346:
0347: // Nobody sets the key field UID...so we cheat here.
0348: // Find the field first so the keyfield is set and then do a delete
0349: find();
0350: User user = new User();
0351: user.setDataContext(this .getDataContext());
0352: user.deleteNotify(this ); //We cannot delete until all listeners have
0353: //agreed that this is workable.
0354: super .delete();
0355:
0356: } /* delete() */
0357:
0358: /**
0359: * Retrieve the account status of the user
0360: *
0361: * @return java.lang.String : one of the account status codes
0362: * @throws DBException upon error
0363: */
0364: public String getAccountStatus() throws DBException {
0365: return getField(ACCOUNT_STATUS);
0366: } /* getAccountStatus() */
0367:
0368: /**
0369: * Retrieve a list of all users... may get REALLY intensive!
0370: *
0371: * @return Vector of UserInfo objects
0372: * @throws DBException upon database error
0373: */
0374: public Vector getAllUsers() throws DBException {
0375: return new Vector(searchAndRetrieveList(LOGIN));
0376: } /* getAllUsers() */
0377:
0378: /**
0379: * Get the account creation date
0380: *
0381: * @return java.lang.String as a date formatted string
0382: * @throws DBException upon error
0383: */
0384: public String getCreateDate() throws DBException {
0385: return getField(CREATED_DATE);
0386: } /* getCreateDate() */
0387:
0388: /**
0389: * Retrieve the email address of the account
0390: *
0391: * @return java.lang.String
0392: * @throws DBException upon error
0393: */
0394: public String getEmail() throws DBException {
0395: return getField(EMAIL_ADDRESS);
0396: } /* getEmail() */
0397:
0398: /**
0399: * Create an email authorization code. Used anymore??
0400: *
0401: * @return java.lang.String
0402: * @throws DBException upon error
0403: */
0404: public String getEmailAuthCode() throws DBException {
0405: Date createDate = getFieldDate(CREATED_DATE);
0406: long dateLong = createDate.getTime();
0407: long emailAuthCode = Math.round(dateLong * 1.71);
0408:
0409: return Long.toString(emailAuthCode);
0410: } /* getEmailAuthCode() */
0411:
0412: /**
0413: * Retrieve the email validation code
0414: *
0415: * @return java.lang.String
0416: */
0417: public String getEmailValCode() throws DBException {
0418: return getField(VALIDATION_CODE);
0419: } /* getEmailValCode() */
0420:
0421: /**
0422: * Get the groups that below to this user
0423: *
0424: * @return Vector of strings
0425: * @throws DBException upon database access error
0426: */
0427: public Vector getGroups() throws DBException {
0428:
0429: //
0430: //Attempt Cache retrieval first.
0431: //
0432: CacheSystem cs = CacheManager.getCacheSystem(this
0433: .getDataContext());
0434: String cacheName = THIS_CLASS + ".groups";
0435: String key = Integer.toString(this .getUid());
0436: Cache cache = cs.getCache(cacheName);
0437: if (cache == null) {
0438: try {
0439: cache = cs.createCache(cacheName, false, 200);
0440: cs
0441: .addListener(
0442: cacheName,
0443: com.jcorporate.expresso.services.dbobj.GroupMembers.class
0444: .getName());
0445: } catch (CacheException ex) {
0446: log.error("Error creating cache: " + cacheName);
0447: }
0448: }
0449:
0450: if (cache != null) {
0451: CachedObject c = (CachedObject) cache.getItem(key);
0452: if (c != null) {
0453: return (Vector) c.getValue();
0454: }
0455: }
0456:
0457: Vector myGroups = new Vector(3);
0458:
0459: GroupMembers memberList = new GroupMembers();
0460: memberList.setDataContext(getDataContext());
0461: memberList.setField(GroupMembers.EXPUID, getUid());
0462:
0463: if (log.isDebugEnabled()) {
0464: log.debug("Getting groups for uid " + getUid()
0465: + ", login name " + getLoginName());
0466: }
0467: for (Iterator e = memberList.searchAndRetrieveList().iterator(); e
0468: .hasNext();) {
0469: GroupMembers oneMember = null;
0470: oneMember = (GroupMembers) e.next();
0471: myGroups.addElement(oneMember.getField("GroupName"));
0472:
0473: if (log.isDebugEnabled()) {
0474: log.debug("" + getUid() + " is a Member of group "
0475: + oneMember.getField("GroupName"));
0476: }
0477: }
0478:
0479: /**
0480: * back in the bad old days, we manually added the UserGroup.UNKNOWN_USERS_GROUP so that
0481: * it appeared as though everyone was a member of this group. If your app depends on this old
0482: * behavior, set the following Setup value to true.
0483: String isAddUnknownUsersGroup = Setup.getValueUnrequired(getDataContext(), "AddUnknownUserGroup");
0484: if ( StringUtil.toBoolean(isAddUnknownUsersGroup) )
0485: myGroups.addElement(UserGroup.UNKNOWN_USERS_GROUP);
0486: */
0487:
0488: myGroups.addElement(UserGroup.UNKNOWN_USERS_GROUP);
0489:
0490: if (log.isDebugEnabled()) {
0491: log.debug("" + getUid() + " is a member of "
0492: + myGroups.size() + " groups");
0493: }
0494:
0495: if (cache != null) {
0496: CachedObject co = new CachedObject(key, myGroups);
0497: try {
0498: cs.addItem(cacheName, co, 1000 * 60 * 10); //10 minute cache;
0499: } catch (CacheException ex) {
0500: log.error("Error adding group list to cache", ex);
0501: }
0502: }
0503:
0504: return myGroups;
0505: } /* getGroups() */
0506:
0507: /**
0508: * get name used for login query that is accompanied by password
0509: */
0510: public String getLoginName() throws DBException {
0511: return getField(LOGIN);
0512: } /* getLoginName() */
0513:
0514: public String getPassword() throws DBException {
0515: return getField(PASSWORD);
0516: } /* getPassword() */
0517:
0518: public boolean getRegComplete() throws DBException {
0519: String statusString = getField(IS_REG_COMPLETE);
0520: boolean status = false;
0521:
0522: if (statusString.equals("Y")) {
0523: status = true;
0524: }
0525:
0526: return status;
0527: } /* getRegComplete() */
0528:
0529: public String getRegistrationDomain() throws DBException {
0530: String domain = "default";
0531: RegistrationDomain rd = new RegistrationDomain();
0532: rd.setDataContext(getDataContext());
0533: rd.setField(REGISTRATION_DOMAIN, getField(REGISTRATION_DOMAIN));
0534:
0535: if (rd.find()) {
0536: domain = rd.getField("Name");
0537: }
0538:
0539: return domain;
0540: } /* getRegistrationDomain() */
0541:
0542: public int getUid() throws DBException {
0543: return getFieldInt(EXPUID);
0544: } /* getUid() */
0545:
0546: public String getUpdateDate() throws DBException {
0547: return getField(UPDATED_DATE);
0548: } /* getUpdateDate() */
0549:
0550: /**
0551: * get descriptive, full name
0552: *
0553: * @deprecated Since Expresso 5.5; use getFullName()
0554: * instead to avoid confusion with login name
0555: */
0556: public String getUserName() throws DBException {
0557: return getField(FULL_NAME);
0558: } /* getUserName() */
0559:
0560: /**
0561: * get descriptive, full name (first + last names) of person
0562: */
0563: public String getFullName() throws DBException {
0564: return getField(FULL_NAME);
0565: } /* getUserName() */
0566:
0567: /**
0568: * Get the valid values for various fields on this data object
0569: *
0570: * @param fieldName The fieldname to retrieve the valid values for.
0571: * @return a java.util.Vector of ValidValue objects
0572: * @throws com.jcorporate.expresso.core.db.DBException
0573: * The exception description.
0574: */
0575: public synchronized Vector getValidValues(String fieldName)
0576: throws DBException {
0577: if (ACCOUNT_STATUS.equals(fieldName)) {
0578: Vector values = new Vector();
0579: values.addElement(new ValidValue("A", "Active"));
0580: values.addElement(new ValidValue("I",
0581: "Inactive Until Email Confirmation"));
0582: values.addElement(new ValidValue("D", "Disabled"));
0583: values.addElement(new ValidValue("W",
0584: "Waiting For Approval"));
0585: values.addElement(new ValidValue("X",
0586: "Registration Denied By Administrator"));
0587:
0588: return values;
0589: } else if (fieldName.equals(IS_REG_COMPLETE)) {
0590: Vector rv = new Vector(2);
0591: ValidValue rvv = new ValidValue("Y", "Complete");
0592: rv.addElement(rvv);
0593: rvv = new ValidValue("N", "Incomplete");
0594: rv.addElement(rvv);
0595:
0596: return rv;
0597: }
0598:
0599: // default for all other fields
0600: return super .getValidValues(fieldName);
0601: } /* getValidValues(String) */
0602:
0603: public Vector getValues() throws DBException {
0604: // FIXME: change the next line!
0605: return getValuesDefault(EXPUID, LOGIN);
0606: } /* getValues() */
0607:
0608: /**
0609: * hashEncodePassword: If passed a plaintext string > 0 bytes, then this
0610: * function will SHA1 hash the password, then Base64 encode it and return it
0611: * as a string.
0612: * <p/>
0613: * If the password is zero length, then it will simply return a zero length
0614: * string also.
0615: *
0616: * @param plaintext - the password to process in this manner: <br>
0617: * returnValue = Base64(SHA-1(plaintext))
0618: * @return a String representing a Base64 encoded Hashed Password
0619: */
0620: public String hashEncodePassword(String plaintext)
0621: throws DBException {
0622: if (plaintext == null) {
0623: throw new DBException("Password Must not be NULL");
0624: }
0625: if (plaintext.length() == 0) {
0626: return plaintext;
0627: }
0628: try {
0629: return Base64.encode(CryptoManager.getInstance()
0630: .getStringHash().produceHash(plaintext.getBytes()));
0631: } catch (Exception ex) {
0632: throw new DBException("Error hashing Password:"
0633: + " You may not have installed the"
0634: + " Cryptography Extensions Properly:", ex);
0635: }
0636: } /* hashEncodePassword(String) */
0637:
0638: /**
0639: * Send this user a notification via e-mail.
0640: *
0641: * @param subject Subject of the e-mail
0642: * @param message Message to send in body of e-mail
0643: * @throws DBException If the mail message cannot be sent
0644: */
0645: public void notify(String subject, String message)
0646: throws DBException, LogException {
0647: log.info("Notifying user " + getField(EXPUID) + " of "
0648: + subject);
0649:
0650: String sendToUser = getField(EMAIL_ADDRESS);
0651:
0652: try {
0653: EMailSender ems = new EMailSender();
0654: ems.setDBName(getDataContext());
0655: ems.send(sendToUser, subject, message);
0656: } catch (Exception e) {
0657: throw new DBException("Uncaught exception sending e-mail",
0658: e);
0659: }
0660: } /* notify(String, String) */
0661:
0662: /**
0663: * Check if the given number is in the range of letters and
0664: * digits that we want to use for generating a password
0665: * Previously in com.jcorporate.expresso.ext.servlet.RegisterUser.java
0666: *
0667: * @param x The byte to check
0668: * @return true if it is a printable form
0669: */
0670: private boolean okNumber(byte x) {
0671: if ((x >= 65) && (x <= 90)) {
0672: return true;
0673: }
0674: if ((x >= 48) && (x <= 57)) {
0675: return true;
0676: }
0677: if ((x >= 97) && (x <= 122)) {
0678: return true;
0679: }
0680:
0681: return false;
0682: } /* okNumber(byte) */
0683:
0684: /**
0685: * passwordEquals - feed it a password and it will tell you if the hash of it
0686: * matches the one on file.
0687: * <p/>
0688: * Also, for backwards compatability and some other issues, this function
0689: * will also accept a plaintext version of the password if it is sitting in
0690: * the database. However, if a plaintext match is encountered, then it will
0691: * hash the password and re-write itself to the database record.
0692: *
0693: * @param tryPassword The value the user input for an attempted login.
0694: * @return true if the password equals
0695: */
0696: public boolean passwordEquals(String tryPassword)
0697: throws DBException {
0698: if (tryPassword == null) {
0699: throw new DBException("tryPassword Must not be NULL");
0700: }
0701:
0702: String fieldData = getPassword();
0703: String trieduser = getLoginName();
0704:
0705: if (log.isDebugEnabled()) {
0706: log.debug("Trying user " + trieduser + ", password '"
0707: + tryPassword + "' - field data is '" + fieldData
0708: + "'");
0709: }
0710:
0711: String triedhash = hashEncodePassword(tryPassword);
0712:
0713: if (log.isDebugEnabled()) {
0714: log.debug("Password hashed is " + triedhash + "'");
0715: }
0716: if (triedhash.equals(fieldData)) {
0717: return true;
0718: } else {
0719: if (log.isDebugEnabled()) {
0720: log.debug("Hash doesn't equal data - trying plaintext");
0721: }
0722: //The second compare check is to make sure somebody isn't just
0723: //replaying a snooped password and attempting to use it against
0724: //us. If Password.length() == 28 then it's a hash.
0725: if (tryPassword.equals(fieldData)
0726: && fieldData.length() < 20) {
0727: if (log.isDebugEnabled()) {
0728: log
0729: .debug("Password matches in plain text - hashing & writing to DB");
0730: }
0731:
0732: setPassword(hashEncodePassword(fieldData));
0733: update();
0734:
0735: return true;
0736: } else {
0737:
0738: //No Match
0739: if (log.isDebugEnabled()) {
0740: log
0741: .debug("Password doesn't equal plain text either ('"
0742: + tryPassword
0743: + "' <> '"
0744: + fieldData
0745: + "') or field data is over 20 characters");
0746: }
0747:
0748: return false;
0749: }
0750: }
0751: } /* passwordEquals(String) */
0752:
0753: /**
0754: * Called by the various objects that can log in a user
0755: * to do post-login tasks
0756: */
0757: public void postLogin() throws DBException, LogException {
0758: UserGroup oneGroup = new UserGroup(
0759: SecuredDBObject.SYSTEM_ACCOUNT);
0760: oneGroup.setDataContext(getDataContext());
0761:
0762: String theEvent = null;
0763: Hashtable allEvents = new Hashtable(1);
0764: String oneGroupName = null;
0765:
0766: for (Enumeration gl = getGroups().elements(); gl
0767: .hasMoreElements();) {
0768: oneGroupName = (String) gl.nextElement();
0769: oneGroup.clear();
0770: oneGroup.setField("GroupName", oneGroupName);
0771:
0772: if (oneGroup.find()) {
0773: theEvent = oneGroup.getField("LoginEvent");
0774:
0775: if (!theEvent.equals("")) {
0776: allEvents.put(theEvent, oneGroup
0777: .getField("GroupName"));
0778: }
0779: } /* if the group exists */
0780:
0781: } /* for each group user is a member of */
0782:
0783: /* if any events need to be triggered... */
0784: String theMessage = null;
0785:
0786: if (allEvents.size() > 0) {
0787: for (Enumeration el = allEvents.keys(); el
0788: .hasMoreElements();) {
0789: theEvent = (String) el.nextElement();
0790: theMessage = ("User " + getLoginName() + " ("
0791: + getFullName() + ") who is a member "
0792: + " of group "
0793: + (String) allEvents.get(theEvent) + " has just logged in.");
0794: EventHandler.Event(getDataContext(), theEvent,
0795: theMessage, true);
0796: } /* for each event */
0797:
0798: } /* if any events to be triggered */
0799:
0800: } /* postLogin() */
0801:
0802: /**
0803: * @return a random generated password
0804: */
0805: public String randomPassword() {
0806: int passwordLength;
0807: int iterations = 0;
0808:
0809: //
0810: //Read the property value of minimum password length
0811: //
0812: String propValue = null;
0813:
0814: try {
0815: propValue = StringUtil.notNull(ConfigManager.getContext(
0816: getDataContext()).getMinPasswordSize());
0817: } catch (ConfigurationException ce) {
0818: throw new IllegalArgumentException(ce.getMessage());
0819: }
0820: if (!propValue.equals("")) {
0821: try {
0822: passwordLength = Integer.parseInt(propValue, 10);
0823: } catch (NumberFormatException ex) {
0824:
0825: //Bad number
0826: passwordLength = 6;
0827: }
0828: } else {
0829: passwordLength = 6;
0830: }
0831: FastStringBuffer newPassword = new FastStringBuffer(
0832: passwordLength);
0833:
0834: /////////////////////////////////
0835: //
0836: //Now Generate the new password. (Code from servlet.RegisterUser) before)
0837: //
0838: //Get 400 bytes worth of
0839: //Modified: Fill an array of 200 possible numbers. This is our previous max
0840: //tries anyway. Then try those in the array. Saves many allocations,
0841: //and more importantly, provides a true random number source.
0842: byte[] possibleNumbers;
0843:
0844: try {
0845: possibleNumbers = CryptoManager.getInstance()
0846: .getRandomGenerator().getRandomBytes(200);
0847: } catch (ChainedException e) {
0848: possibleNumbers = new byte[200];
0849:
0850: //If an error occurs, just fill it with Math.random() after logging the
0851: //exception.
0852: Logger.getLogger("com.jcorporate.expresso.core.security.")
0853: .error("Random Password", e);
0854:
0855: for (int i = 0; i < 200; i++) {
0856: possibleNumbers[i] = (byte) (Math.random() * 122);
0857: }
0858: }
0859: while ((newPassword.length() < passwordLength)
0860: && (iterations < 200)) {
0861: iterations++;
0862:
0863: //oneNumber = Math.random() * 122;
0864: if (okNumber(possibleNumbers[iterations])) {
0865: newPassword.append((char) possibleNumbers[iterations]);
0866: }
0867: }
0868:
0869: return newPassword.toString();
0870: } /* randomPassword() */
0871:
0872: /**
0873: * Sends an Authorization Email to a new User.
0874: * The user must click on the link encoded in this email before
0875: * his account will be activated.
0876: */
0877: public void sendAuthEmail() throws DBException {
0878: try {
0879: String dbContext = getDataContext();
0880: String authURL = Setup.getValue(dbContext,
0881: "EmailValidateURL");
0882: String emailAuthCode = getEmailAuthCode();
0883: this .setField(VALIDATION_CODE, emailAuthCode);
0884: this .update();
0885: authURL = authURL + "?UserName=" + getField(LOGIN) + "&db="
0886: + getDataContext() + "&EmailAuthCode="
0887: + emailAuthCode;
0888:
0889: String subject = "New Account Validation - Please Respond";
0890: FastStringBuffer sb = new FastStringBuffer(512);
0891:
0892: if (!"".equals(getFullName())) {
0893: sb.append("Dear " + getFullName() + ",");
0894: }
0895:
0896: sb.append("\n");
0897: sb.append("\n");
0898: sb.append("Thank you for registering");
0899:
0900: String companyName = Setup.getValue(dbContext,
0901: "CompanyName");
0902: String homePageURL = Setup.getValue(dbContext,
0903: "HomePageURL");
0904:
0905: if (companyName != null && !"".equals(companyName)) {
0906: sb.append(" with " + companyName);
0907: }
0908: if (homePageURL != null && !"".equals(homePageURL)) {
0909: sb.append(" at " + homePageURL);
0910: }
0911:
0912: sb.append("!");
0913: sb.append("\n");
0914: sb.append("\n");
0915: sb.append("Your account has been successfully created. "
0916: + "The final step in the");
0917: sb.append("\n");
0918: sb
0919: .append("registration process is to simply follow the link "
0920: + "below to let us");
0921: sb.append("\n");
0922: sb
0923: .append("know that you received this message. You must follow "
0924: + "the link below");
0925: sb.append("\n");
0926: sb.append("before your account will be activated.");
0927: sb.append("\n");
0928: sb.append("\n");
0929: sb.append("NOTE: If you did not register, you may safely");
0930: sb.append("\n");
0931: sb.append("ignore this message.");
0932: sb.append("\n");
0933: sb.append("\n");
0934: sb
0935: .append("In many email clients, you may simply click on the "
0936: + "link below to");
0937: sb.append("\n");
0938: sb
0939: .append("complete the registration process. If your email "
0940: + "client does not");
0941: sb.append("\n");
0942: sb
0943: .append("support this, cut-and-paste the link below into your "
0944: + "web browser's");
0945: sb.append("\n");
0946: sb.append("\"Location\" window:");
0947: sb.append("\n");
0948: sb.append("\n");
0949: sb.append(authURL);
0950: sb.append("\n");
0951: sb.append("\n");
0952:
0953: if (companyName != null && !"".equals(companyName)) {
0954: sb.append("Thank you from all of us at " + companyName
0955: + ".");
0956: }
0957:
0958: sb.append("\n");
0959:
0960: if (companyName != null && !"".equals(homePageURL)) {
0961: sb.append(homePageURL);
0962: }
0963:
0964: sb.append("\n");
0965:
0966: String message = sb.toString();
0967: notify(subject, message);
0968: } catch (Exception e) {
0969: throw new DBException(
0970: "Error in sending account verification message to "
0971: + getField(FULL_NAME) + " at "
0972: + getField(EMAIL_ADDRESS) + ": "
0973: + e.toString());
0974: }
0975: } /* sendAuthEmail() */
0976:
0977: /**
0978: * Send this user an e-mail with file attachments.
0979: *
0980: * @param subject Subject of the e-mail
0981: * @param message Message to send in body of e-mail
0982: * @param fileNames of the files to attach
0983: * @throws DBException If the mail message cannot be sent
0984: */
0985: public void sendFileTo(String subject, String message,
0986: Vector fileNames) throws DBException, LogException {
0987: log.info("Sending " + fileNames.size()
0988: + " files via e-mail to " + getField(LOGIN));
0989:
0990: String sendToUser = getField(EMAIL_ADDRESS);
0991:
0992: try { // create some properties and get the default Session
0993: EMailSender ems = new EMailSender();
0994: ems.setDBName(getDataContext());
0995: ems.addFileAttachments(fileNames);
0996: ems.send(sendToUser, subject, message);
0997: } catch (Exception e) {
0998: throw new DBException("Error sending e-mail", e);
0999: }
1000: } /* sendFileTo(String, String, Vector) */
1001:
1002: /**
1003: * Once a user has validated his email address through the email validation
1004: * servlet, the user will receive this message giving previously requested
1005: * username/password.
1006: * <p/>
1007: * Creation date: (8/8/00 11:44:26 PM)
1008: * author Adam Rossi, PlatinumSolutions, Inc.
1009: *
1010: * @throws com.jcorporate.expresso.core.db.DBException
1011: * The exception description.
1012: */
1013: public void sendFollowUpEmail() throws DBException {
1014: try {
1015: String subject = "New Registration Complete - Welcome!";
1016: String dbContext = getDataContext();
1017:
1018: // We can't retrieve the passsword in plain text to transmit to the user
1019: // So we just create and set a new passord and send that over.
1020: String password = this .randomPassword();
1021: this .setPassword(password);
1022: this .update();
1023:
1024: FastStringBuffer sb = new FastStringBuffer(512);
1025:
1026: if (!"".equals(getFullName())) {
1027: sb.append("Dear " + getFullName() + ",");
1028: }
1029:
1030: sb.append("\n");
1031: sb.append("\n");
1032: sb.append("Thank you for registering");
1033:
1034: String companyName = Setup.getValue(dbContext,
1035: "CompanyName");
1036: String homePageURL = Setup.getValue(dbContext,
1037: "HomePageURL");
1038:
1039: if (companyName != null && !"".equals(companyName)) {
1040: sb.append(" with " + companyName);
1041: }
1042: if (homePageURL != null && !"".equals(homePageURL)) {
1043: sb.append(" at " + homePageURL);
1044: }
1045:
1046: sb.append("!");
1047: sb.append("\n");
1048: sb.append("\n");
1049: sb
1050: .append("Your account is now active. Below is the information "
1051: + "you will need to log in.");
1052: sb.append("\n");
1053: sb
1054: .append("Please keep this information in a safe place.We hope "
1055: + "you enjoy the site and");
1056: sb.append("\n");
1057: sb.append("look forward to your participation.");
1058: sb.append("\n");
1059: sb.append("\n");
1060: sb.append("Login Name: " + getLoginName());
1061: sb.append("\n");
1062: sb.append("Password: " + password);
1063: sb.append("\n");
1064: sb.append("\n");
1065:
1066: if (companyName != null && !"".equals(companyName)) {
1067: sb.append("Thank you from all of us at " + companyName
1068: + ".");
1069: }
1070:
1071: sb.append("\n");
1072:
1073: if (companyName != null && !"".equals(homePageURL)) {
1074: sb.append(homePageURL);
1075: }
1076:
1077: sb.append("\n");
1078:
1079: String message = sb.toString();
1080: notify(subject, message);
1081: } catch (Exception e) {
1082: throw new DBException(
1083: "Error in sending account verification follow up message to "
1084: + getLoginName() + " at " + getEmail()
1085: + ": " + e.toString());
1086: }
1087: } /* sendFollowUpEmail() */
1088:
1089: public void setAccountStatus(String accountStatus)
1090: throws DBException {
1091: setField(ACCOUNT_STATUS, accountStatus);
1092: } /* setAccountStatus(String) */
1093:
1094: public void setEmail(String email) throws DBException {
1095: setField(EMAIL_ADDRESS, email);
1096: } /* setEmail(String) */
1097:
1098: public void setEmailValCode(String code) throws DBException {
1099: setField(VALIDATION_CODE, code);
1100: } /* setEmailValCode(String) */
1101:
1102: public void setLoginName(String loginName) throws DBException {
1103: setField(LOGIN, loginName);
1104: } /* setLoginName(String) */
1105:
1106: public void setPassword(String password) throws DBException {
1107: setField(PASSWORD, password);
1108: } /* setPassword(String) */
1109:
1110: public void setRegComplete(boolean status) throws DBException {
1111: String statusString = "N";
1112:
1113: if (status) {
1114: statusString = "Y";
1115: }
1116:
1117: setField(IS_REG_COMPLETE, statusString);
1118: } /* setRegistrationComplete(String) */
1119:
1120: public void setRegistrationDomain(String domain) throws DBException {
1121: RegistrationDomain rd = new RegistrationDomain();
1122: rd.setDataContext(getDataContext());
1123: rd.setField("Name", domain);
1124:
1125: if (rd.find()) {
1126: setField(REGISTRATION_DOMAIN, rd
1127: .getField(REGISTRATION_DOMAIN));
1128: } else {
1129: throw new DBException("Registration domain \"" + domain
1130: + "\" has not been defined.");
1131: }
1132: } /* setRegistrationDomain(String) */
1133:
1134: /**
1135: * @see com.jcorporate.expresso.core.dbobj.SecuredDBObject#setupFields
1136: */
1137: public void setupFields() throws DBException {
1138: setTargetTable("USERSTABLE");
1139: setDescription("DBuser");
1140: setCharset("ISO-8859-1");
1141: addField(EXPUID, DBField.AUTOINC_TYPE, 0, false, "userId");
1142: addField(LOGIN, DBField.CHAR_TYPE, LOGIN_LENGTH, false,
1143: "userLogin");
1144: addField(PASSWORD, DBField.VARCHAR_TYPE, PASSWORD_LENGTH, true,
1145: "password");
1146: addField(EMAIL_ADDRESS, DBField.VARCHAR_TYPE,
1147: EMAIL_ADDRESS_LENGTH, false, "email");
1148: addField(REGISTRATION_DOMAIN, DBField.INTEGER_TYPE, 0, false,
1149: "RegDomainId");
1150: addField(ACCOUNT_STATUS, DBField.CHAR_TYPE, 1, false,
1151: "isActive");
1152: addField(IS_REG_COMPLETE, DBField.CHAR_TYPE, 1, false,
1153: "RegComplete");
1154: addField(CREATED_DATE, DBField.DATETIME_TYPE, 0, false,
1155: "accountCreation");
1156: addField(UPDATED_DATE, DBField.DATETIME_TYPE, 0, false,
1157: "accountUpdate");
1158: addField(VALIDATION_CODE, DBField.VARCHAR_TYPE,
1159: VALIDATION_CODE_LENGTH, true, "validationCode");
1160: addField(FULL_NAME, DBField.VARCHAR_TYPE, FULL_NAME_LENGTH,
1161: true, "userFullName");
1162:
1163: //Set up the string filters.
1164: setStringFilter(LOGIN, "stripFilter");
1165:
1166: //Nobody should even put special characters here
1167: setStringFilter(FULL_NAME, "stripFilter");
1168:
1169: //Nobody should even put special characters here
1170: setStringFilter(EMAIL_ADDRESS, "stripFilter");
1171:
1172: //Nobody should even put special characters here
1173: setStringFilter(PASSWORD, "rawFilter");
1174:
1175: //Must all all characters through or Password gets mucked up.
1176: setStringFilter(FULL_NAME, "rawFilter");
1177:
1178: //The default for the field anyway, but included for completeness' sake
1179: setStringFilter(VALIDATION_CODE, "stripFilter");
1180:
1181: addKey(EXPUID);
1182: setSecret(PASSWORD);
1183: setSecret(VALIDATION_CODE);
1184: setMultiValued(ACCOUNT_STATUS);
1185: setMultiValued(IS_REG_COMPLETE);
1186: setMultiValued(REGISTRATION_DOMAIN);
1187: setLookupObject(REGISTRATION_DOMAIN, RegistrationDomain.class
1188: .getName());
1189:
1190: setReadOnly(CREATED_DATE);
1191: setReadOnly(UPDATED_DATE);
1192: addIndex("LoginNames", LOGIN, true);
1193: addIndex("EMails", EMAIL_ADDRESS, false);
1194: addIndex("Acct_status_idx", ACCOUNT_STATUS, false);
1195: addDetail(GroupMembers.class.getName(), EXPUID,
1196: GroupMembers.EXPUID);
1197: } /* setupFields() */
1198:
1199: public void setUserName(String name) throws DBException {
1200: setField(FULL_NAME, name);
1201: } /* setUserName(String) */
1202:
1203: /**
1204: * Override of add to check for duplicate emails, and handle empty fields
1205: *
1206: * @throws DBException upon error
1207: */
1208: public void update() throws DBException {
1209: setCheckZeroUpdate(false);
1210:
1211: checkEmailAddrAlreadyUsed(IS_UPDATE);
1212:
1213: if (getField(FULL_NAME).equals("")) {
1214: setField(FULL_NAME, getField(LOGIN));
1215: }
1216: // If a User is added without a status, we set the AccountStatus to "I"
1217: // for security reasons
1218: if (getField(ACCOUNT_STATUS).equals("")) {
1219: setField(ACCOUNT_STATUS, "I");
1220: }
1221: // Set the registration domain id
1222: if (getRegistrationDomain().equals("")) {
1223: setRegistrationDomain("default");
1224: }
1225:
1226: RegistrationDomain rd = new RegistrationDomain();
1227: rd.setDataContext(getDataContext());
1228: rd.setField("Name", getRegistrationDomain());
1229:
1230: if (!rd.find()) {
1231: throw new DBException("Regsitration domain \""
1232: + getRegistrationDomain()
1233: + "\" has not been defined");
1234: }
1235:
1236: setField(REGISTRATION_DOMAIN, rd.getField(REGISTRATION_DOMAIN));
1237:
1238: // Check value of registration valid flag
1239: if (getField(IS_REG_COMPLETE).equals("")) {
1240: setField(IS_REG_COMPLETE, "N");
1241: }
1242: // We should always have a CreateDate
1243: if (getField(CREATED_DATE).equals("")) {
1244: setField(CREATED_DATE, DateTime.getDateTimeForDB(this
1245: .getDataContext()));
1246: }
1247:
1248: // touch update date
1249: setField(UPDATED_DATE, DateTime.getDateTimeForDB(this
1250: .getDataContext()));
1251:
1252: super .update();
1253:
1254: User user = new User();
1255: user.setDataContext(this .getDataContext());
1256: user.updateNotify(this );
1257:
1258: }
1259:
1260: /**
1261: * Check that another user with same email doesn't exist already
1262: *
1263: * @param isUpdate boolean for true = update case, false = 'add' case
1264: */
1265: private void checkEmailAddrAlreadyUsed(boolean isUpdate)
1266: throws DBException {
1267:
1268: // If this site uses email as login name, force login name equal to email
1269: boolean useEmailAsLogin = false;
1270:
1271: try {
1272: useEmailAsLogin = ConfigManager
1273: .getContext(getDataContext()).useEmailAsLogin();
1274: } catch (ConfigurationException ce) {
1275: throw new DBException(ce);
1276: }
1277:
1278: if (isUpdate) {
1279: // update case may be shortcircuited, thus requiring no db access
1280: String onlychanged = Setup.getValueUnrequired(
1281: getDataContext(), UPDATE_CHANGED_ONLY);
1282: if (StringUtil.toBoolean(onlychanged)) {
1283: // ok, setting says that this app only updates the field which are changed
1284: // if email/login not changed, don't waste time checking for whether they are unique
1285: if (getDataField(EMAIL_ADDRESS).isChanged()
1286: || (!useEmailAsLogin && getDataField(LOGIN)
1287: .isChanged())) {
1288: // go on through tests below
1289: } else {
1290: return; // shortcircuit tests--fields haven't changed
1291: }
1292: }
1293: }
1294:
1295: if (!getField(EMAIL_ADDRESS).equalsIgnoreCase("none")) {
1296: UserInfo anotherUser = new User().getUserInfo();
1297: anotherUser.setDBName(getDataContext());
1298: anotherUser.setEmail(getField(EMAIL_ADDRESS));
1299:
1300: boolean foundEmail = anotherUser.find();
1301: if (foundEmail && isUpdate
1302: && (anotherUser.getUid() != getUid())) {
1303: // update case: must also be diff. uid
1304: throw new DBException(
1305: "Another user with the same email address \""
1306: + getField(EMAIL_ADDRESS)
1307: + "\" already exists");
1308: } else if (foundEmail && !isUpdate) {
1309: // add case--just finding another with this email is enough to throw
1310: throw new DBException(
1311: "Another user with the same email address \""
1312: + getField(EMAIL_ADDRESS)
1313: + "\" already exists");
1314:
1315: }
1316: }
1317:
1318: if (useEmailAsLogin) {
1319: if (getField(LOGIN).equals("")) {
1320: setField(LOGIN, getField(EMAIL_ADDRESS));
1321: }
1322: } else {
1323:
1324: // This site has separate login name, make sure same login name doesn't exist already
1325: UserInfo anotherUser = new User().getUserInfo();
1326: anotherUser.setDBName(getDataContext());
1327: anotherUser.setLoginName(getField(LOGIN));
1328: boolean foundLogin = anotherUser.find();
1329:
1330: if (!isUpdate && foundLogin) {
1331: throw new DBException(
1332: "Another user with the same login \""
1333: + getField(LOGIN) + "\" already exists");
1334: } else if (isUpdate && foundLogin
1335: && (anotherUser.getUid() != getUid())) {
1336: throw new DBException(
1337: "Another user with the same login \""
1338: + getField(LOGIN) + "\" already exists");
1339: }
1340: }
1341: }
1342:
1343: /**
1344: * Override to provide better performance. We cache recently used LoginNames
1345: * into a cache. If we find the appropriate loginname, then
1346: * we map the uid so that subsequent find() will perform a retrieve() so we can utilize the
1347: * cache instead.
1348: *
1349: * @return true if successfully found the object
1350: * @throws DBException if there's an error performing the find.
1351: */
1352: public boolean find()
1353: throws com.jcorporate.expresso.core.db.DBException {
1354:
1355: // case where UID is known means no caching
1356: if (this .getField(EXPUID).length() > 0) {
1357: boolean returnValue = super .find();
1358: return returnValue; // used UID so we already hit any dbobject cache during find()
1359: }
1360:
1361: // if we have a login name, try to find user from cache
1362: if (getLoginName().length() > 0) {
1363:
1364: String keyString = getName2IdCacheKey();
1365: try {
1366: Cache cache = getName2IdCache();
1367: CachedObject c = (CachedObject) cache
1368: .getItem(keyString);
1369: if (c != null) {
1370: Integer cachedUID = (Integer) c.getValue();
1371: this .setUid(cachedUID.intValue());
1372: try {
1373: this .retrieve();
1374:
1375: // success!
1376: return true;
1377: } catch (com.jcorporate.expresso.core.db.exception.DBRecordNotFoundException e) {
1378: // log error
1379: log
1380: .error(
1381: "Error retrieving user from uid found in cache",
1382: e);
1383: // and try again below
1384: }
1385: }
1386: } catch (CacheException e) {
1387: log.error("Error retrieving from cache", e);
1388: // and try again below
1389: }
1390: }
1391:
1392: // get here (in non-error case) when EXPID unknown, nor was any *cached* login name provided
1393: boolean returnValue = super .find();
1394: if (returnValue) {
1395: cacheUser(); // cache in case we search via loginname later
1396: }
1397: return returnValue;
1398:
1399: } /* update() */
1400:
1401: private void cacheUser() throws DBException {
1402: String keyString = getName2IdCacheKey();
1403: try {
1404: Cache cache = getName2IdCache();
1405: CachedObject c = (CachedObject) cache.getItem(keyString);
1406: if (c == null) {
1407: CachedObject co = new CachedObject(keyString,
1408: new Integer(this .getUid()));
1409: CacheSystem cs = CacheManager.getCacheSystem(this
1410: .getDataContext());
1411: cs.addItem(NAME_2_ID_CACHE_NAME, co, 1000 * 60 * 10); //10 minute cache;
1412: }
1413: } catch (CacheException e) {
1414: log.error("Error adding to cache", e);
1415: }
1416: }
1417:
1418: /**
1419: * @return cache; never null
1420: */
1421: private Cache getName2IdCache() throws CacheException {
1422: CacheSystem cs = CacheManager.getCacheSystem(this
1423: .getDataContext());
1424: Cache cache = cs.getCache(NAME_2_ID_CACHE_NAME);
1425: if (cache == null) {
1426: cache = cs.createCache(NAME_2_ID_CACHE_NAME, false, 20);
1427: cs.addListener(NAME_2_ID_CACHE_NAME, this .getClass()
1428: .getName());
1429: }
1430: return cache;
1431: }
1432:
1433: /**
1434: * @return key made from context + name
1435: * @todo use faststrbuf pool
1436: */
1437: private String getName2IdCacheKey() throws DBException {
1438: FastStringBuffer key = new FastStringBuffer(16);
1439: key.append(this .getDataContext());
1440: key.append(".");
1441: key.append(this .getLoginName());
1442: String keyString = key.toString();
1443: return keyString;
1444: }
1445:
1446: /**
1447: * the primary group of this user is appropriate for unix-like purposes,
1448: * such as setting the group for a file permission
1449: *
1450: * @return name of the primary group of this user; null if no group is found
1451: * @throws DBException upon database access error
1452: */
1453: public String getPrimaryGroup() throws DBException {
1454: return getPrimaryGroup(this );
1455: }
1456:
1457: /**
1458: * the primary group of this user is appropriate for unix-like purposes,
1459: * such as setting the group for a file permission
1460: *
1461: * @param user The userInfo object to query
1462: * @return name of the primary group of this user; null if no group is primary
1463: * @throws DBException upon database access error
1464: */
1465: public static String getPrimaryGroup(UserInfo user)
1466: throws DBException {
1467: UserGroup primary = null;
1468:
1469: UserPreference pref = new UserPreference();
1470: pref.setDataContext(user.getDataContext());
1471: pref.setField(UserPreference.PREF_CODE,
1472: UserPreferenceDef.PRIMARY_GROUP_PREF);
1473: pref.setField(UserPreference.CLASS_NAME,
1474: UserPreferenceDef.ANY_CLASS);
1475: pref.setField(UserPreference.EXPUID, user.getUid());
1476: if (!pref.find()) {
1477:
1478: // if none marked as primary, use first group in membership list
1479: Vector groupNames = user.getGroups();
1480: if (groupNames.size() > 0) {
1481: primary = new UserGroup();
1482: primary.setDataContext(user.getDataContext());
1483: primary.setField(UserGroup.GROUP_NAME_FIELD,
1484: (String) groupNames.get(0));
1485: if (!primary.find()) {
1486: primary = null;
1487: }
1488: }
1489: } else {
1490: // have preference; we expect this to be a real group
1491: String primStr = pref.getField(UserPreference.PREF_VALUE);
1492: primary = new UserGroup();
1493: primary.setDataContext(user.getDataContext());
1494: primary.setField(UserGroup.GROUP_NAME_FIELD, primStr);
1495: if (!primary.find()) {
1496: // unexpected
1497: throw new DBException("cannot locate primary group: "
1498: + primStr + " which is specified for user: "
1499: + user.getLoginName());
1500: }
1501: }
1502:
1503: if (primary == null) {
1504: return null;
1505: } else {
1506: return primary.getField(UserGroup.GROUP_NAME_FIELD);
1507: }
1508: }
1509:
1510: /**
1511: * set the primary group of this user. primary group is appropriate for
1512: * unix-like purposes, such as setting the group for a file permission
1513: *
1514: * @param group The UserGroup object to use.
1515: * @throws DBException upon database access error
1516: */
1517: public void setPrimaryGroup(UserGroup group) throws DBException {
1518: UserPreference pref = new UserPreference();
1519: pref.setDataContext(this .getDataContext());
1520: pref.setField(UserPreference.PREF_CODE,
1521: UserPreferenceDef.PRIMARY_GROUP_PREF);
1522: pref.setField(UserPreference.CLASS_NAME,
1523: UserPreferenceDef.ANY_CLASS);
1524: pref.setField(UserPreference.EXPUID, this .getUid());
1525: pref.setField(UserPreference.PREF_VALUE, group.getGroupName());
1526: pref.addOrUpdate();
1527: }
1528: } /* UserDBObj */
|