Fixing incorrectly cached role after update/rename

Closes #37320

Signed-off-by: Giorgos Malliaris <georgemalliaris8@gmail.com>
Signed-off-by: Alexander Schwartz <aschwart@redhat.com>
Co-authored-by: Alexander Schwartz <aschwart@redhat.com>
This commit is contained in:
GMalliaris
2025-03-10 13:32:37 +02:00
committed by GitHub
parent 56226d8699
commit c9d848cd90
2 changed files with 71 additions and 3 deletions

View File

@@ -28,9 +28,9 @@ import org.keycloak.models.utils.KeycloakModelUtils;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
@@ -61,6 +61,15 @@ public class RoleAdapter implements RoleModel {
}
}
protected void getDelegateForRename(String newName) {
if (!Objects.equals(newName, cached.getName())) {
// New role name might have been cached as non-existent
String containerId = getContainerId();
cacheSession.registerRoleInvalidation(cached.getId(), newName, containerId);
}
getDelegateForUpdate();
}
protected boolean invalidated;
public void invalidate() {
@@ -102,7 +111,7 @@ public class RoleAdapter implements RoleModel {
@Override
public void setName(String name) {
getDelegateForUpdate();
getDelegateForRename(name);
updated.setName(name);
}

View File

@@ -32,11 +32,13 @@ import org.keycloak.testsuite.util.RoleBuilder;
import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -47,6 +49,7 @@ import static org.hamcrest.Matchers.empty;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -135,6 +138,7 @@ public class RoleByIdResourceTest extends AbstractAdminTest {
resource.getRole(ids.get("role-a"));
fail("Expected 404");
} catch (NotFoundException e) {
// Ignore
}
}
@@ -276,8 +280,63 @@ public class RoleByIdResourceTest extends AbstractAdminTest {
}
}
@Test (expected = BadRequestException.class)
@Test(expected = BadRequestException.class)
public void deleteDefaultRole() {
resource.deleteRole(adminClient.realm(REALM_NAME).roles().get(Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + REALM_NAME).toRepresentation().getId());
}
/**
* see #37320
*/
@Test
public void renameRoleToNamePreviouslyCached() {
String roleName = "realm-role-new-" + new Random().nextInt();
RoleRepresentation newRoleRepresentation = RoleBuilder.create()
.name(roleName)
.build();
adminClient.realm(REALM_NAME).roles().create(newRoleRepresentation);
RoleRepresentation roleRepresentation = adminClient.realm(REALM_NAME).roles().get(roleName).toRepresentation();
getCleanup().addRoleId(roleRepresentation.getId());
String newRoleName = "realm-role-renamed-" + new Random().nextInt();
cacheMissingRoleName(newRoleName);
RoleRepresentation updatedRoleRepresentation = RoleBuilder.create()
.id(roleRepresentation.getId())
.name(newRoleName)
.build();
resource.updateRole(roleRepresentation.getId(), updatedRoleRepresentation);
try {
adminClient.realm(REALM_NAME).roles().get(newRoleName).toRepresentation();
} catch (NotFoundException e) {
fail("Role is incorrectly cached");
}
}
/**
* see #37320
*/
@Test
public void createRolePreviouslyCached() {
String roleName = "realm-role-new-" + new Random().nextInt();
RoleRepresentation roleRepresentation = RoleBuilder.create()
.name(roleName)
.build();
cacheMissingRoleName(roleName);
adminClient.realm(REALM_NAME).roles().create(roleRepresentation);
try {
roleRepresentation = adminClient.realm(REALM_NAME).roles().get(roleName).toRepresentation();
getCleanup().addRoleId(roleRepresentation.getId());
} catch (NotFoundException e) {
fail("Role is incorrectly cached");
}
}
private void cacheMissingRoleName(String missingRoleName) {
assertThrows(NotFoundException.class, () -> adminClient.realm(REALM_NAME).roles().get(missingRoleName).toRepresentation());
}
}