Fix for Keycloak 22.0.1 unable to create user with long email address (#23109)

Closes #22825
This commit is contained in:
kaustubh-rh 2023-09-11 12:26:13 +05:30 committed by GitHub
parent 2f207a78d7
commit 62927433dc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 21 additions and 3 deletions

View file

@ -10,4 +10,10 @@ The old LinkedIn way based on OAuth seems to be completely removed from the link
``` ```
kc.[sh|bat] start --features linkedin-oauth ... kc.[sh|bat] start --features linkedin-oauth ...
```
= A new parameter --spi-user-profile-declarative-user-profile-max-email-local-part-length is added to set max email local part length taking backwards compatibility into consideration. The default value is 64.
```
kc.[sh|bat] start --spi-user-profile-declarative-user-profile-max-email-local-part-length=100 ...
``` ```

View file

@ -3,12 +3,11 @@ package org.keycloak.utils;
import java.net.IDN; import java.net.IDN;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.keycloak.Config;
import static java.util.regex.Pattern.CASE_INSENSITIVE; import static java.util.regex.Pattern.CASE_INSENSITIVE;
public class EmailValidationUtil { public class EmailValidationUtil {
private static final int MAX_LOCAL_PART_LENGTH = 64;
private static final String LOCAL_PART_ATOM = "[a-z0-9!#$%&'*+/=?^_`{|}~\u0080-\uFFFF-]"; private static final String LOCAL_PART_ATOM = "[a-z0-9!#$%&'*+/=?^_`{|}~\u0080-\uFFFF-]";
private static final String LOCAL_PART_INSIDE_QUOTES_ATOM = "(?:[a-z0-9!#$%&'*.(),<>\\[\\]:; @+/=?^_`{|}~\u0080-\uFFFF-]|\\\\\\\\|\\\\\\\")"; private static final String LOCAL_PART_INSIDE_QUOTES_ATOM = "(?:[a-z0-9!#$%&'*.(),<>\\[\\]:; @+/=?^_`{|}~\u0080-\uFFFF-]|\\\\\\\\|\\\\\\\")";
/** /**
@ -29,6 +28,8 @@ public class EmailValidationUtil {
*/ */
private static final Pattern EMAIL_DOMAIN_PATTERN = Pattern.compile(DOMAIN + "|\\[" + IP_DOMAIN + "\\]|" + "\\[IPv6:" + IP_V6_DOMAIN + "\\]", CASE_INSENSITIVE); private static final Pattern EMAIL_DOMAIN_PATTERN = Pattern.compile(DOMAIN + "|\\[" + IP_DOMAIN + "\\]|" + "\\[IPv6:" + IP_V6_DOMAIN + "\\]", CASE_INSENSITIVE);
public static final String MAX_EMAIL_LOCAL_PART_LENGTH = "max-email-local-part-length";
public static boolean isValidEmail(String value) { public static boolean isValidEmail(String value) {
if ( value == null || value.length() == 0 ) { if ( value == null || value.length() == 0 ) {
@ -56,7 +57,8 @@ public class EmailValidationUtil {
} }
private static boolean isValidEmailLocalPart(String localPart) { private static boolean isValidEmailLocalPart(String localPart) {
if ( localPart.length() > MAX_LOCAL_PART_LENGTH ) {
if ( localPart.length() > Config.scope("user-profile-declarative-user-profile").getInt(MAX_EMAIL_LOCAL_PART_LENGTH,64) ) {
return false; return false;
} }
Matcher matcher = LOCAL_PART_PATTERN.matcher( localPart ); Matcher matcher = LOCAL_PART_PATTERN.matcher( localPart );

View file

@ -71,6 +71,7 @@ public abstract class AbstractUserProfileProvider<U extends UserProfileProvider>
public static final String CONFIG_ADMIN_READ_ONLY_ATTRIBUTES = "admin-read-only-attributes"; public static final String CONFIG_ADMIN_READ_ONLY_ATTRIBUTES = "admin-read-only-attributes";
public static final String CONFIG_READ_ONLY_ATTRIBUTES = "read-only-attributes"; public static final String CONFIG_READ_ONLY_ATTRIBUTES = "read-only-attributes";
public static final String MAX_EMAIL_LOCAL_PART_LENGTH = "max-email-local-part-length";
private static boolean editUsernameCondition(AttributeContext c) { private static boolean editUsernameCondition(AttributeContext c) {
KeycloakSession session = c.getSession(); KeycloakSession session = c.getSession();
@ -441,6 +442,12 @@ public abstract class AbstractUserProfileProvider<U extends UserProfileProvider>
.helpText("Array of regular expressions to identify fields that should be treated read-only so administrators can't change them.") .helpText("Array of regular expressions to identify fields that should be treated read-only so administrators can't change them.")
.add() .add()
.property()
.name(MAX_EMAIL_LOCAL_PART_LENGTH)
.type(ProviderConfigProperty.STRING_TYPE)
.helpText("To set user profile max email local part length")
.add()
.build(); .build();
} }

View file

@ -41,6 +41,8 @@ public class ValidationTest {
Assert.assertFalse(Validation.isEmailValid("abc@foo.")); Assert.assertFalse(Validation.isEmailValid("abc@foo."));
Assert.assertFalse(Validation.isEmailValid("abc@foo..bar")); Assert.assertFalse(Validation.isEmailValid("abc@foo..bar"));
Assert.assertTrue(Validation.isEmailValid("diegø@foo.com")); Assert.assertTrue(Validation.isEmailValid("diegø@foo.com"));
Assert.assertTrue(Validation.isEmailValid("qwertyuiopasdfghjklz@foo.com"));
Assert.assertFalse(Validation.isEmailValid("qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyqwertyu@foo.com"));
} }
@Test @Test

View file

@ -32,6 +32,7 @@ spi-truststore-file-password=secret
spi-user-profile-provider=declarative-user-profile spi-user-profile-provider=declarative-user-profile
spi-user-profile-declarative-user-profile-read-only-attributes=deniedFoo,deniedBar*,deniedSome/thing,deniedsome*thing spi-user-profile-declarative-user-profile-read-only-attributes=deniedFoo,deniedBar*,deniedSome/thing,deniedsome*thing
spi-user-profile-declarative-user-profile-admin-read-only-attributes=deniedSomeAdmin spi-user-profile-declarative-user-profile-admin-read-only-attributes=deniedSomeAdmin
spi-user-profile-declarative-user-profile-max-email-local-part-length=100
#password-blacklists path #password-blacklists path
spi-password-policy-password-blacklist-blacklists-path=${kc.home.dir:}/dependency/password-blacklists spi-password-policy-password-blacklist-blacklists-path=${kc.home.dir:}/dependency/password-blacklists