diff --git a/config/alfresco/subsystems/Authentication/common-ldap-context.xml b/config/alfresco/subsystems/Authentication/common-ldap-context.xml
index 814c0df702..f952714f00 100644
--- a/config/alfresco/subsystems/Authentication/common-ldap-context.xml
+++ b/config/alfresco/subsystems/Authentication/common-ldap-context.xml
@@ -93,6 +93,9 @@
+
+
+
+
+
+
+
+
+
+ ${ldap.synchronization.userAccountStatusProperty}
+
diff --git a/config/alfresco/subsystems/Authentication/ldap-ad/ldap-ad-authentication-context.xml b/config/alfresco/subsystems/Authentication/ldap-ad/ldap-ad-authentication-context.xml
index 05442f1f66..f42893167f 100644
--- a/config/alfresco/subsystems/Authentication/ldap-ad/ldap-ad-authentication-context.xml
+++ b/config/alfresco/subsystems/Authentication/ldap-ad/ldap-ad-authentication-context.xml
@@ -7,4 +7,8 @@
defaults
-->
+
+
+
+
\ No newline at end of file
diff --git a/config/alfresco/subsystems/Authentication/ldap-ad/ldap-ad-authentication.properties b/config/alfresco/subsystems/Authentication/ldap-ad/ldap-ad-authentication.properties
index c719ba8d9b..ffbde08c1a 100644
--- a/config/alfresco/subsystems/Authentication/ldap-ad/ldap-ad-authentication.properties
+++ b/config/alfresco/subsystems/Authentication/ldap-ad/ldap-ad-authentication.properties
@@ -165,4 +165,10 @@ ldap.pooling.com.sun.jndi.ldap.connect.pool.protocol=plain
ldap.pooling.com.sun.jndi.ldap.connect.pool.timeout=
# The string representation of an integer that represents the number of milliseconds to specify how long to wait for a pooled connection. If you omit this property, the application will wait indefinitely.
-ldap.pooling.com.sun.jndi.ldap.connect.timeout=
\ No newline at end of file
+ldap.pooling.com.sun.jndi.ldap.connect.timeout=
+
+# LDAP-AD property name for user enabled/disabled status
+ldap.synchronization.userAccountStatusProperty=userAccountControl
+
+# The Account Status Interpreter bean name
+ldap.synchronization.userAccountStatusInterpreter=ldapadUserAccountStatusInterpreter
diff --git a/config/alfresco/subsystems/Authentication/ldap/ldap-authentication-context.xml b/config/alfresco/subsystems/Authentication/ldap/ldap-authentication-context.xml
index 05442f1f66..6bbaeb3699 100644
--- a/config/alfresco/subsystems/Authentication/ldap/ldap-authentication-context.xml
+++ b/config/alfresco/subsystems/Authentication/ldap/ldap-authentication-context.xml
@@ -7,4 +7,14 @@
defaults
-->
+
+
+
+
+ ${ldap.synchronization.disabledAccountPropertyValue}
+
+
+ ${ldap.synchronization.disabledAccountPropertyValueCanBeNull}
+
+
\ No newline at end of file
diff --git a/config/alfresco/subsystems/Authentication/ldap/ldap-authentication.properties b/config/alfresco/subsystems/Authentication/ldap/ldap-authentication.properties
index 4fdc64b6db..3c509c0bdc 100644
--- a/config/alfresco/subsystems/Authentication/ldap/ldap-authentication.properties
+++ b/config/alfresco/subsystems/Authentication/ldap/ldap-authentication.properties
@@ -172,4 +172,20 @@ ldap.pooling.com.sun.jndi.ldap.connect.pool.timeout=
# The string representation of an integer that represents the number of milliseconds to specify how long to wait for a pooled connection.
# Empty value means the application will wait indefinitely.
-ldap.pooling.com.sun.jndi.ldap.connect.timeout=
\ No newline at end of file
+ldap.pooling.com.sun.jndi.ldap.connect.timeout=
+
+# Enabled/disabled status - there is no standard way to check for this;
+# "nsAccountLock" is used by most NDS derived directory systems (Oracle / Red Hat / 389 DS);
+# For OpenLDAP you may want to specify "pwdAccountLockedTime" instead
+ldap.synchronization.userAccountStatusProperty=nsAccountLock
+
+# Expected value for disabled account;
+# For NDS directory servers: nsAccountLock=true
+# For OpenLDAP: pwdAccountLockedTime=000001010000Z
+ldap.synchronization.disabledAccountPropertyValue=true
+
+# Some directory servers may not send a status value at all if account is enabled
+ldap.synchronization.disabledAccountPropertyValueCanBeNull=true
+
+# The Account Status Interpreter bean name
+ldap.synchronization.userAccountStatusInterpreter=ldapUserAccountStatusInterpreter
diff --git a/config/alfresco/subsystems/Synchronization/default/default-synchronization-context.xml b/config/alfresco/subsystems/Synchronization/default/default-synchronization-context.xml
index acae1ea4a4..f76aaa578d 100644
--- a/config/alfresco/subsystems/Synchronization/default/default-synchronization-context.xml
+++ b/config/alfresco/subsystems/Synchronization/default/default-synchronization-context.xml
@@ -84,6 +84,12 @@
${synchronization.syncDelete}
+
+ ${synchronization.externalUserControl}
+
+
+ ${synchronization.externalUserControlSubsystemName}
+
diff --git a/config/alfresco/subsystems/Synchronization/default/default-synchronization.properties b/config/alfresco/subsystems/Synchronization/default/default-synchronization.properties
index c39f598559..2490acf60e 100644
--- a/config/alfresco/subsystems/Synchronization/default/default-synchronization.properties
+++ b/config/alfresco/subsystems/Synchronization/default/default-synchronization.properties
@@ -33,4 +33,10 @@ synchronization.workerThreads=1
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
+synchronization.syncDelete=true
+
+# external setting (LDAP systems) - whether users can be enabled; if false then users have to be explicitly disabled in Alfresco
+synchronization.externalUserControl=false
+
+# Subsystem that will handle the external user control
+synchronization.externalUserControlSubsystemName=
diff --git a/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java b/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java
index 4357aea5ac..9e4b8e30a5 100644
--- a/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java
+++ b/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java
@@ -31,6 +31,7 @@ import java.util.Set;
import org.alfresco.repo.management.subsystems.ActivateableBean;
import org.alfresco.repo.security.authentication.AuthenticationComponent.UserNameValidationMode;
import org.alfresco.repo.tenant.TenantContextHolder;
+import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.util.Pair;
public class AuthenticationServiceImpl extends AbstractAuthenticationService implements ActivateableBean
@@ -42,7 +43,14 @@ public class AuthenticationServiceImpl extends AbstractAuthenticationService imp
private boolean allowsUserCreation = true;
private boolean allowsUserDeletion = true;
private boolean allowsUserPasswordChange = true;
-
+
+ private PersonService personService;
+
+ public void setPersonService(PersonService personService)
+ {
+ this.personService = personService;
+ }
+
public AuthenticationServiceImpl()
{
super();
@@ -336,6 +344,11 @@ public class AuthenticationServiceImpl extends AbstractAuthenticationService imp
*/
public boolean getAuthenticationEnabled(String userName) throws AuthenticationException
{
+ if (personService.personExists(userName))
+ {
+ return personService.isEnabled(userName);
+ }
+
return true;
}
}
diff --git a/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java b/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java
index 210f1dddfe..4fe954b60f 100644
--- a/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java
+++ b/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java
@@ -848,6 +848,9 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
properties.put(ContentModel.PROP_USERNAME, realUserName);
}
}
+
+ checkIfPersonShouldBeDisabledAndSetAspect(personNode, properties);
+
Map update = nodeService.getProperties(personNode);
update.putAll(properties);
@@ -987,6 +990,8 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
beforeCreateNodeValidationBehaviour.enable();
}
+ checkIfPersonShouldBeDisabledAndSetAspect(personRef, properties);
+
if (zones != null)
{
for (String zone : zones)
@@ -1004,6 +1009,26 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
return personRef;
}
+ private void checkIfPersonShouldBeDisabledAndSetAspect(NodeRef person, Map properties)
+ {
+ if (properties.get(ContentModel.PROP_ENABLED) != null)
+ {
+ boolean isEnabled = Boolean.parseBoolean(properties.get(ContentModel.PROP_ENABLED).toString());
+
+ if (isEnabled)
+ {
+ if (nodeService.hasAspect(person, ContentModel.ASPECT_PERSON_DISABLED))
+ {
+ nodeService.removeAspect(person, ContentModel.ASPECT_PERSON_DISABLED);
+ }
+ }
+ else
+ {
+ nodeService.addAspect(person, ContentModel.ASPECT_PERSON_DISABLED, null);
+ }
+ }
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java b/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java
index 6c64a3cf03..9908dcf979 100644
--- a/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java
+++ b/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java
@@ -39,6 +39,7 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.security.authentication.AuthenticatorDeletedEvent;
import org.alfresco.repo.security.authority.UnknownAuthorityException;
+import org.alfresco.repo.security.sync.ldap.LDAPUserRegistry;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
@@ -65,6 +66,7 @@ import org.springframework.extensions.surf.util.AbstractLifecycleBean;
import org.springframework.extensions.surf.util.I18NUtil;
import javax.management.*;
+
import java.io.IOException;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
@@ -195,6 +197,10 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean
private NameChecker nameChecker;
private SysAdminParams sysAdminParams;
+
+ private String externalUserControl = "";
+
+ private String externalUserControlSubsystemName = "";
public void init()
{
@@ -208,6 +214,16 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean
PropertyCheck.mandatory(this, "sysAdminParams", sysAdminParams);
}
+ public void setExternalUserControl(String externalUserControl)
+ {
+ this.externalUserControl = externalUserControl;
+ }
+
+ public void setExternalUserControlSubsystemName(String externalUserControlSubsystemName)
+ {
+ this.externalUserControlSubsystemName = externalUserControlSubsystemName;
+ }
+
/**
* Sets name checker
*/
@@ -1765,6 +1781,9 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean
this.applicationEventPublisher,
ChainingUserRegistrySynchronizer.logger,
this.loggingInterval);
+
+ final UserRegistry userRegistryFinalRef = userRegistry;
+
class PersonWorker extends BaseBatchProcessWorker
{
private long latestTime;
@@ -1790,6 +1809,36 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean
HashMap personProperties = new HashMap(person.getProperties());
String personName = personProperties.get(ContentModel.PROP_USERNAME).toString().trim();
personProperties.put(ContentModel.PROP_USERNAME, personName);
+
+ if (Boolean.parseBoolean(ChainingUserRegistrySynchronizer.this.externalUserControl)
+ && ChainingUserRegistrySynchronizer.this.externalUserControlSubsystemName.equals(zone)
+ && userRegistryFinalRef instanceof LDAPUserRegistry)
+ {
+ try
+ {
+ LDAPUserRegistry ldapUserRegistry = (LDAPUserRegistry) userRegistryFinalRef;
+
+ if (ldapUserRegistry.getUserAccountStatusInterpreter() != null)
+ {
+ QName propertyNameToCheck = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "userAccountStatusProperty");
+
+ if (personProperties.get(propertyNameToCheck) != null || ldapUserRegistry.getUserAccountStatusInterpreter().acceptsNullArgument())
+ {
+ boolean isUserAccountDisabled = ldapUserRegistry.getUserAccountStatusInterpreter().isUserAccountDisabled(
+ personProperties.get(propertyNameToCheck));
+
+ personProperties.put(ContentModel.PROP_ENABLED, !isUserAccountDisabled);
+ }
+ }
+ }
+ catch (IllegalArgumentException iae)
+ {
+ // Can be thrown by certain implementations of AbstractDirectoryServiceUserAccountStatusInterpreter;
+ // We'll just log it.
+ ChainingUserRegistrySynchronizer.logger.debug(iae.getMessage(), iae);
+ }
+ }
+
// for invalid names will throw ConstraintException that will be catched by BatchProcessor$TxnCallback
nameChecker.evaluate(personName);
Set zones = ChainingUserRegistrySynchronizer.this.authorityService
diff --git a/source/java/org/alfresco/repo/security/sync/ldap/AbstractDirectoryServiceUserAccountStatusInterpreter.java b/source/java/org/alfresco/repo/security/sync/ldap/AbstractDirectoryServiceUserAccountStatusInterpreter.java
new file mode 100644
index 0000000000..ce3c02c85c
--- /dev/null
+++ b/source/java/org/alfresco/repo/security/sync/ldap/AbstractDirectoryServiceUserAccountStatusInterpreter.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2005-2016 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 .
+ */
+package org.alfresco.repo.security.sync.ldap;
+
+import java.io.Serializable;
+
+public abstract class AbstractDirectoryServiceUserAccountStatusInterpreter
+{
+ public static final String USER_ACCOUNT_STATUS_NOT_NULL_MESSAGE = "User account status property value must not be null.";
+
+ protected void checkForNullArgument(Serializable arg)
+ {
+ if (arg == null)
+ {
+ throw new IllegalArgumentException(USER_ACCOUNT_STATUS_NOT_NULL_MESSAGE);
+ }
+ }
+
+ /**
+ * Check if directory server user account status is disabled.
+ *
+ * @param userAccountStatusValue
+ * value to interpret user account status from;
+ *
+ * @return true if interpreted as disabled, false otherwise
+ */
+ public abstract boolean isUserAccountDisabled(Serializable userAccountStatusValue) throws IllegalArgumentException;
+
+ /**
+ * Specify if the particular implementation of
+ * {@link AbstractDirectoryServiceUserAccountStatusInterpreter#isUserAccountDisabled(Serializable)}
+ * will accept null.
+ *
+ * @return true if accepts null.
+ */
+ public abstract boolean acceptsNullArgument();
+}
diff --git a/source/java/org/alfresco/repo/security/sync/ldap/LDAPUserAccountStatusInterpreter.java b/source/java/org/alfresco/repo/security/sync/ldap/LDAPUserAccountStatusInterpreter.java
new file mode 100644
index 0000000000..c3d4a99595
--- /dev/null
+++ b/source/java/org/alfresco/repo/security/sync/ldap/LDAPUserAccountStatusInterpreter.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2005-2016 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 .
+ */
+package org.alfresco.repo.security.sync.ldap;
+
+import java.io.Serializable;
+
+public class LDAPUserAccountStatusInterpreter extends AbstractDirectoryServiceUserAccountStatusInterpreter
+{
+ private String disabledAccountPropertyValue = "";
+ private boolean acceptNullArgument;
+
+ public void setDisabledAccountPropertyValue(String disabledAccountPropertyValue)
+ {
+ this.disabledAccountPropertyValue = disabledAccountPropertyValue;
+ }
+
+ public void setAcceptNullArgument(boolean acceptNullArgument)
+ {
+ this.acceptNullArgument = acceptNullArgument;
+ }
+
+ @Override
+ public boolean isUserAccountDisabled(Serializable userAccountStatus)
+ {
+ if (!acceptsNullArgument())
+ {
+ checkForNullArgument(userAccountStatus);
+ }
+
+ return userAccountStatus != null && userAccountStatus.toString().equalsIgnoreCase(disabledAccountPropertyValue);
+ }
+
+ @Override
+ public boolean acceptsNullArgument()
+ {
+ return acceptNullArgument;
+ }
+}
diff --git a/source/java/org/alfresco/repo/security/sync/ldap/LDAPUserRegistry.java b/source/java/org/alfresco/repo/security/sync/ldap/LDAPUserRegistry.java
index 2d6383eb1e..341df0c010 100644
--- a/source/java/org/alfresco/repo/security/sync/ldap/LDAPUserRegistry.java
+++ b/source/java/org/alfresco/repo/security/sync/ldap/LDAPUserRegistry.java
@@ -191,6 +191,9 @@ public class LDAPUserRegistry implements UserRegistry, LDAPNameResolver, Initial
/** The LDAP generalized time format. */
private DateFormat timestampFormat;
+ /** The LDAP User Account Status Property Interpreter */
+ private AbstractDirectoryServiceUserAccountStatusInterpreter userAccountStatusInterpreter;
+
/**
* Instantiates a new lDAP user registry.
*/
@@ -505,6 +508,16 @@ public class LDAPUserRegistry implements UserRegistry, LDAPNameResolver, Initial
this.attributeBatchSize = attributeBatchSize;
}
+ public void setUserAccountStatusInterpreter(AbstractDirectoryServiceUserAccountStatusInterpreter userAccountStatusInterpreter)
+ {
+ this.userAccountStatusInterpreter = userAccountStatusInterpreter;
+ }
+
+ public AbstractDirectoryServiceUserAccountStatusInterpreter getUserAccountStatusInterpreter()
+ {
+ return userAccountStatusInterpreter;
+ }
+
/*
* (non-Javadoc)
* @see org.alfresco.repo.management.subsystems.ActivateableBean#isActive()
diff --git a/source/java/org/alfresco/repo/security/sync/ldap_ad/LDAPADUserAccountStatusInterpreter.java b/source/java/org/alfresco/repo/security/sync/ldap_ad/LDAPADUserAccountStatusInterpreter.java
new file mode 100644
index 0000000000..8656099522
--- /dev/null
+++ b/source/java/org/alfresco/repo/security/sync/ldap_ad/LDAPADUserAccountStatusInterpreter.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2005-2016 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 .
+ */
+package org.alfresco.repo.security.sync.ldap_ad;
+
+import java.io.Serializable;
+
+import org.alfresco.repo.security.sync.ldap.AbstractDirectoryServiceUserAccountStatusInterpreter;
+
+public class LDAPADUserAccountStatusInterpreter extends AbstractDirectoryServiceUserAccountStatusInterpreter
+{
+ @Override
+ public boolean isUserAccountDisabled(Serializable userAccountStatusValue)
+ {
+ checkForNullArgument(userAccountStatusValue);
+
+ /*
+ * References:
+ * https://blogs.technet.microsoft.com/heyscriptingguy/2005/05/12/how-can-i-get-a-list-of-all-the-disabled-user-accounts-in-active-directory
+ * http://stackoverflow.com/questions/19250969/include-enabled-disabled-account-status-of-ldap-user-in-results/19252033#19252033
+ */
+ return ((Integer.parseInt(userAccountStatusValue.toString())) & 2) != 0;
+ }
+
+ @Override
+ public boolean acceptsNullArgument()
+ {
+ return false;
+ }
+}
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 b053ccfffc..ca0eedcd71 100644
--- a/source/test-java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizerTest.java
+++ b/source/test-java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizerTest.java
@@ -36,6 +36,10 @@ import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.security.person.PersonServiceImpl;
+import org.alfresco.repo.security.sync.ldap.AbstractDirectoryServiceUserAccountStatusInterpreter;
+import org.alfresco.repo.security.sync.ldap.LDAPUserAccountStatusInterpreter;
+import org.alfresco.repo.security.sync.ldap.LDAPUserRegistry;
+import org.alfresco.repo.security.sync.ldap_ad.LDAPADUserAccountStatusInterpreter;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -44,6 +48,7 @@ import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
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.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.GUID;
import org.alfresco.util.PropertyMap;
@@ -407,6 +412,135 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
tearDownTestUsersAndGroups();
}
+ private class MockLDAPUserRegistry extends LDAPUserRegistry implements IMockUserRegistry
+ {
+ MockUserRegistry mockUserRegistry;
+
+ public MockLDAPUserRegistry(MockUserRegistry mockUserRegistry)
+ {
+ this.mockUserRegistry = mockUserRegistry;
+ }
+
+ @Override
+ public void setActive(boolean active)
+ {
+ mockUserRegistry.setActive(active);
+ }
+
+ @Override
+ public boolean isActive()
+ {
+ return mockUserRegistry.isActive();
+ }
+
+ @Override
+ public Set getPersonMappedProperties()
+ {
+ return mockUserRegistry.getPersonMappedProperties();
+ }
+
+ @Override
+ public Collection getPersons(Date modifiedSince)
+ {
+ return mockUserRegistry.getPersons(modifiedSince);
+ }
+
+ @Override
+ public Collection getPersonNames()
+ {
+ return mockUserRegistry.getPersonNames();
+ }
+
+ @Override
+ public Collection getGroupNames()
+ {
+ return mockUserRegistry.getGroupNames();
+ }
+
+ @Override
+ public Collection getGroups(Date modifiedSince)
+ {
+ return mockUserRegistry.getGroups(modifiedSince);
+ }
+
+ @Override
+ public String getZoneId()
+ {
+ return mockUserRegistry.getZoneId();
+ }
+
+ @Override
+ public void updateState(Collection persons, Collection groups)
+ {
+ mockUserRegistry.updateState(persons, groups);
+ }
+ }
+
+ private void testLDAPDisableUserAccount(AbstractDirectoryServiceUserAccountStatusInterpreter userAccountStatusInterpreter,
+ String enabledAccountPropertyValue, String disabledAccountPropertyValue) throws Exception
+ {
+ MockUserRegistry mockUserRegistry = new MockUserRegistry("ldap1", new NodeDescription[] {
+ newPersonWithUserAccountStatusProperty("EnabledUser", enabledAccountPropertyValue),
+ newPersonWithUserAccountStatusProperty("DisabledUser", disabledAccountPropertyValue) }, new NodeDescription[] {});
+
+ MockLDAPUserRegistry mockLDAPUserRegistry = new MockLDAPUserRegistry(mockUserRegistry);
+ mockLDAPUserRegistry.setUserAccountStatusInterpreter(userAccountStatusInterpreter);
+
+ this.applicationContextManager.setUserRegistries(mockLDAPUserRegistry);
+
+ ChainingUserRegistrySynchronizer chainingSynchronizer = (ChainingUserRegistrySynchronizer) this.synchronizer;
+ chainingSynchronizer.setExternalUserControl("true");
+ chainingSynchronizer.setExternalUserControlSubsystemName("ldap1");
+
+ this.synchronizer.synchronize(false, false);
+
+ this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback