Do not expose kc.org attribute in user representations
Closes #31143 Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
parent
b41f3599ea
commit
d475833361
4 changed files with 15 additions and 14 deletions
|
@ -248,6 +248,7 @@ public class ModelToRepresentation {
|
||||||
}
|
}
|
||||||
if (attributes != null && !copy.isEmpty()) {
|
if (attributes != null && !copy.isEmpty()) {
|
||||||
Map<String, List<String>> attrs = new HashMap<>(copy);
|
Map<String, List<String>> attrs = new HashMap<>(copy);
|
||||||
|
attrs.remove(OrganizationModel.ORGANIZATION_ATTRIBUTE);
|
||||||
rep.setAttributes(attrs);
|
rep.setAttributes(attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.ModelDuplicateException;
|
import org.keycloak.models.ModelDuplicateException;
|
||||||
import org.keycloak.models.ModelException;
|
import org.keycloak.models.ModelException;
|
||||||
import org.keycloak.models.ModelIllegalStateException;
|
import org.keycloak.models.ModelIllegalStateException;
|
||||||
|
import org.keycloak.models.OrganizationModel;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserConsentModel;
|
import org.keycloak.models.UserConsentModel;
|
||||||
import org.keycloak.models.UserCredentialModel;
|
import org.keycloak.models.UserCredentialModel;
|
||||||
|
@ -1075,6 +1076,7 @@ public class UserResource {
|
||||||
|
|
||||||
attributes.remove(UserModel.USERNAME);
|
attributes.remove(UserModel.USERNAME);
|
||||||
attributes.remove(UserModel.EMAIL);
|
attributes.remove(UserModel.EMAIL);
|
||||||
|
attributes.remove(OrganizationModel.ORGANIZATION_ATTRIBUTE);
|
||||||
|
|
||||||
return attributes.entrySet().stream()
|
return attributes.entrySet().stream()
|
||||||
.filter(entry -> ofNullable(entry.getValue()).orElse(emptyList()).stream().anyMatch(StringUtil::isNotBlank))
|
.filter(entry -> ofNullable(entry.getValue()).orElse(emptyList()).stream().anyMatch(StringUtil::isNotBlank))
|
||||||
|
|
|
@ -358,13 +358,8 @@ public class DeclarativeUserProfileProviderFactory implements UserProfileProvide
|
||||||
metadata.addAttribute(OrganizationModel.ORGANIZATION_ATTRIBUTE, -1,
|
metadata.addAttribute(OrganizationModel.ORGANIZATION_ATTRIBUTE, -1,
|
||||||
new AttributeValidatorMetadata(OrganizationMemberValidator.ID),
|
new AttributeValidatorMetadata(OrganizationMemberValidator.ID),
|
||||||
new AttributeValidatorMetadata(ImmutableAttributeValidator.ID))
|
new AttributeValidatorMetadata(ImmutableAttributeValidator.ID))
|
||||||
.addReadCondition(c -> USER_API.equals(c.getContext()))
|
.addReadCondition((c) -> false)
|
||||||
.addWriteCondition(context -> {
|
.addWriteCondition((c) -> false);
|
||||||
// the attribute can only be managed within the scope of the Organization API
|
|
||||||
// we assume, for now, that if the organization is set as a session attribute, we are operating within the scope if the Organization API
|
|
||||||
KeycloakSession session = context.getSession();
|
|
||||||
return session.getAttribute(OrganizationModel.class.getName()) != null;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,12 +40,13 @@ import jakarta.ws.rs.NotFoundException;
|
||||||
import jakarta.ws.rs.core.Response;
|
import jakarta.ws.rs.core.Response;
|
||||||
import jakarta.ws.rs.core.Response.Status;
|
import jakarta.ws.rs.core.Response.Status;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import org.hamcrest.Matchers;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.admin.client.resource.OrganizationMemberResource;
|
import org.keycloak.admin.client.resource.OrganizationMemberResource;
|
||||||
import org.keycloak.admin.client.resource.OrganizationResource;
|
import org.keycloak.admin.client.resource.OrganizationResource;
|
||||||
import org.keycloak.admin.client.resource.UserResource;
|
import org.keycloak.admin.client.resource.UserResource;
|
||||||
import org.keycloak.common.Profile.Feature;
|
import org.keycloak.common.Profile.Feature;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.OrganizationModel;
|
import org.keycloak.models.OrganizationModel;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
@ -90,7 +91,6 @@ public class OrganizationMemberTest extends AbstractOrganizationTest {
|
||||||
testRealm().users().userProfile().update(upConfig);
|
testRealm().users().userProfile().update(upConfig);
|
||||||
OrganizationResource organization = testRealm().organizations().get(createOrganization().getId());
|
OrganizationResource organization = testRealm().organizations().get(createOrganization().getId());
|
||||||
UserRepresentation expected = addMember(organization);
|
UserRepresentation expected = addMember(organization);
|
||||||
List<String> expectedOrganizations = expected.getAttributes().get(ORGANIZATION_ATTRIBUTE);
|
|
||||||
|
|
||||||
expected.singleAttribute(ORGANIZATION_ATTRIBUTE, "invalid");
|
expected.singleAttribute(ORGANIZATION_ATTRIBUTE, "invalid");
|
||||||
|
|
||||||
|
@ -109,11 +109,14 @@ public class OrganizationMemberTest extends AbstractOrganizationTest {
|
||||||
expected.getAttributes().remove(ORGANIZATION_ATTRIBUTE);
|
expected.getAttributes().remove(ORGANIZATION_ATTRIBUTE);
|
||||||
userResource.update(expected);
|
userResource.update(expected);
|
||||||
expected = userResource.toRepresentation();
|
expected = userResource.toRepresentation();
|
||||||
assertThat(expected.getAttributes().get(ORGANIZATION_ATTRIBUTE), Matchers.containsInAnyOrder(expectedOrganizations.toArray()));
|
assertNull(expected.getAttributes());
|
||||||
|
getTestingClient().server(TEST_REALM_NAME).run(OrganizationMemberTest::assertMembersHaveOrgAttribute);
|
||||||
|
}
|
||||||
|
|
||||||
userResource.update(expected);
|
private static void assertMembersHaveOrgAttribute(KeycloakSession session) {
|
||||||
expected = userResource.toRepresentation();
|
OrganizationModel organization = session.getProvider(OrganizationProvider.class).getByDomainName("neworg.org");
|
||||||
assertThat(expected.getAttributes().get(ORGANIZATION_ATTRIBUTE), Matchers.containsInAnyOrder(expectedOrganizations.toArray()));
|
assertTrue(session.getProvider(OrganizationProvider.class).getMembersStream(organization, null, false, -1, -1).
|
||||||
|
anyMatch(userModel -> userModel.getAttributes().getOrDefault(ORGANIZATION_ATTRIBUTE, List.of()).contains(organization.getId())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -281,7 +284,7 @@ public class OrganizationMemberTest extends AbstractOrganizationTest {
|
||||||
OrganizationResource organization = testRealm().organizations().get(createOrganization().getId());
|
OrganizationResource organization = testRealm().organizations().get(createOrganization().getId());
|
||||||
UserRepresentation expected = addMember(organization);
|
UserRepresentation expected = addMember(organization);
|
||||||
assertNotNull(expected.getAttributes());
|
assertNotNull(expected.getAttributes());
|
||||||
assertTrue(expected.getAttributes().get(ORGANIZATION_ATTRIBUTE).contains(organization.toRepresentation().getId()));
|
assertNull(expected.getAttributes().get(ORGANIZATION_ATTRIBUTE));
|
||||||
OrganizationMemberResource member = organization.members().member(expected.getId());
|
OrganizationMemberResource member = organization.members().member(expected.getId());
|
||||||
|
|
||||||
try (Response response = member.delete()) {
|
try (Response response = member.delete()) {
|
||||||
|
|
Loading…
Reference in a new issue