Merge pull request #3757 from mstruk/KEYCLOAK-4150

KEYCLOAK-4150 Unresolved variable ${cliane_security-admin-console} in admin web client
This commit is contained in:
Stian Thorgersen 2017-01-19 13:55:36 +01:00 committed by GitHub
commit 536b88790e
7 changed files with 191 additions and 3 deletions

View file

@ -0,0 +1,62 @@
/*
* Copyright 2017 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.theme;
import java.util.Properties;
/**
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
*/
public class TemplatingUtil {
public static String resolveVariables(String text, Properties props) {
return resolveVariables(text, props, "${", "}");
}
public static String resolveVariables(String text, Properties props, String startMarker, String endMarker) {
int e = 0;
int s = text.indexOf(startMarker);
if (s == -1) {
return text;
} else {
StringBuilder sb = new StringBuilder();
do {
if (e < s) {
sb.append(text.substring(e, s));
}
e = text.indexOf(endMarker, s + startMarker.length());
if (e != -1) {
String key = text.substring(s + startMarker.length(), e);
sb.append(props.getProperty(key, key));
e += endMarker.length();
s = text.indexOf(startMarker, e);
} else {
e = s;
break;
}
} while (s != -1);
if (e < text.length()) {
sb.append(text.substring(e));
}
return sb.toString();
}
}
}

View file

