| /* |
| * 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; |
| |
| import org.apache.jackrabbit.guava.common.collect.ImmutableSet; |
| import org.apache.jackrabbit.api.security.user.Authorizable; |
| import org.apache.jackrabbit.api.security.user.Group; |
| import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters; |
| import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalUser; |
| import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncResult; |
| import org.apache.jackrabbit.oak.spi.security.authentication.external.basic.DefaultSyncConfig; |
| import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal; |
| import org.apache.jackrabbit.oak.spi.security.user.UserConfiguration; |
| import org.apache.jackrabbit.oak.spi.xml.ImportBehavior; |
| import org.apache.jackrabbit.oak.spi.xml.ProtectedItemImporter; |
| import org.jetbrains.annotations.NotNull; |
| import org.junit.Test; |
| |
| import javax.jcr.RepositoryException; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| import static org.mockito.Mockito.mock; |
| |
| /** |
| * Test combining dynamic sync, automembership and manual member relationship between external group and local group |
| */ |
| public class DynamicSyncTest extends AbstractDynamicTest { |
| |
| private static final String BASE_ID = "base"; |
| private static final String BASE2_ID = "base2"; |
| private static final String AUTO_GROUPS = "autoForGroups"; |
| private static final String AUTO_USERS = "autoForUsers"; |
| |
| private Group autoForGroups; |
| private Group autoForUsers; |
| private Group base; |
| private Group base2; |
| |
| @Override |
| public void before() throws Exception { |
| super.before(); |
| |
| autoForGroups = userManager.getAuthorizable(AUTO_GROUPS, Group.class); |
| autoForUsers = userManager.getAuthorizable(AUTO_USERS, Group.class); |
| |
| base = userManager.createGroup(BASE_ID); |
| // add automembership groups |
| assertTrue(base.addMembers(AUTO_GROUPS, AUTO_USERS).isEmpty()); |
| // add external groups as members breaching IDP boundary (Not recommended!) |
| assertTrue(base.addMembers("a", "b").isEmpty()); |
| |
| userManager.createGroup(EveryonePrincipal.getInstance()); |
| |
| base2 = userManager.createGroup(BASE2_ID); |
| base2.addMember(autoForUsers); |
| |
| r.commit(); |
| } |
| |
| @Override |
| @NotNull ExternalUser syncPriorToDynamicMembership() { |
| // method not needed |
| return mock(ExternalUser.class); |
| } |
| |
| @Override |
| protected ConfigurationParameters getSecurityConfigParameters() { |
| return ConfigurationParameters.of(UserConfiguration.NAME, |
| ConfigurationParameters.of( |
| ProtectedItemImporter.PARAM_IMPORT_BEHAVIOR, ImportBehavior.NAME_BESTEFFORT) |
| ); |
| } |
| |
| @Override |
| protected @NotNull DefaultSyncConfig createSyncConfig() { |
| DefaultSyncConfig config = super.createSyncConfig(); |
| config.group() |
| .setDynamicGroups(true) |
| .setAutoMembership(AUTO_GROUPS); |
| config.user() |
| .setEnforceDynamicMembership(true) |
| .setMembershipNestingDepth(2) |
| .setAutoMembership(AUTO_USERS); |
| return config; |
| } |
| |
| @Test |
| public void testSyncedUser() throws Exception { |
| ExternalUser externalUser = idp.getUser(USER_ID); |
| sync(externalUser, SyncResult.Status.ADD); |
| |
| Authorizable user = userManager.getAuthorizable(USER_ID); |
| assertNotNull(user); |
| |
| // assert membership |
| Set<String> expDeclaredGroupIds = ImmutableSet.of("a", "b", "c", "aa", "aaa", AUTO_GROUPS, AUTO_USERS, EveryonePrincipal.NAME); |
| assertExpectedIds(expDeclaredGroupIds, user.declaredMemberOf()); |
| |
| Set<String> expGroupIds = ImmutableSet.of(BASE_ID, BASE2_ID, "a", "b", "c", "aa", "aaa", AUTO_GROUPS, AUTO_USERS, EveryonePrincipal.NAME); |
| assertExpectedIds(expGroupIds, user.memberOf()); |
| |
| // assert groups |
| user.declaredMemberOf().forEachRemaining(group -> assertIsMember(group, true, user)); |
| user.memberOf().forEachRemaining(group -> assertIsMember(group, false, user)); |
| |
| // assert principals |
| List<String> principalNames = getPrincipalNames(getPrincipalManager(r).getGroupMembership(user.getPrincipal())); |
| assertEquals(10, principalNames.size()); |
| } |
| |
| @Test |
| public void testSyncedGroup() throws Exception { |
| ExternalUser externalUser = idp.getUser(USER_ID); |
| sync(externalUser, SyncResult.Status.ADD); |
| |
| // verify group 'a' |
| Group aGroup = userManager.getAuthorizable("a", Group.class); |
| assertNotNull(aGroup); |
| |
| assertExpectedIds(Collections.singleton(USER_ID), aGroup.getDeclaredMembers(), aGroup.getMembers()); |
| |
| Set<String> expectedIds = ImmutableSet.of(AUTO_GROUPS, BASE_ID, EveryonePrincipal.NAME); |
| assertExpectedIds(expectedIds, aGroup.declaredMemberOf(), aGroup.memberOf()); |
| } |
| |
| @Test |
| public void testAutomembershipGroups() throws Exception { |
| ExternalUser externalUser = idp.getUser(USER_ID); |
| sync(externalUser, SyncResult.Status.ADD); |
| |
| Authorizable user = userManager.getAuthorizable(USER_ID); |
| Group aGroup = userManager.getAuthorizable("a", Group.class); |
| |
| // verify group 'autoForGroups' |
| Set<String> expMemberIds = ImmutableSet.of("a", "b", "c", "aa", "aaa", USER_ID); |
| assertExpectedIds(expMemberIds, autoForGroups.getDeclaredMembers(), autoForGroups.getMembers()); |
| assertIsMember(autoForGroups, true, user, aGroup); |
| assertIsMember(autoForGroups, false, user, aGroup); |
| assertFalse(autoForGroups.isMember(base)); |
| } |
| |
| @Test |
| public void testAutomembershipUsers() throws Exception { |
| ExternalUser externalUser = idp.getUser(USER_ID); |
| sync(externalUser, SyncResult.Status.ADD); |
| |
| Authorizable user = userManager.getAuthorizable(USER_ID); |
| Group aGroup = userManager.getAuthorizable("a", Group.class); |
| |
| // verify group 'autoForUsers' |
| Set<String> expMemberIds = ImmutableSet.of(USER_ID); |
| assertExpectedIds(expMemberIds, autoForUsers.getDeclaredMembers(), autoForUsers.getMembers()); |
| assertTrue(autoForUsers.isMember(user)); |
| |
| assertFalse(autoForUsers.isMember(aGroup)); |
| assertFalse(autoForUsers.isMember(base)); |
| } |
| |
| @Test |
| public void testInheritedBaseGroup() throws Exception { |
| ExternalUser externalUser = idp.getUser(USER_ID); |
| sync(externalUser, SyncResult.Status.ADD); |
| |
| Authorizable user = userManager.getAuthorizable(USER_ID); |
| |
| // verify group 'base' |
| Set<String> expDeclaredMemberIds = ImmutableSet.of(AUTO_GROUPS, AUTO_USERS, "a", "b"); |
| assertExpectedIds(expDeclaredMemberIds, base.getDeclaredMembers()); |
| assertFalse(base.isDeclaredMember(user)); |
| |
| Set<String> expMemberIds = ImmutableSet.of(USER_ID, AUTO_GROUPS, AUTO_USERS, "a", "b", "c", "aa", "aaa"); |
| assertExpectedIds(expMemberIds, base.getMembers()); |
| assertTrue(base.isMember(user)); |
| } |
| |
| @Test |
| public void testInheritedBase2Group() throws Exception { |
| ExternalUser externalUser = idp.getUser(USER_ID); |
| sync(externalUser, SyncResult.Status.ADD); |
| |
| Authorizable user = userManager.getAuthorizable(USER_ID); |
| |
| // verify group 'base2' |
| Set<String> expDeclaredMemberIds = ImmutableSet.of(AUTO_USERS); |
| assertExpectedIds(expDeclaredMemberIds, base2.getDeclaredMembers()); |
| |
| assertFalse(base2.isDeclaredMember(user)); |
| |
| Set<String> expMemberIds = ImmutableSet.of(USER_ID, AUTO_USERS); |
| assertExpectedIds(expMemberIds, base2.getMembers()); |
| assertTrue(base2.isMember(user)); |
| } |
| |
| private static void assertIsMember(@NotNull Group group, boolean declared, @NotNull Authorizable... members) { |
| try { |
| for (Authorizable member : members) { |
| if (declared) { |
| assertTrue(group.isDeclaredMember(member)); |
| } else { |
| assertTrue(group.isMember(member)); |
| } |
| } |
| } catch (RepositoryException e) { |
| fail(e.getMessage()); |
| } |
| } |
| |
| private static void assertExpectedIds(@NotNull Set<String> expectedIds, @NotNull Iterator<? extends Authorizable>... iterators) { |
| for (Iterator<? extends Authorizable> it : iterators) { |
| List<String> ids = getIds(it); |
| assertEquals("Expected "+expectedIds+" found "+ids, expectedIds.size(), ids.size()); |
| assertTrue("Expected "+expectedIds+" found "+ids, ids.containsAll(expectedIds)); |
| } |
| } |
| } |