From 9db284388b7d99dc7c25323a55f589df711a83de Mon Sep 17 00:00:00 2001 From: knoflook Date: Fri, 24 Nov 2023 16:53:02 +0100 Subject: [PATCH] WIP need to create a UserModel object but it's an abstract class (what does that even mean dog help me) --- .../spi/actions/UserMustBeApprovedAction.java | 34 ++++++++++++++++ .../UserMustBeApprovedActionFactory.java | 40 +++++++++++++++++++ .../RegistrationProfileDomainValidation.java | 14 ++++++- ...cloak.authentication.RequiredActionFactory | 1 + 4 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/gruchalski/idp/spi/actions/UserMustBeApprovedAction.java create mode 100644 src/main/java/com/gruchalski/idp/spi/actions/UserMustBeApprovedActionFactory.java create mode 100644 src/main/resources/META-INF/services/org.keycloak.authentication.RequiredActionFactory diff --git a/src/main/java/com/gruchalski/idp/spi/actions/UserMustBeApprovedAction.java b/src/main/java/com/gruchalski/idp/spi/actions/UserMustBeApprovedAction.java new file mode 100644 index 0000000..5311bae --- /dev/null +++ b/src/main/java/com/gruchalski/idp/spi/actions/UserMustBeApprovedAction.java @@ -0,0 +1,34 @@ +package com.gruchalski.idp.spi.actions; + +import org.keycloak.authentication.RequiredActionContext; +import org.keycloak.authentication.RequiredActionProvider; + +public class UserMustBeApprovedAction implements RequiredActionProvider { + + public static String PROVIDER_ID = "USER_MUST_BE_APPROVED"; + + @Override + public void evaluateTriggers(RequiredActionContext requiredActionContext) {} + + @Override + public void requiredActionChallenge(RequiredActionContext requiredActionContext) { + if (requiredActionContext + .getUser() + .getAttributes() + .containsKey("x-approved")) { + requiredActionContext.success(); + } else { + requiredActionContext + .getAuthenticationSession() + .setRedirectUri("/errors/approval-required/"); + requiredActionContext.failure(); + } + } + + @Override + public void processAction(RequiredActionContext requiredActionContext) {} + + @Override + public void close() {} +} + diff --git a/src/main/java/com/gruchalski/idp/spi/actions/UserMustBeApprovedActionFactory.java b/src/main/java/com/gruchalski/idp/spi/actions/UserMustBeApprovedActionFactory.java new file mode 100644 index 0000000..929583e --- /dev/null +++ b/src/main/java/com/gruchalski/idp/spi/actions/UserMustBeApprovedActionFactory.java @@ -0,0 +1,40 @@ +// original author: radek gruchalski +// https://gruchalski.com/posts/2021-06-06-extending-keycloak-required-action-providers/ + +package com.gruchalski.idp.spi.actions; + +import org.keycloak.Config; +import org.keycloak.authentication.RequiredActionFactory; +import org.keycloak.authentication.RequiredActionProvider; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakSessionFactory; + +public class UserMustBeApprovedActionFactory implements RequiredActionFactory { + + private static final UserMustBeApprovedAction SINGLETON = new UserMustBeApprovedAction(); + + @Override + public RequiredActionProvider create(KeycloakSession session) { + return SINGLETON; + } + + @Override + public void init(Config.Scope scope) {} + + @Override + public void postInit(KeycloakSessionFactory keycloakSessionFactory) {} + + @Override + public void close() {} + + @Override + public String getId() { + return UserMustBeApprovedAction.PROVIDER_ID; + } + + @Override + public String getDisplayText() { + return "User must be approved by an admin."; + } +} + diff --git a/src/main/java/net/micedre/keycloak/registration/RegistrationProfileDomainValidation.java b/src/main/java/net/micedre/keycloak/registration/RegistrationProfileDomainValidation.java index c3a1356..165133c 100644 --- a/src/main/java/net/micedre/keycloak/registration/RegistrationProfileDomainValidation.java +++ b/src/main/java/net/micedre/keycloak/registration/RegistrationProfileDomainValidation.java @@ -8,9 +8,12 @@ import org.keycloak.authentication.forms.RegistrationProfile; import org.keycloak.events.Details; import org.keycloak.events.Errors; import org.keycloak.models.AuthenticatorConfigModel; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.RealmModel; import org.keycloak.models.utils.FormMessage; import org.keycloak.services.messages.Messages; import org.keycloak.services.validation.Validation; +import org.keycloak.storage.adapter.AbstractUserAdapter; import jakarta.ws.rs.core.MultivaluedMap; import java.util.ArrayList; @@ -82,8 +85,15 @@ public abstract class RegistrationProfileDomainValidation extends RegistrationPr boolean emailDomainValid = isEmailValid(email, domainList); if (!emailDomainValid) { - context.getEvent().detail(Details.EMAIL, email); - errors.add(new FormMessage(RegistrationPage.FIELD_EMAIL, Messages.INVALID_EMAIL)); + // add user to a "waiting" group + // show a message saying you need to be approved by admin + KeycloakSession session = context.getSession(); + RealmModel realm = context.getRealm(); + AbstractUserAdapter user = new AbstractUserAdapter(); + user.addRequiredAction("USER_MUST_BE_APPROVED"); + setRequiredActions(context.getSession(), context.getRealm(), user); + + context.success(); } if (errors.size() > 0) { context.error(eventError); diff --git a/src/main/resources/META-INF/services/org.keycloak.authentication.RequiredActionFactory b/src/main/resources/META-INF/services/org.keycloak.authentication.RequiredActionFactory new file mode 100644 index 0000000..420a81e --- /dev/null +++ b/src/main/resources/META-INF/services/org.keycloak.authentication.RequiredActionFactory @@ -0,0 +1 @@ +com.gruchalski.idp.spi.actions.UserMustBeApprovedActionFactory