You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
So, we recently were asked to add Email One Time Passcodes to our Keycloak. I was very happy to find this repository!
However, after several hours of testing/compiling/deploying/pulling hairs out, I've found that there seems to be an issue with how the plugin itself handles theme lookup.
We deploy Keycloak into Kubernetes using the bitnami container/helm chart. We're running 22.0.5. In order to add this awesome plugin, I:
Clone this repository and built from master after updating the pom.xml to specify a new custom version (v0.4-KC22.0.5-custom) and updating the keycloak.version to 22.0.5 using openJDK 17 on RHEL 8.
a dockerfile to build a custom container:
FROM docker.io/bitnami/keycloak:22.0.5-debian-11-r4
# Copy over the plugin itself
COPY keycloak-2fa-email-authenticator-v0.4-KC22.0.5-custom.jar /opt/bitnami/keycloak/providers/
# # Copy over the template resources
COPY themes/ /opt/bitnami/keycloak/themes/
# Build it.
RUN /opt/bitnami/keycloak/bin/kc.sh build
ENTRYPOINT ["/opt/bitnami/scripts/keycloak/entrypoint.sh"]
CMD ["/opt/bitnami/scripts/keycloak/run.sh"]
I tried having the themes/ dir containing several things, and here are the results:
Nothing
The email code theme items per the README under /opt/bitnami/keycloak/themes/base/(etc)
The email code theme as a folder under themes/ Did not work
I additionally copied the themes/ out from the org.keycloak.keycloak-themes-22.0.5.jar jar so that /opt/bitnami/keycloak/themes/ looks like:
base
email-code-theme
keycloak
keycloak.v2
However, testing revealed a consistent behavior:
Email verification works
Email OTP does not work with the following stack trace:
2023-12-21 18:36:42,047 ERROR [com.mesutpiskin.keycloak.auth.email.EmailAuthenticatorForm] (executor-thread-2) Failed to send access code email. realm=d2dfd77d-5b84-484f-a89b-b7896349df06 [email protected]: org.keycloak.email.EmailException: Failed to template email
at org.keycloak.email.freemarker.FreeMarkerEmailTemplateProvider.processTemplate(FreeMarkerEmailTemplateProvider.java:242)
at org.keycloak.email.freemarker.FreeMarkerEmailTemplateProvider.send(FreeMarkerEmailTemplateProvider.java:257)
at org.keycloak.email.freemarker.FreeMarkerEmailTemplateProvider.send(FreeMarkerEmailTemplateProvider.java:252)
at com.mesutpiskin.keycloak.auth.email.EmailAuthenticatorForm.sendEmailWithCode(EmailAuthenticatorForm.java:179)
at com.mesutpiskin.keycloak.auth.email.EmailAuthenticatorForm.generateAndSendEmailCode(EmailAuthenticatorForm.java:77)
at com.mesutpiskin.keycloak.auth.email.EmailAuthenticatorForm.challenge(EmailAuthenticatorForm.java:44)
at org.keycloak.authentication.authenticators.browser.AbstractUsernameFormAuthenticator.challenge(AbstractUsernameFormAuthenticator.java:66)
at com.mesutpiskin.keycloak.auth.email.EmailAuthenticatorForm.authenticate(EmailAuthenticatorForm.java:39)
at org.keycloak.authentication.DefaultAuthenticationFlow.processSingleFlowExecutionModel(DefaultAuthenticationFlow.java:445)
at org.keycloak.authentication.DefaultAuthenticationFlow.processFlow(DefaultAuthenticationFlow.java:249)
at org.keycloak.authentication.DefaultAuthenticationFlow.processSingleFlowExecutionModel(DefaultAuthenticationFlow.java:380)
at org.keycloak.authentication.DefaultAuthenticationFlow.processFlow(DefaultAuthenticationFlow.java:249)
at org.keycloak.authentication.DefaultAuthenticationFlow.processSingleFlowExecutionModel(DefaultAuthenticationFlow.java:380)
at org.keycloak.authentication.DefaultAuthenticationFlow.processFlow(DefaultAuthenticationFlow.java:271)
at org.keycloak.authentication.AuthenticationProcessor.authenticateOnly(AuthenticationProcessor.java:1026)
at org.keycloak.services.resources.LoginActionsService$2.authenticateOnly(LoginActionsService.java:874)
at org.keycloak.authentication.AuthenticationProcessor.authenticate(AuthenticationProcessor.java:888)
at org.keycloak.services.resources.LoginActionsService.processFlow(LoginActionsService.java:380)
at org.keycloak.services.resources.LoginActionsService.brokerLoginFlow(LoginActionsService.java:904)
at org.keycloak.services.resources.LoginActionsService.postBrokerLoginGet(LoginActionsService.java:809)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:154)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:118)
at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:560)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:452)
at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:413)
at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:321)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:415)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:378)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:174)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:131)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:33)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:429)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:240)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:154)
at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:321)
at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:157)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:229)
at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:82)
at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:147)
at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:84)
at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:44)
at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284)
at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:177)
at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
at io.quarkus.vertx.http.runtime.options.HttpServerCommonHandlers$1.handle(HttpServerCommonHandlers.java:58)
at io.quarkus.vertx.http.runtime.options.HttpServerCommonHandlers$1.handle(HttpServerCommonHandlers.java:36)
at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284)
at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:177)
at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
at org.keycloak.quarkus.runtime.integration.web.QuarkusRequestFilter.lambda$createBlockingHandler$0(QuarkusRequestFilter.java:82)
at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:576)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538)
at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: org.keycloak.email.EmailException: Failed to template plain text email.
at org.keycloak.email.freemarker.FreeMarkerEmailTemplateProvider.processTemplate(FreeMarkerEmailTemplateProvider.java:230)
... 60 more
Caused by: org.keycloak.theme.FreeMarkerException: Failed to process template text/code-email.ftl
at org.keycloak.theme.freemarker.DefaultFreeMarkerProvider.processTemplate(DefaultFreeMarkerProvider.java:52)
at org.keycloak.email.freemarker.FreeMarkerEmailTemplateProvider.processTemplate(FreeMarkerEmailTemplateProvider.java:228)
... 60 more
Caused by: freemarker.template.TemplateNotFoundException: Template not found for name "text/code-email.ftl".
The name was interpreted by this TemplateLoader: org.keycloak.theme.freemarker.DefaultFreeMarkerProvider$ThemeTemplateLoader@6e291479.
at freemarker.template.Configuration.getTemplate(Configuration.java:2957)
at freemarker.template.Configuration.getTemplate(Configuration.java:2777)
at org.keycloak.theme.freemarker.DefaultFreeMarkerProvider.getTemplate(DefaultFreeMarkerProvider.java:66)
at org.keycloak.theme.freemarker.DefaultFreeMarkerProvider.processTemplate(DefaultFreeMarkerProvider.java:45)
... 61 more
Part of what I discovered is that the plugin seems to be expecting to use the template based on what the Realm Settings -> Themes -> Email Code Theme setting is, set to. However, Keycloak uses this same setting for email verification. So if we change that setting to the email-code-theme, then Email OTP works, but keycloak's email verification does not. If we set it to Base or Keycloak, then Email verification works, but Email OTP does not.
I tried looking at the java source to figure out how to figure out how to set the plugin to use a different theme but I couldn't figure it out (I haven't been a Java dev in like, 10 years, so forgive me XD). It seems to be set on this line but...clearly something isn't correct.
The text was updated successfully, but these errors were encountered:
So, we recently were asked to add Email One Time Passcodes to our Keycloak. I was very happy to find this repository!
However, after several hours of testing/compiling/deploying/pulling hairs out, I've found that there seems to be an issue with how the plugin itself handles theme lookup.
We deploy Keycloak into Kubernetes using the bitnami container/helm chart. We're running 22.0.5. In order to add this awesome plugin, I:
Clone this repository and built from master after updating the pom.xml to specify a new custom version (v0.4-KC22.0.5-custom) and updating the keycloak.version to 22.0.5 using openJDK 17 on RHEL 8.
a dockerfile to build a custom container:
I tried having the themes/ dir containing several things, and here are the results:
org.keycloak.keycloak-themes-22.0.5.jar
jar so that /opt/bitnami/keycloak/themes/ looks like:However, testing revealed a consistent behavior:
Part of what I discovered is that the plugin seems to be expecting to use the template based on what the Realm Settings -> Themes -> Email Code Theme setting is, set to. However, Keycloak uses this same setting for email verification. So if we change that setting to the email-code-theme, then Email OTP works, but keycloak's email verification does not. If we set it to Base or Keycloak, then Email verification works, but Email OTP does not.
I tried looking at the java source to figure out how to figure out how to set the plugin to use a different theme but I couldn't figure it out (I haven't been a Java dev in like, 10 years, so forgive me XD). It seems to be set on this line but...clearly something isn't correct.
The text was updated successfully, but these errors were encountered: