diff --git a/events/email/src/main/java/org/keycloak/events/email/EmailEventListenerProvider.java b/events/email/src/main/java/org/keycloak/events/email/EmailEventListenerProvider.java index 400ef04e15..9e1e127bea 100755 --- a/events/email/src/main/java/org/keycloak/events/email/EmailEventListenerProvider.java +++ b/events/email/src/main/java/org/keycloak/events/email/EmailEventListenerProvider.java @@ -2,7 +2,7 @@ package org.keycloak.events.email; import org.jboss.logging.Logger; import org.keycloak.email.EmailException; -import org.keycloak.email.EmailProvider; +import org.keycloak.email.EmailTemplateProvider; import org.keycloak.events.admin.AdminEvent; import org.keycloak.events.Event; import org.keycloak.events.EventListenerProvider; @@ -23,13 +23,13 @@ public class EmailEventListenerProvider implements EventListenerProvider { private KeycloakSession session; private RealmProvider model; - private EmailProvider emailProvider; + private EmailTemplateProvider emailTemplateProvider; private Set includedEvents; - public EmailEventListenerProvider(KeycloakSession session, EmailProvider emailProvider, Set includedEvents) { + public EmailEventListenerProvider(KeycloakSession session, EmailTemplateProvider emailTemplateProvider, Set includedEvents) { this.session = session; this.model = session.realms(); - this.emailProvider = emailProvider; + this.emailTemplateProvider = emailTemplateProvider; this.includedEvents = includedEvents; } @@ -41,7 +41,7 @@ public class EmailEventListenerProvider implements EventListenerProvider { UserModel user = session.users().getUserById(event.getUserId(), realm); if (user != null && user.getEmail() != null && user.isEmailVerified()) { try { - emailProvider.setRealm(realm).setUser(user).sendEvent(event); + emailTemplateProvider.setRealm(realm).setUser(user).sendEvent(event); } catch (EmailException e) { log.error("Failed to send type mail", e); } diff --git a/events/email/src/main/java/org/keycloak/events/email/EmailEventListenerProviderFactory.java b/events/email/src/main/java/org/keycloak/events/email/EmailEventListenerProviderFactory.java index 9f662dc2d7..ae2c4d011b 100755 --- a/events/email/src/main/java/org/keycloak/events/email/EmailEventListenerProviderFactory.java +++ b/events/email/src/main/java/org/keycloak/events/email/EmailEventListenerProviderFactory.java @@ -1,7 +1,7 @@ package org.keycloak.events.email; import org.keycloak.Config; -import org.keycloak.email.EmailProvider; +import org.keycloak.email.EmailTemplateProvider; import org.keycloak.events.EventListenerProvider; import org.keycloak.events.EventListenerProviderFactory; import org.keycloak.events.EventType; @@ -26,8 +26,8 @@ public class EmailEventListenerProviderFactory implements EventListenerProviderF @Override public EventListenerProvider create(KeycloakSession session) { - EmailProvider emailProvider = session.getProvider(EmailProvider.class); - return new EmailEventListenerProvider(session, emailProvider, includedEvents); + EmailTemplateProvider emailTemplateProvider = session.getProvider(EmailTemplateProvider.class); + return new EmailEventListenerProvider(session, emailTemplateProvider, includedEvents); } @Override diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js index a6945f304c..b2c7848235 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js @@ -1195,7 +1195,7 @@ module.controller('RealmSMTPSettingsCtrl', function($scope, Current, Realm, real } } - obj['port'] = obj['port'].toString(); + obj['port'] = obj['port'] && obj['port'].toString(); return obj; } diff --git a/forms/email-api/src/main/java/org/keycloak/email/EmailSenderProvider.java b/forms/email-api/src/main/java/org/keycloak/email/EmailSenderProvider.java new file mode 100755 index 0000000000..95ccabe6b7 --- /dev/null +++ b/forms/email-api/src/main/java/org/keycloak/email/EmailSenderProvider.java @@ -0,0 +1,14 @@ +package org.keycloak.email; + +import org.keycloak.models.RealmModel; +import org.keycloak.models.UserModel; +import org.keycloak.provider.Provider; + +/** + * @author Stian Thorgersen + */ +public interface EmailSenderProvider extends Provider { + + void send(RealmModel realm, UserModel user, String subject, String textBody, String htmlBody) throws EmailException; + +} diff --git a/forms/email-api/src/main/java/org/keycloak/email/EmailProviderFactory.java b/forms/email-api/src/main/java/org/keycloak/email/EmailSenderProviderFactory.java similarity index 63% rename from forms/email-api/src/main/java/org/keycloak/email/EmailProviderFactory.java rename to forms/email-api/src/main/java/org/keycloak/email/EmailSenderProviderFactory.java index 02d7daff00..452ab7688d 100644 --- a/forms/email-api/src/main/java/org/keycloak/email/EmailProviderFactory.java +++ b/forms/email-api/src/main/java/org/keycloak/email/EmailSenderProviderFactory.java @@ -5,5 +5,5 @@ import org.keycloak.provider.ProviderFactory; /** * @author Stian Thorgersen */ -public interface EmailProviderFactory extends ProviderFactory { +public interface EmailSenderProviderFactory extends ProviderFactory { } diff --git a/forms/email-api/src/main/java/org/keycloak/email/EmailSpi.java b/forms/email-api/src/main/java/org/keycloak/email/EmailSenderSpi.java similarity index 76% rename from forms/email-api/src/main/java/org/keycloak/email/EmailSpi.java rename to forms/email-api/src/main/java/org/keycloak/email/EmailSenderSpi.java index 8d085336c6..abb5601acf 100644 --- a/forms/email-api/src/main/java/org/keycloak/email/EmailSpi.java +++ b/forms/email-api/src/main/java/org/keycloak/email/EmailSenderSpi.java @@ -7,7 +7,7 @@ import org.keycloak.provider.Spi; /** * @author Stian Thorgersen */ -public class EmailSpi implements Spi { +public class EmailSenderSpi implements Spi { @Override public boolean isInternal() { @@ -16,16 +16,16 @@ public class EmailSpi implements Spi { @Override public String getName() { - return "email"; + return "emailSender"; } @Override public Class getProviderClass() { - return EmailProvider.class; + return EmailSenderProvider.class; } @Override public Class getProviderFactoryClass() { - return EmailProviderFactory.class; + return EmailSenderProviderFactory.class; } } diff --git a/forms/email-api/src/main/java/org/keycloak/email/EmailProvider.java b/forms/email-api/src/main/java/org/keycloak/email/EmailTemplateProvider.java similarity index 82% rename from forms/email-api/src/main/java/org/keycloak/email/EmailProvider.java rename to forms/email-api/src/main/java/org/keycloak/email/EmailTemplateProvider.java index 151eec701e..e599e2fac3 100755 --- a/forms/email-api/src/main/java/org/keycloak/email/EmailProvider.java +++ b/forms/email-api/src/main/java/org/keycloak/email/EmailTemplateProvider.java @@ -8,15 +8,15 @@ import org.keycloak.provider.Provider; /** * @author Stian Thorgersen */ -public interface EmailProvider extends Provider { +public interface EmailTemplateProvider extends Provider { String IDENTITY_PROVIDER_BROKER_CONTEXT = "identityProviderBrokerCtx"; - public EmailProvider setRealm(RealmModel realm); + public EmailTemplateProvider setRealm(RealmModel realm); - public EmailProvider setUser(UserModel user); + public EmailTemplateProvider setUser(UserModel user); - public EmailProvider setAttribute(String name, Object value); + public EmailTemplateProvider setAttribute(String name, Object value); public void sendEvent(Event event) throws EmailException; diff --git a/forms/email-api/src/main/java/org/keycloak/email/EmailTemplateProviderFactory.java b/forms/email-api/src/main/java/org/keycloak/email/EmailTemplateProviderFactory.java new file mode 100644 index 0000000000..bc934cbf7c --- /dev/null +++ b/forms/email-api/src/main/java/org/keycloak/email/EmailTemplateProviderFactory.java @@ -0,0 +1,9 @@ +package org.keycloak.email; + +import org.keycloak.provider.ProviderFactory; + +/** + * @author Stian Thorgersen + */ +public interface EmailTemplateProviderFactory extends ProviderFactory { +} diff --git a/forms/email-api/src/main/java/org/keycloak/email/EmailTemplateSpi.java b/forms/email-api/src/main/java/org/keycloak/email/EmailTemplateSpi.java new file mode 100644 index 0000000000..c84c87c5c6 --- /dev/null +++ b/forms/email-api/src/main/java/org/keycloak/email/EmailTemplateSpi.java @@ -0,0 +1,31 @@ +package org.keycloak.email; + +import org.keycloak.provider.Provider; +import org.keycloak.provider.ProviderFactory; +import org.keycloak.provider.Spi; + +/** + * @author Stian Thorgersen + */ +public class EmailTemplateSpi implements Spi { + + @Override + public boolean isInternal() { + return true; + } + + @Override + public String getName() { + return "emailTemplate"; + } + + @Override + public Class getProviderClass() { + return EmailTemplateProvider.class; + } + + @Override + public Class getProviderFactoryClass() { + return org.keycloak.email.EmailTemplateProviderFactory.class; + } +} diff --git a/forms/email-api/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/forms/email-api/src/main/resources/META-INF/services/org.keycloak.provider.Spi index 4110dbad33..80967a250e 100644 --- a/forms/email-api/src/main/resources/META-INF/services/org.keycloak.provider.Spi +++ b/forms/email-api/src/main/resources/META-INF/services/org.keycloak.provider.Spi @@ -1 +1,2 @@ -org.keycloak.email.EmailSpi \ No newline at end of file +org.keycloak.email.EmailSenderSpi +org.keycloak.email.EmailTemplateSpi \ No newline at end of file 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/FreeMarkerEmailTemplateProvider.java similarity index 64% rename from forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailProvider.java rename to forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailTemplateProvider.java index 25b0166fd7..4ce817021e 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/FreeMarkerEmailTemplateProvider.java @@ -1,29 +1,10 @@ package org.keycloak.email.freemarker; -import java.text.MessageFormat; -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -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.broker.provider.BrokeredIdentityContext; import org.keycloak.common.util.ObjectUtil; import org.keycloak.email.EmailException; -import org.keycloak.email.EmailProvider; +import org.keycloak.email.EmailSenderProvider; +import org.keycloak.email.EmailTemplateProvider; import org.keycloak.email.freemarker.beans.EventBean; import org.keycloak.email.freemarker.beans.ProfileBean; import org.keycloak.events.Event; @@ -33,43 +14,43 @@ import org.keycloak.freemarker.FreeMarkerUtil; import org.keycloak.freemarker.Theme; import org.keycloak.freemarker.ThemeProvider; import org.keycloak.freemarker.beans.MessageFormatterMethod; -import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; +import java.text.MessageFormat; +import java.util.*; + /** * @author Stian Thorgersen */ -public class FreeMarkerEmailProvider implements EmailProvider { - - private static final Logger log = Logger.getLogger(FreeMarkerEmailProvider.class); +public class FreeMarkerEmailTemplateProvider implements EmailTemplateProvider { private KeycloakSession session; private FreeMarkerUtil freeMarker; private RealmModel realm; private UserModel user; - private final Map attributes = new HashMap(); + private final Map attributes = new HashMap<>(); - public FreeMarkerEmailProvider(KeycloakSession session, FreeMarkerUtil freeMarker) { + public FreeMarkerEmailTemplateProvider(KeycloakSession session, FreeMarkerUtil freeMarker) { this.session = session; this.freeMarker = freeMarker; } @Override - public EmailProvider setRealm(RealmModel realm) { + public EmailTemplateProvider setRealm(RealmModel realm) { this.realm = realm; return this; } @Override - public EmailProvider setUser(UserModel user) { + public EmailTemplateProvider setUser(UserModel user) { this.user = user; return this; } @Override - public EmailProvider setAttribute(String name, Object value) { + public EmailTemplateProvider setAttribute(String name, Object value) { attributes.put(name, value); return this; } @@ -178,73 +159,9 @@ public class FreeMarkerEmailProvider implements EmailProvider { } } - private void send(String subject, String textBody, String htmlBody) throws EmailException { - try { - String address = user.getEmail(); - Map config = realm.getSmtpConfig(); - - Properties props = new Properties(); - props.setProperty("mail.smtp.host", config.get("host")); - - boolean auth = "true".equals(config.get("auth")); - boolean ssl = "true".equals(config.get("ssl")); - boolean starttls = "true".equals(config.get("starttls")); - - if (config.containsKey("port")) { - props.setProperty("mail.smtp.port", config.get("port")); - } - - if (auth) { - props.put("mail.smtp.auth", "true"); - } - - if (ssl) { - props.put("mail.smtp.socketFactory.port", config.get("port")); - props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); - } - - if (starttls) { - props.put("mail.smtp.starttls.enable", "true"); - } - - String from = config.get("from"); - - 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.setContent(multipart); - msg.saveChanges(); - msg.setSentDate(new Date()); - - 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) { - log.warn("Failed to send email", e); - throw new EmailException(e); - } + EmailSenderProvider emailSender = session.getProvider(EmailSenderProvider.class); + emailSender.send(realm, user, subject, textBody, htmlBody); } @Override diff --git a/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailProviderFactory.java b/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailTemplateProviderFactory.java similarity index 67% rename from forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailProviderFactory.java rename to forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailTemplateProviderFactory.java index f0dc1209ed..db0d9f2a1a 100755 --- a/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailProviderFactory.java +++ b/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailTemplateProviderFactory.java @@ -1,8 +1,8 @@ package org.keycloak.email.freemarker; import org.keycloak.Config; -import org.keycloak.email.EmailProvider; -import org.keycloak.email.EmailProviderFactory; +import org.keycloak.email.EmailTemplateProvider; +import org.keycloak.email.EmailTemplateProviderFactory; import org.keycloak.freemarker.FreeMarkerUtil; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; @@ -10,13 +10,13 @@ import org.keycloak.models.KeycloakSessionFactory; /** * @author Stian Thorgersen */ -public class FreeMarkerEmailProviderFactory implements EmailProviderFactory { +public class FreeMarkerEmailTemplateProviderFactory implements EmailTemplateProviderFactory { private FreeMarkerUtil freeMarker; @Override - public EmailProvider create(KeycloakSession session) { - return new FreeMarkerEmailProvider(session, freeMarker); + public EmailTemplateProvider create(KeycloakSession session) { + return new FreeMarkerEmailTemplateProvider(session, freeMarker); } @Override @@ -26,7 +26,6 @@ public class FreeMarkerEmailProviderFactory implements EmailProviderFactory { @Override public void postInit(KeycloakSessionFactory factory) { - } @Override diff --git a/forms/email-freemarker/src/main/resources/META-INF/services/org.keycloak.email.EmailProviderFactory b/forms/email-freemarker/src/main/resources/META-INF/services/org.keycloak.email.EmailProviderFactory deleted file mode 100644 index 5b31f6e990..0000000000 --- a/forms/email-freemarker/src/main/resources/META-INF/services/org.keycloak.email.EmailProviderFactory +++ /dev/null @@ -1 +0,0 @@ -org.keycloak.email.freemarker.FreeMarkerEmailProviderFactory \ No newline at end of file diff --git a/forms/email-freemarker/src/main/resources/META-INF/services/org.keycloak.email.EmailTemplateProviderFactory b/forms/email-freemarker/src/main/resources/META-INF/services/org.keycloak.email.EmailTemplateProviderFactory new file mode 100644 index 0000000000..aa87e5378e --- /dev/null +++ b/forms/email-freemarker/src/main/resources/META-INF/services/org.keycloak.email.EmailTemplateProviderFactory @@ -0,0 +1 @@ +org.keycloak.email.freemarker.FreeMarkerEmailTemplateProviderFactory \ No newline at end of file diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java index d1b4df9bd6..1cbd32830b 100755 --- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java +++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java @@ -24,7 +24,7 @@ import org.keycloak.authentication.requiredactions.util.UserUpdateProfileContext import org.keycloak.broker.provider.BrokeredIdentityContext; import org.keycloak.common.util.ObjectUtil; import org.keycloak.email.EmailException; -import org.keycloak.email.EmailProvider; +import org.keycloak.email.EmailTemplateProvider; import org.keycloak.freemarker.BrowserSecurityHeaderSetup; import org.keycloak.freemarker.FreeMarkerException; import org.keycloak.freemarker.FreeMarkerUtil; @@ -153,7 +153,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider { String link = builder.build(realm.getName()).toString(); long expiration = TimeUnit.SECONDS.toMinutes(realm.getAccessCodeLifespanUserAction()); - session.getProvider(EmailProvider.class).setRealm(realm).setUser(user).sendVerifyEmail(link, expiration); + session.getProvider(EmailTemplateProvider.class).setRealm(realm).setUser(user).sendVerifyEmail(link, expiration); } catch (EmailException e) { logger.error("Failed to send verification email", e); return setError(Messages.EMAIL_SENT_ERROR).createErrorPage(); diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpEmailVerificationAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpEmailVerificationAuthenticator.java index ae28d3edc9..9780d6a134 100644 --- a/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpEmailVerificationAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpEmailVerificationAuthenticator.java @@ -13,7 +13,7 @@ import org.keycloak.authentication.requiredactions.VerifyEmail; import org.keycloak.authentication.authenticators.broker.util.SerializedBrokeredIdentityContext; import org.keycloak.broker.provider.BrokeredIdentityContext; import org.keycloak.email.EmailException; -import org.keycloak.email.EmailProvider; +import org.keycloak.email.EmailTemplateProvider; import org.keycloak.events.Details; import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; @@ -68,10 +68,10 @@ public class IdpEmailVerificationAuthenticator extends AbstractIdpAuthenticator long expiration = TimeUnit.SECONDS.toMinutes(context.getRealm().getAccessCodeLifespanUserAction()); try { - context.getSession().getProvider(EmailProvider.class) + context.getSession().getProvider(EmailTemplateProvider.class) .setRealm(realm) .setUser(existingUser) - .setAttribute(EmailProvider.IDENTITY_PROVIDER_BROKER_CONTEXT, brokerContext) + .setAttribute(EmailTemplateProvider.IDENTITY_PROVIDER_BROKER_CONTEXT, brokerContext) .sendConfirmIdentityBrokerLink(link, expiration); event.success(); diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialChooseUser.java b/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialChooseUser.java index a3538aab38..e48d19456c 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialChooseUser.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialChooseUser.java @@ -8,29 +8,20 @@ import org.keycloak.authentication.Authenticator; import org.keycloak.authentication.AuthenticatorFactory; import org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticator; import org.keycloak.authentication.authenticators.browser.AbstractUsernameFormAuthenticator; -import org.keycloak.email.EmailException; -import org.keycloak.email.EmailProvider; import org.keycloak.events.Details; import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; -import org.keycloak.login.LoginFormsProvider; import org.keycloak.models.AuthenticationExecutionModel; -import org.keycloak.models.ClientSessionModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; -import org.keycloak.models.UserSessionModel; -import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.provider.ProviderConfigProperty; -import org.keycloak.services.Urls; import org.keycloak.services.messages.Messages; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriBuilder; import java.util.List; -import java.util.concurrent.TimeUnit; /** * @author Bill Burke diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialEmail.java b/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialEmail.java index 678aac21c4..a66126dfce 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialEmail.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialEmail.java @@ -8,7 +8,7 @@ import org.keycloak.authentication.Authenticator; import org.keycloak.authentication.AuthenticatorFactory; import org.keycloak.authentication.authenticators.browser.AbstractUsernameFormAuthenticator; import org.keycloak.email.EmailException; -import org.keycloak.email.EmailProvider; +import org.keycloak.email.EmailTemplateProvider; import org.keycloak.events.Details; import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; @@ -72,7 +72,7 @@ public class ResetCredentialEmail implements Authenticator, AuthenticatorFactory long expiration = TimeUnit.SECONDS.toMinutes(context.getRealm().getAccessCodeLifespanUserAction()); try { - context.getSession().getProvider(EmailProvider.class).setRealm(context.getRealm()).setUser(user).sendPasswordReset(link, expiration); + context.getSession().getProvider(EmailTemplateProvider.class).setRealm(context.getRealm()).setUser(user).sendPasswordReset(link, expiration); event.clone().event(EventType.SEND_RESET_PASSWORD) .user(user) .detail(Details.USERNAME, username) diff --git a/services/src/main/java/org/keycloak/email/DefaultEmailSenderProvider.java b/services/src/main/java/org/keycloak/email/DefaultEmailSenderProvider.java new file mode 100644 index 0000000000..1a06877867 --- /dev/null +++ b/services/src/main/java/org/keycloak/email/DefaultEmailSenderProvider.java @@ -0,0 +1,102 @@ +package org.keycloak.email; + +import org.jboss.logging.Logger; +import org.keycloak.models.RealmModel; +import org.keycloak.models.UserModel; + +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 java.util.Date; +import java.util.Map; +import java.util.Properties; + +/** + * @author Stian Thorgersen + */ +public class DefaultEmailSenderProvider implements EmailSenderProvider { + + private static final Logger log = Logger.getLogger(DefaultEmailSenderProvider.class); + + @Override + public void send(RealmModel realm, UserModel user, String subject, String textBody, String htmlBody) throws EmailException { + try { + String address = user.getEmail(); + Map config = realm.getSmtpConfig(); + + Properties props = new Properties(); + props.setProperty("mail.smtp.host", config.get("host")); + + boolean auth = "true".equals(config.get("auth")); + boolean ssl = "true".equals(config.get("ssl")); + boolean starttls = "true".equals(config.get("starttls")); + + if (config.containsKey("port")) { + props.setProperty("mail.smtp.port", config.get("port")); + } + + if (auth) { + props.setProperty("mail.smtp.auth", "true"); + } + + if (ssl) { + props.setProperty("mail.smtp.ssl.enable", "true"); + } + + if (starttls) { + props.setProperty("mail.smtp.starttls.enable", "true"); + } + + props.setProperty("mail.smtp.timeout", "10000"); + props.setProperty("mail.smtp.connectiontimeout", "10000"); + + String from = config.get("from"); + + 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.setContent(multipart); + msg.saveChanges(); + msg.setSentDate(new Date()); + + 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) { + log.error("Failed to send email", e); + throw new EmailException(e); + } + } + + @Override + public void close() { + + } + +} diff --git a/services/src/main/java/org/keycloak/email/DefaultEmailSenderProviderFactory.java b/services/src/main/java/org/keycloak/email/DefaultEmailSenderProviderFactory.java new file mode 100644 index 0000000000..96770001ff --- /dev/null +++ b/services/src/main/java/org/keycloak/email/DefaultEmailSenderProviderFactory.java @@ -0,0 +1,34 @@ +package org.keycloak.email; + +import org.keycloak.Config; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakSessionFactory; + +/** + * @author Stian Thorgersen + */ +public class DefaultEmailSenderProviderFactory implements EmailSenderProviderFactory { + + @Override + public EmailSenderProvider create(KeycloakSession session) { + return new DefaultEmailSenderProvider(); + } + + @Override + public void init(Config.Scope config) { + } + + @Override + public void postInit(KeycloakSessionFactory factory) { + } + + @Override + public void close() { + } + + @Override + public String getId() { + return "default"; + } + +} diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleMapperResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleMapperResource.java index 4423c549c5..dfd2119c47 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/RoleMapperResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleMapperResource.java @@ -2,61 +2,37 @@ package org.keycloak.services.resources.admin; import org.jboss.logging.Logger; import org.jboss.resteasy.annotations.cache.NoCache; -import org.jboss.resteasy.spi.BadRequestException; import org.jboss.resteasy.spi.NotFoundException; import org.keycloak.common.ClientConnection; -import org.keycloak.email.EmailException; -import org.keycloak.email.EmailProvider; import org.keycloak.events.admin.OperationType; import org.keycloak.models.ClientModel; -import org.keycloak.models.ClientSessionModel; -import org.keycloak.models.Constants; import org.keycloak.models.KeycloakSession; -import org.keycloak.models.ModelReadOnlyException; import org.keycloak.models.RealmModel; import org.keycloak.models.RoleMapperModel; import org.keycloak.models.RoleModel; -import org.keycloak.models.UserCredentialModel; -import org.keycloak.models.UserModel; -import org.keycloak.models.UserSessionModel; import org.keycloak.models.utils.ModelToRepresentation; -import org.keycloak.models.utils.RepresentationToModel; -import org.keycloak.protocol.oidc.OIDCLoginProtocol; -import org.keycloak.protocol.oidc.TokenManager; -import org.keycloak.protocol.oidc.utils.RedirectUtils; import org.keycloak.representations.idm.ClientMappingsRepresentation; -import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.MappingsRepresentation; import org.keycloak.representations.idm.RoleRepresentation; -import org.keycloak.services.ErrorResponse; -import org.keycloak.services.Urls; import org.keycloak.services.managers.BruteForceProtector; -import org.keycloak.services.managers.ClientSessionCode; import org.keycloak.services.managers.RealmManager; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; -import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; import java.util.ArrayList; import java.util.HashMap; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.TimeUnit; /** * Base resource for managing users diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java index 202861049b..901de1f7b2 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java @@ -8,7 +8,7 @@ import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.keycloak.common.ClientConnection; import org.keycloak.authentication.RequiredActionProvider; import org.keycloak.email.EmailException; -import org.keycloak.email.EmailProvider; +import org.keycloak.email.EmailTemplateProvider; import org.keycloak.events.Details; import org.keycloak.events.EventBuilder; import org.keycloak.events.EventType; @@ -23,7 +23,6 @@ import org.keycloak.models.KeycloakSession; import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.ModelReadOnlyException; import org.keycloak.models.RealmModel; -import org.keycloak.models.RoleModel; import org.keycloak.models.UserConsentModel; import org.keycloak.models.UserCredentialModel; import org.keycloak.models.UserModel; @@ -34,18 +33,14 @@ import org.keycloak.protocol.oidc.OIDCLoginProtocol; import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.protocol.oidc.utils.RedirectUtils; import org.keycloak.provider.ProviderFactory; -import org.keycloak.representations.idm.ClientMappingsRepresentation; import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.FederatedIdentityRepresentation; import org.keycloak.representations.idm.GroupRepresentation; -import org.keycloak.representations.idm.MappingsRepresentation; -import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.UserConsentRepresentation; import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserSessionRepresentation; import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.ClientSessionCode; -import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.UserManager; import org.keycloak.services.ErrorResponse; import org.keycloak.services.Urls; @@ -804,7 +799,7 @@ public class UsersResource { String link = builder.build(realm.getName()).toString(); long expiration = TimeUnit.SECONDS.toMinutes(realm.getAccessCodeLifespanUserAction()); - this.session.getProvider(EmailProvider.class).setRealm(realm).setUser(user).sendExecuteActions(link, expiration); + this.session.getProvider(EmailTemplateProvider.class).setRealm(realm).setUser(user).sendExecuteActions(link, expiration); //audit.user(user).detail(Details.EMAIL, user.getEmail()).detail(Details.CODE_ID, accessCode.getCodeId()).success(); @@ -856,7 +851,7 @@ public class UsersResource { String link = builder.build(realm.getName()).toString(); long expiration = TimeUnit.SECONDS.toMinutes(realm.getAccessCodeLifespanUserAction()); - this.session.getProvider(EmailProvider.class).setRealm(realm).setUser(user).sendVerifyEmail(link, expiration); + this.session.getProvider(EmailTemplateProvider.class).setRealm(realm).setUser(user).sendVerifyEmail(link, expiration); //audit.user(user).detail(Details.EMAIL, user.getEmail()).detail(Details.CODE_ID, accessCode.getCodeId()).success(); diff --git a/services/src/main/resources/META-INF/services/org.keycloak.email.EmailSenderProviderFactory b/services/src/main/resources/META-INF/services/org.keycloak.email.EmailSenderProviderFactory new file mode 100644 index 0000000000..42c58909cf --- /dev/null +++ b/services/src/main/resources/META-INF/services/org.keycloak.email.EmailSenderProviderFactory @@ -0,0 +1 @@ +org.keycloak.email.DefaultEmailSenderProviderFactory \ No newline at end of file