/** * This file is part of Faktotum. * * * Faktotum 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. * * Faktotum 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 Faktotum. * * If not, see <http://www.gnu.org/licenses/>. */ package de.romankreisel.faktotum.beans; import java.util.Date; import java.util.List; import javax.ejb.EJB; import javax.ejb.Schedule; import javax.ejb.Stateless; import javax.persistence.NoResultException; import org.apache.commons.lang3.StringUtils; import de.romankreisel.faktotum.beans.CryptBean.AUTHENTICATION_SCHEME; import de.romankreisel.faktotum.dao.BundesbruderDao; import de.romankreisel.faktotum.dao.SessionDao; import de.romankreisel.faktotum.datamodel.BundesbruderEntity; import de.romankreisel.faktotum.datamodel.SessionEntity; import de.romankreisel.faktotum.exceptions.InvalidPasswordException; import de.romankreisel.faktotum.exceptions.UnknownUserException; /** * The AuthenticationBean contains the businesscode to authenticate users * * @author Roman Kreisel <mail@romankreisel.de> */ @Stateless public class AuthenticationBean extends FaktotumBean { @EJB private BundesbruderDao bundesbruderDao; @EJB private SettingBean settingBean; @EJB private CryptBean cryptBean; @EJB private SessionDao sessionDao; /** * @param sessionKey * @return */ public List<SessionEntity> getSessionsByKeyAndUsername(String sessionKey, String username) throws NoResultException { return this.sessionDao.findBySessionKeyAndUsername(sessionKey, username); } /** * The method representing a user-login. * * @param userName * The user to be logged in * @param password * The password to be used for login * @return If the login succeeds, the matching BundesBruderEntity will be * returned. Otherwise an exception is thrown * @throws UnknownUserException * if the user doesn't exist. * @throws InvalidPasswordException * if the password is invalid. */ public BundesbruderEntity login(String userName, String password) throws UnknownUserException, InvalidPasswordException { BundesbruderEntity bundesBruder = this.bundesbruderDao.findByUserName(userName); if (bundesBruder == null) { throw new UnknownUserException(); } String passwordToken = bundesBruder.getPassword(); if (StringUtils.isEmpty(passwordToken)) { throw new InvalidPasswordException("The given user has no password defined, login denied!"); } AUTHENTICATION_SCHEME authenticationScheme = (AUTHENTICATION_SCHEME) this.settingBean.getEnumSettingValue(SettingBean.SETTING_STRING_AUTH_SCHEME); if (!this.cryptBean.verify(passwordToken, password, authenticationScheme)) { throw new InvalidPasswordException(); } bundesBruder.setLastLogin(new Date()); this.bundesbruderDao.merge(bundesBruder); return bundesBruder; } /** * Logs in a user with a previously stored session key * * @param sessionKey * @param username * @return the logged in Bundesbruder or null, if no valid session could be * found in the database */ public BundesbruderEntity loginWithCookie(String sessionKey, String username) { if (StringUtils.isBlank(sessionKey)) { if (StringUtils.isNotBlank(username)) { this.getLogger().warning("Blocking attempt to login with blank session key for username " + username); } return null; } if (StringUtils.isBlank(username)) { if (StringUtils.isNotBlank(sessionKey)) { this.getLogger().warning("Blocking attempt to login with blank user name"); } return null; } List<SessionEntity> sessions = this.getSessionsByKeyAndUsername(sessionKey, username); for (SessionEntity session : sessions) { if (session != null) { Integer maxAgeInSeconds = this.settingBean.getIntegerSettingValue(SettingBean.SETTING_LONG_AUTH_SESSION_MAXAGE); long ageInSeconds = (System.currentTimeMillis() - session.getCreationTimestamp().getTime()) / 1000; if (ageInSeconds < maxAgeInSeconds) { session.setLastLogin(new Date()); this.sessionDao.merge(session); this.getLogger().info("Restored previously persisted session for " + session.getBundesbruder().getUserName()); return session.getBundesbruder(); } else { this.getLogger().warning("Sorry, session for " + session.getBundesbruder().getUserName() + " is too old and cannot be used anymore"); this.sessionDao.remove(session); } } } return null; } /** * Persist a new session to the database * * @param sessionKey * @param bundesbruder */ public void persistSession(String sessionKey, BundesbruderEntity bundesbruder) { // persist session to DB SessionEntity session = new SessionEntity(); session.setKey(sessionKey); session.setLastLogin(new Date()); session.setBundesbruder(bundesbruder); this.sessionDao.persist(session); this.getLogger().fine("Session for " + bundesbruder.getUserName() + " was persisted"); } /** * Removes outdated sessions from the system */ @Schedule(second = "0", minute = "0", hour = "0", persistent = false) public void removeOldSessions() { long startTime = System.currentTimeMillis(); long numberOfSessions = 0; List<SessionEntity> sessions = this.sessionDao.getAll(SessionEntity.class); if (sessions != null) { for (SessionEntity session : sessions) { if (session != null) { Integer maxAgeInSeconds = this.settingBean.getIntegerSettingValue(SettingBean.SETTING_LONG_AUTH_SESSION_MAXAGE); long ageInSeconds = (System.currentTimeMillis() - session.getCreationTimestamp().getTime()) / 1000; if (ageInSeconds >= maxAgeInSeconds) { numberOfSessions++; this.getLogger().warning( "Session " + session.getKey() + " for " + session.getBundesbruder().getUserName() + " is too old and cannot be used anymore - it will be removed"); this.sessionDao.remove(session); } } } } this.getLogger().info("Removed " + numberOfSessions + " old session(s) in " + (System.currentTimeMillis() - startTime) + " ms"); } /** * @param sessionKey * @param username */ public void removeSession(String sessionKey, String username) { List<SessionEntity> sessions = this.getSessionsByKeyAndUsername(sessionKey, username); if (sessions != null) { for (SessionEntity session : sessions) { if (session != null) { this.sessionDao.remove(session); this.getLogger().fine("Session was removed from persistence"); } } } } }