From 1346a4dacacdb7cbbe9188e2da5c1fc47b358760 Mon Sep 17 00:00:00 2001
From: sar
Date: Tue, 15 Jul 2025 12:50:13 -0500
Subject: [PATCH 01/10] Create custom email verification flow
---
.../CustomVerifyEmailRequiredAction.java | 133 ++++++++++++++++++
...cloak.authentication.RequiredActionFactory | 1 +
.../ol/email/mjml/email-verification.mjml | 37 ++++-
.../theme/ol/login/login-verify-email.ftl | 43 +++++-
4 files changed, 207 insertions(+), 7 deletions(-)
create mode 100644 ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
create mode 100644 ol-keycloak/oltheme/src/main/resources/META-INF/services/org.keycloak.authentication.RequiredActionFactory
diff --git a/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java b/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
new file mode 100644
index 0000000..6265f33
--- /dev/null
+++ b/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
@@ -0,0 +1,133 @@
+package edu.mit.ol.keycloak.providers;
+
+import org.keycloak.authentication.RequiredActionContext;
+import org.keycloak.authentication.RequiredActionProvider;
+import org.keycloak.authentication.RequiredActionFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.email.EmailException;
+import org.keycloak.email.EmailTemplateProvider;
+import org.keycloak.common.util.RandomString;
+import org.jboss.logging.Logger;
+
+import jakarta.ws.rs.core.Response;
+import java.util.Objects;
+
+public class CustomVerifyEmailRequiredAction implements RequiredActionProvider {
+
+ private static final Logger logger = Logger.getLogger(CustomVerifyEmailRequiredAction.class);
+ public static final String PROVIDER_ID = "CUSTOM_VERIFY_EMAIL";
+
+ @Override
+ public void evaluateTriggers(RequiredActionContext context) {
+ if (!context.getUser().isEmailVerified()) {
+ context.getUser().addRequiredAction(PROVIDER_ID);
+ }
+ }
+
+ @Override
+ public void requiredActionChallenge(RequiredActionContext context) {
+ // Check if we need to resend code
+ String resend = context.getHttpRequest().getDecodedFormParameters().getFirst("resend");
+ if ("true".equals(resend)) {
+ sendVerificationCode(context);
+ } else if (context.getUser().getFirstAttribute("email_verification_code") == null) {
+ // First time - send code
+ sendVerificationCode(context);
+ }
+
+ Response challenge = context.form()
+ .setAttribute("user", context.getUser())
+ .createForm("verify-email.ftl");
+ context.challenge(challenge);
+ }
+
+ @Override
+ public void processAction(RequiredActionContext context) {
+ String code = context.getHttpRequest().getDecodedFormParameters().getFirst("email_code");
+ String resend = context.getHttpRequest().getDecodedFormParameters().getFirst("resend");
+
+ if ("true".equals(resend)) {
+ sendVerificationCode(context);
+ requiredActionChallenge(context);
+ return;
+ }
+
+ if (code != null && isValidVerificationCode(context, code)) {
+ context.getUser().setEmailVerified(true);
+ context.getUser().removeAttribute("email_verification_code");
+ context.getUser().removeAttribute("email_code_timestamp");
+ context.success();
+ } else {
+ Response challenge = context.form()
+ .setError("Invalid verification code. Please check your email and try again.")
+ .setAttribute("user", context.getUser())
+ .createForm("verify-email.ftl");
+ context.challenge(challenge);
+ }
+ }
+
+ private void sendVerificationCode(RequiredActionContext context) {
+ String code = RandomString.randomCode(6);
+ long timestamp = System.currentTimeMillis();
+
+ context.getUser().setSingleAttribute("email_verification_code", code);
+ context.getUser().setSingleAttribute("email_code_timestamp", String.valueOf(timestamp));
+
+ try {
+ EmailTemplateProvider emailProvider = context.getSession().getProvider(EmailTemplateProvider.class);
+ emailProvider.setRealm(context.getRealm())
+ .setUser(context.getUser())
+ .setAttribute("code", code)
+ .send("emailVerificationSubject", "email-verification.ftl");
+ } catch (EmailException e) {
+ logger.error("Failed to send verification email", e);
+ }
+ }
+
+ private boolean isValidVerificationCode(RequiredActionContext context, String code) {
+ String storedCode = context.getUser().getFirstAttribute("email_verification_code");
+ String timestampStr = context.getUser().getFirstAttribute("email_code_timestamp");
+
+ if (storedCode == null || timestampStr == null) {
+ return false;
+ }
+
+ // Check if code is expired (15 minutes)
+ try {
+ long timestamp = Long.parseLong(timestampStr);
+ long now = System.currentTimeMillis();
+ if (now - timestamp > 15 * 60 * 1000) {
+ context.getUser().removeAttribute("email_verification_code");
+ context.getUser().removeAttribute("email_code_timestamp");
+ return false;
+ }
+ } catch (NumberFormatException e) {
+ return false;
+ }
+
+ return Objects.equals(code, storedCode);
+ }
+
+ @Override
+ public void close() {}
+
+ public static class Factory implements RequiredActionFactory {
+
+ @Override
+ public RequiredActionProvider create(KeycloakSession session) {
+ return new CustomVerifyEmailRequiredAction();
+ }
+
+ @Override
+ public String getDisplayText() {
+ return "Custom Email Verification with Code";
+ }
+
+ @Override
+ public String getId() {
+ return PROVIDER_ID;
+ }
+ }
+}
diff --git a/ol-keycloak/oltheme/src/main/resources/META-INF/services/org.keycloak.authentication.RequiredActionFactory b/ol-keycloak/oltheme/src/main/resources/META-INF/services/org.keycloak.authentication.RequiredActionFactory
new file mode 100644
index 0000000..a256d4b
--- /dev/null
+++ b/ol-keycloak/oltheme/src/main/resources/META-INF/services/org.keycloak.authentication.RequiredActionFactory
@@ -0,0 +1 @@
+edu.mit.ol.keycloak.providers.CustomVerifyEmailRequiredAction$Factory
diff --git a/ol-keycloak/oltheme/src/main/resources/theme/ol/email/mjml/email-verification.mjml b/ol-keycloak/oltheme/src/main/resources/theme/ol/email/mjml/email-verification.mjml
index 0eedba9..12d3a29 100644
--- a/ol-keycloak/oltheme/src/main/resources/theme/ol/email/mjml/email-verification.mjml
+++ b/ol-keycloak/oltheme/src/main/resources/theme/ol/email/mjml/email-verification.mjml
@@ -3,7 +3,6 @@
-
@@ -12,6 +11,39 @@
Thank you for creating an account with ${realmName}. Please complete
the account verification process by clicking this link:
+
+ <#if code??>
+
+
+ Your Verification Code
+
+
+
+
+
+ ${code}
+
+
+
+
+
+
+ Enter this code on the verification page to complete your email verification.
+
+
+ This code expires in 15 minutes.
+
+
+
+
+
+
+
+ Or click the button below to verify automatically:
+
+
+ #if>
+
Verify Your Email
@@ -21,8 +53,7 @@
-
-
+
\ No newline at end of file
diff --git a/ol-keycloak/oltheme/src/main/resources/theme/ol/login/login-verify-email.ftl b/ol-keycloak/oltheme/src/main/resources/theme/ol/login/login-verify-email.ftl
index bb23f5e..62ed93b 100755
--- a/ol-keycloak/oltheme/src/main/resources/theme/ol/login/login-verify-email.ftl
+++ b/ol-keycloak/oltheme/src/main/resources/theme/ol/login/login-verify-email.ftl
@@ -6,18 +6,53 @@
${msg("emailVerifyInstruction1", user.email)}
+
+
+
+
+
+
+
+
+
<#elseif section = "info">
-
${msg("emailVerifyInstruction2")}
+
A 6-digit verification code has been sent to your email address.
-
${msg("emailVerifyInstruction3")}
+
Enter the code from your email to verify your account.
- ${msg("emailVerifyInstruction4Bold")}
+ Code not working?
${msg("emailVerifyInstruction4")}
+
+
+ Didn't receive the code?
+ Check your spam folder or click "Resend Code" above.
${msg("emailVerifySupportLinkTitle")}.
#if>
-@layout.registrationLayout>
+@layout.registrationLayout>
\ No newline at end of file
From ee16a6cae079aab059cd466ca9855004c6d6de98 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Tue, 15 Jul 2025 17:53:25 +0000
Subject: [PATCH 02/10] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
.../CustomVerifyEmailRequiredAction.java | 20 +++++++++----------
.../ol/email/mjml/email-verification.mjml | 8 ++++----
.../theme/ol/login/login-verify-email.ftl | 14 ++++++-------
3 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java b/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
index 6265f33..267b588 100644
--- a/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
+++ b/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
@@ -18,7 +18,7 @@ public class CustomVerifyEmailRequiredAction implements RequiredActionProvider {
private static final Logger logger = Logger.getLogger(CustomVerifyEmailRequiredAction.class);
public static final String PROVIDER_ID = "CUSTOM_VERIFY_EMAIL";
-
+
@Override
public void evaluateTriggers(RequiredActionContext context) {
if (!context.getUser().isEmailVerified()) {
@@ -36,7 +36,7 @@ public void requiredActionChallenge(RequiredActionContext context) {
// First time - send code
sendVerificationCode(context);
}
-
+
Response challenge = context.form()
.setAttribute("user", context.getUser())
.createForm("verify-email.ftl");
@@ -47,13 +47,13 @@ public void requiredActionChallenge(RequiredActionContext context) {
public void processAction(RequiredActionContext context) {
String code = context.getHttpRequest().getDecodedFormParameters().getFirst("email_code");
String resend = context.getHttpRequest().getDecodedFormParameters().getFirst("resend");
-
+
if ("true".equals(resend)) {
sendVerificationCode(context);
requiredActionChallenge(context);
return;
}
-
+
if (code != null && isValidVerificationCode(context, code)) {
context.getUser().setEmailVerified(true);
context.getUser().removeAttribute("email_verification_code");
@@ -71,10 +71,10 @@ public void processAction(RequiredActionContext context) {
private void sendVerificationCode(RequiredActionContext context) {
String code = RandomString.randomCode(6);
long timestamp = System.currentTimeMillis();
-
+
context.getUser().setSingleAttribute("email_verification_code", code);
context.getUser().setSingleAttribute("email_code_timestamp", String.valueOf(timestamp));
-
+
try {
EmailTemplateProvider emailProvider = context.getSession().getProvider(EmailTemplateProvider.class);
emailProvider.setRealm(context.getRealm())
@@ -89,11 +89,11 @@ private void sendVerificationCode(RequiredActionContext context) {
private boolean isValidVerificationCode(RequiredActionContext context, String code) {
String storedCode = context.getUser().getFirstAttribute("email_verification_code");
String timestampStr = context.getUser().getFirstAttribute("email_code_timestamp");
-
+
if (storedCode == null || timestampStr == null) {
return false;
}
-
+
// Check if code is expired (15 minutes)
try {
long timestamp = Long.parseLong(timestampStr);
@@ -106,7 +106,7 @@ private boolean isValidVerificationCode(RequiredActionContext context, String co
} catch (NumberFormatException e) {
return false;
}
-
+
return Objects.equals(code, storedCode);
}
@@ -114,7 +114,7 @@ private boolean isValidVerificationCode(RequiredActionContext context, String co
public void close() {}
public static class Factory implements RequiredActionFactory {
-
+
@Override
public RequiredActionProvider create(KeycloakSession session) {
return new CustomVerifyEmailRequiredAction();
diff --git a/ol-keycloak/oltheme/src/main/resources/theme/ol/email/mjml/email-verification.mjml b/ol-keycloak/oltheme/src/main/resources/theme/ol/email/mjml/email-verification.mjml
index 12d3a29..6cde617 100644
--- a/ol-keycloak/oltheme/src/main/resources/theme/ol/email/mjml/email-verification.mjml
+++ b/ol-keycloak/oltheme/src/main/resources/theme/ol/email/mjml/email-verification.mjml
@@ -17,7 +17,7 @@
Your Verification Code
-
+
@@ -25,7 +25,7 @@
-
+
Enter this code on the verification page to complete your email verification.
@@ -36,7 +36,7 @@
-
+
Or click the button below to verify automatically:
@@ -56,4 +56,4 @@
-
\ No newline at end of file
+
diff --git a/ol-keycloak/oltheme/src/main/resources/theme/ol/login/login-verify-email.ftl b/ol-keycloak/oltheme/src/main/resources/theme/ol/login/login-verify-email.ftl
index 62ed93b..1cba92f 100755
--- a/ol-keycloak/oltheme/src/main/resources/theme/ol/login/login-verify-email.ftl
+++ b/ol-keycloak/oltheme/src/main/resources/theme/ol/login/login-verify-email.ftl
@@ -6,7 +6,7 @@
${msg("emailVerifyInstruction1", user.email)}
-
+
-
+
-
+
<#elseif section = "info">
#if>
-@layout.registrationLayout>
\ No newline at end of file
+@layout.registrationLayout>
From 59a305c19809a1f56d79df866657a942c84d0ad3 Mon Sep 17 00:00:00 2001
From: sar
Date: Tue, 15 Jul 2025 13:00:54 -0500
Subject: [PATCH 03/10] Add dependencies
---
ol-keycloak/oltheme/pom.xml | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/ol-keycloak/oltheme/pom.xml b/ol-keycloak/oltheme/pom.xml
index b0dfa32..dec1fc8 100644
--- a/ol-keycloak/oltheme/pom.xml
+++ b/ol-keycloak/oltheme/pom.xml
@@ -11,4 +11,25 @@
1.8
OL theme
+
+
+
+ org.keycloak
+ keycloak-server-spi
+ ${keycloak.version}
+ provided
+
+
+ org.keycloak
+ keycloak-server-spi-private
+ ${keycloak.version}
+ provided
+
+
+ org.keycloak
+ keycloak-services
+ ${keycloak.version}
+ provided
+
+
From e4ea854995a855ce1be93070ec877fd4e6549280 Mon Sep 17 00:00:00 2001
From: sar
Date: Tue, 15 Jul 2025 13:08:18 -0500
Subject: [PATCH 04/10] Resolve code review feedback
---
ol-keycloak/oltheme/pom.xml | 1 +
.../CustomVerifyEmailRequiredAction.java | 72 ++++++++++---------
2 files changed, 41 insertions(+), 32 deletions(-)
diff --git a/ol-keycloak/oltheme/pom.xml b/ol-keycloak/oltheme/pom.xml
index dec1fc8..6d0dca0 100644
--- a/ol-keycloak/oltheme/pom.xml
+++ b/ol-keycloak/oltheme/pom.xml
@@ -9,6 +9,7 @@
UTF-8
1.8
1.8
+ 26.3.0
OL theme
diff --git a/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java b/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
index 267b588..b98b872 100644
--- a/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
+++ b/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
@@ -28,12 +28,8 @@ public void evaluateTriggers(RequiredActionContext context) {
@Override
public void requiredActionChallenge(RequiredActionContext context) {
- // Check if we need to resend code
- String resend = context.getHttpRequest().getDecodedFormParameters().getFirst("resend");
- if ("true".equals(resend)) {
- sendVerificationCode(context);
- } else if (context.getUser().getFirstAttribute("email_verification_code") == null) {
- // First time - send code
+ // Only send code if one doesn't already exist
+ if (context.getUser().getFirstAttribute("email_verification_code") == null) {
sendVerificationCode(context);
}
@@ -43,6 +39,31 @@ public void requiredActionChallenge(RequiredActionContext context) {
context.challenge(challenge);
}
+ private enum VerificationCodeStatus {
+ VALID, INVALID, EXPIRED
+ }
+
+ private VerificationCodeStatus checkVerificationCode(RequiredActionContext context, String code) {
+ String storedCode = context.getUser().getFirstAttribute("email_verification_code");
+ String timestampStr = context.getUser().getFirstAttribute("email_code_timestamp");
+
+ if (storedCode == null || timestampStr == null) {
+ return VerificationCodeStatus.INVALID;
+ }
+
+ try {
+ long timestamp = Long.parseLong(timestampStr);
+ long now = System.currentTimeMillis();
+ if (now - timestamp > 15 * 60 * 1000) {
+ return VerificationCodeStatus.EXPIRED;
+ }
+ } catch (NumberFormatException e) {
+ return VerificationCodeStatus.INVALID;
+ }
+
+ return Objects.equals(code, storedCode) ? VerificationCodeStatus.VALID : VerificationCodeStatus.INVALID;
+ }
+
@Override
public void processAction(RequiredActionContext context) {
String code = context.getHttpRequest().getDecodedFormParameters().getFirst("email_code");
@@ -54,11 +75,22 @@ public void processAction(RequiredActionContext context) {
return;
}
- if (code != null && isValidVerificationCode(context, code)) {
+ VerificationCodeStatus status = checkVerificationCode(context, code);
+
+ if (status == VerificationCodeStatus.VALID) {
context.getUser().setEmailVerified(true);
context.getUser().removeAttribute("email_verification_code");
context.getUser().removeAttribute("email_code_timestamp");
context.success();
+ } else if (status == VerificationCodeStatus.EXPIRED) {
+ context.getUser().removeAttribute("email_verification_code");
+ context.getUser().removeAttribute("email_code_timestamp");
+ sendVerificationCode(context);
+ Response challenge = context.form()
+ .setError("Your verification code has expired. A new code has been sent to your email.")
+ .setAttribute("user", context.getUser())
+ .createForm("verify-email.ftl");
+ context.challenge(challenge);
} else {
Response challenge = context.form()
.setError("Invalid verification code. Please check your email and try again.")
@@ -69,7 +101,7 @@ public void processAction(RequiredActionContext context) {
}
private void sendVerificationCode(RequiredActionContext context) {
- String code = RandomString.randomCode(6);
+ String code = RandomString.randomString(6, RandomString.DIGITS); // 6-digit numeric code
long timestamp = System.currentTimeMillis();
context.getUser().setSingleAttribute("email_verification_code", code);
@@ -86,30 +118,6 @@ private void sendVerificationCode(RequiredActionContext context) {
}
}
- private boolean isValidVerificationCode(RequiredActionContext context, String code) {
- String storedCode = context.getUser().getFirstAttribute("email_verification_code");
- String timestampStr = context.getUser().getFirstAttribute("email_code_timestamp");
-
- if (storedCode == null || timestampStr == null) {
- return false;
- }
-
- // Check if code is expired (15 minutes)
- try {
- long timestamp = Long.parseLong(timestampStr);
- long now = System.currentTimeMillis();
- if (now - timestamp > 15 * 60 * 1000) {
- context.getUser().removeAttribute("email_verification_code");
- context.getUser().removeAttribute("email_code_timestamp");
- return false;
- }
- } catch (NumberFormatException e) {
- return false;
- }
-
- return Objects.equals(code, storedCode);
- }
-
@Override
public void close() {}
From 233b84c155144f95ecb0e42f0fc761631d1ff772 Mon Sep 17 00:00:00 2001
From: sar
Date: Tue, 15 Jul 2025 13:11:47 -0500
Subject: [PATCH 05/10] Resolve missing randomstring lib
---
.../providers/CustomVerifyEmailRequiredAction.java | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java b/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
index b98b872..a06c7e3 100644
--- a/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
+++ b/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
@@ -8,7 +8,6 @@
import org.keycloak.models.UserModel;
import org.keycloak.email.EmailException;
import org.keycloak.email.EmailTemplateProvider;
-import org.keycloak.common.util.RandomString;
import org.jboss.logging.Logger;
import jakarta.ws.rs.core.Response;
@@ -101,7 +100,7 @@ public void processAction(RequiredActionContext context) {
}
private void sendVerificationCode(RequiredActionContext context) {
- String code = RandomString.randomString(6, RandomString.DIGITS); // 6-digit numeric code
+ String code = generateNumericCode(6); // 6-digit numeric code
long timestamp = System.currentTimeMillis();
context.getUser().setSingleAttribute("email_verification_code", code);
@@ -118,6 +117,15 @@ private void sendVerificationCode(RequiredActionContext context) {
}
}
+ private String generateNumericCode(int length) {
+ StringBuilder sb = new StringBuilder(length);
+ java.util.Random random = new java.util.Random();
+ for (int i = 0; i < length; i++) {
+ sb.append(random.nextInt(10));
+ }
+ return sb.toString();
+ }
+
@Override
public void close() {}
From 45bfce2f7f6a74d7afa9cd414686cb3b5c450f1d Mon Sep 17 00:00:00 2001
From: sar
Date: Tue, 15 Jul 2025 13:15:26 -0500
Subject: [PATCH 06/10] Resolve signature mismatch
---
.../providers/CustomVerifyEmailRequiredAction.java | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java b/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
index a06c7e3..8c08beb 100644
--- a/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
+++ b/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
@@ -12,6 +12,8 @@
import jakarta.ws.rs.core.Response;
import java.util.Objects;
+import java.util.HashMap;
+import java.util.Map;
public class CustomVerifyEmailRequiredAction implements RequiredActionProvider {
@@ -108,10 +110,11 @@ private void sendVerificationCode(RequiredActionContext context) {
try {
EmailTemplateProvider emailProvider = context.getSession().getProvider(EmailTemplateProvider.class);
+ Map attributes = new HashMap<>();
+ attributes.put("code", code);
emailProvider.setRealm(context.getRealm())
.setUser(context.getUser())
- .setAttribute("code", code)
- .send("emailVerificationSubject", "email-verification.ftl");
+ .send("emailVerificationSubject", "email-verification.ftl", attributes);
} catch (EmailException e) {
logger.error("Failed to send verification email", e);
}
@@ -127,7 +130,8 @@ private String generateNumericCode(int length) {
}
@Override
- public void close() {}
+ public void close() {
+ }
public static class Factory implements RequiredActionFactory {
From b4591cede49a1597eb063d1f50ccf45be65a25c2 Mon Sep 17 00:00:00 2001
From: sar
Date: Tue, 15 Jul 2025 13:19:44 -0500
Subject: [PATCH 07/10] Add a close method
---
.../keycloak/providers/CustomVerifyEmailRequiredAction.java | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java b/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
index 8c08beb..6d0b55f 100644
--- a/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
+++ b/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
@@ -149,5 +149,10 @@ public String getDisplayText() {
public String getId() {
return PROVIDER_ID;
}
+
+ @Override
+ public void close() {
+ // No resources to clean up
+ }
}
}
From b59308f68d84bc56a240066ae5cbab03d57f9ba3 Mon Sep 17 00:00:00 2001
From: sar
Date: Tue, 15 Jul 2025 13:25:04 -0500
Subject: [PATCH 08/10] postInit method
---
.../keycloak/providers/CustomVerifyEmailRequiredAction.java | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java b/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
index 6d0b55f..aea5062 100644
--- a/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
+++ b/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
@@ -154,5 +154,10 @@ public String getId() {
public void close() {
// No resources to clean up
}
+
+ @Override
+ public void postInit(org.keycloak.models.KeycloakSessionFactory factory) {
+ // No post-initialization needed
+ }
}
}
From 0d2253332ebd0c3b2dfb5567d23951831bce3a02 Mon Sep 17 00:00:00 2001
From: sar
Date: Tue, 15 Jul 2025 13:27:43 -0500
Subject: [PATCH 09/10] Add init method to Factory class
---
.../providers/CustomVerifyEmailRequiredAction.java | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java b/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
index aea5062..b30b1c5 100644
--- a/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
+++ b/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
@@ -151,13 +151,18 @@ public String getId() {
}
@Override
- public void close() {
- // No resources to clean up
+ public void init(org.keycloak.Config.Scope config) {
+ // No initialization needed
}
@Override
public void postInit(org.keycloak.models.KeycloakSessionFactory factory) {
// No post-initialization needed
}
+
+ @Override
+ public void close() {
+ // No resources to clean up
+ }
}
}
From 6e0c198071e8b2ae7edcef351b4122d7da29a4bc Mon Sep 17 00:00:00 2001
From: sar
Date: Tue, 15 Jul 2025 13:44:44 -0500
Subject: [PATCH 10/10] Fixes based on feedback
---
.../CustomVerifyEmailRequiredAction.java | 3 +-
.../ol/email/mjml/email-verification.mjml | 32 -------------------
2 files changed, 2 insertions(+), 33 deletions(-)
diff --git a/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java b/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
index b30b1c5..07f10ae 100644
--- a/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
+++ b/ol-keycloak/oltheme/src/main/java/edu/mit/ol/keycloak/providers/CustomVerifyEmailRequiredAction.java
@@ -14,6 +14,7 @@
import java.util.Objects;
import java.util.HashMap;
import java.util.Map;
+import java.security.SecureRandom;
public class CustomVerifyEmailRequiredAction implements RequiredActionProvider {
@@ -122,7 +123,7 @@ private void sendVerificationCode(RequiredActionContext context) {
private String generateNumericCode(int length) {
StringBuilder sb = new StringBuilder(length);
- java.util.Random random = new java.util.Random();
+ SecureRandom random = new SecureRandom();
for (int i = 0; i < length; i++) {
sb.append(random.nextInt(10));
}
diff --git a/ol-keycloak/oltheme/src/main/resources/theme/ol/email/mjml/email-verification.mjml b/ol-keycloak/oltheme/src/main/resources/theme/ol/email/mjml/email-verification.mjml
index 6cde617..ff95ce7 100644
--- a/ol-keycloak/oltheme/src/main/resources/theme/ol/email/mjml/email-verification.mjml
+++ b/ol-keycloak/oltheme/src/main/resources/theme/ol/email/mjml/email-verification.mjml
@@ -12,38 +12,6 @@
the account verification process by clicking this link:
- <#if code??>
-
-
- Your Verification Code
-
-
-
-
-
- ${code}
-
-
-
-
-
-
- Enter this code on the verification page to complete your email verification.
-
-
- This code expires in 15 minutes.
-
-
-
-
-
-
-
- Or click the button below to verify automatically:
-
-
- #if>
-
Verify Your Email