diff --git a/config/alfresco/subsystems/Synchronization/default/default-synchronization-context.xml b/config/alfresco/subsystems/Synchronization/default/default-synchronization-context.xml
index 6ad115a104..acae1ea4a4 100644
--- a/config/alfresco/subsystems/Synchronization/default/default-synchronization-context.xml
+++ b/config/alfresco/subsystems/Synchronization/default/default-synchronization-context.xml
@@ -80,6 +80,9 @@
${synchronization.allowDeletions}
+
+ ${synchronization.syncDelete}
+
diff --git a/config/alfresco/subsystems/Synchronization/default/default-synchronization.properties b/config/alfresco/subsystems/Synchronization/default/default-synchronization.properties
index 069822fb7c..c39f598559 100644
--- a/config/alfresco/subsystems/Synchronization/default/default-synchronization.properties
+++ b/config/alfresco/subsystems/Synchronization/default/default-synchronization.properties
@@ -30,4 +30,7 @@ synchronization.loggingInterval=100
synchronization.workerThreads=1
# Synchronization with deletions
-synchronization.allowDeletions=true
\ No newline at end of file
+synchronization.allowDeletions=true
+
+# For large LDAP directories the delete query is expensive and time consuming, needing to read the entire LDAP directory.
+synchronization.syncDelete=true
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java b/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java
index 3d655471f8..52e05139c8 100644
--- a/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java
+++ b/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java
@@ -180,6 +180,9 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean
/** Allow a full sync to perform deletions? */
private boolean allowDeletions = true;
+
+ /** Controls whether to query for users and groups that have been deleted in LDAP */
+ private boolean syncDelete = true;
/** Validates person names over cm:filename constraint **/
private NameChecker nameChecker;
@@ -350,14 +353,30 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean
}
/**
- * Fullsync is run with deletions. By default is set to true.
+ * Controls how deleted users and groups are handled.
+ * By default is set to true.
*
* @param allowDeletions
+ * If true the entries are deleted from alfresco.
+ * If false then they are unlinked from their LDAP authentication zone but remain within alfresco.
*/
public void setAllowDeletions(boolean allowDeletions)
{
this.allowDeletions = allowDeletions;
}
+
+ /**
+ * Controls whether to query for users and groups that have been deleted in LDAP.
+ * For large LDAP directories the delete query is expensive and time consuming, needing to read the entire LDAP directory.
+ * By default is set to true.
+ *
+ * @param syncDelete
+ * If false then LDAP sync does not even attempt to search for deleted users.
+ */
+ public void setSyncDelete(boolean syncDelete)
+ {
+ this.syncDelete = syncDelete;
+ }
@Override
public SynchronizeDiagnostic testSynchronize(String authenticatorName)
@@ -1425,9 +1444,8 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean
private void processGroups(UserRegistry userRegistry, boolean isFullSync, boolean splitTxns)
{
- // If we got back some groups, we have to cross reference them with the set of known authorities
- // MNT-9711 fix. If allowDeletions is false, there is no need to pull all users and all groups from LDAP during the full synchronization.
- if ((allowDeletions || !groupsToCreate.isEmpty()) && (isFullSync || !this.groupParentAssocsToDelete.isEmpty()))
+ // MNT-12454 fix. If syncDelete is false, there is no need to pull all users and all groups from LDAP during the full synchronization.
+ if ((syncDelete || !groupsToCreate.isEmpty()) && (isFullSync || !this.groupParentAssocsToDelete.isEmpty()))
{
final Set allZonePersons = newPersonSet();
final Set allZoneGroups = new TreeSet();
@@ -1473,8 +1491,41 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean
this.deletionCandidates.addAll(personDeletionCandidates);
this.deletionCandidates.addAll(groupDeletionCandidates);
- allZonePersons.removeAll(personDeletionCandidates);
- allZoneGroups.removeAll(groupDeletionCandidates);
+ if (allowDeletions)
+ {
+ allZonePersons.removeAll(personDeletionCandidates);
+ allZoneGroups.removeAll(groupDeletionCandidates);
+ }
+ else
+ {
+ // Complete association deletion information by scanning deleted groups
+ BatchProcessor groupScanner = new BatchProcessor(zone
+ + " Missing Authority Scanning",
+ ChainingUserRegistrySynchronizer.this.transactionService.getRetryingTransactionHelper(),
+ this.deletionCandidates,
+ ChainingUserRegistrySynchronizer.this.workerThreads, 20,
+ ChainingUserRegistrySynchronizer.this.applicationEventPublisher,
+ ChainingUserRegistrySynchronizer.logger,
+ ChainingUserRegistrySynchronizer.this.loggingInterval);
+ groupScanner.process(new BaseBatchProcessWorker()
+ {
+
+ @Override
+ public String getIdentifier(String entry)
+ {
+ return entry;
+ }
+
+ @Override
+ public void process(String authority) throws Throwable
+ {
+ //MNT-12454 fix. Modifies an authority's zone. Move authority from AUTH.EXT.LDAP1 to AUTH.ALF.
+ updateAuthorityZones(authority, Collections.singleton(zoneId),
+ Collections.singleton(AuthorityService.ZONE_AUTH_ALFRESCO));
+ }
+ }, splitTxns);
+ }
+
}
// Prune the group associations now that we have complete information
diff --git a/source/test-java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizerTest.java b/source/test-java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizerTest.java
index e603ab3f7a..5723d10ee6 100644
--- a/source/test-java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizerTest.java
+++ b/source/test-java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizerTest.java
@@ -432,8 +432,8 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
public Object execute() throws Throwable
{
- // MNT-9711 fix. User U6 already exists in zone "Z0". According ChainingUserRegistrySynchronizercurrent
- // implementation when allowDeletions==false person that exists in a different zone with higher
+ // MNT-13867 fix. User U6 already exists in zone "Z0". According ChainingUserRegistrySynchronizercurrent
+ // implementation when syncDelete==false person that exists in a different zone with higher
// precedence will be ignored
assertExists("Z0", "U6");
assertExists("Z1", "U1");
@@ -797,8 +797,10 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
// Check in correct zone
if (zone == null)
{
- assertEquals(Collections.singleton(AuthorityService.ZONE_APP_DEFAULT), this.authorityService
- .getAuthorityZones(longName));
+ Set zones = new TreeSet();
+ zones.add(AuthorityService.ZONE_APP_DEFAULT);
+ zones.add(AuthorityService.ZONE_AUTH_ALFRESCO);
+ assertEquals(zones, this.authorityService.getAuthorityZones(longName));
}
else
{
diff --git a/source/test-resources/sync-test-context.xml b/source/test-resources/sync-test-context.xml
index 47bec0188d..63cd994814 100644
--- a/source/test-resources/sync-test-context.xml
+++ b/source/test-resources/sync-test-context.xml
@@ -64,6 +64,9 @@
false
+
+ false
+