Client Scope updates are not replicated between Keycloak nodes
Fixes #33731 Signed-off-by: Pedro Ruivo <pruivo@redhat.com>
This commit is contained in:
parent
e41553bcfb
commit
84f4bd8af1
2 changed files with 108 additions and 0 deletions
|
@ -264,6 +264,7 @@ public class RealmCacheSession implements CacheRealmProvider {
|
||||||
public void registerClientScopeInvalidation(String id, String realmId) {
|
public void registerClientScopeInvalidation(String id, String realmId) {
|
||||||
invalidateClientScope(id);
|
invalidateClientScope(id);
|
||||||
cache.clientScopeUpdated(realmId, invalidations);
|
cache.clientScopeUpdated(realmId, invalidations);
|
||||||
|
invalidationEvents.add(new CacheKeyInvalidatedEvent(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void invalidateClientScope(String id) {
|
private void invalidateClientScope(String id) {
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 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.testsuite.cluster;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import jakarta.ws.rs.NotFoundException;
|
||||||
|
import org.keycloak.admin.client.resource.ClientScopeResource;
|
||||||
|
import org.keycloak.admin.client.resource.ClientScopesResource;
|
||||||
|
import org.keycloak.representations.idm.ClientScopeRepresentation;
|
||||||
|
import org.keycloak.testsuite.admin.ApiUtil;
|
||||||
|
import org.keycloak.testsuite.arquillian.ContainerInfo;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
public class ClientScopeInvalidationClusterTest extends AbstractInvalidationClusterTestWithTestRealm<ClientScopeRepresentation, ClientScopeResource> {
|
||||||
|
@Override
|
||||||
|
protected ClientScopeRepresentation createTestEntityRepresentation() {
|
||||||
|
var clientScope = new ClientScopeRepresentation();
|
||||||
|
clientScope.setName("client-scope-name");
|
||||||
|
clientScope.setDescription("client-scope-description");
|
||||||
|
clientScope.setProtocol("openid-connect");
|
||||||
|
clientScope.setAttributes(Map.of("a", "b", "c", "d"));
|
||||||
|
return clientScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ClientScopeResource entityResource(ClientScopeRepresentation testEntity, ContainerInfo node) {
|
||||||
|
return entityResource(testEntity.getId(), node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ClientScopeResource entityResource(String idOrName, ContainerInfo node) {
|
||||||
|
return clientScopes(node).get(idOrName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ClientScopeRepresentation createEntity(ClientScopeRepresentation testEntity, ContainerInfo node) {
|
||||||
|
try (var rsp = clientScopes(node).create(testEntity)) {
|
||||||
|
testEntity.setId(ApiUtil.getCreatedId(rsp));
|
||||||
|
}
|
||||||
|
return readEntity(testEntity, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ClientScopeRepresentation readEntity(ClientScopeRepresentation entity, ContainerInfo node) {
|
||||||
|
try {
|
||||||
|
return entityResource(entity, node).toRepresentation();
|
||||||
|
} catch (NotFoundException nfe) {
|
||||||
|
// expected when client scope doesn't exist
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ClientScopeRepresentation updateEntity(ClientScopeRepresentation entity, ContainerInfo node) {
|
||||||
|
entityResource(entity, node).update(entity);
|
||||||
|
return readEntity(entity, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deleteEntity(ClientScopeRepresentation testEntity, ContainerInfo node) {
|
||||||
|
entityResource(testEntity, node).remove();
|
||||||
|
assertNull(readEntity(testEntity, node));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ClientScopeRepresentation testEntityUpdates(ClientScopeRepresentation testEntity, boolean backendFailover) {
|
||||||
|
// groupname
|
||||||
|
testEntity.setName("name-updated");
|
||||||
|
testEntity = updateEntityOnCurrentFailNode(testEntity, "name");
|
||||||
|
verifyEntityUpdateDuringFailover(testEntity, backendFailover);
|
||||||
|
|
||||||
|
testEntity.setProtocol("protocol-updated");
|
||||||
|
testEntity = updateEntityOnCurrentFailNode(testEntity, "protocol");
|
||||||
|
verifyEntityUpdateDuringFailover(testEntity, backendFailover);
|
||||||
|
|
||||||
|
testEntity.setDescription("description-updated");
|
||||||
|
testEntity = updateEntityOnCurrentFailNode(testEntity, "description");
|
||||||
|
verifyEntityUpdateDuringFailover(testEntity, backendFailover);
|
||||||
|
|
||||||
|
testEntity.setAttributes(Map.of("updated", "updated"));
|
||||||
|
testEntity = updateEntityOnCurrentFailNode(testEntity, "attributes");
|
||||||
|
verifyEntityUpdateDuringFailover(testEntity, backendFailover);
|
||||||
|
|
||||||
|
return testEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClientScopesResource clientScopes(ContainerInfo node) {
|
||||||
|
return getAdminClientFor(node).realm(testRealmName).clientScopes();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue