Merge pull request #3718 from thomasdarimont/issue/KEYCLOAK-4163-improve-support-for-email-addresses
KEYCLOAK-4163 Improve support for e-mail addresses
This commit is contained in:
commit
af4c74f1d9
5 changed files with 91 additions and 5 deletions
|
@ -17,6 +17,7 @@
|
|||
|
||||
package org.keycloak.email;
|
||||
|
||||
import com.sun.mail.smtp.SMTPMessage;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
@ -25,15 +26,17 @@ import org.keycloak.services.ServicesLogger;
|
|||
import org.keycloak.truststore.HostnameVerificationPolicy;
|
||||
import org.keycloak.truststore.JSSETruststoreConfigurator;
|
||||
|
||||
import javax.mail.Address;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Multipart;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.Transport;
|
||||
import javax.mail.internet.AddressException;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeBodyPart;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Date;
|
||||
|
@ -91,6 +94,10 @@ public class DefaultEmailSenderProvider implements EmailSenderProvider {
|
|||
props.setProperty("mail.smtp.connectiontimeout", "10000");
|
||||
|
||||
String from = config.get("from");
|
||||
String fromDisplayName = config.get("fromDisplayName");
|
||||
String replyTo = config.get("replyTo");
|
||||
String replyToDisplayName = config.get("replyToDisplayName");
|
||||
String envelopeFrom = config.get("envelopeFrom");
|
||||
|
||||
Session session = Session.getInstance(props);
|
||||
|
||||
|
@ -108,8 +115,17 @@ public class DefaultEmailSenderProvider implements EmailSenderProvider {
|
|||
multipart.addBodyPart(htmlPart);
|
||||
}
|
||||
|
||||
MimeMessage msg = new MimeMessage(session);
|
||||
msg.setFrom(new InternetAddress(from));
|
||||
SMTPMessage msg = new SMTPMessage(session);
|
||||
msg.setFrom(toInternetAddress(from, fromDisplayName));
|
||||
|
||||
msg.setReplyTo(new Address[]{toInternetAddress(from, fromDisplayName)});
|
||||
if (replyTo != null) {
|
||||
msg.setReplyTo(new Address[]{toInternetAddress(replyTo, replyToDisplayName)});
|
||||
}
|
||||
if (envelopeFrom != null) {
|
||||
msg.setEnvelopeFrom(envelopeFrom);
|
||||
}
|
||||
|
||||
msg.setHeader("To", address);
|
||||
msg.setSubject(subject, "utf-8");
|
||||
msg.setContent(multipart);
|
||||
|
@ -136,6 +152,13 @@ public class DefaultEmailSenderProvider implements EmailSenderProvider {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected InternetAddress toInternetAddress(String email, String displayName) throws UnsupportedEncodingException, AddressException {
|
||||
if (displayName == null || "".equals(displayName.trim())) {
|
||||
return new InternetAddress(email);
|
||||
}
|
||||
return new InternetAddress(email, displayName, "utf-8");
|
||||
}
|
||||
|
||||
protected String retrieveEmailAddress(UserModel user) {
|
||||
return user.getEmail();
|
||||
|
|
|
@ -46,7 +46,6 @@ import javax.mail.MessagingException;
|
|||
import javax.mail.Multipart;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
@ -98,6 +97,28 @@ public class RequiredActionEmailVerificationTest extends AbstractTestRealmKeyclo
|
|||
ApiUtil.createUserAndResetPasswordWithAdminClient(testRealm(), user, "password");
|
||||
}
|
||||
|
||||
/**
|
||||
* see KEYCLOAK-4163
|
||||
*/
|
||||
@Test
|
||||
public void verifyEmailConfig() throws IOException, MessagingException {
|
||||
|
||||
loginPage.open();
|
||||
loginPage.login("test-user@localhost", "password");
|
||||
|
||||
Assert.assertTrue(verifyEmailPage.isCurrent());
|
||||
|
||||
Assert.assertEquals(1, greenMail.getReceivedMessages().length);
|
||||
|
||||
MimeMessage message = greenMail.getReceivedMessages()[0];
|
||||
|
||||
// see testsuite/integration-arquillian/tests/base/src/test/resources/testrealm.json
|
||||
Assert.assertEquals("<auto+bounces@keycloak.org>", message.getHeader("Return-Path")[0]);
|
||||
// displayname <email@example.org>
|
||||
Assert.assertEquals("Keycloak SSO <auto@keycloak.org>", message.getHeader("From")[0]);
|
||||
Assert.assertEquals("Keycloak no-reply <reply-to@keycloak.org>", message.getHeader("Reply-To")[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyEmailExisting() throws IOException, MessagingException {
|
||||
loginPage.open();
|
||||
|
|
|
@ -13,7 +13,11 @@
|
|||
"smtpServer": {
|
||||
"from": "auto@keycloak.org",
|
||||
"host": "localhost",
|
||||
"port":"3025"
|
||||
"port":"3025",
|
||||
"fromDisplayName": "Keycloak SSO",
|
||||
"replyTo":"reply-to@keycloak.org",
|
||||
"replyToDisplayName": "Keycloak no-reply",
|
||||
"envelopeFrom": "auto+bounces@keycloak.org"
|
||||
},
|
||||
"users" : [
|
||||
{
|
||||
|
|
|
@ -55,7 +55,18 @@ smtp-host=SMTP Host
|
|||
port=Port
|
||||
smtp-port=SMTP Port (defaults to 25)
|
||||
from=From
|
||||
fromDisplayName=From Display Name
|
||||
fromDisplayName.tooltip=A user-friendly name for the 'From' address (optional).
|
||||
replyTo=Reply To
|
||||
replyToDisplayName=Reply To Display Name
|
||||
replyToDisplayName.tooltip=A user-friendly name for the 'Reply-To' address (optional).
|
||||
envelopeFrom=Envelope From
|
||||
envelopeFrom.tooltip=An email address used for bounces (optional).
|
||||
sender-email-addr=Sender Email Address
|
||||
sender-email-addr-display=Display Name for Sender Email Address
|
||||
reply-to-email-addr=Reply To Email Address
|
||||
reply-to-email-addr-display=Display Name for Reply To Email Address
|
||||
sender-envelope-email-addr=Sender Envelope Email Address
|
||||
enable-ssl=Enable SSL
|
||||
enable-start-tls=Enable StartTLS
|
||||
enable-auth=Enable Authentication
|
||||
|
|
|
@ -17,12 +17,39 @@
|
|||
<input class="form-control" id="smtpPort" type="number" ng-model="realm.smtpServer.port" placeholder="{{:: 'smtp-port' | translate}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="smtpFromDisplayName">{{:: 'fromDisplayName' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="smtpFromDisplayName" type="text" ng-model="realm.smtpServer.fromDisplayName" placeholder="{{:: 'sender-email-addr-display' | translate}}">
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'fromDisplayName.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="smtpFrom"><span class="required">*</span> {{:: 'from' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="smtpFrom" type="email" ng-model="realm.smtpServer.from" placeholder="{{:: 'sender-email-addr' | translate}}" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="smtpReplyToDisplayName">{{:: 'replyToDisplayName' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="smtpReplyToDisplayName" type="text" ng-model="realm.smtpServer.replyToDisplayName" placeholder="{{:: 'reply-to-email-addr-display' | translate}}">
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'replyToDisplayName.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="smtpReplyTo">{{:: 'replyTo' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="smtpReplyTo" type="email" ng-model="realm.smtpServer.replyTo" placeholder="{{:: 'reply-to-email-addr' | translate}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="smtpEnvelopeFrom">{{:: 'envelopeFrom' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="smtpEnvelopeFrom" type="email" ng-model="realm.smtpServer.envelopeFrom" placeholder="{{:: 'sender-envelope-email-addr' | translate}}">
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'envelopeFrom.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="smtpSSL">{{:: 'enable-ssl' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
|
|
Loading…
Reference in a new issue