or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication-sessions.mdcomponent-framework.mdcore-models.mdcredential-management.mdindex.mdorganization-management.mdprovider-framework.mdsession-management.mduser-storage.mdvalidation-framework.mdvault-integration.md

validation-framework.mddocs/

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

```