KEYCLOAK-218 Show error page if failed to send email
This commit is contained in:
1 parent
c368a64b4b
commit
43da684a91
8 files changed
+70
-50
No files matched your search
@@ -59,6 +59,7 @@ errorHeader=Error!
|
||||
emailForgotHeader=Forgot Your Password?
|
||||
emailUpdateHeader=Update password
|
||||
emailSent=You should receive an email shortly with further instructions.
|
||||
emailSendError=Failed to send email, please try again later
|
||||
emailError=Invalid username or email.
|
||||
emailErrorInfo=Please, fill in the fields again.
|
||||
emailInstruction=Enter your username and email address and we will send you instructions on how to create a new password.
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.keycloak.services.email;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class EmailException extends Exception {
|
||||
|
||||
public EmailException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -54,7 +54,7 @@ public class EmailSender {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public void send(String address, String subject, String body) throws MessagingException {
|
||||
public void send(String address, String subject, String body) throws EmailException {
|
||||
Properties props = new Properties();
|
||||
props.setProperty("mail.smtp.host", config.get("host"));
|
||||
|
||||
@@ -81,24 +81,28 @@ public class EmailSender {
|
||||
|
||||
String from = config.get("from");
|
||||
|
||||
Session session = Session.getInstance(props);
|
||||
try {
|
||||
Session session = Session.getInstance(props);
|
||||
|
||||
Message msg = new MimeMessage(session);
|
||||
msg.setFrom(new InternetAddress(from));
|
||||
msg.setSubject(subject);
|
||||
msg.setText(body);
|
||||
msg.saveChanges();
|
||||
Message msg = new MimeMessage(session);
|
||||
msg.setFrom(new InternetAddress(from));
|
||||
msg.setSubject(subject);
|
||||
msg.setText(body);
|
||||
msg.saveChanges();
|
||||
|
||||
Transport transport = session.getTransport("smtp");
|
||||
if (auth) {
|
||||
transport.connect(config.get("user"), config.get("password"));
|
||||
} else {
|
||||
transport.connect();
|
||||
Transport transport = session.getTransport("smtp");
|
||||
if (auth) {
|
||||
transport.connect(config.get("user"), config.get("password"));
|
||||
} else {
|
||||
transport.connect();
|
||||
}
|
||||
transport.sendMessage(msg, new InternetAddress[]{new InternetAddress(address)});
|
||||
} catch (Exception e) {
|
||||
throw new EmailException(e);
|
||||
}
|
||||
transport.sendMessage(msg, new InternetAddress[] { new InternetAddress(address) });
|
||||
}
|
||||
|
||||
public void sendEmailVerification(UserModel user, RealmModel realm, AccessCodeEntry accessCode, UriInfo uriInfo) {
|
||||
public void sendEmailVerification(UserModel user, RealmModel realm, AccessCodeEntry accessCode, UriInfo uriInfo) throws EmailException {
|
||||
UriBuilder builder = Urls.loginActionEmailVerificationBuilder(uriInfo.getBaseUri());
|
||||
builder.queryParam("key", accessCode.getId());
|
||||
|
||||
@@ -115,14 +119,10 @@ public class EmailSender {
|
||||
sb.append("Thanks,\n");
|
||||
sb.append("The Keycloak Team");
|
||||
|
||||
try {
|
||||
send(user.getEmail(), "Verify email", sb.toString());
|
||||
} catch (Exception e1) {
|
||||
log.warn("Failed to send email verification");
|
||||
}
|
||||
send(user.getEmail(), "Verify email", sb.toString());
|
||||
}
|
||||
|
||||
public void sendPasswordReset(UserModel user, RealmModel realm, AccessCodeEntry accessCode, UriInfo uriInfo) {
|
||||
public void sendPasswordReset(UserModel user, RealmModel realm, AccessCodeEntry accessCode, UriInfo uriInfo) throws EmailException {
|
||||
UriBuilder builder = Urls.loginPasswordResetBuilder(uriInfo.getBaseUri());
|
||||
builder.queryParam("key", accessCode.getId());
|
||||
|
||||
@@ -140,11 +140,7 @@ public class EmailSender {
|
||||
sb.append("Thanks,\n");
|
||||
sb.append("The Keycloak Team");
|
||||
|
||||
try {
|
||||
send(user.getEmail(), "Reset password link", sb.toString());
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to send reset password link", e);
|
||||
}
|
||||
send(user.getEmail(), "Reset password link", sb.toString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -46,7 +46,6 @@ import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.*;
|
||||
import javax.ws.rs.ext.Providers;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -175,8 +174,7 @@ public class AccountService {
|
||||
user.setLastName(formData.getFirst("lastName"));
|
||||
user.setEmail(formData.getFirst("email"));
|
||||
|
||||
return Flows.forms(realm, request, uriInfo).setUser(user).setError("accountUpdated")
|
||||
.setErrorType(FormFlows.MessageType.SUCCESS).forwardToAccount();
|
||||
return Flows.forms(realm, request, uriInfo).setUser(user).setSuccess("accountUpdated").forwardToAccount();
|
||||
}
|
||||
|
||||
@Path("totp-remove")
|
||||
@@ -190,8 +188,7 @@ public class AccountService {
|
||||
UserModel user = auth.getUser();
|
||||
|
||||
user.setTotp(false);
|
||||
return Flows.forms(realm, request, uriInfo).setError("successTotpRemoved").setErrorType(FormFlows.MessageType.SUCCESS)
|
||||
.setUser(user).forwardToTotp();
|
||||
return Flows.forms(realm, request, uriInfo).setSuccess("successTotpRemoved").setUser(user).forwardToTotp();
|
||||
}
|
||||
|
||||
@Path("totp")
|
||||
@@ -222,8 +219,7 @@ public class AccountService {
|
||||
|
||||
user.setTotp(true);
|
||||
|
||||
return Flows.forms(realm, request, uriInfo).setError("successTotp").setErrorType(FormFlows.MessageType.SUCCESS)
|
||||
.setUser(user).forwardToTotp();
|
||||
return Flows.forms(realm, request, uriInfo).setSuccess("successTotp").setUser(user).forwardToTotp();
|
||||
}
|
||||
|
||||
@Path("password")
|
||||
@@ -266,8 +262,7 @@ public class AccountService {
|
||||
|
||||
realm.updateCredential(user, credentials);
|
||||
|
||||
return Flows.forms(realm, request, uriInfo).setUser(user).setError("accountPasswordUpdated")
|
||||
.setErrorType(FormFlows.MessageType.SUCCESS).forwardToPassword();
|
||||
return Flows.forms(realm, request, uriInfo).setUser(user).setSuccess("accountPasswordUpdated").forwardToPassword();
|
||||
}
|
||||
|
||||
@Path("login-redirect")
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserModel.RequiredAction;
|
||||
import org.keycloak.models.utils.TimeBasedOTP;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.services.email.EmailException;
|
||||
import org.keycloak.services.email.EmailSender;
|
||||
import org.keycloak.services.managers.AccessCodeEntry;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
@@ -265,10 +266,14 @@ public class RequiredActionsService {
|
||||
accessCode.setRequiredActions(requiredActions);
|
||||
accessCode.setExpiration(System.currentTimeMillis() / 1000 + realm.getAccessCodeLifespanUserAction());
|
||||
|
||||
new EmailSender(realm.getSmtpConfig()).sendPasswordReset(user, realm, accessCode, uriInfo);
|
||||
try {
|
||||
new EmailSender(realm.getSmtpConfig()).sendPasswordReset(user, realm, accessCode, uriInfo);
|
||||
} catch (EmailException e) {
|
||||
logger.error("Failed to send password reset email", e);
|
||||
return Flows.forms(realm, request, uriInfo).setError("emailSendError").forwardToErrorPage();
|
||||
}
|
||||
|
||||
return Flows.forms(realm, request, uriInfo).setError("emailSent").setErrorType(FormFlows.MessageType.SUCCESS)
|
||||
.forwardToPasswordReset();
|
||||
return Flows.forms(realm, request, uriInfo).setSuccess("emailSent").forwardToPasswordReset();
|
||||
}
|
||||
|
||||
private AccessCodeEntry getAccessCodeEntry(RequiredAction requiredAction) {
|
||||
|
||||
@@ -27,7 +27,6 @@ import org.jboss.resteasy.spi.HttpRequest;
|
||||
import org.jboss.resteasy.spi.HttpResponse;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.SocialLinkModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserModel.RequiredAction;
|
||||
import org.keycloak.services.FormService;
|
||||
import org.keycloak.services.email.EmailException;
|
||||
import org.keycloak.services.email.EmailSender;
|
||||
import org.keycloak.services.managers.AccessCodeEntry;
|
||||
import org.keycloak.services.messages.Messages;
|
||||
@@ -51,8 +52,7 @@ public class FormFlows {
|
||||
|
||||
public static final String CODE = "code";
|
||||
|
||||
// TODO refactor/rename "error" to "message" everywhere where it makes sense
|
||||
private String error;
|
||||
private String message;
|
||||
|
||||
public static enum MessageType {SUCCESS, WARNING, ERROR};
|
||||
private MessageType messageType = MessageType.ERROR;
|
||||
@@ -86,7 +86,11 @@ public class FormFlows {
|
||||
case UPDATE_PASSWORD:
|
||||
return forwardToActionForm(Pages.LOGIN_UPDATE_PASSWORD, Messages.ACTION_WARN_PASSWD);
|
||||
case VERIFY_EMAIL:
|
||||
new EmailSender(realm.getSmtpConfig()).sendEmailVerification(userModel, realm, accessCode, uriInfo);
|
||||
try {
|
||||
new EmailSender(realm.getSmtpConfig()).sendEmailVerification(userModel, realm, accessCode, uriInfo);
|
||||
} catch (EmailException e) {
|
||||
return setError("emailSendError").forwardToErrorPage();
|
||||
}
|
||||
return forwardToActionForm(Pages.LOGIN_VERIFY_EMAIL, Messages.ACTION_WARN_EMAIL);
|
||||
default:
|
||||
return Response.serverError().build();
|
||||
@@ -146,7 +150,7 @@ public class FormFlows {
|
||||
|
||||
public Response forwardToForm(String template) {
|
||||
|
||||
FormService.FormServiceDataBean formDataBean = new FormService.FormServiceDataBean(realm, userModel, formData, queryParams, error);
|
||||
FormService.FormServiceDataBean formDataBean = new FormService.FormServiceDataBean(realm, userModel, formData, queryParams, message);
|
||||
formDataBean.setMessageType(messageType);
|
||||
|
||||
return forwardToForm(template, formDataBean);
|
||||
@@ -156,9 +160,9 @@ public class FormFlows {
|
||||
|
||||
// If no other message is set, notify user about required action in the warning window
|
||||
// so it's clear that this is a req. action form not a login form
|
||||
if (error == null){
|
||||
if (message == null){
|
||||
messageType = MessageType.WARNING;
|
||||
error = warningSummary;
|
||||
message = warningSummary;
|
||||
}
|
||||
|
||||
return forwardToForm(template);
|
||||
@@ -198,7 +202,7 @@ public class FormFlows {
|
||||
|
||||
public Response forwardToOAuthGrant(){
|
||||
|
||||
FormService.FormServiceDataBean formDataBean = new FormService.FormServiceDataBean(realm, userModel, formData, queryParams, error);
|
||||
FormService.FormServiceDataBean formDataBean = new FormService.FormServiceDataBean(realm, userModel, formData, queryParams, message);
|
||||
|
||||
formDataBean.setOAuthRealmRolesRequested((List<RoleModel>) request.getAttribute("realmRolesRequested"));
|
||||
formDataBean.setOAuthResourceRolesRequested((MultivaluedMap<String, RoleModel>) request.getAttribute("resourceRolesRequested"));
|
||||
@@ -222,13 +226,21 @@ public class FormFlows {
|
||||
return this;
|
||||
}
|
||||
|
||||
public FormFlows setError(String error) {
|
||||
this.error = error;
|
||||
public FormFlows setError(String message) {
|
||||
this.message = message;
|
||||
this.messageType = MessageType.ERROR;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FormFlows setErrorType(MessageType errorType) {
|
||||
this.messageType = errorType;
|
||||
public FormFlows setSuccess(String message) {
|
||||
this.message = message;
|
||||
this.messageType = MessageType.SUCCESS;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FormFlows setWarning(String message) {
|
||||
this.message = message;
|
||||
this.messageType = MessageType.WARNING;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ public class EmailSenderTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendMail() throws MessagingException, IOException {
|
||||
public void sendMail() throws Exception {
|
||||
emailSender.send("test@test.com", "Test subject", "Test body");
|
||||
|
||||
MimeMessage[] receivedMessages = greenMail.getReceivedMessages();
|
||||
|
||||
Reference in new issue
Block a user