mirror of
https://github.com/keycloak/keycloak.git
synced 2025-12-21 06:20:05 -06:00
[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:
@@ -12,6 +12,8 @@ public @interface InjectAdminClient {
|
||||
|
||||
String ref() default "";
|
||||
|
||||
String realmRef() default "";
|
||||
|
||||
Mode mode() default Mode.BOOTSTRAP;
|
||||
|
||||
String client() default "";
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -233,7 +233,7 @@ public class DeclarativeUserTest {
|
||||
|
||||
@Override
|
||||
public RealmConfigBuilder configure(RealmConfigBuilder realm) {
|
||||
realm.internationalizationEnabled()
|
||||
realm.internationalizationEnabled(true)
|
||||
.supportedLocales("en", "de");
|
||||
return realm;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user