@ -17,10 +17,13 @@
package org.keycloak.theme.beans;
import freemarker.template.SimpleScalar;
import freemarker.template.TemplateMethodModelEx;
import freemarker.template.TemplateModelException;
import org.keycloak.theme.TemplatingUtil;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
@ -40,10 +43,27 @@ public class MessageFormatterMethod implements TemplateMethodModelEx {
@Override
public Object exec(List list) throws TemplateModelException {
if (list.size() >= 1) {
// resolve any remaining ${} expressions
List<Object> resolved = resolve(list.subList(1, list.size()));
String key = list.get(0).toString();
return new MessageFormat(messages.getProperty(key,key),locale).format(list.subList(1, list.size()).toArray());
return new MessageFormat(messages.getProperty(key,key),locale).format(resolved.toArray());
} else {
return null;
}
}
private List<Object> resolve(List<Object> list) {
ArrayList<Object> result = new ArrayList<>();
for (Object item: list) {
if (item instanceof SimpleScalar) {
item = ((SimpleScalar) item).getAsString();
}
if (item instanceof String) {
result.add(TemplatingUtil.resolveVariables((String) item, messages));
} else {
result.add(item);
}
}
return result;
}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright 2017 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.theme.beans;
import freemarker.template.TemplateModelException;
import org.junit.Assert;
import org.junit.Test;
import java.util.Arrays;
import java.util.Locale;
import java.util.Properties;
/**
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
*/
public class MessageFormatterMethodTest {
@Test
public void test() throws TemplateModelException {
Locale locale = Locale.US;
Properties properties = new Properties();
properties.setProperty("backToApplication", "Back to application");
properties.setProperty("backToClient", "Back to {0}");
properties.setProperty("client_admin-console", "Admin Console");
properties.setProperty("realm_example-realm", "Example Realm");
MessageFormatterMethod fmt = new MessageFormatterMethod(locale, properties);
String msg = (String) fmt.exec(Arrays.asList("backToClient", "${client_admin-console}"));
Assert.assertEquals("Back to Admin Console", msg);
msg = (String) fmt.exec(Arrays.asList("backToClient", "client_admin-console"));
Assert.assertEquals("Back to client_admin-console", msg);
msg = (String) fmt.exec(Arrays.asList("backToClient", "client '${client_admin-console}' from '${realm_example-realm}'."));
Assert.assertEquals("Back to client 'Admin Console' from 'Example Realm'.", msg);
}
}

View file

@ -864,7 +864,7 @@ public class AccountTest extends AbstractTestRealmKeycloakTest {
Assert.assertTrue(applicationsPage.isCurrent());
Map<String, AccountApplicationsPage.AppEntry> apps = applicationsPage.getApplications();
Assert.assertThat(apps.keySet(), containsInAnyOrder("Account", "test-app", "test-app-scope", "third-party", "test-app-authz", "My Named Test App"));
Assert.assertThat(apps.keySet(), containsInAnyOrder("Account", "test-app", "test-app-scope", "third-party", "test-app-authz", "My Named Test App", "Test App Named - ${client_account}"));
AccountApplicationsPage.AppEntry accountEntry = apps.get("Account");
Assert.assertEquals(2, accountEntry.getRolesAvailable().size());
@ -951,7 +951,20 @@ public class AccountTest extends AbstractTestRealmKeycloakTest {
// When a client has a name provided, the name should be available to the back link
Assert.assertEquals("Back to " + namedClient.getName(), profilePage.getBackToApplicationLinkText());
Assert.assertEquals(namedClient.getBaseUrl(), profilePage.getBackToApplicationLinkHref());
foundClients = testRealm.clients().findByClientId("var-named-test-app");
if (foundClients.isEmpty()) {
Assert.fail("Unable to find var-named-test-app");
}
namedClient = foundClients.get(0);
driver.navigate().to(profilePage.getPath() + "?referrer=" + namedClient.getClientId());
Assert.assertTrue(profilePage.isCurrent());
// When a client has a name provided as a variable, the name should be resolved using a localized bundle and available to the back link
Assert.assertEquals("Back to Test App Named - Account", profilePage.getBackToApplicationLinkText());
Assert.assertEquals(namedClient.getBaseUrl(), profilePage.getBackToApplicationLinkHref());
foundClients = testRealm.clients().findByClientId("test-app");
if (foundClients.isEmpty()) {
Assert.fail("Unable to find test-app");

View file

@ -19,9 +19,13 @@ package org.keycloak.testsuite.i18n;
import org.jboss.arquillian.graphene.page.Page;
import org.junit.Assert;
import org.junit.Test;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
import org.keycloak.testsuite.pages.LoginPage;
import java.util.List;
/**
* @author <a href="mailto:gerbermichi@me.com">Michael Gerber</a>
* @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
@ -49,4 +53,25 @@ public class AccountPageTest extends AbstractI18NTest {
Assert.assertEquals("English", accountUpdateProfilePage.getLanguageDropdownText());
accountUpdateProfilePage.logout();
}
@Test
public void testLocalizedReferrerLinkContent() {
RealmResource testRealm = testRealm();
List<ClientRepresentation> foundClients = testRealm.clients().findByClientId("var-named-test-app");
if (foundClients.isEmpty()) {
Assert.fail("Unable to find var-named-test-app");
}
ClientRepresentation namedClient = foundClients.get(0);
driver.navigate().to(accountUpdateProfilePage.getPath() + "?referrer=" + namedClient.getClientId());
loginPage.login("test-user@localhost", "password");
Assert.assertTrue(accountUpdateProfilePage.isCurrent());
accountUpdateProfilePage.openLanguage("Deutsch");
Assert.assertEquals("Deutsch", accountUpdateProfilePage.getLanguageDropdownText());
// When a client has a name provided as a variable, the name should be resolved using a localized bundle and available to the back link
Assert.assertEquals("Zur\u00FCck zu Test App Named - Konto", accountUpdateProfilePage.getBackToApplicationLinkText());
Assert.assertEquals(namedClient.getBaseUrl(), accountUpdateProfilePage.getBackToApplicationLinkHref());
}
}

View file

@ -331,6 +331,17 @@
],
"adminUrl": "http://localhost:8180/namedapp/base/admin",
"secret": "password"
},
{
"clientId": "var-named-test-app",
"name": "Test App Named - ${client_account}",
"enabled": true,
"baseUrl": "http://localhost:8180/varnamedapp/base",
"redirectUris": [
"http://localhost:8180/varnamedapp/base/*"
],
"adminUrl": "http://localhost:8180/varnamedapp/base/admin",
"secret": "password"
}
],
"roles" : {

View file

@ -50,6 +50,7 @@ role_manage-clients=Clients verwalten
role_manage-events=Events verwalten
role_view-profile=Profile ansehen
role_manage-account=Profile verwalten
client_account=Konto
requiredFields=Erforderliche Felder
allFieldsRequired=Alle Felder sind Erforderlich