Add ability to set one or more internet domain to an organization.

Closed #28274

Signed-off-by: Stefan Guilhen <sguilhen@redhat.com>
This commit is contained in:
Stefan Guilhen 2024-04-10 08:51:36 -03:00 committed by Pedro Igor
parent adc8d388dc
commit 9a466f90ab
15 changed files with 498 additions and 16 deletions

View file

@ -0,0 +1,63 @@
/*
* 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.representations.idm;
/**
* Representation implementation of an organization internet domain.
*
* @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a>
*/
public class OrganizationDomainRepresentation {
private String name;
private Boolean verified;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Boolean isVerified() {
return this.verified;
}
public void setVerified(Boolean verified) {
this.verified = verified;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
if (!(o instanceof OrganizationDomainRepresentation)) return false;
OrganizationDomainRepresentation that = (OrganizationDomainRepresentation) o;
return name != null && name.equals(that.getName());
}
@Override
public int hashCode() {
if (name == null) {
return super.hashCode();
}
return name.hashCode();
}
}

View file

@ -21,12 +21,15 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.HashSet;
import java.util.Set;
public class OrganizationRepresentation {
private String id;
private String name;
private Map<String, List<String>> attributes = new HashMap<>();
private Set<OrganizationDomainRepresentation> domains = new HashSet<>();
public String getId() {
return id;
@ -58,6 +61,18 @@ public class OrganizationRepresentation {
return this;
}
public Set<OrganizationDomainRepresentation> getDomains() {
return this.domains;
}
public void addDomain(OrganizationDomainRepresentation domain) {
this.domains.add(domain);
}
public void removeDomain(OrganizationDomainRepresentation domain) {
this.domains.remove(domain);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;

View file

@ -25,6 +25,7 @@ import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.keycloak.representations.idm.OrganizationRepresentation;
@ -40,5 +41,7 @@ public interface OrganizationsResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
List<OrganizationRepresentation> getAll();
List<OrganizationRepresentation> getAll(
@QueryParam("domain-name") String domainName
);
}

View file

@ -0,0 +1,95 @@
/*
* 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.models.jpa.entities;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.NamedQueries;
import jakarta.persistence.NamedQuery;
import jakarta.persistence.Table;
/**
* JPA entity representing an internet domain that can be associated with an organization.
*
* @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a>
*/
@Entity
@Table(name="ORG_DOMAIN")
@NamedQueries({
@NamedQuery(name="getByName", query="select o from OrganizationDomainEntity o where o.name = :name")
})
public class OrganizationDomainEntity {
@Id
@Column(name="NAME")
protected String name;
@Column(name="VERIFIED")
protected Boolean verified;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ORG_ID")
private OrganizationEntity organization;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Boolean isVerified() {
return this.verified;
}
public void setVerified(Boolean verified) {
this.verified = verified;
}
public OrganizationEntity getOrganization() {
return this.organization;
}
public void setOrganization(OrganizationEntity organization) {
this.organization = organization;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
if (!(o instanceof OrganizationDomainEntity)) return false;
OrganizationDomainEntity that = (OrganizationDomainEntity) o;
return name != null && name.equals(that.getName());
}
@Override
public int hashCode() {
if (name == null) {
return super.hashCode();
}
return name.hashCode();
}
}

View file

@ -17,14 +17,23 @@
package org.keycloak.models.jpa.entities;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.NamedQueries;
import jakarta.persistence.NamedQuery;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import org.hibernate.annotations.BatchSize;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
@Table(name="ORG")
@Entity
@ -50,6 +59,11 @@ public class OrganizationEntity {
@Column(name = "IPD_ALIAS")
private String idpAlias;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy="organization")
@Fetch(FetchMode.SELECT)
@BatchSize(size = 20)
protected Set<OrganizationDomainEntity> domains = new HashSet<>();
public String getId() {
return id;
}
@ -90,6 +104,21 @@ public class OrganizationEntity {
this.idpAlias = idpAlias;
}
public Collection<OrganizationDomainEntity> getDomains() {
if (this.domains == null) {
this.domains = new HashSet<>();
}
return this.domains;
}
public void addDomain(OrganizationDomainEntity domainEntity) {
this.domains.add(domainEntity);
}
public void removeDomain(OrganizationDomainEntity domainEntity) {
this.domains.remove(domainEntity);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;

View file

@ -23,6 +23,7 @@ import static org.keycloak.utils.StreamsUtil.closing;
import java.util.stream.Stream;
import jakarta.persistence.EntityManager;
import jakarta.persistence.NoResultException;
import jakarta.persistence.TypedQuery;
import org.keycloak.connections.jpa.JpaConnectionProvider;
import org.keycloak.models.GroupModel;
@ -35,6 +36,7 @@ import org.keycloak.models.OrganizationModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserProvider;
import org.keycloak.models.jpa.entities.OrganizationDomainEntity;
import org.keycloak.models.jpa.entities.OrganizationEntity;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.organization.OrganizationProvider;
@ -122,6 +124,18 @@ public class JpaOrganizationProvider implements OrganizationProvider {
return entity == null ? null : new OrganizationAdapter(realm, entity);
}
@Override
public OrganizationModel getByDomainName(String domain) {
TypedQuery<OrganizationDomainEntity> query = em.createNamedQuery("getByName", OrganizationDomainEntity.class);
query.setParameter("name", domain.toLowerCase());
try {
OrganizationDomainEntity entity = query.getSingleResult();
return new OrganizationAdapter(realm, entity.getOrganization());
} catch (NoResultException nre) {
return null;
}
}
@Override
public Stream<OrganizationModel> getAllStream() {
TypedQuery<OrganizationEntity> query = em.createNamedQuery("getByRealm", OrganizationEntity.class);

View file

@ -18,14 +18,20 @@
package org.keycloak.organization.jpa;
import org.keycloak.models.GroupModel;
import java.util.Collection;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.keycloak.models.OrganizationDomainModel;
import org.keycloak.models.OrganizationModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.jpa.JpaModel;
import org.keycloak.models.jpa.entities.OrganizationDomainEntity;
import org.keycloak.models.jpa.entities.OrganizationEntity;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
public final class OrganizationAdapter implements OrganizationModel, JpaModel<OrganizationEntity> {
@ -91,6 +97,37 @@ public final class OrganizationAdapter implements OrganizationModel, JpaModel<Or
return getGroup().getAttributes();
}
@Override
public Stream<OrganizationDomainModel> getDomains() {
return entity.getDomains().stream().map(this::toModel);
}
@Override
public void setDomains(Collection<OrganizationDomainModel> domains) {
Map<String, OrganizationDomainModel> modelMap = domains.stream()
.collect(Collectors.toMap(model -> model.getName(), Function.identity()));
for (OrganizationDomainEntity domainEntity : this.entity.getDomains()) {
// update the existing domain (for now, only the verified flag can be changed).
if (modelMap.containsKey(domainEntity.getName())) {
domainEntity.setVerified(modelMap.get(domainEntity.getName()).getVerified());
modelMap.remove(domainEntity.getName());
}
// remove domain that is not found in the new set.
else {
this.entity.removeDomain(domainEntity);
}
}
// create the remaining domains.
for (OrganizationDomainModel model : modelMap.values()) {
OrganizationDomainEntity domainEntity = new OrganizationDomainEntity();
domainEntity.setName(model.getName().toLowerCase());
domainEntity.setVerified(model.getVerified() == null ? Boolean.FALSE : model.getVerified());
domainEntity.setOrganization(this.entity);
this.entity.addDomain(domainEntity);
}
}
@Override
public OrganizationEntity getEntity() {
return entity;
@ -118,4 +155,8 @@ public final class OrganizationAdapter implements OrganizationModel, JpaModel<Or
.append("groupId=")
.append(getGroupId()).toString();
}
private OrganizationDomainModel toModel(OrganizationDomainEntity entity) {
return new OrganizationDomainModel(entity.getName(), entity.isVerified());
}
}

View file

@ -77,7 +77,7 @@
<changeSet author="keycloak" id="25.0.0-org">
<createTable tableName="ORG">
<column name="ID" type="VARCHAR(255)">
<constraints nullable="false"/>
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="REALM_ID" type="VARCHAR(255)">
<constraints nullable="false"/>
@ -90,10 +90,20 @@
<constraints nullable="false"/>
</column>
</createTable>
<addPrimaryKey columnNames="ID" tableName="ORG"/>
<addUniqueConstraint tableName="ORG" columnNames="REALM_ID, NAME" constraintName="UK_ORG_NAME"/>
<addUniqueConstraint tableName="ORG" columnNames="GROUP_ID" constraintName="UK_ORG_GROUP"/>
<createTable tableName="ORG_DOMAIN">
<column name="NAME" type="VARCHAR(255)">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="VERIFIED" type="boolean">
<constraints nullable="false"/>
</column>
<column name="ORG_ID" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
<changeSet author="keycloak" id="unique-consentuser">

View file

@ -86,6 +86,7 @@
<!-- Organization -->
<class>org.keycloak.models.jpa.entities.OrganizationEntity</class>
<class>org.keycloak.models.jpa.entities.OrganizationDomainEntity</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>

View file

@ -45,6 +45,20 @@ public interface OrganizationProvider extends Provider {
*/
OrganizationModel getById(String id);
/**
* Returns a {@link OrganizationModel} by its internet domain.
*
* @param domainName the organization's internet domain (e.g. redhat.com)
* @return the organization that is linked to the given internet domain
*/
OrganizationModel getByDomainName(String domainName);
/**
* Returns the organizations of the given realm as a stream.
* @return Stream of the organizations. Never returns {@code null}.
*/
Stream<OrganizationModel> getAllStream();
/**
* Removes the given organization from the realm together with the data associated with it, e.g. its members etc.
*
@ -69,12 +83,6 @@ public interface OrganizationProvider extends Provider {
*/
boolean addMember(OrganizationModel organization, UserModel user);
/**
* Returns the organizations of the realm as a stream.
* @return Stream of the organizations. Never returns {@code null}.
*/
Stream<OrganizationModel> getAllStream();
/**
* Returns the members of a given {@link OrganizationModel}.
*

View file

@ -0,0 +1,70 @@
/*
* 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.models;
import java.io.Serializable;
/**
* Model implementation of an organization internet domain.
*
* @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a>
*/
public class OrganizationDomainModel implements Serializable {
private String name;
private Boolean verified;
public OrganizationDomainModel(String name, Boolean verified) {
this.name = name;
this.verified = verified;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Boolean getVerified() {
return this.verified;
}
public void setVerified(Boolean verified) {
this.verified = verified;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
if (!(o instanceof OrganizationDomainModel)) return false;
OrganizationDomainModel that = (OrganizationDomainModel) o;
return name != null && name.equals(that.getName());
}
@Override
public int hashCode() {
if (name == null) {
return super.hashCode();
}
return name.hashCode();
}
}

View file

@ -19,6 +19,7 @@ package org.keycloak.models;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.stream.Stream;
public interface OrganizationModel {
@ -42,4 +43,8 @@ public interface OrganizationModel {
Stream<String> getAttributeStream(String name);
Map<String, List<String>> getAttributes();
Stream<OrganizationDomainModel> getDomains();
void setDomains(Collection<OrganizationDomainModel> domains);
}

View file

@ -18,6 +18,8 @@
package org.keycloak.organization.admin.resource;
import java.util.Set;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jakarta.ws.rs.BadRequestException;
@ -30,13 +32,18 @@ import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.Provider;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.OrganizationDomainModel;
import org.keycloak.models.OrganizationModel;
import org.keycloak.organization.OrganizationProvider;
import org.keycloak.representations.idm.OrganizationDomainRepresentation;
import org.keycloak.representations.idm.OrganizationRepresentation;
import org.keycloak.services.ErrorResponse;
import org.keycloak.services.resources.admin.AdminEventBuilder;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.utils.StringUtil;
@ -69,14 +76,23 @@ public class OrganizationResource {
}
OrganizationModel model = provider.create(organization.getName());
toModel(organization, model);
return Response.created(session.getContext().getUri().getAbsolutePathBuilder().path(model.getId()).build()).build();
}
@GET
@Produces(MediaType.APPLICATION_JSON)
public Stream<OrganizationRepresentation> get() {
return provider.getAllStream().map(this::toRepresentation);
public Stream<OrganizationRepresentation> search(
@Parameter(description = "A String representing an organization internet domain") @QueryParam("domain-name") String domainName
) {
if (domainName == null || domainName.trim().isEmpty()) {
return provider.getAllStream().map(this::toRepresentation);
} else {
// search for the organization associated with the given domain
OrganizationModel org = provider.getByDomainName(domainName.trim());
return org == null ? Stream.empty() : Stream.of(toRepresentation(org));
}
}
@Path("{id}")
@ -107,7 +123,6 @@ public class OrganizationResource {
@Consumes(MediaType.APPLICATION_JSON)
public Response update(@PathParam("id") String id, OrganizationRepresentation organization) {
OrganizationModel model = getOrganization(id);
toModel(organization, model);
return Response.noContent().build();
@ -148,10 +163,19 @@ public class OrganizationResource {
rep.setId(model.getId());
rep.setName(model.getName());
rep.setAttributes(model.getAttributes());
model.getDomains().filter(Objects::nonNull).map(this::toRepresentation)
.forEach(rep::addDomain);
return rep;
}
private OrganizationDomainRepresentation toRepresentation(OrganizationDomainModel model) {
OrganizationDomainRepresentation representation = new OrganizationDomainRepresentation();
representation.setName(model.getName());
representation.setVerified(model.getVerified());
return representation;
}
private OrganizationModel toModel(OrganizationRepresentation rep, OrganizationModel model) {
if (rep == null) {
return null;
@ -167,6 +191,25 @@ public class OrganizationResource {
rep.getAttributes().entrySet().forEach(entry -> model.setAttribute(entry.getKey(), entry.getValue()));
}
if (rep.getDomains() != null) {
model.setDomains(rep.getDomains().stream().filter(this::validateDomainRepresentation)
.peek(domainRep -> {
OrganizationModel orgModel = provider.getByDomainName(domainRep.getName());
if (orgModel != null && !Objects.equals(model.getId(), orgModel.getId())) {
throw ErrorResponse.error("Domain " + domainRep.getName() + " is already linked to another organization", Response.Status.BAD_REQUEST);
}
})
.map(this::toModel)
.collect(Collectors.toSet()));
}
return model;
}
private OrganizationDomainModel toModel(OrganizationDomainRepresentation domainRepresentation) {
return new OrganizationDomainModel(domainRepresentation.getName(), domainRepresentation.isVerified());
}
private boolean validateDomainRepresentation(OrganizationDomainRepresentation rep) {
return rep != null && rep.getName() != null && !rep.getName().trim().isEmpty();
}
}

View file

@ -23,6 +23,7 @@ import static org.junit.Assert.assertNotNull;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
import org.keycloak.admin.client.resource.OrganizationResource;
import org.keycloak.representations.idm.OrganizationDomainRepresentation;
import org.keycloak.representations.idm.OrganizationRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.admin.AbstractAdminTest;
@ -43,12 +44,23 @@ public abstract class AbstractOrganizationTest extends AbstractAdminTest {
}
protected OrganizationRepresentation createOrganization(String name) {
return createOrganization(name, null);
}
protected OrganizationRepresentation createOrganization(String name, String orgDomain) {
OrganizationRepresentation org = new OrganizationRepresentation();
org.setName(name);
String id;
if (orgDomain != null) {
OrganizationDomainRepresentation domainRep = new OrganizationDomainRepresentation();
domainRep.setName(orgDomain);
domainRep.setVerified(true);
org.addDomain(domainRep);
}
try (Response response = testRealm().organizations().create(org)) {
assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
id = ApiUtil.getCreatedId(response);

View file

@ -21,6 +21,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.ArrayList;
@ -35,6 +36,7 @@ import org.hamcrest.Matchers;
import org.junit.Test;
import org.keycloak.admin.client.resource.OrganizationResource;
import org.keycloak.common.Profile.Feature;
import org.keycloak.representations.idm.OrganizationDomainRepresentation;
import org.keycloak.representations.idm.OrganizationRepresentation;
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
@ -48,6 +50,12 @@ public class OrganizationTest extends AbstractOrganizationTest {
assertEquals(organizationName, expected.getName());
expected.setName("acme");
// add an internet domain to the organization.
OrganizationDomainRepresentation orgDomain = new OrganizationDomainRepresentation();
orgDomain.setName("neworg.org");
orgDomain.setVerified(true);
expected.addDomain(orgDomain);
OrganizationResource organization = testRealm().organizations().get(expected.getId());
try (Response response = organization.update(expected)) {
@ -57,6 +65,49 @@ public class OrganizationTest extends AbstractOrganizationTest {
OrganizationRepresentation existing = organization.toRepresentation();
assertEquals(expected.getId(), existing.getId());
assertEquals(expected.getName(), existing.getName());
assertEquals(1, existing.getDomains().size());
OrganizationDomainRepresentation existingDomain = existing.getDomains().iterator().next();
assertEquals(orgDomain.getName(), existingDomain.getName());
assertEquals(orgDomain.isVerified(), existingDomain.isVerified());
// now test updating an existing internet domain (change verified to false and check the model was updated).
orgDomain.setVerified(false);
try (Response response = organization.update(expected)) {
assertEquals(Status.NO_CONTENT.getStatusCode(), response.getStatus());
}
existing = organization.toRepresentation();
assertEquals(1, existing.getDomains().size());
existingDomain = existing.getDomains().iterator().next();
assertEquals(false, existingDomain.isVerified());
// now replace the internet domain for a different one.
orgDomain.setName("acme.com");
try (Response response = organization.update(expected)) {
assertEquals(Status.NO_CONTENT.getStatusCode(), response.getStatus());
}
existing = organization.toRepresentation();
assertEquals(1, existing.getDomains().size());
existingDomain = existing.getDomains().iterator().next();
assertEquals("acme.com", existingDomain.getName());
assertEquals(false, existingDomain.isVerified());
// create another org and attempt to set the same internet domain during update - should not be possible.
OrganizationRepresentation anotherOrg = createOrganization("another-org");
anotherOrg.addDomain(orgDomain);
organization = testRealm().organizations().get(anotherOrg.getId());
try (Response response = organization.update(anotherOrg)) {
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
}
// finally, attempt to create a new org with an existing internet domain in the representation - should not be possible.
OrganizationRepresentation newOrg = new OrganizationRepresentation();
newOrg.setName("new-org");
newOrg.addDomain(orgDomain);
try (Response response = testRealm().organizations().create(newOrg)) {
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
}
}
@Test
@ -76,11 +127,33 @@ public class OrganizationTest extends AbstractOrganizationTest {
expected.add(createOrganization("kc.org." + i));
}
List<OrganizationRepresentation> existing = testRealm().organizations().getAll();
List<OrganizationRepresentation> existing = testRealm().organizations().getAll(null);
assertFalse(existing.isEmpty());
MatcherAssert.assertThat(expected, Matchers.containsInAnyOrder(existing.toArray()));
}
@Test
public void testGetByDomain() {
// create some organizations with a domain already set.
for (int i = 0; i < 5; i++) {
createOrganization("test-org-" + i, "testorg" + i + ".org");
}
// search for an organization with an existing domain.
List<OrganizationRepresentation> existing = testRealm().organizations().getAll("testorg2.org");
assertEquals(1, existing.size());
OrganizationRepresentation orgRep = existing.get(0);
assertEquals("test-org-2", orgRep.getName());
assertEquals(1, orgRep.getDomains().size());
OrganizationDomainRepresentation domainRep = orgRep.getDomains().iterator().next();
assertEquals("testorg2.org", domainRep.getName());
assertTrue(domainRep.isVerified());
// search for an organization with an non-existent domain.
existing = testRealm().organizations().getAll("someother.org");
assertEquals(0, existing.size());
}
@Test
public void testDelete() {
OrganizationRepresentation expected = createOrganization();