Search code examples
jbosssingle-sign-onwildflykeycloakfreemarker

Add custom validation in Update User Profile in Keycloak


I have added a custom attribute in login-update-profile.ftl named organization, it is able to save the input from user into Keycloak.

<div class="${properties.kcFormGroupClass!}">
    <div class="${properties.kcLabelWrapperClass!}">
        <label for="user.attributes.organization" class="${properties.kcLabelClass!}">${msg("organization")}</label>
    </div>
    <div class="${properties.kcInputWrapperClass!}">
        <div class="${properties.kcInputWrapperClass!}">
            <input type="text" id="user.attributes.organization" name="user.attributes.organization" value="${(user.attributes.organization!'')}" class="${properties.kcInputClass!}" aria-invalid="<#if messagesPerField.existsError('organization')>true</#if>"
            />
        </div>

        <#if messagesPerField.existsError('organization')>
            <span id="input-error-organization" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
                ${kcSanitize(messagesPerField.get('organization'))?no_esc}
            </span>
        </#if>
    </div>
</div>

How to add validation for this field? I need to make it an obligatory field and meet certain condition (for example the length of the string). If the input is invalid, the error message is expected to be shown (like what we see in email or username field)


Solution

  • I found out the solution by creating a custom implementation of service provider Review Profile in First Broker Login flow. Here is the steps:

        public List<FormMessage> getCustomAttributeError(String organization) {
            List<FormMessage> errors = new ArrayList<>();
    
            // You can add more conditions & parameters to be validated
            if(Validation.isBlank(organization)){
                errors.add(new FormMessage("organization", "missingOrganizationMessage"));
            }
    
            return errors;
        }
    
    • Go to actionImpl function and add this lines between profile.update((attributeName, userModel) and catch (ValidationException pve):
        if(getCustomAttributeError(profile.getAttributes().getFirstValue("organization")).size() > 0){
            throw new ValidationException();                
        }
    
    • Add this lines in catch (ValidationException pve) after List<FormMessage> errors:
        List<FormMessage> extraErrors = getCustomAttributeErrors(profile.getAttributes().getFirstValue("organization"));
        for(FormMessage error : extraErrors) {
            errors.add(error);
        }
    
    • Open IdpReviewProfileAuthenticatorFactory.java go to getDisplayType() function and change the return value into "Custom Review Profile"
    • Build the .jar, deploy it into keycloak, create a copy of First Broker Login flow we name Custom First Broker Login, and in Custom First Broker Login we replace Review Profile with Custom Review Profile
    • Configure Custom Review Profile by clicking its action button, give it an alias, and turn Update Profile on First Login into on
    • Bind the desired Identity Providers with the new Custom First Broker Login