Compare commits

...

15 Commits

Author SHA1 Message Date
288029fe31 wip: move logic from validate to success 2023-12-11 15:17:55 +01:00
cd738a4a6f wip: compiles and doesn't break startup 2023-12-08 16:07:46 +01:00
86cfd9cf57 wip: it builds????? 2023-12-08 15:37:09 +01:00
cc4c0867f1 wip???? 2023-12-08 15:23:25 +01:00
9db284388b WIP need to create a UserModel object but it's an abstract class (what does that even mean dog help me) 2023-11-24 16:53:02 +01:00
119b7b4edd Prepare new version 2023-09-18 20:07:01 +00:00
f93e7c7496 Bump maven-gpg-plugin from 3.0.1 to 3.1.0
Bumps [maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.0.1 to 3.1.0.
- [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.0.1...maven-gpg-plugin-3.1.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-gpg-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-18 21:49:29 +02:00
4642aa476b Update gh actions to use java 17 2023-09-18 21:46:57 +02:00
df60257603 feat: adding support for Keycloak 22 2023-09-18 21:46:57 +02:00
81514b06a3 feat: add RegistrationProfileWithDomainBlock 2023-08-08 18:06:32 +02:00
a0efd5999e feat: create form action to block list of domains 2023-08-08 18:06:32 +02:00
afa1ec202c Prepare new version 2022-08-05 16:14:54 +00:00
e118cf5d7b Bump maven-javadoc-plugin from 3.3.0 to 3.4.0
Bumps [maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.3.0 to 3.4.0.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.3.0...maven-javadoc-plugin-3.4.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-05 18:13:18 +02:00
5dee8d05cf Bump wildfly-maven-plugin from 2.0.2.Final to 3.0.2.Final
Bumps [wildfly-maven-plugin](https://github.com/wildfly/wildfly-maven-plugin) from 2.0.2.Final to 3.0.2.Final.
- [Release notes](https://github.com/wildfly/wildfly-maven-plugin/releases)
- [Commits](https://github.com/wildfly/wildfly-maven-plugin/compare/2.0.2.Final...3.0.2.Final)

---
updated-dependencies:
- dependency-name: org.wildfly.plugins:wildfly-maven-plugin
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-05 18:13:09 +02:00
cb0296aa56 Fix for compatibility with KC 19¨+
The ui for configuring valid domains changed. It is now just a simple textfield expecting a list of valid domains separated by '##'
2022-08-05 18:12:02 +02:00
13 changed files with 483 additions and 176 deletions

View File

@ -8,9 +8,10 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Set up Maven Central Repository
uses: actions/setup-java@v1
uses: actions/setup-java@v3
with:
java-version: 11
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
server-id: ossrh
server-username: MAVEN_USERNAME
server-password: MAVEN_PASSWORD

View File

@ -15,10 +15,10 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
- uses: actions/setup-java@v3
with:
java-version: 1.8
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Cache Maven packages
uses: actions/cache@v2
with:

View File

@ -11,10 +11,10 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- uses: actions/setup-java@v3
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Cache Maven packages
uses: actions/cache@v2
with:

View File

@ -1,6 +1,6 @@
# Keycloak - Whitelist email domain for registration
# Keycloak - Email domain validation for registration
This extension allows you to validate email domain used for registration in keycloak to accept only a finite list of domain.
This extension allows you to validate email domain used for registration in keycloak to accept or deny a finite list of domain.
You can use basic [glob syntax](https://en.wikipedia.org/wiki/Glob_(programming))
(only `*` and `?` are supported)
@ -23,15 +23,15 @@ The plugin directory is `$KEYCLOAK_HOME\providers`.
- Go to the admin console, in authentication menu.
- Copy the registration flow
- add a new execution below "Profile Validation" and choose "Profile Validation With Email Domain Check"
- add a new execution below "Profile Validation" and choose "Profile Validation With Email Domain Check" or "Profile Validation with domain block"
- Set the execution "Required"
- Configure this new execution (otherwise, keycloak will only accept "exemple.org" domains)
- Configure this new execution with the allowed or blocked domains, otherwise, keycloak will only accept or block "exemple.org" domains
- Change the registration binding to this new flow
- Configure the realm to accept registration and verify email (this is important!)
## Display authorized mail domains in register forms
## Display mail domains in register forms
This extension provides the list of authorized patterns in the `authorizedMailDomains` attribute of the registration page.
This extension provides the list of authorized patterns in the `authorizedMailDomains` and `unauthorizedMailDomains` attribute of the registration page.
This can be used like this :

24
pom.xml
View File

@ -1,8 +1,8 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.micedre.keycloak</groupId>
<groupId>com.github.thomasdarimont.keycloak</groupId>
<artifactId>keycloak-mail-whitelisting</artifactId>
<version>1.6-SNAPSHOT</version>
<version>1.9-SNAPSHOT</version>
<name>Keycloak mail whitelisting extension</name>
<description>A keycloak extension to block non authorized domain to register</description>
@ -30,9 +30,9 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<keycloak.version>9.0.3</keycloak.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<keycloak.version>23.0.0</keycloak.version>
</properties>
<dependencies>
@ -60,13 +60,19 @@
<scope>provided</scope>
<version>${keycloak.version}</version>
</dependency>
<dependency>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service</artifactId>
<version>1.0</version>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.wildfly.plugins</groupId>
<artifactId>wildfly-maven-plugin</artifactId>
<version>2.0.2.Final</version>
<version>3.0.2.Final</version>
<configuration>
<skip>false</skip>
</configuration>
@ -87,7 +93,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.3.0</version>
<version>3.4.0</version>
<executions>
<execution>
<id>attach-javadocs</id>
@ -128,7 +134,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.0.1</version>
<version>3.1.0</version>
<executions>
<execution>
<id>sign-artifacts</id>
@ -149,4 +155,4 @@
</build>
</profile>
</profiles>
</project>
</project>

View File

@ -0,0 +1,230 @@
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.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;
import java.util.ArrayList;
import java.util.List;
//
import org.keycloak.authentication.FormActionFactory;
import org.keycloak.authentication.FormContext;
import org.keycloak.authentication.forms.RegistrationUserCreation;
import org.keycloak.events.Errors;
import org.keycloak.forms.login.LoginFormsProvider;
import org.keycloak.models.utils.FormMessage;
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 String DEFAULT_DOMAIN_LIST = "example.org";
protected static final String DOMAIN_LIST_SEPARATOR = "##";
@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);
}
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 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<String, String> 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<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
List<FormMessage> 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";
private static final List<ProviderConfigProperty> CONFIG_PROPERTIES = new ArrayList<>();
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);
}
@Override
public String getDisplayType() {
return "Profile Validation with email domain check";
}
@Override
public String getId() {
return PROVIDER_ID;
}
@Override
public String getHelpText() {
return "Adds validation of domain emails for registration";
}
@Override
public List<ProviderConfigProperty> getConfigProperties() {
return CONFIG_PROPERTIES;
}
@Override
public void buildPage(FormContext context, LoginFormsProvider form) {
List<String> authorizedMailDomains = Arrays.asList(
context.getAuthenticatorConfig().getConfig().getOrDefault(domainListConfigName,DEFAULT_DOMAIN_LIST).split(DOMAIN_LIST_SEPARATOR));
form.setAttribute("authorizedMailDomains", authorizedMailDomains);
}
}

View File

@ -0,0 +1,72 @@
package com.github.thomasdarimont.keycloak.auth;
import org.keycloak.authentication.FormContext;
import org.keycloak.forms.login.LoginFormsProvider;
import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.models.AuthenticatorConfigModel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class RegistrationProfileWithDomainBlock extends RegistrationProfileDomainValidation {
public static final String PROVIDER_ID = "registration-domain-block-action";
private static final List<ProviderConfigProperty> CONFIG_PROPERTIES = new ArrayList<>();
public static String domainListConfigName = "invalidDomains";
static {
ProviderConfigProperty property;
property = new ProviderConfigProperty();
property.setName(domainListConfigName);
property.setLabel("Invalid domain for emails");
property.setType(ProviderConfigProperty.STRING_TYPE);
property.setHelpText("List mail domains not authorized to register, separated by '##'");
CONFIG_PROPERTIES.add(property);
}
@Override
public String getDisplayType() {
return "Profile Validation with domain block";
}
@Override
public String getId() {
return PROVIDER_ID;
}
@Override
public String getHelpText() {
return "Adds validation of not accepted domain emails for registration";
}
@Override
public List<ProviderConfigProperty> getConfigProperties() {
return CONFIG_PROPERTIES;
}
@Override
public void buildPage(FormContext context, LoginFormsProvider form) {
List<String> unauthorizedMailDomains = Arrays.asList(
context.getAuthenticatorConfig().getConfig().getOrDefault(domainListConfigName, DEFAULT_DOMAIN_LIST).split(DOMAIN_LIST_SEPARATOR));
form.setAttribute("unauthorizedMailDomains", unauthorizedMailDomains);
}
@Override
public String[] getDomainList(AuthenticatorConfigModel mailDomainConfig) {
return mailDomainConfig.getConfig().getOrDefault(domainListConfigName, DEFAULT_DOMAIN_LIST).split(DOMAIN_LIST_SEPARATOR);
}
@Override
public boolean isEmailValid(String email, String[] domains) {
for (String domain : domains) {
if (email.endsWith("@" + domain) || email.equals(domain) || globmatches(email, "*@" + domain)) {
return false;
}
}
return true;
}
}

View File

@ -0,0 +1,72 @@
package com.github.thomasdarimont.keycloak.auth;
import org.keycloak.authentication.FormContext;
import org.keycloak.forms.login.LoginFormsProvider;
import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.models.AuthenticatorConfigModel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class RegistrationProfileWithMailDomainCheck extends RegistrationProfileDomainValidation {
public static final String PROVIDER_ID = "registration-mail-check-action";
private static final List<ProviderConfigProperty> CONFIG_PROPERTIES = new ArrayList<>();
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);
}
@Override
public String getDisplayType() {
return "Profile Validation with email domain check";
}
@Override
public String getId() {
return PROVIDER_ID;
}
@Override
public String getHelpText() {
return "Adds validation of domain emails for registration";
}
@Override
public List<ProviderConfigProperty> getConfigProperties() {
return CONFIG_PROPERTIES;
}
@Override
public void buildPage(FormContext context, LoginFormsProvider form) {
List<String> authorizedMailDomains = Arrays.asList(
context.getAuthenticatorConfig().getConfig().getOrDefault(domainListConfigName,DEFAULT_DOMAIN_LIST).split(DOMAIN_LIST_SEPARATOR));
form.setAttribute("authorizedMailDomains", authorizedMailDomains);
}
@Override
public String[] getDomainList(AuthenticatorConfigModel mailDomainConfig) {
return mailDomainConfig.getConfig().getOrDefault(domainListConfigName, DEFAULT_DOMAIN_LIST).split(DOMAIN_LIST_SEPARATOR);
}
@Override
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;
}
}

