fixed reset password process
This commit is contained in:
@ -21,6 +21,8 @@ import de.muehlencord.shared.account.business.account.entity.AccountLoginEntity;
|
|||||||
import de.muehlencord.shared.account.business.account.entity.AccountStatus;
|
import de.muehlencord.shared.account.business.account.entity.AccountStatus;
|
||||||
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
|
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
|
||||||
import de.muehlencord.shared.account.business.application.entity.ApplicationRoleEntity;
|
import de.muehlencord.shared.account.business.application.entity.ApplicationRoleEntity;
|
||||||
|
import de.muehlencord.shared.account.business.config.boundary.ConfigService;
|
||||||
|
import de.muehlencord.shared.account.business.config.entity.ConfigException;
|
||||||
import de.muehlencord.shared.account.business.instance.boundary.ApplicationPermissions;
|
import de.muehlencord.shared.account.business.instance.boundary.ApplicationPermissions;
|
||||||
import de.muehlencord.shared.account.business.mail.boundary.MailService;
|
import de.muehlencord.shared.account.business.mail.boundary.MailService;
|
||||||
import de.muehlencord.shared.account.business.mail.entity.MailException;
|
import de.muehlencord.shared.account.business.mail.entity.MailException;
|
||||||
@ -65,6 +67,9 @@ public class AccountControl implements Serializable {
|
|||||||
@Inject
|
@Inject
|
||||||
private ApplicationEntity application;
|
private ApplicationEntity application;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ConfigService configService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@AccountPU
|
@AccountPU
|
||||||
EntityManager em;
|
EntityManager em;
|
||||||
@ -109,7 +114,6 @@ public class AccountControl implements Serializable {
|
|||||||
return query.getResultList();
|
return query.getResultList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Lock(LockType.READ)
|
@Lock(LockType.READ)
|
||||||
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
|
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
|
||||||
public AccountEntity getAccountEntity(String userName, boolean loadRoles) {
|
public AccountEntity getAccountEntity(String userName, boolean loadRoles) {
|
||||||
@ -121,7 +125,6 @@ public class AccountControl implements Serializable {
|
|||||||
queryBuilder.append("WHERE a.username = :username");
|
queryBuilder.append("WHERE a.username = :username");
|
||||||
Query query = em.createQuery(queryBuilder.toString());
|
Query query = em.createQuery(queryBuilder.toString());
|
||||||
query.setParameter("username", userName);
|
query.setParameter("username", userName);
|
||||||
query.setHint("org.hibernate.cacheable", true);
|
|
||||||
try {
|
try {
|
||||||
return (AccountEntity) query.getSingleResult();
|
return (AccountEntity) query.getSingleResult();
|
||||||
} catch (NoResultException ex) {
|
} catch (NoResultException ex) {
|
||||||
@ -207,6 +210,7 @@ public class AccountControl implements Serializable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
public boolean initPasswordReset(String userName) {
|
public boolean initPasswordReset(String userName) {
|
||||||
try {
|
try {
|
||||||
AccountEntity account = getAccountEntity(userName, false);
|
AccountEntity account = getAccountEntity(userName, false);
|
||||||
@ -215,6 +219,11 @@ public class AccountControl implements Serializable {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (account.getAccountLogin() == null) {
|
||||||
|
LOGGER.error("No login for account {} defined, cannot reset password", userName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (account.getStatus().equals(AccountStatus.BLOCKED.name())) {
|
if (account.getStatus().equals(AccountStatus.BLOCKED.name())) {
|
||||||
LOGGER.warn("Account " + userName + " is locked, cannot initialize password reset");
|
LOGGER.warn("Account " + userName + " is locked, cannot initialize password reset");
|
||||||
return false;
|
return false;
|
||||||
@ -225,15 +234,15 @@ public class AccountControl implements Serializable {
|
|||||||
Date validTo = DateUtil.getCurrentTimeInUTC();
|
Date validTo = DateUtil.getCurrentTimeInUTC();
|
||||||
validTo = new Date(validTo.getTime() + 1000 * 600); // 10 minutes to react
|
validTo = new Date(validTo.getTime() + 1000 * 600); // 10 minutes to react
|
||||||
|
|
||||||
// TODO rework password reset
|
account.getAccountLogin().setPasswordResetHash(randomString);
|
||||||
// account.setPasswordResetHash(randomString);
|
account.getAccountLogin().setPasswordResetOngoing(true);
|
||||||
// account.setPasswordResetOngoing(true);
|
account.getAccountLogin().setPasswordResetValidTo(validTo);
|
||||||
// account.setPasswordResetValidTo(validTo);
|
|
||||||
mailService.sendPasswortResetStartEmail(account, randomString);
|
mailService.sendPasswortResetStartEmail(account, randomString);
|
||||||
|
|
||||||
|
em.merge(account.getAccountLogin());
|
||||||
em.merge(account);
|
em.merge(account);
|
||||||
return true;
|
return true;
|
||||||
} catch (MailException ex) {
|
} catch (MailException | ConfigException ex) {
|
||||||
LOGGER.error("Error while sending password reset mail. " + ex.toString());
|
LOGGER.error("Error while sending password reset mail. " + ex.toString());
|
||||||
if (LOGGER.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
LOGGER.debug("Error while sending password reset mail.", ex);
|
LOGGER.debug("Error while sending password reset mail.", ex);
|
||||||
@ -242,6 +251,7 @@ public class AccountControl implements Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
public boolean resetPassword(String userName, String newPassword, String resetPasswordToken) {
|
public boolean resetPassword(String userName, String newPassword, String resetPasswordToken) {
|
||||||
AccountEntity account = getAccountEntity(userName, false);
|
AccountEntity account = getAccountEntity(userName, false);
|
||||||
|
|
||||||
@ -251,11 +261,15 @@ public class AccountControl implements Serializable {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (account.getAccountLogin() == null) {
|
||||||
if (account.getPasswordResetOngoing() && (account.getPasswordResetHash() != null) && (account.getPasswordResetValidTo() != null)) {
|
// user has no defined login, cannot reset password
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (account.getAccountLogin().getPasswordResetOngoing() && (account.getAccountLogin().getPasswordResetHash() != null) && (account.getAccountLogin().getPasswordResetValidTo() != null)) {
|
||||||
Date now = DateUtil.getCurrentTimeInUTC();
|
Date now = DateUtil.getCurrentTimeInUTC();
|
||||||
String storedHash = account.getPasswordResetHash().trim();
|
String storedHash = account.getAccountLogin().getPasswordResetHash().trim();
|
||||||
if (account.getPasswordResetValidTo().after(now)) {
|
if (account.getAccountLogin().getPasswordResetValidTo().after(now)) {
|
||||||
if (storedHash.equals(resetPasswordToken)) {
|
if (storedHash.equals(resetPasswordToken)) {
|
||||||
// everything ok, reset password
|
// everything ok, reset password
|
||||||
executePasswordReset(account, newPassword);
|
executePasswordReset(account, newPassword);
|
||||||
@ -279,26 +293,26 @@ public class AccountControl implements Serializable {
|
|||||||
addLoginError(account);
|
addLoginError(account);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
return false; // FIMXE re-implement password reset
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void executePasswordReset(AccountEntity account, String newPassword) {
|
private void executePasswordReset(AccountEntity account, String newPassword) {
|
||||||
Date now = DateUtil.getCurrentTimeInUTC();
|
Date now = DateUtil.getCurrentTimeInUTC();
|
||||||
|
|
||||||
String hashedPassword = SecurityUtil.createPassword(newPassword);
|
String hashedPassword = SecurityUtil.createPassword(newPassword);
|
||||||
// account.setAccountPassword(hashedPassword);
|
if (account.getAccountLogin() == null) {
|
||||||
//
|
return;
|
||||||
// account.setPasswordResetOngoing(false);
|
}
|
||||||
// account.setPasswordResetHash(null);
|
account.getAccountLogin().setAccountPassword(hashedPassword);
|
||||||
// account.setPasswordResetValidTo(null);
|
account.getAccountLogin().setPasswordResetOngoing(false);
|
||||||
|
account.getAccountLogin().setPasswordResetHash(null);
|
||||||
|
account.getAccountLogin().setPasswordResetValidTo(null);
|
||||||
account.setLastUpdatedBy(account.getUsername());
|
account.setLastUpdatedBy(account.getUsername());
|
||||||
account.setLastUpdatedOn(now);
|
account.setLastUpdatedOn(now);
|
||||||
em.merge(account);
|
em.merge(account);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
public AccountLoginEntity updateSuccessFullLogin(AccountLoginEntity login, String byUser) {
|
public AccountLoginEntity updateSuccessFullLogin(AccountLoginEntity login, String byUser) {
|
||||||
Date now = DateUtil.getCurrentTimeInUTC();
|
Date now = DateUtil.getCurrentTimeInUTC();
|
||||||
// a scucessful login ends a password reset procedure
|
// a scucessful login ends a password reset procedure
|
||||||
@ -315,10 +329,12 @@ public class AccountControl implements Serializable {
|
|||||||
return updateLogin(login);
|
return updateLogin(login);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
public AccountLoginEntity updateLogin(AccountLoginEntity login) {
|
public AccountLoginEntity updateLogin(AccountLoginEntity login) {
|
||||||
return em.merge(login);
|
return em.merge(login);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
public void updateLogin(AccountEntity account) {
|
public void updateLogin(AccountEntity account) {
|
||||||
if (account.getAccountLogin() == null) {
|
if (account.getAccountLogin() == null) {
|
||||||
// TODO connect to IPRS - how can an account ask for an updated login if the user cannot login
|
// TODO connect to IPRS - how can an account ask for an updated login if the user cannot login
|
||||||
@ -327,35 +343,39 @@ public class AccountControl implements Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
public void addLoginError(AccountEntity account) {
|
public void addLoginError(AccountEntity account) {
|
||||||
// TODO reimplement
|
if (account.getAccountLogin() == null) {
|
||||||
// try {
|
LOGGER.error("No login defined for {}", account.getUsername());
|
||||||
// Date now = DateUtil.getCurrentTimeInUTC();
|
} else {
|
||||||
// account.setLastFailedLogin(now);
|
try {
|
||||||
// account.setFailureCount(account.getFailureCount() + 1);
|
Date now = DateUtil.getCurrentTimeInUTC();
|
||||||
//
|
account.getAccountLogin().setLastFailedLogin(now);
|
||||||
// int maxFailedLogins = Integer.parseInt(configService.getConfigValue( "account.maxFailedLogins"));
|
account.getAccountLogin().setFailureCount(account.getAccountLogin().getFailureCount() + 1);
|
||||||
// if ((account.getFailureCount() >= maxFailedLogins) && (!account.getStatus().equals("LOCKED"))) { // TOD add status enum
|
|
||||||
// // max failed logins reached, disabling user
|
int maxFailedLogins = Integer.parseInt(configService.getConfigValue("account.maxFailedLogins"));
|
||||||
// LOGGER.info("Locking account " + account.getUsername() + " due to " + account.getFailureCount() + " failed logins");
|
if ((account.getAccountLogin().getFailureCount() >= maxFailedLogins) && (!account.getStatus().equals("LOCKED"))) { // TOD add status enum
|
||||||
// account.setStatus(AccountStatus.BLOCKED.name());
|
// max failed logins reached, disabling user
|
||||||
// }
|
LOGGER.info("Locking account " + account.getUsername() + " due to " + account.getAccountLogin().getFailureCount() + " failed logins");
|
||||||
//
|
account.setStatus(AccountStatus.BLOCKED.name());
|
||||||
// // on a failed login request, disable password reset
|
}
|
||||||
// account.setPasswordResetOngoing(false);
|
|
||||||
// account.setPasswordResetHash(null);
|
// on a failed login request, disable password reset
|
||||||
// account.setPasswordResetValidTo(null);
|
account.getAccountLogin().setPasswordResetOngoing(false);
|
||||||
//
|
account.getAccountLogin().setPasswordResetHash(null);
|
||||||
// account.setLastUpdatedBy("system");
|
account.getAccountLogin().setPasswordResetValidTo(null);
|
||||||
// account.setLastUpdatedOn(now);
|
|
||||||
// em.merge(account);
|
account.setLastUpdatedBy("system");
|
||||||
// } catch (ConfigException ex) {
|
account.setLastUpdatedOn(now);
|
||||||
// if (LOGGER.isDebugEnabled()) {
|
em.merge(account);
|
||||||
// LOGGER.debug(ex.toString(), ex);
|
} catch (ConfigException ex) {
|
||||||
// } else {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
// LOGGER.error(ex.toString());
|
LOGGER.debug(ex.toString(), ex);
|
||||||
// }
|
} else {
|
||||||
// }
|
LOGGER.error(ex.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public AccountLoginEntity createLoginWithRandomPassword() {
|
public AccountLoginEntity createLoginWithRandomPassword() {
|
||||||
|
|||||||
@ -15,16 +15,22 @@
|
|||||||
*/
|
*/
|
||||||
package de.muehlencord.shared.account.business.mail.boundary;
|
package de.muehlencord.shared.account.business.mail.boundary;
|
||||||
|
|
||||||
import de.muehlencord.shared.account.business.mail.entity.MailTemplateException;
|
|
||||||
import de.muehlencord.shared.account.business.account.entity.AccountConfigurationKey;
|
|
||||||
import de.muehlencord.shared.account.business.account.entity.AccountEntity;
|
import de.muehlencord.shared.account.business.account.entity.AccountEntity;
|
||||||
import de.muehlencord.shared.account.business.account.entity.AccountLoginEntity;
|
import de.muehlencord.shared.account.business.account.entity.AccountLoginEntity;
|
||||||
|
import de.muehlencord.shared.account.business.config.boundary.ConfigService;
|
||||||
|
import de.muehlencord.shared.account.business.config.entity.ConfigException;
|
||||||
import de.muehlencord.shared.account.business.mail.entity.MailDatamodel;
|
import de.muehlencord.shared.account.business.mail.entity.MailDatamodel;
|
||||||
import de.muehlencord.shared.account.business.mail.entity.MailException;
|
import de.muehlencord.shared.account.business.mail.entity.MailException;
|
||||||
|
import de.muehlencord.shared.account.business.mail.entity.MailTemplateException;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.ejb.EJB;
|
|
||||||
import javax.ejb.Stateless;
|
import javax.ejb.Stateless;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.mail.Message;
|
import javax.mail.Message;
|
||||||
@ -38,13 +44,6 @@ import javax.mail.internet.MimeMessage;
|
|||||||
import javax.mail.internet.MimeMultipart;
|
import javax.mail.internet.MimeMultipart;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import de.muehlencord.shared.account.business.account.entity.AccountConfigurationValue;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -57,16 +56,19 @@ public class MailService implements Serializable {
|
|||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(MailService.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(MailService.class);
|
||||||
|
|
||||||
@EJB
|
@Inject
|
||||||
private MailTemplateService mailTemplateService;
|
private MailTemplateService mailTemplateService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@AccountConfigurationValue(key = AccountConfigurationKey.BaseUrl)
|
ConfigService configService;
|
||||||
private String baseUrl;
|
|
||||||
|
|
||||||
@Inject
|
// @Inject
|
||||||
@AccountConfigurationValue(key = AccountConfigurationKey.PasswordResetUrl)
|
// @AccountConfigurationValue(key = AccountConfigurationKey.BaseUrl)
|
||||||
private String passwordResetUrl;
|
// private String baseUrl;
|
||||||
|
|
||||||
|
// @Inject
|
||||||
|
// @AccountConfigurationValue(key = AccountConfigurationKey.PasswordResetUrl)
|
||||||
|
// private String passwordResetUrl;
|
||||||
|
|
||||||
// TODO make this configurable by injection from the application it uses it, fall back to defaul mail setup if not available
|
// TODO make this configurable by injection from the application it uses it, fall back to defaul mail setup if not available
|
||||||
@Resource(lookup = "java:jboss/mail/ssgMail")
|
@Resource(lookup = "java:jboss/mail/ssgMail")
|
||||||
@ -189,7 +191,7 @@ public class MailService implements Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String sendPasswortResetStartEmail(AccountEntity account, String token) throws MailException {
|
public String sendPasswortResetStartEmail(AccountEntity account, String token) throws MailException, ConfigException {
|
||||||
MailDatamodel model = new MailDatamodel(account);
|
MailDatamodel model = new MailDatamodel(account);
|
||||||
|
|
||||||
/* old aproach via FacesContext - add this back as fallback if injection point if not configured
|
/* old aproach via FacesContext - add this back as fallback if injection point if not configured
|
||||||
@ -209,10 +211,14 @@ public class MailService implements Serializable {
|
|||||||
} catch (MalformedURLException ex) {
|
} catch (MalformedURLException ex) {
|
||||||
throw new MailException("Error while sending email.", ex);
|
throw new MailException("Error while sending email.", ex);
|
||||||
}
|
}
|
||||||
String baseUrl = configService.getConfigValue(configKey);
|
|
||||||
String resetUrlWithToken = baseUrl + "/login.xhtml?token=" + token;
|
String resetUrlWithToken = baseUrl + "/login.xhtml?token=" + token;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
String passwordResetUrl = configService.getConfigValue("backend.passwordreset.url");
|
||||||
|
String baseUrl = configService.getConfigValue("backend.base.url");
|
||||||
String resetUrlWithToken = passwordResetUrl + "?token=" + token;
|
String resetUrlWithToken = passwordResetUrl + "?token=" + token;
|
||||||
|
|
||||||
model.addParameter("url", baseUrl);
|
model.addParameter("url", baseUrl);
|
||||||
model.addParameter("resetUrl", resetUrlWithToken);
|
model.addParameter("resetUrl", resetUrlWithToken);
|
||||||
return sendHTMLMail(account.getEmailaddress(), "Reset your password", model, "password_reset_html");
|
return sendHTMLMail(account.getEmailaddress(), "Reset your password", model, "password_reset_html");
|
||||||
|
|||||||
Reference in New Issue
Block a user