You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by an...@apache.org on 2023/06/08 14:34:27 UTC
[jackrabbit-oak] 01/01: OAK-10286 : AutoMembershipPrincipals.isInheritedMember add check for cyclic membership, OAK-10285 : MembershipProvider change log level to ERROR for cyclic membership
This is an automated email from the ASF dual-hosted git repository.
angela pushed a commit to branch OAK-10286_OAK-10285
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
commit 1ac567e59dadad7fe0a6eeacb24b9d26e75b8f13
Author: angela <an...@adobe.com>
AuthorDate: Thu Jun 8 16:34:13 2023 +0200
OAK-10286 : AutoMembershipPrincipals.isInheritedMember add check for cyclic membership, OAK-10285 : MembershipProvider change log level to ERROR for cyclic membership
---
.../impl/principal/AutoMembershipPrincipals.java | 12 ++-
.../impl/principal/AutoMembershipCycleTest.java | 109 +++++++++++++++++++++
.../oak/security/user/MembershipProvider.java | 2 +-
3 files changed, 120 insertions(+), 3 deletions(-)
diff --git a/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/AutoMembershipPrincipals.java b/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/AutoMembershipPrincipals.java
index f7f29c823d..fc9c664940 100644
--- a/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/AutoMembershipPrincipals.java
+++ b/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/AutoMembershipPrincipals.java
@@ -127,15 +127,23 @@ final class AutoMembershipPrincipals {
}
boolean isInheritedMember(@NotNull String idpName, @NotNull Group group, @NotNull Authorizable authorizable) throws RepositoryException {
+ return isInheritedMember(idpName, group, authorizable, new HashSet<>());
+ }
+
+ boolean isInheritedMember(@NotNull String idpName, @NotNull Group group, @NotNull Authorizable authorizable, @NotNull Set<String> processedIds) throws RepositoryException {
String groupId = group.getID();
+ if (!processedIds.add(groupId)) {
+ log.error("Cyclic group membership detected for group id {}", groupId);
+ return false;
+ }
if (isMember(idpName, groupId, authorizable)) {
return true;
}
-
+
Iterator<Authorizable> declaredGroupMembers = Iterators.filter(group.getDeclaredMembers(), Authorizable::isGroup);
while (declaredGroupMembers.hasNext()) {
Group grMember = (Group) declaredGroupMembers.next();
- if (isInheritedMember(idpName, grMember, authorizable)) {
+ if (isInheritedMember(idpName, grMember, authorizable, processedIds)) {
return true;
}
}
diff --git a/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/AutoMembershipCycleTest.java b/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/AutoMembershipCycleTest.java
new file mode 100644
index 0000000000..60a088f821
--- /dev/null
+++ b/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/AutoMembershipCycleTest.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.jackrabbit.oak.spi.security.authentication.external.impl.principal;
+
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.guava.common.collect.Iterators;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.jcr.RepositoryException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+public class AutoMembershipCycleTest extends AbstractAutoMembershipTest {
+
+ private AutoMembershipPrincipals amp;
+ private final Authorizable authorizable = mock(Authorizable.class);
+
+ @Before
+ public void before() throws Exception {
+ super.before();
+ Map<String, String[]> mapping = Collections.singletonMap(IDP_VALID_AM, new String[] {AUTOMEMBERSHIP_GROUP_ID_1});
+ amp = new AutoMembershipPrincipals(userManager, mapping, getAutoMembershipConfigMapping());
+ }
+
+ @Test
+ public void testIsInheritedMemberCircularIncludingAutoMembership() throws Exception {
+ Group amGr1 = mockGroup(AUTOMEMBERSHIP_GROUP_ID_1);
+ Group gr = mockGroup("testGroup");
+
+ // mock a membership cycle
+ List<Authorizable> members = Arrays.asList(authorizable, amGr1);
+ when(gr.getDeclaredMembers()).thenReturn(members.iterator(), members.iterator(), members.iterator()).thenThrow(new RuntimeException("cicle"));
+ when(amGr1.getDeclaredMembers()).thenReturn(Iterators.singletonIterator(gr), Iterators.singletonIterator(gr), Iterators.singletonIterator(gr)).thenThrow(new RuntimeException("cicle"));
+
+ // declared automembership
+ assertTrue(amp.isInheritedMember(IDP_VALID_AM, amGr1, authorizable));
+ verify(amGr1, never()).getDeclaredMembers();
+
+ // declared automembership in amGr1
+ assertTrue(amp.isInheritedMember(IDP_VALID_AM, gr, authorizable));
+ verify(gr).getDeclaredMembers();
+ verify(amGr1, never()).getDeclaredMembers();
+ clearInvocations(amGr1, gr);
+
+ // declared automembership
+ assertTrue(amp.isInheritedMember(IDP_VALID_AM, amGr1, gr));
+ verify(amGr1, never()).getDeclaredMembers();
+ verify(gr, never()).getDeclaredMembers();
+
+ assertTrue(amp.isInheritedMember(IDP_VALID_AM, gr, amGr1));
+ verify(gr).getDeclaredMembers();
+ verify(amGr1, never()).getDeclaredMembers();
+ }
+
+ @Test
+ public void testIsInheritedMemberCircularWithoutAutoMembership() throws Exception {
+ // mock a membership cycle
+ Group gr = mockGroup("testGroup");
+ Group gr2 = mockGroup("testGroup2");
+
+ when(gr.getDeclaredMembers()).thenReturn(Iterators.singletonIterator(gr2)).thenThrow(new RuntimeException("circle"));
+ when(gr2.getDeclaredMembers()).thenReturn(Iterators.singletonIterator(gr)).thenThrow(new RuntimeException("circle"));
+
+ assertFalse(amp.isInheritedMember(IDP_VALID_AM, gr, gr2));
+
+ verify(gr, times(1)).getDeclaredMembers();
+ verify(gr, times(2)).getID();
+ verify(gr, times(1)).isGroup();
+ verify(gr2, times(1)).getDeclaredMembers();
+ verify(gr2, times(1)).getID();
+ verify(gr2, times(1)).isGroup();
+ verifyNoMoreInteractions(gr, gr2);
+ }
+
+ private static @NotNull Group mockGroup(@NotNull String id) throws RepositoryException {
+ Group gr = when(mock(Group.class).isGroup()).thenReturn(true).getMock();
+ when(gr.getID()).thenReturn(id);
+ return gr;
+ }
+}
\ No newline at end of file
diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/MembershipProvider.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/MembershipProvider.java
index af0615ac22..4457049589 100644
--- a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/MembershipProvider.java
+++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/MembershipProvider.java
@@ -202,7 +202,7 @@ class MembershipProvider extends AuthorizableBaseProvider {
@Override
protected boolean hasProcessedReference(@NotNull String value) {
if (groupContentId.equals(value)) {
- log.warn("Cyclic group membership detected for contentId {}", groupContentId);
+ log.error("Cyclic group membership detected for contentId {}", groupContentId);
return false;
}
return processedRefs.add(value);