diff --git a/pom.xml b/pom.xml
index a1960c6..dbe7a1b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -32,7 +32,7 @@
UTF-8
17
17
- 22.0.0
+ 23.0.0
diff --git a/src/main/java/com/github/thomasdarimont/keycloak/auth/RegistrationProfileDomainValidation.java b/src/main/java/com/github/thomasdarimont/keycloak/auth/RegistrationProfileDomainValidation.java
index 61eeb0b..75a4b75 100644
--- a/src/main/java/com/github/thomasdarimont/keycloak/auth/RegistrationProfileDomainValidation.java
+++ b/src/main/java/com/github/thomasdarimont/keycloak/auth/RegistrationProfileDomainValidation.java
@@ -1,20 +1,24 @@
package com.github.thomasdarimont.keycloak.auth;
//
import org.jboss.logging.Logger;
+import org.keycloak.authentication.AuthenticationFlowError;
+import org.keycloak.authentication.AuthenticationFlowException;
import org.keycloak.authentication.FormAction;
import org.keycloak.authentication.ValidationContext;
import org.keycloak.authentication.forms.RegistrationPage;
-import org.keycloak.authentication.forms.RegistrationProfile;
import org.keycloak.events.Details;
import org.keycloak.events.Errors;
+import org.keycloak.events.EventType;
import org.keycloak.models.AuthenticatorConfigModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.FormMessage;
import org.keycloak.provider.ProviderConfigProperty;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.services.messages.Messages;
import org.keycloak.services.validation.Validation;
+import org.keycloak.userprofile.UserProfile;
import jakarta.ws.rs.core.MultivaluedMap;
import java.util.Arrays;
@@ -32,143 +36,195 @@ import com.google.auto.service.AutoService;
@AutoService(FormActionFactory.class)
public class RegistrationProfileDomainValidation extends RegistrationUserCreation {
- protected static final Logger logger = Logger.getLogger(RegistrationProfileDomainValidation.class);
+ protected static final Logger logger = Logger.getLogger(RegistrationProfileDomainValidation.class);
- protected static final String DEFAULT_DOMAIN_LIST = "example.org";
- protected static final String DOMAIN_LIST_SEPARATOR = "##";
+ protected static final String DEFAULT_DOMAIN_LIST = "example.org";
+ protected static final String DOMAIN_LIST_SEPARATOR = "##";
- @Override
- public boolean isConfigurable() {
- return true;
- }
+ @Override
+ public boolean isConfigurable() {
+ return true;
+ }
- protected static final boolean globmatches(String text, String glob) {
- if (text.length() > 200) {
- return false;
- }
- String rest = null;
- int pos = glob.indexOf('*');
- if (pos != -1) {
- rest = glob.substring(pos + 1);
- glob = glob.substring(0, pos);
- }
+ protected static final boolean globmatches(String text, String glob) {
+ if (text.length() > 200) {
+ return false;
+ }
+ String rest = null;
+ int pos = glob.indexOf('*');
+ if (pos != -1) {
+ rest = glob.substring(pos + 1);
+ glob = glob.substring(0, pos);
+ }
+ if (glob.length() > text.length())
+ return false;
+ // handle the part up to the first *
+ for (int i = 0; i < glob.length(); i++)
+ if (glob.charAt(i) != '?'
+ && !glob.substring(i, i + 1).equalsIgnoreCase(text.substring(i, i + 1)))
+ return false;
- if (glob.length() > text.length())
- return false;
-
- // handle the part up to the first *
- for (int i = 0; i < glob.length(); i++)
- if (glob.charAt(i) != '?'
- && !glob.substring(i, i + 1).equalsIgnoreCase(text.substring(i, i + 1)))
- return false;
-
- // recurse for the part after the first *, if any
- if (rest == null) {
- return glob.length() == text.length();
- } else {
- for (int i = glob.length(); i <= text.length(); i++) {
- if (globmatches(text.substring(i), rest))
- return true;
- }
- return false;
- }
- }
-
- @Override
- public void validate(ValidationContext context) {
- MultivaluedMap formData = context.getHttpRequest().getDecodedFormParameters();
-
- List errors = new ArrayList<>();
- String email = formData.getFirst(Validation.FIELD_EMAIL);
-
- AuthenticatorConfigModel mailDomainConfig = context.getAuthenticatorConfig();
- String eventError = Errors.INVALID_REGISTRATION;
-
- if(email == null){
- context.getEvent().detail(Details.EMAIL, email);
- errors.add(new FormMessage(RegistrationPage.FIELD_EMAIL, Messages.INVALID_EMAIL));
- context.error(eventError);
- context.validationError(formData, errors);
- return;
- }
-
- String[] domainList = getDomainList(mailDomainConfig);
-
- boolean emailDomainValid = isEmailValid(email, domainList);
-
- if (!emailDomainValid) {
- super.success(context);
- KeycloakSession session = context.getSession();
- RealmModel realm = context.getRealm();
- UserModel user = context.getUser();
- user.addRequiredAction("USER_MUST_BE_APPROVED");
- setRequiredActions(session, realm, user);
-
- }
- if (errors.size() > 0) {
- context.error(eventError);
- context.validationError(formData, errors);
- } else {
- context.success();
- }
- }
-
- public String[] getDomainList(AuthenticatorConfigModel mailDomainConfig) {
- return mailDomainConfig.getConfig().getOrDefault(domainListConfigName, DEFAULT_DOMAIN_LIST).split(DOMAIN_LIST_SEPARATOR);
- }
-
- public boolean isEmailValid(String email, String[] domains) {
- for (String domain : domains) {
- if (email.endsWith("@" + domain) || email.equals(domain) || globmatches(email, "*@" + domain)) {
- return true;
- }
+ // recurse for the part after the first *, if any
+ if (rest == null) {
+ return glob.length() == text.length();
+ } else {
+ for (int i = glob.length(); i <= text.length(); i++) {
+ if (globmatches(text.substring(i), rest))
+ return true;
}
return false;
- }
+ }
+ }
+
+ @Override
+ public void success(FormContext context) {
+
+ if (context.getUser() != null) {
+ // the user probably did some back navigation in the browser, hitting this page in a strange state
+ context.getEvent().detail(Details.EXISTING_USER, context.getUser().getUsername());
+ throw new AuthenticationFlowException(AuthenticationFlowError.GENERIC_AUTHENTICATION_ERROR, Errors.DIFFERENT_USER_AUTHENTICATING, Messages.EXPIRED_ACTION);
+ }
+
+ MultivaluedMap formData = context.getHttpRequest().getDecodedFormParameters();
+
+ String email = formData.getFirst(UserModel.EMAIL);
+ String username = formData.getFirst(UserModel.USERNAME);
+
+ if (context.getRealm().isRegistrationEmailAsUsername()) {
+ username = email;
+ }
+ // get the allowlist of mail domains
+ AuthenticatorConfigModel mailDomainConfig = context.getAuthenticatorConfig();
+ String eventError = Errors.INVALID_REGISTRATION;
+
+ String[] domainList = getDomainList(mailDomainConfig);
+
+ boolean emailDomainValid = isEmailValid(email, domainList);
+
+ context.getEvent().detail(Details.USERNAME, username).detail(Details.REGISTER_METHOD, "form").detail(Details.EMAIL, email);
+
+ UserProfile profile = getOrCreateUserProfile(context, formData);
+ UserModel user = profile.create();
+ if (!emailDomainValid)
+ user.addRequiredAction("USER_MUST_BE_APPROVED");
+
+ user.setEnabled(true);
+
+ context.setUser(user);
+
+ if (!emailDomainValid) {
+ user.addRequiredAction("USER_MUST_BE_APPROVED");
+ }
+ context.getAuthenticationSession().setClientNote(OIDCLoginProtocol.LOGIN_HINT_PARAM, username);
+
+ context.getEvent().user(user);
+ context.getEvent().success();
+ context.newEvent().event(EventType.LOGIN);
+ context.getEvent().client(context.getAuthenticationSession().getClient().getClientId())
+ .detail(Details.REDIRECT_URI, context.getAuthenticationSession().getRedirectUri())
+ .detail(Details.AUTH_METHOD, context.getAuthenticationSession().getProtocol());
+ String authType = context.getAuthenticationSession().getAuthNote(Details.AUTH_TYPE);
+ if (authType != null) {
+ context.getEvent().detail(Details.AUTH_TYPE, authType);
+ }
+}
+
+/* @Override
+ public void validate(ValidationContext context) {
+ MultivaluedMap formData = context.getHttpRequest().getDecodedFormParameters();
+
+ List errors = new ArrayList<>();
+ String email = formData.getFirst(Validation.FIELD_EMAIL);
+
+ AuthenticatorConfigModel mailDomainConfig = context.getAuthenticatorConfig();
+ String eventError = Errors.INVALID_REGISTRATION;
+
+ if(email == null){
+ context.getEvent().detail(Details.EMAIL, email);
+ errors.add(new FormMessage(RegistrationPage.FIELD_EMAIL, Messages.INVALID_EMAIL));
+ context.error(eventError);
+ context.validationError(formData, errors);
+ return;
+ }
+
+ String[] domainList = getDomainList(mailDomainConfig);
+
+ boolean emailDomainValid = isEmailValid(email, domainList);
+
+ if (!emailDomainValid) {
+ super.success(context);
+ KeycloakSession session = context.getSession();
+ RealmModel realm = context.getRealm();
+ UserModel user = context.getUser();
+ user.addRequiredAction("USER_MUST_BE_APPROVED");
+ setRequiredActions(session, realm, user);
+
+ }
+ if (errors.size() > 0) {
+ context.error(eventError);
+ context.validationError(formData, errors);
+ } else {
+ context.success();
+ }
+ */
+
+
+ public String[] getDomainList(AuthenticatorConfigModel mailDomainConfig) {
+ return mailDomainConfig.getConfig().getOrDefault(domainListConfigName, DEFAULT_DOMAIN_LIST).split(DOMAIN_LIST_SEPARATOR);
+ }
+
+ public boolean isEmailValid(String email, String[] domains) {
+ for (String domain : domains) {
+ if (email.endsWith("@" + domain) || email.equals(domain) || globmatches(email, "*@" + domain)) {
+ return true;
+ }
+ }
+ return false;
+ }
- public static final String PROVIDER_ID = "registration-mail-check-action";
+ public static final String PROVIDER_ID = "registration-mail-check-action";
- private static final List CONFIG_PROPERTIES = new ArrayList<>();
+ private static final List CONFIG_PROPERTIES = new ArrayList<>();
- public static String domainListConfigName = "validDomains";
+ public static String domainListConfigName = "validDomains";
- static {
- ProviderConfigProperty property;
- property = new ProviderConfigProperty();
- property.setName(domainListConfigName);
- property.setLabel("Valid domains for emails");
- property.setType(ProviderConfigProperty.STRING_TYPE);
- property.setHelpText("List mail domains authorized to register, separated by '##'");
- CONFIG_PROPERTIES.add(property);
- }
+ static {
+ ProviderConfigProperty property;
+ property = new ProviderConfigProperty();
+ property.setName(domainListConfigName);
+ property.setLabel("Valid domains for emails");
+ property.setType(ProviderConfigProperty.STRING_TYPE);
+ property.setHelpText("List mail domains authorized to register, separated by '##'");
+ CONFIG_PROPERTIES.add(property);
+ }
- @Override
- public String getDisplayType() {
- return "Profile Validation with email domain check";
- }
+ @Override
+ public String getDisplayType() {
+ return "Profile Validation with email domain check";
+ }
- @Override
- public String getId() {
- return PROVIDER_ID;
- }
+ @Override
+ public String getId() {
+ return PROVIDER_ID;
+ }
- @Override
- public String getHelpText() {
- return "Adds validation of domain emails for registration";
- }
+ @Override
+ public String getHelpText() {
+ return "Adds validation of domain emails for registration";
+ }
- @Override
- public List getConfigProperties() {
- return CONFIG_PROPERTIES;
- }
+ @Override
+ public List getConfigProperties() {
+ return CONFIG_PROPERTIES;
+ }
- @Override
- public void buildPage(FormContext context, LoginFormsProvider form) {
- List authorizedMailDomains = Arrays.asList(
- context.getAuthenticatorConfig().getConfig().getOrDefault(domainListConfigName,DEFAULT_DOMAIN_LIST).split(DOMAIN_LIST_SEPARATOR));
+ @Override
+ public void buildPage(FormContext context, LoginFormsProvider form) {
+ List authorizedMailDomains = Arrays.asList(
+ context.getAuthenticatorConfig().getConfig().getOrDefault(domainListConfigName,DEFAULT_DOMAIN_LIST).split(DOMAIN_LIST_SEPARATOR));
form.setAttribute("authorizedMailDomains", authorizedMailDomains);
- }
+ }
}