mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-09 15:02:05 -03:30
Expose system-info information in the serverinfo endpoint only for users in the admin realm
Closes #42828 (cherry picked from commit 1d28c0cd35a186551cf4114cbd6cdf75b9e3fe58) Signed-off-by: rmartinc <rmartinc@redhat.com>
This commit is contained in:
parent
27121d010c
commit
69685b54f2
@ -0,0 +1,15 @@
|
||||
// ------------------------ Notable changes ------------------------ //
|
||||
== Notable changes
|
||||
|
||||
Notable changes where an internal behavior changed to prevent common misconfigurations, fix bugs or simplify running {project_name}.
|
||||
|
||||
=== The `serverinfo` endpoint only returns the system info for administrators in the administrator realm
|
||||
|
||||
Starting with this version, the `serverinfo` endpoint, which is used by the admin console to obtain some general information of the {project_name} installation, will only return the system information for administrators in the administration (master) realm. This change was done for security reasons.
|
||||
|
||||
If, for whatever reason, an administrator in a common realm needs to access the `systemInfo`, `cpuInfo` or `memoryInfo` fields of the `serverinfo` response, you need to create and assign a new *view-system* role to that admin user:
|
||||
|
||||
. In the affected realm, select the management client *realm-management*, and, in the *Roles* tab, create a new role called *view-system*.
|
||||
. In *Users* select the administrator account, and, in the *Role mapping* tab, assign the just created *view-system* client role to the admin user.
|
||||
|
||||
The previous workaround is marked as deprecated and it can be removed in a future version of {project_name}.
|
||||
@ -1,6 +1,10 @@
|
||||
[[migration-changes]]
|
||||
== Migration Changes
|
||||
|
||||
=== Migrating to 26.2.10
|
||||
|
||||
include::changes-26_2_10.adoc[leveloffset=2]
|
||||
|
||||
=== Migrating to 26.2.9
|
||||
|
||||
include::changes-26_2_9.adoc[leveloffset=2]
|
||||
|
||||
@ -35,12 +35,14 @@ public class AdminRoles {
|
||||
public static String CREATE_REALM = "create-realm";
|
||||
public static String CREATE_CLIENT = "create-client";
|
||||
|
||||
public static String VIEW_REALM = "view-realm";
|
||||
public static String VIEW_USERS = "view-users";
|
||||
public static String VIEW_CLIENTS = "view-clients";
|
||||
public static String VIEW_EVENTS = "view-events";
|
||||
public static String VIEW_IDENTITY_PROVIDERS = "view-identity-providers";
|
||||
public static String VIEW_AUTHORIZATION = "view-authorization";
|
||||
public static final String VIEW_REALM = "view-realm";
|
||||
public static final String VIEW_USERS = "view-users";
|
||||
public static final String VIEW_CLIENTS = "view-clients";
|
||||
public static final String VIEW_EVENTS = "view-events";
|
||||
public static final String VIEW_IDENTITY_PROVIDERS = "view-identity-providers";
|
||||
public static final String VIEW_AUTHORIZATION = "view-authorization";
|
||||
@Deprecated(since = "26.2.9", forRemoval = true)
|
||||
public static final String VIEW_SYSTEM = "view-system";
|
||||
|
||||
public static String MANAGE_REALM = "manage-realm";
|
||||
public static String MANAGE_USERS = "manage-users";
|
||||
|
||||
@ -291,7 +291,7 @@ public class AdminRoot {
|
||||
|
||||
Cors.builder().allowedOrigins(auth.getToken()).allowedMethods("GET", "PUT", "POST", "DELETE").auth().add();
|
||||
|
||||
return new ServerInfoAdminResource(session);
|
||||
return new ServerInfoAdminResource(session, auth);
|
||||
}
|
||||
|
||||
private HttpRequest getHttpRequest() {
|
||||
|
||||
@ -34,7 +34,9 @@ import org.keycloak.crypto.ClientSignatureVerifierProvider;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
import org.keycloak.models.AdminRoles;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.policy.PasswordPolicyProvider;
|
||||
import org.keycloak.policy.PasswordPolicyProviderFactory;
|
||||
@ -62,7 +64,10 @@ import org.keycloak.representations.info.ServerInfoRepresentation;
|
||||
import org.keycloak.representations.info.SpiInfoRepresentation;
|
||||
import org.keycloak.representations.info.SystemInfoRepresentation;
|
||||
import org.keycloak.representations.info.ThemeInfoRepresentation;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.resources.KeycloakOpenAPI;
|
||||
import org.keycloak.services.resources.admin.AdminAuth;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissions;
|
||||
import org.keycloak.theme.Theme;
|
||||
|
||||
import jakarta.ws.rs.GET;
|
||||
@ -92,9 +97,11 @@ public class ServerInfoAdminResource {
|
||||
private static final Map<String, List<String>> ENUMS = createEnumsMap(EventType.class, OperationType.class, ResourceType.class);
|
||||
|
||||
private final KeycloakSession session;
|
||||
private final AdminAuth auth;
|
||||
|
||||
public ServerInfoAdminResource(KeycloakSession session) {
|
||||
public ServerInfoAdminResource(KeycloakSession session, AdminAuth auth) {
|
||||
this.session = session;
|
||||
this.auth = auth;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -109,8 +116,13 @@ public class ServerInfoAdminResource {
|
||||
@Operation( summary = "Get themes, social providers, auth providers, and event listeners available on this server")
|
||||
public ServerInfoRepresentation getInfo() {
|
||||
ServerInfoRepresentation info = new ServerInfoRepresentation();
|
||||
info.setSystemInfo(SystemInfoRepresentation.create(session.getKeycloakSessionFactory().getServerStartupTimestamp(), Version.VERSION));
|
||||
info.setMemoryInfo(MemoryInfoRepresentation.create());
|
||||
RealmModel userRealm = session.getContext().getRealm();
|
||||
if (RealmManager.isAdministrationRealm(userRealm)
|
||||
|| AdminPermissions.evaluator(session, userRealm, auth).hasOneAdminRole(AdminRoles.VIEW_SYSTEM)) {
|
||||
// system information is only for admins in the administration realm or fallback view-system role
|
||||
info.setSystemInfo(SystemInfoRepresentation.create(session.getKeycloakSessionFactory().getServerStartupTimestamp(), Version.VERSION));
|
||||
info.setMemoryInfo(MemoryInfoRepresentation.create());
|
||||
}
|
||||
info.setProfileInfo(createProfileInfo());
|
||||
info.setFeatures(createFeatureRepresentations());
|
||||
|
||||
|
||||
@ -24,13 +24,15 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.Keycloak;
|
||||
import org.keycloak.admin.client.resource.AuthorizationResource;
|
||||
import org.keycloak.admin.client.resource.ClientResource;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.models.AdminRoles;
|
||||
import org.keycloak.models.CibaConfig;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.credential.OTPCredentialModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.representations.KeyStoreConfig;
|
||||
import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticationExecutionRepresentation;
|
||||
@ -58,11 +60,11 @@ import org.keycloak.representations.idm.authorization.ResourcePermissionRepresen
|
||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
|
||||
import org.keycloak.representations.info.ServerInfoRepresentation;
|
||||
import org.keycloak.services.resources.admin.AdminAuth.Resource;
|
||||
import org.keycloak.testsuite.AbstractKeycloakTest;
|
||||
import org.keycloak.testsuite.Assert;
|
||||
import org.keycloak.testsuite.ProfileAssume;
|
||||
import org.keycloak.testsuite.updaters.RealmAttributeUpdater;
|
||||
import org.keycloak.testsuite.util.AdminClientUtil;
|
||||
import org.keycloak.testsuite.util.ClientBuilder;
|
||||
import org.keycloak.testsuite.util.CredentialBuilder;
|
||||
@ -71,9 +73,9 @@ import org.keycloak.testsuite.util.GreenMailRule;
|
||||
import org.keycloak.testsuite.util.IdentityProviderBuilder;
|
||||
import org.keycloak.testsuite.util.RealmBuilder;
|
||||
import org.keycloak.testsuite.util.UserBuilder;
|
||||
import org.keycloak.userprofile.DeclarativeUserProfileProvider;
|
||||
|
||||
import jakarta.ws.rs.ClientErrorException;
|
||||
import jakarta.ws.rs.ForbiddenException;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
@ -93,7 +95,6 @@ import static org.keycloak.testsuite.util.ServerURLs.getAuthServerContextRoot;
|
||||
|
||||
import org.keycloak.testsuite.utils.tls.TLSUtils;
|
||||
import org.jgroups.util.UUID;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
@ -1893,6 +1894,46 @@ public class PermissionsTest extends AbstractKeycloakTest {
|
||||
}, clients.get("REALM2"), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerInfo() throws Exception {
|
||||
// user in master with no permission => forbidden
|
||||
Assert.assertThrows(ForbiddenException.class, () -> clients.get("master-none").serverInfo().getInfo());
|
||||
// user in master with any permission can see the system info
|
||||
ServerInfoRepresentation serverInfo = clients.get("master-view-realm").serverInfo().getInfo();
|
||||
Assert.assertNotNull(serverInfo.getSystemInfo());
|
||||
Assert.assertNotNull(serverInfo.getMemoryInfo());
|
||||
|
||||
// user in test realm with no permission => forbidden
|
||||
Assert.assertThrows(ForbiddenException.class, () -> clients.get("none").serverInfo().getInfo());
|
||||
// user in test realm with any permission cannot see the system info
|
||||
serverInfo = clients.get("view-realm").serverInfo().getInfo();
|
||||
Assert.assertNull(serverInfo.getSystemInfo());
|
||||
Assert.assertNull(serverInfo.getMemoryInfo());
|
||||
serverInfo = clients.get("manage-users").serverInfo().getInfo();
|
||||
Assert.assertNull(serverInfo.getSystemInfo());
|
||||
Assert.assertNull(serverInfo.getMemoryInfo());
|
||||
|
||||
// assign the view-system permission to a test realm user and check the fallback works
|
||||
ClientRepresentation realmMgtRep = adminClient.realm(REALM_NAME).clients().findByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID).get(0);
|
||||
ClientResource realmMgtRes = adminClient.realm(REALM_NAME).clients().get(realmMgtRep.getId());
|
||||
RoleRepresentation viewSystem = new RoleRepresentation();
|
||||
viewSystem.setName(AdminRoles.VIEW_SYSTEM);
|
||||
realmMgtRes.roles().create(viewSystem);
|
||||
viewSystem = realmMgtRes.roles().get(AdminRoles.VIEW_SYSTEM).toRepresentation();
|
||||
UserRepresentation userRep = adminClient.realm(REALM_NAME).users().search("view-realm", Boolean.TRUE).get(0);
|
||||
UserResource userRes = adminClient.realm(REALM_NAME).users().get(userRep.getId());
|
||||
userRes.roles().clientLevel(realmMgtRep.getId()).add(Collections.singletonList(viewSystem));
|
||||
try (Keycloak keycloak = Keycloak.getInstance(getAuthServerContextRoot() + "/auth", REALM_NAME,
|
||||
userRep.getUsername(), "password", "test-client", TLSUtils.initializeTLS())) {
|
||||
serverInfo = keycloak.serverInfo().getInfo();
|
||||
Assert.assertNotNull(serverInfo.getSystemInfo());
|
||||
Assert.assertNotNull(serverInfo.getMemoryInfo());
|
||||
} finally {
|
||||
userRes.roles().clientLevel(realmMgtRep.getId()).remove(Collections.singletonList(viewSystem));
|
||||
realmMgtRes.roles().get(AdminRoles.VIEW_SYSTEM).remove();
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyAnyAdminRoleReqired(Invocation invocation) {
|
||||
invoke(invocation, clients.get("view-realm"), true);
|
||||
invoke(invocation, clients.get("manage-realm"), true);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user