diff --git a/config/alfresco/authentication-services-context.xml b/config/alfresco/authentication-services-context.xml
index ffb1782e5e..1a305de31e 100644
--- a/config/alfresco/authentication-services-context.xml
+++ b/config/alfresco/authentication-services-context.xml
@@ -198,9 +198,6 @@
-
- ${authentication.syncWhenMissingPeopleLogIn}
-
@@ -223,24 +220,17 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- userRegistry
-
-
+
+
+
+
+
+
+
+ org.alfresco.repo.security.sync.UserRegistrySynchronizer
+
+
+
diff --git a/config/alfresco/repository.properties b/config/alfresco/repository.properties
index efc9ddd4c0..d86f406568 100644
--- a/config/alfresco/repository.properties
+++ b/config/alfresco/repository.properties
@@ -328,7 +328,6 @@ V2.1-A.fixes.to.schema=0
# The default authentication chain
authentication.chain=alfrescoNtlm1:alfrescoNtlm
-authentication.syncWhenMissingPeopleLogIn=true
# Default NFS user mappings
nfs.user.mappings=admin
diff --git a/config/alfresco/subsystems/Synchronization/default/default-synchronization-context.xml b/config/alfresco/subsystems/Synchronization/default/default-synchronization-context.xml
index 652502fa81..19f5670947 100644
--- a/config/alfresco/subsystems/Synchronization/default/default-synchronization-context.xml
+++ b/config/alfresco/subsystems/Synchronization/default/default-synchronization-context.xml
@@ -2,7 +2,7 @@
-
+
@@ -30,4 +30,30 @@
+
+
+
+ ${synchronization.syncWhenMissingPeopleLogIn}
+
+
+ ${synchronization.autoCreatePeopleOnLogin}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ userRegistry
+
+
+
+
\ No newline at end of file
diff --git a/config/alfresco/subsystems/Synchronization/default/default-synchronization.properties b/config/alfresco/subsystems/Synchronization/default/default-synchronization.properties
index b875ff5706..56ec2d23b3 100644
--- a/config/alfresco/subsystems/Synchronization/default/default-synchronization.properties
+++ b/config/alfresco/subsystems/Synchronization/default/default-synchronization.properties
@@ -1,13 +1,19 @@
#
-# This properties file is used to configure scheduled user registry syncronisation (e.g. LDAP)
+# This properties file is used to configure user registry syncronisation (e.g. LDAP)
#
# Should the scheduled sync job only query users and groups changed since the
# last sync? Note that when true, the sync job will not be able to detect which
# users or groups have been removed from the directory (but obviously group
# membership changes would still be reflected). When false, a more regular
-# differential sync on login can still be enabled on the person service.
+# differential sync on login can still be enabled.
synchronization.synchronizeChangesOnly=false
# The cron expression defining when imports should take place
synchronization.import.cron=0 0 0 * * ?
+
+# Should we trigger a differential sync when missing people log in?
+synchronization.syncWhenMissingPeopleLogIn=true
+
+# Should we auto create a missing person on log in?
+synchronization.autoCreatePeopleOnLogin=true
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationComponent.java b/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationComponent.java
index c880f59ad7..c418c54dcf 100644
--- a/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationComponent.java
+++ b/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationComponent.java
@@ -44,7 +44,6 @@ import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
-import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.transaction.TransactionService;
@@ -63,10 +62,6 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC
private Set defaultAdministratorUserNames = Collections.emptySet();
- private boolean syncWhenMissingPeopleLogIn = true;
-
- private boolean autoCreatePeopleOnLogin = true;
-
private AuthenticationContext authenticationContext;
private PersonService personService;
@@ -136,21 +131,6 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC
{
return personService;
}
-
- public boolean isAutoCreatePeopleOnLogin()
- {
- return autoCreatePeopleOnLogin;
- }
-
- public void setAutoCreatePeopleOnLogin(boolean autoCreatePeopleOnLogin)
- {
- this.autoCreatePeopleOnLogin = autoCreatePeopleOnLogin;
- }
-
- public void setSyncWhenMissingPeopleLogIn(boolean syncWhenMissingPeopleLogIn)
- {
- this.syncWhenMissingPeopleLogIn = syncWhenMissingPeopleLogIn;
- }
public void authenticate(String userName, char[] password) throws AuthenticationException
{
@@ -448,30 +428,7 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC
{
public String doWork() throws Exception
{
- boolean personExists = personService.personExists(userName);
-
- // If the person is missing, synchronize or auto-create the missing person if we are allowed
- if (!personExists)
- {
- if ((userName != null) && !userName.equals(AuthenticationUtil.getSystemUserName()))
- {
- if (syncWhenMissingPeopleLogIn)
- {
- userRegistrySynchronizer.synchronize(false);
- personExists = personService.personExists(userName);
- }
- if (!personExists && autoCreatePeopleOnLogin && personService.createMissingPeople())
- {
- AuthorityType authorityType = AuthorityType.getAuthorityType(userName);
- if (authorityType == AuthorityType.USER)
- {
- personService.getPerson(userName);
- }
- }
- }
- }
-
- if (personExists)
+ if (personService.personExists(userName)|| userRegistrySynchronizer.createMissingPerson(userName))
{
NodeRef userNode = personService.getPerson(userName);
if (userNode != null)
@@ -480,8 +437,8 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC
// checks
return (String) nodeService.getProperty(userNode, ContentModel.PROP_USERNAME);
}
- }
- return userName;
+ }
+ throw new AuthenticationException("Person does not exist in Alfresco");
}
}, getSystemUserName(getUserDomain(userName)));
diff --git a/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java b/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java
index d3b98b2cc4..f91e6ab78c 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.attributes.LongAttributeValue;
import org.alfresco.repo.attributes.MapAttributeValue;
import org.alfresco.repo.management.subsystems.ActivateableBean;
import org.alfresco.repo.management.subsystems.ChildApplicationContextManager;
+import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.attributes.AttributeService;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.AuthorityType;
@@ -66,14 +67,16 @@ import org.springframework.context.ApplicationContext;
* false
then only those users and groups modified since the most recent modification date of all the
* objects last queried from the same {@link UserRegistry} are retrieved. In this mode, local users and groups are
* created and updated, but not deleted (except where a name collision with a lower priority {@link UserRegistry} is
- * detected). This 'differential' mode is much faster, and by default is triggered when a user is successfully
- * authenticated who doesn't yet have a local person object in Alfresco. This should mean that new users and their group
- * information are pulled over from LDAP servers as and when required.
+ * detected). This 'differential' mode is much faster, and by default is triggered by
+ * {@link #createMissingPerson(String)} when a user is successfully authenticated who doesn't yet have a local person
+ * object in Alfresco. This should mean that new users and their group information are pulled over from LDAP servers as
+ * and when required.
*
* @author dward
*/
public class ChainingUserRegistrySynchronizer implements UserRegistrySynchronizer
{
+
/** The logger. */
private static final Log logger = LogFactory.getLog(ChainingUserRegistrySynchronizer.class);
@@ -101,6 +104,12 @@ public class ChainingUserRegistrySynchronizer implements UserRegistrySynchronize
/** The attribute service. */
private AttributeService attributeService;
+ /** Should we trigger a sync when missing people log in? */
+ private boolean syncWhenMissingPeopleLogIn = true;
+
+ /** Should we auto create a missing person on log in? */
+ private boolean autoCreatePeopleOnLogin = true;
+
/**
* Sets the application context manager.
*
@@ -156,6 +165,28 @@ public class ChainingUserRegistrySynchronizer implements UserRegistrySynchronize
this.attributeService = attributeService;
}
+ /**
+ * Controls whether we auto create a missing person on log in
+ *
+ * @param autoCreatePeopleOnLogin
+ * true
if we should auto create a missing person on log in
+ */
+ public void setAutoCreatePeopleOnLogin(boolean autoCreatePeopleOnLogin)
+ {
+ this.autoCreatePeopleOnLogin = autoCreatePeopleOnLogin;
+ }
+
+ /**
+ * Controls whether we trigger a sync when missing people log in
+ *
+ * @param syncWhenMissingPeopleLogIn
+ * if we should trigger a sync when missing people log in
+ */
+ public void setSyncWhenMissingPeopleLogIn(boolean syncWhenMissingPeopleLogIn)
+ {
+ this.syncWhenMissingPeopleLogIn = syncWhenMissingPeopleLogIn;
+ }
+
/*
* (non-Javadoc)
* @see org.alfresco.repo.security.sync.UserRegistrySynchronizer#synchronize(boolean)
@@ -188,7 +219,8 @@ public class ChainingUserRegistrySynchronizer implements UserRegistrySynchronize
int groupsProcessed = syncGroupsWithPlugin(zoneId, plugin, force, visitedZoneIds);
ChainingUserRegistrySynchronizer.logger
.info("Finished synchronizing users and groups with user registry '" + zoneId + "'");
- logger.info(personsProcessed + " user(s) and " + groupsProcessed + " group(s) processed");
+ ChainingUserRegistrySynchronizer.logger.info(personsProcessed + " user(s) and " + groupsProcessed
+ + " group(s) processed");
}
}
catch (NoSuchBeanDefinitionException e)
@@ -199,6 +231,36 @@ public class ChainingUserRegistrySynchronizer implements UserRegistrySynchronize
}
}
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.repo.security.sync.UserRegistrySynchronizer#ensureExists(java.lang.String)
+ */
+ public boolean createMissingPerson(String userName)
+ {
+ // synchronize or auto-create the missing person if we are allowed
+ if (userName != null && !userName.equals(AuthenticationUtil.getSystemUserName()))
+ {
+ if (this.syncWhenMissingPeopleLogIn)
+ {
+ synchronize(false);
+ if (this.personService.personExists(userName))
+ {
+ return true;
+ }
+ }
+ if (this.autoCreatePeopleOnLogin && this.personService.createMissingPeople())
+ {
+ AuthorityType authorityType = AuthorityType.getAuthorityType(userName);
+ if (authorityType == AuthorityType.USER)
+ {
+ this.personService.getPerson(userName);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
/**
* Synchronizes local users (persons) with a {@link UserRegistry} for a particular zone.
*
@@ -300,7 +362,7 @@ public class ChainingUserRegistrySynchronizer implements UserRegistrySynchronize
return processedCount;
}
-
+
/**
* Synchronizes local groups (authorities) with a {@link UserRegistry} for a particular zone.
*
@@ -318,7 +380,7 @@ public class ChainingUserRegistrySynchronizer implements UserRegistrySynchronize
* of the zones in this set, then it will be ignored as this zone has lower priority.
* @return the number of groups processed
*/
- private int syncGroupsWithPlugin(String zoneId, UserRegistry plugin, boolean force, Set visitedZoneIds)
+ private int syncGroupsWithPlugin(String zoneId, UserRegistry userRegistry, boolean force, Set visitedZoneIds)
{
int processedCount = 0;
long lastModifiedMillis = force ? -1L : getMostRecentUpdateTime(
@@ -334,7 +396,7 @@ public class ChainingUserRegistrySynchronizer implements UserRegistrySynchronize
+ DateFormat.getDateTimeInstance().format(lastModified) + " from user registry '" + zoneId + "'");
}
- Iterator groups = plugin.getGroups(lastModified);
+ Iterator groups = userRegistry.getGroups(lastModified);
Map> groupAssocsToCreate = new TreeMap>();
Set groupsToDelete = this.authorityService.getAllAuthoritiesInZone(zoneId, AuthorityType.GROUP);
while (groups.hasNext())
@@ -483,7 +545,16 @@ public class ChainingUserRegistrySynchronizer implements UserRegistrySynchronize
}
this.attributeService.setAttribute(path, zoneId, new LongAttributeValue(lastModifiedMillis));
}
-
+
+ /**
+ * Gets the default set of zones to set on a person or group belonging to the user registry with the given zone ID.
+ * We add the default zone as well as the zone corresponding to the user registry so that the users and groups are
+ * visible in the UI.
+ *
+ * @param zoneId
+ * the zone id
+ * @return the zone set
+ */
private Set getZones(String zoneId)
{
HashSet zones = new HashSet(2, 1.0f);
diff --git a/source/java/org/alfresco/repo/security/sync/UserRegistrySynchronizer.java b/source/java/org/alfresco/repo/security/sync/UserRegistrySynchronizer.java
index 02fe5a0796..30ab728990 100644
--- a/source/java/org/alfresco/repo/security/sync/UserRegistrySynchronizer.java
+++ b/source/java/org/alfresco/repo/security/sync/UserRegistrySynchronizer.java
@@ -31,7 +31,18 @@ package org.alfresco.repo.security.sync;
* @author dward
*/
public interface UserRegistrySynchronizer
-{
+{
+ /**
+ * Creates a person object for a successfully authenticated user who does not yet have a person object, if allowed
+ * to by configuration. Depending on configuration, may trigger a partial synchronize and/or create a new person
+ * with default settings.
+ *
+ * @param username
+ * the user name
+ * @return true, if a person is created
+ */
+ public boolean createMissingPerson(String username);
+
/**
* Retrieves timestamped user and group information from configured external sources and compares it with the local
* users and groups last retrieved from the same sources. Any updates and additions made to those users and groups