// --------------------------------------------------------------------------- // jWebSocket - User Class // Copyright (c) 2010 jWebSocket.org, Alexander Schulze, Innotrade GmbH // --------------------------------------------------------------------------- // This program is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 3 of the License, or (at your // option) any later version. // This program 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 Lesser General Public License for // more details. // You should have received a copy of the GNU Lesser General Public License along // with this program; if not, see <http://www.gnu.org/licenses/lgpl.html>. // --------------------------------------------------------------------------- package org.jwebsocket.security; import java.util.Set; import org.apache.log4j.Logger; /** * implements a user with all its data fields and roles. * @author aschulze */ public class User { private static Logger log = Logger.getLogger(User.class); /** * The maximum number of login tries until the account gets locked. */ public static int MAX_PWD_FAIL_COUNT = 3; /** * The state of the user is unknown. This state is used only as default * when instantiating a new user. This value should not be saved. */ public static int ST_UNKNOWN = -1; /** * The user is already registered but not activated. * A user needs to get activated to get access to the system. */ public static int ST_REGISTERED = 0; /** * The user is activated and has access to the system according to his * rights and roles. */ public static int ST_ACTIVE = 1; /** * The user is (temporarily) inactive. * He needs to get (re-)activated to get access to the system. */ public static int ST_INACTIVE = 2; /** * The user is (temporarily) locked, eg due to too much logins * with wrong credentials. * He needs to gets unlocked again to get access to the system. */ public static int ST_LOCKED = 3; /** * The user is deleted, he can't log in and is not reachable for others. * The row is kept in the database for reference purposes only and * to keep the database consistent (eg for logs, journal or transactions). * He can be activated again to get access to the system. */ public static int ST_DELETED = 4; private Integer userId = null; private String loginname = null; private String title = null; private String company = null; private String firstname = null; private String lastname = null; private String password = null; private Integer pwdFailCount = 0; private int status = ST_UNKNOWN; private String defaultLocale = null; private String city = null; private String address = null; private String zipcode = null; private String country_code = null; private String email = null; private String phone = null; private String fax = null; private int sessionTimeout = 0; private Roles mRoles = new Roles(); /** * creates a new user instance by loginname, firstname, lastname, password * and roles. * @param aLoginName * @param aFirstname * @param aLastname * @param aPassword * @param aRoles */ public User(String aLoginName, String aFirstname, String aLastname, String aPassword, Roles aRoles) { loginname = aLoginName; firstname = aFirstname; lastname = aLastname; password = aPassword; mRoles = aRoles; } /** * returns the id of the user. The id is supposed to be used for storing * users in a database. It's the primary key. * @return id of the user. */ public Integer getUserId() { return userId; } /** * specifies the id of the user. The id is supposed to be used for storing * users in a database. It's the primary key. * @param userId */ public void setUserId(Integer userId) { this.userId = userId; } /** * returns the login name of the user. The login name needs to be unique * for each user. It's the key to identify a user within jWebSocket. * @return */ public String getLoginname() { return loginname; } /** * specifies the login name of the user. The login name needs to be unique * for each user. It's the key to identify a user within jWebSocket. * @param aLoginName */ public void setLoginname(String aLoginName) { this.loginname = aLoginName; } /** * returns the title of the user (e.g. mr./mrs.). * @return the title */ public String getTitle() { return title; } /** * specifies the title of the user (e.g. mr./mrs.). * @param aTitle */ public void setTitle(String aTitle) { this.title = aTitle; } /** * returns the company of the user. * @return the company */ public String getCompany() { return company; } /** * specifies the company of the user. * @param company the company to set */ public void setCompany(String company) { this.company = company; } /** * returns the firstname of the user. * @return */ public String getFirstname() { return firstname; } /** * specifies the firstname of the user. * @param firstName */ public void setFirstname(String firstName) { this.firstname = firstName; } /** * returns the lastname of the user. * @return */ public String getLastname() { return lastname; } /** * specifies the lastname of the user. * @param lastName */ public void setLastname(String lastName) { this.lastname = lastName; } /** * checks if the given password matches the user password, it is not * possible to obtain the password for the user. If the password is not * correct the fail counter is incremented. If the fail counter exceeds * the configured maximum the account gets locked. If the password is * correct the password fail counter is resetted. * @param aPassword * @return */ public boolean checkPassword(String aPassword) { boolean lOk = (aPassword != null && aPassword.equals(password)); if (lOk) { resetPwdFailCount(); } else { incPwdFailCount(); } return lOk; } /** * changes the password of the user, to change it the caller needs to know * the original password. For initialization purposes e.g. during the * startup process the original password is null. * The password cannot be reset to null. * @param aOldPW original password or null of password is set first time. * @param aNewPW new password, nust not be <tt>null</tt>. * @return true if the password was changed successfully otherwise false. */ public boolean changePassword(String aOldPW, String aNewPW) { if (aOldPW != null && aNewPW != null && password.equals(aOldPW)) { password = aNewPW; return true; } return false; } @Override public String toString() { return loginname + ": " + firstname + " " + lastname; } // TODO: potential security hole: don't allow to change roles w/o a special permission! /** * specifies the roles of the user. * @param aRoles */ public void setRoles(Roles aRoles) { this.mRoles = aRoles; } /** * returns the user's current status (one of the ST_XXX constants). * @return */ public int getStatus() { return status; } // TODO: potential security hole: don't allow to e.g. unlock a user w/o a special permission! /** * specifies the user's current status (one of the ST_XXX constants). * @param status */ public void setStatus(int status) { this.status = status; } /** * returns the user's current password fail counter. Please consider that * since currently the users are stored in memory only the fail counter * is reset after an application restart. * @return */ public Integer getPwdFailCount() { return pwdFailCount; } // TODO: potential security hole: don't allow to reset password fail counter w/o a special permission! /** * explicitly sets the password fail counter for the user. * @param aPwdFailCount */ public void setPwdFailCount(Integer aPwdFailCount) { pwdFailCount = aPwdFailCount; } // TODO: potential security hole: don't allow to roll over password fail counter! /** * increments the password fail counter. If the password fail counter * exceeds the maximum value the user gets locked. * This is called after the application passed an incorrect password to * the checkPassword method. * @return */ private Integer incPwdFailCount() { setPwdFailCount(pwdFailCount + 1); if (pwdFailCount >= MAX_PWD_FAIL_COUNT) { lock(); } return pwdFailCount; } // TODO: potential security hole: don't allow to reset password fail counter w/o a special permission! /** * resets the password fail counter and saves the user back to the database. * This is called after a successful authentication. */ private void resetPwdFailCount() { setPwdFailCount(0); } /** * returns the default locale for the user.For future use in an * internationalized environment. * @return */ public String getDefaultLocale() { return defaultLocale; } /** * specifies the default locale for the user. For future use in an * internationalized environment. * @param default_locale */ public void setDefaultLocale(String default_locale) { this.defaultLocale = default_locale; } /** * returns the city of the user. * @return */ public String getCity() { return city; } /** * specifies the city of the user. * @param city */ public void setCity(String city) { this.city = city; } /** * returns the address of the user. * @return */ public String getAddress() { return address; } /** * specifies the address of the user. * @param address */ public void setAddress(String address) { this.address = address; } /** * returns the zip code of the user. * @return */ public String getZipcode() { return zipcode; } /** * specifies the zip code of the user. * @param zipcode */ public void setZipcode(String zipcode) { this.zipcode = zipcode; } /** * returns the country code of the user, either 2 digits like "DE" or * 5 digits like "EN-US". * @return */ public String getCountryCode() { return country_code; } /** * specifies the country code of the user, either 2 digits like "DE" or * 5 digits like "EN-US". * @param country_code */ public void setCountryCode(String country_code) { this.country_code = country_code; } /** * returns the phone number of the user. * @return */ public String getPhone() { return phone; } /** * specifies the phone number of the user. * @param aPhone */ public void setPhone(String aPhone) { this.phone = aPhone; } /** * returns the email address of the user. * @return */ public String getEmail() { return email; } /** * specifies the email address of the user. * @param aEmail */ public void setEmail(String aEmail) { this.email = aEmail; } /** * returns the fax number of the user. * @return */ public String getFax() { return fax; } /** * specifies the fax number of the user. * @param aFax */ public void setFax(String aFax) { this.fax = aFax; } /** * returns the individual session timeout for the user - * not yet supported. * @return */ public int getSessionTimeout() { return sessionTimeout; } /** * specifies the individual session timeout for the user - * not yet supported. * @param session_timeout */ public void setSessionTimeout(int session_timeout) { this.sessionTimeout = session_timeout; } /** * sets the user to locked state. He cannot login anymore after that. */ public void lock() { this.setStatus(ST_LOCKED); } // TODO: potential security hole: don't allow to unlock account w/o a special permission! /** * Releases the user's locked state. He cannot login again after that. */ public void unlock() { this.setStatus(ST_ACTIVE); } /** * checks if the user has a certain right. The right is passed as a string * which associates the key of the right. * @param aRight * @return */ public boolean hasRight(String aRight) { return mRoles.hasRight(aRight); } /** * checks if the user has a certain role. The role is passed as a string * which associates the key of the role. * @param aRole * @return */ public boolean hasRole(String aRole) { return mRoles.hasRole(aRole); } /** * returns the roles of the user. * @return */ public Roles getRoles() { return mRoles; } /** * returns an unmodifiable set of rights for this user instance. * @return */ public Rights getRights(String aNamespace) { // the getRights method of the Roles class already delivers an // unmodifiable set of rights Rights lRights = new Rights(); for (Right lRight : mRoles.getRights()) { if (aNamespace == null || lRight.getId().startsWith(aNamespace)) { lRights.addRight(lRight); } } return lRights; } /** * returns an unmodifiable set of rights for this user instance. * @return */ public Rights getRights() { return getRights(null); } /** * returns an unmodifiable set of role ids for this user instance. * @return */ public Set<String> getRoleIdSet() { return mRoles.getRoleIdSet(); } /** * returns an unmodifiable set of right ids for this user instance. * @return */ public Set<String> getRightIdSet() { return getRights().getRightIdSet(); } }