REALM_CLIENT attribute to recognize realm clients (#30433)
Closes #29413 Signed-off-by: Giuseppe Graziano <g.graziano94@gmail.com>
This commit is contained in:
parent
acf79b81c7
commit
24aa6e143d
4 changed files with 37 additions and 6 deletions
|
@ -4,7 +4,8 @@ import type { TFunction } from "i18next";
|
||||||
/**
|
/**
|
||||||
* Checks if a client is intended to be used for authenticating a to a realm.
|
* Checks if a client is intended to be used for authenticating a to a realm.
|
||||||
*/
|
*/
|
||||||
export const isRealmClient = (client: ClientRepresentation) => !client.protocol;
|
export const isRealmClient = (client: ClientRepresentation): boolean =>
|
||||||
|
client.attributes?.["realm_client"] === true.toString();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a human readable name for the specified protocol.
|
* Gets a human readable name for the specified protocol.
|
||||||
|
|
|
@ -181,4 +181,7 @@ public final class Constants {
|
||||||
|
|
||||||
// attribute name used in apps to mark that it is an admin console and its azp is allowed
|
// attribute name used in apps to mark that it is an admin console and its azp is allowed
|
||||||
public static final String SECURITY_ADMIN_CONSOLE_ATTR = "security.admin.console";
|
public static final String SECURITY_ADMIN_CONSOLE_ATTR = "security.admin.console";
|
||||||
|
|
||||||
|
//attribute name used to mark a client as realm client
|
||||||
|
public static final String REALM_CLIENT = "realm_client";
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import static java.util.Optional.ofNullable;
|
||||||
import static org.keycloak.models.utils.StripSecretsUtils.stripSecrets;
|
import static org.keycloak.models.utils.StripSecretsUtils.stripSecrets;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.Config;
|
||||||
import org.keycloak.authentication.otp.OTPApplicationProvider;
|
import org.keycloak.authentication.otp.OTPApplicationProvider;
|
||||||
import org.keycloak.authorization.AuthorizationProvider;
|
import org.keycloak.authorization.AuthorizationProvider;
|
||||||
import org.keycloak.authorization.AuthorizationProviderFactory;
|
import org.keycloak.authorization.AuthorizationProviderFactory;
|
||||||
|
@ -737,6 +738,8 @@ public class ModelToRepresentation {
|
||||||
rep.setNodeReRegistrationTimeout(clientModel.getNodeReRegistrationTimeout());
|
rep.setNodeReRegistrationTimeout(clientModel.getNodeReRegistrationTimeout());
|
||||||
rep.setClientAuthenticatorType(clientModel.getClientAuthenticatorType());
|
rep.setClientAuthenticatorType(clientModel.getClientAuthenticatorType());
|
||||||
|
|
||||||
|
rep.getAttributes().put(Constants.REALM_CLIENT, String.valueOf(isRealmClient(clientModel.getClientId(), clientModel.getRealm(), session)));
|
||||||
|
|
||||||
// adding the secret if non public or bearer only
|
// adding the secret if non public or bearer only
|
||||||
if (clientModel.isBearerOnly() || clientModel.isPublicClient()) {
|
if (clientModel.isBearerOnly() || clientModel.isPublicClient()) {
|
||||||
rep.setSecret(null);
|
rep.setSecret(null);
|
||||||
|
@ -778,6 +781,23 @@ public class ModelToRepresentation {
|
||||||
return rep;
|
return rep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isRealmClient(String clientId, RealmModel realm, KeycloakSession session) {
|
||||||
|
final String realmClientSuffix = "-realm";
|
||||||
|
|
||||||
|
if (clientId == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Constants.BROKER_SERVICE_CLIENT_ID.equals(clientId)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (Config.getAdminRealm().equals(realm.getName())) {
|
||||||
|
return clientId.endsWith(realmClientSuffix) && session.realms().getRealmByName(clientId.substring(0, clientId.length() - realmClientSuffix.length())) != null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Constants.REALM_MANAGEMENT_CLIENT_ID.equals(clientId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static IdentityProviderRepresentation toBriefRepresentation(RealmModel realm, IdentityProviderModel identityProviderModel) {
|
public static IdentityProviderRepresentation toBriefRepresentation(RealmModel realm, IdentityProviderModel identityProviderModel) {
|
||||||
IdentityProviderRepresentation providerRep = new IdentityProviderRepresentation();
|
IdentityProviderRepresentation providerRep = new IdentityProviderRepresentation();
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,13 @@ public class ClientTest extends AbstractAdminTest {
|
||||||
Assert.assertNames(realm.clients().findAll(), "account", "account-console", "realm-management", "security-admin-console", "broker", Constants.ADMIN_CLI_CLIENT_ID);
|
Assert.assertNames(realm.clients().findAll(), "account", "account-console", "realm-management", "security-admin-console", "broker", Constants.ADMIN_CLI_CLIENT_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getRealmClients() {
|
||||||
|
assertTrue(realm.clients().findAll().stream().filter(client-> client.getAttributes().get(Constants.REALM_CLIENT).equals("true"))
|
||||||
|
.map(ClientRepresentation::getClientId)
|
||||||
|
.allMatch(clientId -> clientId.equals(Constants.REALM_MANAGEMENT_CLIENT_ID) || clientId.equals(Constants.BROKER_SERVICE_CLIENT_ID) || clientId.endsWith("-realm")));
|
||||||
|
}
|
||||||
|
|
||||||
private ClientRepresentation createClient() {
|
private ClientRepresentation createClient() {
|
||||||
return createClient(null);
|
return createClient(null);
|
||||||
}
|
}
|
||||||
|
@ -122,7 +129,7 @@ public class ClientTest extends AbstractAdminTest {
|
||||||
|
|
||||||
return rep;
|
return rep;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClientRepresentation createClientNonPublic() {
|
private ClientRepresentation createClientNonPublic() {
|
||||||
ClientRepresentation rep = new ClientRepresentation();
|
ClientRepresentation rep = new ClientRepresentation();
|
||||||
rep.setClientId("my-app");
|
rep.setClientId("my-app");
|
||||||
|
@ -142,7 +149,7 @@ public class ClientTest extends AbstractAdminTest {
|
||||||
|
|
||||||
return rep;
|
return rep;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createClientVerifyWithSecret() {
|
public void createClientVerifyWithSecret() {
|
||||||
String id = createClientNonPublic().getId();
|
String id = createClientNonPublic().getId();
|
||||||
|
@ -442,14 +449,14 @@ public class ClientTest extends AbstractAdminTest {
|
||||||
|
|
||||||
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.roleResourceCompositesPath(Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + REALM_NAME), Collections.singletonList(role), ResourceType.REALM_ROLE);
|
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.roleResourceCompositesPath(Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + REALM_NAME), Collections.singletonList(role), ResourceType.REALM_ROLE);
|
||||||
|
|
||||||
assertThat(realm.roles().get(Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + REALM_NAME).getRoleComposites().stream().map(RoleRepresentation::getName).collect(Collectors.toSet()),
|
assertThat(realm.roles().get(Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + REALM_NAME).getRoleComposites().stream().map(RoleRepresentation::getName).collect(Collectors.toSet()),
|
||||||
hasItem(role.getName()));
|
hasItem(role.getName()));
|
||||||
|
|
||||||
realm.clients().get(id).roles().deleteRole("test");
|
realm.clients().get(id).roles().deleteRole("test");
|
||||||
|
|
||||||
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientRoleResourcePath(id, "test"), ResourceType.CLIENT_ROLE);
|
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientRoleResourcePath(id, "test"), ResourceType.CLIENT_ROLE);
|
||||||
|
|
||||||
assertThat(realm.roles().get(Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + REALM_NAME).getRoleComposites().stream().map(RoleRepresentation::getName).collect(Collectors.toSet()),
|
assertThat(realm.roles().get(Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + REALM_NAME).getRoleComposites().stream().map(RoleRepresentation::getName).collect(Collectors.toSet()),
|
||||||
not(hasItem(role)));
|
not(hasItem(role)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,7 +565,7 @@ public class ClientTest extends AbstractAdminTest {
|
||||||
|
|
||||||
realm.clients().get(id).registerNode(Collections.singletonMap("node", "foo#"));
|
realm.clients().get(id).registerNode(Collections.singletonMap("node", "foo#"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void nodes() {
|
public void nodes() {
|
||||||
testingClient.testApp().clearAdminActions();
|
testingClient.testApp().clearAdminActions();
|
||||||
|
|
Loading…
Reference in a new issue