Can not update organization group error when trying to create organisation from REST API

Closes #31144

Signed-off-by: Martin Kanis <mkanis@redhat.com>
This commit is contained in:
Martin Kanis 2024-07-22 15:15:41 +02:00 committed by Marek Posolda
parent 00d8e06f79
commit d91d6d18d5
6 changed files with 39 additions and 18 deletions

View file

@ -93,7 +93,7 @@ public class JpaOrganizationProvider implements OrganizationProvider {
}
RealmModel realm = getRealm();
OrganizationAdapter adapter = new OrganizationAdapter(realm, this);
OrganizationAdapter adapter = new OrganizationAdapter(session, realm, this);
try {
session.setAttribute(OrganizationModel.class.getName(), adapter);
@ -194,7 +194,7 @@ public class JpaOrganizationProvider implements OrganizationProvider {
@Override
public OrganizationModel getById(String id) {
OrganizationEntity entity = getEntity(id, false);
return entity == null ? null : new OrganizationAdapter(getRealm(), entity, this);
return entity == null ? null : new OrganizationAdapter(session, getRealm(), entity, this);
}
@Override
@ -205,7 +205,7 @@ public class JpaOrganizationProvider implements OrganizationProvider {
query.setParameter("name", domain.toLowerCase());
try {
OrganizationEntity entity = query.getSingleResult();
return new OrganizationAdapter(realm, entity, this);
return new OrganizationAdapter(session, realm, entity, this);
} catch (NoResultException nre) {
return null;
}
@ -227,7 +227,7 @@ public class JpaOrganizationProvider implements OrganizationProvider {
query.setParameter("realmId", realm.getId());
return closing(paginateQuery(query, first, max).getResultStream()
.map(entity -> new OrganizationAdapter(realm, entity, this)));
.map(entity -> new OrganizationAdapter(session, realm, entity, this)));
}
@Override
@ -260,7 +260,7 @@ public class JpaOrganizationProvider implements OrganizationProvider {
Predicate finalPredicate = builder.and(predicates.toArray(new Predicate[0]));
TypedQuery<OrganizationEntity> typedQuery = em.createQuery(query.select(org).where(finalPredicate));
return closing(paginateQuery(typedQuery, first, max).getResultStream())
.map(entity -> new OrganizationAdapter(realm, entity, this));
.map(entity -> new OrganizationAdapter(session, realm, entity, this));
}
@Override

View file

@ -19,7 +19,6 @@ package org.keycloak.organization.jpa;
import static java.util.Optional.ofNullable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.List;
@ -31,6 +30,7 @@ import java.util.stream.Stream;
import org.keycloak.models.GroupModel;
import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelValidationException;
import org.keycloak.models.OrganizationDomainModel;
import org.keycloak.models.OrganizationModel;
@ -46,13 +46,15 @@ import org.keycloak.utils.StringUtil;
public final class OrganizationAdapter implements OrganizationModel, JpaModel<OrganizationEntity> {
private final KeycloakSession session;
private final RealmModel realm;
private final OrganizationEntity entity;
private final OrganizationProvider provider;
private GroupModel group;
private Map<String, List<String>> attributes;
public OrganizationAdapter(RealmModel realm, OrganizationProvider provider) {
public OrganizationAdapter(KeycloakSession session, RealmModel realm, OrganizationProvider provider) {
this.session = session;
entity = new OrganizationEntity();
entity.setId(KeycloakModelUtils.generateId());
entity.setRealmId(realm.getId());
@ -60,7 +62,8 @@ public final class OrganizationAdapter implements OrganizationModel, JpaModel<Or
this.provider = provider;
}
public OrganizationAdapter(RealmModel realm, OrganizationEntity entity, OrganizationProvider provider) {
public OrganizationAdapter(KeycloakSession session, RealmModel realm, OrganizationEntity entity, OrganizationProvider provider) {
this.session = session;
this.realm = realm;
this.entity = entity;
this.provider = provider;
@ -137,10 +140,23 @@ public final class OrganizationAdapter implements OrganizationModel, JpaModel<Or
if (attributes == null) {
return;
}
Set<String> attrsToRemove = getAttributes().keySet();
attrsToRemove.removeAll(attributes.keySet());
attrsToRemove.forEach(group::removeAttribute);
attributes.forEach(group::setAttribute);
// add organization to the session as the following code updates the underlying group
OrganizationModel current = (OrganizationModel) session.getAttribute(OrganizationModel.class.getName());
if (current == null) {
session.setAttribute(OrganizationModel.class.getName(), this);
}
try {
Set<String> attrsToRemove = getAttributes().keySet();
attrsToRemove.removeAll(attributes.keySet());
attrsToRemove.forEach(group::removeAttribute);
attributes.forEach(group::setAttribute);
} finally {
if (current == null) {
session.removeAttribute(OrganizationModel.class.getName());
}
}
}
@Override

View file

@ -190,10 +190,10 @@ public class Organizations {
model.setDescription(rep.getDescription());
model.setAttributes(rep.getAttributes());
model.setDomains(ofNullable(rep.getDomains()).orElse(Set.of()).stream()
.filter(Objects::nonNull)
.filter(domain -> StringUtil.isNotBlank(domain.getName()))
.map(Organizations::toModel)
.collect(Collectors.toSet()));
.filter(Objects::nonNull)
.filter(domain -> StringUtil.isNotBlank(domain.getName()))
.map(Organizations::toModel)
.collect(Collectors.toSet()));
return model;
}

View file

@ -2,7 +2,7 @@
<#if org?has_content>
Sign-in to ${org.name} organization
<#list org.attributes?keys as key>
The ${key} is ${org.attributes[key]}
The ${key} is ${org.attributes[key]?join(", ")}
</#list>
<#if org.member>
User is member of ${org.name}

View file

@ -26,6 +26,7 @@ import static org.junit.Assert.assertTrue;
import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
@ -148,6 +149,8 @@ public abstract class AbstractOrganizationTest extends AbstractAdminTest {
org.addDomain(domainRep);
}
org.setAttributes(Map.of("key", List.of("value1", "value2")));
return org;
}

View file

@ -19,12 +19,14 @@
package org.keycloak.testsuite.organization.admin;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage;
import java.util.List;
import java.util.Map.Entry;
import jakarta.ws.rs.core.Response;
import org.hamcrest.Matchers;
import org.jboss.arquillian.graphene.page.Page;
import org.junit.Assert;
import org.junit.Before;
@ -175,7 +177,7 @@ public class OrganizationThemeTest extends AbstractOrganizationTest {
loginPage.loginUsername("non-user@myorg.com");
Assert.assertTrue(driver.getPageSource().contains("Sign-in to myorg organization"));
for (Entry<String, List<String>> attribute : orgRep.getAttributes().entrySet()) {
Assert.assertTrue(driver.getPageSource().contains("The " + attribute.getKey() + " is " + attribute.getValue()));
assertThat(driver.getPageSource(), Matchers.containsString("The " + attribute.getKey() + " is " + String.join(", ", attribute.getValue())));
}
Assert.assertFalse(loginPage.isPasswordInputPresent());
}