From 0ac000adcac04e7085bc8bd23c9791d9e333c69c Mon Sep 17 00:00:00 2001 From: Cory Snyder Date: Tue, 2 Jun 2015 12:25:58 -0400 Subject: [PATCH] KEYCLOAK-681 multi-part emails --- .../email/html/email-verification.ftl | 5 ++ .../keycloak/email/html/event-login_error.ftl | 5 ++ .../keycloak/email/html/event-remove_totp.ftl | 5 ++ .../email/html/event-update_password.ftl | 5 ++ .../keycloak/email/html/event-update_totp.ftl | 5 ++ .../keycloak/email/html/password-reset.ftl | 5 ++ .../email/messages/messages_de.properties | 6 ++ .../email/messages/messages_en.properties | 10 +++- .../email/messages/messages_pt_BR.properties | 6 ++ .../email/{ => text}/email-verification.ftl | 0 .../email/{ => text}/event-login_error.ftl | 0 .../email/{ => text}/event-remove_totp.ftl | 0 .../{ => text}/event-update_password.ftl | 0 .../email/{ => text}/event-update_totp.ftl | 0 .../email/{ => text}/password-reset.ftl | 0 .../freemarker/FreeMarkerEmailProvider.java | 60 +++++++++++++++---- .../java/org/keycloak/testsuite/MailUtil.java | 2 +- .../RequiredActionEmailVerificationTest.java | 39 ++++++++---- .../broker/AbstractIdentityProviderTest.java | 26 +++++++- .../testsuite/forms/ResetPasswordTest.java | 47 ++++++++++----- 20 files changed, 183 insertions(+), 43 deletions(-) create mode 100644 forms/common-themes/src/main/resources/theme/keycloak/email/html/email-verification.ftl create mode 100644 forms/common-themes/src/main/resources/theme/keycloak/email/html/event-login_error.ftl create mode 100644 forms/common-themes/src/main/resources/theme/keycloak/email/html/event-remove_totp.ftl create mode 100644 forms/common-themes/src/main/resources/theme/keycloak/email/html/event-update_password.ftl create mode 100644 forms/common-themes/src/main/resources/theme/keycloak/email/html/event-update_totp.ftl create mode 100644 forms/common-themes/src/main/resources/theme/keycloak/email/html/password-reset.ftl rename forms/common-themes/src/main/resources/theme/keycloak/email/{ => text}/email-verification.ftl (100%) rename forms/common-themes/src/main/resources/theme/keycloak/email/{ => text}/event-login_error.ftl (100%) rename forms/common-themes/src/main/resources/theme/keycloak/email/{ => text}/event-remove_totp.ftl (100%) rename forms/common-themes/src/main/resources/theme/keycloak/email/{ => text}/event-update_password.ftl (100%) rename forms/common-themes/src/main/resources/theme/keycloak/email/{ => text}/event-update_totp.ftl (100%) rename forms/common-themes/src/main/resources/theme/keycloak/email/{ => text}/password-reset.ftl (100%) diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/html/email-verification.ftl b/forms/common-themes/src/main/resources/theme/keycloak/email/html/email-verification.ftl new file mode 100644 index 0000000000..eb7682a272 --- /dev/null +++ b/forms/common-themes/src/main/resources/theme/keycloak/email/html/email-verification.ftl @@ -0,0 +1,5 @@ + + +${msg("emailVerificationBodyHtml",link, linkExpiration, realmName)} + + diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-login_error.ftl b/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-login_error.ftl new file mode 100644 index 0000000000..d31410307c --- /dev/null +++ b/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-login_error.ftl @@ -0,0 +1,5 @@ + + +${msg("eventLoginErrorBodyHtml",event.date,event.ipAddress)} + + diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-remove_totp.ftl b/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-remove_totp.ftl new file mode 100644 index 0000000000..91699ea349 --- /dev/null +++ b/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-remove_totp.ftl @@ -0,0 +1,5 @@ + + +${msg("eventRemoveTotpBodyHtml",event.date, event.ipAddress)} + + diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-update_password.ftl b/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-update_password.ftl new file mode 100644 index 0000000000..8a6da60a50 --- /dev/null +++ b/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-update_password.ftl @@ -0,0 +1,5 @@ + + +${msg("eventUpdatePasswordBodyHtml",event.date, event.ipAddress)} + + diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-update_totp.ftl b/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-update_totp.ftl new file mode 100644 index 0000000000..c0190c7278 --- /dev/null +++ b/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-update_totp.ftl @@ -0,0 +1,5 @@ + + +${msg("eventUpdateTotpBodyHtml",event.date, event.ipAddress)} + + diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/html/password-reset.ftl b/forms/common-themes/src/main/resources/theme/keycloak/email/html/password-reset.ftl new file mode 100644 index 0000000000..846b45dafd --- /dev/null +++ b/forms/common-themes/src/main/resources/theme/keycloak/email/html/password-reset.ftl @@ -0,0 +1,5 @@ + + +${msg("passwordResetBodyHtml",link, linkExpiration, realmName)} + + \ No newline at end of file diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_de.properties b/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_de.properties index 0256640286..91337c4ee8 100644 --- a/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_de.properties +++ b/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_de.properties @@ -1,12 +1,18 @@ emailVerificationSubject=E-Mail verifizieren passwordResetSubject=Passwort zur\u00FCckzusetzen passwordResetBody=Jemand hat angefordert Ihr {2} Passwort zur\u00FCckzusetzen. Falls das Sie waren, dann klicken Sie auf den folgenden Link um das Passwort zur\u00FCckzusetzen.\n\n{0}\n\nDieser Link wird in {1} Minuten ablaufen.\n\nFalls Sie das Passwort nicht zur\u00FCcksetzen m\u00F6chten, dann k\u00F6nnen Sie diese E-Mail ignorieren. +passwordResetBodyHtml=

