0
# Validation Framework
1
2
The validation framework provides extensible field validation for user input, form data, and configuration parameters. It supports built-in validators and custom validation logic.
3
4
## Core Validation Interfaces
5
6
### Validator
7
8
Base interface for field validators.
9
10
```java { .api }
11
public interface Validator {
12
/**
13
* Gets the validator ID.
14
*
15
* @return validator ID
16
*/
17
String getId();
18
19
/**
20
* Validates input value.
21
*
22
* @param input the input value to validate
23
* @param inputHint hint about the input context
24
* @param context validation context
25
* @param config validator configuration
26
* @return validation result
27
* @throws ValidationException if validation fails unexpectedly
28
*/
29
ValidationResult validate(Object input, String inputHint, ValidationContext context, ValidatorConfig config)
30
throws ValidationException;
31
}
32
```
33
34
### SimpleValidator
35
36
Base interface for simple validators that validate individual values.
37
38
```java { .api }
39
public interface SimpleValidator extends Validator {
40
/**
41
* Validates a single input value.
42
*
43
* @param input the input value
44
* @param inputHint hint about the input
45
* @param context validation context
46
* @param config validator configuration
47
* @return validation result
48
*/
49
ValidationResult validateValue(Object input, String inputHint, ValidationContext context, ValidatorConfig config);
50
51
@Override
52
default ValidationResult validate(Object input, String inputHint, ValidationContext context, ValidatorConfig config)
53
throws ValidationException {
54
return validateValue(input, inputHint, context, config);
55
}
56
}
57
```
58
59
## Validation Context
60
61
### ValidationContext
62
63
Provides context for validation operations.
64
65
```java { .api }
66
public interface ValidationContext extends AttributeContext {
67
/**
68
* Gets the Keycloak session.
69
*
70
* @return Keycloak session
71
*/
72
KeycloakSession getSession();
73
74
/**
75
* Gets the attributes being validated.
76
*
77
* @return attributes
78
*/
79
Attributes getAttributes();
80
81
/**
82
* Gets the current realm.
83
*
84
* @return realm model
85
*/
86
RealmModel getRealm();
87
88
/**
89
* Gets the current user (if available).
90
*
91
* @return user model or null
92
*/
93
UserModel getUser();
94
}
95
```
96
97
### AttributeContext
98
99
Base context interface for attribute operations.
100
101
```java { .api }
102
public interface AttributeContext {
103
/**
104
* Gets the Keycloak session.
105
*
106
* @return Keycloak session
107
*/
108
KeycloakSession getSession();
109
110
/**
111
* Gets the current realm.
112
*
113
* @return realm model
114
*/
115
RealmModel getRealm();
116
}
117
```
118
119
## Validation Results
120
121
### ValidationResult
122
123
Represents the result of a validation operation.
124
125
```java { .api }
126
public class ValidationResult {
127
public static final ValidationResult VALID = new ValidationResult();
128
129
private final boolean valid;
130
private final Set<ValidationError> errors;
131
132
private ValidationResult() {
133
this.valid = true;
134
this.errors = Collections.emptySet();
135
}
136
137
private ValidationResult(Set<ValidationError> errors) {
138
this.valid = false;
139
this.errors = errors != null ? Collections.unmodifiableSet(errors) : Collections.emptySet();
140
}
141
142
/**
143
* Creates a valid result.
144
*
145
* @return valid validation result
146
*/
147
public static ValidationResult valid() {
148
return VALID;
149
}
150
151
/**
152
* Creates an invalid result with errors.
153
*
154
* @param errors validation errors
155
* @return invalid validation result
156
*/
157
public static ValidationResult invalid(ValidationError... errors) {
158
if (errors == null || errors.length == 0) {
159
return valid();
160
}
161
return new ValidationResult(Set.of(errors));
162
}
163
164
/**
165
* Creates an invalid result with error set.
166
*
167
* @param errors validation errors
168
* @return invalid validation result
169
*/
170
public static ValidationResult invalid(Set<ValidationError> errors) {
171
if (errors == null || errors.isEmpty()) {
172
return valid();
173
}
174
return new ValidationResult(errors);
175
}
176
177
/**
178
* Checks if validation was successful.
179
*
180
* @return true if valid
181
*/
182
public boolean isValid() {
183
return valid;
184
}
185
186
/**
187
* Gets validation errors.
188
*
189
* @return set of validation errors
190
*/
191
public Set<ValidationError> getErrors() {
192
return errors;
193
}
194
195
/**
196
* Combines this result with another result.
197
*
198
* @param other the other validation result
199
* @return combined result
200
*/
201
public ValidationResult combine(ValidationResult other) {
202
if (this.isValid() && other.isValid()) {
203
return valid();
204
}
205
206
Set<ValidationError> combinedErrors = new HashSet<>();
207
if (!this.isValid()) {
208
combinedErrors.addAll(this.errors);
209
}
210
if (!other.isValid()) {
211
combinedErrors.addAll(other.errors);
212
}
213
214
return invalid(combinedErrors);
215
}
216
217
@Override
218
public boolean equals(Object obj) {
219
if (this == obj) return true;
220
if (obj == null || getClass() != obj.getClass()) return false;
221
ValidationResult that = (ValidationResult) obj;
222
return valid == that.valid && Objects.equals(errors, that.errors);
223
}
224
225
@Override
226
public int hashCode() {
227
return Objects.hash(valid, errors);
228
}
229
230
@Override
231
public String toString() {
232
return valid ? "ValidationResult{valid}" : "ValidationResult{invalid, errors=" + errors + "}";
233
}
234
}
235
```
236
237
### ValidationError
238
239
Represents a validation error.
240
241
```java { .api }
242
public class ValidationError {
243
private final String message;
244
private final String messageKey;
245
private final Object[] messageParameters;
246
private final String inputHint;
247
248
public ValidationError(String message) {
249
this(message, null, null, null);
250
}
251
252
public ValidationError(String message, String inputHint) {
253
this(message, null, null, inputHint);
254
}
255
256
public ValidationError(String messageKey, Object[] messageParameters) {
257
this(null, messageKey, messageParameters, null);
258
}
259
260
public ValidationError(String messageKey, Object[] messageParameters, String inputHint) {
261
this(null, messageKey, messageParameters, inputHint);
262
}
263
264
private ValidationError(String message, String messageKey, Object[] messageParameters, String inputHint) {
265
this.message = message;
266
this.messageKey = messageKey;
267
this.messageParameters = messageParameters;
268
this.inputHint = inputHint;
269
}
270
271
public String getMessage() { return message; }
272
public String getMessageKey() { return messageKey; }
273
public Object[] getMessageParameters() { return messageParameters; }
274
public String getInputHint() { return inputHint; }
275
276
@Override
277
public boolean equals(Object obj) {
278
if (this == obj) return true;
279
if (obj == null || getClass() != obj.getClass()) return false;
280
ValidationError that = (ValidationError) obj;
281
return Objects.equals(message, that.message) &&
282
Objects.equals(messageKey, that.messageKey) &&
283
Arrays.equals(messageParameters, that.messageParameters) &&
284
Objects.equals(inputHint, that.inputHint);
285
}
286
287
@Override
288
public int hashCode() {
289
int result = Objects.hash(message, messageKey, inputHint);
290
result = 31 * result + Arrays.hashCode(messageParameters);
291
return result;
292
}
293
294
@Override
295
public String toString() {
296
return "ValidationError{" +
297
"message='" + message + '\'' +
298
", messageKey='" + messageKey + '\'' +
299
", messageParameters=" + Arrays.toString(messageParameters) +
300
", inputHint='" + inputHint + '\'' +
301
'}';
302
}
303
}
304
```
305
306
## Validator Configuration
307
308
### ValidatorConfig
309
310
Configuration for validators.
311
312
```java { .api }
313
public class ValidatorConfig {
314
private final Map<String, Object> config;
315
316
public ValidatorConfig() {
317
this.config = new HashMap<>();
318
}
319
320
public ValidatorConfig(Map<String, Object> config) {
321
this.config = config != null ? new HashMap<>(config) : new HashMap<>();
322
}
323
324
/**
325
* Gets a configuration value.
326
*
327
* @param key the configuration key
328
* @return configuration value or null
329
*/
330
public Object get(String key) {
331
return config.get(key);
332
}
333
334
/**
335
* Gets a configuration value with default.
336
*
337
* @param key the configuration key
338
* @param defaultValue default value if key not found
339
* @return configuration value or default
340
*/
341
@SuppressWarnings("unchecked")
342
public <T> T get(String key, T defaultValue) {
343
Object value = config.get(key);
344
return value != null ? (T) value : defaultValue;
345
}
346
347
/**
348
* Gets a string configuration value.
349
*
350
* @param key the configuration key
351
* @return string value or null
352
*/
353
public String getString(String key) {
354
Object value = config.get(key);
355
return value != null ? value.toString() : null;
356
}
357
358
/**
359
* Gets a string configuration value with default.
360
*
361
* @param key the configuration key
362
* @param defaultValue default value
363
* @return string value or default
364
*/
365
public String getString(String key, String defaultValue) {
366
String value = getString(key);
367
return value != null ? value : defaultValue;
368
}
369
370
/**
371
* Gets an integer configuration value.
372
*
373
* @param key the configuration key
374
* @param defaultValue default value
375
* @return integer value or default
376
*/
377
public int getInt(String key, int defaultValue) {
378
Object value = config.get(key);
379
if (value instanceof Number) {
380
return ((Number) value).intValue();
381
}
382
if (value instanceof String) {
383
try {
384
return Integer.parseInt((String) value);
385
} catch (NumberFormatException e) {
386
return defaultValue;
387
}
388
}
389
return defaultValue;
390
}
391
392
/**
393
* Gets a boolean configuration value.
394
*
395
* @param key the configuration key
396
* @param defaultValue default value
397
* @return boolean value or default
398
*/
399
public boolean getBoolean(String key, boolean defaultValue) {
400
Object value = config.get(key);
401
if (value instanceof Boolean) {
402
return (Boolean) value;
403
}
404
if (value instanceof String) {
405
return Boolean.parseBoolean((String) value);
406
}
407
return defaultValue;
408
}
409
410
/**
411
* Sets a configuration value.
412
*
413
* @param key the configuration key
414
* @param value the configuration value
415
*/
416
public void put(String key, Object value) {
417
if (value == null) {
418
config.remove(key);
419
} else {
420
config.put(key, value);
421
}
422
}
423
424
/**
425
* Gets all configuration as map.
426
*
427
* @return configuration map
428
*/
429
public Map<String, Object> asMap() {
430
return new HashMap<>(config);
431
}
432
}
433
```
434
435
## Validator Factory
436
437
### ValidatorFactory
438
439
Factory for creating validator instances.
440
441
```java { .api }
442
public interface ValidatorFactory extends ProviderFactory<Validator> {
443
/**
444
* Gets the validator ID.
445
*
446
* @return validator ID
447
*/
448
@Override
449
String getId();
450
451
/**
452
* Creates a validator instance.
453
*
454
* @param session Keycloak session
455
* @return validator instance
456
*/
457
@Override
458
Validator create(KeycloakSession session);
459
}
460
```
461
462
### ValidatorSPI
463
464
SPI for the validation framework.
465
466
```java { .api }
467
public class ValidatorSPI implements Spi {
468
@Override
469
public boolean isInternal() {
470
return true;
471
}
472
473
@Override
474
public String getName() {
475
return "validator";
476
}
477
478
@Override
479
public Class<? extends Provider> getProviderClass() {
480
return Validator.class;
481
}
482
483
@Override
484
public Class<? extends ProviderFactory> getProviderFactoryClass() {
485
return ValidatorFactory.class;
486
}
487
}
488
```
489
490
## Abstract Base Classes
491
492
### AbstractSimpleValidator
493
494
Abstract base for simple validators.
495
496
```java { .api }
497
public abstract class AbstractSimpleValidator implements SimpleValidator {
498
@Override
499
public ValidationResult validateValue(Object input, String inputHint, ValidationContext context, ValidatorConfig config) {
500
if (input == null) {
501
return ValidationResult.valid();
502
}
503
504
return doValidate(input, inputHint, context, config);
505
}
506
507
/**
508
* Performs the actual validation logic.
509
*
510
* @param input the non-null input value
511
* @param inputHint hint about the input
512
* @param context validation context
513
* @param config validator configuration
514
* @return validation result
515
*/
516
protected abstract ValidationResult doValidate(Object input, String inputHint, ValidationContext context, ValidatorConfig config);
517
}
518
```
519
520
### AbstractStringValidator
521
522
Abstract base for string validators.
523
524
```java { .api }
525
public abstract class AbstractStringValidator extends AbstractSimpleValidator {
526
@Override
527
protected ValidationResult doValidate(Object input, String inputHint, ValidationContext context, ValidatorConfig config) {
528
String stringValue = input.toString();
529
if (stringValue.isEmpty() && ignoreEmptyValues()) {
530
return ValidationResult.valid();
531
}
532
533
return validateString(stringValue, inputHint, context, config);
534
}
535
536
/**
537
* Validates a string value.
538
*
539
* @param value the string value
540
* @param inputHint hint about the input
541
* @param context validation context
542
* @param config validator configuration
543
* @return validation result
544
*/
545
protected abstract ValidationResult validateString(String value, String inputHint, ValidationContext context, ValidatorConfig config);
546
547
/**
548
* Whether to ignore empty string values.
549
*
550
* @return true to ignore empty values
551
*/
552
protected boolean ignoreEmptyValues() {
553
return true;
554
}
555
}
556
```
557
558
## Built-in Validators
559
560
### Validators Utility
561
562
Utility class providing access to built-in validators.
563
564
```java { .api }
565
public class Validators {
566
public static final String LENGTH = "length";
567
public static final String EMAIL = "email";
568
public static final String PATTERN = "pattern";
569
public static final String URI = "uri";
570
public static final String INTEGER = "integer";
571
public static final String DOUBLE = "double";
572
public static final String DATE = "date";
573
public static final String PHONE_NUMBER = "phone-number";
574
public static final String POSTAL_CODE = "postal-code";
575
576
/**
577
* Creates a length validator configuration.
578
*
579
* @param min minimum length
580
* @param max maximum length
581
* @return validator configuration
582
*/
583
public static ValidatorConfig length(int min, int max) {
584
ValidatorConfig config = new ValidatorConfig();
585
config.put("min", min);
586
config.put("max", max);
587
return config;
588
}
589
590
/**
591
* Creates a pattern validator configuration.
592
*
593
* @param pattern regular expression pattern
594
* @return validator configuration
595
*/
596
public static ValidatorConfig pattern(String pattern) {
597
ValidatorConfig config = new ValidatorConfig();
598
config.put("pattern", pattern);
599
return config;
600
}
601
602
/**
603
* Creates an email validator configuration.
604
*
605
* @return validator configuration
606
*/
607
public static ValidatorConfig email() {
608
return new ValidatorConfig();
609
}
610
611
/**
612
* Creates a URI validator configuration.
613
*
614
* @return validator configuration
615
*/
616
public static ValidatorConfig uri() {
617
return new ValidatorConfig();
618
}
619
620
/**
621
* Creates an integer validator configuration.
622
*
623
* @param min minimum value
624
* @param max maximum value
625
* @return validator configuration
626
*/
627
public static ValidatorConfig integer(int min, int max) {
628
ValidatorConfig config = new ValidatorConfig();
629
config.put("min", min);
630
config.put("max", max);
631
return config;
632
}
633
}
634
```
635
636
## Usage Examples
637
638
### Creating Custom Validators
639
640
```java
641
// Custom phone number validator
642
public class PhoneNumberValidator extends AbstractStringValidator {
643
public static final String ID = "phone-number";
644
645
private static final Pattern PHONE_PATTERN = Pattern.compile("^\\+?[1-9]\\d{1,14}$");
646
647
@Override
648
public String getId() {
649
return ID;
650
}
651
652
@Override
653
protected ValidationResult validateString(String value, String inputHint, ValidationContext context, ValidatorConfig config) {
654
if (!PHONE_PATTERN.matcher(value).matches()) {
655
return ValidationResult.invalid(
656
new ValidationError("invalid-phone-number", new Object[]{value}, inputHint)
657
);
658
}
659
660
// Additional validation based on country
661
String country = config.getString("country");
662
if (country != null) {
663
return validateForCountry(value, country, inputHint);
664
}
665
666
return ValidationResult.valid();
667
}
668
669
private ValidationResult validateForCountry(String phone, String country, String inputHint) {
670
// Country-specific validation logic
671
switch (country.toUpperCase()) {
672
case "US":
673
if (!phone.matches("^\\+?1[2-9]\\d{9}$")) {
674
return ValidationResult.invalid(
675
new ValidationError("invalid-us-phone-number", new Object[]{phone}, inputHint)
676
);
677
}
678
break;
679
case "UK":
680
if (!phone.matches("^\\+?44[1-9]\\d{8,9}$")) {
681
return ValidationResult.invalid(
682
new ValidationError("invalid-uk-phone-number", new Object[]{phone}, inputHint)
683
);
684
}
685
break;
686
}
687
return ValidationResult.valid();
688
}
689
}
690
691
// Custom validator factory
692
public class PhoneNumberValidatorFactory implements ValidatorFactory {
693
@Override
694
public Validator create(KeycloakSession session) {
695
return new PhoneNumberValidator();
696
}
697
698
@Override
699
public String getId() {
700
return PhoneNumberValidator.ID;
701
}
702
703
@Override
704
public List<ProviderConfigProperty> getConfigMetadata() {
705
return Arrays.asList(
706
new ProviderConfigProperty("country", "Country Code", "ISO country code for validation",
707
ProviderConfigProperty.STRING_TYPE, null)
708
);
709
}
710
}
711
```
712
713
### Using Validators in User Profile
714
715
```java
716
// Validate user profile attributes
717
try (KeycloakSession session = sessionFactory.create()) {
718
RealmModel realm = session.realms().getRealmByName("myrealm");
719
UserModel user = session.users().getUserByUsername(realm, "john");
720
721
// Create validation context
722
ValidationContext context = new ValidationContext() {
723
@Override
724
public KeycloakSession getSession() { return session; }
725
726
@Override
727
public RealmModel getRealm() { return realm; }
728
729
@Override
730
public UserModel getUser() { return user; }
731
732
@Override
733
public Attributes getAttributes() {
734
// Return user attributes
735
Map<String, List<String>> attrs = user.getAttributes();
736
return new AttributesImpl(attrs);
737
}
738
};
739
740
// Validate email
741
Validator emailValidator = session.getProvider(Validator.class, Validators.EMAIL);
742
ValidatorConfig emailConfig = Validators.email();
743
String email = user.getEmail();
744
745
ValidationResult emailResult = emailValidator.validate(email, "email", context, emailConfig);
746
if (!emailResult.isValid()) {
747
System.out.println("Email validation failed: " + emailResult.getErrors());
748
}
749
750
// Validate phone number with custom validator
751
Validator phoneValidator = session.getProvider(Validator.class, PhoneNumberValidator.ID);
752
ValidatorConfig phoneConfig = new ValidatorConfig();
753
phoneConfig.put("country", "US");
754
String phone = user.getFirstAttribute("phoneNumber");
755
756
ValidationResult phoneResult = phoneValidator.validate(phone, "phoneNumber", context, phoneConfig);
757
if (!phoneResult.isValid()) {
758
System.out.println("Phone validation failed: " + phoneResult.getErrors());
759
}
760
761
// Combine validation results
762
ValidationResult combinedResult = emailResult.combine(phoneResult);
763
if (!combinedResult.isValid()) {
764
System.out.println("Overall validation failed with " + combinedResult.getErrors().size() + " errors");
765
}
766
}
767
```
768
769
### Form Validation
770
771
```java
772
// Validate form input during user registration
773
public class RegistrationFormValidator {
774
private final KeycloakSession session;
775
private final RealmModel realm;
776
777
public RegistrationFormValidator(KeycloakSession session, RealmModel realm) {
778
this.session = session;
779
this.realm = realm;
780
}
781
782
public ValidationResult validateRegistrationForm(MultivaluedMap<String, String> formData) {
783
ValidationContext context = createValidationContext();
784
785
ValidationResult result = ValidationResult.valid();
786
787
// Validate username
788
String username = formData.getFirst("username");
789
result = result.combine(validateUsername(username, context));
790
791
// Validate email
792
String email = formData.getFirst("email");
793
result = result.combine(validateEmail(email, context));
794
795
// Validate password
796
String password = formData.getFirst("password");
797
result = result.combine(validatePassword(password, context));
798
799
// Validate confirm password
800
String confirmPassword = formData.getFirst("confirmPassword");
801
result = result.combine(validatePasswordConfirmation(password, confirmPassword, context));
802
803
// Validate first name
804
String firstName = formData.getFirst("firstName");
805
result = result.combine(validateFirstName(firstName, context));
806
807
// Validate last name
808
String lastName = formData.getFirst("lastName");
809
result = result.combine(validateLastName(lastName, context));
810
811
return result;
812
}
813
814
private ValidationResult validateUsername(String username, ValidationContext context) {
815
if (username == null || username.trim().isEmpty()) {
816
return ValidationResult.invalid(new ValidationError("username-required", null, "username"));
817
}
818
819
// Check length
820
Validator lengthValidator = session.getProvider(Validator.class, Validators.LENGTH);
821
ValidatorConfig lengthConfig = Validators.length(3, 50);
822
ValidationResult lengthResult = lengthValidator.validate(username, "username", context, lengthConfig);
823
824
if (!lengthResult.isValid()) {
825
return lengthResult;
826
}
827
828
// Check pattern (alphanumeric and underscore only)
829
Validator patternValidator = session.getProvider(Validator.class, Validators.PATTERN);
830
ValidatorConfig patternConfig = Validators.pattern("^[a-zA-Z0-9_]+$");
831
ValidationResult patternResult = patternValidator.validate(username, "username", context, patternConfig);
832
833
if (!patternResult.isValid()) {
834
return ValidationResult.invalid(new ValidationError("username-invalid-characters", null, "username"));
835
}
836
837
// Check uniqueness
838
UserModel existingUser = session.users().getUserByUsername(realm, username);
839
if (existingUser != null) {
840
return ValidationResult.invalid(new ValidationError("username-exists", null, "username"));
841
}
842
843
return ValidationResult.valid();
844
}
845
846
private ValidationResult validateEmail(String email, ValidationContext context) {
847
if (email == null || email.trim().isEmpty()) {
848
return ValidationResult.invalid(new ValidationError("email-required", null, "email"));
849
}
850
851
Validator emailValidator = session.getProvider(Validator.class, Validators.EMAIL);
852
ValidatorConfig emailConfig = Validators.email();
853
ValidationResult emailResult = emailValidator.validate(email, "email", context, emailConfig);
854
855
if (!emailResult.isValid()) {
856
return emailResult;
857
}
858
859
// Check uniqueness
860
UserModel existingUser = session.users().getUserByEmail(realm, email);
861
if (existingUser != null) {
862
return ValidationResult.invalid(new ValidationError("email-exists", null, "email"));
863
}
864
865
return ValidationResult.valid();
866
}
867
868
private ValidationResult validatePassword(String password, ValidationContext context) {
869
if (password == null || password.isEmpty()) {
870
return ValidationResult.invalid(new ValidationError("password-required", null, "password"));
871
}
872
873
// Use realm password policy
874
PasswordPolicy policy = realm.getPasswordPolicy();
875
if (policy != null) {
876
try {
877
policy.validate(realm.getName(), null, password);
878
} catch (PolicyError e) {
879
return ValidationResult.invalid(new ValidationError(e.getMessage(), null, "password"));
880
}
881
}
882
883
return ValidationResult.valid();
884
}
885
886
private ValidationResult validatePasswordConfirmation(String password, String confirmPassword, ValidationContext context) {
887
if (confirmPassword == null || confirmPassword.isEmpty()) {
888
return ValidationResult.invalid(new ValidationError("password-confirmation-required", null, "confirmPassword"));
889
}
890
891
if (!Objects.equals(password, confirmPassword)) {
892
return ValidationResult.invalid(new ValidationError("passwords-do-not-match", null, "confirmPassword"));
893
}
894
895
return ValidationResult.valid();
896
}
897
898
private ValidationResult validateFirstName(String firstName, ValidationContext context) {
899
if (firstName == null || firstName.trim().isEmpty()) {
900
return ValidationResult.invalid(new ValidationError("first-name-required", null, "firstName"));
901
}
902
903
Validator lengthValidator = session.getProvider(Validator.class, Validators.LENGTH);
904
ValidatorConfig lengthConfig = Validators.length(1, 100);
905
return lengthValidator.validate(firstName.trim(), "firstName", context, lengthConfig);
906
}
907
908
private ValidationResult validateLastName(String lastName, ValidationContext context) {
909
if (lastName == null || lastName.trim().isEmpty()) {
910
return ValidationResult.invalid(new ValidationError("last-name-required", null, "lastName"));
911
}
912
913
Validator lengthValidator = session.getProvider(Validator.class, Validators.LENGTH);
914
ValidatorConfig lengthConfig = Validators.length(1, 100);
915
return lengthValidator.validate(lastName.trim(), "lastName", context, lengthConfig);
916
}
917
918
private ValidationContext createValidationContext() {
919
return new ValidationContext() {
920
@Override
921
public KeycloakSession getSession() { return session; }
922
923
@Override
924
public RealmModel getRealm() { return realm; }
925
926
@Override
927
public UserModel getUser() { return null; }
928
929
@Override
930
public Attributes getAttributes() { return null; }
931
};
932
}
933
}
934
```