Disallow special characters in usernames to prevent confusion with similarly looking usernames (#11531)
Closes #11532 Co-authored-by: Douglas Palmer <dpalmer@redhat.com>
This commit is contained in:
parent
b29b27d731
commit
ac79fd0c23
6 changed files with 89 additions and 0 deletions
|
@ -35,6 +35,7 @@ public class Validation {
|
|||
|
||||
// Actually allow same emails like angular. See ValidationTest.testEmailValidation()
|
||||
private static final Pattern EMAIL_PATTERN = Pattern.compile("[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*");
|
||||
private static final Pattern USERNAME_PATTERN = Pattern.compile("^[\\p{IsLatin}|\\p{IsCommon}]+$");
|
||||
|
||||
private static void addError(List<FormMessage> errors, String field, String message, Object... parameters){
|
||||
errors.add(new FormMessage(field, message, parameters));
|
||||
|
@ -64,6 +65,10 @@ public class Validation {
|
|||
return EMAIL_PATTERN.matcher(email).matches();
|
||||
}
|
||||
|
||||
public static boolean isUsernameValid(String username) {
|
||||
|
||||
return USERNAME_PATTERN.matcher(username).matches();
|
||||
}
|
||||
|
||||
public static List<FormMessage> getFormErrorsFromValidation(List<ValidationException.Error> errors) {
|
||||
List<FormMessage> messages = new ArrayList<>();
|
||||
|
|
|
@ -54,6 +54,7 @@ import org.keycloak.userprofile.validator.RegistrationEmailAsUsernameEmailValueV
|
|||
import org.keycloak.userprofile.validator.RegistrationEmailAsUsernameUsernameValueValidator;
|
||||
import org.keycloak.userprofile.validator.RegistrationUsernameExistsValidator;
|
||||
import org.keycloak.userprofile.validator.UsernameHasValueValidator;
|
||||
import org.keycloak.userprofile.validator.UsernameIDNHomographValidator;
|
||||
import org.keycloak.userprofile.validator.UsernameMutationValidator;
|
||||
import org.keycloak.validate.ValidatorConfig;
|
||||
import org.keycloak.validate.validators.EmailValidator;
|
||||
|
@ -299,6 +300,7 @@ public abstract class AbstractUserProfileProvider<U extends UserProfileProvider>
|
|||
AbstractUserProfileProvider::editUsernameCondition,
|
||||
AbstractUserProfileProvider::readUsernameCondition,
|
||||
new AttributeValidatorMetadata(UsernameHasValueValidator.ID),
|
||||
new AttributeValidatorMetadata(UsernameIDNHomographValidator.ID),
|
||||
new AttributeValidatorMetadata(DuplicateUsernameValidator.ID),
|
||||
new AttributeValidatorMetadata(UsernameMutationValidator.ID)).setAttributeDisplayName("${username}");
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.userprofile.validator;
|
||||
|
||||
import org.keycloak.services.messages.Messages;
|
||||
import org.keycloak.services.validation.Validation;
|
||||
import org.keycloak.validate.SimpleValidator;
|
||||
import org.keycloak.validate.ValidationContext;
|
||||
import org.keycloak.validate.ValidationError;
|
||||
import org.keycloak.validate.ValidatorConfig;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Validator to check that User Profile username is provided. Expects List of Strings as input.
|
||||
*
|
||||
* @author Vlastimil Elias <velias@redhat.com>
|
||||
*
|
||||
*/
|
||||
public class UsernameIDNHomographValidator implements SimpleValidator {
|
||||
|
||||
public static final String ID = "up-username-not-idn-homograph";
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationContext validate(Object input, String inputHint, ValidationContext context, ValidatorConfig config) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> values = (List<String>) input;
|
||||
|
||||
String value = null;
|
||||
|
||||
if (values != null && !values.isEmpty()) {
|
||||
value = values.get(0);
|
||||
}
|
||||
|
||||
if (!Validation.isBlank(value) && !Validation.isUsernameValid(value)) {
|
||||
context.addError(new ValidationError(ID, value, Messages.INVALID_USERNAME));
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
}
|
|
@ -3,6 +3,7 @@ org.keycloak.userprofile.validator.AttributeRequiredByMetadataValidator
|
|||
org.keycloak.userprofile.validator.ReadOnlyAttributeUnchangedValidator
|
||||
org.keycloak.userprofile.validator.DuplicateUsernameValidator
|
||||
org.keycloak.userprofile.validator.UsernameHasValueValidator
|
||||
org.keycloak.userprofile.validator.UsernameIDNHomographValidator
|
||||
org.keycloak.userprofile.validator.UsernameMutationValidator
|
||||
org.keycloak.userprofile.validator.DuplicateEmailValidator
|
||||
org.keycloak.userprofile.validator.EmailExistsAsUsernameValidator
|
||||
|
|
|
@ -200,6 +200,16 @@ public class AssertEvents implements TestRule {
|
|||
.detail(Details.REDIRECT_URI, Matchers.equalTo(DEFAULT_REDIRECT_URI));
|
||||
}
|
||||
|
||||
public ExpectedEvent expectRegisterError(String username, String email) {
|
||||
UserRepresentation user = username != null ? getUser(username) : null;
|
||||
return expect(EventType.REGISTER_ERROR)
|
||||
.user(user != null ? user.getId() : null)
|
||||
.detail(Details.USERNAME, username)
|
||||
.detail(Details.EMAIL, email)
|
||||
.detail(Details.REGISTER_METHOD, "form")
|
||||
.detail(Details.REDIRECT_URI, Matchers.equalTo(DEFAULT_REDIRECT_URI));
|
||||
}
|
||||
|
||||
public ExpectedEvent expectAccount(EventType event) {
|
||||
return expect(event).client("account");
|
||||
}
|
||||
|
|
|
@ -1350,6 +1350,16 @@ public class AccountFormServiceTest extends AbstractTestRealmKeycloakTest {
|
|||
}
|
||||
}
|
||||
|
||||
//KEYCLOAK-17256
|
||||
@Test
|
||||
public void testHomographicUsername() {
|
||||
loginPage.open();
|
||||
loginPage.clickRegister();
|
||||
String username = "b"+"\u043E"+"b";
|
||||
registerPage.register("bob", "spoof", "bob@spoof.com", username, "password", "password");
|
||||
events.expectRegisterError(username, "bob@spoof.com").error("invalid_registration").assertEvent();
|
||||
}
|
||||
|
||||
// KEYCLOAK-5155
|
||||
@Test
|
||||
public void testConsoleListedInApplications() {
|
||||
|
|
Loading…
Reference in a new issue