diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java index ce9bf4c6e0..80318b567b 100644 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java @@ -78,6 +78,7 @@ import org.keycloak.models.jpa.entities.RealmEntity; import org.keycloak.models.jpa.entities.RealmLocalizationTextsEntity; import org.keycloak.models.jpa.entities.RoleEntity; import org.keycloak.models.utils.KeycloakModelUtils; +import org.keycloak.organization.utils.Organizations; import org.keycloak.protocol.oidc.OIDCLoginProtocol; @@ -190,7 +191,7 @@ public class JpaRealmProvider implements RealmProvider, ClientProvider, ClientSc session.clientScopes().removeClientScopes(adapter); session.roles().removeRoles(adapter); - session.groups().getTopLevelGroupsStream(adapter).forEach(adapter::removeGroup); + session.groups().getTopLevelGroupsStream(adapter).forEach(Organizations.removeGroup(session, adapter)); num = em.createNamedQuery("removeClientInitialAccessByRealm") .setParameter("realm", realm).executeUpdate(); diff --git a/model/jpa/src/main/java/org/keycloak/organization/jpa/JpaOrganizationProvider.java b/model/jpa/src/main/java/org/keycloak/organization/jpa/JpaOrganizationProvider.java index 43c16d6cf3..438846add9 100644 --- a/model/jpa/src/main/java/org/keycloak/organization/jpa/JpaOrganizationProvider.java +++ b/model/jpa/src/main/java/org/keycloak/organization/jpa/JpaOrganizationProvider.java @@ -113,14 +113,21 @@ public class JpaOrganizationProvider implements OrganizationProvider { try { session.setAttribute(OrganizationModel.class.getName(), organization); - GroupModel group = getOrganizationGroup(entity); + RealmModel realm = session.realms().getRealm(this.realm.getId()); + + // check if the realm is being removed so that we don't need to remove manually remove any other data but the org + if (realm != null) { + GroupModel group = getOrganizationGroup(entity); + + if (group != null) { + //TODO: won't scale, requires a better mechanism for bulk deleting users + userProvider.getGroupMembersStream(this.realm, group).forEach(userModel -> removeMember(organization, userModel)); + groupProvider.removeGroup(this.realm, group); + } - if (group != null) { - //TODO: won't scale, requires a better mechanism for bulk deleting users - userProvider.getGroupMembersStream(realm, group).forEach(userModel -> removeMember(organization, userModel)); - groupProvider.removeGroup(realm, group); organization.getIdentityProviders().forEach((model) -> removeIdentityProvider(organization, model)); } + em.remove(entity); } finally { session.removeAttribute(OrganizationModel.class.getName()); diff --git a/services/src/main/java/org/keycloak/organization/utils/Organizations.java b/services/src/main/java/org/keycloak/organization/utils/Organizations.java index dce6a652c7..3aefd260cf 100644 --- a/services/src/main/java/org/keycloak/organization/utils/Organizations.java +++ b/services/src/main/java/org/keycloak/organization/utils/Organizations.java @@ -19,6 +19,7 @@ package org.keycloak.organization.utils; import java.util.List; import java.util.Objects; +import java.util.function.Consumer; import org.keycloak.common.Profile; import org.keycloak.common.Profile.Feature; @@ -85,4 +86,32 @@ public class Organizations { return null; } + + public static Consumer removeGroup(KeycloakSession session, RealmModel realm) { + return group -> { + if (!Profile.isFeatureEnabled(Feature.ORGANIZATION)) { + realm.removeGroup(group); + return; + } + + OrganizationModel current = (OrganizationModel) session.getAttribute(OrganizationModel.class.getName()); + + try { + String orgId = group.getFirstAttribute(OrganizationModel.ORGANIZATION_ATTRIBUTE); + OrganizationProvider provider = session.getProvider(OrganizationProvider.class); + + if (orgId != null) { + session.setAttribute(OrganizationModel.class.getName(), provider.getById(orgId)); + } + + realm.removeGroup(group); + } finally { + if (current == null) { + session.removeAttribute(OrganizationModel.class.getName()); + } else { + session.setAttribute(OrganizationModel.class.getName(), current); + } + } + }; + } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/admin/OrganizationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/admin/OrganizationTest.java index 4920e0f41d..26a5ca2a76 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/admin/OrganizationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/admin/OrganizationTest.java @@ -43,10 +43,15 @@ import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response.Status; import org.junit.Test; import org.keycloak.admin.client.resource.OrganizationResource; +import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.common.Profile.Feature; +import org.keycloak.models.utils.KeycloakModelUtils; +import org.keycloak.representations.idm.IdentityProviderRepresentation; import org.keycloak.representations.idm.OrganizationDomainRepresentation; import org.keycloak.representations.idm.OrganizationRepresentation; +import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.testsuite.arquillian.annotation.EnableFeature; +import org.keycloak.testsuite.util.RealmBuilder; @EnableFeature(Feature.ORGANIZATION) public class OrganizationTest extends AbstractOrganizationTest { @@ -367,4 +372,36 @@ public class OrganizationTest extends AbstractOrganizationTest { assertEquals(1, existing.getDomains().size()); assertNotNull(existing.getDomain("acme.com")); } + + @Test + public void testDeleteRealm() { + RealmRepresentation realmRep = RealmBuilder.create().name(KeycloakModelUtils.generateId()).build(); + RealmResource realm = realmsResouce().realm(realmRep.getRealm()); + + try { + realmRep.setEnabled(true); + realmsResouce().create(realmRep); + realm = realmsResouce().realm(realmRep.getRealm()); + realm.toRepresentation(); + OrganizationRepresentation org = new OrganizationRepresentation(); + org.setName("test-org"); + org.addDomain(new OrganizationDomainRepresentation("test.org")); + org.setEnabled(true); + Response response = realm.organizations().create(org); + response.close(); + assertEquals(Status.CREATED.getStatusCode(), response.getStatus()); + List orgs = realm.organizations().getAll(); + assertEquals(1, orgs.size()); + IdentityProviderRepresentation broker = bc.setUpIdentityProvider(); + broker.setAlias(KeycloakModelUtils.generateId()); + response = realm.identityProviders().create(broker); + response.close(); + assertEquals(Status.CREATED.getStatusCode(), response.getStatus()); + response = realm.organizations().get(orgs.get(0).getId()).identityProviders().addIdentityProvider(broker.getAlias()); + response.close(); + assertEquals(Status.NO_CONTENT.getStatusCode(), response.getStatus()); + } finally { + realm.remove(); + } + } }