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.ext.dbobj;
0066:
0067: import com.jcorporate.expresso.core.controller.ControllerRequest;
0068: import com.jcorporate.expresso.core.db.DBException;
0069: import com.jcorporate.expresso.core.dbobj.SecuredDBObject;
0070: import com.jcorporate.expresso.core.dbobj.ValidValue;
0071: import com.jcorporate.expresso.core.logging.LogException;
0072: import com.jcorporate.expresso.core.misc.Base64;
0073: import com.jcorporate.expresso.core.misc.ConfigManager;
0074: import com.jcorporate.expresso.core.misc.ConfigurationException;
0075: import com.jcorporate.expresso.core.misc.DateTime;
0076: import com.jcorporate.expresso.core.misc.EMailSender;
0077: import com.jcorporate.expresso.core.misc.EventHandler;
0078: import com.jcorporate.expresso.core.misc.StringUtil;
0079: import com.jcorporate.expresso.core.security.CryptoManager;
0080: import com.jcorporate.expresso.core.security.User;
0081: import com.jcorporate.expresso.core.security.UserInfo;
0082: import com.jcorporate.expresso.kernel.exception.ChainedException;
0083: import com.jcorporate.expresso.services.dbobj.DefaultUserInfo;
0084: import com.jcorporate.expresso.services.dbobj.GroupMembers;
0085: import com.jcorporate.expresso.services.dbobj.RegistrationDomain;
0086: import com.jcorporate.expresso.services.dbobj.Setup;
0087: import com.jcorporate.expresso.services.dbobj.UserGroup;
0088: import org.apache.log4j.Logger;
0089:
0090: import java.util.Date;
0091: import java.util.Enumeration;
0092: import java.util.Hashtable;
0093: import java.util.Iterator;
0094: import java.util.Vector;
0095:
0096: /**
0097: * @author Michael Nash
0098: * @deprecated 10/4/2004 functionality can be handled by DefaultUserInfo with DBOTHERMAP
0099: * method to map a table to a context
0100: */
0101: public class SingleDBUserInfo extends SecuredDBObject implements
0102: UserInfo {
0103: /**
0104: * Field name for full name.
0105: */
0106: public static final String FULL_NAME = "UserName";
0107:
0108: private static final String this Class = SingleDBUserInfo.class
0109: .getName();
0110: private static Logger log = Logger
0111: .getLogger(SingleDBUserInfo.class);
0112: private boolean noConfig = false;
0113: private static String noConfigMessage = "Unable to read userContext custom property - can't use SingleDBUserInfo";
0114:
0115: public void setUid(String uid) throws DBException {
0116: StringUtil.assertNotBlank(uid, "Can't set a blank UID");
0117: setField("ExpUid", uid);
0118: } /* setUid(String) */
0119:
0120: public void setUid(int uid) throws DBException {
0121: setField("ExpUid", uid);
0122: }
0123:
0124: public void setDBName() {
0125: setFixedDBName();
0126: }
0127:
0128: public String getDataContext() {
0129: setFixedDBName();
0130:
0131: return super .getDataContext();
0132: }
0133:
0134: public SingleDBUserInfo() throws DBException {
0135: super ();
0136: } /* SingleDBUserInfo() */
0137:
0138: /**
0139: * Use over (String) constructor. Initializes the object in the context
0140: * of the user who's uid belongs to the parameter.
0141: *
0142: * @param uid the Uid of the user context
0143: * @throws DBException if there's an initialization problem
0144: */
0145: public SingleDBUserInfo(int uid) throws DBException {
0146: super (uid);
0147: }
0148:
0149: /**
0150: * For using DBObjects within Controllers. Initializes based upon the current
0151: * user and the requested db. [Of course this can be modified later]
0152: *
0153: * @param request - The controller request handed to you by the framework.
0154: */
0155: public SingleDBUserInfo(ControllerRequest request)
0156: throws DBException {
0157: super (request);
0158: }
0159:
0160: private void setFixedDBName() {
0161: try {
0162: String newDBName = StringUtil.notNull(ConfigManager
0163: .getContext("default").getCustomProperty(
0164: "userContext"));
0165:
0166: if (newDBName.equals("")) {
0167: noConfig = true;
0168:
0169: return;
0170: }
0171:
0172: super .setDataContext(newDBName);
0173: } catch (ConfigurationException ce) {
0174: throw new IllegalArgumentException(ce.getMessage());
0175: }
0176: }
0177:
0178: public void add() throws DBException {
0179: setFixedDBName();
0180:
0181: if (noConfig) {
0182: throw new DBException(noConfigMessage);
0183: }
0184:
0185: // Check that another user with same email doesn't exist already
0186: SingleDBUserInfo anotherUser = new SingleDBUserInfo();
0187:
0188: if (!getField("EMail").equalsIgnoreCase("none")) {
0189: anotherUser.setDataContext(getDataContext());
0190: anotherUser.setEmail(getField("EMail"));
0191:
0192: if (anotherUser.find()) {
0193: throw new DBException(
0194: "Another user with the same email address \""
0195: + getField("EMail")
0196: + "\" already exists");
0197: }
0198: }
0199:
0200: // If this site uses email as login name, force login name equal to email
0201: boolean useEmailAsLogin = false;
0202:
0203: try {
0204: useEmailAsLogin = ConfigManager
0205: .getContext(getDataContext()).useEmailAsLogin();
0206: } catch (ConfigurationException ce) {
0207: throw new DBException(ce);
0208: }
0209: if (useEmailAsLogin) {
0210: if (getField("LoginName").equals("")) {
0211: setField("LoginName", getField("EMail"));
0212: }
0213: } else {
0214:
0215: // This site has separate login name, make sure same login name doesn't exist already
0216: anotherUser.clear();
0217: anotherUser.setDataContext(getDataContext());
0218: anotherUser.setLoginName(getField("LoginName"));
0219:
0220: if (anotherUser.find()) {
0221: throw new DBException(
0222: "Another user with the same login \""
0223: + getField("LoginName")
0224: + "\" already exists");
0225: }
0226: }
0227: // At initial login, UserName == LoginName, Registation controllers can later modify this
0228: if (getField("UserName").equals("")) {
0229: setField("UserName", getField("LoginName"));
0230: }
0231: // If a User is added without a status, we set the AccountStatus to "I"
0232: // for security reasons
0233: if (getField("AccountStatus").equals("")) {
0234: setField("AccountStatus", "I");
0235: }
0236: // Set the registration domain id
0237: if (getRegistrationDomain().equals("")) {
0238: setRegistrationDomain("default");
0239: }
0240:
0241: RegistrationDomain rd = new RegistrationDomain();
0242: rd.setDataContext(getDataContext());
0243: rd.setField("Name", getRegistrationDomain());
0244:
0245: if (!rd.find()) {
0246: throw new DBException("Registration domain \""
0247: + getRegistrationDomain()
0248: + "\" has not been defined");
0249: }
0250:
0251: setField("RegDomId", rd.getField("RegDomId"));
0252:
0253: // Check value of registration valid flag
0254: if (getField("RegComplete").equals("")) {
0255: setField("RegComplete", "N");
0256: }
0257: // We should always have a CreateDate
0258: if (getField("CreateDate").equals("")) {
0259: setField("CreateDate", DateTime.getDateTimeForDB(this
0260: .getDataContext()));
0261: }
0262: // We should always have a UpdateDate
0263: if (getField("UpdateDate").equals("")) {
0264: setField("UpdateDate", getField("CreateDate"));
0265: }
0266:
0267: super .add();
0268: User user = new User();
0269: user.setDataContext(this .getDataContext());
0270: user.addNotify(this );
0271: } /* add() */
0272:
0273: /**
0274: * Extends the checkAllRefs method to check for valid Registration Domain Id
0275: *
0276: * @throws DBException If a referential integrity violation is found
0277: */
0278: protected void checkAllRefs() throws DBException {
0279: checkRef("RegDomId", new RegistrationDomain(), "Invalid "
0280: + getString(getMetaData().getDescription("RegDomId")));
0281: } /* checkAllRefs() */
0282:
0283: public void delete() throws DBException {
0284: if (noConfig) {
0285: throw new DBException(noConfigMessage);
0286: }
0287:
0288: User user = new User();
0289: user.setDataContext(this .getDataContext());
0290: user.deleteNotify(this );
0291:
0292: super .delete();
0293:
0294: } /* delete() */
0295:
0296: public String getAccountStatus() throws DBException {
0297: return getField("AccountStatus");
0298: } /* getAccountStatus() */
0299:
0300: public Vector getAllUsers() throws DBException {
0301: return new Vector(searchAndRetrieveList("LoginName"));
0302: } /* getAllUsers() */
0303:
0304: public String getCreateDate() throws DBException {
0305: return getField("CreateDate");
0306: } /* getCreateDate() */
0307:
0308: public String getEmail() throws DBException {
0309: return getField("EMail");
0310: } /* getEmail() */
0311:
0312: public String getEmailAuthCode() throws DBException {
0313: Date createDate = getFieldDate("CreateDate");
0314: long dateLong = createDate.getTime();
0315: long emailAuthCode = Math.round(dateLong * 1.71);
0316:
0317: return Long.toString(emailAuthCode);
0318: } /* getEmailAuthCode() */
0319:
0320: public String getEmailValCode() throws DBException {
0321: return getField("EmailValCode");
0322: } /* getEmailValCode() */
0323:
0324: public Vector getGroups() throws DBException {
0325: Vector myGroups = new Vector(1);
0326: GroupMembers memberList = new GroupMembers();
0327: memberList.setDataContext(getDataContext());
0328:
0329: GroupMembers oneMember = null;
0330: memberList.setField("ExpUid", getUid());
0331:
0332: if (log.isDebugEnabled()) {
0333: log.debug("Getting groups for uid " + getUid()
0334: + ", login name " + getLoginName());
0335: }
0336: for (Iterator e = memberList.searchAndRetrieveList().iterator(); e
0337: .hasNext();) {
0338: oneMember = (GroupMembers) e.next();
0339: myGroups.addElement(oneMember.getField("GroupName"));
0340:
0341: if (log.isDebugEnabled()) {
0342: log.debug("" + getUid() + " is a Member of group "
0343: + oneMember.getField("GroupName"));
0344: }
0345: }
0346:
0347: /**
0348: * back in the bad old days, we manually added the UserGroup.UNKNOWN_USERS_GROUP so that
0349: * it appeared as though everyone was a member of this group. If your app depends on this old
0350: * behavior, set the following Setup value to true.
0351: String isAddUnknownUsersGroup = Setup.getValueUnrequired(getDataContext(), "AddUnknownUserGroup");
0352: if (StringUtil.toBoolean(isAddUnknownUsersGroup))
0353: myGroups.addElement(UserGroup.UNKNOWN_USERS_GROUP);
0354: */
0355:
0356: myGroups.addElement(UserGroup.UNKNOWN_USERS_GROUP);
0357:
0358: if (log.isDebugEnabled()) {
0359: log.debug("" + getUid() + " is a member of "
0360: + myGroups.size() + " groups");
0361: }
0362:
0363: return myGroups;
0364: } /* getGroups() */
0365:
0366: public String getLoginName() throws DBException {
0367: return getField("LoginName");
0368: } /* getLoginName() */
0369:
0370: public String getPassword() throws DBException {
0371: return getField("Passwd");
0372: } /* getPassword() */
0373:
0374: public boolean getRegComplete() throws DBException {
0375: String statusString = getField("RegComplete");
0376: boolean status = false;
0377:
0378: if (statusString.equals("Y")) {
0379: status = true;
0380: }
0381:
0382: return status;
0383: } /* getRegComplete() */
0384:
0385: public String getRegistrationDomain() throws DBException {
0386: String domain = "default";
0387: RegistrationDomain rd = new RegistrationDomain();
0388: rd.setDataContext(getDataContext());
0389: rd.setField("RegDomId", getField("RegDomId"));
0390:
0391: if (rd.find()) {
0392: domain = rd.getField("Name");
0393: }
0394:
0395: return domain;
0396: } /* getRegistrationDomain() */
0397:
0398: public int getUid() throws DBException {
0399: return getFieldInt("ExpUid");
0400: } /* getUid() */
0401:
0402: public String getUpdateDate() throws DBException {
0403: return getField("UpdateDate");
0404: } /* getUpdateDate() */
0405:
0406: /**
0407: * get descriptive, full name
0408: *
0409: * @deprecated Since Expresso 5.5; use getFullName()
0410: * instead to avoid confusion with login name
0411: */
0412: public String getUserName() throws DBException {
0413: return getField("UserName");
0414: } /* getUserName() */
0415:
0416: /**
0417: * get descriptive, full name
0418: */
0419: public String getFullName() throws DBException {
0420: return getField(FULL_NAME);
0421: } /* getUserName() */
0422:
0423: /**
0424: * @param fieldName The name of the field to get the valid values for
0425: * @return java.util.Vector of ValidValue objects
0426: * @throws com.jcorporate.expresso.core.db.DBException
0427: * The exception description.
0428: */
0429: public synchronized Vector getValidValues(String fieldName)
0430: throws DBException {
0431:
0432: if ("AccountStatus".equals(fieldName)) {
0433: Vector values = new Vector();
0434: values.addElement(new ValidValue("A", "Active"));
0435: values.addElement(new ValidValue("I",
0436: "Inactive Until Email Confirmation"));
0437: values.addElement(new ValidValue("D", "Disabled"));
0438: values.addElement(new ValidValue("W",
0439: "Waiting For Approval"));
0440: values.addElement(new ValidValue("X",
0441: "Registration Denied By Administrator"));
0442:
0443: return values;
0444: } else if (fieldName.equals("RegComplete")) {
0445: Vector rv = new Vector(2);
0446: ValidValue rvv = new ValidValue("Y", "Complete");
0447: rv.addElement(rvv);
0448: rvv = new ValidValue("N", "Incomplete");
0449: rv.addElement(rvv);
0450:
0451: return rv;
0452: }
0453:
0454: return super .getValidValues(fieldName);
0455: } /* getValidValues(String) */
0456:
0457: /**
0458: * hashEncodePassword: If passed a plaintext string > 0 bytes, then this
0459: * function will SHA1 hash the password, then Base64 encode it and return it
0460: * as a string.
0461: * <p/>
0462: * If the password is zero length, then it will simply return a zero length
0463: * string also.
0464: *
0465: * @param plaintext - the password to process in this manner: <br>
0466: * returnValue = Base64(SHA-1(plaintext))
0467: * @return Base64-hash encoded password
0468: */
0469: public String hashEncodePassword(String plaintext)
0470: throws DBException {
0471: String myName = (this Class + "hashEncodePassword()");
0472:
0473: if (plaintext == null) {
0474: throw new DBException(myName
0475: + ": Password Must not be NULL");
0476: }
0477: if (plaintext.length() == 0) {
0478: return plaintext;
0479: }
0480: try {
0481: return Base64.encode(CryptoManager.getInstance()
0482: .getStringHash().produceHash(plaintext.getBytes()));
0483: } catch (Exception ex) {
0484: throw new DBException(myName + ":Error hashing Password:"
0485: + " You may not have installed the"
0486: + " Cryptography Extensions Properly:", ex);
0487: }
0488: } /* hashEncodePassword(String) */
0489:
0490: /**
0491: * Send this user a notification via e-mail.
0492: *
0493: * @param subject Subject of the e-mail
0494: * @param message Message to send in body of e-mail
0495: * @throws DBException If the mail message cannot be sent
0496: */
0497: public void notify(String subject, String message)
0498: throws DBException, LogException {
0499: if (noConfig) {
0500: throw new DBException(noConfigMessage);
0501: }
0502:
0503: String myName = (this Class + "notify(String, String)");
0504: log.info("Notifying user " + getField("ExpUid") + " of "
0505: + subject);
0506:
0507: String sendToUser = getField("EMail");
0508:
0509: try {
0510: EMailSender ems = new EMailSender();
0511: ems.setDBName(getDataContext());
0512: ems.send(sendToUser, subject, message);
0513: } catch (Exception e) {
0514: throw new DBException(myName
0515: + ":Uncaught exception sending e-mail", e);
0516: }
0517: } /* notify(String, String) */
0518:
0519: /**
0520: * Check if the given number is in the range of letters and
0521: * digits that we want to use for generating a password
0522: * Previously in com.jcorporate.expresso.ext.servlet.RegisterUser.java
0523: *
0524: * @param x The byte to check if printable
0525: * @return true if it is a printable ASCII character
0526: */
0527: private boolean okNumber(byte x) {
0528: if ((x >= 65) && (x <= 90)) {
0529: return true;
0530: }
0531: if ((x >= 48) && (x <= 57)) {
0532: return true;
0533: }
0534: if ((x >= 97) && (x <= 122)) {
0535: return true;
0536: }
0537:
0538: return false;
0539: } /* okNumber(byte) */
0540:
0541: /**
0542: * passwordEquals - feed it a password and it will tell you if the hash of it
0543: * matches the one on file.
0544: * <p/>
0545: * Also, for backwards compatability and some other issues, this function
0546: * will also accept a plaintext version of the password if it is sitting in
0547: * the database. However, if a plaintext match is encountered, then it will
0548: * hash the password and re-write itself to the database record.
0549: *
0550: * @param tryPassword The value the user input for an attempted login.
0551: * @return true if the compared password equals
0552: */
0553: public boolean passwordEquals(String tryPassword)
0554: throws DBException {
0555:
0556: if (tryPassword == null) {
0557: throw new DBException(this Class
0558: + ":tryPassword Must not be NULL");
0559: }
0560:
0561: String fieldData = getPassword();
0562: String trieduser = getLoginName();
0563:
0564: if (log.isDebugEnabled()) {
0565: log.debug("Trying user " + trieduser + ", password '"
0566: + tryPassword + "' - field data is '" + fieldData
0567: + "'");
0568: }
0569:
0570: String triedhash = hashEncodePassword(tryPassword);
0571:
0572: if (log.isDebugEnabled()) {
0573: log.debug("Password hashed is " + triedhash + "'");
0574: }
0575: if (triedhash.equals(fieldData)) {
0576: return true;
0577: } else {
0578: if (log.isDebugEnabled()) {
0579: log.debug("Hash doesn't equal data - trying plaintext");
0580: }
0581: //The second compare check is to make sure somebody isn't just
0582: //replaying a snooped password and attempting to use it against
0583: //us. If Password.length() == 28 then it's a hash.
0584: if (tryPassword.equals(fieldData)
0585: && fieldData.length() < 20) {
0586: if (log.isDebugEnabled()) {
0587: log
0588: .debug("Password matches in plain text - hashing & writing to DB");
0589: }
0590:
0591: setPassword(hashEncodePassword(fieldData));
0592: update();
0593:
0594: return true;
0595: } else {
0596:
0597: //No Match
0598: if (log.isDebugEnabled()) {
0599: log
0600: .debug("Password doesn't equal plain text either ('"
0601: + tryPassword
0602: + "' <> '"
0603: + fieldData
0604: + "') or field data is over 20 characters");
0605: }
0606:
0607: return false;
0608: }
0609: }
0610: } /* passwordEquals(String) */
0611:
0612: /**
0613: * Called by the various objects that can log in a user
0614: * to do post-login tasks
0615: */
0616: public void postLogin() throws DBException, LogException {
0617: UserGroup oneGroup = new UserGroup(
0618: SecuredDBObject.SYSTEM_ACCOUNT);
0619: oneGroup.setDataContext(getDataContext());
0620:
0621: String theEvent = null;
0622: Hashtable allEvents = new Hashtable(1);
0623: String oneGroupName = null;
0624:
0625: for (Enumeration gl = getGroups().elements(); gl
0626: .hasMoreElements();) {
0627: oneGroupName = (String) gl.nextElement();
0628: oneGroup.clear();
0629: oneGroup.setField("GroupName", oneGroupName);
0630:
0631: if (oneGroup.find()) {
0632: theEvent = oneGroup.getField("LoginEvent");
0633:
0634: if (!theEvent.equals("")) {
0635: allEvents.put(theEvent, oneGroup
0636: .getField("GroupName"));
0637: }
0638: } /* if the group exists */
0639:
0640: } /* for each group user is a member of */
0641:
0642: /* if any events need to be triggered... */
0643: String theMessage = null;
0644:
0645: if (allEvents.size() > 0) {
0646: for (Enumeration el = allEvents.keys(); el
0647: .hasMoreElements();) {
0648: theEvent = (String) el.nextElement();
0649: theMessage = ("User " + getLoginName() + " ("
0650: + getFullName() + ") who is a member "
0651: + " of group "
0652: + (String) allEvents.get(theEvent) + " has just logged in.");
0653: EventHandler.Event(getDataContext(), theEvent,
0654: theMessage, true);
0655: } /* for each event */
0656:
0657: } /* if any events to be triggered */
0658:
0659: } /* postLogin() */
0660:
0661: /**
0662: * @return a new random generated password
0663: */
0664: public String randomPassword() {
0665: int passwordLength;
0666: StringBuffer newPassword = new StringBuffer("");
0667: int iterations = 0;
0668:
0669: //
0670: //Read the property value of minimum password length
0671: //
0672: String propValue = null;
0673:
0674: try {
0675: propValue = StringUtil.notNull(ConfigManager.getContext(
0676: getDataContext()).getMinPasswordSize());
0677: } catch (ConfigurationException ce) {
0678: throw new IllegalArgumentException(ce.getMessage());
0679: }
0680: if (!propValue.equals("")) {
0681: try {
0682: passwordLength = Integer.parseInt(propValue, 10);
0683: } catch (NumberFormatException ex) {
0684:
0685: //Bad number
0686: passwordLength = 6;
0687: }
0688: } else {
0689: passwordLength = 6;
0690: }
0691:
0692: /////////////////////////////////
0693: //
0694: //Now Generate the new password. (Code from servlet.RegisterUser) before)
0695: //
0696: //Get 400 bytes worth of
0697: //Modified: Fill an array of 200 possible numbers. This is our previous max
0698: //tries anyway. Then try those in the array. Saves many allocations,
0699: //and more importantly, provides a true random number source.
0700: byte[] possibleNumbers;
0701:
0702: try {
0703: possibleNumbers = CryptoManager.getInstance()
0704: .getRandomGenerator().getRandomBytes(200);
0705: } catch (ChainedException e) {
0706: possibleNumbers = new byte[200];
0707:
0708: //If an error occurs, just fill it with Math.random() after logging the
0709: //exception.
0710: Logger.getLogger("com.jcorporate.expresso.core.security.")
0711: .error("Random Password", e);
0712:
0713: for (int i = 0; i < 200; i++) {
0714: possibleNumbers[i] = (byte) (Math.random() * 122);
0715: }
0716: }
0717: while ((newPassword.length() < passwordLength)
0718: && (iterations < 200)) {
0719: iterations++;
0720:
0721: //oneNumber = Math.random() * 122;
0722: if (okNumber(possibleNumbers[iterations])) {
0723: newPassword.append((char) possibleNumbers[iterations]);
0724: }
0725: }
0726:
0727: return newPassword.toString();
0728: } /* randomPassword() */
0729:
0730: /**
0731: * Sends an Authorization Email to a new User.
0732: * The user must click on the link encoded in this email before
0733: * his account will be activated.
0734: */
0735: public void sendAuthEmail() throws DBException {
0736: try {
0737: String dbContext = getDataContext();
0738: String authURL = Setup.getValue(dbContext,
0739: "EmailValidateURL");
0740: String emailAuthCode = getEmailAuthCode();
0741: this .setField("EmailValCode", emailAuthCode);
0742: this .update();
0743: authURL = authURL + "?UserName=" + getField("LoginName")
0744: + "&db=" + getDataContext() + "&EmailAuthCode="
0745: + emailAuthCode;
0746:
0747: String subject = "New Account Validation - Please Respond";
0748: StringBuffer sb = new StringBuffer();
0749:
0750: if (!"".equals(getFullName())) {
0751: sb.append("Dear " + getFullName() + ",");
0752: }
0753:
0754: sb.append("\n");
0755: sb.append("\n");
0756: sb.append("Thank you for registering");
0757:
0758: String companyName = Setup.getValue(dbContext,
0759: "CompanyName");
0760: String homePageURL = Setup.getValue(dbContext,
0761: "HomePageURL");
0762:
0763: if (companyName != null && !"".equals(companyName)) {
0764: sb.append(" with " + companyName);
0765: }
0766: if (homePageURL != null && !"".equals(homePageURL)) {
0767: sb.append(" at " + homePageURL);
0768: }
0769:
0770: sb.append("!");
0771: sb.append("\n");
0772: sb.append("\n");
0773: sb.append("Your account has been successfully created. "
0774: + "The final step in the");
0775: sb.append("\n");
0776: sb
0777: .append("registration process is to simply follow the link "
0778: + "below to let us");
0779: sb.append("\n");
0780: sb
0781: .append("know that you received this message. You must follow "
0782: + "the link below");
0783: sb.append("\n");
0784: sb.append("before your account will be activated.");
0785: sb.append("\n");
0786: sb.append("\n");
0787: sb.append("NOTE: If you did not register, you may safely");
0788: sb.append("\n");
0789: sb.append("ignore this message.");
0790: sb.append("\n");
0791: sb.append("\n");
0792: sb
0793: .append("In many email clients, you may simply click on the "
0794: + "link below to");
0795: sb.append("\n");
0796: sb
0797: .append("complete the registration process. If your email "
0798: + "client does not");
0799: sb.append("\n");
0800: sb
0801: .append("support this, cut-and-paste the link below into your "
0802: + "web browser's");
0803: sb.append("\n");
0804: sb.append("\"Location\" window:");
0805: sb.append("\n");
0806: sb.append("\n");
0807: sb.append(authURL);
0808: sb.append("\n");
0809: sb.append("\n");
0810:
0811: if (companyName != null && !"".equals(companyName)) {
0812: sb.append("Thank you from all of us at " + companyName
0813: + ".");
0814: }
0815:
0816: sb.append("\n");
0817:
0818: if (companyName != null && !"".equals(homePageURL)) {
0819: sb.append(homePageURL);
0820: }
0821:
0822: sb.append("\n");
0823:
0824: String message = sb.toString();
0825: notify(subject, message);
0826: } catch (Exception e) {
0827: throw new DBException(
0828: "Error in sending account verification message to "
0829: + getField("UserName") + " at "
0830: + getField("EMail") + ": " + e.toString());
0831: }
0832: } /* sendAuthEmail() */
0833:
0834: /**
0835: * Send this user an e-mail with file attachments.
0836: *
0837: * @param subject Subject of the e-mail
0838: * @param message Message to send in body of e-mail
0839: * @param fileNames of the files to attach
0840: * @throws DBException If the mail message cannot be sent
0841: */
0842: public void sendFileTo(String subject, String message,
0843: Vector fileNames) throws DBException, LogException {
0844: String myName = (this Class + "sendFileTo(String, String, String)");
0845: log.info("Sending " + fileNames.size()
0846: + " files via e-mail to " + getField("LoginName"));
0847:
0848: String sendToUser = getField("EMail");
0849:
0850: try { // create some properties and get the default Session
0851: EMailSender ems = new EMailSender();
0852: ems.setDBName(getDataContext());
0853: ems.addFileAttachments(fileNames);
0854: ems.send(sendToUser, subject, message);
0855: } catch (Exception e) {
0856: throw new DBException(myName + ":Error sending e-mail", e);
0857: }
0858: } /* sendFileTo(String, String, Vector) */
0859:
0860: /**
0861: * Once a user has validated his email address through the email validation
0862: * servlet, the user will receive this message giving previously requested
0863: * username/password.
0864: * <p/>
0865: * Creation date: (8/8/00 11:44:26 PM)
0866: * author: Adam Rossi, PlatinumSolutions, Inc.
0867: *
0868: * @throws com.jcorporate.expresso.core.db.DBException
0869: * The exception description.
0870: */
0871: public void sendFollowUpEmail() throws DBException {
0872: try {
0873: String subject = "New Registration Complete - Welcome!";
0874: String dbContext = getDataContext();
0875:
0876: // We can't retrieve the passsword in plain text to transmit to the user
0877: // So we just create and set a new passord and send that over.
0878: String password = this .randomPassword();
0879: this .setPassword(password);
0880: this .update();
0881:
0882: StringBuffer sb = new StringBuffer();
0883:
0884: if (!"".equals(getFullName())) {
0885: sb.append("Dear " + getFullName() + ",");
0886: }
0887:
0888: sb.append("\n");
0889: sb.append("\n");
0890: sb.append("Thank you for registering");
0891:
0892: String companyName = Setup.getValue(dbContext,
0893: "CompanyName");
0894: String homePageURL = Setup.getValue(dbContext,
0895: "HomePageURL");
0896:
0897: if (companyName != null && !"".equals(companyName)) {
0898: sb.append(" with " + companyName);
0899: }
0900: if (homePageURL != null && !"".equals(homePageURL)) {
0901: sb.append(" at " + homePageURL);
0902: }
0903:
0904: sb.append("!");
0905: sb.append("\n");
0906: sb.append("\n");
0907: sb
0908: .append("Your account is now active. Below is the information "
0909: + "you will need to log in.");
0910: sb.append("\n");
0911: sb
0912: .append("Please keep this information in a safe place.We hope "
0913: + "you enjoy the site and");
0914: sb.append("\n");
0915: sb.append("look forward to your participation.");
0916: sb.append("\n");
0917: sb.append("\n");
0918: sb.append("Login Name: " + getLoginName());
0919: sb.append("\n");
0920: sb.append("Password: " + password);
0921: sb.append("\n");
0922: sb.append("\n");
0923:
0924: if (companyName != null && !"".equals(companyName)) {
0925: sb.append("Thank you from all of us at " + companyName
0926: + ".");
0927: }
0928:
0929: sb.append("\n");
0930:
0931: if (companyName != null && !"".equals(homePageURL)) {
0932: sb.append(homePageURL);
0933: }
0934:
0935: sb.append("\n");
0936:
0937: String message = sb.toString();
0938: notify(subject, message);
0939: } catch (Exception e) {
0940: throw new DBException(
0941: "Error in sending account verification follow up message to "
0942: + getLoginName() + " at " + getEmail()
0943: + ": " + e.toString());
0944: }
0945: } /* sendFollowUpEmail() */
0946:
0947: public void setAccountStatus(String accountStatus)
0948: throws DBException {
0949: setField("AccountStatus", accountStatus);
0950: } /* setAccountStatus(String) */
0951:
0952: public void setEmail(String email) throws DBException {
0953: setField("EMail", email);
0954: } /* setEmail(String) */
0955:
0956: public void setEmailValCode(String code) throws DBException {
0957: setField("EmailValCode", code);
0958: } /* setEmailValCode(String) */
0959:
0960: public void setLoginName(String loginName) throws DBException {
0961: setField("LoginName", loginName);
0962: } /* setLoginName(String) */
0963:
0964: public void setPassword(String password) throws DBException {
0965: setField("Passwd", password);
0966: } /* setPassword(String) */
0967:
0968: public void setRegComplete(boolean status) throws DBException {
0969: String statusString = "N";
0970:
0971: if (status) {
0972: statusString = "Y";
0973: }
0974:
0975: setField("RegComplete", statusString);
0976: } /* setRegistrationComplete(String) */
0977:
0978: public void setRegistrationDomain(String domain) throws DBException {
0979: RegistrationDomain rd = new RegistrationDomain();
0980: rd.setDataContext(getDataContext());
0981: rd.setField("Name", domain);
0982:
0983: if (rd.find()) {
0984: setField("RegDomId", rd.getField("RegDomId"));
0985: } else {
0986: throw new DBException("Registration domain \"" + domain
0987: + "\" has not been defined.");
0988: }
0989: } /* setRegistrationDomain(String) */
0990:
0991: /**
0992: * @see com.jcorporate.expresso.core.dbobj.SecuredDBObject#setupFields
0993: */
0994: public void setupFields() throws DBException {
0995: setTargetTable("USERSTABLE");
0996: setDescription("User Information - Single Database");
0997: setCharset("ISO-8859-1");
0998: addField("ExpUid", "auto-inc", 0, false, "User Id");
0999: addField("LoginName", "char", 30, false, "User Login Name");
1000: addField("Passwd", "varchar", 30, true, "Password");
1001: addField("EMail", "varchar", 80, false, "User E-mail Address");
1002: addField("RegDomId", "int", 0, false, "Registration Domain Id");
1003: addField("AccountStatus", "char", 1, false,
1004: "Is User Account Active?");
1005: addField("RegComplete", "char", 1, false,
1006: "Has User Completed Registration?");
1007: addField("CreateDate", "datetime", 0, false,
1008: "Account Creation Date");
1009: addField("UpdateDate", "datetime", 0, false,
1010: "Account Update Date");
1011: addField("EmailValCode", "varchar", 30, true,
1012: "Validation code for Email");
1013: addField(FULL_NAME, "varchar", 80, true, "User Full Name");
1014:
1015: //Set up the string filters.
1016: setStringFilter("LoginName", "stripFilter");
1017:
1018: //Nobody should even put special characters here
1019: setStringFilter("UserName", "stripFilter");
1020:
1021: //Nobody should even put special characters here
1022: setStringFilter("EMail", "stripFilter");
1023:
1024: //Nobody should even put special characters here
1025: setStringFilter("Passwd", "rawFilter");
1026:
1027: //Must all all characters through or Password gets mucked up.
1028: setStringFilter("UserName", "rawFilter");
1029:
1030: //The default for the field anyway, but included for completeness' sake
1031: setStringFilter("EmailValCode", "stripFilter");
1032:
1033: //This only has HEX strings.. no special chars
1034: addKey("ExpUid");
1035: setSecret("Passwd");
1036: setSecret("EmailValCode");
1037: setMultiValued("AccountStatus");
1038: setMultiValued("RegComplete");
1039: setMultiValued("RegDomId");
1040: setLookupObject("RegDomId",
1041: "com.jcorporate.expresso.services.dbobj.RegistrationDomain");
1042: setReadOnly("CreateDate");
1043: setReadOnly("UpdateDate");
1044: this .addIndex("LoginNames", "LoginName", true);
1045: this .addIndex("EMails", "EMail", false);
1046: addDetail(
1047: "com.jcorporate.expresso.services.dbobj.GroupMembers",
1048: "ExpUid", "ExpUid");
1049: } /* setupFields() */
1050:
1051: public void setUserName(String name) throws DBException {
1052: setField("UserName", name);
1053: } /* setUserName(String) */
1054:
1055: /**
1056: * @throws DBException
1057: */
1058: public void update() throws DBException {
1059: if (noConfig) {
1060: throw new DBException(noConfigMessage);
1061: }
1062:
1063: setCheckZeroUpdate(false);
1064:
1065: // Check that another user with same email doesn't exist already
1066: SingleDBUserInfo anotherUser = new SingleDBUserInfo();
1067:
1068: if (!getField("EMail").equalsIgnoreCase("none")) {
1069: anotherUser.setDataContext(getDataContext());
1070: anotherUser.setEmail(getField("EMail"));
1071:
1072: if (anotherUser.find()
1073: && (anotherUser.getUid() != getUid())) {
1074: throw new DBException(
1075: "Another user with the same email address \""
1076: + getField("EMail")
1077: + "\" already exists");
1078: }
1079: }
1080:
1081: // If this site uses email as login name, force login name equal to email
1082: boolean useEmailAsLogin = false;
1083:
1084: try {
1085: useEmailAsLogin = ConfigManager
1086: .getContext(getDataContext()).useEmailAsLogin();
1087: } catch (ConfigurationException ce) {
1088: throw new DBException(ce);
1089: }
1090: if (useEmailAsLogin) {
1091: if (getField("LoginName").equals("")) {
1092: setField("LoginName", getField("EMail"));
1093: }
1094: } else {
1095:
1096: // This site has separate login name, make sure same login name doesn't exist already
1097: anotherUser.clear();
1098: anotherUser.setDataContext(getDataContext());
1099: anotherUser.setLoginName(getField("LoginName"));
1100:
1101: if (anotherUser.find()
1102: && (anotherUser.getUid() != getUid())) {
1103: throw new DBException(
1104: "Another user with the same login \""
1105: + getField("LoginName")
1106: + "\" already exists");
1107: }
1108: }
1109: if (getField("UserName").equals("")) {
1110: setField("UserName", getField("LoginName"));
1111: }
1112: // If a User is added without a status, we set the AccountStatus to "I"
1113: // for security reasons
1114: if (getField("AccountStatus").equals("")) {
1115: setField("AccountStatus", "I");
1116: }
1117: // Set the registration domain id
1118: if (getRegistrationDomain().equals("")) {
1119: setRegistrationDomain("default");
1120: }
1121:
1122: RegistrationDomain rd = new RegistrationDomain();
1123: rd.setDataContext(getDataContext());
1124: rd.setField("Name", getRegistrationDomain());
1125:
1126: if (!rd.find()) {
1127: throw new DBException("Regsitration domain \""
1128: + getRegistrationDomain()
1129: + "\" has not been defined");
1130: }
1131:
1132: setField("RegDomId", rd.getField("RegDomId"));
1133:
1134: // Check value of registration valid flag
1135: if (getField("RegComplete").equals("")) {
1136: setField("RegComplete", "N");
1137: }
1138: // We should always have a CreateDate
1139: if (getField("CreateDate").equals("")) {
1140: setField("CreateDate", DateTime.getDateTimeForDB(this
1141: .getDataContext()));
1142: }
1143: // We should always have a UpdateDate
1144: if (getField("UpdateDate").equals("")) {
1145: setField("UpdateDate", DateTime.getDateTimeForDB(this
1146: .getDataContext()));
1147: }
1148:
1149: super .update();
1150: User user = new User();
1151: user.setDataContext(this .getDataContext());
1152: user.updateNotify(this );
1153:
1154: } /* update() */
1155:
1156: public void retrieve() throws DBException {
1157: if (noConfig) {
1158: throw new DBException(noConfigMessage);
1159: }
1160:
1161: super .retrieve();
1162: }
1163:
1164: /**
1165: * the primary group of this user is appropriate for unix-like purposes,
1166: * such as setting the group for a file permission
1167: *
1168: * @return name of the primary group of this user; null if no group is primary
1169: */
1170: public String getPrimaryGroup() throws DBException {
1171: return DefaultUserInfo.getPrimaryGroup(this );
1172: }
1173:
1174: } /* SingleDBUserInfo */
|