///////////////////////////////////////////////////////////////////////////// // // Project ProjectForge Community Edition // www.projectforge.org // // Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de) // // ProjectForge is dual-licensed. // // This community edition 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; version 3 of the License. // // This community edition 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, see http://www.gnu.org/licenses/. // ///////////////////////////////////////////////////////////////////////////// package org.projectforge.user; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.sql.DataSource; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.PredicateUtils; import org.projectforge.registry.Registry; import org.projectforge.web.UserFilter; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.orm.hibernate3.HibernateTemplate; public class LoginDefaultHandler implements LoginHandler { private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LoginDefaultHandler.class); private UserDao userDao; /** * Only needed if the data-base needs an update first (may-be the PFUserDO can't be read because of unmatching tables). */ private DataSource dataSource; private HibernateTemplate hibernateTemplate; /** * @see org.projectforge.user.LoginHandler#initialize(org.projectforge.registry.Registry) */ @Override public void initialize() { final Registry registry = Registry.instance(); userDao = registry.getDao(UserDao.class); dataSource = registry.getDataSource(); hibernateTemplate = registry.getHibernateTemplate(); } /** * @see org.projectforge.user.LoginHandler#checkLogin(java.lang.String, java.lang.String, boolean) */ @Override public LoginResult checkLogin(final String username, final String password) { final LoginResult loginResult = new LoginResult(); PFUserDO user = null; if (UserFilter.isUpdateRequiredFirst() == true) { // Only administrator login is allowed. The login is checked without Hibernate because the data-base schema may be out-dated thus // Hibernate isn't functioning. try { final PFUserDO resUser = getUserWithJdbc(username, password); if (resUser == null || resUser.getUsername() == null) { log.info("Admin login for maintenance (data-base update) failed for user '" + username + "' (user/password not found)."); return loginResult.setLoginResultStatus(LoginResultStatus.FAILED); } if (isAdminUser(resUser) == false) { return loginResult.setLoginResultStatus(LoginResultStatus.ADMIN_LOGIN_REQUIRED); } userDao.getUserGroupCache().internalSetAdminUser(resUser); // User is now marked as admin user. return loginResult.setLoginResultStatus(LoginResultStatus.SUCCESS).setUser(resUser); } catch (final Exception ex) { log.error(ex.getMessage(), ex); } } else { user = userDao.authenticateUser(username, password); } if (user != null) { log.info("User with valid username/password: " + username + "/****"); if (user.hasSystemAccess() == false) { log.info("User has no system access (is deleted/deactivated): " + user.getDisplayUsername()); return loginResult.setLoginResultStatus(LoginResultStatus.LOGIN_EXPIRED); } else { return loginResult.setLoginResultStatus(LoginResultStatus.SUCCESS).setUser(user); } } else { log.info("User login failed: " + username + "/****"); return loginResult.setLoginResultStatus(LoginResultStatus.FAILED); } } /** * Only administrator login is allowed. The login is checked without Hibernate because the data-base schema may be out-dated thus * Hibernate isn't functioning. * @param jdbc * @param username * @param password * @return * @throws SQLException */ private PFUserDO getUserWithJdbc(final String username, final String password) throws SQLException { final JdbcTemplate jdbc = new JdbcTemplate(dataSource); String sql = "select pk, firstname, lastname, password, password_salt from t_pf_user where username=? and deleted=false and deactivated=false and restricted_user=false"; PFUserDO user = null; try { user = loadUser(jdbc, sql, username, true); } catch (final Exception ex) { log.warn("This SQLException is only OK if you've a ProjectForge installation 5.2 or minor!"); sql = "select pk, firstname, lastname, password from t_pf_user where username=? and deleted=false and deactivated=false and restricted_user=false"; user = loadUser(jdbc, sql, username, false); } if (user == null) { return null; } final PasswordCheckResult passwordCheckResult = userDao.checkPassword(user, password); if (passwordCheckResult.isOK() == false) { log.warn("Login for admin user '" + username + "' in maintenance mode failed, wrong password."); return null; } return user; } /** * @param user * @param rs * @param username * @param withSaltString false before ProjectForge version 5.3. * @throws SQLException */ @SuppressWarnings({ "unchecked", "rawtypes"}) private PFUserDO loadUser(final JdbcTemplate jdbc, final String sql, final String username, final boolean withSaltString) throws SQLException { final PFUserDO user = (PFUserDO)jdbc.query(sql, new Object[] { username}, new ResultSetExtractor() { @Override public Object extractData(final ResultSet rs) throws SQLException, DataAccessException { if (rs.next() == true) { final PFUserDO user = new PFUserDO(); user.setUsername(username); final String password = rs.getString("password"); final int pk = rs.getInt("pk"); final String firstname = rs.getString("firstname"); final String lastname = rs.getString("lastname"); if (withSaltString == true) { final String saltString = rs.getString("password_salt"); user.setPasswordSalt(saltString); } user.setId(pk); user.setUsername(username).setFirstname(firstname).setLastname(lastname).setPassword(password); return user; } return null; } }); return user; } public boolean isAdminUser(final PFUserDO user) { final JdbcTemplate jdbc = new JdbcTemplate(dataSource); String sql = "select pk from t_group where name=?"; final int adminGroupId = jdbc.queryForInt(sql, new Object[] { ProjectForgeGroup.ADMIN_GROUP.getKey()}); sql = "select count(*) from t_group_user where group_id=? and user_id=?"; final int count = jdbc.queryForInt(sql, new Object[] { adminGroupId, user.getId()}); if (count != 1) { log.info("Admin login for maintenance (data-base update) failed for user '" + user.getUsername() + "' (user not member of admin group)."); return false; } return true; } /** * @see org.projectforge.user.LoginHandler#checkStayLoggedIn(org.projectforge.user.PFUserDO) */ @Override public boolean checkStayLoggedIn(final PFUserDO user) { final PFUserDO dbUser = userDao.getUserGroupCache().getUser(user.getId()); if (dbUser != null && dbUser.hasSystemAccess() == true) { return true; } log.warn("User is deleted/deactivated, stay-logged-in denied for the given user: " + user); return false; } /** * The assigned users are fetched. * @see org.projectforge.user.LoginHandler#getAllGroups() */ @SuppressWarnings("unchecked") @Override public List<GroupDO> getAllGroups() { try { List<GroupDO> list = hibernateTemplate.find("from GroupDO t"); if (list != null) { list = (List<GroupDO>) selectUnique(list); } return list; } catch (final Exception ex) { log.fatal( "******* Exception while getting groups from data-base (OK only in case of migration from older versions): " + ex.getMessage(), ex); return new ArrayList<GroupDO>(); } } /** * @see org.projectforge.user.LoginHandler#getAllUsers() */ @SuppressWarnings("unchecked") @Override public List<PFUserDO> getAllUsers() { try { return hibernateTemplate.find("from PFUserDO t"); } catch (final Exception ex) { log.fatal("******* Exception while getting users from data-base (OK only in case of migration from older versions): " + ex.getMessage(), ex); return new ArrayList<PFUserDO>(); } } /** * Do nothing. * @see org.projectforge.user.LoginHandler#afterUserGroupCacheRefresh(java.util.List, java.util.List) */ @Override public void afterUserGroupCacheRefresh(final Collection<PFUserDO> users, final Collection<GroupDO> groups) { } protected List< ? > selectUnique(final List< ? > list) { final List< ? > result = (List< ? >) CollectionUtils.select(list, PredicateUtils.uniquePredicate()); return result; } /** * This login handler doesn't support an external user management system. * @return false. * @see org.projectforge.user.LoginHandler#hasExternalUsermanagementSystem() */ @Override public boolean hasExternalUsermanagementSystem() { return false; } /** * Do nothing. * @see org.projectforge.user.LoginHandler#passwordChanged(org.projectforge.user.PFUserDO, java.lang.String) */ @Override public void passwordChanged(final PFUserDO user, final String newPassword) { // Do nothing. } /** * @see org.projectforge.user.LoginHandler#isPasswordChangeSupported(org.projectforge.user.PFUserDO) * @return always true. */ @Override public boolean isPasswordChangeSupported(final PFUserDO user) { return true; } }