I think the validation part that's mentioned in milestone m2 of the User-Profile spec can be converted by this and much more. You could also use the validations SPI to validate other objects too, e.g. realm and client settings or even mappers and federation or identity broker settings.
Let's see what comes out of this.
Cheers,
Thomas
--
You received this message because you are subscribed to a topic in the Google Groups "Keycloak Dev" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/keycloak-dev/-XjQu7rn56s/unsubscribe.
To unsubscribe from this group and all its topics, send an email to keycloak-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/keycloak-dev/9207113a-74ac-424e-94b2-16b1922337fcn%40googlegroups.com.
Hello Thomas,
We would like to team up with you as we currently approaching the very same issues and details in the new user profile.
The good news for you is: You don’t have to look up all the places where validations happen we did already.
In the branch you can see all validators which existed in Keycloak https://github.com/keycloak/keycloak/blob/54aeab7c262c361ed1ad6794307f513b1ea0cc8f/services/src/main/java/org/keycloak/userprofile/LegacyUserProfileProvider.java#L70
And the Static validators (which are functions as in your proposal) https://github.com/keycloak/keycloak/blob/54aeab7c262c361ed1ad6794307f513b1ea0cc8f/services/src/main/java/org/keycloak/userprofile/validation/StaticValidators.java
According PR https://github.com/keycloak/keycloak/pull/7155/files#diff-8ae01ac5703b69f70d1046eb97178e1cR71
As you can see the code has overlaps with your proposal.
As of that I would like to get you in the boat of the new user profile and rebase your efforts against our branch. So we can merge our changes and then yours afterwards.
You will only have to care to embed the validator factories within the profile as there is no context specific code anymore.
We also would be open for a short call with you if there is interest on your side and if you feel that’s useful.
Mit freundlichen Grüßen / Best regards
Markus Till
Project Delivery Berlin 22 (IOC/PDL22)
Bosch.IO GmbH | Ziegelei 7 | 88090 Immenstaad |
GERMANY | www.bosch.io
Tel. +49 30 726112-354 | Mobil +49 172 57 82 078 | Telefax +49 30 726112-100 |
marku...@bosch-si.com
Sitz: Berlin, Registergericht: Amtsgericht Charlottenburg; HRB 148411 B
Aufsichtsratsvorsitzender: Dr.-Ing. Thorsten Lücke; Geschäftsführung: Dr. Stefan Ferber, Dr. Aleksandar Mitrovic, Yvonne Reckling
--
You received this message because you are subscribed to the Google Groups "Keycloak Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to
keycloak-dev...@googlegroups.com.
To view this discussion on the web visit
https://groups.google.com/d/msgid/keycloak-dev/CAF1uOF28qhffhjHC1254196JJ2jRAUywDMyUSGHeTLiZJF%3Ds0g%40mail.gmail.com.
Hello Keycloak Developers,
I made some progress with the Validation SPI and I just wanted to give you a quick update on the current state of the API.
If you have questions about the validation SPI or some additional ideas, I'm looking forward to hearing from you.
# Validation SPI
## Rationale
Currently, validation logic is scattered and duplicated all around the Keycloak codebase with partially significant differences concerning the implementation although the validation
logic is the same. Also reusing built-in validation logic for custom extensions usually means a lot of duplicated code, which needs to be maintained for Keycloak upgrades.
This proposal introduces a new extensible validation SPI with a uniform facility to register validation rules and to perform validations of arbitrary values while being able to
select which validations should be executed in which context. This eases to reuse of existing validation logic and allows the augmentation of the built-in validations with custom validation logic.
This is, of course, no replacement for small static utility functions, e.g. to check whether a value is not null or empty e.g. but rather to describe more complex validation rules that
need to be augmented for some use-cases.
## Why not just using bean-validation
Well I thought about this for some time but after a quick prototype, I concluded that it would make more sense to go with a custom implementation that leverages the existing Keycloak infrastructure for providing custom extensions and better integration with the existing Keycloak structures. Note that it is still possible to provide a validation/validator implementation that leverages bean validation. Also, bean-validation still works quite well for declarative validation rules in JAX-RS endpoints.
# Some features of the Validation SPI
- Support for Validation of arbitrary Keycloak components on object and property level / single value level
- Functional interface based Validation function definitions
- Built-in validations for common values like usernames, email addresses, etc.
- Support for user-defined custom validations via ValidationProvider SPI
- Validation Problems can be reported as Errors or Warnings
- Validations can be performed in bulk mode (all problems are collected for a value) or in short-circuit mode (validation exits on the first problem).
- Support for nested validations, custom Validations can use other Validations within a validation function
- Support for validation ordering: validations can be added before or after existing Validations to augment validations, e.g. validate an email for correct format and then check if the email domain is allowed.
- Support for replacing built-in validations to completely replace a validation if necessary.
## Core Abstractions (in server-spi Module)
- Validation (Functional Interface, describes a Validation)
- ValidatorProvider (Interface, SPI, denotes a Validator that can validate a given value according to some Validations governed by the given ValidationKey in a ValidationContext)
- ValidationKey (references a set of validations, like User.USERNAME, User.EMAIL, User.MOBILE_PHONE, etc.)
- ValidationProvider (Interface, SPI, provides built-in a custom Validations to the validation infrastructure)
- ValidationContext (A context a validation is performed in, provides access to the current realm, client, session and validation attributes, etc.)
- ValidationResult (Contains the validation state (valid or not) and access to problems found during the validation run)
- ValidationProblem (Denotes a concrete problem found during validation (Errors, Warnings) for a ValidationKey an i18n errorMessage reference)
- ValidationContextKey (Refers to a particular validation context like USER_PROFILE_UPDATE or USER_REGISTRATION, this allows different validations for a validation key in different contexts)
- ValidationRegistry (Allows to register new Validations for a ValidationKey which can be bound to one or more ValidationContextKeys)
## Default implementations (in keycloak-services Module)
- DefaultValidatorProvider (can discover provided Validations and use them to validate values in a validation context)
- DefaultValidationRegistry (Allows to register new Validations
- DefaultValidationProvider (Registers a set of default validation primitives, like validations for email, username, firstname, lastname etc.)
# API examples
## Registering a new Validation via SPI
public class DefaultValidationProvider implements ValidationProvider {
@Override
public void register(MutableValidationRegistry registry) {
...
registry.register(createEmailValidation(), ValidationKey.User.EMAIL,
ValidationContextKey.User.PROFILE_UPDATE, ValidationContextKey.User.REGISTRATION);
...
}
...
protected Validation createEmailValidation() {
return (key, value, context) -> {
String input = value instanceof String ? (String) value : null;
if (org.keycloak.services.validation.Validation.isBlank(input)) {
context.addError(key, Messages.MISSING_EMAIL);
return false;
}
if (!org.keycloak.services.validation.Validation.isEmailValid(input)) {
context.addError(key, Messages.INVALID_EMAIL);
return false;
}
return true;
};
}
}
## Using the Validator to Validate a value
ValidatorProvider validator = context.getSession().getProvider(ValidatorProvider.class);
ValidationContext context = new ValidationContext(realm, ValidationContextKey.User.PROFILE_UPDATE,
Collections.singletonMap("userNameRequired", userNameRequired));
List<FormMessage> errors = new ArrayList<>();
validator.validate(context, formData.getFirst(FIELD_EMAIL), ValidationKey.User.EMAIL)
// this can be stream-lined in line with the upcoming user-profile changes
.accept(res -> res.getErrors().forEach(p -> addError(errors, FIELD_EMAIL, p.getMessage())));
...
PR for current Validation SPI proposal: https://github.com/keycloak/keycloak/pull/7324
## Additional Validator examples
// validation with KeycloakSession access
protected Validation uniqueEmailValidation() {
return (key, value, context) -> {
if (context.getRealm().isDuplicateEmailsAllowed()) {
return true;
}
String input = value instanceof String ? (String) value : null;
if (input == null) {
context.addError(key, Messages.MISSING_EMAIL);
}
UserModel userByEmail = context.getSession().users().getUserByEmail(input, context.getRealm());
return userByEmail == null;
};
}
// validation with nested validation of a complex object (UserModel), e.g. using the built-in email validation
protected Validation createProfileValidation() {
return (key, value, context) -> {
UserModel input = value instanceof UserModel ? (UserModel) value : null;
if (input == null) {
context.addError(key, Messages.INVALID_USER);
return false;
}
if (!"content".equals(input.getFirstAttribute("FAKE_FIELD"))) {
context.addError(key, "FAKE_FIELD_ERRORKEY");
return false;
}
boolean emailValid = context.validateNested(ValidationKey.User.EMAIL, input.getEmail());
if (!emailValid) {
context.addError(key, Messages.INVALID_EMAIL);
}
return emailValid;
};
}
Some more API examples can be found in the DefaultValidatorProviderTest: https://github.com/keycloak/keycloak/blob/7c9ca79ef52072ea12602705d53b346addd3535d/services/src/test/java/org/keycloak/services/validation/DefaultValidatorProviderTest.java
Additionally, some integration examples can be seen here:
# User Profile Proposal integration
Markus Till, Martin Idel, and me had a zoom call this week where we discussed the proposed API and how it could serve as a foundation for the user-profile SPI proposal.
We concluded that a great portion of the current implementation of the user-profile proposal can be implemented on top of the generic validation spi.
We're currently working on putting the two worlds together.
User-Profile SPI PR: https://github.com/keycloak/keycloak/pull/7155
User-Profile SPI Proposal: https://github.com/keycloak/keycloak-community/blob/master/design/user-profile.md
Cheers,
Thomas
To unsubscribe from this group and all its topics, send an email to keycl...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/keycloak-dev/9207113a-74ac-424e-94b2-16b1922337fcn%40googlegroups.com.
--
You received this message because you are subscribed to the Google Groups "Keycloak Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to keyclo...@googlegroups.com.
To unsubscribe from this group and stop receiving emails from it, send an email to keycloak-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/keycloak-dev/b72870e4-591f-439a-8569-d59882433c21o%40googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/keycloak-dev/b72870e4-591f-439a-8569-d59882433c21o%40googlegroups.com.
To unsubscribe from this group and stop receiving emails from it, send an email to keycloak-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/keycloak-dev/8e60ccf0-87d0-4203-8063-6720059af8f3o%40googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/keycloak-dev/f670f0c3-a2ed-4461-a978-f9f59bb3ca20n%40googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/keycloak-dev/CA%2B3s2iS4j9kVSpdPe7aV77tEe0Mndi57t01TeT-Z2010PaAxHA%40mail.gmail.com.