Commit e7571522 by jhrabal

wip

parent 4a595b2d
...@@ -76,6 +76,12 @@ ...@@ -76,6 +76,12 @@
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!-- email configuration -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency> <dependency>
<groupId>commons-httpclient</groupId> <groupId>commons-httpclient</groupId>
......
...@@ -106,3 +106,64 @@ CREATE TABLE RESET_PASSWORD_TOKEN ( ...@@ -106,3 +106,64 @@ CREATE TABLE RESET_PASSWORD_TOKEN (
CONSTRAINT PK_RESET_PASSWORD_TOKEN PRIMARY KEY(ID) CONSTRAINT PK_RESET_PASSWORD_TOKEN PRIMARY KEY(ID)
); );
CREATE INDEX RESET_PASSWORD_TOKEN_LOGIN_IDX ON RESET_PASSWORD_TOKEN(LOGIN); CREATE INDEX RESET_PASSWORD_TOKEN_LOGIN_IDX ON RESET_PASSWORD_TOKEN(LOGIN);
CREATE TABLE EMAIL (
ID INT8 NOT NULL,
LOCKED BOOLEAN DEFAULT FALSE,
TO_BE_SENT BOOLEAN DEFAULT FALSE,
STATUS VARCHAR(10),
SENT_DATE TIMESTAMP,
TO_BE_SENT_DATE TIMESTAMP,
EMAIL_FROM VARCHAR(250) NOT NULL,
SUBJECT VARCHAR(1000),
TEXT_CONTENT TEXT,
HTML_CONTENT TEXT,
ATTEMPTS NUMERIC(2, 0),
ERROR VARCHAR(2000),
RECEIPT BOOLEAN,
CONSTRAINT PK_EMAIL PRIMARY KEY(ID)
);
CREATE INDEX EMAIL_IDX ON EMAIL(TO_BE_SENT, LOCKED);
CREATE TABLE EMAIL_RECIPIENT (
ID INT8 NOT NULL,
EMAIL_ID INT8 NOT NULL,
ADDRESS VARCHAR(100),
RECIPIENT_TYPE VARCHAR(10),
CONSTRAINT PK_EMAIL_RECIPIENT PRIMARY KEY(ID),
CONSTRAINT FK_RECIPIENT_EMAIL FOREIGN KEY (EMAIL_ID) REFERENCES EMAIL(ID)
);
CREATE INDEX EMAIL_RECIPIENT_IDX ON EMAIL_RECIPIENT(EMAIL_ID);
CREATE TABLE EMAIL_ATTACHMENT (
ID INT8 NOT NULL,
EMAIL_ID INT8 NOT NULL,
CID VARCHAR(100),
NAME VARCHAR(256),
MIME_TYPE VARCHAR(100),
SIZE NUMERIC(19,0),
DATA TEXT,
CONSTRAINT PK_EMAIL_ATTACHMENT PRIMARY KEY(ID),
CONSTRAINT FK_EMAIL_ATTACHMENT_EMAIL FOREIGN KEY (EMAIL_ID) REFERENCES EMAIL(ID)
);
CREATE INDEX EMAIL_ATTACHMENT_IDX ON EMAIL_ATTACHMENT(EMAIL_ID);
package com.jh.common.email;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import com.jh.common.jpa.AbstractIdEntity;
/**
* The Class Email.
*/
@Entity
@Table(name = "EMAIL")
public class Email extends AbstractIdEntity {
/** The locked. */
@Column(name = "LOCKED")
private Boolean locked;
/** The unit id. */
@Column(name = "UNIT_ID")
private Long unitId;
/** The email from. */
@Column(name = "EMAIL_FROM")
private String emailFrom;
/** The recipients. */
@OneToMany(mappedBy = "email", cascade = CascadeType.ALL)
private Set<EmailRecipient> recipients;
/** The subject. */
@Column(name = "SUBJECT")
private String subject;
/** The text. */
@Column(name = "TEXT_CONTENT")
private String text;
/** The html. */
@Column(name = "HTML_CONTENT")
private String html;
/** The to be sent. */
@Column(name = "TO_BE_SENT")
private Boolean toBeSent;
/** The status. */
@Column(name = "STATUS")
private String status;
/** The error. */
@Column(name = "ERROR")
private String error;
/** The receipt. */
@Column(name = "RECEIPT")
private Boolean receipt;
/** The attachments. */
@OneToMany(mappedBy = "email", cascade = CascadeType.ALL)
private Set<EmailAttachment> attachments;
/**
* Gets the locked.
*
* @return the locked
*/
public Boolean getLocked() {
return locked;
}
/**
* Sets the locked.
*
* @param locked the new locked
*/
public void setLocked(Boolean locked) {
this.locked = locked;
}
/**
* Gets the unit id.
*
* @return the unit id
*/
public Long getUnitId() {
return unitId;
}
/**
* Sets the unit id.
*
* @param unitId the new unit id
*/
public void setUnitId(Long unitId) {
this.unitId = unitId;
}
/**
* Gets the from.
*
* @return the from
*/
public String getFrom() {
return emailFrom;
}
/**
* Sets the from.
*
* @param from the new from
*/
public void setFrom(String from) {
this.emailFrom = from;
}
/**
* Gets the recipients.
*
* @return the recipients
*/
public Set<EmailRecipient> getRecipients() {
return recipients;
}
/**
* Sets the recipients.
*
* @param recipients the new recipients
*/
public void setRecipients(Set<EmailRecipient> recipients) {
this.recipients = recipients;
}
/**
* Gets the subject.
*
* @return the subject
*/
public String getSubject() {
return subject;
}
/**
* Sets the subject.
*
* @param subject the new subject
*/
public void setSubject(String subject) {
this.subject = subject;
}
/**
* Gets the text.
*
* @return the text
*/
public String getText() {
return text;
}
/**
* Sets the text.
*
* @param text the new text
*/
public void setText(String text) {
this.text = text;
}
/**
* Gets the html.
*
* @return the html
*/
public String getHtml() {
return html;
}
/**
* Sets the html.
*
* @param html the new html
*/
public void setHtml(String html) {
this.html = html;
}
/**
* Gets the status.
*
* @return the status
*/
public String getStatus() {
return status;
}
/**
* Sets the status.
*
* @param status the new status
*/
public void setStatus(String status) {
this.status = status;
}
/**
* Gets the attachments.
*
* @return the attachments
*/
public Set<EmailAttachment> getAttachments() {
return attachments;
}
/**
* Sets the attachments.
*
* @param attachments the new attachments
*/
public void setAttachments(Set<EmailAttachment> attachments) {
this.attachments = attachments;
}
/**
* Gets the to be sent.
*
* @return the to be sent
*/
public Boolean getToBeSent() {
return toBeSent;
}
/**
* Sets the to be sent.
*
* @param toBeSent the new to be sent
*/
public void setToBeSent(Boolean toBeSent) {
this.toBeSent = toBeSent;
}
/**
* Gets the email from.
*
* @return the email from
*/
public String getEmailFrom() {
return emailFrom;
}
/**
* Sets the email from.
*
* @param emailFrom the new email from
*/
public void setEmailFrom(String emailFrom) {
this.emailFrom = emailFrom;
}
/**
* Gets the error.
*
* @return the error
*/
public String getError() {
return error;
}
/**
* Sets the error.
*
* @param error the new error
*/
public void setError(String error) {
this.error = error;
}
/**
* Gets the receipt.
*
* @return the receipt
*/
public Boolean getReceipt() {
return receipt;
}
/**
* Sets the receipt.
*
* @param receipt the new receipt
*/
public void setReceipt(Boolean receipt) {
this.receipt = receipt;
}
}
/*
* Created on 8. 8. 2017 8:36:15
*
*/
package com.jh.common.email;
import java.util.Base64;
import java.util.Base64.Encoder;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.jh.common.jpa.AbstractIdEntity;
/**
* The Class EmailAttachment.
*
* @author Jan Hrabal
*/
@Entity
@Table(name = "EMAIL_ATTACHMENT")
public class EmailAttachment extends AbstractIdEntity {
/** The name. */
@Column(name = "NAME")
private String name;
/** The mime type. */
@Column(name = "MIME_TYPE")
private String mimeType;
/** The data. */
//base 64
@Column(name = "DATA")
private String data;
/** The email. */
@ManyToOne @org.hibernate.annotations.NotFound(action = org.hibernate.annotations.NotFoundAction.IGNORE)
@JoinColumn(name = "EMAIL_ID")
@JsonIgnore
private Email email;
/** The cid. */
@Column(name = "CID")
private String cid;
/**
* Gets the name.
*
* @return the name
*/
public String getName() {
return name;
}
/**
* Sets the name.
*
* @param name the new name
*/
public void setName(String name) {
this.name = name;
}
/**
* Gets the mime type.
*
* @return the mime type
*/
public String getMimeType() {
return mimeType;
}
/**
* Sets the mime type.
*
* @param mimeType the new mime type
*/
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
/**
* Gets the data.
*
* @return the data
*/
public String getData() {
return data;
}
/**
* Sets the data.
*
* @param data the new data
*/
public void setData(String data) {
this.data = data;
}
/**
* Sets the data.
*
* @param bytes the new data
*/
public void setData(byte[] bytes) {
if (bytes == null || bytes.length == 0) {
setData((String) null);
return;
}
Encoder encoder = Base64.getEncoder();
setData(new String(encoder.encode(bytes)));
}
/**
* Gets the email.
*
* @return the email
*/
public Email getEmail() {
return email;
}
/**
* Sets the email.
*
* @param email the new email
*/
public void setEmail(Email email) {
this.email = email;
}
/**
* Gets the cid.
*
* @return the cid
*/
public String getCid() {
return cid;
}
/**
* Sets the cid.
*
* @param cid the new cid
*/
public void setCid(String cid) {
this.cid = cid;
}
}
package com.jh.common.email;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* The Class EmailConfig.
*/
@Configuration
@EnableScheduling
public class EmailConfig {
}
package com.jh.common.email;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.jh.common.jpa.AbstractIdEntity;
/**
* The Class EmailRecipient.
*/
@Entity
@Table(name = "EMAIL_RECIPIENT")
public class EmailRecipient extends AbstractIdEntity {
/** The email. */
@JsonIgnore
@ManyToOne @org.hibernate.annotations.NotFound(action = org.hibernate.annotations.NotFoundAction.IGNORE)
@JoinColumn(name = "EMAIL_ID")
private Email email;
/** The address. */
@Column(name = "ADDRESS")
private String address;
/** The recipient type. */
@Column(name = "RECIPIENT_TYPE")
@Enumerated(EnumType.STRING)
private RecipientType recipientType;
/**
* Instantiates a new email recipient.
*/
public EmailRecipient() {
}
/**
* Instantiates a new email recipient.
*
* @param address the address
* @param recipientType the recipient type
*/
public EmailRecipient(String address, RecipientType recipientType) {
this.address = address;
this.recipientType = recipientType;
}
/**
* Gets the email.
*
* @return the email
*/
public Email getEmail() {
return email;
}
/**
* Sets the email.
*
* @param email the new email
*/
public void setEmail(Email email) {
this.email = email;
}
/**
* Gets the address.
*
* @return the address
*/
public String getAddress() {
return address;
}
/**
* Sets the address.
*
* @param address the new address
*/
public void setAddress(String address) {
this.address = address;
}
/**
* Gets the recipient type.
*
* @return the recipient type
*/
public RecipientType getRecipientType() {
return recipientType;
}
/**
* Sets the recipient type.
*
* @param recipientType the new recipient type
*/
public void setRecipientType(RecipientType recipientType) {
this.recipientType = recipientType;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((address == null) ? 0 : address.hashCode());
result = prime * result + ((recipientType == null) ? 0 : recipientType.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (!(obj instanceof EmailRecipient)) {
return false;
}
EmailRecipient other = (EmailRecipient) obj;
if (address == null) {
if (other.address != null) {
return false;
}
} else if (!address.equals(other.address)) {
return false;
}
if (recipientType != other.recipientType) {
return false;
}
return true;
}
}
package com.jh.common.email;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import javax.persistence.Query;
import org.hibernate.query.NativeQuery;
import org.springframework.stereotype.Repository;
import com.jh.common.jpa.AbstractHibernateRepository;
/**
* The Class EmailRepository.
*/
@Repository
public class EmailRepository extends AbstractHibernateRepository {
/**
* Fetch emails to send.
*
* @return the list
*/
@SuppressWarnings("unchecked")
public List<Email> fetchEmailsToSend() {
String sql = "select ID from EMAIL where LOCKED<>true and TO_BE_SENT=true for update limit 100";
NativeQuery<Number> nq = nativeQuery(sql);
//fetch ids
List<Number> result = nq.getResultList();
List<Long> ids = result.stream().map((n) -> n.longValue()).collect(Collectors.toList());
if (!ids.isEmpty()) {
lockEmails(ids, true);
Query q = entityManager.createQuery("select distinct e from Email e left join fetch e.attachments left join fetch e.recipients where e.id in (:ids)");
q.setParameter("ids", ids);
return q.getResultList();
}
return Collections.emptyList();
}
/**
* Lock emails.
*
* @param ids the ids
* @param locked the locked
*/
public void lockEmails(Collection<Long> ids, boolean locked) {
if (ids == null || ids.isEmpty()) {
return;
}
String hql = "update Email e set e.locked=:locked where e.id in (:ids)";
Query q = entityManager.createQuery(hql);
q.setParameter("locked", locked);
q.setParameter("ids", ids);
q.executeUpdate();
}
}
package com.jh.common.email;
/**
* The Interface EmailService.
*/
public interface EmailService {
/**
* Send email.
*
* @param email the email
* @return the email
*/
Email sendEmail(Email email);
}
\ No newline at end of file
package com.jh.common.email;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Objects;
import javax.mail.internet.MimeMessage;
import javax.transaction.Transactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.util.StringUtils;
/**
* The Class LocalEmailService.
*/
public class LocalEmailService implements EmailService {
/** The Constant LOG. */
private static final Logger LOG = LoggerFactory.getLogger(LocalEmailService.class);
/** The repo. */
@Autowired
private EmailRepository repo;
/** The mail sender. */
@Autowired
private JavaMailSender mailSender;
/** The email sender address. */
@Value("${email.sender.from:}")
private String emailSenderAddress;
/**
* @param email
* @return
* @see com.jh.module.email.EmailService#sendEmail(com.jh.module.email.Email)
*/
@Override
@Transactional
public Email sendEmail(Email email) {
email.setToBeSent(true);
email.setLocked(false);
if (!StringUtils.hasText(email.getEmailFrom())) {
email.setEmailFrom(emailSenderAddress);
}
if (email.getRecipients() != null) {
for (EmailRecipient er : email.getRecipients()) {
er.setEmail(email);
}
}
if (email.getAttachments() != null) {
for (EmailAttachment ea : email.getAttachments()) {
ea.setEmail(email);
}
}
repo.save(email);
return email;
}
/**
* Scheduled.
*/
@Scheduled(fixedDelayString = "${localEmail.scheduled.interval.ms:120000}")
@Transactional
public void scheduled() {
List<Email> emails = repo.fetchEmailsToSend();
if (emails == null || emails.isEmpty()) {
return;
}
LOG.info("Going to send {} emails", emails.size());
for (Email email : emails) {
doSendEmail(email);
}
}
/**
* TODO.
*
* @param email the email
*/
private void doSendEmail(Email email) {
MimeMessage msg = mailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(msg, true);
//send receipt?
if (Objects.equals(email.getReceipt(), true)) {
msg.addHeader("Disposition-Notification-To", email.getEmailFrom());
}
//TODO add tracking-number
msg.addHeader("X-Email-RefId", String.valueOf(email.getId()));
//use properly configured (reverse DNS) sender address?
if (StringUtils.hasText(emailSenderAddress)) {
helper.setFrom(emailSenderAddress);
if (StringUtils.hasText(email.getFrom())) {
helper.setReplyTo(email.getFrom());
}
} else {
helper.setFrom(email.getFrom());
}
List<String> to = new ArrayList<>();
List<String> cc = new ArrayList<>();
List<String> bcc = new ArrayList<>();
if (email.getRecipients() != null) {
for (EmailRecipient r : email.getRecipients()) {
RecipientType rt = r.getRecipientType();
switch(rt) {
case BCC:
bcc.add(r.getAddress());
break;
case CC:
cc.add(r.getAddress());
break;
case TO:
default:
to.add(r.getAddress());
}
}
}
String[] s = new String[0];
helper.setTo(to.toArray(s));
helper.setCc(cc.toArray(s));
helper.setBcc(bcc.toArray(s));
helper.setSubject(email.getSubject());
helper.setText(email.getText());
if (StringUtils.hasText(email.getHtml())) {
helper.setText(email.getHtml(), true);
}
if (email.getAttachments() != null) {
for (EmailAttachment a : email.getAttachments()) {
if (a.getData() != null) {
byte[] bytes = Base64.getDecoder().decode(a.getData().getBytes());
if (StringUtils.hasText(a.getCid())) {
helper.addInline(a.getCid(), new ByteArrayResource(bytes), a.getMimeType());
} else {
helper.addAttachment(a.getName(), new ByteArrayResource(bytes), a.getMimeType());
}
}
}
}
mailSender.send(msg);
email.setStatus("SENT");
} catch (Exception e) {
e.printStackTrace();
email.setStatus("FAILED");
email.setError(e.getMessage());
}
email.setToBeSent(false);
email.setLocked(false);
}
}
package com.jh.common.email;
/**
* The Enum RecipientType.
*/
public enum RecipientType {
/** The to. */
TO,
/** The cc. */
CC,
/** The bcc. */
BCC
}
package com.jh.common.email;
import java.net.URI;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
/**
* The Class RestEmailService.
*/
@SuppressWarnings("unused")
public class RestEmailService implements EmailService {
/** The rest template. */
protected RestTemplate restTemplate;
/** The username. */
private String username;
/** The password. */
private String password;
/** The unit id. */
private String unitId;
/** The url. */
private String url;
/** The uri. */
private URI uri;
/**
* Inits the.
*
* @throws Exception the exception
*/
@PostConstruct
public void init() throws Exception {
uri = new URI(url);
}
/**
* {@inheritDoc}
* @see com.jh.module.email.EmailService#sendEmail(com.jh.module.email.Email)
*/
@Override
public Email sendEmail(Email email) {
//TODO
RequestEntity<Email> request = new RequestEntity<>(email, HttpMethod.POST, uri);
ResponseEntity<Email> response = restTemplate.exchange(request, Email.class);
return email;
}
/**
* Sets the rest template.
*
* @param restTemplate the new rest template
*/
@Autowired
public void setRestTemplate(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
/**
* Sets the username.
*
* @param username the new username
*/
@Value("${email.username:}")
public void setUsername(String username) {
this.username = username;
}
/**
* Sets the password.
*
* @param password the new password
*/
@Value("${email.password:}")
public void setPassword(String password) {
this.password = password;
}
/**
* Sets the unit id.
*
* @param unitId the new unit id
*/
@Value("${email.unitId:}")
public void setUnitId(String unitId) {
this.unitId = unitId;
}
/**
* Sets the url.
*
* @param url the new url
*/
@Value("${email.url:}")
public void setUrl(String url) {
this.url = url;
}
}
/*
'use strict';
const http = require('http');
//TODO
module.exports = function(config = {}) {
//TODO validate config
const
login = config.login,
password = config.password,
unitId = config.unitId,
hostname = config.hostname || 'localhost',
port = config.port || 3033,
path = '/api/email';
if (!unitId) {
throw new Error("Parameter unitId is required");
}
//TODO
return function(message) {
//TODO validate email...
if (!message) {
return Promise.reject(new Error("Email is required"));
}
//TODO
const email = Object.assign({}, message);
email.unit_id = unitId;
//async request
return new Promise(function(resolve, reject) {
const postData = JSON.stringify(email);
const options = {
hostname: hostname,
port: port,
path: path,
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=UTF-8',
'Content-Length': Buffer.byteLength(postData)
}
};
const req = http.request(options, (res) => {
let resobj = "";
//res.setEncoding('utf8');
res.on('data', (chunk) => {
resobj += chunk;
});
res.on('end', () => {
if (res.statusCode > 199 && res.statusCode < 300) {
resolve(JSON.parse(resobj));
} else {
reject(JSON.parse(resobj));
}
});
});
req.on('error', (e) => {
//console.error(`problem with request: ${e.message}`);
reject(e);
});
// write data to request body
req.write(postData);
req.end();
});
}
}
*/
\ No newline at end of file
...@@ -145,7 +145,7 @@ public class AuthApiController { ...@@ -145,7 +145,7 @@ public class AuthApiController {
return ResponseEntity.notFound().build(); return ResponseEntity.notFound().build();
} }
Utils.sleep(250); Utils.sleep(250);
authService.generateResetToken(request.getLogin()); String token = authService.generateResetToken(request.getLogin());
return ResponseEntity.accepted().build(); return ResponseEntity.accepted().build();
} }
...@@ -158,7 +158,7 @@ public class AuthApiController { ...@@ -158,7 +158,7 @@ public class AuthApiController {
Utils.sleep(250); Utils.sleep(250);
String token = resetPassword.getToken(); String token = resetPassword.getToken();
if (!StringUtils.hasText(token)) { if (!StringUtils.hasText(token)) {
return new ResponseEntity<>(Collections.singletonList(new AuthError(null, "BadRequest")), HttpStatus.BAD_REQUEST); return new ResponseEntity<>(Collections.singletonList(new AuthError(null, "NO_TOKEN")), HttpStatus.BAD_REQUEST);
} }
List<AuthError> errors = new ArrayList<>(); List<AuthError> errors = new ArrayList<>();
......
...@@ -8,6 +8,7 @@ import com.jh.common.jpa.AbstractHibernateRepository; ...@@ -8,6 +8,7 @@ import com.jh.common.jpa.AbstractHibernateRepository;
import com.jh.common.security.PasswordHash; import com.jh.common.security.PasswordHash;
import com.jh.common.security.PasswordUtils; import com.jh.common.security.PasswordUtils;
import com.jh.common.security.model.AppUser; import com.jh.common.security.model.AppUser;
import com.jh.common.security.model.ResetPasswordToken;
public class AppUserRepository extends AbstractHibernateRepository { public class AppUserRepository extends AbstractHibernateRepository {
...@@ -34,5 +35,22 @@ public class AppUserRepository extends AbstractHibernateRepository { ...@@ -34,5 +35,22 @@ public class AppUserRepository extends AbstractHibernateRepository {
return user; return user;
} }
public ResetPasswordToken saveResetPasswordToken(ResetPasswordToken token) {
entityManager.persist(token);
return token;
}
public ResetPasswordToken findResetPasswordToken(String login, String token) {
if (!StringUtils.hasText(login) || StringUtils.hasText(token)) {
return null;
}
Query q = entityManager.createQuery("select au from ResetPasswordToken au where lower(au.login) = :login and au.token = :token and (au.used is null or au.used = :used)");
q.setParameter("login", login.trim().toLowerCase());
q.setParameter("token", token.trim().toLowerCase());
q.setParameter("used", Boolean.TRUE);
return singleResult(q);
}
} }
package com.jh.common.security.service; package com.jh.common.security.service;
import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
...@@ -11,18 +15,25 @@ import org.springframework.security.core.AuthenticationException; ...@@ -11,18 +15,25 @@ import org.springframework.security.core.AuthenticationException;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import com.jh.common.email.EmailService;
import com.jh.common.security.AuthService; import com.jh.common.security.AuthService;
import com.jh.common.security.GrantedRole; import com.jh.common.security.GrantedRole;
import com.jh.common.security.PasswordHash;
import com.jh.common.security.PasswordUtils; import com.jh.common.security.PasswordUtils;
import com.jh.common.security.model.AppUser; import com.jh.common.security.model.AppUser;
import com.jh.common.security.model.ResetPasswordToken;
import com.jh.common.security.repository.AppUserRepository; import com.jh.common.security.repository.AppUserRepository;
public class AppUserAuthService implements AuthService { public class AppUserAuthService implements AuthService {
private static final Logger LOG = LoggerFactory.getLogger(AppUserAuthService.class);
private AppUserRepository appUserRepository; private AppUserRepository appUserRepository;
private EmailService emailService;
@Override @Override
@Transactional @Transactional
...@@ -57,17 +68,52 @@ public class AppUserAuthService implements AuthService { ...@@ -57,17 +68,52 @@ public class AppUserAuthService implements AuthService {
@Override @Override
@Transactional @Transactional
public String generateResetToken(String login) { public String generateResetToken(String login) {
return "TOKEN"; AppUser user = appUserRepository.findByLogin(login);
if (user == null) {
throw new BadCredentialsException("User does not exist");
}
ResetPasswordToken token = new ResetPasswordToken(login, new Date(), UUID.randomUUID().toString());
appUserRepository.saveResetPasswordToken(token);
//TODO send email
if (emailService == null) {
LOG.warn("Reset password email cannot be sent: no email service configured");
} else {
}
return token.getToken();
} }
@Override @Override
@Transactional @Transactional
public void resetPassword(String login, String token, String newPassword) throws AuthenticationException { public void resetPassword(String login, String token, String newPassword) throws AuthenticationException {
ResetPasswordToken rpt = appUserRepository.findResetPasswordToken(login, token);
if (rpt == null) {
throw new BadCredentialsException("Invalid token");
}
AppUser user = appUserRepository.findByLogin(login);
if (user == null) {
throw new BadCredentialsException("User does not exist");
}
PasswordHash hash = PasswordUtils.hashPassword(newPassword);
user.setPassword(hash.getHash());
user.setPasswordSalt(hash.getSalt());
} }
@Autowired(required = false) @Autowired(required = false)
public void setAppUserRepository(AppUserRepository appUserRepository) { public void setAppUserRepository(AppUserRepository appUserRepository) {
this.appUserRepository = appUserRepository; this.appUserRepository = appUserRepository;
} }
@Autowired(required = false)
public void setEmailService(EmailService emailService) {
this.emailService = emailService;
}
} }
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