KEYCLOAK-18590 Realm localizations of one realm must not affect themes displayed in context of other realms.

This commit is contained in:
bal1imb 2021-06-29 06:07:01 -07:00 committed by Hynek Mlnařík
parent fbaeb18a5f
commit 2c8d4ad9b4
5 changed files with 70 additions and 26 deletions

View file

@ -207,9 +207,9 @@ public class FreeMarkerEmailTemplateProvider implements EmailTemplateProvider {
Theme theme = getTheme();
Locale locale = session.getContext().resolveLocale(user);
attributes.put("locale", locale);
Properties rb = theme.getMessages(locale);
Map<String, String> localizationTexts = realm.getRealmLocalizationTextsByLocale(locale.toLanguageTag());
rb.putAll(localizationTexts);
Properties rb = new Properties();
rb.putAll(theme.getMessages(locale));
rb.putAll(realm.getRealmLocalizationTextsByLocale(locale.toLanguageTag()));
attributes.put("msg", new MessageFormatterMethod(locale, rb));
attributes.put("properties", theme.getProperties());
String subject = new MessageFormat(rb.getProperty(subjectKey, subjectKey), locale).format(subjectAttributes.toArray());

View file

@ -129,8 +129,6 @@ public class FreeMarkerAccountProvider implements AccountProvider {
Locale locale = session.getContext().resolveLocale(user);
Properties messagesBundle = handleThemeResources(theme, locale, attributes);
Map<String, String> localizationTexts = realm.getRealmLocalizationTextsByLocale(locale.toLanguageTag());
messagesBundle.putAll(localizationTexts);
URI baseUri = uriInfo.getBaseUri();
UriBuilder baseUriBuilder = uriInfo.getBaseUriBuilder();
@ -217,9 +215,10 @@ public class FreeMarkerAccountProvider implements AccountProvider {
* @return message bundle for other use
*/
protected Properties handleThemeResources(Theme theme, Locale locale, Map<String, Object> attributes) {
Properties messagesBundle;
Properties messagesBundle = new Properties();
try {
messagesBundle = theme.getMessages(locale);
messagesBundle.putAll(theme.getMessages(locale));
messagesBundle.putAll(realm.getRealmLocalizationTextsByLocale(locale.toLanguageTag()));
attributes.put("msg", new MessageFormatterMethod(locale, messagesBundle));
} catch (IOException e) {
logger.warn("Failed to load messages", e);

View file

@ -198,8 +198,6 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
Locale locale = session.getContext().resolveLocale(user);
Properties messagesBundle = handleThemeResources(theme, locale);
Map<String, String> localizationTexts = realm.getRealmLocalizationTextsByLocale(locale.toLanguageTag());
messagesBundle.putAll(localizationTexts);
handleMessages(locale, messagesBundle);
@ -288,8 +286,6 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
Locale locale = session.getContext().resolveLocale(user);
Properties messagesBundle = handleThemeResources(theme, locale);
Map<String, String> localizationTexts = realm.getRealmLocalizationTextsByLocale(locale.getCountry());
messagesBundle.putAll(localizationTexts);
handleMessages(locale, messagesBundle);
@ -339,9 +335,10 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
* @return message bundle for other use
*/
protected Properties handleThemeResources(Theme theme, Locale locale) {
Properties messagesBundle;
Properties messagesBundle = new Properties();
try {
messagesBundle = theme.getMessages(locale);
messagesBundle.putAll(theme.getMessages(locale));
messagesBundle.putAll(realm.getRealmLocalizationTextsByLocale(locale.toLanguageTag()));
attributes.put("msg", new MessageFormatterMethod(locale, messagesBundle));
attributes.put("advancedMsg", new AdvancedMessageFormatterMethod(locale, messagesBundle));
} catch (IOException e) {

View file

@ -48,10 +48,10 @@ public class AdminMessageFormatter implements BiFunction<String, Object[], Strin
try {
KeycloakContext context = session.getContext();
locale = context.resolveLocale(user);
messages = getTheme(session).getMessages(locale);
messages = new Properties();
messages.putAll(getTheme(session).getMessages(locale));
RealmModel realm = context.getRealm();
Map<String, String> localizationTexts = realm.getRealmLocalizationTextsByLocale(locale.toLanguageTag());
messages.putAll(localizationTexts);
messages.putAll(realm.getRealmLocalizationTextsByLocale(locale.toLanguageTag()));
} catch (IOException cause) {
throw new RuntimeException("Failed to configure error messages", cause);
}

View file

@ -16,9 +16,12 @@
*/
package org.keycloak.testsuite.i18n;
import java.io.IOException;
import java.util.Arrays;
import java.util.Locale;
import org.apache.http.impl.client.CloseableHttpClient;
import org.hamcrest.Matchers;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine;
@ -44,6 +47,8 @@ import org.keycloak.testsuite.pages.OAuthGrantPage;
import org.keycloak.testsuite.util.IdentityProviderBuilder;
import org.openqa.selenium.Cookie;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* @author <a href="mailto:gerbermichi@me.com">Michael Gerber</a>
* @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
@ -117,21 +122,25 @@ public class LoginPageTest extends AbstractI18NTest {
}
@Test
public void acceptLanguageHeader() {
public void acceptLanguageHeader() throws IOException {
ProfileAssume.assumeCommunity();
CloseableHttpClient httpClient = (CloseableHttpClient) new HttpClientBuilder().build();
ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient);
ResteasyClient client = new ResteasyClientBuilder().httpEngine(engine).build();
try(CloseableHttpClient httpClient = (CloseableHttpClient) new HttpClientBuilder().build()) {
ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient);
ResteasyClient client = new ResteasyClientBuilder().httpEngine(engine).build();
loginPage.open();
Response response = client.target(driver.getCurrentUrl()).request().acceptLanguage("de").get();
Assert.assertTrue(response.readEntity(String.class).contains("Anmeldung bei test"));
loginPage.open();
response = client.target(driver.getCurrentUrl()).request().acceptLanguage("en").get();
Assert.assertTrue(response.readEntity(String.class).contains("Sign in to test"));
try(Response responseDe = client.target(driver.getCurrentUrl()).request().acceptLanguage("de").get()) {
Assert.assertTrue(responseDe.readEntity(String.class).contains("Anmeldung bei test"));
client.close();
try(Response responseEn = client.target(driver.getCurrentUrl()).request().acceptLanguage("en").get()) {
Assert.assertTrue(responseEn.readEntity(String.class).contains("Sign in to test"));
}
}
client.close();
}
}
@Test
@ -242,6 +251,45 @@ public class LoginPageTest extends AbstractI18NTest {
Assert.assertNull(localeCookie);
}
// KEYCLOAK-18590
@Test
public void realmLocalizationMessagesAreNotCachedWithinTheTheme() throws IOException {
final String locale = Locale.ENGLISH.toLanguageTag();
final String realmLocalizationMessageKey = "loginAccountTitle";
final String realmLocalizationMessageValue = "Localization Test";
try(CloseableHttpClient httpClient = (CloseableHttpClient) new HttpClientBuilder().build()) {
ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient);
testRealm().localization().saveRealmLocalizationText(locale, realmLocalizationMessageKey,
realmLocalizationMessageValue);
ResteasyClient client = new ResteasyClientBuilder().httpEngine(engine).build();
loginPage.open();
try(Response responseWithLocalization =
client.target(driver.getCurrentUrl()).request().acceptLanguage(locale).get()) {
assertThat(responseWithLocalization.readEntity(String.class),
Matchers.containsString(realmLocalizationMessageValue));
testRealm().localization().deleteRealmLocalizationText(locale, realmLocalizationMessageKey);
loginPage.open();
try(Response responseWithoutLocalization =
client.target(driver.getCurrentUrl()).request().acceptLanguage(locale).get()) {
assertThat(responseWithoutLocalization.readEntity(String.class),
Matchers.not(Matchers.containsString(realmLocalizationMessageValue)));
}
}
client.close();
}
}
private void switchLanguageToGermanAndBack(String expectedEnglishMessage, String expectedGermanMessage, LanguageComboboxAwarePage page) {
// Switch language to Deutsch