Jemand hat angefordert Ihr {2} Passwort zur\u00FCckzusetzen. Falls das Sie waren, dann klicken Sie auf den folgenden Link um das Passwort zur\u00FCckzusetzen.

{0}

Dieser Link wird in {1} Minuten ablaufen.

Falls Sie das Passwort nicht zur\u00FCcksetzen m\u00F6chten, dann k\u00F6nnen Sie diese E-Mail ignorieren.

emailVerificationBody=Jemand hat ein {2} Konto mit dieser E-Mail Adresse erstellt. Fall das Sie waren, dann klicken Sie auf den Link um die E-Mail Adresse zu verifizieren.\n\n{0}\n\nDieser Link wird in {1} Minuten ablaufen.\n\nFalls Sie dieses Konto nicht erstellt haben, dann k\u00F6nnen sie diese Nachricht ignorieren. +emailVerificationBodyHtml=

Jemand hat ein {2} Konto mit dieser E-Mail Adresse erstellt. Fall das Sie waren, dann klicken Sie auf den Link um die E-Mail Adresse zu verifizieren.

{0}

Dieser Link wird in {1} Minuten ablaufen.

Falls Sie dieses Konto nicht erstellt haben, dann k\u00F6nnen sie diese Nachricht ignorieren.

eventLoginErrorSubject=Fehlgeschlagene Anmeldung eventLoginErrorBody=Jemand hat um {0} von {1} versucht sich mit ihrem Konto anzumelden. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin. +eventLoginErrorBodyHtml=

Jemand hat um {0} von {1} versucht sich mit ihrem Konto anzumelden. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.

eventRemoveTotpSubject=TOTP Entfernt eventRemoveTotpBody=TOTP wurde von ihrem Konto am {0} von {1} entfernt. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin. +eventRemoveTotpBodyHtml=

TOTP wurde von ihrem Konto am {0} von {1} entfernt. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.

eventUpdatePasswordSubject=Passwort Aktualisiert eventUpdatePasswordBody=Ihr Passwort wurde am {0} von {1} ge\u00E4ndert. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin. +eventUpdatePasswordBodyHtml=

Ihr Passwort wurde am {0} von {1} ge\u00E4ndert. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.

eventUpdateTotpSubject=TOTP Aktualisiert eventUpdateTotpBody=TOTP wurde am {0} von {1} ge\u00E4ndert. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin. +eventUpdateTotpBodyHtml=

TOTP wurde am {0} von {1} ge\u00E4ndert. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.

diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_en.properties b/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_en.properties index c0afc9ca91..7a3ac65499 100755 --- a/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_en.properties +++ b/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_en.properties @@ -1,12 +1,18 @@ emailVerificationSubject=Verify email emailVerificationBody=Someone has created a {2} account with this email address. If this was you, click the link below to verify your email address\n\n{0}\n\nThis link will expire within {1} minutes.\n\nIf you didn''t create this account, just ignore this message. +emailVerificationBodyHtml=

Someone has created a {2} account with this email address. If this was you, click the link below to verify your email address

{0}

This link will expire within {1} minutes.

If you didn''t create this account, just ignore this message.

passwordResetSubject=Reset password passwordResetBody=Someone just requested to change your {2} account''s password. If this was you, click on the link below to set a new password\n\n{0}\n\nThis link will expire within {1} minutes.\n\nIf you don''t want to reset your password, just ignore this message and nothing will be changed. +passwordResetBodyHtml=

Someone just requested to change your {2} account''s password. If this was you, click on the link below to set a new password

{0}

This link will expire within {1} minutes.

If you don''t want to reset your password, just ignore this message and nothing will be changed.

eventLoginErrorSubject=Login error -eventLoginErrorBody=A failed login attempt was dettected to your account on {0} from {1}. If this was not you, please contact an admin. +eventLoginErrorBody=A failed login attempt was detected to your account on {0} from {1}. If this was not you, please contact an admin. +eventLoginErrorBodyHtml=

A failed login attempt was detected to your account on {0} from {1}. If this was not you, please contact an admin.

eventRemoveTotpSubject=Remove TOTP eventRemoveTotpBody=TOTP was removed from your account on {0} from {1}. If this was not you, please contact an admin. +eventRemoveTotpBodyHtml=

TOTP was removed from your account on {0} from {1}. If this was not you, please contact an admin.

eventUpdatePasswordSubject=Update password eventUpdatePasswordBody=Your password was changed on {0} from {1}. If this was not you, please contact an admin. +eventUpdatePasswordBodyHtml=

Your password was changed on {0} from {1}. If this was not you, please contact an admin.

eventUpdateTotpSubject=Update TOTP -eventUpdateTotpBody=TOTP was updated for your account on {0} from {1}. If this was not you, please contact an admin. \ No newline at end of file +eventUpdateTotpBody=TOTP was updated for your account on {0} from {1}. If this was not you, please contact an admin. +eventUpdateTotpBodyHtml=

TOTP was updated for your account on {0} from {1}. If this was not you, please contact an admin.

diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_pt_BR.properties b/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_pt_BR.properties index 0316e19009..fff7e10475 100644 --- a/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_pt_BR.properties +++ b/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_pt_BR.properties @@ -1,12 +1,18 @@ emailVerificationSubject=Verifica\u00E7\u00E3o de e-mail emailVerificationBody=Algu\u00E9m criou uma conta {2} com este endere\u00E7o de e-mail. Se foi voc\u00EA, clique no link abaixo para verificar o seu endere\u00E7o de email\n\n{0}\n\nEste link ir\u00E1 expirar dentro de {1} minutos.\n\nSe n\u00E3o foi voc\u00EA que criou esta conta, basta ignorar esta mensagem. +emailVerificationBodyHtml=

Algu\u00E9m criou uma conta {2} com este endere\u00E7o de e-mail. Se foi voc\u00EA, clique no link abaixo para verificar o seu endere\u00E7o de email

{0}

Este link ir\u00E1 expirar dentro de {1} minutos.

Se n\u00E3o foi voc\u00EA que criou esta conta, basta ignorar esta mensagem.

passwordResetSubject=Redefini\u00E7\u00E3o de senha passwordResetBody=Algu\u00E9m pediu para mudar a senha de sua conta {2}. Se foi voc\u00EA, clique no link abaixo para definir uma nova senha\n\n{0}\n\nEste link ir\u00E1 expirar dentro de {1} minutos.\n\nSe voc\u00EA n\u00E3o deseja redefinir sua senha, basta ignorar esta mensagem e nada ser\u00E1 mudado. +passwordResetBodyHtml=

