diff --git a/services/src/main/java/org/keycloak/organization/admin/resource/OrganizationsResource.java b/services/src/main/java/org/keycloak/organization/admin/resource/OrganizationsResource.java index 49b38ecf3ea..16c437e2ba7 100644 --- a/services/src/main/java/org/keycloak/organization/admin/resource/OrganizationsResource.java +++ b/services/src/main/java/org/keycloak/organization/admin/resource/OrganizationsResource.java @@ -227,7 +227,11 @@ public class OrganizationsResource { public Stream getOrganizations( @PathParam("member-id") String memberId, @Parameter(description = "if false, return the full representation. Otherwise, only the basic fields are returned.") - @QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) { + @QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation + ) { + auth.realm().requireManageRealm(); + Organizations.checkEnabled(provider); + return new OrganizationMemberResource(session, null, adminEvent).getOrganizations(memberId, briefRepresentation); } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/member/OrganizationMemberTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/member/OrganizationMemberTest.java index c35e2b12b95..7d714a9afe9 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/member/OrganizationMemberTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/member/OrganizationMemberTest.java @@ -24,13 +24,16 @@ import java.util.List; import java.util.stream.Stream; import jakarta.ws.rs.BadRequestException; +import jakarta.ws.rs.ForbiddenException; import jakarta.ws.rs.NotFoundException; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response.Status; +import org.keycloak.admin.client.Keycloak; import org.keycloak.admin.client.resource.OrganizationMemberResource; import org.keycloak.admin.client.resource.OrganizationResource; import org.keycloak.admin.client.resource.UserResource; +import org.keycloak.models.Constants; import org.keycloak.models.OrganizationModel; import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; @@ -49,6 +52,7 @@ import org.keycloak.testsuite.admin.ApiUtil; import org.keycloak.testsuite.organization.admin.AbstractOrganizationTest; import org.keycloak.testsuite.pages.AppPage; import org.keycloak.testsuite.updaters.RealmAttributeUpdater; +import org.keycloak.testsuite.util.AdminClientUtil; import org.keycloak.testsuite.util.UserBuilder; import org.hamcrest.Matchers; @@ -705,6 +709,38 @@ public class OrganizationMemberTest extends AbstractOrganizationTest { fullOrgsGlobal.get(0).getAttributes().containsKey("testAttribute")); } + @Test + public void testGetMemberOrganizationsForbiddenForNonAdminUser() throws Exception { + // create 2 orgs + OrganizationRepresentation orgA = createOrganization("orga"); + OrganizationRepresentation orgB = createOrganization("orgb"); + + // create userA and add as member of both orgs + OrganizationResource orgAResource = testRealm().organizations().get(orgA.getId()); + OrganizationResource orgBResource = testRealm().organizations().get(orgB.getId()); + UserRepresentation userA = addMember(orgAResource, "usera@orga.org"); + orgBResource.members().addMember(userA.getId()).close(); + + // create userB (non-admin user) + UserRepresentation userB = UserBuilder.create() + .username("userb") + .password("password") + .enabled(true) + .build(); + try (Response response = testRealm().users().create(userB)) { + userB.setId(ApiUtil.getCreatedId(response)); + } + getCleanup().addCleanup(() -> testRealm().users().get(userB.getId()).remove()); + + // send request as userB to OrganizationsResource.getOrganizations with member-id = userA + try (Keycloak userBClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(), + TEST_REALM_NAME, "userb", "password", Constants.ADMIN_CLI_CLIENT_ID, null)) { + userBClient.realm(TEST_REALM_NAME).organizations().members().getOrganizations(userA.getId(), true); + fail("Expected ForbiddenException"); + } catch (ForbiddenException expected) { + } + } + private void loginViaNonOrgIdP(String idpAlias) { oauth.clientId("broker-app"); loginPage.open(bc.consumerRealmName());