Add validation for the organization's internet domains.
Closes #28634 Signed-off-by: Stefan Guilhen <sguilhen@redhat.com>
This commit is contained in:
parent
0f88753f34
commit
2ab8bf852d
4 changed files with 27 additions and 7 deletions
|
@ -23,7 +23,6 @@ import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
@ -36,6 +35,7 @@ import org.keycloak.models.jpa.JpaModel;
|
||||||
import org.keycloak.models.jpa.entities.OrganizationDomainEntity;
|
import org.keycloak.models.jpa.entities.OrganizationDomainEntity;
|
||||||
import org.keycloak.models.jpa.entities.OrganizationEntity;
|
import org.keycloak.models.jpa.entities.OrganizationEntity;
|
||||||
import org.keycloak.organization.OrganizationProvider;
|
import org.keycloak.organization.OrganizationProvider;
|
||||||
|
import org.keycloak.utils.EmailValidationUtil;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ public final class OrganizationAdapter implements OrganizationModel, JpaModel<Or
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, OrganizationDomainModel> modelMap = domains.stream()
|
Map<String, OrganizationDomainModel> modelMap = domains.stream()
|
||||||
.peek(this::isDomainInUse)
|
.peek(this::validateDomainRepresentation)
|
||||||
.collect(Collectors.toMap(OrganizationDomainModel::getName, Function.identity()));
|
.collect(Collectors.toMap(OrganizationDomainModel::getName, Function.identity()));
|
||||||
|
|
||||||
for (OrganizationDomainEntity domainEntity : new HashSet<>(this.entity.getDomains())) {
|
for (OrganizationDomainEntity domainEntity : new HashSet<>(this.entity.getDomains())) {
|
||||||
|
@ -153,10 +153,23 @@ public final class OrganizationAdapter implements OrganizationModel, JpaModel<Or
|
||||||
return new OrganizationDomainModel(entity.getName(), entity.isVerified());
|
return new OrganizationDomainModel(entity.getName(), entity.isVerified());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void isDomainInUse(OrganizationDomainModel domainRep) {
|
/**
|
||||||
OrganizationModel orgModel = provider.getByDomainName(domainRep.getName());
|
* Validates the domain representation. Specifically, the method first checks if the specified domain is valid,
|
||||||
|
* and then checks if the domain is not already linked to a different organization.
|
||||||
|
*
|
||||||
|
* @param domainModel the {@link OrganizationDomainModel} representing the domain being added.
|
||||||
|
* @throws {@link ModelValidationException} if the domain is invalid or is already linked to a different organization.
|
||||||
|
*/
|
||||||
|
private void validateDomainRepresentation(OrganizationDomainModel domainModel) {
|
||||||
|
String domainName = domainModel.getName();
|
||||||
|
|
||||||
|
// we rely on the same validation util used by the EmailValidator to ensure the domain part is consistently validated.
|
||||||
|
if(domainName == null || domainName.isEmpty() || !EmailValidationUtil.isValidEmail("nouser@" + domainName)) {
|
||||||
|
throw new ModelValidationException("The specified domain is invalid: " + domainName);
|
||||||
|
}
|
||||||
|
OrganizationModel orgModel = provider.getByDomainName(domainName);
|
||||||
if (orgModel != null && !Objects.equals(getId(), orgModel.getId())) {
|
if (orgModel != null && !Objects.equals(getId(), orgModel.getId())) {
|
||||||
throw new ModelValidationException("Domain " + domainRep.getName() + " is already linked to another organization");
|
throw new ModelValidationException("Domain " + domainName + " is already linked to another organization");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ public class OrganizationDomainModel implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
this.name = name;
|
this.name = name != null ? name.trim() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getVerified() {
|
public boolean getVerified() {
|
||||||
|
|
|
@ -187,6 +187,7 @@ public class OrganizationResource {
|
||||||
model.setName(rep.getName());
|
model.setName(rep.getName());
|
||||||
model.setAttributes(rep.getAttributes());
|
model.setAttributes(rep.getAttributes());
|
||||||
model.setDomains(Optional.ofNullable(rep.getDomains()).orElse(Set.of()).stream()
|
model.setDomains(Optional.ofNullable(rep.getDomains()).orElse(Set.of()).stream()
|
||||||
|
.filter(Objects::nonNull)
|
||||||
.map(this::toModel)
|
.map(this::toModel)
|
||||||
.collect(Collectors.toSet()));
|
.collect(Collectors.toSet()));
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -212,6 +211,13 @@ public class OrganizationTest extends AbstractOrganizationTest {
|
||||||
assertEquals(expectedNewOrgBrDomain.getName(), existingNewOrgBrDomain.getName());
|
assertEquals(expectedNewOrgBrDomain.getName(), existingNewOrgBrDomain.getName());
|
||||||
assertEquals(expectedNewOrgBrDomain.isVerified(), existingNewOrgBrDomain.isVerified());
|
assertEquals(expectedNewOrgBrDomain.isVerified(), existingNewOrgBrDomain.isVerified());
|
||||||
|
|
||||||
|
// attempt to set the internet domain to an invalid domain.
|
||||||
|
expectedNewOrgBrDomain.setName("_invalid.domain.3com");
|
||||||
|
try (Response response = organization.update(expected)) {
|
||||||
|
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
|
||||||
|
}
|
||||||
|
expectedNewOrgBrDomain.setName("acme.com");
|
||||||
|
|
||||||
// create another org and attempt to set the same internet domain during update - should not be possible.
|
// create another org and attempt to set the same internet domain during update - should not be possible.
|
||||||
OrganizationRepresentation anotherOrg = createOrganization("another-org");
|
OrganizationRepresentation anotherOrg = createOrganization("another-org");
|
||||||
anotherOrg.addDomain(expectedNewOrgDomain);
|
anotherOrg.addDomain(expectedNewOrgDomain);
|
||||||
|
|
Loading…
Reference in a new issue