Commit 057b9775 authored by Markus Scheidgen's avatar Markus Scheidgen
Browse files

Custom username validation for keycloak.

parent 4bec888a
......@@ -25,6 +25,9 @@ ADD ./fairdi_nomad_prod.json /opt/jboss/keycloak/fairdi_nomad_prod.json
# Add a custom theme to mimic the rest of nomad's GUI
ADD ./material_theme /opt/jboss/keycloak/themes/material
# Add custom registration validation
ADD ./registration_form_action/target/form-extension-1.0-SNAPSHOT.jar /opt/jboss/keycloak/standalone/deployments/form-extension-1.0-SNAPSHOT.jar
# Additing a bcrypt password hashing algorithm to reuse old repo users
RUN curl http://central.maven.org/maven2/org/mindrot/jbcrypt/0.4/jbcrypt-0.4.jar > /tmp/jbcrypt-0.4.jar
RUN /opt/jboss/keycloak/bin/jboss-cli.sh --command="module add --name=org.mindrot.jbcrypt --resources=/tmp/jbcrypt-0.4.jar"
......
......@@ -3,4 +3,7 @@ errorTitle=We''re sorry...
errorTitleHtml=We''re <span style="font-weight: normal">sorry</span> ...
capsLockWarning=Caps Lock is On!
loginTitleHtml=NOMAD login
loginTitle=NOMAD login
\ No newline at end of file
loginTitle=NOMAD login
missingAffiliationMessage=Affiliation is required
missingAffiliationAddressMessage=Affiliation address is required
invalidUsernameMessage=The username is invalid. Only use letters, numbers, ''_'', ''-'', ''or'' ''.''.
\ No newline at end of file
.classpath
.project
target
.settings
\ No newline at end of file
<?xml version="1.0" encoding="UTF-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>eu.nomad.keycloak</groupId>
<artifactId>form-extension</artifactId>
<version>1.0-SNAPSHOT</version>
<name>form-extension</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<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>7.0.0</keycloak.version>
<jboss-transaction-api_1.2_spec>1.1.1.Final</jboss-transaction-api_1.2_spec>
<resteasy.version>3.6.1.Final</resteasy.version>
<bouncycastle.version>1.60</bouncycastle.version>
<jboss.logging.version>3.3.2.Final</jboss.logging.version>
<apache.httpcomponents.version>4.5.2</apache.httpcomponents.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<version>${keycloak.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi</artifactId>
<version>${keycloak.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-services</artifactId>
<version>${keycloak.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi-private</artifactId>
<version>${keycloak.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.transaction</groupId>
<artifactId>jboss-transaction-api_1.2_spec</artifactId>
<scope>provided</scope>
<version>${jboss-transaction-api_1.2_spec}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<scope>provided</scope>
<version>${resteasy.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<scope>provided</scope>
<version>${bouncycastle.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<scope>provided</scope>
<version>${bouncycastle.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<scope>provided</scope>
<version>${jboss.logging.version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<scope>provided</scope>
<version>${apache.httpcomponents.version}</version>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven
defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
package eu.nomad.keycloak;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.core.MultivaluedMap;
import org.keycloak.Config.Scope;
import org.keycloak.authentication.FormAction;
import org.keycloak.authentication.FormActionFactory;
import org.keycloak.authentication.FormContext;
import org.keycloak.authentication.ValidationContext;
import org.keycloak.authentication.forms.RegistrationPage;
import org.keycloak.events.Errors;
import org.keycloak.forms.login.LoginFormsProvider;
import org.keycloak.models.AuthenticationExecutionModel.Requirement;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.FormMessage;
import org.keycloak.provider.ProviderConfigProperty;
public class CustomRegistrationFromAction implements FormAction, FormActionFactory {
private static final String PROVIDER_ID = "organization-field-validation-action";
private static Requirement[] REQUIREMENT_CHOICES = { Requirement.REQUIRED, Requirement.DISABLED };
@Override
public void close() {
// TODO Auto-generated method stub
}
@Override
public void buildPage(FormContext arg0, LoginFormsProvider arg1) {
// TODO Auto-generated method stub
}
@Override
public boolean configuredFor(KeycloakSession arg0, RealmModel arg1, UserModel arg2) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean requiresUser() {
// TODO Auto-generated method stub
return false;
}
@Override
public void setRequiredActions(KeycloakSession arg0, RealmModel arg1, UserModel arg2) {
// TODO Auto-generated method stub
}
@Override
public void success(FormContext arg0) {
// TODO Auto-generated method stub
}
private boolean validateUsername(String username) {
return username.matches("^[a-zA-Z0-9_\\-\\.]+$");
}
@Override
public void validate(ValidationContext context) {
MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
List<FormMessage> errors = new ArrayList<>();
String eventError = Errors.INVALID_REGISTRATION;
if (!isBlank(formData.getFirst(RegistrationPage.FIELD_USERNAME))) {
if (!this.validateUsername(formData.getFirst(RegistrationPage.FIELD_USERNAME))) {
errors.add(new FormMessage(RegistrationPage.FIELD_USERNAME, "invalidUsernameMessage"));
}
}
if (isBlank(formData.getFirst("user.attributes.affiliation"))) {
errors.add(new FormMessage("user.attributes.affiliation", "missingAffiliationMessage"));
}
if (isBlank(formData.getFirst("user.attributes.affiliation_address"))) {
errors.add(new FormMessage("user.attributes.affiliation_address", "missingAffiliationAddressMessage"));
}
if (errors.size() > 0) {
context.error(eventError);
context.validationError(formData, errors);
return;
} else {
context.success();
}
}
@Override
public FormAction create(KeycloakSession arg0) {
return this;
}
@Override
public String getId() {
return PROVIDER_ID;
}
@Override
public void init(Scope arg0) {
}
@Override
public void postInit(KeycloakSessionFactory arg0) {
}
@Override
public String getDisplayType() {
return "Signup Form Validation";
}
@Override
public String getReferenceCategory() {
return null;
}
@Override
public Requirement[] getRequirementChoices() {
return REQUIREMENT_CHOICES;
}
@Override
public boolean isConfigurable() {
return false;
}
@Override
public boolean isUserSetupAllowed() {
return false;
}
@Override
public List<ProviderConfigProperty> getConfigProperties() {
return null;
}
@Override
public String getHelpText() {
return "Validates Signup form fields.";
}
/**
* Check if string is blank (null or lenght is 0 or contains only white
* characters)
*
* @param s
* to check
* @return true if string is blank
*/
public static boolean isBlank(String s) {
return s == null || s.trim().length() == 0;
}
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment