Merged 5.2.N (5.2.1) to HEAD (5.2)

125792 rmunteanu: Merged 5.1.N (5.1.2) to 5.2.N (5.2.1)
      125621 rmunteanu: Merged 5.0.N (5.0.4) to 5.1.N (5.1.2)
         125577 abalmus: MNT-15038 : Unexpected behavior when disabling Active Directory user (New feature to sync userAccountControl)
            - Implemented new requirements and tests


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@127813 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Alan Davis
2016-06-04 11:00:24 +00:00
parent bd2cf2c35d
commit b4576ce3ca
15 changed files with 491 additions and 22 deletions

View File

@@ -93,6 +93,9 @@
<property name="sysAdminParams">
<ref bean="sysAdminParams" />
</property>
<property name="personService">
<ref bean="PersonService" />
</property>
</bean>
<!--
@@ -365,6 +368,13 @@
<value>${ldap.synchronization.timestampFormat}</value>
</property>
<!--
The user account status property interpreter. Unfortunately, this varies between directory servers.
-->
<property name="userAccountStatusInterpreter">
<ref bean="${ldap.synchronization.userAccountStatusInterpreter}" />
</property>
<!--
An attribute that is a unique identifier for each group found.
This is also the name of the group with the current group implementation.
@@ -451,6 +461,12 @@
<entry key="cm:homeFolderProvider">
<null/>
</entry>
<entry key="cm:userAccountStatusProperty">
<!-- Oracle / Red Hat / 389 DS: "nsAccountLock"-->
<!-- OpenLDAP: "pwdAccountLockedTime" -->
<!-- Active Directory: "userAccountControl" -->
<value>${ldap.synchronization.userAccountStatusProperty}</value>
</entry>
</map>
</property>
<!-- Set a default home folder provider -->

View File

@@ -7,4 +7,8 @@
defaults
-->
<import resource="../common-ldap-context.xml" />
<!-- LDAP-AD User Account Status Interpreter -->
<bean id="ldapadUserAccountStatusInterpreter" class="org.alfresco.repo.security.sync.ldap_ad.LDAPADUserAccountStatusInterpreter">
</bean>
</beans>

View File

@@ -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=
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

View File

@@ -7,4 +7,14 @@
defaults
-->
<import resource="../common-ldap-context.xml" />
<!-- LDAP User Account Status Interpreter -->
<bean id="ldapUserAccountStatusInterpreter" class="org.alfresco.repo.security.sync.ldap.LDAPUserAccountStatusInterpreter">
<property name="disabledAccountPropertyValue">
<value>${ldap.synchronization.disabledAccountPropertyValue}</value>
</property>
<property name="acceptNullArgument">
<value>${ldap.synchronization.disabledAccountPropertyValueCanBeNull}</value>
</property>
</bean>
</beans>

View File

@@ -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=
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

View File

@@ -84,6 +84,12 @@
<value>${synchronization.syncDelete}</value>
</property>
<property name="nameChecker" ref="nameChecker" />
<property name="externalUserControl">
<value>${synchronization.externalUserControl}</value>
</property>
<property name="externalUserControlSubsystemName">
<value>${synchronization.externalUserControlSubsystemName}</value>
</property>
</bean>

View File

@@ -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
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=

View File

@@ -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;
}
}

View File

@@ -848,6 +848,9 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
properties.put(ContentModel.PROP_USERNAME, realUserName);
}
}
checkIfPersonShouldBeDisabledAndSetAspect(personNode, properties);
Map<QName, Serializable> 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<QName, Serializable> 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}
*/

View File

@@ -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<NodeDescription>
{
private long latestTime;
@@ -1790,6 +1809,36 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean
HashMap<QName, Serializable> personProperties = new HashMap<QName, Serializable>(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<String> zones = ChainingUserRegistrySynchronizer.this.authorityService

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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();
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@@ -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()

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@@ -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<QName> getPersonMappedProperties()
{
return mockUserRegistry.getPersonMappedProperties();
}
@Override
public Collection<NodeDescription> getPersons(Date modifiedSince)
{
return mockUserRegistry.getPersons(modifiedSince);
}
@Override
public Collection<String> getPersonNames()
{
return mockUserRegistry.getPersonNames();
}
@Override
public Collection<String> getGroupNames()
{
return mockUserRegistry.getGroupNames();
}
@Override
public Collection<NodeDescription> getGroups(Date modifiedSince)
{
return mockUserRegistry.getGroups(modifiedSince);
}
@Override
public String getZoneId()
{
return mockUserRegistry.getZoneId();
}
@Override
public void updateState(Collection<NodeDescription> persons, Collection<NodeDescription> 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<Object>()
{
public Object execute() throws Throwable
{
NodeRef enabledUserRef = ChainingUserRegistrySynchronizerTest.this.personService.getPerson("EnabledUser", false);
assertFalse(ChainingUserRegistrySynchronizerTest.this.nodeService.hasAspect(enabledUserRef, ContentModel.ASPECT_PERSON_DISABLED));
NodeRef disabledUserRef = ChainingUserRegistrySynchronizerTest.this.personService.getPerson("DisabledUser", false);
assertTrue(ChainingUserRegistrySynchronizerTest.this.nodeService.hasAspect(disabledUserRef, ContentModel.ASPECT_PERSON_DISABLED));
return null;
}
}, false, true);
}
public void testLDAPDisableUserAccountWithActiveDirectoryProperty() throws Exception
{
LDAPADUserAccountStatusInterpreter ldapadUserAccountStatusInterpreter = new LDAPADUserAccountStatusInterpreter();
// Active Directory enabled account: userAccountControl=512;
// disabled account: userAccountControl=514.
testLDAPDisableUserAccount(ldapadUserAccountStatusInterpreter, "512", "514");
}
public void testLDAPDisableUserAccountWithNetscapDSProperty() throws Exception
{
LDAPUserAccountStatusInterpreter ldapUserAccountStatusInterpreter = new LDAPUserAccountStatusInterpreter();
ldapUserAccountStatusInterpreter.setAcceptNullArgument(true);
// Netscape Directory Server derivatives (Oracle, Red Hat, 389 DS)
// disabled account property: nsAccountLock=true.
ldapUserAccountStatusInterpreter.setDisabledAccountPropertyValue("true");
testLDAPDisableUserAccount(ldapUserAccountStatusInterpreter, null, "true");
}
public void testLDAPDisableUserAccountWithOpenLDAPProperty() throws Exception
{
LDAPUserAccountStatusInterpreter ldapUserAccountStatusInterpreter = new LDAPUserAccountStatusInterpreter();
ldapUserAccountStatusInterpreter.setAcceptNullArgument(true);
// OpenLDAP disabled account: pwdAccountLockedTime=000001010000Z (part of PPolicy module)
ldapUserAccountStatusInterpreter.setDisabledAccountPropertyValue("000001010000Z");
testLDAPDisableUserAccount(ldapUserAccountStatusInterpreter, null, "000001010000Z");
}
/**
* Tests a forced update of the test users and groups with deletions disabled. No users or groups should be deleted,
* whether or not they move registry. Groups that would have been deleted should have no members and should only be
@@ -785,6 +919,16 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
return person;
}
private NodeDescription newPersonWithUserAccountStatusProperty(String userName, String userAccountPropertyValue)
{
NodeDescription person = newPerson(userName, userName + "@somedomain.com");
person.getProperties().put(QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "userAccountStatusProperty"), userAccountPropertyValue);
person.setLastModified(new Date());
return person;
}
/**
* Perform all the necessary assertions to ensure that an authority and its members exist in the correct zone.
*
@@ -936,10 +1080,31 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
}
public static interface IMockUserRegistry extends UserRegistry, ActivateableBean
{
/**
* Gets the zone id.
*
* @return the zoneId
*/
String getZoneId();
/**
* 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
*/
void updateState(Collection<NodeDescription> persons, Collection<NodeDescription> groups);
}
/**
* A Mock {@link UserRegistry} that returns a fixed set of users and groups.
*/
public static class MockUserRegistry implements UserRegistry, ActivateableBean
public static class MockUserRegistry implements IMockUserRegistry
{
private boolean isActive = true;
@@ -973,15 +1138,7 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
/**
* 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
*/
@Override
public void updateState(Collection<NodeDescription> persons, Collection<NodeDescription> groups)
{
List<NodeDescription> newPersons = new ArrayList<NodeDescription>(this.persons);
@@ -1066,11 +1223,7 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
this(zoneId, Arrays.asList(persons), Arrays.asList(groups));
}
/**
* Gets the zone id.
*
* @return the zoneId
*/
@Override
public String getZoneId()
{
return this.zoneId;
@@ -1195,10 +1348,10 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
* @param registries
* the new user registries
*/
public void setUserRegistries(MockUserRegistry... registries)
public void setUserRegistries(IMockUserRegistry... registries)
{
this.contexts = new LinkedHashMap<String, ApplicationContext>(registries.length * 2);
for (MockUserRegistry registry : registries)
for (IMockUserRegistry registry : registries)
{
StaticApplicationContext context = new StaticApplicationContext();
context.getDefaultListableBeanFactory().registerSingleton("userRegistry", registry);
@@ -1230,7 +1383,7 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
public void updateZone(String zoneId, NodeDescription[] persons, NodeDescription[] groups)
{
ApplicationContext context = this.contexts.get(zoneId);
MockUserRegistry registry = (MockUserRegistry) context.getBean("userRegistry");
IMockUserRegistry registry = (IMockUserRegistry) context.getBean("userRegistry");
registry.updateState(Arrays.asList(persons), Arrays.asList(groups));
}