Commit 0940539f authored by Matija Obreza's avatar Matija Obreza

Fixed “Password reset” functionality

parent 730159b4
......@@ -23,4 +23,6 @@ public interface VerificationTokenRepository extends JpaRepository<VerificationT
VerificationToken findByPurposeAndUuid(String string, String tokenUuid);
VerificationToken findByUuid(String tokenUuid);
}
......@@ -20,9 +20,14 @@ import org.genesys2.server.model.impl.User;
public interface EMailVerificationService {
void sendVerificationEmail(User user, boolean isVerification);
void sendVerificationEmail(User user);
boolean validateEMail(String tokenUuid, String key);
void sendPasswordResetEmail(User user);
void cancelValidation(String tokenUuid);
boolean validateEMail(String tokenUuid, String key);
boolean changePassword(String tokenUuid, String key, String password);
}
......@@ -16,6 +16,9 @@
package org.genesys2.server.service.impl;
import java.text.MessageFormat;
import java.util.Locale;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
......@@ -33,9 +36,6 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.text.MessageFormat;
import java.util.Locale;
@Service
@Transactional(readOnly = true)
public class EMailVerificationServiceImpl implements EMailVerificationService {
......@@ -57,17 +57,25 @@ public class EMailVerificationServiceImpl implements EMailVerificationService {
@Value("${base.url}")
private String baseUrl;
@Override
@Transactional
public void sendVerificationEmail(User user, boolean isVerification) {
public void sendVerificationEmail(User user) {
// Generate new token
VerificationToken verificationToken = generateToken("email-verification", user.getUuid());
Article article=null;
Article article = contentService.getGlobalArticle("smtp.email-verification", Locale.ENGLISH);
if (isVerification){
article = contentService.getGlobalArticle("smtp.email-verification", Locale.ENGLISH);
}else {
article = contentService.getGlobalArticle("smtp.email-password", Locale.ENGLISH);
}
String mailSubject = article.getTitle();
String mailBody = MessageFormat.format(article.getBody(), baseUrl, verificationToken.getUuid(), user.getEmail(), verificationToken.getKey());
emailService.sendMail(user.getEmail(), user.getName(), mailSubject, mailBody);
}
@Override
@Transactional
public void sendPasswordResetEmail(User user) {
// Generate new token
VerificationToken verificationToken = generateToken("email-password", user.getUuid());
Article article = contentService.getGlobalArticle("smtp.email-password", Locale.ENGLISH);
String mailSubject = article.getTitle();
String mailBody = MessageFormat.format(article.getBody(), baseUrl, verificationToken.getUuid(), user.getEmail(), verificationToken.getKey());
......@@ -88,7 +96,7 @@ public class EMailVerificationServiceImpl implements EMailVerificationService {
@Override
@Transactional
public void cancelValidation(String tokenUuid) {
VerificationToken verificationToken = verificationTokenRepository.findByPurposeAndUuid("email-verification", tokenUuid);
VerificationToken verificationToken = verificationTokenRepository.findByUuid(tokenUuid);
if (verificationToken == null) {
LOG.warn("Canceling verification token failed. No such verification token " + tokenUuid);
} else {
......@@ -108,6 +116,7 @@ public class EMailVerificationServiceImpl implements EMailVerificationService {
if (!verificationToken.getKey().equals(key)) {
LOG.error("Email verification key invalid for token=" + verificationToken.getUuid() + " providedKey=" + key);
return false;
}
try {
......@@ -124,4 +133,33 @@ public class EMailVerificationServiceImpl implements EMailVerificationService {
return false;
}
@Override
@Transactional
public boolean changePassword(String tokenUuid, String key, String password) {
VerificationToken verificationToken = verificationTokenRepository.findByPurposeAndUuid("email-password", tokenUuid);
if (verificationToken == null) {
LOG.warn("No such verification token " + tokenUuid + " key=" + key);
return false;
}
if (!verificationToken.getKey().equals(key)) {
LOG.error("Password reset verification key invalid for token=" + verificationToken.getUuid() + " providedKey=" + key);
return false;
}
try {
User user = userService.getUserByUuid(verificationToken.getData());
userService.updatePassword(user.getId(), password);
// Remove token
verificationTokenRepository.delete(verificationToken);
return true;
} catch (UserException e) {
LOG.error(e.getMessage(), e);
}
return false;
}
}
......@@ -35,7 +35,7 @@ public class ArticleController extends BaseController {
@Autowired
private ContentService contentService;
@RequestMapping("{url}")
@RequestMapping("{url:.+}")
public String view(ModelMap model, @PathVariable(value = "url") String slug) {
_logger.debug("Viewing article " + slug);
......
......@@ -116,7 +116,7 @@ public class HtmlController extends BaseController {
if (!userService.exists(user.getEmail())) {
User newUser = userService.createAccount(user.getEmail(), user.getPassword(), user.getName());
emailVerificationService.sendVerificationEmail(newUser, true);
emailVerificationService.sendVerificationEmail(newUser);
return "redirect:/content/account-created";
} else {
......@@ -134,7 +134,8 @@ public class HtmlController extends BaseController {
}
@RequestMapping(value = "/forgot-password")
public String forgotPassword() {
public String forgotPassword(ModelMap model) {
model.addAttribute("blurp", contentService.getGlobalArticle("user.reset-password-instructions", getLocale()));
return "/user/email";
}
......
......@@ -107,7 +107,7 @@ public class UserProfileController extends BaseController {
public String sendEmail(ModelMap model, @PathVariable("uuid") String uuid) {
User user = userService.getUserByUuid(uuid);
emailVerificationService.sendVerificationEmail(user,true);
emailVerificationService.sendVerificationEmail(user);
return "redirect:/profile/" + user.getUuid();
}
......@@ -117,36 +117,18 @@ public class UserProfileController extends BaseController {
emailVerificationService.cancelValidation(tokenUuid);
return "redirect:/";
}
@RequestMapping(value = "/{tokenUuid:.+}/validate", method = RequestMethod.GET)
public String validateEmail(ModelMap model,
@PathVariable("tokenUuid") String tokenUuid,
@RequestParam(value = "email",required = false)String email) {
if (email!=null){
User user=userService.getUserByEmail(email);
model.addAttribute("uuid",user.getUuid());
model.addAttribute("isReset",true);
}
@RequestMapping(value = "/{tokenUuid:.+}/validate", method = RequestMethod.GET)
public String validateEmail(ModelMap model, @PathVariable("tokenUuid") String tokenUuid) {
model.addAttribute("tokenUuid", tokenUuid);
return "/user/validateemail";
}
@RequestMapping(value = "/{tokenUuid:.+}/validate", method = RequestMethod.POST)
public String validateEmail2(ModelMap model,
@PathVariable("tokenUuid") String tokenUuid,
@RequestParam(value = "key",required = true) String key,
@RequestParam(value = "uuid",required = false)String uuid,
@RequestParam(value = "isReset",required = false,defaultValue ="0")boolean isReset) {
public String validateEmail2(ModelMap model, @PathVariable("tokenUuid") String tokenUuid, @RequestParam(value = "key", required = true) String key) {
if (emailVerificationService.validateEMail(tokenUuid, key)) {
// Valid
if (isReset){
model.addAttribute("uuid",uuid);
return "/user/password";
}
return "redirect:/profile";
} else {
// Not valid
model.addAttribute("tokenUuid", tokenUuid);
......@@ -155,26 +137,37 @@ public class UserProfileController extends BaseController {
}
}
@RequestMapping(value = "/password/reset",method = RequestMethod.POST)
public String resetPassword(@RequestParam("email") String email){
User user = userService.getUserByEmail(email);
if(user!=null){
emailVerificationService.sendVerificationEmail(user,false);
}
@RequestMapping(value = "/password/reset", method = RequestMethod.POST)
public String resetPassword(ModelMap model, @RequestParam("email") String email) {
User user = userService.getUserByEmail(email);
return "redirect:/profile";
}
if (user != null) {
emailVerificationService.sendPasswordResetEmail(user);
}
@RequestMapping(value = "/{uuid}/password/update",method = RequestMethod.POST)
public String updatePassword(@PathVariable("uuid")String uuid,
@RequestParam("password")String password) throws UserException {
User user=userService.getUserByUuid(uuid);
return "redirect:/content/user.password-reset-email-sent";
}
userService.updatePassword(user.getId(),password);
@RequestMapping(value = "/{tokenUuid:.+}/pwdreset", method = RequestMethod.GET)
public String passwordReset(ModelMap model, @PathVariable("tokenUuid") String tokenUuid) {
model.addAttribute("tokenUuid", tokenUuid);
return "/user/password";
}
return "redirect:/profile";
}
@RequestMapping(value = "/{tokenUuid:.+}/pwdreset", method = RequestMethod.POST)
public String updatePassword(ModelMap model, @PathVariable("tokenUuid") String tokenUuid, @RequestParam(value = "key", required = true) String key,
@RequestParam("password") String password) throws UserException {
if (emailVerificationService.changePassword(tokenUuid, key, password)) {
return "redirect:/content/user.password-reset";
} else {
// Not valid
model.addAttribute("tokenUuid", tokenUuid);
model.addAttribute("error", "error");
return "/user/password";
}
}
@RequestMapping(value = "/{uuid:.+}/update", method = { RequestMethod.POST })
@PreAuthorize("hasRole('ADMINISTRATOR') || principal.user.uuid == #uuid")
......
......@@ -35,6 +35,7 @@ login.remember-me=Remember me
login.login-button=Login
login.register-now=Create an account
logout=Logout
login.forgot-password=Forgot password
# Registration
registration.page.title=Create a user account
......@@ -424,3 +425,6 @@ userprofile.password=Reset password
userprofile.enter.email=Enter your email
userprofile.enter.password=Enter new password
userprofile.email.send=Send email
verification.invalid-key=Token key is not valid.
verification.token-key=Validation key
{
"en": {
"title": "Reset password",
"body": "<h2><small>Genesys account</small><br/>Reset password</h2><p><a href=\"{0}/profile/{1}/validate?email={2}\">Recovery </a></p><h2>Validation key: {3}</h2><p>If you didn't make this request, <a href=\"{0}/profile/{1}/cancel\">click here to cancel</a>.</p><p>Thanks,<br/ >Genesys team</p>"
"body": "<h2><small>Genesys account</small><br/>Reset password</h2><p><a href=\"{0}/profile/{1}/pwdreset\">Recovery </a></p><h2>Validation key: {3}</h2><p>If you didn't make this request, <a href=\"{0}/profile/{1}/cancel\">click here to cancel</a>.</p><p>Thanks,<br/ >Genesys team</p>"
}
}
\ No newline at end of file
{
"en": {
"title": "Password changed",
"body": "<p>Your password is now updated. You may now use it to <a href=\"/profile\">log in</a>.</p>"
}
}
\ No newline at end of file
{
"en": {
"title": "Password reset",
"body": "<p>We've sent an email with further instructions to the specified email address. The email should arrive shortly.</p><p>Please check the <b>SPAM</b> or <b>Junk mail</b> folders!</p>"
}
}
\ No newline at end of file
{
"en": {
"title": "Resetting your password",
"body": "<p>To reset your password, you have to provide your registered email address.</p><p>In the unlikely case that the email address does not exist in our system, we will silently ignore your password reset request and pretend all was okay with your input.</p>"
}
}
\ No newline at end of file
......@@ -54,7 +54,6 @@
<prop key="hibernate.hbm2ddl.auto">${db.hbm2ddl}</prop>
<prop key="hibernate.search.default.indexBase">${lucene.indexDir}</prop>
<prop key="hibernate.search.default.exclusive_index_use">false</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
</props>
</property>
<property name="packagesToScan">
......
......@@ -35,15 +35,10 @@
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-3">
<a href="/forgot-password" id="forgot-password" >Forgot password</a>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-3">
<div class="col-lg-offset-2 col-lg-10">
<input type="submit" value="<spring:message code="login.login-button" />" class="btn btn-primary" />
<a href="registration" id="registration" class="btn btn-default"><spring:message code="login.register-now"/></a>
<a href="forgot-password" id="forgot-password" class="btn"><spring:message code="login.forgot-password"/></a>
</div>
</div>
</form>
......
......@@ -10,15 +10,18 @@
<h1>
<spring:message code="userprofile.password" />
</h1>
<form class="form-horizontal" action="<c:url value="/profile/password/reset"/>" method="post">
<div class="form-group">
<label for="email" class="col-lg-2 control-label"><spring:message code="userprofile.enter.email" /></label>
<div class="col-lg-3"><input type="text" id="email" name="email" class="span3 form-control" /></div>
<div class="col-lg-1">
<input type="submit" value="<spring:message code="userprofile.email.send" />" class="btn btn-primary" />
</div>
<%@include file="/WEB-INF/jsp/content/include/blurp-display.jsp"%>
<form class="form-horizontal" action="<c:url value="/profile/password/reset"/>" method="post">
<div class="form-group">
<label for="email" class="col-lg-2 control-label"><spring:message code="userprofile.enter.email" /></label>
<div class="col-lg-3"><input type="text" id="email" name="email" class="span3 form-control" /></div>
<div class="col-lg-1">
<input type="submit" value="<spring:message code="userprofile.email.send" />" class="btn btn-primary" />
</div>
</form>
</div>
</form>
</body>
</html>
\ No newline at end of file
......@@ -10,14 +10,24 @@
<h1>
<spring:message code="userprofile.password" />
</h1>
<form class="form-horizontal" action="<c:url value="/profile/${uuid}/password/update"/>" method="post">
<div class="form-group">
<label for="password" class="col-lg-2 control-label"><spring:message code="userprofile.enter.password" /></label>
<div class="col-lg-3"><input type="password" id="password" name="password" class="span3 form-control" /></div>
<div class="col-lg-1">
<input type="submit" value="<spring:message code="userprofile.password" />" class="btn btn-primary" />
</div>
<c:if test="${error ne null}">
<div class="alert alert-danger"><spring:message code="verification.invalid-key"/></div>
</c:if>
<form class="form-horizontal" action="<c:url value="/profile/${tokenUuid}/pwdreset"/>" method="post">
<div class="form-group">
<label for="password" class="col-lg-2 control-label"><spring:message code="verification.token-key" /></label>
<div class="col-lg-3"><input type="text" id="key" name="key" class="span1 form-control" maxlength="4" placeholder="..." value="" /></div>
</div>
<div class="form-group">
<label for="password" class="col-lg-2 control-label"><spring:message code="userprofile.enter.password" /></label>
<div class="col-lg-3"><input type="password" id="password" name="password" class="span3 form-control" value="" /></div>
</div>
<div class="form-group">
<div class="col-lg-1">
<input type="submit" value="<spring:message code="userprofile.password" />" class="btn btn-primary" />
</div>
</form>
</div>
</form>
</body>
</html>
\ No newline at end of file
......@@ -12,8 +12,7 @@
</h1>
<form role="form" class="form-vertical validate" action="<c:url value="/profile/${tokenUuid}/validate" />" method="post">
<input type="hidden" value="${isReset}" name="isReset">
<input type="hidden" value="${uuid}" name="uuid">
<div class="col-lg-3">
<input type="text" id="key" name="key" class="span1 form-control" maxlength="4"/>
</div>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment