Ensure that IDP's linked domains are remove when org is deleted or when the domain is removed from the org.
Closes #29481 Signed-off-by: Stefan Guilhen <sguilhen@redhat.com>
This commit is contained in:
parent
1d613d9037
commit
c4760b8188
4 changed files with 41 additions and 2 deletions
|
@ -17,7 +17,9 @@
|
||||||
|
|
||||||
package org.keycloak.organization.jpa;
|
package org.keycloak.organization.jpa;
|
||||||
|
|
||||||
|
import static org.keycloak.models.OrganizationModel.BROKER_PUBLIC;
|
||||||
import static org.keycloak.models.OrganizationModel.ORGANIZATION_ATTRIBUTE;
|
import static org.keycloak.models.OrganizationModel.ORGANIZATION_ATTRIBUTE;
|
||||||
|
import static org.keycloak.models.OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE;
|
||||||
import static org.keycloak.models.jpa.PaginationUtils.paginateQuery;
|
import static org.keycloak.models.jpa.PaginationUtils.paginateQuery;
|
||||||
import static org.keycloak.utils.StreamsUtil.closing;
|
import static org.keycloak.utils.StreamsUtil.closing;
|
||||||
|
|
||||||
|
@ -327,7 +329,10 @@ public class JpaOrganizationProvider implements OrganizationProvider {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clear the organization id and any domain assigned to the IDP.
|
||||||
identityProvider.setOrganizationId(null);
|
identityProvider.setOrganizationId(null);
|
||||||
|
identityProvider.getConfig().remove(ORGANIZATION_DOMAIN_ATTRIBUTE);
|
||||||
|
identityProvider.getConfig().remove(BROKER_PUBLIC);
|
||||||
realm.updateIdentityProvider(identityProvider);
|
realm.updateIdentityProvider(identityProvider);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -136,6 +136,8 @@ public final class OrganizationAdapter implements OrganizationModel, JpaModel<Or
|
||||||
throw new ModelValidationException("You must provide at least one domain");
|
throw new ModelValidationException("You must provide at least one domain");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<IdentityProviderModel> idps = this.getIdentityProviders().toList();
|
||||||
|
|
||||||
Map<String, OrganizationDomainModel> modelMap = domains.stream()
|
Map<String, OrganizationDomainModel> modelMap = domains.stream()
|
||||||
.map(this::validateDomain)
|
.map(this::validateDomain)
|
||||||
.collect(Collectors.toMap(OrganizationDomainModel::getName, Function.identity()));
|
.collect(Collectors.toMap(OrganizationDomainModel::getName, Function.identity()));
|
||||||
|
@ -149,6 +151,12 @@ public final class OrganizationAdapter implements OrganizationModel, JpaModel<Or
|
||||||
// remove domain that is not found in the new set.
|
// remove domain that is not found in the new set.
|
||||||
else {
|
else {
|
||||||
this.entity.removeDomain(domainEntity);
|
this.entity.removeDomain(domainEntity);
|
||||||
|
// check if any idp is assigned to the removed domain, and unset the domain if that's the case.
|
||||||
|
idps.forEach(idp -> {
|
||||||
|
if (Objects.equals(domainEntity.getName(), idp.getConfig().get(ORGANIZATION_DOMAIN_ATTRIBUTE))) {
|
||||||
|
idp.getConfig().remove(ORGANIZATION_DOMAIN_ATTRIBUTE);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,6 @@ import jakarta.ws.rs.core.Response.Status;
|
||||||
import org.jboss.arquillian.graphene.page.Page;
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
import org.keycloak.admin.client.resource.OrganizationResource;
|
import org.keycloak.admin.client.resource.OrganizationResource;
|
||||||
import org.keycloak.models.OrganizationModel;
|
import org.keycloak.models.OrganizationModel;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
|
||||||
import org.keycloak.admin.client.resource.UsersResource;
|
import org.keycloak.admin.client.resource.UsersResource;
|
||||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||||
import org.keycloak.admin.client.resource.RealmResource;
|
import org.keycloak.admin.client.resource.RealmResource;
|
||||||
|
|
|
@ -20,6 +20,10 @@ package org.keycloak.testsuite.organization.admin;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
|
import static org.keycloak.models.OrganizationModel.BROKER_PUBLIC;
|
||||||
|
import static org.keycloak.models.OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE;
|
||||||
|
|
||||||
import jakarta.ws.rs.BadRequestException;
|
import jakarta.ws.rs.BadRequestException;
|
||||||
import jakarta.ws.rs.NotFoundException;
|
import jakarta.ws.rs.NotFoundException;
|
||||||
|
@ -156,6 +160,8 @@ public class OrganizationIdentityProviderTest extends AbstractOrganizationTest {
|
||||||
IdentityProviderRepresentation idpRep = testRealm().identityProviders().get(bc.getIDPAlias()).toRepresentation();
|
IdentityProviderRepresentation idpRep = testRealm().identityProviders().get(bc.getIDPAlias()).toRepresentation();
|
||||||
// broker no longer linked to the org
|
// broker no longer linked to the org
|
||||||
Assert.assertNull(idpRep.getConfig().get(OrganizationModel.ORGANIZATION_ATTRIBUTE));
|
Assert.assertNull(idpRep.getConfig().get(OrganizationModel.ORGANIZATION_ATTRIBUTE));
|
||||||
|
Assert.assertNull(idpRep.getConfig().get(ORGANIZATION_DOMAIN_ATTRIBUTE));
|
||||||
|
Assert.assertNull(idpRep.getConfig().get(BROKER_PUBLIC));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -183,7 +189,7 @@ public class OrganizationIdentityProviderTest extends AbstractOrganizationTest {
|
||||||
OrganizationResource orgResource = testRealm().organizations().get(orgRep.getId());
|
OrganizationResource orgResource = testRealm().organizations().get(orgRep.getId());
|
||||||
OrganizationIdentityProviderResource orgIdPResource = orgResource.identityProviders().get(bc.getIDPAlias());
|
OrganizationIdentityProviderResource orgIdPResource = orgResource.identityProviders().get(bc.getIDPAlias());
|
||||||
IdentityProviderRepresentation idpRep = orgIdPResource.toRepresentation();
|
IdentityProviderRepresentation idpRep = orgIdPResource.toRepresentation();
|
||||||
idpRep.getConfig().put(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE, "unknown.org");
|
idpRep.getConfig().put(ORGANIZATION_DOMAIN_ATTRIBUTE, "unknown.org");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
testRealm().identityProviders().get(idpRep.getAlias()).update(idpRep);
|
testRealm().identityProviders().get(idpRep.getAlias()).update(idpRep);
|
||||||
|
@ -220,6 +226,27 @@ public class OrganizationIdentityProviderTest extends AbstractOrganizationTest {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemovedDomainUpdatedInIDP() {
|
||||||
|
OrganizationRepresentation orgRep = createOrganization("testorg", "testorg.com", "testorg.net");
|
||||||
|
OrganizationResource orgResource = testRealm().organizations().get(orgRep.getId());
|
||||||
|
OrganizationIdentityProviderResource orgIdPResource = orgResource.identityProviders().get("testorg-identity-provider");
|
||||||
|
IdentityProviderRepresentation idpRep = orgIdPResource.toRepresentation();
|
||||||
|
|
||||||
|
// IDP should have been assigned to the first domain.
|
||||||
|
assertThat(idpRep.getConfig().get(ORGANIZATION_DOMAIN_ATTRIBUTE), is(equalTo("testorg.com")));
|
||||||
|
|
||||||
|
// let's update the organization, removing the domain linked to the IDP.
|
||||||
|
orgRep.removeDomain(orgRep.getDomain("testorg.com"));
|
||||||
|
try (Response response = orgResource.update(orgRep)) {
|
||||||
|
assertThat(response.getStatus(), is(equalTo(Status.NO_CONTENT.getStatusCode())));
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch the idp config and check if the domain has been unlinked.
|
||||||
|
idpRep = orgIdPResource.toRepresentation();
|
||||||
|
assertThat(idpRep.getConfig().get(ORGANIZATION_DOMAIN_ATTRIBUTE), is(nullValue()));
|
||||||
|
}
|
||||||
|
|
||||||
private IdentityProviderRepresentation createRep(String alias, String providerId) {
|
private IdentityProviderRepresentation createRep(String alias, String providerId) {
|
||||||
IdentityProviderRepresentation idp = new IdentityProviderRepresentation();
|
IdentityProviderRepresentation idp = new IdentityProviderRepresentation();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue