Merged V3.1 to HEAD

12943: Port of support for ADB-47 from V2.1-A to 3.1
   12948: Port of tests from CHK-2235 for ADB-20 from V2.1-A to 3.1
   12965: Activated index tracker Quartz job by default
   12974: Port for lazy creation of home folders with configuration from V2.1-A to V3.1: original CHK-2619, CHK-2716
   12976: Merged V2.1A to V3.1
      8562: (record-only) Fix to lazily create home folders - DO NOT MERGE
      8694: (record-only) Added configuration for lazy or eager creation of home folders
   12978: Merged V3.0 to V3.1
      12920: Merged V2.2 to V3.0
         12456: Wire up AVM locking service by interface to allow for potential over-ride
         12457: Make AVM ChildKey case insensitive
         12470: Merged V2.2.1-NBC-FIXES to V2.2
            12156: Optimizations to WCMWorkflowEvaluator and WCMWorkflowDeletedEvaluator    
            12605: Hide annoying "Virtualisation Server not started" warnings (by making them debug)
         12707: AVM console - "snap" also allows tag and description to be specified
   12979: Build/test fix
   ___________________________________________________________________
   Modified: svn:mergeinfo
      Merged /alfresco/BRANCHES/DEV/V2.2.1-NBC-FIXES:r12156
      Merged /alfresco/BRANCHES/V2.1-A:r8562,8694
      Merged /alfresco/BRANCHES/V3.0:r12920
      Merged /alfresco/BRANCHES/V2.2:r12456-12457,12470,12605,12707
      Merged /alfresco/BRANCHES/V3.1:r12943,12948,12965,12974,12976,12978-12979


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@13544 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2009-03-11 01:06:49 +00:00
parent b30c8f915b
commit f77e816467
16 changed files with 423 additions and 196 deletions

View File

@@ -90,11 +90,11 @@
<property name="searchService">
<ref bean="admSearchService" />
</property>
<property name="retryingTransactionHelper">
<ref bean="retryingTransactionHelper"/>
</property>
<property name="userNamesAreCaseSensitive">
<value>${user.name.caseSensitive}</value>
<property name="retryingTransactionHelper">
<ref bean="retryingTransactionHelper"/>
</property>
<property name="userNameMatcher">
<ref bean="userNameMatcher" />
</property>
<property name="passwordEncoder">
<ref bean="passwordEncoder" />
@@ -231,6 +231,20 @@
</bean>
<!-- support to match user names -->
<bean id="userNameMatcher" class="org.alfresco.repo.security.person.UserNameMatcherImpl">
<property name="userNamesAreCaseSensitive">
<value>${user.name.caseSensitive}</value>
</property>
<property name="domainNamesAreCaseSensitive">
<value>${domain.name.caseSensitive}</value>
</property>
<property name="domainSeparator">
<value>${domain.separator}</value>
</property>
</bean>
<!-- The person service. -->
<bean id="personService" class="org.alfresco.repo.security.person.PersonServiceImpl" init-method="init">
@@ -288,8 +302,8 @@
<property name="createMissingPeople">
<value>${server.transaction.allow-writes}</value>
</property>
<property name="userNamesAreCaseSensitive">
<value>${user.name.caseSensitive}</value>
<property name="userNameMatcher">
<ref bean="userNameMatcher" />
</property>
<!-- New properties after 1.4.0 to deal with duplicate user ids when found -->
<property name="processDuplicates">
@@ -304,6 +318,9 @@
</property>
<property name="includeAutoCreated">
<value>false</value>
</property>
<property name="homeFolderManager">
<ref bean="homeFolderManager" />
</property>
</bean>
@@ -316,6 +333,10 @@
</property>
<property name="defaultProvider">
<ref bean="userHomesHomeFolderProvider" />
</property>
<property name="enableHomeFolderCreationAsPeopleAreCreated">
<!--<value>false</value> -->
<value>${home.folder.creation.eager}</value>
</property>
</bean>

View File

@@ -38,10 +38,11 @@ index.recovery.maximumPoolSize=5
# http://wiki.alfresco.com/wiki/High_Availability_Configuration_V1.4_to_V2.1#Version_1.4.5.2C_2.1.1_and_later
# By default, this is effectively never, but can be modified as required.
# Examples:
# Never: * * * * * ? 2099
# Once every five seconds: 0/5 * * * * ?
# Once every two seconds : 0/2 * * * * ?
# See http://quartz.sourceforge.net/javadoc/org/quartz/CronTrigger.html
index.tracking.cronExpression=* * * * * ? 2099
index.tracking.cronExpression=0/5 * * * * ?
index.tracking.adm.cronExpression=${index.tracking.cronExpression}
index.tracking.avm.cronExpression=${index.tracking.cronExpression}
# Other properties.
@@ -231,6 +232,8 @@ system.workflow_container.childname=sys:workflow
# Are user names case sensitive?
user.name.caseSensitive=false
domain.name.caseSensitive=false
domain.separator=
# AVM Specific properties.
avm.remote.idlestream.timeout=30000
@@ -259,6 +262,9 @@ system.usages.enabled=true
# Repository endpoint - used by Activity Service
repo.remote.endpoint.url=http://localhost:8080/alfresco/service
# Create home folders as people are created (true) or create them lazily (false)
home.folder.creation.eager=true
# The well known RMI registry port is defined in the alfresco-shared.properties file
# alfresco.rmi.services.port=50500
#

View File

@@ -357,11 +357,15 @@ public class AVMInterpreter
}
else if (command[0].equals("snap"))
{
if (command.length != 2)
if ((command.length < 2) || (command.length > 4))
{
return "Syntax Error.";
}
fService.createSnapshot(command[1], null, null);
String tag = (command.length > 2) ? command[2] : null;
String description = (command.length > 3) ? command[3] : null;
fService.createSnapshot(command[1], tag, description);
}
else if (command[0].equals("cat"))
{

View File

@@ -109,7 +109,7 @@ public class ChildKey implements Serializable
}
ChildKey o = (ChildKey)other;
return fParent.equals(o.getParent()) &&
fName.equals(o.getName());
fName.equalsIgnoreCase(o.getName());
}
/**
@@ -117,6 +117,6 @@ public class ChildKey implements Serializable
*/
public int hashCode()
{
return fParent.hashCode() + fName.hashCode();
return fParent.hashCode() + fName.toLowerCase().hashCode();
}
}

View File

@@ -25,32 +25,41 @@
package org.alfresco.repo.avm.locking;
import org.alfresco.service.cmr.avm.locking.AVMLockingService;
import org.alfresco.util.AbstractLifecycleBean;
import org.springframework.context.ApplicationEvent;
/**
* Bootstrap for AVM Locking Service.
*
* @author britt
*/
public class AVMLockingBootstrap extends AbstractLifecycleBean
{
private AVMLockingServiceImpl fLockingService;
public void setAvmLockingService(AVMLockingServiceImpl service)
private AVMLockingService fLockingService;
public void setAvmLockingService(AVMLockingService service)
{
fLockingService = service;
}
/* (non-Javadoc)
/*
* (non-Javadoc)
*
* @see org.alfresco.util.AbstractLifecycleBean#onBootstrap(org.springframework.context.ApplicationEvent)
*/
@Override
protected void onBootstrap(ApplicationEvent event)
{
fLockingService.init();
if (fLockingService instanceof AVMLockingServiceImpl)
{
((AVMLockingServiceImpl) fLockingService).init();
}
}
/* (non-Javadoc)
/*
* (non-Javadoc)
*
* @see org.alfresco.util.AbstractLifecycleBean#onShutdown(org.springframework.context.ApplicationEvent)
*/
@Override

View File

@@ -51,6 +51,7 @@ import org.alfresco.repo.cache.SimpleCache;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.security.authentication.InMemoryTicketComponentImpl.ExpiryMode;
import org.alfresco.repo.security.authentication.InMemoryTicketComponentImpl.Ticket;
import org.alfresco.repo.security.person.UserNameMatcher;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.ServiceRegistry;
@@ -118,6 +119,8 @@ public class AuthenticationTest extends TestCase
private PersonService personService;
private UserNameMatcher userNameMatcher;
public AuthenticationTest()
{
super();
@@ -143,6 +146,7 @@ public class AuthenticationTest extends TestCase
authenticationComponentImpl = (AuthenticationComponent) ctx.getBean("authenticationComponent");
pubPersonService = (PersonService) ctx.getBean("PersonService");
personService = (PersonService) ctx.getBean("personService");
userNameMatcher = (UserNameMatcher) ctx.getBean("userNameMatcher");
// permissionServiceSPI = (PermissionServiceSPI)
// ctx.getBean("permissionService");
ticketsCache = (SimpleCache<String, Ticket>) ctx.getBean("ticketsCache");
@@ -182,6 +186,8 @@ public class AuthenticationTest extends TestCase
dao.setDictionaryService(dictionaryService);
dao.setNamespaceService(getNamespacePrefixReolsver(""));
dao.setPasswordEncoder(passwordEncoder);
dao.setUserNameMatcher(userNameMatcher);
dao.setRetryingTransactionHelper(transactionService.getRetryingTransactionHelper());
if (dao.getUserOrNull("andy") != null)
{
@@ -388,6 +394,8 @@ public class AuthenticationTest extends TestCase
dao.setDictionaryService(dictionaryService);
dao.setNamespaceService(getNamespacePrefixReolsver(""));
dao.setPasswordEncoder(passwordEncoder);
dao.setUserNameMatcher(userNameMatcher);
dao.setRetryingTransactionHelper(transactionService.getRetryingTransactionHelper());
dao.createUser("Andy", "cabbage".toCharArray());
assertNotNull(dao.getUserOrNull("Andy"));

View File

@@ -39,9 +39,9 @@ import net.sf.acegisecurity.providers.encoding.PasswordEncoder;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.person.UserNameMatcher;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.Managed;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
@@ -63,6 +63,7 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao
private static final StoreRef STOREREF_USERS = new StoreRef("user", "alfrescoUserStore");
private NodeService nodeService;
private TenantService tenantService;
private NamespacePrefixResolver namespacePrefixResolver;
@@ -71,22 +72,26 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao
private DictionaryService dictionaryService;
private SearchService searchService;
private RetryingTransactionHelper retryingTransactionHelper;
private PasswordEncoder passwordEncoder;
private boolean userNamesAreCaseSensitive;
private UserNameMatcher userNameMatcher;
public RepositoryAuthenticationDao()
{
super();
}
public boolean getUserNamesAreCaseSensitive()
{
return userNamesAreCaseSensitive;
return userNameMatcher.getUserNamesAreCaseSensitive();
}
@Managed(category="Security")
public void setUserNamesAreCaseSensitive(boolean userNamesAreCaseSensitive)
public void setUserNameMatcher(UserNameMatcher userNameMatcher)
{
this.userNamesAreCaseSensitive = userNamesAreCaseSensitive;
this.userNameMatcher = userNameMatcher;
}
public void setDictionaryService(DictionaryService dictionaryService)
@@ -103,7 +108,7 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao
{
this.nodeService = nodeService;
}
public void setRetryingTransactionHelper(RetryingTransactionHelper retryingTransactionHelper)
{
this.retryingTransactionHelper = retryingTransactionHelper;
@@ -124,8 +129,7 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao
this.searchService = searchService;
}
public UserDetails loadUserByUsername(String incomingUserName) throws UsernameNotFoundException,
DataAccessException
public UserDetails loadUserByUsername(String incomingUserName) throws UsernameNotFoundException, DataAccessException
{
NodeRef userRef = getUserOrNull(incomingUserName);
if (userRef == null)
@@ -134,28 +138,25 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao
}
Map<QName, Serializable> properties = nodeService.getProperties(userRef);
String password = DefaultTypeConverter.INSTANCE.convert(String.class, properties
.get(ContentModel.PROP_PASSWORD));
String password = DefaultTypeConverter.INSTANCE.convert(String.class, properties.get(ContentModel.PROP_PASSWORD));
// Report back the user name as stored on the user
String userName = DefaultTypeConverter.INSTANCE.convert(String.class, properties
.get(ContentModel.PROP_USER_USERNAME));
String userName = DefaultTypeConverter.INSTANCE.convert(String.class, properties.get(ContentModel.PROP_USER_USERNAME));
GrantedAuthority[] gas = new GrantedAuthority[1];
gas[0] = new GrantedAuthorityImpl("ROLE_AUTHENTICATED");
UserDetails ud = new User(userName, password, getEnabled(userRef), !getAccountHasExpired(userRef),
!getCredentialsHaveExpired(userRef), !getAccountlocked(userRef), gas);
UserDetails ud = new User(userName, password, getEnabled(userRef), !getAccountHasExpired(userRef), !getCredentialsHaveExpired(userRef), !getAccountlocked(userRef), gas);
return ud;
}
public NodeRef getUserOrNull(String searchUserName)
{
if(searchUserName == null)
if (searchUserName == null)
{
return null;
}
if(searchUserName.length() == 0)
if (searchUserName.length() == 0)
{
return null;
}
@@ -189,75 +190,37 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao
final NodeRef nodeRef = row.getNodeRef();
if (nodeService.exists(nodeRef))
{
String realUserName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(
nodeRef, ContentModel.PROP_USER_USERNAME));
String realUserName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(nodeRef, ContentModel.PROP_USER_USERNAME));
if (userNamesAreCaseSensitive)
if(userNameMatcher.matches(realUserName, searchUserName))
{
if (realUserName.equals(searchUserName))
if (returnRef == null)
{
if(returnRef == null)
returnRef = nodeRef;
}
else
{
try
{
returnRef = nodeRef;
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Object>()
{
public Object execute() throws Throwable
{
// Delete the extra user node references
RepositoryAuthenticationDao.this.nodeService.deleteNode(nodeRef);
return null;
}
}, false, true);
}
else
catch (InvalidNodeRefException exception)
{
try
{
this.retryingTransactionHelper.doInTransaction(
new RetryingTransactionHelper.RetryingTransactionCallback<Object>()
{
public Object execute()
throws Throwable
{
// Delete the extra user node references
RepositoryAuthenticationDao.this.nodeService.deleteNode(nodeRef);
return null;
}
}, false, true);
}
catch (InvalidNodeRefException exception)
{
// Ignore this exception as the node has already been deleted
}
}
}
}
else
{
if (realUserName.equalsIgnoreCase(searchUserName))
{
if(returnRef == null)
{
returnRef = nodeRef;
}
else
{
try
{
this.retryingTransactionHelper.doInTransaction(
new RetryingTransactionHelper.RetryingTransactionCallback<Object>()
{
public Object execute()
throws Throwable
{
// Delete the extra user node references
RepositoryAuthenticationDao.this.nodeService.deleteNode(nodeRef);
return null;
}
}, false, true);
}
catch (InvalidNodeRefException exception)
{
// Ignore this exception as the node has already been deleted
}
// Ignore this exception as the node has already been deleted
}
}
}
}
}
@@ -291,8 +254,7 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao
properties.put(ContentModel.PROP_CREDENTIALS_EXPIRE, Boolean.valueOf(false));
properties.put(ContentModel.PROP_ENABLED, Boolean.valueOf(true));
properties.put(ContentModel.PROP_ACCOUNT_LOCKED, Boolean.valueOf(false));
nodeService.createNode(typesNode, ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_USER, ContentModel.TYPE_USER,
properties);
nodeService.createNode(typesNode, ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_USER, ContentModel.TYPE_USER, properties);
}
private NodeRef getUserFolderLocation(String caseSensitiveUserName)
@@ -304,8 +266,7 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao
// AR-527
NodeRef rootNode = nodeService.getRootNode(userStoreRef);
List<ChildAssociationRef> results = nodeService.getChildAssocs(rootNode, RegexQNamePattern.MATCH_ALL,
qnameAssocSystem);
List<ChildAssociationRef> results = nodeService.getChildAssocs(rootNode, RegexQNamePattern.MATCH_ALL, qnameAssocSystem);
NodeRef sysNodeRef = null;
if (results.size() == 0)
{
@@ -404,11 +365,9 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao
{
return null;
}
if (DefaultTypeConverter.INSTANCE.booleanValue(nodeService.getProperty(userNode,
ContentModel.PROP_ACCOUNT_EXPIRES)))
if (DefaultTypeConverter.INSTANCE.booleanValue(nodeService.getProperty(userNode, ContentModel.PROP_ACCOUNT_EXPIRES)))
{
return DefaultTypeConverter.INSTANCE.convert(Date.class, nodeService.getProperty(userNode,
ContentModel.PROP_ACCOUNT_EXPIRY_DATE));
return DefaultTypeConverter.INSTANCE.convert(Date.class, nodeService.getProperty(userNode, ContentModel.PROP_ACCOUNT_EXPIRY_DATE));
}
else
{
@@ -427,11 +386,9 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao
{
return false;
}
if (DefaultTypeConverter.INSTANCE.booleanValue(nodeService.getProperty(userNode,
ContentModel.PROP_ACCOUNT_EXPIRES)))
if (DefaultTypeConverter.INSTANCE.booleanValue(nodeService.getProperty(userNode, ContentModel.PROP_ACCOUNT_EXPIRES)))
{
Date date = DefaultTypeConverter.INSTANCE.convert(Date.class, nodeService.getProperty(userNode,
ContentModel.PROP_ACCOUNT_EXPIRY_DATE));
Date date = DefaultTypeConverter.INSTANCE.convert(Date.class, nodeService.getProperty(userNode, ContentModel.PROP_ACCOUNT_EXPIRY_DATE));
if (date == null)
{
return false;
@@ -498,11 +455,9 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao
{
return null;
}
if (DefaultTypeConverter.INSTANCE.booleanValue(nodeService.getProperty(userNode,
ContentModel.PROP_CREDENTIALS_EXPIRE)))
if (DefaultTypeConverter.INSTANCE.booleanValue(nodeService.getProperty(userNode, ContentModel.PROP_CREDENTIALS_EXPIRE)))
{
return DefaultTypeConverter.INSTANCE.convert(Date.class, nodeService.getProperty(userNode,
ContentModel.PROP_CREDENTIALS_EXPIRY_DATE));
return DefaultTypeConverter.INSTANCE.convert(Date.class, nodeService.getProperty(userNode, ContentModel.PROP_CREDENTIALS_EXPIRY_DATE));
}
else
{
@@ -521,11 +476,9 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao
{
return false;
}
if (DefaultTypeConverter.INSTANCE.booleanValue(nodeService.getProperty(userNode,
ContentModel.PROP_CREDENTIALS_EXPIRE)))
if (DefaultTypeConverter.INSTANCE.booleanValue(nodeService.getProperty(userNode, ContentModel.PROP_CREDENTIALS_EXPIRE)))
{
Date date = DefaultTypeConverter.INSTANCE.convert(Date.class, nodeService.getProperty(userNode,
ContentModel.PROP_CREDENTIALS_EXPIRY_DATE));
Date date = DefaultTypeConverter.INSTANCE.convert(Date.class, nodeService.getProperty(userNode, ContentModel.PROP_CREDENTIALS_EXPIRY_DATE));
if (date == null)
{
return false;
@@ -634,8 +587,7 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao
}
else
{
String password = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(userNode,
ContentModel.PROP_PASSWORD));
String password = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(userNode, ContentModel.PROP_PASSWORD));
return password;
}
}

View File

@@ -590,6 +590,26 @@ public class PermissionServiceTest extends AbstractPermissionTest
assertEquals(permissionService.hasPermission(rootNodeRef, (PermissionService.CONSUMER)), AccessStatus.DENIED);
}
public void testEqualBarCaseAuthorities()
{
runAs("admin");
NodeRef n1 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef();
permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.READ), "andy", AccessStatus.ALLOWED));
permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.READ), "Andy", AccessStatus.ALLOWED));
permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.READ), "ANDY", AccessStatus.ALLOWED));
permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.READ), "woof/adobe", AccessStatus.ALLOWED));
permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.READ), "woof/Adobe", AccessStatus.ALLOWED));
permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.READ), "woof/ADOBE", AccessStatus.ALLOWED));
permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.READ), "Woof/Adobe", AccessStatus.ALLOWED));
permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.READ), "WOOF/ADOBE", AccessStatus.ALLOWED));
assertEquals(8, permissionService.getAllSetPermissions(n1).size());
}
public void testGetAllSetPermissions()
{
runAs("andy");

View File

@@ -49,6 +49,8 @@ public class HomeFolderManager implements InitializingBean, NodeServicePolicies.
private PolicyComponent policyComponent;
private NodeService nodeService;
private boolean enableHomeFolderCreationAsPeopleAreCreated = false;
/**
* A default provider
@@ -61,12 +63,19 @@ public class HomeFolderManager implements InitializingBean, NodeServicePolicies.
private Map<String, HomeFolderProvider> providers = new HashMap<String, HomeFolderProvider>();
/**
* Bind the calss behaviour to this implementation
* Bind the class behaviour to this implementation
*/
public void afterPropertiesSet() throws Exception
{
policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateNode"),
ContentModel.TYPE_PERSON, new JavaBehaviour(this, "onCreateNode"));
if (enableHomeFolderCreationAsPeopleAreCreated)
{
policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateNode"), ContentModel.TYPE_PERSON, new JavaBehaviour(this, "onCreateNode"));
}
}
public void setEnableHomeFolderCreationAsPeopleAreCreated(boolean enableHomeFolderCreationAsPeopleAreCreated)
{
this.enableHomeFolderCreationAsPeopleAreCreated = enableHomeFolderCreationAsPeopleAreCreated;
}
/**

View File

@@ -31,7 +31,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
public interface PersonDao
{
public List<NodeRef> getPersonOrNull(String searchUserName, boolean userNamesAreCaseSensitive);
public List<NodeRef> getPersonOrNull(final String searchUserName, UserNameMatcher matcher);
public Set<NodeRef> getAllPeople();
}

View File

@@ -51,8 +51,9 @@ import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
public class PersonDaoImpl extends HibernateDaoSupport implements PersonDao
{
private static final String QUERY_PERSON_GET_PERSON = "person.getPerson";
private static final String QUERY_PERSON_GET_ALL_PEOPLE = "person.getAllPeople";
private static final String QUERY_PERSON_GET_PERSON = "person.getPerson";
private static final String QUERY_PERSON_GET_ALL_PEOPLE = "person.getAllPeople";
private QNameDAO qnameDAO;
@@ -61,33 +62,33 @@ public class PersonDaoImpl extends HibernateDaoSupport implements PersonDao
private LocaleDAO localeDAO;
private DictionaryService dictionaryService;
private StoreRef storeRef;
private TenantService tenantService;
public void setStoreUrl(String storeUrl)
{
this.storeRef = new StoreRef(storeUrl);
}
public void setTenantService(TenantService tenantService)
{
this.tenantService = tenantService;
}
@SuppressWarnings("unchecked")
public List<NodeRef> getPersonOrNull(final String searchUserName, boolean userNamesAreCaseSensitive)
public List<NodeRef> getPersonOrNull(final String searchUserName, UserNameMatcher matcher)
{
final StoreRef personStoreRef = tenantService.getName(storeRef);
List<NodeRef> answer = new ArrayList<NodeRef>();
HibernateCallback callback = new HibernateCallback()
{
public Object doInHibernate(Session session)
{
SQLQuery query = (SQLQuery) session.getNamedQuery(QUERY_PERSON_GET_PERSON);
SQLQuery query = (SQLQuery) session.getNamedQuery(QUERY_PERSON_GET_PERSON);
query.setParameter("qnameId", qNameId);
query.setParameter("userName1", searchUserName);
query.setParameter("userName2", searchUserName);
@@ -111,19 +112,9 @@ public class PersonDaoImpl extends HibernateDaoSupport implements PersonDao
Serializable value = converted.get(ContentModel.PROP_USERNAME);
String realUserName = DefaultTypeConverter.INSTANCE.convert(String.class, value);
if (userNamesAreCaseSensitive)
if (matcher.matches(searchUserName, realUserName))
{
if (realUserName.equals(searchUserName))
{
answer.add(nodeRef);
}
}
else
{
if (realUserName.equalsIgnoreCase(searchUserName))
{
answer.add(nodeRef);
}
answer.add(nodeRef);
}
}
@@ -133,21 +124,21 @@ public class PersonDaoImpl extends HibernateDaoSupport implements PersonDao
public void init()
{
qNameId = qnameDAO.getOrCreateQName(ContentModel.PROP_USERNAME).getFirst();
qNameId = qnameDAO.getOrCreateQName(ContentModel.PROP_USERNAME).getFirst();
}
@SuppressWarnings("unchecked")
public Set<NodeRef> getAllPeople()
{
final StoreRef personStoreRef = tenantService.getName(storeRef);
Set<NodeRef> answer = new HashSet<NodeRef>();
HibernateCallback callback = new HibernateCallback()
{
public Object doInHibernate(Session session)
{
SQLQuery query = (SQLQuery) session.getNamedQuery(QUERY_PERSON_GET_ALL_PEOPLE);
SQLQuery query = (SQLQuery) session.getNamedQuery(QUERY_PERSON_GET_ALL_PEOPLE);
query.setParameter("qnameId", qNameId);
query.setParameter("False", Boolean.FALSE);
query.setParameter("storeProtocol", personStoreRef.getProtocol());

View File

@@ -67,6 +67,7 @@ import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.GUID;
import org.alfresco.util.Pair;
import org.alfresco.util.PropertyCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -92,27 +93,27 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
private TransactionService transactionService;
private NodeService nodeService;
private TenantService tenantService;
private SearchService searchService;
private AuthorityService authorityService;
private DictionaryService dictionaryService;
private PermissionServiceSPI permissionServiceSPI;
private NamespacePrefixResolver namespacePrefixResolver;
private HomeFolderManager homeFolderManager;
private PolicyComponent policyComponent;
private boolean createMissingPeople;
private static Set<QName> mutableProperties;
private boolean userNamesAreCaseSensitive = false;
private String defaultHomeFolderProvider;
private boolean processDuplicates = true;
@@ -128,6 +129,8 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
/** a transactionally-safe cache to be injected */
private SimpleCache<String, NodeRef> personCache;
private UserNameMatcher userNameMatcher;
static
{
Set<QName> props = new HashSet<QName>();
@@ -168,20 +171,21 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
PropertyCheck.mandatory(this, "personCache", personCache);
PropertyCheck.mandatory(this, "personDao", personDao);
this.policyComponent
.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateNode"), ContentModel.TYPE_PERSON, new JavaBehaviour(this, "onCreateNode"));
// Avoid clash with home folder registration
//this.policyComponent
// .bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateNode"), ContentModel.TYPE_PERSON, new JavaBehaviour(this, "onCreateNode"));
this.policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"), ContentModel.TYPE_PERSON, new JavaBehaviour(this,
"beforeDeleteNode"));
}
public boolean getUserNamesAreCaseSensitive()
public UserNameMatcher getUserNameMatcher()
{
return userNamesAreCaseSensitive;
return userNameMatcher;
}
public void setUserNamesAreCaseSensitive(boolean userNamesAreCaseSensitive)
public void setUserNameMatcher(UserNameMatcher userNameMatcher)
{
this.userNamesAreCaseSensitive = userNamesAreCaseSensitive;
this.userNameMatcher = userNameMatcher;
}
void setDefaultHomeFolderProvider(String defaultHomeFolderProvider)
@@ -208,6 +212,11 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
{
this.processDuplicates = processDuplicates;
}
public void setHomeFolderManager(HomeFolderManager homeFolderManager)
{
this.homeFolderManager = homeFolderManager;
}
public void setPersonDao(PersonDao personDao)
{
@@ -287,7 +296,7 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
NodeRef returnRef = this.personCache.get(searchUserName);
if (returnRef == null)
{
List<NodeRef> refs = personDao.getPersonOrNull(searchUserName, userNamesAreCaseSensitive);
List<NodeRef> refs = personDao.getPersonOrNull(searchUserName, userNameMatcher);
if (refs.size() > 1)
{
returnRef = handleDuplicates(refs, searchUserName);
@@ -300,6 +309,7 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
// add to cache
this.personCache.put(searchUserName, returnRef);
}
makeHomeFolderIfRequired(returnRef);
return returnRef;
}
@@ -316,14 +326,14 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
}
else
{
if (userNamesAreCaseSensitive)
String userNameSensitivity = " (user name is case-" + (userNameMatcher.getUserNamesAreCaseSensitive() ? "sensitive" : "insensitive") + ")";
String domainNameSensitivity = "";
if (! userNameMatcher.getDomainSeparator().equals(""))
{
throw new AlfrescoRuntimeException("Found more than one user for " + searchUserName + " (case sensitive)");
}
else
{
throw new AlfrescoRuntimeException("Found more than one user for " + searchUserName + " (case insensitive)");
domainNameSensitivity = " (domain name is case-" + (userNameMatcher.getDomainNamesAreCaseSensitive() ? "sensitive" : "insensitive") + ")";
}
throw new AlfrescoRuntimeException("Found more than one user for " + searchUserName + userNameSensitivity + domainNameSensitivity);
}
}
@@ -510,7 +520,7 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
}
Map<QName, Serializable> update = nodeService.getProperties(personNode);
update.putAll(properties);
nodeService.setProperties(personNode, update);
}
@@ -522,9 +532,31 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
private NodeRef createMissingPerson(String userName)
{
HashMap<QName, Serializable> properties = getDefaultProperties(userName);
return createPerson(properties);
NodeRef person = createPerson(properties);
makeHomeFolderIfRequired(person);
return person;
}
private void makeHomeFolderIfRequired(NodeRef person)
{
if (person != null)
{
NodeRef homeFolder = DefaultTypeConverter.INSTANCE.convert(NodeRef.class, nodeService.getProperty(person, ContentModel.PROP_HOMEFOLDER));
if (homeFolder == null)
{
final ChildAssociationRef ref = nodeService.getPrimaryParent(person);
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
{
public Object execute() throws Throwable
{
homeFolderManager.onCreateNode(ref);
return null;
}
}, transactionService.isReadOnly(), false);
}
}
}
private HashMap<QName, Serializable> getDefaultProperties(String userName)
{
HashMap<QName, Serializable> properties = new HashMap<QName, Serializable>();
@@ -534,48 +566,46 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
properties.put(ContentModel.PROP_EMAIL, "");
properties.put(ContentModel.PROP_ORGID, "");
properties.put(ContentModel.PROP_HOME_FOLDER_PROVIDER, defaultHomeFolderProvider);
properties.put(ContentModel.PROP_SIZE_CURRENT, 0L);
properties.put(ContentModel.PROP_SIZE_QUOTA, -1L); // no quota
return properties;
}
public NodeRef createPerson(Map<QName, Serializable> properties)
{
String userName = DefaultTypeConverter.INSTANCE.convert(String.class, properties.get(ContentModel.PROP_USERNAME));
tenantService.checkDomainUser(userName);
properties.put(ContentModel.PROP_USERNAME, userName);
properties.put(ContentModel.PROP_SIZE_CURRENT, 0L);
return nodeService.createNode(
getPeopleContainer(),
ContentModel.ASSOC_CHILDREN,
QName.createQName("cm", userName, namespacePrefixResolver),
ContentModel.TYPE_PERSON, properties).getChildRef();
return nodeService.createNode(getPeopleContainer(), ContentModel.ASSOC_CHILDREN, QName.createQName("cm", userName, namespacePrefixResolver), ContentModel.TYPE_PERSON,
properties).getChildRef();
}
public NodeRef getPeopleContainer()
{
NodeRef rootNodeRef = nodeService.getRootNode(tenantService.getName(storeRef));
List<ChildAssociationRef> children = nodeService.getChildAssocs(rootNodeRef, RegexQNamePattern.MATCH_ALL, QName.createQName(SYSTEM_FOLDER_SHORT_QNAME, namespacePrefixResolver));
List<ChildAssociationRef> children = nodeService.getChildAssocs(rootNodeRef, RegexQNamePattern.MATCH_ALL, QName.createQName(SYSTEM_FOLDER_SHORT_QNAME,
namespacePrefixResolver));
if (children.size() == 0)
{
throw new AlfrescoRuntimeException("Required people system path not found: " + SYSTEM_FOLDER_SHORT_QNAME);
}
NodeRef systemNodeRef = children.get(0).getChildRef();
children = nodeService.getChildAssocs(systemNodeRef, RegexQNamePattern.MATCH_ALL, QName.createQName(PEOPLE_FOLDER_SHORT_QNAME, namespacePrefixResolver));
if (children.size() == 0)
if (children.size() == 0)
{
throw new AlfrescoRuntimeException("Required people system path not found: " + PEOPLE_FOLDER_SHORT_QNAME);
}
NodeRef peopleNodeRef = children.get(0).getChildRef();
return peopleNodeRef;
}
@@ -612,16 +642,15 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
// and throw exception if it isn't
if (this.dictionaryService.getProperty(ContentModel.TYPE_PERSON, propertyKey) == null)
{
throw new AlfrescoRuntimeException("Property '" + propertyKey + "' is not defined "
+ "for content model type cm:person");
throw new AlfrescoRuntimeException("Property '" + propertyKey + "' is not defined " + "for content model type cm:person");
}
LinkedHashSet<NodeRef> people = new LinkedHashSet<NodeRef>();
//
// Search for people using the given property
//
SearchParameters sp = new SearchParameters();
sp.setLanguage(SearchService.LANGUAGE_LUCENE);
sp.setQuery("@cm\\:" + propertyKey.getLocalName() + ":\"" + propertyValue + "\"");
@@ -650,10 +679,10 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
rs.close();
}
}
return people;
}
// Policies
/*
@@ -695,7 +724,7 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
{
this.authorityService = authorityService;
}
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
@@ -715,17 +744,17 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
{
this.nodeService = nodeService;
}
public void setTenantService(TenantService tenantService)
{
this.tenantService = tenantService;
}
}
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
public void setPolicyComponent(PolicyComponent policyComponent)
{
this.policyComponent = policyComponent;
@@ -789,4 +818,11 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
}
}
public boolean getUserNamesAreCaseSensitive()
{
return userNameMatcher.getUserNamesAreCaseSensitive();
}
}

View File

@@ -28,6 +28,10 @@ import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
@@ -106,6 +110,51 @@ public class PersonServiceLoader
PersonServiceLoader loader = new PersonServiceLoader(ctx, batchSize, batchCount);
loader.run(user, pwd, threads);
// check the lazy creation
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName());
final ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
final AuthenticationService authenticationService = serviceRegistry.getAuthenticationService();
final PersonService personService = serviceRegistry.getPersonService();
final TransactionService transactionService = serviceRegistry.getTransactionService();
final NodeService nodeService = serviceRegistry.getNodeService();
String firstName = "" + System.currentTimeMillis();
String lastName = String.format("%05d", -1);
String username = GUID.generate();
String emailAddress = String.format("%s.%s@xyz.com", firstName, lastName);
PropertyMap properties = new PropertyMap(7);
properties.put(ContentModel.PROP_USERNAME, username);
properties.put(ContentModel.PROP_FIRSTNAME, firstName);
properties.put(ContentModel.PROP_LASTNAME, lastName);
properties.put(ContentModel.PROP_EMAIL, emailAddress);
NodeRef madePerson = personService.createPerson(properties);
NodeRef homeFolder = DefaultTypeConverter.INSTANCE.convert(NodeRef.class, nodeService.getProperty(madePerson, ContentModel.PROP_HOMEFOLDER));
if(homeFolder != null)
{
throw new IllegalStateException("Home folder created eagerly");
}
NodeRef person = personService.getPerson(username);
homeFolder = DefaultTypeConverter.INSTANCE.convert(NodeRef.class, nodeService.getProperty(person, ContentModel.PROP_HOMEFOLDER));
if(homeFolder == null)
{
throw new IllegalStateException("Home folder not created lazily");
}
NodeRef autoPerson = personService.getPerson(GUID.generate());
NodeRef autoHomeFolder = DefaultTypeConverter.INSTANCE.convert(NodeRef.class, nodeService.getProperty(autoPerson, ContentModel.PROP_HOMEFOLDER));
if(autoHomeFolder == null)
{
throw new IllegalStateException("Home folder not created lazily for auto created users");
}
// All done
ApplicationContextHelper.closeApplicationContext();
System.exit(0);

View File

@@ -0,0 +1,48 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.security.person;
/**
* Check if userNames match
* @author andyh
*
*/
public interface UserNameMatcher
{
/**
* Do the two user names match?
*
* @param userName1
* @param userName2
* @return
*/
public boolean matches(String userName1, String userName2);
public boolean getUserNamesAreCaseSensitive();
public boolean getDomainNamesAreCaseSensitive();
public String getDomainSeparator();
}

View File

@@ -0,0 +1,74 @@
package org.alfresco.repo.security.person;
import org.alfresco.util.Pair;
public class UserNameMatcherImpl implements UserNameMatcher
{
private boolean userNamesAreCaseSensitive = false;
private boolean domainNamesAreCaseSensitive = false;
private String domainSeparator = "";
public boolean getUserNamesAreCaseSensitive()
{
return userNamesAreCaseSensitive;
}
public void setUserNamesAreCaseSensitive(boolean userNamesAreCaseSensitive)
{
this.userNamesAreCaseSensitive = userNamesAreCaseSensitive;
}
public boolean getDomainNamesAreCaseSensitive()
{
return domainNamesAreCaseSensitive;
}
public void setDomainNamesAreCaseSensitive(boolean domainNamesAreCaseSensitive)
{
this.domainNamesAreCaseSensitive = domainNamesAreCaseSensitive;
}
public String getDomainSeparator()
{
return domainSeparator;
}
public void setDomainSeparator(String domainSeparator)
{
this.domainSeparator = domainSeparator;
}
public boolean matches(String realUserName, String searchUserName)
{
// note: domain string may be empty
Pair<String, String> real = splitByDomain(realUserName, domainSeparator);
Pair<String, String> search = splitByDomain(searchUserName, domainSeparator);
return (((userNamesAreCaseSensitive && (real.getFirst().equals(search.getFirst()))) || (!userNamesAreCaseSensitive && (real.getFirst().equalsIgnoreCase(search
.getFirst())))) &&
((domainNamesAreCaseSensitive && (real.getSecond().equals(search.getSecond()))) || (!domainNamesAreCaseSensitive && (real.getSecond().equalsIgnoreCase(search
.getSecond())))));
}
// Trailing domain only
private Pair<String, String> splitByDomain(String name, String domainSeparator)
{
int idx = name.lastIndexOf(domainSeparator);
if (idx != -1)
{
if ((idx + 1) > name.length())
{
return new Pair<String, String>(name.substring(0, idx), "");
}
else
{
return new Pair<String, String>(name.substring(0, idx), name.substring(idx + 1));
}
}
return new Pair<String, String>(name, "");
}
}

View File

@@ -82,7 +82,7 @@ public class UserUsageTrackingComponentTest extends TestCase
nodeService = (NodeService)applicationContext.getBean("NodeService");
authenticationService = (AuthenticationService)applicationContext.getBean("authenticationService");
transactionService = (TransactionService)applicationContext.getBean("transactionComponent");
personService = (PersonService)applicationContext.getBean("personService");
personService = (PersonService)applicationContext.getBean("PersonService");
contentService = (ContentService)applicationContext.getBean("ContentService");
contentUsageService = (ContentUsageService)applicationContext.getBean("ContentUsageService");