| /* |
| * 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 java.util.Calendar; |
| import java.util.Iterator; |
| import java.util.Set; |
| import javax.jcr.SimpleCredentials; |
| import javax.jcr.Value; |
| |
| import com.google.common.collect.Sets; |
| import org.apache.jackrabbit.api.security.user.Authorizable; |
| import org.apache.jackrabbit.api.security.user.UserManager; |
| import org.apache.jackrabbit.oak.api.Root; |
| import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentity; |
| import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityRef; |
| import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalLoginModuleTestBase; |
| import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncContext; |
| import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncHandler; |
| import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncResult; |
| import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncedIdentity; |
| import org.apache.jackrabbit.oak.spi.security.authentication.external.basic.DefaultSyncConfig; |
| import org.apache.jackrabbit.oak.spi.security.authentication.external.basic.DefaultSyncContext; |
| import org.apache.jackrabbit.oak.spi.security.authentication.external.basic.DefaultSyncedIdentity; |
| import org.jetbrains.annotations.NotNull; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertSame; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| /** |
| * DefaultSyncHandlerTest |
| */ |
| public class DefaultSyncHandlerTest extends ExternalLoginModuleTestBase { |
| |
| private UserManager userManager; |
| private DefaultSyncHandler syncHandler; |
| |
| @Before |
| public void before() throws Exception { |
| super.before(); |
| |
| userManager = getUserManager(root); |
| SyncHandler sh = syncManager.getSyncHandler("default"); |
| |
| assertTrue(sh instanceof DefaultSyncHandler); |
| syncHandler = (DefaultSyncHandler) sh; |
| } |
| |
| @After |
| public void after() throws Exception { |
| super.after(); |
| } |
| |
| @Override |
| protected void setSyncConfig(DefaultSyncConfig cfg) { |
| if (cfg != null) { |
| cfg.user().setExpirationTime(500); |
| cfg.group().setExpirationTime(Long.MAX_VALUE); |
| } |
| super.setSyncConfig(cfg); |
| } |
| |
| private void sync(@NotNull String id, boolean isGroup) throws Exception { |
| SyncContext ctx = syncHandler.createContext(idp, userManager, getValueFactory()); |
| ExternalIdentity exIdentity = (isGroup) ? idp.getGroup(id) : idp.getUser(id); |
| assertNotNull(exIdentity); |
| |
| SyncResult res = ctx.sync(exIdentity); |
| assertSame(SyncResult.Status.ADD, res.getStatus()); |
| root.commit(); |
| } |
| |
| @Test |
| public void testGetName() { |
| assertEquals(syncConfig.getName(), syncHandler.getName()); |
| } |
| |
| @Test |
| public void testCreateContext() throws Exception { |
| SyncContext ctx = syncHandler.createContext(idp, userManager, getValueFactory()); |
| assertTrue(ctx instanceof DefaultSyncContext); |
| } |
| |
| @Test |
| public void testFindMissingIdentity() throws Exception { |
| SyncedIdentity id = syncHandler.findIdentity(userManager, "foobar"); |
| assertNull("unknown authorizable should not exist", id); |
| } |
| |
| @Test |
| public void testFindLocalIdentity() throws Exception { |
| SyncedIdentity id = syncHandler.findIdentity(userManager, "admin"); |
| assertNotNull("known authorizable should exist", id); |
| assertNull("local user should not have external ref", id.getExternalIdRef()); |
| } |
| |
| @Test |
| public void testFindExternalIdentity() throws Exception { |
| login(new SimpleCredentials(USER_ID, new char[0])).close(); |
| root.refresh(); |
| |
| SyncedIdentity id = syncHandler.findIdentity(userManager, USER_ID); |
| assertNotNull("known authorizable should exist", id); |
| ExternalIdentityRef ref = id.getExternalIdRef(); |
| assertNotNull(ref); |
| assertEquals("external user should have correct external ref.idp", idp.getName(), ref.getProviderName()); |
| assertEquals("external user should have correct external ref.id", USER_ID, id.getExternalIdRef().getId()); |
| } |
| |
| @Test |
| public void testFindGroupIdentity() throws Exception { |
| SyncedIdentity si = syncHandler.findIdentity(userManager, "c"); |
| assertNull(si); |
| |
| sync("c", true); |
| |
| si = syncHandler.findIdentity(userManager, "c"); |
| assertNotNull(si); |
| assertTrue(si.isGroup()); |
| assertNotNull(si.getExternalIdRef()); |
| } |
| |
| @Test |
| public void testFindIdentityWithRemovedExternalId() throws Exception { |
| sync(USER_ID, false); |
| |
| // NOTE: use system-root to remove the protected rep:externalId property (since Oak 1.5.8) |
| Authorizable authorizable = userManager.getAuthorizable(USER_ID); |
| Root systemRoot = getSystemRoot(); |
| systemRoot.getTree(authorizable.getPath()).removeProperty(DefaultSyncContext.REP_EXTERNAL_ID); |
| systemRoot.commit(); |
| root.refresh(); |
| |
| SyncedIdentity si = syncHandler.findIdentity(userManager, USER_ID); |
| assertNotNull(si); |
| assertNull(si.getExternalIdRef()); |
| } |
| |
| @Test |
| public void testRequiresSyncAfterCreate() throws Exception { |
| login(new SimpleCredentials(USER_ID, new char[0])).close(); |
| root.refresh(); |
| |
| SyncedIdentity id = syncHandler.findIdentity(userManager, USER_ID); |
| assertNotNull("Known authorizable should exist", id); |
| |
| assertFalse("Freshly synced id should not require sync", syncHandler.requiresSync(id)); |
| } |
| |
| @Test |
| public void testRequiresSyncExpiredSyncProperty() throws Exception { |
| login(new SimpleCredentials(USER_ID, new char[0])).close(); |
| root.refresh(); |
| |
| final Calendar nowCal = Calendar.getInstance(); |
| nowCal.setTimeInMillis(nowCal.getTimeInMillis() - 1000); |
| Value nowValue = getValueFactory().createValue(nowCal); |
| |
| Authorizable a = userManager.getAuthorizable(USER_ID); |
| a.setProperty(DefaultSyncContext.REP_LAST_SYNCED, nowValue); |
| root.commit(); |
| |
| SyncedIdentity id = syncHandler.findIdentity(userManager, USER_ID); |
| assertNotNull("known authorizable should exist", id); |
| |
| assertTrue("synced id should require sync", syncHandler.requiresSync(id)); |
| } |
| |
| @Test |
| public void testRequiresSyncMissingSyncProperty() throws Exception { |
| sync(USER_ID, false); |
| |
| Authorizable a = userManager.getAuthorizable(USER_ID); |
| a.removeProperty(DefaultSyncContext.REP_LAST_SYNCED); |
| root.commit(); |
| |
| SyncedIdentity si = syncHandler.findIdentity(userManager, USER_ID); |
| assertNotNull(si); |
| assertTrue(syncHandler.requiresSync(si)); |
| } |
| |
| @Test |
| public void testRequiresSyncMissingExternalIDRef() throws Exception { |
| assertTrue(syncHandler.requiresSync(new DefaultSyncedIdentity(USER_ID, null, false, Long.MAX_VALUE))); |
| } |
| |
| @Test |
| public void testRequiresSyncNotYetSynced() throws Exception { |
| assertTrue(syncHandler.requiresSync(new DefaultSyncedIdentity(USER_ID, idp.getUser(USER_ID).getExternalId(), false, Long.MIN_VALUE))); |
| } |
| |
| @Test |
| public void testRequiresSyncGroup() throws Exception { |
| sync("c", true); |
| |
| SyncedIdentity si = syncHandler.findIdentity(userManager, "c"); |
| assertNotNull(si); |
| assertTrue(si.isGroup()); |
| assertFalse(syncHandler.requiresSync(si)); |
| } |
| |
| @Test |
| public void testListIdentitiesBeforeSync() throws Exception { |
| Iterator<SyncedIdentity> identities = syncHandler.listIdentities(userManager); |
| if (identities.hasNext()) { |
| SyncedIdentity si = identities.next(); |
| fail("Sync handler returned unexpected identity: " + si); |
| } |
| } |
| |
| @Test |
| public void testListIdentitiesAfterSync() throws Exception { |
| sync(USER_ID, false); |
| |
| // membership-nesting is 1 => expect only 'USER_ID' plus the declared group-membership |
| Set<String> expected = Sets.newHashSet(USER_ID); |
| for (ExternalIdentityRef extRef : idp.getUser(USER_ID).getDeclaredGroups()) { |
| expected.add(extRef.getId()); |
| } |
| |
| Iterator<SyncedIdentity> identities = syncHandler.listIdentities(userManager); |
| while (identities.hasNext()) { |
| SyncedIdentity si = identities.next(); |
| if (expected.contains(si.getId())) { |
| expected.remove(si.getId()); |
| assertNotNull(si.getExternalIdRef()); |
| } else { |
| fail("Sync handler returned unexpected identity: " + si); |
| } |
| } |
| assertTrue(expected.isEmpty()); |
| } |
| |
| @Test |
| public void testListIdentitiesIgnoresLocal() throws Exception { |
| sync(USER_ID, false); |
| |
| Iterator<SyncedIdentity> identities = syncHandler.listIdentities(userManager); |
| while (identities.hasNext()) { |
| SyncedIdentity si = identities.next(); |
| ExternalIdentityRef ref = si.getExternalIdRef(); |
| assertNotNull(ref); |
| assertNotNull(ref.getProviderName()); |
| } |
| } |
| } |