mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-06-30 18:15:39 +00:00
20884: Merged V3.3 to V3.3-BUG-FIX 20883: ALF-3604: Fix PersonTest 20881: Merged PATCHES/V3.2.r to V3.3 20880: ALF-3264: Fix up handling of default namespace. Workaround to JXPATH-61 20878: Merged V2.2 to V3.3 20474: Fix for ALF-1362 - encode group identifiers when used inside embedded param tags 20621: Fix for reopened ALF-1362 - UnknownAuthorityException when viewing/editing/deleting a user group with html entities in it's name 20874: Merged HEAD to V3.3 20873: ALF-3604: Correct case-sensitivity issues in LDAP sync - User names are now brought in line with the case of the LDAP directory during sync (in case the UID attribute is case sensitive) - User names are now compared according to Alfresco's case sensitivity setting - Group name comparisions are still case sensitive - Added unit test to ensure correct behaviour 20868: Merged PATCHES/V3.2.r to V3.3 20832: ALF-3264: XForms 'schema evolution': Remove nodes from XForms instance document with XPaths that don't occur in prototype document 20867: Merged PATCHES/V3.2.r to V3.3 (RECORD ONLY) 20833: Incremented version label 20688: Incremented version label 20687: Merged V3.3 to PATCHES/V3.2.r 20398: Fixed ALF-2890: Upgrade removes content if transaction retries are triggered - Setting ContentData that was derived outside of the current transaction opened up a window for the post-rollback code to delete the underlying binary. The binaries are only registered for writers fetched via the ContentService now; the low-level DAO no longer does management because it can't assume that a new content URL indicates a new underlying binary. - The contentUrlConverter was creating new URLs and thus the low-level DAO cleaned up live content when retrying collisions took place. The cleanup is no longer on the stack for the patch. - Removes the ALF-558 changes around ContentData.reference() 20590: Fixed ALF-3189: Oracle/DB2/SQLServer/PostgreSQL are missing indexes to support many FK constraints - Reverses rev 17421 - Added patchy bits to post-create script and declared patch - Patch only applies to *new* installations from 3.2.0 onwards (schema 3007 to 3400) 20686: ALF-3259: Merged HEAD to PATCHES/V3.2.r 19784: Fix for CIFS/CheckInOut.exe save of working copy breaks lock on original file. ALF-2028. 20866: Merged PATCHES/V3.2.1 to V3.3 (RECORD ONLY) 20840: Incremented version label 20839: ALF-3691: Merged V3.3-BUG-FIX to PATCHES/V3.2.1 20307: VersionStore - minor fixes if running deprecated V1 - warn in startup log - do not execute migration cleanup 20367: ALF-2829: Avoid reading entire result set into memory in FixNameCrcValuesPatch 20368: Work-around for ALF-2366: patch.updateDmPermissions takes too long to complete - this patch may now be deferred until 3.4 using the sample context (DM will use old permissions and AVM new as it did in 2.2.x) - this is only supported upgrading direct to 3.2.1.x 20370: Version Migrator (ALF-1000) - use common batch processor to enable multiple workers 20373: Version Migrator (ALF-1000) - resolve runtime conflict (w/ r20334) 20387: Version Migrator (ALF-1000) - approx x3 boost (policies ignore version2 store) 20431: Version Migrator (ALF-1000) - migrate 1st batch independently 20738:ALF-3617: Merged V3.3-BUG-FIX to PATCHES/V3.2.1 20438: ALF-479: Merged DEV/BELARUS/V3.2-2010_01_11 to DEV/V3.3-BUG-FIX 18448: ETHREEOH-4044: External Authentication Subsystem does not perform user mapping for WebDAV requests The changes listed in the bug comments have been made (and corrected). 20728: Incremented version label 20727: ALF-3617: Merged HEAD to PATCHES/V3.2.1 20616: ALF-2265: Share 'Uber Filter' part 2 - WebScriptNTLMAuthenticationFilter detached from its superclass and renamed to WebScriptSSOAuthenticationFilter - Now the filter simply chains to the downstream authentication filter rather than call its superclass - This means the same filter can be used for Kerberos-protected webscripts as well as NTLM - Wired globalAuthenticationFilter behind webscriptAuthenticationFilter in the filter chain in web.xml - Configured webscriptAuthenticationFilter for Kerberos subsystem 20612: Incremented version label 20610: Merged V3.3 to PATCHES/V3.2.1 20590: Fixed ALF-3189: Oracle/DB2/SQLServer/PostgreSQL are missing indexes to support many FK constraints - Reverses rev 17421 - Added patchy bits to post-create script and declared patch - Patch only applies to *new* installations from 3.2.0 onwards (schema 3007 to 3501) 20403: Merged V3.3 to PATCHES/V3.2.1 20398: Fixed ALF-2890: Upgrade removes content if transaction retries are triggered - Setting ContentData that was derived outside of the current transaction opened up a window for the post-rollback code to delete the underlying binary. The binaries are only registered for writers fetched via the ContentService now; the low-level DAO no longer does management because it can't assume that a new content URL indicates a new underlying binary. - The contentUrlConverter was creating new URLs and thus the low-level DAO cleaned up live content when retrying collisions took place. The cleanup is no longer on the stack for the patch. - Removes the ALF-558 changes around ContentData.reference() 20391: Incremented version label 20390: ALF-2966: Merged DEV/V3.3-BUG-FIX to PATCHES/V3.2.1 20388: Merged BRANCHES/DEV/BELARUS/HEAD-2010_04_28 to BRANCHES/DEV/V3.3-BUG-FIX: 20372: ALF-897: It is impossible to create content when default value selected in ContentHeadlineBackground field for intranet_rssi_landing_template web-form (also fixes ALF-2798 & ALF-791) 20371: ALF-2861: Merged V3.2 to PATCHES/V3.2.1 20028: Reverted (and fixed line endings) of log4j.properties 20027: Merged BRANCHES/V3.1 to BRANCHES/V3.2: 19983: Changes for ALF-2545: Cannot upgrade from 2.1.2a (b 209) to the 3.1.2 (.a3 458) on Oracle 20008: ALF-2351: Oracle upgrade scripts need enhancements from 2.2SP7 20362: ALF-2883: Merged HEAD to V3.2.1 19750: Fix for ALF-2310: alfresco-mmt-3.3dev.jar shows NoClassDefFoundError: org/safehaus/uuid/UUIDGenerator 20359: Merged PATCHES/V3.2.0 to PATCHES/V3.2.1 20349: Merged V3.3 to PATCHES/V3.2.0 20346: ALF-2839: Node pre-loading generates needless resultset rows - Added missing Criteria.list() call 20280: Fixed ALF-2839: Node pre-loading generates needless resultset rows - Split Criteria query to retrieve properties and aspects separately 20272: Backports to help fix ALF-2839: Node pre-loading generates needless resultset rows Merged BRANCHES/V3.2 to PATCHES/V3.2.0: 18490: Added cache for alf_content_data Merged BRANCHES/DEV/V3.3-BUG-FIX to PATCHES/V3.2.0: 20231: Fixed ALF-2784: Degradation of performance between 3.1.1 and 3.2x (observed in JSF) 20266: Test reproduction of ALF-2839 failure: Node pre-loading generates needless resultset rows 20358: Increment version label 20343: Incremented version label 20342: Merged V3.3 to PATCHES/V3.2.1 20322: Fixed ALF-1998: contentStoreCleanerJob leads to foreign key exception - Possible concurrent modification of alf_content_url.orphan_time led to false orphan detection - Fixed queries to check for dereferencing AND use the indexed orphan_time column - More robust use of EagerContentStoreCleaner: On eager cleanup, ensure that URLs are deleted - Added optimistic lock checks on updates and deletes of alf_content_url 20864: Merged PATCHES/V3.2.0 to V3.3 (RECORD ONLY) 20750: Merged V3.3 to PATCHES/V3.2.0 20590: Fixed ALF-3189: Oracle/DB2/SQLServer/PostgreSQL are missing indexes to support many FK constraints - Reverses rev 17421 - Added patchy bits to post-create script and declared patch - Patch only applies to *new* installations from 3.2.0 onwards (schema 3007 to 3400) 20748: Incremented version label 20745: ALF-3639: Merged V3.2 to PATCHES/V3.2.0 18363: WCM clustering - ETHREEOH-3962 (duplicate root node entry) 20863: Merged PATCHES/V3.1.2 to V3.3 20830: ALF-934: Another go at making External Access Servlet reset JSF view state for the document it is requesting 20701: ALF-3203: Guarantee a deterministic initialization sequence for WebClientConfigBootstrap (PARTIAL - Needs Surf fix) 20861: Merged PATCHES/V3.2.1 to V3.3 (RECORD ONLY) 20831: Incremented version label 20702: Incremented version label 20681: ALF-3109: Merged V3.2 to PATCHES/V3.1.2 16933: Fix ETHREEOH-1788 - Bootstrap fails due to disabled-avm-indexing-context.xml 20680: ALF-3109: Merged V3.2 to PATCHES/V3.1.2 16714: WCM/AVM fixes - ETHREEOH-2697 - file system likely to get full with avm lucene directories for unindexed WCM store - ETHREEOH-1847 - re-starting cluster node may show non-staging WCM store indexes out-of-date (although not indexed) 20611: Incremented version label 20538: ALF-3117: Merged HEAD to PATCHES/V3.1.2 17099: Build Fix for failing permission test (missing flush in DAO) 20535: ALF-3141: Merged V3.2 to PATCHES/V3.1.2 17441: Build fix: Fix AVM permission inheritance to match DM and fix common permission dao component 20534: Incremented version label 20533: ALF-3117: Merged DEV/V3.3-BUG-FIX to PATCHES/V3.1.2 20368: Work-around for ALF-2366: patch.updateDmPermissions takes too long to complete - this patch may now be deferred until 3.4 using the sample context (DM will use old permissions and AVM new as it did in 2.2.x) - this is only supported upgrading direct to 3.3.1 20532: ALF-3117: Merged V3.2 to PATCHES/V3.1.2 17076: Improvements for ETHREEOH-2153: patch.updateDmPermissions takes too long to complete 20531: ALF-3141: Merged V3.2 to PATCHES/V3.1.2 17419: Fix for ETHREEOH-3296: Enterprise 3.X / Permissions Error When Cut & Paste on Sub-Folder 20516: Incremented version label 20515: ALF-3109: Merged V3.2 to PATCHES/V3.1.2 18363: WCM clustering - ETHREEOH-3962 (duplicate root node entry) 20860: Merged V3.1 to V3.3 19424: Fix bug in permission evaluation time reporting 20859: Merged V3.1 to V3.3 (RECORD ONLY) 20599: Incremented version label 20596: ALF-3184: Merged V3.3-BUGFIX to V3.1A 20307: VersionStore - minor fixes if running deprecated V1 - warn in startup log - do not execute migration cleanup 20370: Version Migrator (ALF-1000) - use common batch processor to enable multiple workers 20373: Version Migrator (ALF-1000) - resolve runtime conflict (w/ r20334) 20387: Version Migrator (ALF-1000) - approx x3 boost (policies ignore version2 store) 20431: Version Migrator (ALF-1000) - migrate 1st batch independently 20591: ALF-3184: Merged V3.2 to V3.1A (partial) 19507: ALF-955: deletion of dynamic custom model - ignore policies/behaviours for node archive store (reviewed w/ DH) 19553: Follow-on to r19507 (ALF-955) - fix testAutoRemovalOfVersionHistory 20577: ALF-3184: Ported BatchProcessor to V3.1A in preparation for VersionMigrator port 19426: Fix for eclipse build path: Part 2 19425: Fix for eclipse build path 19305: Merged V3.2 to V3.1 ('cause you never know!) 19304: Removed static (singleton) usage of CacheFactory 18996: MOB-388: Fixed copying of properties 18919: CopyServiceChildAssocsFix on 3.1 18566: Removed svn:mergeinfo 18428: Backport of r14260: fixed code typo which cased a ClassCastException with multiple pooled actors. 18424: Updated version label to 3.1.2.1 17861: Merge 2.2 to 3.1: 17803: Re-use open files for the same session/process id so that writes on each file handle go to the same file. ETWOTWO-1250. (Record-only) 17843: Re-use open files for the same session/process id so that writes on each file handle go to the same file. Port of ETWOTWO-1250. 17842: Missing file from previous checkin. 17839: Rewrite the rename file logic to handle MS Office file rename patterns. ETHREEOH-1951. 17359: Fix for CIFS/Kerberos/SPNEGO logon problem with Win2008/Win7 client. ETHREEOH-3225. 17193: ETHREEOH-3112: Issue for adding / deleting non-English files Appropriate encoding for non English symbols was added. Ported from V3.2. 17181: Fixed typo on --record-only 17130: Fix for cannot delete file via CIFS that has a thumbnail associated with it. ETHREEOH-3143 and ETHREEOH-3115. 20858: Merged V2.2 to V3.3 18568: (RECORD ONLY) Fix for CIFS SendTo->Compressed Folder 'not enough space' error. ETWOTWO-596. Ported latest v3 repo filesystem rename logic to v2, should fix a few other issues too. 17803: (RECORD ONLY) Re-use open files for the same session/process id so that writes on each file handle go to the same file. ETWOTWO-1250. 20857: Merged V2.2 to V3.3 20504: Merged DEV/BELARUS/V2.2-2010_02_03 to V2.2 19346: ALF-1358: Deleting space with "execute a script" rule fails - The invocation of the RuleServiceImpl.getRule() was added on the ruleNodeRef to get updated associations of the last one. (???) 20476: Fix for ALF-1863: Advanced Search does not work with custom type of type d:int with a constraint of type LIST 20475: Merged DEV/TEMPORARY to V2.2 20375: ALF-1830: Manage Task UI for Pooled Tasks: don't show Reject/Accept if user hasn't taken ownership 20472: (RECORD ONLY) ALF-1841: Merged DEV/BELARUS/V2.2-2009_12_01 to V2.2 (with corrections) 17865: ETWOTWO-935: Regression: readOnly settings do not work in 2.2 causing bootstrap to fail The check on current mode is read only was added into AbstractLuceneIndexerAndSearcherFactory and AlfrescoJobExecutorThread classes. 20068: Merged BRANCHES/DEV/BELARUS/V2.2-2010_02_03 to BRANCHES/V2.2: 19326: ALF-1932: ALF-1358 Deleting space with "execute a script" rule fails: Unit Test move to RuleServiceImplTest. 19670: Fix for ALF-1788: Renamed Category not usable in Query - renaming a category in the admin console now also renames the association and changes the PATH by which the category is known. 19093: Fix ALF-1791 - added unit test 19055: Fix compile error introduced during pervious merge 19048: Merge DEV/BELARUS/V2.2-2010_02_03 to V2.2 19014 : ALF-883: Rule is not triggered for a item which is restored from the bin 19045: Merge DEV/V2.1SP7 to V2.2 12225 : ETWOONE-74 (Authentication tickets expire after set time, but would be more useful to have them expire after an inactivity timeout.) 18958: Merged BELARUS/V2.2-2010_02_03 18850 Fixed ALF-1358: Deleting space with "execute a script" rule fails - Merged the fix only. The unit test belongs to the RuleService. 18918: (RECORD ONLY) Fixed backward compatibility of CopyServiceChildAssocsFix module 18759: (RECORD ONLY) Merged DEV/BELARUS/V2.2-2010_02_03 to V2.2 18553: ResultSet closing was added to methods This was fixed separately in V3.2; port forward selectively 18561: (RECORD ONLY) Merged DEV to V2.2 18552: Fix ETWOTWO-1389: Issues with ACL upgrade script for Oracle (DH: Removed commented-out SQL statements) 16304: (RECORD ONLY) ETWOONE-335: Parallel Review does not store Priority and Due Date set at task creation 1. Appropriate changes have been made in parallelreview_group_processdefinition.xml and parallelreview_processdefinition.xml files. 2. Redeploy flag is kept with false value by default in the workflow-context.xml.sample file. 3. A sorting of the list of workflow definitions by name has been already applied in all branches according to ETWOTWO-302 issue fix. 20855: Fix for ALF-3690. Unable to FTP files into Share site documentLibrary folder. This fix corrects what it essentially a typo. The dictionaryService was injected twice into the CreateNodeRuleTrigger bean, rather than the dictionaryService and the ruleService. 20853: Merged V2.2 to V3.3 (RECORD ONLY) 20459: Build fix - don't try to delete the guest user in PersonTest 20411: Merged BRANCHES/V3.1 to BRANCHES/V2.2: (for ALF-2628) 14863: (RECORD ONLY) Fixed ETHREEOH-2223: Oracle version-specific schema update failure in upgrading from 2.1A build to 20383: Merged V3.2 to V2.2 (Fixes duplicate ALF-1359) 16731: ETHREEOH-2411: Error message appears when trying to create advanced workflow with long description 19303: Updated version to 2.2.7 17811: Updated version to 2.2.6 17433: Merged V3.1 to V2.2 15894: Fix ETHREEOH-2416 and ALFCOM-3300: Duplicate name exceptions not being trapped correctly Fixes ETWOTWO-1261 15869: Port of desktop action client side EXE fixes from v3.x. ETWOTWO-1374. 20849: (RECORD ONLY) Merged V3.3-BUG-FIX to V3.3 20847: Fixes Recent Documents and My Tasks localisation issues: ALF-2021 & adds an FTL friendly medium length date format property 20828: Missed svn:mergeinfo git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@20885 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
1112 lines
40 KiB
Java
1112 lines
40 KiB
Java
/*
|
|
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
|
*
|
|
* This file is part of Alfresco
|
|
*
|
|
* Alfresco is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Alfresco is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package org.alfresco.repo.security.sync;
|
|
|
|
import java.util.AbstractCollection;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.Date;
|
|
import java.util.HashSet;
|
|
import java.util.Iterator;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Random;
|
|
import java.util.Set;
|
|
import java.util.TreeMap;
|
|
|
|
import junit.framework.TestCase;
|
|
|
|
import org.alfresco.model.ContentModel;
|
|
import org.alfresco.repo.management.subsystems.ChildApplicationContextManager;
|
|
import org.alfresco.repo.security.authentication.AuthenticationContext;
|
|
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
|
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
|
import org.alfresco.service.cmr.repository.NodeRef;
|
|
import org.alfresco.service.cmr.repository.NodeService;
|
|
import org.alfresco.service.cmr.security.AuthorityService;
|
|
import org.alfresco.service.cmr.security.AuthorityType;
|
|
import org.alfresco.service.cmr.security.PersonService;
|
|
import org.alfresco.service.namespace.QName;
|
|
import org.alfresco.util.GUID;
|
|
import org.alfresco.util.PropertyMap;
|
|
import org.springframework.context.ApplicationContext;
|
|
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
|
import org.springframework.context.support.StaticApplicationContext;
|
|
|
|
/**
|
|
* Tests the {@link ChainingUserRegistrySynchronizer} using a simulated {@link UserRegistry}.
|
|
*
|
|
* @author dward
|
|
*/
|
|
public class ChainingUserRegistrySynchronizerTest extends TestCase
|
|
{
|
|
|
|
/** The context locations, in reverse priority order. */
|
|
private static final String[] CONFIG_LOCATIONS =
|
|
{
|
|
"classpath:alfresco/application-context.xml", "classpath:sync-test-context.xml"
|
|
};
|
|
|
|
/** The Spring application context. */
|
|
private static ApplicationContext context = new ClassPathXmlApplicationContext(
|
|
ChainingUserRegistrySynchronizerTest.CONFIG_LOCATIONS);
|
|
|
|
/** The synchronizer we are testing. */
|
|
private UserRegistrySynchronizer synchronizer;
|
|
|
|
/** The application context manager. */
|
|
private MockApplicationContextManager applicationContextManager;
|
|
|
|
/** The person service. */
|
|
private PersonService personService;
|
|
|
|
/** The authority service. */
|
|
private AuthorityService authorityService;
|
|
|
|
/** The node service. */
|
|
private NodeService nodeService;
|
|
|
|
/** The authentication context. */
|
|
private AuthenticationContext authenticationContext;
|
|
|
|
/** The retrying transaction helper. */
|
|
private RetryingTransactionHelper retryingTransactionHelper;
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
* @see junit.framework.TestCase#setUp()
|
|
*/
|
|
@Override
|
|
protected void setUp() throws Exception
|
|
{
|
|
this.synchronizer = (UserRegistrySynchronizer) ChainingUserRegistrySynchronizerTest.context
|
|
.getBean("testUserRegistrySynchronizer");
|
|
this.applicationContextManager = (MockApplicationContextManager) ChainingUserRegistrySynchronizerTest.context
|
|
.getBean("testApplicationContextManager");
|
|
this.personService = (PersonService) ChainingUserRegistrySynchronizerTest.context.getBean("personService");
|
|
this.authorityService = (AuthorityService) ChainingUserRegistrySynchronizerTest.context
|
|
.getBean("authorityService");
|
|
this.nodeService = (NodeService) ChainingUserRegistrySynchronizerTest.context.getBean("nodeService");
|
|
|
|
this.authenticationContext = (AuthenticationContext) ChainingUserRegistrySynchronizerTest.context
|
|
.getBean("authenticationContext");
|
|
this.authenticationContext.setSystemUserAsCurrentUser();
|
|
|
|
this.retryingTransactionHelper = (RetryingTransactionHelper) ChainingUserRegistrySynchronizerTest.context
|
|
.getBean("retryingTransactionHelper");
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
* @see junit.framework.TestCase#tearDown()
|
|
*/
|
|
@Override
|
|
protected void tearDown() throws Exception
|
|
{
|
|
this.authenticationContext.clearCurrentSecurityContext();
|
|
}
|
|
|
|
/**
|
|
* Sets up the test users and groups in three zones, "Z0", "Z1" and "Z2", by doing a forced synchronize with a Mock
|
|
* user registry. Note that the zones have some overlapping entries. "Z0" is not used in subsequent synchronizations
|
|
* and is used to test that users and groups in zones that aren't in the authentication chain get 're-zoned'
|
|
* appropriately. The layout is as follows
|
|
*
|
|
* <pre>
|
|
* Z0
|
|
* G1
|
|
* U6
|
|
*
|
|
* Z1
|
|
* G2 - U1, G3 - U2, G4, G5
|
|
*
|
|
* Z2
|
|
* G2 - U1, U3, U4
|
|
* G6 - U3, U4, G7 - U5
|
|
* </pre>
|
|
*
|
|
* @throws Exception
|
|
* the exception
|
|
*/
|
|
private void setUpTestUsersAndGroups() throws Exception
|
|
{
|
|
this.applicationContextManager.setUserRegistries(new MockUserRegistry("Z0", new NodeDescription[]
|
|
{
|
|
newPerson("U6")
|
|
}, new NodeDescription[]
|
|
{
|
|
newGroup("G1")
|
|
}), new MockUserRegistry("Z1", new NodeDescription[]
|
|
{
|
|
newPerson("U1"), newPerson("U2"), newPerson("U7")
|
|
}, new NodeDescription[]
|
|
{
|
|
newGroup("G2", "U1", "G3"), newGroup("G3", "U2", "G4", "G5"), newGroup("G4"), newGroup("G5")
|
|
}), new MockUserRegistry("Z2", new NodeDescription[]
|
|
{
|
|
newPerson("U1"), newPerson("U3"), newPerson("U4"), newPerson("U5")
|
|
}, new NodeDescription[]
|
|
{
|
|
newGroup("G2", "U1", "U3", "U4"), newGroup("G6", "U3", "U4", "G7"), newGroup("G7", "U5")
|
|
}));
|
|
this.synchronizer.synchronize(true, true, true);
|
|
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
|
{
|
|
|
|
public Object execute() throws Throwable
|
|
{
|
|
assertExists("Z0", "U6");
|
|
assertExists("Z0", "G1");
|
|
assertExists("Z1", "U1");
|
|
assertExists("Z1", "U2");
|
|
assertExists("Z1", "G2", "U1", "G3");
|
|
assertExists("Z1", "G3", "U2", "G4", "G5");
|
|
assertExists("Z1", "G4");
|
|
assertExists("Z1", "G5");
|
|
assertExists("Z2", "U3");
|
|
assertExists("Z2", "U4");
|
|
assertExists("Z2", "U5");
|
|
assertExists("Z2", "G6", "U3", "U4", "G7");
|
|
assertExists("Z2", "G7", "U5");
|
|
return null;
|
|
}
|
|
}, false, true);
|
|
}
|
|
|
|
/**
|
|
* Tear down test users and groups.
|
|
*
|
|
* @throws Exception
|
|
* the exception
|
|
*/
|
|
public void tearDownTestUsersAndGroups() throws Exception
|
|
{
|
|
// Wipe out everything that was in Z1 and Z2
|
|
this.applicationContextManager.setUserRegistries(new MockUserRegistry("Z0", new NodeDescription[] {},
|
|
new NodeDescription[] {}), new MockUserRegistry("Z1", new NodeDescription[] {},
|
|
new NodeDescription[] {}), new MockUserRegistry("Z2", new NodeDescription[] {},
|
|
new NodeDescription[] {}));
|
|
this.synchronizer.synchronize(true, true, true);
|
|
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
|
{
|
|
|
|
public Object execute() throws Throwable
|
|
{
|
|
assertNotExists("U1");
|
|
assertNotExists("U2");
|
|
assertNotExists("U3");
|
|
assertNotExists("U4");
|
|
assertNotExists("U5");
|
|
assertNotExists("U6");
|
|
assertNotExists("U7");
|
|
assertNotExists("G1");
|
|
assertNotExists("G2");
|
|
assertNotExists("G3");
|
|
assertNotExists("G4");
|
|
assertNotExists("G5");
|
|
assertNotExists("G6");
|
|
assertNotExists("G7");
|
|
return null;
|
|
}
|
|
}, false, true);
|
|
}
|
|
|
|
/**
|
|
* Tests a differential update of the test users and groups. The layout is as follows
|
|
*
|
|
* <pre>
|
|
* Z1
|
|
* G1 - U1, U6
|
|
* G2 - U1
|
|
* G3 - U2, G4, G5 - U6
|
|
*
|
|
* Z2
|
|
* G2 - U1, U3, U4, U6
|
|
* G6 - U3, U4, G7
|
|
* </pre>
|
|
*
|
|
* @throws Exception
|
|
* the exception
|
|
*/
|
|
public void testDifferentialUpdate() throws Exception
|
|
{
|
|
setUpTestUsersAndGroups();
|
|
this.applicationContextManager.removeZone("Z0");
|
|
this.applicationContextManager.updateZone("Z1", new NodeDescription[]
|
|
{
|
|
newPerson("U1", "changeofemail@alfresco.com"), newPerson("U6"), newPerson("U7")
|
|
}, new NodeDescription[]
|
|
{
|
|
newGroup("G1", "U1", "U6", "UDangling"), newGroup("G2", "U1", "GDangling"),
|
|
newGroupWithDisplayName("G5", "Amazing Group", "U6", "U7", "G4")
|
|
});
|
|
this.applicationContextManager.updateZone("Z2", new NodeDescription[]
|
|
{
|
|
newPerson("U1", "shouldbeignored@alfresco.com"), newPerson("U5", "u5email@alfresco.com"), newPerson("U6")
|
|
}, new NodeDescription[]
|
|
{
|
|
newGroup("G2", "U1", "U3", "U4", "U6"), newGroup("G7")
|
|
});
|
|
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
|
{
|
|
|
|
public Object execute() throws Throwable
|
|
{
|
|
|
|
ChainingUserRegistrySynchronizerTest.this.synchronizer.synchronize(false, false, false);
|
|
// Stay in the same transaction
|
|
assertExists("Z1", "U1");
|
|
assertEmailEquals("U1", "changeofemail@alfresco.com");
|
|
assertExists("Z1", "U2");
|
|
assertExists("Z1", "U6");
|
|
assertExists("Z1", "U7");
|
|
assertExists("Z1", "G1", "U1", "U6");
|
|
assertExists("Z1", "G2", "U1");
|
|
assertExists("Z1", "G3", "U2", "G4", "G5");
|
|
assertExists("Z1", "G4");
|
|
assertExists("Z1", "G5", "U6", "U7", "G4");
|
|
assertGroupDisplayNameEquals("G5", "Amazing Group");
|
|
assertExists("Z2", "U3");
|
|
assertExists("Z2", "U4");
|
|
assertExists("Z2", "U5");
|
|
assertEmailEquals("U5", "u5email@alfresco.com");
|
|
assertExists("Z2", "G6", "U3", "U4", "G7");
|
|
assertExists("Z2", "G7");
|
|
return null;
|
|
}
|
|
});
|
|
tearDownTestUsersAndGroups();
|
|
}
|
|
|
|
/**
|
|
* Tests a forced update of the test users and groups. Also tests that groups and users that previously existed in
|
|
* Z2 get moved when they appear in Z1. Also tests that 'dangling references' to removed users (U4, U5) do not cause
|
|
* any problems. Also tests that case-sensitivity is not a problem when an occluded user is recreated with different
|
|
* case. The layout is as follows
|
|
*
|
|
* <pre>
|
|
* Z1
|
|
* G1 - U6
|
|
* G2 -
|
|
* G3 - U2, G5 - U6
|
|
* G6 - u3
|
|
*
|
|
* Z2
|
|
* G2 - U1, U3, U6
|
|
* G6 - U3, G7
|
|
* </pre>
|
|
*
|
|
* @throws Exception
|
|
* the exception
|
|
*/
|
|
public void testForcedUpdate() throws Exception
|
|
{
|
|
setUpTestUsersAndGroups();
|
|
this.applicationContextManager.setUserRegistries(new MockUserRegistry("Z1", new NodeDescription[]
|
|
{
|
|
newPerson("U2"), newPerson("u3"), newPerson("U6")
|
|
}, new NodeDescription[]
|
|
{
|
|
newGroup("G1", "U6"), newGroup("G2"), newGroup("G3", "U2", "G5"), newGroup("G5", "U6"),
|
|
newGroup("G6", "u3")
|
|
}), new MockUserRegistry("Z2", new NodeDescription[]
|
|
{
|
|
newPerson("U1", "somenewemail@alfresco.com"), newPerson("U3"), newPerson("U6")
|
|
}, new NodeDescription[]
|
|
{
|
|
newGroup("G2", "U1", "U3", "U4", "U6"), newGroup("G6", "U3", "U4", "G7"),
|
|
newGroupWithDisplayName("G7", "Late Arrival", "U4", "U5")
|
|
}));
|
|
this.synchronizer.synchronize(true, true, true);
|
|
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
|
{
|
|
|
|
public Object execute() throws Throwable
|
|
{
|
|
assertExists("Z1", "U2");
|
|
assertExists("Z1", "u3");
|
|
assertExists("Z1", "U6");
|
|
assertExists("Z1", "G1", "U6");
|
|
assertExists("Z1", "G2");
|
|
assertExists("Z1", "G3", "U2", "G5");
|
|
assertNotExists("G4");
|
|
assertExists("Z1", "G5", "U6");
|
|
assertExists("Z1", "G6", "u3");
|
|
assertExists("Z2", "U1");
|
|
assertEmailEquals("U1", "somenewemail@alfresco.com");
|
|
assertNotExists("U4");
|
|
assertNotExists("U5");
|
|
assertExists("Z2", "G7");
|
|
assertGroupDisplayNameEquals("G7", "Late Arrival");
|
|
return null;
|
|
}
|
|
}, false, true);
|
|
tearDownTestUsersAndGroups();
|
|
}
|
|
|
|
/**
|
|
* Tests a forced update of the test users and groups where some of the users change their case and some groups
|
|
* appear with different case.
|
|
*/
|
|
public void testCaseChange() throws Exception
|
|
{
|
|
setUpTestUsersAndGroups();
|
|
|
|
final Map<String, NodeRef> personNodes = new TreeMap<String, NodeRef>();
|
|
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
|
{
|
|
public Object execute() throws Throwable
|
|
{
|
|
// Get hold of the original person nodes so we can compare them later
|
|
personNodes.put("u1", ChainingUserRegistrySynchronizerTest.this.personService.getPerson("U1", false));
|
|
personNodes.put("u2", ChainingUserRegistrySynchronizerTest.this.personService.getPerson("U2", false));
|
|
personNodes.put("u6", ChainingUserRegistrySynchronizerTest.this.personService.getPerson("U6", false));
|
|
return null;
|
|
}
|
|
}, false, true);
|
|
|
|
this.applicationContextManager.setUserRegistries(new MockUserRegistry("Z1", new NodeDescription[]
|
|
{
|
|
newPerson("u1"), newPerson("u2"), newPerson("u6"), newPerson("U7")
|
|
}, new NodeDescription[]
|
|
{
|
|
newGroup("g1", "u6"), newGroup("g2", "u1", "G3"), newGroup("G3", "u2", "g4", "g5"), newGroup("g4"),
|
|
newGroup("g5")
|
|
}), new MockUserRegistry("Z2", new NodeDescription[]
|
|
{
|
|
newPerson("U1"), newPerson("U3"), newPerson("U4"), newPerson("U5")
|
|
}, new NodeDescription[]
|
|
{
|
|
newGroup("G2", "U1", "U3", "U4"), newGroup("G6", "U3", "U4", "G7"), newGroup("G7", "U5")
|
|
}));
|
|
this.synchronizer.synchronize(true, true, true);
|
|
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
|
{
|
|
|
|
public Object execute() throws Throwable
|
|
{
|
|
assertExists("Z1", "u1");
|
|
assertExists("Z1", "u2");
|
|
assertExists("Z1", "u6");
|
|
assertExists("Z1", "g1", "u6");
|
|
assertExists("Z1", "g2", "u1", "G3");
|
|
assertExists("Z1", "G3", "u2", "g4", "g5");
|
|
assertExists("Z1", "g4");
|
|
assertExists("Z1", "g5");
|
|
assertExists("Z2", "U3");
|
|
assertExists("Z2", "U4");
|
|
assertExists("Z2", "U5");
|
|
assertExists("Z2", "G2", "U3", "U4");
|
|
assertExists("Z2", "G6", "U3", "U4", "G7");
|
|
assertExists("Z2", "G7", "U5");
|
|
|
|
// Make sure the original people have been preserved
|
|
assertEquals(personNodes.get("u1"), ChainingUserRegistrySynchronizerTest.this.personService.getPerson(
|
|
"U1", false));
|
|
assertEquals(personNodes.get("u2"), ChainingUserRegistrySynchronizerTest.this.personService.getPerson(
|
|
"U2", false));
|
|
assertEquals(personNodes.get("u6"), ChainingUserRegistrySynchronizerTest.this.personService.getPerson(
|
|
"U6", false));
|
|
return null;
|
|
}
|
|
}, false, true);
|
|
|
|
tearDownTestUsersAndGroups();
|
|
}
|
|
|
|
/**
|
|
* Tests synchronization with a zone with a larger volume of authorities.
|
|
*
|
|
* @throws Exception
|
|
* the exception
|
|
*/
|
|
public void testVolume() throws Exception
|
|
{
|
|
List<NodeDescription> persons = new ArrayList<NodeDescription>(new RandomPersonCollection(100));
|
|
List<NodeDescription> groups = new ArrayList<NodeDescription>(new RandomGroupCollection(50, persons));
|
|
this.applicationContextManager.setUserRegistries(new MockUserRegistry("Z0", persons, groups));
|
|
this.synchronizer.synchronize(true, true, true);
|
|
tearDownTestUsersAndGroups();
|
|
}
|
|
|
|
/**
|
|
* Tests synchronization of group associations in a zone with a larger volume of authorities.
|
|
*
|
|
* @throws Exception
|
|
* the exception
|
|
*/
|
|
public void dontTestAssocs() throws Exception
|
|
{
|
|
List<NodeDescription> groups = this.retryingTransactionHelper.doInTransaction(
|
|
new RetryingTransactionCallback<List<NodeDescription>>()
|
|
{
|
|
|
|
public List<NodeDescription> execute() throws Throwable
|
|
{
|
|
return new ArrayList<NodeDescription>(new RandomGroupCollection(1000,
|
|
ChainingUserRegistrySynchronizerTest.this.authorityService.getAllAuthoritiesInZone(
|
|
AuthorityService.ZONE_AUTH_EXT_PREFIX + "Z0", null)));
|
|
}
|
|
}, true, true);
|
|
ChainingUserRegistrySynchronizerTest.this.applicationContextManager.setUserRegistries(new MockUserRegistry(
|
|
"Z0", Collections.<NodeDescription> emptyList(), groups));
|
|
ChainingUserRegistrySynchronizerTest.this.synchronizer.synchronize(true, true, true);
|
|
tearDownTestUsersAndGroups();
|
|
}
|
|
|
|
/**
|
|
* Constructs a description of a test group.
|
|
*
|
|
* @param name
|
|
* the name
|
|
* @param members
|
|
* the members
|
|
* @return the node description
|
|
*/
|
|
private NodeDescription newGroup(String name, String... members)
|
|
{
|
|
return newGroupWithDisplayName(name, name, members);
|
|
}
|
|
|
|
/**
|
|
* Constructs a description of a test group with a display name.
|
|
*
|
|
* @param name
|
|
* the name
|
|
* @param displayName
|
|
* the display name
|
|
* @param members
|
|
* the members
|
|
* @return the node description
|
|
*/
|
|
private NodeDescription newGroupWithDisplayName(String name, String displayName, String... members)
|
|
{
|
|
String longName = longName(name);
|
|
NodeDescription group = new NodeDescription(longName);
|
|
PropertyMap properties = group.getProperties();
|
|
properties.put(ContentModel.PROP_AUTHORITY_NAME, longName);
|
|
properties.put(ContentModel.PROP_AUTHORITY_DISPLAY_NAME, displayName);
|
|
if (members.length > 0)
|
|
{
|
|
Set<String> assocs = group.getChildAssociations();
|
|
for (String member : members)
|
|
{
|
|
assocs.add(longName(member));
|
|
}
|
|
}
|
|
group.setLastModified(new Date());
|
|
return group;
|
|
}
|
|
|
|
/**
|
|
* Constructs a description of a test person with default email (userName@alfresco.com)
|
|
*
|
|
* @param userName
|
|
* the user name
|
|
* @return the node description
|
|
*/
|
|
private NodeDescription newPerson(String userName)
|
|
{
|
|
return newPerson(userName, userName + "@alfresco.com");
|
|
}
|
|
|
|
/**
|
|
* Constructs a description of a test person with a given email.
|
|
*
|
|
* @param userName
|
|
* the user name
|
|
* @param email
|
|
* the email
|
|
* @return the node description
|
|
*/
|
|
private NodeDescription newPerson(String userName, String email)
|
|
{
|
|
NodeDescription person = new NodeDescription(userName);
|
|
PropertyMap properties = person.getProperties();
|
|
properties.put(ContentModel.PROP_USERNAME, userName);
|
|
properties.put(ContentModel.PROP_FIRSTNAME, userName + "F");
|
|
properties.put(ContentModel.PROP_LASTNAME, userName + "L");
|
|
properties.put(ContentModel.PROP_EMAIL, email);
|
|
person.setLastModified(new Date());
|
|
return person;
|
|
}
|
|
|
|
/**
|
|
* Perform all the necessary assertions to ensure that an authority and its members exist in the correct zone.
|
|
*
|
|
* @param zone
|
|
* the zone
|
|
* @param name
|
|
* the name
|
|
* @param members
|
|
* the members
|
|
*/
|
|
private void assertExists(String zone, String name, String... members)
|
|
{
|
|
String longName = longName(name);
|
|
// Check authority exists
|
|
assertTrue(this.authorityService.authorityExists(longName));
|
|
|
|
// Check in correct zone
|
|
assertTrue(this.authorityService.getAuthorityZones(longName).contains(
|
|
AuthorityService.ZONE_AUTH_EXT_PREFIX + zone));
|
|
if (AuthorityType.getAuthorityType(longName).equals(AuthorityType.GROUP))
|
|
{
|
|
// Check groups have expected members
|
|
Set<String> memberSet = new HashSet<String>(members.length * 2);
|
|
for (String member : members)
|
|
{
|
|
memberSet.add(longName(member));
|
|
}
|
|
assertEquals(memberSet, this.authorityService.getContainedAuthorities(null, longName, true));
|
|
}
|
|
else
|
|
{
|
|
// Check users exist as persons
|
|
assertTrue(this.personService.personExists(name));
|
|
|
|
// Check case matches
|
|
assertEquals(this.personService.getUserIdentifier(name), name);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Perform all the necessary assertions to ensure that an authority does not exist.
|
|
*
|
|
* @param name
|
|
* the name
|
|
*/
|
|
private void assertNotExists(String name)
|
|
{
|
|
String longName = longName(name);
|
|
// Check authority does not exist
|
|
assertFalse(this.authorityService.authorityExists(longName));
|
|
|
|
// Check there is no zone
|
|
assertNull(this.authorityService.getAuthorityZones(longName));
|
|
if (!AuthorityType.getAuthorityType(longName).equals(AuthorityType.GROUP))
|
|
{
|
|
// Check person does not exist
|
|
assertFalse(this.personService.personExists(name));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Asserts that a person's email has the expected value.
|
|
*
|
|
* @param personName
|
|
* the person name
|
|
* @param email
|
|
* the email
|
|
*/
|
|
private void assertEmailEquals(String personName, String email)
|
|
{
|
|
NodeRef personRef = this.personService.getPerson(personName);
|
|
assertEquals(email, this.nodeService.getProperty(personRef, ContentModel.PROP_EMAIL));
|
|
}
|
|
|
|
/**
|
|
* Asserts that a group's display name has the expected value.
|
|
*
|
|
* @param personName
|
|
* the person name
|
|
* @param email
|
|
* the email
|
|
*/
|
|
private void assertGroupDisplayNameEquals(String name, String displayName)
|
|
{
|
|
assertEquals(displayName, this.authorityService.getAuthorityDisplayName(longName(name)));
|
|
}
|
|
|
|
/**
|
|
* Converts the given short name to a full authority name, assuming that those short names beginning with 'G'
|
|
* correspond to groups and all others correspond to users.
|
|
*
|
|
* @param shortName
|
|
* the short name
|
|
* @return the full authority name
|
|
*/
|
|
private String longName(String shortName)
|
|
{
|
|
return this.authorityService.getName(shortName.toLowerCase().startsWith("g") ? AuthorityType.GROUP
|
|
: AuthorityType.USER, shortName);
|
|
}
|
|
|
|
/**
|
|
* A Mock {@link UserRegistry} that returns a fixed set of users and groups.
|
|
*/
|
|
public static class MockUserRegistry implements UserRegistry
|
|
{
|
|
|
|
/** The zone id. */
|
|
private String zoneId;
|
|
|
|
/** The persons. */
|
|
private Collection<NodeDescription> persons;
|
|
|
|
/** The groups. */
|
|
private Collection<NodeDescription> groups;
|
|
|
|
/**
|
|
* Instantiates a new mock user registry.
|
|
*
|
|
* @param zoneId
|
|
* the zone id
|
|
* @param persons
|
|
* the persons
|
|
* @param groups
|
|
* the groups
|
|
*/
|
|
public MockUserRegistry(String zoneId, Collection<NodeDescription> persons, Collection<NodeDescription> groups)
|
|
{
|
|
this.zoneId = zoneId;
|
|
this.persons = persons;
|
|
this.groups = groups;
|
|
}
|
|
|
|
/**
|
|
* Modifies the state to match the arguments. Compares new with old and records new modification dates only for
|
|
* changes.
|
|
*
|
|
* @param persons
|
|
* the persons
|
|
* @param groups
|
|
* the groups
|
|
*/
|
|
public void updateState(Collection<NodeDescription> persons, Collection<NodeDescription> groups)
|
|
{
|
|
List<NodeDescription> newPersons = new ArrayList<NodeDescription>(this.persons);
|
|
mergeNodeDescriptions(newPersons, persons, ContentModel.PROP_USERNAME, false);
|
|
this.persons = newPersons;
|
|
|
|
List<NodeDescription> newGroups = new ArrayList<NodeDescription>(this.groups);
|
|
mergeNodeDescriptions(newGroups, groups, ContentModel.PROP_AUTHORITY_NAME, true);
|
|
this.groups = newGroups;
|
|
}
|
|
|
|
/**
|
|
* Merges together an old and new list of node descriptions. Retains the old node with its old modification date
|
|
* if it is the same in the new list, otherwises uses the node from the new list.
|
|
*
|
|
* @param oldNodes
|
|
* the old node list
|
|
* @param newNodes
|
|
* the new node list
|
|
* @param idProp
|
|
* the name of the ID property
|
|
* @param caseSensitive
|
|
* are IDs case sensitive?
|
|
*/
|
|
private void mergeNodeDescriptions(List<NodeDescription> oldNodes, Collection<NodeDescription> newNodes,
|
|
QName idProp, boolean caseSensitive)
|
|
{
|
|
Map<String, NodeDescription> nodeMap = new LinkedHashMap<String, NodeDescription>(newNodes.size() * 2);
|
|
for (NodeDescription node : newNodes)
|
|
{
|
|
String id = (String) node.getProperties().get(idProp);
|
|
if (!caseSensitive)
|
|
{
|
|
id = id.toLowerCase();
|
|
}
|
|
nodeMap.put(id, node);
|
|
}
|
|
for (int i = 0; i < oldNodes.size(); i++)
|
|
{
|
|
NodeDescription oldNode = oldNodes.get(i);
|
|
String id = (String) oldNode.getProperties().get(idProp);
|
|
if (!caseSensitive)
|
|
{
|
|
id = id.toLowerCase();
|
|
}
|
|
NodeDescription newNode = nodeMap.remove(id);
|
|
if (newNode == null)
|
|
{
|
|
oldNodes.remove(i);
|
|
i--;
|
|
}
|
|
else if (!oldNode.getProperties().equals(newNode.getProperties())
|
|
|| !oldNode.getChildAssociations().equals(newNode.getChildAssociations()))
|
|
{
|
|
oldNodes.set(i, newNode);
|
|
}
|
|
}
|
|
oldNodes.addAll(nodeMap.values());
|
|
}
|
|
|
|
/**
|
|
* Instantiates a new mock user registry.
|
|
*
|
|
* @param zoneId
|
|
* the zone id
|
|
* @param persons
|
|
* the persons
|
|
* @param groups
|
|
* the groups
|
|
*/
|
|
public MockUserRegistry(String zoneId, NodeDescription[] persons, NodeDescription[] groups)
|
|
{
|
|
this(zoneId, Arrays.asList(persons), Arrays.asList(groups));
|
|
}
|
|
|
|
/**
|
|
* Gets the zone id.
|
|
*
|
|
* @return the zoneId
|
|
*/
|
|
public String getZoneId()
|
|
{
|
|
return this.zoneId;
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
* @see org.alfresco.repo.security.sync.UserRegistry#getGroupNames()
|
|
*/
|
|
public Collection<String> getGroupNames()
|
|
{
|
|
List<String> groupNames = new LinkedList<String>();
|
|
for (NodeDescription group : this.groups)
|
|
{
|
|
groupNames.add((String) group.getProperties().get(ContentModel.PROP_AUTHORITY_NAME));
|
|
}
|
|
return groupNames;
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
* @see org.alfresco.repo.security.sync.UserRegistry#getPersonNames()
|
|
*/
|
|
public Collection<String> getPersonNames()
|
|
{
|
|
List<String> personNames = new LinkedList<String>();
|
|
for (NodeDescription person : this.persons)
|
|
{
|
|
personNames.add((String) person.getProperties().get(ContentModel.PROP_USERNAME));
|
|
}
|
|
return personNames;
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
* @see org.alfresco.repo.security.sync.UserRegistry#getGroups(java.util.Date)
|
|
*/
|
|
public Collection<NodeDescription> getGroups(Date modifiedSince)
|
|
{
|
|
return filterNodeDescriptions(this.groups, modifiedSince);
|
|
}
|
|
|
|
/**
|
|
* Filters the given list of node descriptions, retaining only those with a modification date greater than the
|
|
* given date.
|
|
*
|
|
* @param nodes
|
|
* the list of nodes
|
|
* @param modifiedSince
|
|
* the modified date
|
|
* @return the filter list of nodes
|
|
*/
|
|
private Collection<NodeDescription> filterNodeDescriptions(Collection<NodeDescription> nodes, Date modifiedSince)
|
|
{
|
|
if (modifiedSince == null)
|
|
{
|
|
return nodes;
|
|
}
|
|
List<NodeDescription> filteredNodes = new LinkedList<NodeDescription>();
|
|
for (NodeDescription node : nodes)
|
|
{
|
|
Date modified = node.getLastModified();
|
|
if (modifiedSince.compareTo(modified) < 0)
|
|
{
|
|
filteredNodes.add(node);
|
|
}
|
|
}
|
|
return filteredNodes;
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
* @see org.alfresco.repo.security.sync.UserRegistry#getPersons(java.util.Date)
|
|
*/
|
|
public Collection<NodeDescription> getPersons(Date modifiedSince)
|
|
{
|
|
return filterNodeDescriptions(this.persons, modifiedSince);
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
* @see org.alfresco.repo.security.sync.UserRegistry#getPersonMappedProperties()
|
|
*/
|
|
public Set<QName> getPersonMappedProperties()
|
|
{
|
|
return new HashSet<QName>(Arrays.asList(new QName[]
|
|
{
|
|
ContentModel.PROP_USERNAME, ContentModel.PROP_FIRSTNAME, ContentModel.PROP_LASTNAME,
|
|
ContentModel.PROP_EMAIL, ContentModel.PROP_ORGID, ContentModel.PROP_ORGANIZATION,
|
|
ContentModel.PROP_HOME_FOLDER_PROVIDER
|
|
}));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* An {@link ChildApplicationContextManager} for a chain of application contexts containing mock user registries.
|
|
*/
|
|
public static class MockApplicationContextManager implements ChildApplicationContextManager
|
|
{
|
|
|
|
/** The contexts. */
|
|
private Map<String, ApplicationContext> contexts = Collections.emptyMap();
|
|
|
|
/**
|
|
* Sets the user registries.
|
|
*
|
|
* @param registries
|
|
* the new user registries
|
|
*/
|
|
public void setUserRegistries(MockUserRegistry... registries)
|
|
{
|
|
this.contexts = new LinkedHashMap<String, ApplicationContext>(registries.length * 2);
|
|
for (MockUserRegistry registry : registries)
|
|
{
|
|
StaticApplicationContext context = new StaticApplicationContext();
|
|
context.getDefaultListableBeanFactory().registerSingleton("userRegistry", registry);
|
|
this.contexts.put(registry.getZoneId(), context);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes the application context for the given zone ID (simulating a change in the authentication chain).
|
|
*
|
|
* @param zoneId
|
|
* the zone id
|
|
*/
|
|
public void removeZone(String zoneId)
|
|
{
|
|
this.contexts.remove(zoneId);
|
|
}
|
|
|
|
/**
|
|
* Updates the state of the given zone ID, oopying in new modification dates only where changes have been made.
|
|
*
|
|
* @param zoneId
|
|
* the zone id
|
|
* @param persons
|
|
* the new list of persons
|
|
* @param groups
|
|
* the new list of groups
|
|
*/
|
|
public void updateZone(String zoneId, NodeDescription[] persons, NodeDescription[] groups)
|
|
{
|
|
ApplicationContext context = this.contexts.get(zoneId);
|
|
MockUserRegistry registry = (MockUserRegistry) context.getBean("userRegistry");
|
|
registry.updateState(Arrays.asList(persons), Arrays.asList(groups));
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
* @see
|
|
* org.alfresco.repo.management.subsystems.ChildApplicationContextManager#getApplicationContext(java.lang.String
|
|
* )
|
|
*/
|
|
public ApplicationContext getApplicationContext(String id)
|
|
{
|
|
return this.contexts.get(id);
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
* @see org.alfresco.repo.management.subsystems.ChildApplicationContextManager#getInstanceIds()
|
|
*/
|
|
public Collection<String> getInstanceIds()
|
|
{
|
|
return this.contexts.keySet();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A collection whose iterator returns randomly generated persons.
|
|
*/
|
|
public class RandomPersonCollection extends AbstractCollection<NodeDescription>
|
|
{
|
|
|
|
/** The collection size. */
|
|
private final int size;
|
|
|
|
/**
|
|
* The Constructor.
|
|
*
|
|
* @param size
|
|
* the collection size
|
|
*/
|
|
public RandomPersonCollection(int size)
|
|
{
|
|
this.size = size;
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
* @see java.util.AbstractCollection#iterator()
|
|
*/
|
|
@Override
|
|
public Iterator<NodeDescription> iterator()
|
|
{
|
|
return new Iterator<NodeDescription>()
|
|
{
|
|
|
|
private int pos;
|
|
|
|
public boolean hasNext()
|
|
{
|
|
return this.pos < RandomPersonCollection.this.size;
|
|
}
|
|
|
|
public NodeDescription next()
|
|
{
|
|
this.pos++;
|
|
return newPerson("U" + GUID.generate());
|
|
}
|
|
|
|
public void remove()
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
* @see java.util.AbstractCollection#size()
|
|
*/
|
|
@Override
|
|
public int size()
|
|
{
|
|
return this.size;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* A collection whose iterator returns randomly generated groups with random associations to a given list of
|
|
* persons.
|
|
*/
|
|
public class RandomGroupCollection extends AbstractCollection<NodeDescription>
|
|
{
|
|
/** Use a fixed seed to give this class deterministic behaviour */
|
|
private Random generator = new Random(1628876500L);
|
|
|
|
/** The collection size. */
|
|
private final int size;
|
|
|
|
/** The authorities. */
|
|
private final List<String> authorities;
|
|
|
|
/**
|
|
* The Constructor.
|
|
*
|
|
* @param size
|
|
* the collection size
|
|
* @param authorities
|
|
* the authorities
|
|
*/
|
|
public RandomGroupCollection(int size, Set<String> authorities)
|
|
{
|
|
this.size = size;
|
|
this.authorities = new ArrayList<String>(authorities);
|
|
}
|
|
|
|
/**
|
|
* The Constructor.
|
|
*
|
|
* @param size
|
|
* the collection size
|
|
* @param authorities
|
|
* the authorities
|
|
*/
|
|
public RandomGroupCollection(int size, Collection<NodeDescription> persons)
|
|
{
|
|
this.size = size;
|
|
this.authorities = new ArrayList<String>(persons.size());
|
|
for (NodeDescription nodeDescription : persons)
|
|
{
|
|
this.authorities.add((String) nodeDescription.getProperties().get(ContentModel.PROP_USERNAME));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
* @see java.util.AbstractCollection#iterator()
|
|
*/
|
|
@Override
|
|
public Iterator<NodeDescription> iterator()
|
|
{
|
|
return new Iterator<NodeDescription>()
|
|
{
|
|
|
|
private int pos;
|
|
|
|
public boolean hasNext()
|
|
{
|
|
return this.pos < RandomGroupCollection.this.size;
|
|
}
|
|
|
|
public NodeDescription next()
|
|
{
|
|
this.pos++;
|
|
String[] authorityNames = new String[17];
|
|
for (int i = 0; i < authorityNames.length; i++)
|
|
{
|
|
// Choose an authority at random from the list of known authorities
|
|
int index = RandomGroupCollection.this.generator.nextInt(RandomGroupCollection.this.authorities
|
|
.size());
|
|
authorityNames[i] = ChainingUserRegistrySynchronizerTest.this.authorityService
|
|
.getShortName((String) RandomGroupCollection.this.authorities.get(index));
|
|
}
|
|
NodeDescription group = newGroup("G" + GUID.generate(), authorityNames);
|
|
// Make this group a candidate for adding to other groups
|
|
RandomGroupCollection.this.authorities.add((String) group.getProperties().get(
|
|
ContentModel.PROP_AUTHORITY_NAME));
|
|
return group;
|
|
}
|
|
|
|
public void remove()
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
* @see java.util.AbstractCollection#size()
|
|
*/
|
|
@Override
|
|
public int size()
|
|
{
|
|
return this.size;
|
|
}
|
|
|
|
}
|
|
|
|
}
|