[Test framework] AdminConsoleWhoAmILocaleTest migration (#38158)

* Moving files to the new test suite

Signed-off-by: Lukas Hanusovsky <lhanusov@redhat.com>

* Move AdminConsoleWhoAmILocaleTest.java, DeclarativeUserTest.java to the new testsuite

Part of: #34494

Signed-off-by: Lukas Hanusovsky <lhanusov@redhat.com>

---------

Signed-off-by: Lukas Hanusovsky <lhanusov@redhat.com>
This commit is contained in:
Lukas Hanusovsky
2025-04-07 12:45:52 +02:00
committed by GitHub
parent 570dc0f81a
commit f5323fec24
9 changed files with 382 additions and 317 deletions

View File

@@ -12,6 +12,8 @@ public @interface InjectAdminClient {
String ref() default "";
String realmRef() default "";
Mode mode() default Mode.BOOTSTRAP;
String client() default "";

View File

@@ -138,8 +138,8 @@ public class RealmConfigBuilder {
return this;
}
public RealmConfigBuilder internationalizationEnabled() {
rep.setInternationalizationEnabled(true);
public RealmConfigBuilder internationalizationEnabled(boolean enabled) {
rep.setInternationalizationEnabled(enabled);
return this;
}
@@ -151,6 +151,11 @@ public class RealmConfigBuilder {
return this;
}
public RealmConfigBuilder defaultLocale(String locale) {
rep.setDefaultLocale(locale);
return this;
}
public RealmConfigBuilder smtp(String host, int port, String from) {
Map<String, String> config = new HashMap<>();
config.put("host", host);

View File

@@ -82,6 +82,11 @@ public class UserConfigBuilder {
return this;
}
public UserConfigBuilder attribute(String key, String value) {
rep.singleAttribute(key, value);
return this;
}
public UserRepresentation build() {
return rep;
}

View File

@@ -7,9 +7,13 @@ public class ApiUtil {
public static String handleCreatedResponse(Response response) {
try (response) {
String uuid = getCreatedId(response);
response.close();
return uuid;
if (response.getStatus() != Response.Status.CONFLICT.getStatusCode()) {
String uuid = getCreatedId(response);
response.close();
return uuid;
} else {
return null;
}
}
}

View File

@@ -4,7 +4,6 @@ import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.CloseableHttpClient;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.testframework.injection.InstanceContext;
import org.keycloak.testframework.injection.LifeCycle;
import org.keycloak.testframework.injection.RequestedInstance;
import org.keycloak.testframework.injection.Supplier;
import org.keycloak.testframework.injection.SupplierHelpers;
@@ -52,12 +51,7 @@ public class OAuthClientSupplier implements Supplier<OAuthClient, InjectOAuthCli
@Override
public boolean compatible(InstanceContext<OAuthClient, InjectOAuthClient> a, RequestedInstance<OAuthClient, InjectOAuthClient> b) {
return true;
}
@Override
public LifeCycle getDefaultLifecycle() {
return LifeCycle.GLOBAL;
return a.getAnnotation().ref().equals(b.getAnnotation().ref());
}
@Override

View File

@@ -1,5 +1,6 @@
package org.keycloak.testframework.oauth.annotations;
import org.keycloak.testframework.injection.LifeCycle;
import org.keycloak.testframework.oauth.DefaultOAuthClientConfiguration;
import org.keycloak.testframework.realm.ClientConfig;
@@ -14,6 +15,10 @@ public @interface InjectOAuthClient {
Class<? extends ClientConfig> config() default DefaultOAuthClientConfiguration.class;
LifeCycle lifecycle() default LifeCycle.CLASS;
String ref() default "";
String realmRef() default "";
boolean kcAdmin() default false;

View File

@@ -0,0 +1,354 @@
package org.keycloak.tests.admin;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.ws.rs.core.Response;
import org.apache.http.Header;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicHeader;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.Constants;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.testframework.annotations.InjectClient;
import org.keycloak.testframework.annotations.InjectHttpClient;
import org.keycloak.testframework.annotations.InjectKeycloakUrls;
import org.keycloak.testframework.annotations.InjectRealm;
import org.keycloak.testframework.annotations.InjectUser;
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
import org.keycloak.testframework.oauth.OAuthClient;
import org.keycloak.testframework.oauth.annotations.InjectOAuthClient;
import org.keycloak.testframework.realm.ClientConfig;
import org.keycloak.testframework.realm.ClientConfigBuilder;
import org.keycloak.testframework.realm.ManagedClient;
import org.keycloak.testframework.realm.ManagedRealm;
import org.keycloak.testframework.realm.ManagedUser;
import org.keycloak.testframework.realm.RealmConfig;
import org.keycloak.testframework.realm.RealmConfigBuilder;
import org.keycloak.testframework.realm.UserConfig;
import org.keycloak.testframework.realm.UserConfigBuilder;
import org.keycloak.testframework.server.KeycloakUrls;
import org.keycloak.testsuite.util.oauth.AccessTokenResponse;
import java.io.IOException;
import java.util.List;
import static org.keycloak.models.Constants.ADMIN_CLI_CLIENT_ID;
@KeycloakIntegrationTest
public class AdminConsoleWhoAmILocaleTest {
@InjectRealm(ref = "master", attachTo = "master")
ManagedRealm masterRealm;
@InjectRealm(ref = "realm-i18n-off", config = LocaleOffRealmConfig.class)
ManagedRealm managedRealmOff;
@InjectRealm(ref = "realm-i18n-on", config = LocaleOnRealmConfig.class)
ManagedRealm managedRealmOn;
@InjectUser(realmRef = "master", config = MasterAdminUserConfig.class)
ManagedUser masterAdmin;
@InjectClient(realmRef = "master", config = MasterAdminClientConfig.class)
ManagedClient masterClient;
@InjectOAuthClient(ref = "master", realmRef = "master")
OAuthClient oAuthClientMaster;
@InjectOAuthClient(ref = "locale-off", realmRef = "realm-i18n-off")
OAuthClient oAuthClientLocaleOff;
@InjectOAuthClient(ref = "locale-on", realmRef = "realm-i18n-on")
OAuthClient oAuthClientLocaleOn;
@InjectKeycloakUrls
KeycloakUrls keycloakUrls;
@InjectHttpClient
CloseableHttpClient client;
private static final String REALM_I18N_OFF = "realm-i18n-off";
private static final String REALM_I18N_ON = "realm-i18n-on";
private static final String USER_WITHOUT_LOCALE = "user-without-locale";
private static final String USER_WITH_LOCALE = "user-with-locale";
private static final String USER_NO_ACCESS = "user-no-access";
private static final String PASSWORD = "password";
private static final String ADMIN_CLI_NOT_ALLOWED = "admin-cli-not-allowed";
private static final String SECRET = "secret";
private static final String DEFAULT_LOCALE = "en";
private static final String REALM_LOCALE = "no";
private static final String USER_LOCALE = "de";
private static final String EXTRA_LOCALE = "zh-CN";
@Test
public void testLocaleRealmI18nDisabledUserWithoutLocale() throws Exception {
AccessTokenResponse response = accessToken(oAuthClientLocaleOff, ADMIN_CLI_CLIENT_ID, SECRET, USER_WITHOUT_LOCALE, PASSWORD);
JsonNode whoAmI = getHttpJsonResponse(whoAmiUrl(managedRealmOff), response);
Assertions.assertEquals(REALM_I18N_OFF, whoAmI.get("realm").asText());
Assertions.assertEquals(DEFAULT_LOCALE, whoAmI.get("locale").asText());
checkRealmAccess(REALM_I18N_OFF, whoAmI);
oAuthClientLocaleOff.doLogout(response.getRefreshToken());
}
@Test
public void testLocaleRealmI18nDisabledUserWithLocale() throws Exception {
AccessTokenResponse response = accessToken(oAuthClientLocaleOff, ADMIN_CLI_CLIENT_ID, SECRET, USER_WITH_LOCALE, PASSWORD);
JsonNode whoAmI = getHttpJsonResponse(whoAmiUrl(managedRealmOff), response);
Assertions.assertEquals(REALM_I18N_OFF, whoAmI.get("realm").asText());
Assertions.assertEquals(DEFAULT_LOCALE, whoAmI.get("locale").asText());
checkRealmAccess(REALM_I18N_OFF, whoAmI);
oAuthClientLocaleOff.doLogout(response.getRefreshToken());
}
@Test
public void testLocaleRealmI18nEnabledUserWithoutLocale() throws Exception {
AccessTokenResponse response = accessToken(oAuthClientLocaleOn, ADMIN_CLI_CLIENT_ID, SECRET, USER_WITHOUT_LOCALE, PASSWORD);
JsonNode whoAmI = getHttpJsonResponse(whoAmiUrl(managedRealmOn), response);
Assertions.assertEquals(REALM_I18N_ON, whoAmI.get("realm").asText());
Assertions.assertEquals(REALM_LOCALE, whoAmI.get("locale").asText());
checkRealmAccess(REALM_I18N_ON, whoAmI);
oAuthClientLocaleOn.doLogout(response.getRefreshToken());
}
@Test
public void testLocaleRealmI18nEnabledUserWithLocale() throws Exception {
AccessTokenResponse response = accessToken(oAuthClientLocaleOn, ADMIN_CLI_CLIENT_ID, SECRET, USER_WITH_LOCALE, PASSWORD);
JsonNode whoAmI = getHttpJsonResponse(whoAmiUrl(managedRealmOn), response);
Assertions.assertEquals(REALM_I18N_ON, whoAmI.get("realm").asText());
Assertions.assertEquals(USER_LOCALE, whoAmI.get("locale").asText());
checkRealmAccess(REALM_I18N_ON, whoAmI);
oAuthClientLocaleOn.doLogout(response.getRefreshToken());
}
@Test
public void testLocaleRealmI18nEnabledAcceptLanguageHeader() throws Exception {
AccessTokenResponse response = accessToken(oAuthClientLocaleOn, ADMIN_CLI_CLIENT_ID, SECRET, USER_WITHOUT_LOCALE, PASSWORD);
JsonNode whoAmI = getHttpJsonResponse(whoAmiUrl(managedRealmOn), response, new BasicHeader("Accept-Language", EXTRA_LOCALE));
Assertions.assertEquals(REALM_I18N_ON, whoAmI.get("realm").asText());
Assertions.assertEquals(EXTRA_LOCALE, whoAmI.get("locale").asText());
checkRealmAccess(REALM_I18N_ON, whoAmI);
oAuthClientLocaleOn.doLogout(response.getRefreshToken());
}
@Test
public void testLocaleRealmI18nEnabledKeycloakLocaleCookie() throws Exception {
AccessTokenResponse response = accessToken(oAuthClientLocaleOn, ADMIN_CLI_CLIENT_ID, SECRET, USER_WITHOUT_LOCALE, PASSWORD);
JsonNode whoAmI = getHttpJsonResponse(whoAmiUrl(managedRealmOn), response, new BasicHeader("Cookie", "KEYCLOAK_LOCALE=" + EXTRA_LOCALE));
Assertions.assertEquals(REALM_I18N_ON, whoAmI.get("realm").asText());
Assertions.assertEquals(EXTRA_LOCALE, whoAmI.get("locale").asText());
checkRealmAccess(REALM_I18N_ON, whoAmI);
oAuthClientLocaleOn.doLogout(response.getRefreshToken());
}
@Test
public void testMasterRealm() throws Exception {
updateMasterAdminRole();
AccessTokenResponse response = accessToken(oAuthClientMaster, masterClient.getClientId(), SECRET, masterAdmin.getUsername(), PASSWORD);
JsonNode whoAmI = getHttpJsonResponse(whoAmiUrl(masterRealm), response);
Assertions.assertEquals(masterRealm.getName(), whoAmI.get("realm").asText());
Assertions.assertEquals(DEFAULT_LOCALE, whoAmI.get("locale").asText());
checkRealmAccess(masterRealm.getName(), whoAmI);
oAuthClientMaster.doLogout(response.getRefreshToken());
}
@Test
public void testMasterRealmCurrentRealm() throws Exception {
updateMasterAdminRole();
AccessTokenResponse response = accessToken(oAuthClientMaster, masterClient.getClientId(), SECRET, masterAdmin.getUsername(), PASSWORD);
JsonNode whoAmI = getHttpJsonResponse(whoAmiUrl(masterRealm, REALM_I18N_ON), response);
Assertions.assertEquals(masterRealm.getName(), whoAmI.get("realm").asText());
Assertions.assertEquals(DEFAULT_LOCALE, whoAmI.get("locale").asText());
checkRealmAccess(REALM_I18N_ON, whoAmI);
oAuthClientMaster.doLogout(response.getRefreshToken());
}
@Test
public void testLocaleRealmNoToken() throws Exception {
HttpGet httpGet = new HttpGet(whoAmiUrl(managedRealmOn));
httpGet.addHeader("Accept", "application/json");
CloseableHttpResponse httpGetResponse = client.execute(httpGet);
Assertions.assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), httpGetResponse.getStatusLine().getStatusCode());
httpGetResponse.close();
}
@Test
public void testLocaleRealmUserNoAccess() throws Exception {
AccessTokenResponse response = accessToken(oAuthClientLocaleOn, ADMIN_CLI_CLIENT_ID, SECRET, USER_NO_ACCESS, PASSWORD);
HttpGet httpGet = new HttpGet(whoAmiUrl(managedRealmOn));
httpGet.addHeader("Accept", "application/json");
httpGet.addHeader("Authorization", "Bearer " + response.getAccessToken());
CloseableHttpResponse httpGetResponse = client.execute(httpGet);
Assertions.assertEquals(Response.Status.FORBIDDEN.getStatusCode(), httpGetResponse.getStatusLine().getStatusCode());
httpGetResponse.close();
oAuthClientLocaleOn.doLogout(response.getRefreshToken());
}
@Test
public void testLocaleRealmTokenAdminNotAllowed() throws Exception {
AccessTokenResponse response = accessToken(oAuthClientLocaleOn, ADMIN_CLI_NOT_ALLOWED, SECRET, USER_WITH_LOCALE, PASSWORD);
Assertions.assertNotNull(response.getAccessToken());
HttpGet httpGet = new HttpGet(whoAmiUrl(managedRealmOn));
httpGet.addHeader("Accept", "application/json");
httpGet.addHeader("Authorization", "Bearer " + response.getAccessToken());
CloseableHttpResponse httpGetResponse = client.execute(httpGet);
Assertions.assertEquals(Response.Status.FORBIDDEN.getStatusCode(), httpGetResponse.getStatusLine().getStatusCode());
httpGetResponse.close();
}
private void updateMasterAdminRole() {
RoleRepresentation roleRep = masterRealm.admin().roles().get("admin").toRepresentation();
masterRealm.admin().users().get(masterAdmin.getId()).roles().realmLevel().add(List.of(roleRep));
}
private AccessTokenResponse accessToken(OAuthClient oAuth, String clientId, String clientSecret, String username, String password) {
return oAuth.client(clientId, clientSecret).doPasswordGrantRequest(username, password);
}
private JsonNode getHttpJsonResponse(String url, AccessTokenResponse response, Header... headers) throws IOException{
HttpGet httpGet = new HttpGet(url);
httpGet.addHeader("Accept", "application/json");
httpGet.addHeader("Authorization", "Bearer " + response.getAccessToken());
for (Header header : headers) {
httpGet.addHeader(header.getName(), header.getValue());
}
return new ObjectMapper().readTree(client.execute(httpGet).getEntity().getContent());
}
private String whoAmiUrl(ManagedRealm realm) {
return whoAmiUrl(realm, null);
}
private String whoAmiUrl(ManagedRealm realm, String currentRealm) {
StringBuilder sb = new StringBuilder()
.append(keycloakUrls.getBaseUrl())
.append("/admin/")
.append(realm.getName())
.append("/console/whoami");
if (currentRealm != null) {
sb.append("?currentRealm=").append(currentRealm);
}
return sb.toString();
}
private void checkRealmAccess(String realm, JsonNode whoAmI) {
Assertions.assertNotNull(whoAmI.get("realm_access"));
Assertions.assertNotNull(whoAmI.get("realm_access").get(realm));
Assertions.assertTrue(whoAmI.get("realm_access").get(realm).isArray());
Assertions.assertTrue(whoAmI.get("realm_access").get(realm).size() > 0);
}
private static class LocaleOffRealmConfig implements RealmConfig {
@Override
public RealmConfigBuilder configure(RealmConfigBuilder realm) {
realm.internationalizationEnabled(false);
realm.addUser(USER_WITHOUT_LOCALE).password(PASSWORD)
.name("My", "Locale Off")
.email("locale-off@email.org").emailVerified()
.clientRoles(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.REALM_ADMIN);
realm.addUser(USER_WITH_LOCALE).password(PASSWORD)
.name("My", "Locale On")
.email("locale-on@email.org").emailVerified()
.attribute("locale", USER_LOCALE)
.clientRoles(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.REALM_ADMIN);
realm.addClient(ADMIN_CLI_CLIENT_ID).name(ADMIN_CLI_CLIENT_ID).secret(SECRET)
.attribute(Constants.SECURITY_ADMIN_CONSOLE_ATTR, "true")
.directAccessGrants();
return realm;
}
}
private static class LocaleOnRealmConfig implements RealmConfig {
@Override
public RealmConfigBuilder configure(RealmConfigBuilder realm) {
realm.internationalizationEnabled(true);
realm.supportedLocales(REALM_LOCALE, USER_LOCALE, EXTRA_LOCALE);
realm.defaultLocale(REALM_LOCALE);
realm.addUser(USER_WITHOUT_LOCALE).password(PASSWORD)
.name("My", "Locale Off")
.email("locale-off@email.org").emailVerified()
.clientRoles(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.REALM_ADMIN);
realm.addUser(USER_WITH_LOCALE).password(PASSWORD)
.email("locale-on@email.org").emailVerified().name("My", "Locale On")
.attribute("locale", USER_LOCALE)
.clientRoles(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.REALM_ADMIN);
realm.addUser(USER_NO_ACCESS).password(PASSWORD)
.name("No", "Access")
.email("no-access@email.org").emailVerified()
.attribute("locale", USER_LOCALE);
realm.addClient(ADMIN_CLI_CLIENT_ID).name(ADMIN_CLI_CLIENT_ID).secret(SECRET)
.attribute(Constants.SECURITY_ADMIN_CONSOLE_ATTR, "true")
.directAccessGrants();
realm.addClient(ADMIN_CLI_NOT_ALLOWED).name(ADMIN_CLI_NOT_ALLOWED).secret(SECRET)
.attribute(Constants.SECURITY_ADMIN_CONSOLE_ATTR, null)
.directAccessGrants();
return realm;
}
}
private static class MasterAdminUserConfig implements UserConfig {
@Override
public UserConfigBuilder configure(UserConfigBuilder user) {
user.username("master-admin");
user.password(PASSWORD);
user.name("My", "Admin");
user.roles("admin");
user.email("master-admin@email.org");
user.emailVerified();
user.attribute("locale", DEFAULT_LOCALE);
return user;
}
}
private static class MasterAdminClientConfig implements ClientConfig {
@Override
public ClientConfigBuilder configure(ClientConfigBuilder client) {
client.clientId("master-admin-cli");
client.name("master-admin-cli");
client.secret(SECRET);
client.attribute(Constants.SECURITY_ADMIN_CONSOLE_ATTR, "true");
client.directAccessGrants();
return client;
}
}
}

View File

@@ -233,7 +233,7 @@ public class DeclarativeUserTest {
@Override
public RealmConfigBuilder configure(RealmConfigBuilder realm) {
realm.internationalizationEnabled()
realm.internationalizationEnabled(true)
.supportedLocales("en", "de");
return realm;
}

View File

@@ -1,304 +0,0 @@
package org.keycloak.testsuite.admin;
import com.fasterxml.jackson.databind.JsonNode;
import jakarta.ws.rs.core.Response;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.broker.provider.util.SimpleHttp;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.Constants;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.auth.page.AuthRealm;
import org.keycloak.testsuite.broker.util.SimpleHttpDefault;
import org.keycloak.testsuite.updaters.ClientAttributeUpdater;
import org.keycloak.testsuite.util.AdminClientUtil;
import org.keycloak.testsuite.util.RealmBuilder;
import org.keycloak.testsuite.util.UserBuilder;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import static org.keycloak.models.Constants.ADMIN_CLI_CLIENT_ID;
public class AdminConsoleWhoAmILocaleTest extends AbstractKeycloakTest {
private static final String REALM_I18N_OFF = "realm-i18n-off";
private static final String REALM_I18N_ON = "realm-i18n-on";
private static final String USER_WITHOUT_LOCALE = "user-without-locale";
private static final String USER_WITH_LOCALE = "user-with-locale";
private static final String USER_NO_ACCESS = "user-no-access";
private static final String PASSWORD = "password";
private static final String DEFAULT_LOCALE = "en";
private static final String REALM_LOCALE = "no";
private static final String USER_LOCALE = "de";
private static final String EXTRA_LOCALE = "zh-CN";
private CloseableHttpClient client;
@Before
public void createHttpClient() throws Exception {
client = HttpClientBuilder.create().build();
getCleanup().addCleanup(ClientAttributeUpdater.forClient(adminClient, "master", ADMIN_CLI_CLIENT_ID).setAttribute(Constants.SECURITY_ADMIN_CONSOLE_ATTR, "true").update());
getCleanup().addCleanup(ClientAttributeUpdater.forClient(adminClient, REALM_I18N_OFF, ADMIN_CLI_CLIENT_ID).setAttribute(Constants.SECURITY_ADMIN_CONSOLE_ATTR, "true").update());
getCleanup().addCleanup(ClientAttributeUpdater.forClient(adminClient, REALM_I18N_ON, ADMIN_CLI_CLIENT_ID).setAttribute(Constants.SECURITY_ADMIN_CONSOLE_ATTR, "true").update());
}
@After
public void closeHttpClient() {
try {
client.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public void addTestRealms(List<RealmRepresentation> testRealms) {
RealmBuilder realm = RealmBuilder.create()
.name(REALM_I18N_OFF)
.internationalizationEnabled(false);
realm.user(UserBuilder.create()
.username(USER_WITHOUT_LOCALE)
.password(PASSWORD)
.role(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.REALM_ADMIN));
realm.user(UserBuilder.create()
.username(USER_WITH_LOCALE)
.password(PASSWORD)
.addAttribute("locale", USER_LOCALE)
.role(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.REALM_ADMIN));
testRealms.add(realm.build());
realm = RealmBuilder.create()
.name(REALM_I18N_ON)
.internationalizationEnabled(true)
.supportedLocales(new HashSet<>(Arrays.asList(REALM_LOCALE, USER_LOCALE, EXTRA_LOCALE)))
.defaultLocale(REALM_LOCALE);
realm.user(UserBuilder.create()
.username(USER_WITHOUT_LOCALE)
.password(PASSWORD)
.role(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.REALM_ADMIN));
realm.user(UserBuilder.create()
.username(USER_WITH_LOCALE)
.password(PASSWORD)
.addAttribute("locale", USER_LOCALE)
.role(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.REALM_ADMIN));
realm.user(UserBuilder.create()
.username(USER_NO_ACCESS)
.password(PASSWORD)
.addAttribute("locale", USER_LOCALE));
testRealms.add(realm.build());
}
private org.keycloak.testsuite.util.oauth.AccessTokenResponse accessToken(String realmName, String username, String password) throws Exception {
return oauth.realm(realmName).client(ADMIN_CLI_CLIENT_ID).doPasswordGrantRequest(username, password);
}
private String whoAmiUrl(String realmName) {
return whoAmiUrl(realmName, null);
}
private String whoAmiUrl(String realmName, String currentRealm) {
StringBuilder sb = new StringBuilder()
.append(suiteContext.getAuthServerInfo().getContextRoot().toString())
.append("/auth/admin/")
.append(realmName)
.append("/console/whoami");
if (currentRealm != null) {
sb.append("?currentRealm=").append(currentRealm);
}
return sb.toString();
}
private void checkRealmAccess(String realm, JsonNode whoAmI) {
Assert.assertNotNull(whoAmI.get("realm_access"));
Assert.assertNotNull(whoAmI.get("realm_access").get(realm));
Assert.assertTrue(whoAmI.get("realm_access").get(realm).isArray());
Assert.assertTrue(whoAmI.get("realm_access").get(realm).size() > 0);
}
@Test
public void testLocaleRealmI18nDisabledUserWithoutLocale() throws Exception {
org.keycloak.testsuite.util.oauth.AccessTokenResponse response = oauth.realm(REALM_I18N_OFF).client(ADMIN_CLI_CLIENT_ID).doPasswordGrantRequest(USER_WITHOUT_LOCALE, PASSWORD);
JsonNode whoAmI = SimpleHttpDefault
.doGet(whoAmiUrl(REALM_I18N_OFF), client)
.header("Accept", "application/json")
.auth(response.getAccessToken())
.asJson();
Assert.assertEquals(REALM_I18N_OFF, whoAmI.get("realm").asText());
Assert.assertEquals(DEFAULT_LOCALE, whoAmI.get("locale").asText());
checkRealmAccess(REALM_I18N_OFF, whoAmI);
oauth.doLogout(response.getRefreshToken());
}
@Test
public void testLocaleRealmI18nDisabledUserWithLocale() throws Exception {
org.keycloak.testsuite.util.oauth.AccessTokenResponse response = accessToken(REALM_I18N_OFF, USER_WITH_LOCALE, PASSWORD);
JsonNode whoAmI = SimpleHttpDefault
.doGet(whoAmiUrl(REALM_I18N_OFF), client)
.header("Accept", "application/json")
.auth(response.getAccessToken())
.asJson();
Assert.assertEquals(REALM_I18N_OFF, whoAmI.get("realm").asText());
Assert.assertEquals(DEFAULT_LOCALE, whoAmI.get("locale").asText());
checkRealmAccess(REALM_I18N_OFF, whoAmI);
oauth.doLogout(response.getRefreshToken());
}
@Test
public void testLocaleRealmI18nEnabledUserWithoutLocale() throws Exception {
org.keycloak.testsuite.util.oauth.AccessTokenResponse response = accessToken(REALM_I18N_ON, USER_WITHOUT_LOCALE, PASSWORD);
JsonNode whoAmI = SimpleHttpDefault
.doGet(whoAmiUrl(REALM_I18N_ON), client)
.header("Accept", "application/json")
.auth(response.getAccessToken())
.asJson();
Assert.assertEquals(REALM_I18N_ON, whoAmI.get("realm").asText());
Assert.assertEquals(REALM_LOCALE, whoAmI.get("locale").asText());
checkRealmAccess(REALM_I18N_ON, whoAmI);
oauth.doLogout(response.getRefreshToken());
}
@Test
public void testLocaleRealmI18nEnabledUserWithLocale() throws Exception {
org.keycloak.testsuite.util.oauth.AccessTokenResponse response = accessToken(REALM_I18N_ON, USER_WITH_LOCALE, PASSWORD);
JsonNode whoAmI = SimpleHttpDefault
.doGet(whoAmiUrl(REALM_I18N_ON), client)
.header("Accept", "application/json")
.auth(response.getAccessToken())
.asJson();
Assert.assertEquals(REALM_I18N_ON, whoAmI.get("realm").asText());
Assert.assertEquals(USER_LOCALE, whoAmI.get("locale").asText());
checkRealmAccess(REALM_I18N_ON, whoAmI);
oauth.doLogout(response.getRefreshToken());
}
@Test
public void testLocaleRealmI18nEnabledAcceptLanguageHeader() throws Exception {
org.keycloak.testsuite.util.oauth.AccessTokenResponse response = accessToken(REALM_I18N_ON, USER_WITHOUT_LOCALE, PASSWORD);
JsonNode whoAmI = SimpleHttpDefault
.doGet(whoAmiUrl(REALM_I18N_ON), client)
.header("Accept", "application/json")
.auth(response.getAccessToken())
.header("Accept-Language", EXTRA_LOCALE)
.asJson();
Assert.assertEquals(REALM_I18N_ON, whoAmI.get("realm").asText());
Assert.assertEquals(EXTRA_LOCALE, whoAmI.get("locale").asText());
checkRealmAccess(REALM_I18N_ON, whoAmI);
oauth.doLogout(response.getRefreshToken());
}
@Test
public void testLocaleRealmI18nEnabledKeycloakLocaleCookie() throws Exception {
org.keycloak.testsuite.util.oauth.AccessTokenResponse response = accessToken(REALM_I18N_ON, USER_WITHOUT_LOCALE, PASSWORD);
JsonNode whoAmI = SimpleHttpDefault
.doGet(whoAmiUrl(REALM_I18N_ON), client)
.header("Accept", "application/json")
.auth(response.getAccessToken())
.header("Cookie", "KEYCLOAK_LOCALE=" + EXTRA_LOCALE)
.asJson();
Assert.assertEquals(REALM_I18N_ON, whoAmI.get("realm").asText());
Assert.assertEquals(EXTRA_LOCALE, whoAmI.get("locale").asText());
checkRealmAccess(REALM_I18N_ON, whoAmI);
oauth.doLogout(response.getRefreshToken());
}
@Test
public void testMasterRealm() throws Exception {
org.keycloak.testsuite.util.oauth.AccessTokenResponse response = accessToken(AuthRealm.MASTER, AuthRealm.ADMIN, AuthRealm.ADMIN);
JsonNode whoAmI = SimpleHttpDefault
.doGet(whoAmiUrl(AuthRealm.MASTER), client)
.header("Accept", "application/json")
.auth(response.getAccessToken())
.asJson();
Assert.assertEquals(AuthRealm.MASTER, whoAmI.get("realm").asText());
Assert.assertEquals(DEFAULT_LOCALE, whoAmI.get("locale").asText());
checkRealmAccess(AuthRealm.MASTER, whoAmI);
oauth.doLogout(response.getRefreshToken());
}
@Test
public void testMasterRealmCurrentRealm() throws Exception {
org.keycloak.testsuite.util.oauth.AccessTokenResponse response = accessToken(AuthRealm.MASTER, AuthRealm.ADMIN, AuthRealm.ADMIN);
JsonNode whoAmI = SimpleHttpDefault
.doGet(whoAmiUrl(AuthRealm.MASTER, REALM_I18N_ON), client)
.header("Accept", "application/json")
.auth(response.getAccessToken())
.asJson();
Assert.assertEquals(AuthRealm.MASTER, whoAmI.get("realm").asText());
Assert.assertEquals(DEFAULT_LOCALE, whoAmI.get("locale").asText());
checkRealmAccess(REALM_I18N_ON, whoAmI);
oauth.doLogout(response.getRefreshToken());
}
@Test
public void testLocaleRealmNoToken() throws Exception {
try (SimpleHttp.Response response = SimpleHttpDefault
.doGet(whoAmiUrl(REALM_I18N_ON), client)
.header("Accept", "application/json")
.asResponse()) {
Assert.assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
}
}
@Test
public void testLocaleRealmUserNoAccess() throws Exception {
org.keycloak.testsuite.util.oauth.AccessTokenResponse response = accessToken(REALM_I18N_ON, USER_NO_ACCESS, PASSWORD);
try (SimpleHttp.Response res = SimpleHttpDefault
.doGet(whoAmiUrl(REALM_I18N_ON), client)
.header("Accept", "application/json")
.auth(response.getAccessToken())
.asResponse()) {
Assert.assertEquals(Response.Status.FORBIDDEN.getStatusCode(), res.getStatus());
}
oauth.doLogout(response.getRefreshToken());
}
@Test
public void testLocaleRealmTokenForOtherClient() throws Exception {
try (var c = ClientAttributeUpdater.forClient(adminClient, REALM_I18N_ON, ADMIN_CLI_CLIENT_ID).setAttribute(Constants.SECURITY_ADMIN_CONSOLE_ATTR, null).update();
Keycloak adminCliClient = AdminClientUtil.createAdminClient(true, REALM_I18N_ON,
USER_WITH_LOCALE, PASSWORD, Constants.ADMIN_CLI_CLIENT_ID, null)) {
AccessTokenResponse accessToken = adminCliClient.tokenManager().getAccessToken();
Assert.assertNotNull(accessToken);
String token = accessToken.getToken();
try (SimpleHttp.Response response = SimpleHttpDefault
.doGet(whoAmiUrl(REALM_I18N_ON), client)
.header("Accept", "application/json")
.auth(token)
.asResponse()) {
Assert.assertEquals(Response.Status.FORBIDDEN.getStatusCode(), response.getStatus());
}
}
}
@Test
public void testLocaleRealmTokenForOtherClientButAllowed() throws Exception {
try (ClientAttributeUpdater updater = ClientAttributeUpdater.forClient(adminClient, REALM_I18N_ON, Constants.ADMIN_CLI_CLIENT_ID)
.setAttribute(Constants.SECURITY_ADMIN_CONSOLE_ATTR, Boolean.TRUE.toString())
.update();
Keycloak adminCliClient = AdminClientUtil.createAdminClient(true, REALM_I18N_ON,
USER_WITH_LOCALE, PASSWORD, Constants.ADMIN_CLI_CLIENT_ID, null)) {
AccessTokenResponse accessToken = adminCliClient.tokenManager().getAccessToken();
Assert.assertNotNull(accessToken);
String token = accessToken.getToken();
JsonNode whoAmI = SimpleHttpDefault
.doGet(whoAmiUrl(REALM_I18N_ON), client)
.header("Accept", "application/json")
.auth(token)
.asJson();
Assert.assertEquals(REALM_I18N_ON, whoAmI.get("realm").asText());
Assert.assertEquals(USER_LOCALE, whoAmI.get("locale").asText());
checkRealmAccess(REALM_I18N_ON, whoAmI);
}
}
}