/* * UserBean.java * * This work is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, * or (at your option) any later version. * * This work is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * * Copyright (c) 2004-2006 Per Cederberg. All rights reserved. */ package org.liquidsite.app.template; import java.util.ArrayList; import org.liquidsite.core.content.ContentException; import org.liquidsite.core.content.ContentSecurityException; import org.liquidsite.core.content.Domain; import org.liquidsite.core.content.Group; import org.liquidsite.core.content.User; import org.liquidsite.core.web.RequestSession; import org.liquidsite.util.log.Log; /** * A user template bean. This class is used to insert the user object * in the into the template data model. * * @author Per Cederberg, <per at percederberg dot net> * @version 1.0 */ public class UserBean extends TemplateBean { /** * The class logger. */ private static final Log LOG = new Log(UserBean.class); /** * The session email verification user attribute. This session * key value stores the login name for the user for which an * email verification request was sent. This value is required * for security reasons so that only the correct user can be * unlocked. * * @see #VERIFY_KEY_ATTRIBUTE * @see #sendEmailVerification(String, String, String) * @see #verifyEmail(String) */ private static final String VERIFY_USER_ATTRIBUTE = "template.verification.user"; /** * The session email verification key attribute. This session key * value is only sent to the user email address and is not * retreivable through the public template API. If the user can * provide the correct verification key, the user object is * unlocked for saving by anonymous users. This is used to * overwrite the user password without requiring a correct login * (used for password "recovery"). * * @see #VERIFY_USER_ATTRIBUTE * @see #sendEmailVerification(String, String, String) * @see #verifyEmail(String) */ private static final String VERIFY_KEY_ATTRIBUTE = "template.verification.key"; /** * The request user. */ private User user; /** * The modified login username. */ private String login; /** * The modified password. */ private String password; /** * The modified real name. */ private String realName; /** * The modified email. */ private String email; /** * The list of group additions. The list contains the group * objects to add to the user when saving. */ private ArrayList groupAdds; /** * The list of group removals. The list contains the group * objects to remove from the user when saving. */ private ArrayList groupRemoves; /** * The email verified flag. This flag is set when the user has * provided the correct verification key, i.e. has been able to * read an email that was previously sent. Once the email has * been verified, this object is unlocked for saving by anonymous * users. This can be used to overwrite the user password without * requiring a correct login (used for password "recovery"). */ private boolean emailVerified; /** * Creates a new user template bean. * * @param context the bean context * @param user the request user */ UserBean(BeanContext context, User user) { super(context); this.user = user; this.login = null; this.password = null; this.realName = null; this.email = null; this.emailVerified = false; } /** * Returns a description of this user. The description will * contain the real user name and the login name. * * @return a description of this user, or * an empty string if the user doesn't exist */ public String toString() { if (user == null) { return ""; } else { return user.getRealName() + " (" + user.getName() + ")"; } } /** * Returns the user login name. * * @return the user login name, or * an empty string if the user doesn't exist */ public String getLogin() { if (user == null) { return ""; } else { return user.getName(); } } /** * Sets the login user name. This action will not take effect * until this object is saved. Note that login names of existing * users cannot be modified. * * @param login the new use login name */ public void setLogin(String login) { if (user == null) { this.login = login; } } /** * Sets the user password. This action will not take effect * until this object is saved. * * @param password the new user password */ public void setPassword(String password) { this.password = password; } /** * Returns the real user name. * * @return the real user name, or * an empty string if the user doesn't exist */ public String getRealName() { if (user == null) { return ""; } else { return user.getRealName(); } } /** * Sets the real user name. This action will not take effect * until this object is saved. * * @param realName the new real user name */ public void setRealName(String realName) { this.realName = realName; } /** * Returns the user email address. * * @return the user email address, or * an empty string if the user doesn't exist */ public String getEmail() { if (user == null) { return ""; } else { return user.getEmail(); } } /** * Sets the user e-mail address. This action will not take effect * until this object is saved. * * @param email the new user e-mail address */ public void setEmail(String email) { this.email = email; } /** * Checks if the users has administration privileges in the * domain. For superusers, this method will always return true. * * @return true if the user is a domain admin, or * false otherwise */ public boolean getDomainadmin() { Domain domain; try { domain = user.getDomain(); if (domain == null) { return true; } else { return domain.hasAdminAccess(user); } } catch (ContentException e) { LOG.error(e.getMessage()); return false; } } /** * Returns the superuser flag for the user. * * @return true if the user is a superuser, or * false otherwise */ public boolean getSuperuser() { if (user == null) { return false; } else { return user.isSuperUser(); } } /** * Returns a list of the group names to which the user belong. * * @return a list of group names */ public ArrayList getGroups() { ArrayList list = new ArrayList(); Group[] groups; try { if (user != null) { groups = user.getGroups(); for (int i = 0; i < groups.length; i++) { list.add(groups[i].getName()); } } } catch (ContentException e) { LOG.error(e.getMessage()); } return list; } /** * Checks if the user is member of a named group. * * @param name the group name * * @return true if the user is a member of the group, or * false otherwise */ public boolean inGroup(String name) { ArrayList groups = getGroups(); return groups.contains(name); } /** * Adds this user to the specified group. The user will only be * added if the group exists and is public. Furthermore, this * action will not take effect until this object is saved. * * @param name the group name */ public void groupAdd(String name) { Group group = getContext().findGroup(name); if (group != null && group.isPublic()) { if (groupAdds == null) { groupAdds = new ArrayList(); } groupAdds.add(group); } } /** * Removes this user to the specified group. The user will only * be removed if the group exists and is public. Furthermore, * this action will not take effect until this object is saved. * * @param name the group name */ public void groupRemove(String name) { Group group = getContext().findGroup(name); if (group != null && group.isPublic()) { if (groupRemoves == null) { groupRemoves = new ArrayList(); } groupRemoves.add(group); } } /** * Saves all the modifications for this user to the database. * * @return true if the user could be saved, or * false otherwise */ public boolean save() { Domain domain = getContextRequest().getEnvironment().getDomain(); User currentUser; boolean created = false; String msg; int i; if (user == null) { if (login == null || login.equals("")) { LOG.info("failed to create user, no login name given"); return false; } user = getContext().createUser(login); if (user == null) { LOG.error("couldn't create user with login " + login + " in domain " + domain); return false; } created = true; } if (password != null) { user.setPassword(password); } if (realName != null) { user.setRealName(realName); } if (email != null) { user.setEmail(email); } if (groupAdds != null) { for (i = 0; i < groupAdds.size(); i++) { user.addToGroup((Group) groupAdds.get(i)); } } if (groupRemoves != null) { for (i = 0; i < groupRemoves.size(); i++) { user.removeFromGroup((Group) groupRemoves.get(i)); } } try { currentUser = getContext().findUser("").user; if (currentUser == null && (created || emailVerified)) { user.save(user); } else { user.save(currentUser); } if (created) { msg = "created new user "; } else { msg = "modified user "; } msg += user + " in domain " + domain.getName() + ", saved by "; if (emailVerified) { msg += "anonymous (email verification)"; } else if (currentUser == null) { msg += "anonymous"; } else { msg += currentUser; } LOG.info(msg); login = null; password = null; realName = null; email = null; groupAdds = null; groupRemoves = null; } catch (ContentException e) { LOG.error(e.getMessage()); if (created) { user = null; } return false; } catch (ContentSecurityException e) { LOG.error(e.getMessage()); if (created) { user = null; } return false; } return true; } /** * Sends an email verification request to the user. The request * email will only be sent if the user exists, has an email * address set and has not been modified. A verfication key will * be inserted into the email subject and text where a specified * replacement text matches. This allows for customizing the * verification email while only sending the secret validation * key in the email. * * @param subject the mail subject * @param text the mail text * @param replaceText the key replacement text * * @return true if the email verification was sent, or * false otherwise * * @see #verifyEmail(String) */ public boolean sendEmailVerification(String subject, String text, String replaceText) { RequestSession session; String key; if (user == null || email != null) { return false; } key = User.generatePassword(); session = getContextRequest().getSession(); session.setAttribute(VERIFY_USER_ATTRIBUTE, user.getName()); session.setAttribute(VERIFY_KEY_ATTRIBUTE, key); subject = replace(subject, replaceText, key); text = replace(text, replaceText, key); return getContext().sendMail(user.getEmail(), subject, text); } /** * Verifies the user email address and unlocks this user. The * verification is done by comparing a previously sent key with * the specified one. If the two keys match, the user email is * considered verified and this user object is unlocked for save * operations by an anonymous user. * * @param key the verification key * * @return true if the verification was correct, or * false otherwise */ public boolean verifyEmail(String key) { RequestSession session; String verificationUser; String verificationKey; session = getContextRequest().getSession(); verificationUser = (String) session.getAttribute(VERIFY_USER_ATTRIBUTE); verificationKey = (String) session.getAttribute(VERIFY_KEY_ATTRIBUTE); emailVerified = user != null && verificationUser != null && verificationKey != null && verificationUser.equals(user.getName()) && verificationKey.equals(key); return emailVerified; } /** * Replaces all occurrencies of a text within a string. * * @param str the string to process * @param from the text to replace * @param to the new text to use * * @return the processed string */ private String replace(String str, String from, String to) { int pos; do { pos = str.indexOf(from); if (pos >= 0) { str = str.substring(0, pos) + to + str.substring(pos + from.length()); } } while (pos >= 0); return str; } }