/**
* 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");
}
}
}
}
}