View File

@ -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() {}
}

View File

@ -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.";
}
}

View File

@ -1,151 +0,0 @@
package net.micedre.keycloak.registration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.ws.rs.core.MultivaluedMap;
import org.keycloak.authentication.FormAction;
import org.keycloak.authentication.FormContext;
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.forms.login.LoginFormsProvider;
import org.keycloak.models.AuthenticatorConfigModel;
import org.keycloak.models.utils.FormMessage;
import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.services.messages.Messages;
import org.keycloak.services.validation.Validation;
public class RegistrationProfileWithMailDomainCheck extends RegistrationProfile implements FormAction {
public static final String PROVIDER_ID = "registration-mail-check-action";
@Override
public String getDisplayType() {
return "Profile Validation with email domain check";
}
@Override
public String getId() {
return PROVIDER_ID;
}
@Override
public boolean isConfigurable() {
return true;
}
@Override
public String getHelpText() {
return "Adds validation of domain emails for registration";
}
private static final List<ProviderConfigProperty> CONFIG_PROPERTIES = new ArrayList<ProviderConfigProperty>();
static {
ProviderConfigProperty property;
property = new ProviderConfigProperty();
property.setName("validDomains");
property.setLabel("Valid domain for emails");
property.setType(ProviderConfigProperty.MULTIVALUED_STRING_TYPE);
property.setHelpText("List mail domains authorized to register");
CONFIG_PROPERTIES.add(property);
}
private 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;
// 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 List<ProviderConfigProperty> getConfigProperties() {
return CONFIG_PROPERTIES;
}
@Override
public void validate(ValidationContext context) {
MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
List<FormMessage> errors = new ArrayList<>();
String email = formData.getFirst(Validation.FIELD_EMAIL);
boolean emailDomainValid = false;
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[] domains = mailDomainConfig.getConfig().getOrDefault("validDomains","exemple.org").split("##");
for (String domain : domains) {
if (email.endsWith("@" + domain) || email.equals(domain)) {
emailDomainValid = true;
break;
} else if (globmatches(email, "*@" + domain)) {
emailDomainValid = true;
break;
}
}
if (!emailDomainValid) {
context.getEvent().detail(Details.EMAIL, email);
errors.add(new FormMessage(RegistrationPage.FIELD_EMAIL, Messages.INVALID_EMAIL));
}
if (errors.size() > 0) {
context.error(eventError);
context.validationError(formData, errors);
return;
} else {
context.success();
}
}
@Override
public void buildPage(FormContext context, LoginFormsProvider form) {
List<String> authorizedMailDomains = Arrays.asList(
context.getAuthenticatorConfig().getConfig().getOrDefault("validDomains","exemple.org").split("##"));
form.setAttribute("authorizedMailDomains", authorizedMailDomains);
}
}

View File

@ -1 +1,3 @@
net.micedre.keycloak.registration.RegistrationProfileWithMailDomainCheck
com.github.thomasdarimont.keycloak.auth.RegistrationProfileDomainValidation
com.github.thomasdarimont.keycloak.auth.RegistrationProfileWithDomainBlock
com.github.thomasdarimont.keycloak.auth.RegistrationProfileWithMailDomainCheck

View File

@ -0,0 +1 @@
com.gruchalski.idp.spi.actions.UserMustBeApprovedActionFactory