Algu\u00E9m pediu para mudar a senha de sua conta {2}. Se foi voc\u00EA, clique no link abaixo para definir uma nova senha

{0}

Este link ir\u00E1 expirar dentro de {1} minutos.

Se voc\u00EA n\u00E3o deseja redefinir sua senha, basta ignorar esta mensagem e nada ser\u00E1 mudado.

eventLoginErrorSubject=Erro de login eventLoginErrorBody=Uma tentativa de login mal sucedida para a sua conta foi detectada em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador. +eventLoginErrorBodyHtml=

Uma tentativa de login mal sucedida para a sua conta foi detectada em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador.

eventRemoveTotpSubject=Remover TOTP eventRemoveTotpBody=TOTP foi removido da sua conta em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador. +eventRemoveTotpBodyHtml=

TOTP foi removido da sua conta em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador.

eventUpdatePasswordSubject=Atualiza\u00E7\u00E3o de senha eventUpdatePasswordBody=Sua senha foi alterada em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador. +eventUpdatePasswordBodyHtml=

Sua senha foi alterada em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador.

eventUpdateTotpSubject=Atualiza\u00E7\u00E3o TOTP eventUpdateTotpBody=TOTP foi atualizado para a sua conta em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador. +eventUpdateTotpBodyHtml=

TOTP foi atualizado para a sua conta em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador.

diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/email-verification.ftl b/forms/common-themes/src/main/resources/theme/keycloak/email/text/email-verification.ftl similarity index 100% rename from forms/common-themes/src/main/resources/theme/keycloak/email/email-verification.ftl rename to forms/common-themes/src/main/resources/theme/keycloak/email/text/email-verification.ftl diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/event-login_error.ftl b/forms/common-themes/src/main/resources/theme/keycloak/email/text/event-login_error.ftl similarity index 100% rename from forms/common-themes/src/main/resources/theme/keycloak/email/event-login_error.ftl rename to forms/common-themes/src/main/resources/theme/keycloak/email/text/event-login_error.ftl diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/event-remove_totp.ftl b/forms/common-themes/src/main/resources/theme/keycloak/email/text/event-remove_totp.ftl similarity index 100% rename from forms/common-themes/src/main/resources/theme/keycloak/email/event-remove_totp.ftl rename to forms/common-themes/src/main/resources/theme/keycloak/email/text/event-remove_totp.ftl diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/event-update_password.ftl b/forms/common-themes/src/main/resources/theme/keycloak/email/text/event-update_password.ftl similarity index 100% rename from forms/common-themes/src/main/resources/theme/keycloak/email/event-update_password.ftl rename to forms/common-themes/src/main/resources/theme/keycloak/email/text/event-update_password.ftl diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/event-update_totp.ftl b/forms/common-themes/src/main/resources/theme/keycloak/email/text/event-update_totp.ftl similarity index 100% rename from forms/common-themes/src/main/resources/theme/keycloak/email/event-update_totp.ftl rename to forms/common-themes/src/main/resources/theme/keycloak/email/text/event-update_totp.ftl diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/password-reset.ftl b/forms/common-themes/src/main/resources/theme/keycloak/email/text/password-reset.ftl similarity index 100% rename from forms/common-themes/src/main/resources/theme/keycloak/email/password-reset.ftl rename to forms/common-themes/src/main/resources/theme/keycloak/email/text/password-reset.ftl diff --git a/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailProvider.java b/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailProvider.java index 95f55f3674..79080de2c2 100755 --- a/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailProvider.java +++ b/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailProvider.java @@ -1,11 +1,28 @@ package org.keycloak.email.freemarker; +import java.text.MessageFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; + +import javax.mail.Message; +import javax.mail.Multipart; +import javax.mail.Session; +import javax.mail.Transport; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeBodyPart; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; + import org.jboss.logging.Logger; import org.keycloak.email.EmailException; import org.keycloak.email.EmailProvider; import org.keycloak.email.freemarker.beans.EventBean; import org.keycloak.events.Event; import org.keycloak.events.EventType; +import org.keycloak.freemarker.FreeMarkerException; import org.keycloak.freemarker.FreeMarkerUtil; import org.keycloak.freemarker.LocaleHelper; import org.keycloak.freemarker.Theme; @@ -15,14 +32,6 @@ import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; -import javax.mail.Message; -import javax.mail.Session; -import javax.mail.Transport; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeMessage; -import java.text.MessageFormat; -import java.util.*; - /** * @author Stian Thorgersen */ @@ -93,16 +102,29 @@ public class FreeMarkerEmailProvider implements EmailProvider { Properties rb = theme.getMessages(locale); attributes.put("msg", new MessageFormatterMethod(locale, rb)); String subject = new MessageFormat(rb.getProperty(subjectKey,subjectKey),locale).format(new Object[0]); - String body = freeMarker.processTemplate(attributes, template, theme); + String textTemplate = String.format("text/%s", template); + String textBody; + try { + textBody = freeMarker.processTemplate(attributes, textTemplate, theme); + } catch (final FreeMarkerException e ) { + textBody = null; + } + String htmlTemplate = String.format("html/%s", template); + String htmlBody; + try { + htmlBody = freeMarker.processTemplate(attributes, htmlTemplate, theme); + } catch (final FreeMarkerException e ) { + htmlBody = null; + } - send(subject, body); + send(subject, textBody, htmlBody); } catch (Exception e) { throw new EmailException("Failed to template email", e); } } - private void send(String subject, String body) throws EmailException { + private void send(String subject, String textBody, String htmlBody) throws EmailException { try { String address = user.getEmail(); Map config = realm.getSmtpConfig(); @@ -135,11 +157,25 @@ public class FreeMarkerEmailProvider implements EmailProvider { Session session = Session.getInstance(props); + Multipart multipart = new MimeMultipart("alternative"); + + if(textBody != null) { + MimeBodyPart textPart = new MimeBodyPart(); + textPart.setText(textBody, "UTF-8"); + multipart.addBodyPart(textPart); + } + + if(htmlBody != null) { + MimeBodyPart htmlPart = new MimeBodyPart(); + htmlPart.setContent(htmlBody, "text/html; charset=UTF-8"); + multipart.addBodyPart(htmlPart); + } + Message msg = new MimeMessage(session); msg.setFrom(new InternetAddress(from)); msg.setHeader("To", address); msg.setSubject(subject); - msg.setText(body); + msg.setContent(multipart); msg.saveChanges(); msg.setSentDate(new Date()); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/MailUtil.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/MailUtil.java index 9691301076..f29ae4ec0c 100644 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/MailUtil.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/MailUtil.java @@ -8,7 +8,7 @@ import java.util.regex.Pattern; */ public class MailUtil { - private static Pattern mailPattern = Pattern.compile("http[^\\s]*"); + private static Pattern mailPattern = Pattern.compile("http[^\\s\"]*"); public static String getLink(String body) { Matcher matcher = mailPattern.matcher(body); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionEmailVerificationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionEmailVerificationTest.java index 0d6b4cfefc..4b167cb7ec 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionEmailVerificationTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionEmailVerificationTest.java @@ -49,7 +49,9 @@ import org.keycloak.testsuite.rule.WebRule; import org.openqa.selenium.WebDriver; import javax.mail.MessagingException; +import javax.mail.Multipart; import javax.mail.internet.MimeMessage; + import java.io.IOException; import static org.junit.Assert.assertEquals; @@ -119,9 +121,8 @@ public class RequiredActionEmailVerificationTest { Assert.assertEquals(1, greenMail.getReceivedMessages().length); MimeMessage message = greenMail.getReceivedMessages()[0]; - - String body = (String) message.getContent(); - String verificationUrl = MailUtil.getLink(body); + + String verificationUrl = getPasswordResetEmailLink(message); AssertEvents.ExpectedEvent emailEvent = events.expectRequiredAction(EventType.SEND_VERIFY_EMAIL).detail("email", "test-user@localhost"); Event sendEvent = emailEvent.assertEvent(); @@ -154,14 +155,12 @@ public class RequiredActionEmailVerificationTest { MimeMessage message = greenMail.getReceivedMessages()[0]; - String body = (String) message.getContent(); - Event sendEvent = events.expectRequiredAction(EventType.SEND_VERIFY_EMAIL).user(userId).detail("username", "verifyEmail").detail("email", "email@mail.com").assertEvent(); String sessionId = sendEvent.getSessionId(); String mailCodeId = sendEvent.getDetails().get(Details.CODE_ID); - String verificationUrl = MailUtil.getLink(body); + String verificationUrl = getPasswordResetEmailLink(message); driver.navigate().to(verificationUrl.trim()); @@ -192,11 +191,9 @@ public class RequiredActionEmailVerificationTest { MimeMessage message = greenMail.getReceivedMessages()[1]; - String body = (String) message.getContent(); - events.expectRequiredAction(EventType.SEND_VERIFY_EMAIL).session(sessionId).detail("email", "test-user@localhost").assertEvent(sendEvent); - String verificationUrl = MailUtil.getLink(body); + String verificationUrl = getPasswordResetEmailLink(message); driver.navigate().to(verificationUrl.trim()); @@ -218,8 +215,7 @@ public class RequiredActionEmailVerificationTest { MimeMessage message = greenMail.getReceivedMessages()[0]; - String body = (String) message.getContent(); - String verificationUrl = MailUtil.getLink(body); + String verificationUrl = getPasswordResetEmailLink(message); AssertEvents.ExpectedEvent emailEvent = events.expectRequiredAction(EventType.SEND_VERIFY_EMAIL).detail("email", "test-user@localhost"); Event sendEvent = emailEvent.assertEvent(); @@ -242,6 +238,27 @@ public class RequiredActionEmailVerificationTest { assertTrue(loginPage.isCurrent()); } + + private String getPasswordResetEmailLink(MimeMessage message) throws IOException, MessagingException { + Multipart multipart = (Multipart) message.getContent(); + + final String textContentType = multipart.getBodyPart(0).getContentType(); + + assertEquals("text/plain; charset=UTF-8", textContentType); + + final String textBody = (String) multipart.getBodyPart(0).getContent(); + final String textChangePwdUrl = MailUtil.getLink(textBody); + + final String htmlContentType = multipart.getBodyPart(1).getContentType(); + + assertEquals("text/html; charset=UTF-8", htmlContentType); + + final String htmlBody = (String) multipart.getBodyPart(1).getContent(); + final String htmlChangePwdUrl = MailUtil.getLink(htmlBody); + + assertEquals(htmlChangePwdUrl, textChangePwdUrl); + return htmlChangePwdUrl; + } } diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java index e82744fb3d..f6f7345f99 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java @@ -53,6 +53,7 @@ import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import javax.mail.MessagingException; +import javax.mail.Multipart; import javax.mail.internet.MimeMessage; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; @@ -187,8 +188,7 @@ public abstract class AbstractIdentityProviderTest { // read email to take verification link from Assert.assertEquals(1, greenMail.getReceivedMessages().length); MimeMessage message = greenMail.getReceivedMessages()[0]; - String body = (String) message.getContent(); - String verificationUrl = MailUtil.getLink(body); + String verificationUrl = getVerificationEmailLink(message); driver.navigate().to(verificationUrl.trim()); @@ -805,4 +805,26 @@ public abstract class AbstractIdentityProviderTest { } } } + + private String getVerificationEmailLink(MimeMessage message) throws IOException, MessagingException { + Multipart multipart = (Multipart) message.getContent(); + + final String textContentType = multipart.getBodyPart(0).getContentType(); + + assertEquals("text/plain; charset=UTF-8", textContentType); + + final String textBody = (String) multipart.getBodyPart(0).getContent(); + final String textVerificationUrl = MailUtil.getLink(textBody); + + final String htmlContentType = multipart.getBodyPart(1).getContentType(); + + assertEquals("text/html; charset=UTF-8", htmlContentType); + + final String htmlBody = (String) multipart.getBodyPart(1).getContent(); + final String htmlVerificationUrl = MailUtil.getLink(htmlBody); + + assertEquals(htmlVerificationUrl, textVerificationUrl); + + return htmlVerificationUrl; + } } diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java index ed945026aa..26b1f799d3 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java @@ -52,7 +52,9 @@ import org.keycloak.util.Time; import org.openqa.selenium.WebDriver; import javax.mail.MessagingException; +import javax.mail.Multipart; import javax.mail.internet.MimeMessage; + import java.io.IOException; import java.util.Collections; @@ -146,9 +148,8 @@ public class ResetPasswordTest { assertEquals(1, greenMail.getReceivedMessages().length); MimeMessage message = greenMail.getReceivedMessages()[0]; - - String body = (String) message.getContent(); - String changePasswordUrl = MailUtil.getLink(body); + + final String changePasswordUrl = getPasswordResetEmailLink(message); driver.navigate().to(changePasswordUrl.trim()); @@ -211,8 +212,7 @@ public class ResetPasswordTest { MimeMessage message = greenMail.getReceivedMessages()[0]; - String body = (String) message.getContent(); - String changePasswordUrl = MailUtil.getLink(body); + String changePasswordUrl = getPasswordResetEmailLink(message); driver.navigate().to(changePasswordUrl.trim()); @@ -256,8 +256,7 @@ public class ResetPasswordTest { MimeMessage message = greenMail.getReceivedMessages()[greenMail.getReceivedMessages().length - 1]; - String body = (String) message.getContent(); - String changePasswordUrl = MailUtil.getLink(body); + String changePasswordUrl = getPasswordResetEmailLink(message); driver.navigate().to(changePasswordUrl.trim()); @@ -294,8 +293,7 @@ public class ResetPasswordTest { MimeMessage message = greenMail.getReceivedMessages()[greenMail.getReceivedMessages().length - 1]; - String body = (String) message.getContent(); - String changePasswordUrl = MailUtil.getLink(body); + String changePasswordUrl = getPasswordResetEmailLink(message); driver.navigate().to(changePasswordUrl.trim()); @@ -364,8 +362,7 @@ public class ResetPasswordTest { MimeMessage message = greenMail.getReceivedMessages()[0]; - String body = (String) message.getContent(); - String changePasswordUrl = MailUtil.getLink(body); + String changePasswordUrl = getPasswordResetEmailLink(message); Time.setOffset(350); @@ -513,8 +510,7 @@ public class ResetPasswordTest { MimeMessage message = greenMail.getReceivedMessages()[0]; - String body = (String) message.getContent(); - String changePasswordUrl = MailUtil.getLink(body); + String changePasswordUrl = getPasswordResetEmailLink(message); String sessionId = events.expectRequiredAction(EventType.SEND_RESET_PASSWORD).user(userId).detail(Details.USERNAME, "login-test").detail(Details.EMAIL, "login@test.com").assertEvent().getSessionId(); @@ -609,8 +605,7 @@ public class ResetPasswordTest { MimeMessage message = greenMail.getReceivedMessages()[0]; - String body = (String) message.getContent(); - String changePasswordUrl = MailUtil.getLink(body); + String changePasswordUrl = getPasswordResetEmailLink(message); driver.manage().deleteAllCookies(); @@ -629,5 +624,27 @@ public class ResetPasswordTest { assertTrue(loginPage.isCurrent()); } + + private String getPasswordResetEmailLink(MimeMessage message) throws IOException, MessagingException { + Multipart multipart = (Multipart) message.getContent(); + + final String textContentType = multipart.getBodyPart(0).getContentType(); + + assertEquals("text/plain; charset=UTF-8", textContentType); + + final String textBody = (String) multipart.getBodyPart(0).getContent(); + final String textChangePwdUrl = MailUtil.getLink(textBody); + + final String htmlContentType = multipart.getBodyPart(1).getContentType(); + + assertEquals("text/html; charset=UTF-8", htmlContentType); + + final String htmlBody = (String) multipart.getBodyPart(1).getContent(); + final String htmlChangePwdUrl = MailUtil.getLink(htmlBody); + + assertEquals(htmlChangePwdUrl, textChangePwdUrl); + + return htmlChangePwdUrl; + } }