KEYCLOAK-14231 - validate supported locales
This commit is contained in:
parent
edef93cd49
commit
7f916ad20c
4 changed files with 93 additions and 13 deletions
|
@ -409,6 +409,7 @@ public class RealmAdminResource {
|
|||
}
|
||||
|
||||
ReservedCharValidator.validate(rep.getRealm());
|
||||
ReservedCharValidator.validateLocales(rep.getSupportedLocales());
|
||||
|
||||
try {
|
||||
if (!Constants.GENERATE.equals(rep.getPublicKey()) && (rep.getPrivateKey() != null && rep.getPublicKey() != null)) {
|
||||
|
|
|
@ -19,29 +19,45 @@ package org.keycloak.utils;
|
|||
import javax.ws.rs.BadRequestException;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Stan Silvert
|
||||
* @author Lukas Hanusovsky lhanusov@redhat.com
|
||||
*/
|
||||
public class ReservedCharValidator {
|
||||
protected static final Logger logger = Logger.getLogger(ReservedCharValidator.class);
|
||||
|
||||
// https://tools.ietf.org/html/rfc3986#section-2.2
|
||||
private static final String[] RESERVED_CHARS = { ":", "/", "?", "#", "[", "@", "!", "$",
|
||||
"&", "(", ")", "*", "+", ",", ";", "=",
|
||||
"]", "[", "\\" };
|
||||
private static final Pattern RESERVED_CHARS_PATTERN = Pattern.compile("[:/?#@!$&()*+,;=\\[\\]\\\\]");
|
||||
|
||||
// KEYCLOAK-14231 - Supported Locales: Three new characters were added on top of this RFC: "{", "}", "%"
|
||||
private static final Pattern RESERVED_CHARS_LOCALES_PATTERN = Pattern.compile("[:/?#@!$&()*+,;=\\[\\]\\\\{}%]");
|
||||
|
||||
private ReservedCharValidator() {}
|
||||
|
||||
public static void validate(String str) throws ReservedCharException {
|
||||
|
||||
public static void validate(String str, Pattern pattern) throws ReservedCharException {
|
||||
if (str == null) return;
|
||||
|
||||
for (String c : RESERVED_CHARS) {
|
||||
if (str.contains(c)) {
|
||||
String message = "Character '" + c + "' not allowed.";
|
||||
ReservedCharException e = new ReservedCharException(message);
|
||||
logger.warn(message, e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
Matcher matcher = pattern.matcher(str);
|
||||
if (matcher.find()) {
|
||||
String message = "Character '" + matcher.group() + "' not allowed.";
|
||||
logger.warn(message);
|
||||
throw new ReservedCharException(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void validate(String str) {
|
||||
validate(str, RESERVED_CHARS_PATTERN);
|
||||
}
|
||||
|
||||
public static void validateLocales(Iterable<String> strIterable) {
|
||||
if (strIterable == null) return;
|
||||
|
||||
for (String str: strIterable) {
|
||||
validate(str, RESERVED_CHARS_LOCALES_PATTERN);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
package org.keycloak.testsuite.console.page.realm;
|
||||
|
||||
import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
|
||||
import org.openqa.selenium.Keys;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
import org.openqa.selenium.support.ui.Select;
|
||||
|
||||
|
@ -26,6 +28,7 @@ import static org.keycloak.testsuite.util.UIUtils.clickLink;
|
|||
/**
|
||||
*
|
||||
* @author Filip Kiss
|
||||
* @author Lukas Hanusovsky lhanusov@redhat.com
|
||||
*/
|
||||
public class ThemeSettings extends RealmSettings {
|
||||
|
||||
|
@ -49,6 +52,12 @@ public class ThemeSettings extends RealmSettings {
|
|||
@FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='internationalizationEnabled']]")
|
||||
private OnOffSwitch internatEnabledSwitch;
|
||||
|
||||
@FindBy(className = "select2-input")
|
||||
private WebElement supportedLocalesInput;
|
||||
|
||||
@FindBy(id = "defaultLocale")
|
||||
private Select defaultLocaleSelect;
|
||||
|
||||
public void changeLoginTheme(String themeName) {
|
||||
loginThemeSelect.selectByVisibleText(themeName);
|
||||
}
|
||||
|
@ -73,6 +82,17 @@ public class ThemeSettings extends RealmSettings {
|
|||
return internatEnabledSwitch.isOn();
|
||||
}
|
||||
|
||||
public void addSupportedLocale(String supportedLocale) {
|
||||
supportedLocalesInput.sendKeys(supportedLocale);
|
||||
supportedLocalesInput.sendKeys(Keys.RETURN);
|
||||
}
|
||||
|
||||
public void deleteSupportedLocale(String supportedLocale) {
|
||||
supportedLocalesInput.sendKeys(Keys.chord(Keys.CONTROL, supportedLocale, Keys.BACK_SPACE, Keys.BACK_SPACE));
|
||||
}
|
||||
|
||||
public void setDefaultLocale () { defaultLocaleSelect.selectByVisibleText("en"); }
|
||||
|
||||
public void saveTheme() {
|
||||
clickLink(primaryButton);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import static org.keycloak.testsuite.util.URLAssert.*;
|
|||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
* @author Lukas Hanusovsky lhanusov@redhat.com
|
||||
*/
|
||||
@DisableFeature(value = Profile.Feature.ACCOUNT2, skipRestart = true) // TODO remove this (KEYCLOAK-16228)
|
||||
public class InternationalizationTest extends AbstractRealmTest {
|
||||
|
@ -95,6 +96,34 @@ public class InternationalizationTest extends AbstractRealmTest {
|
|||
assertConsoleLocale(LABEL_CS_REALM_SETTINGS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSupportedLocalesOnReservedChars() {
|
||||
realmSettingsPage.setAdminRealm(AuthRealm.MASTER);
|
||||
realmSettingsPage.navigateTo();
|
||||
loginPage.form().login(adminUser);
|
||||
tabs().themes();
|
||||
|
||||
if (!themeSettingsPage.isInternatEnabled()) {
|
||||
themeSettingsPage.setInternatEnabled(true);
|
||||
themeSettingsPage.saveTheme();
|
||||
}
|
||||
|
||||
// This Locales should pass, because they do not contain special chars.
|
||||
assertSupportedLocale("test", "succeed");
|
||||
assertSupportedLocale("sausage", "succeed");
|
||||
|
||||
// This Locales should raise exception, because the reserved chars are validated.
|
||||
assertSupportedLocale("%00f%00", "fail");
|
||||
assertSupportedLocale("test; Path=/", "fail");
|
||||
assertSupportedLocale("{test}", "fail");
|
||||
assertSupportedLocale("\\xc0", "fail");
|
||||
assertSupportedLocale("\\xbc", "fail");
|
||||
|
||||
// Clean up session: back to realm Test
|
||||
realmSettingsPage.setAdminRealm(AuthRealm.TEST);
|
||||
deleteAllCookiesForMasterRealm();
|
||||
}
|
||||
|
||||
private void assertConsoleLocale(String expected) {
|
||||
assertCurrentUrlEquals(realmSettingsPage);
|
||||
assertLocale(".//div[@class='nav-category'][1]/ul/li[1]//a", expected); // Realm Settings
|
||||
|
@ -113,4 +142,18 @@ public class InternationalizationTest extends AbstractRealmTest {
|
|||
private void assertLocale(WebElement element, String expected) {
|
||||
assertEquals(expected, getTextFromElement(element));
|
||||
}
|
||||
|
||||
private void assertSupportedLocale(String supportedLocale, String updateStatus) {
|
||||
themeSettingsPage.addSupportedLocale(supportedLocale);
|
||||
themeSettingsPage.setDefaultLocale();
|
||||
themeSettingsPage.saveTheme();
|
||||
if (updateStatus.equals("succeed")) {
|
||||
assertAlertSuccess();
|
||||
} else if (updateStatus.equals("fail")) {
|
||||
assertAlertDanger();
|
||||
themeSettingsPage.deleteSupportedLocale(supportedLocale);
|
||||
} else {
|
||||
assertTrue(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue