diff --git a/config/alfresco/authentication-services-context.xml b/config/alfresco/authentication-services-context.xml index c1a83469b7..0504dfc5e4 100644 --- a/config/alfresco/authentication-services-context.xml +++ b/config/alfresco/authentication-services-context.xml @@ -74,7 +74,6 @@ - @@ -118,7 +117,6 @@ - diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml index 5bebbe3f9c..ed29ca3e85 100644 --- a/config/alfresco/core-services-context.xml +++ b/config/alfresco/core-services-context.xml @@ -519,7 +519,7 @@ - + diff --git a/config/alfresco/extension/chaining-authentication-context.xml.sample b/config/alfresco/extension/chaining-authentication-context.xml.sample index f73a4a09b1..8abcbfd99b 100644 --- a/config/alfresco/extension/chaining-authentication-context.xml.sample +++ b/config/alfresco/extension/chaining-authentication-context.xml.sample @@ -5,9 +5,9 @@ - + - + @@ -18,6 +18,17 @@ + + + + + + + + + + + diff --git a/config/alfresco/extension/ldap-authentication-context.xml.sample b/config/alfresco/extension/ldap-authentication-context.xml.sample index 08d68177ad..9830dba432 100644 --- a/config/alfresco/extension/ldap-authentication-context.xml.sample +++ b/config/alfresco/extension/ldap-authentication-context.xml.sample @@ -3,6 +3,17 @@ + + + + + true + + + classpath:alfresco/extension/ldap-authentication.properties + + + @@ -34,11 +45,11 @@ "%s" - the user id is passed through without modification. Used for LDAP authentication such as DIGEST-MD5, anything that is not "simple". - "cn=%s,ou=London,dc=company,dc=com" - If the user types in "Joe Bloggs" the authentricate as "cn=Joe Bloggs,ou=London,dc=company,dc=com" - Usually for simple authentication. + "cn=%s,ou=London,dc=company,dc=com" - If the user types in "Joe Bloggs" the authenticate as "cn=Joe Bloggs,ou=London,dc=company,dc=com" + Usually for simple authentication. Simple authentication always uses the DN for the user. --> - %s + ${ldap.authentication.userNameFormat} @@ -54,14 +65,14 @@ - com.sun.jndi.ldap.LdapCtxFactory + ${ldap.authentication.java.naming.factory.initial} - ldap://openldap.domain.com:389 + ${ldap.authentication.java.naming.provider.url} @@ -69,390 +80,21 @@ - DIGEST-MD5 + ${ldap.authentication.java.naming.security.authentication} - reader + ${ldap.authentication.java.naming.security.principal} - secret + ${ldap.authentication.java.naming.security.credentials} - - - - - - - - - - - (objectclass=inetOrgPerson) - - - - - dc=alfresco,dc=org - - - - - uid - - - - - - - - - - - - - - - - - - - uid - - - - - givenName - - - - - sn - - - - - mail - - - - - o - - - - - - - - - - - - - personalHomeFolderProvider - - - - - - - - - - - (objectclass=groupOfNames) - - - - - dc=alfresco,dc=org - - - - - uid - - - - - cn - - - - - groupOfNames - - - - - inetOrgPerson - - - - - - - - - - - member - - - - - - - - - - - - - - - - - - - - - org.alfresco.repo.importer.ImporterJob - - - - - - - - - - - - - 300000 - - - - 3600000 - - - - - - - - - org.alfresco.repo.importer.ImporterJob - - - - - - - - - - - - - 300000 - - - - 3600000 - - - - - - - - - - - - - - - - - - - - - - - ${spaces.store} - - - - - /${system.system_container.childname}/${system.people_container.childname} - - - - - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ${alfresco_user_store.store} - - - - - /${alfresco_user_store.system_container.childname}/${alfresco_user_store.authorities_container.childname} - - - - - true - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/config/alfresco/extension/ldap-authentication.properties b/config/alfresco/extension/ldap-authentication.properties new file mode 100644 index 0000000000..7b5a8bab83 --- /dev/null +++ b/config/alfresco/extension/ldap-authentication.properties @@ -0,0 +1,27 @@ +# +# This properties file brings together the common options for LDAP authentication rather than editing the bean definitions +# + +# How to map the user id entered by the user to taht passed through to LDAP +# - simple +# - this must be a DN and would be something like +# CN=%s,DC=company,DC=com +# - digest +# - usually pass through what is entered +# %s +ldap.authentication.userNameFormat=%s + +# The LDAP context factory to use +ldap.authentication.java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory + +# The URL to connect to the LDAP server +ldap.authentication.java.naming.provider.url=ldap://openldap.domain.com:389 + +# The authentication mechanism to use +ldap.authentication.java.naming.security.authentication=DIGEST-MD5 + +# The default principal to use (only used for LDAP sync) +ldap.authentication.java.naming.security.principal=reader + +# The password for the default principal (only used for LDAP sync) +ldap.authentication.java.naming.security.credentials=secret \ No newline at end of file diff --git a/config/alfresco/extension/ldap-synchronisation-context.xml.sample b/config/alfresco/extension/ldap-synchronisation-context.xml.sample new file mode 100644 index 0000000000..d61cb0b408 --- /dev/null +++ b/config/alfresco/extension/ldap-synchronisation-context.xml.sample @@ -0,0 +1,377 @@ + + + + + + + + true + + + classpath:alfresco/extension/ldap-synchronisation.properties + + + + + + + + + + + + + + + + + + ${ldap.synchronisation.personQuery} + + + + + ${ldap.synchronisation.personSearchBase} + + + + + ${ldap.synchronisation.userIdAttributeName] + + + + + + + + + + + + + + + + + + + ${ldap.synchronisation.userIdAttributeName} + + + + + ${ldap.synchronisation.userFirstNameAttributeName} + + + + + ${ldap.synchronisation.userLastNameAttributeName} + + + + + ${ldap.synchronisation.userEmailAttributeName} + + + + + ${ldap.synchronisation.userOrganizationalIdAttributeName} + + + + + + + + + + + + + ${ldap.synchronisation.defaultHomeFolderProvider} + + + + + + + + + + + ${ldap.synchronisation.groupQuery} + + + + + ${ldap.synchronisation.groupSearchBase} + + + + + ${ldap.synchronisation.userIdAttributeName} + + + + + ${ldap.synchronisation.groupIdAttributeName} + + + + + ${ldap.synchronisation.groupType} + + + + + ${ldap.synchronisation.personType} + + + + + + + + + + + ${ldap.synchronisation.groupMemberAttributeName} + + + + + + + + + + + + + + + + + + + + + org.alfresco.repo.importer.ImporterJob + + + + + + + + + + + + ${ldap.synchronisation.import.person.cron} + + + + + + + + + + + org.alfresco.repo.importer.ImporterJob + + + + + + + + + + + + ${ldap.synchronisation.import.group.cron} + + + + + + + + + + + + + + + + + + + + + + + + + ${spaces.store} + + + + + /${system.system_container.childname}/${system.people_container.childname} + + + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${alfresco_user_store.store} + + + + + /${alfresco_user_store.system_container.childname}/${alfresco_user_store.authorities_container.childname} + + + + + ${ldap.synchronisation.import.group.clearAllChildren} + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/alfresco/extension/ldap-synchronisation.properties b/config/alfresco/extension/ldap-synchronisation.properties new file mode 100644 index 0000000000..ffd1392f9d --- /dev/null +++ b/config/alfresco/extension/ldap-synchronisation.properties @@ -0,0 +1,59 @@ +# +# This properties file is used to configure LDAP syncronisation +# + +# The query to find the people to import +ldap.synchronisation.personQuery=(objectclass=inetOrgPerson) + +# The search base of the query to find people to import +ldap.synchronisation.personSearchBase=dc=company,dc=com + +# The attribute name on people objects found in LDAP to use as the uid in Alfresco +ldap.synchronisation.userIdAttributeName=uid + +# The attribute on person objects in LDAP to map to the first name property in Alfresco +ldap.synchronisation.userFirstNameAttributeName=givenName + +# The attribute on person objects in LDAP to map to the last name property in Alfresco +ldap.synchronisation.userLastNameAttributeName=sn + +# The attribute on person objects in LDAP to map to the email property in Alfresco +ldap.synchronisation.userEmailAttributeName=mail + +# The attribute on person objects in LDAP to map to the organizational id property in Alfresco +ldap.synchronisation.userOrganizationalIdAttributeName=o + +# The default home folder provider to use for people created via LDAP import +ldap.synchronisation.defaultHomeFolderProvider=personalHomeFolderProvider + +# The query to find group objects +ldap.synchronisation.groupQuery=(objectclass=groupOfNames) + +# The search base to use to find group objects +ldap.synchronisation.groupSearchBase=dc=company,dc=com + +# The attribute on LDAP group objects to map to the gid property in Alfrecso +ldap.synchronisation.groupIdAttributeName=cn + +# The group type in LDAP +ldap.synchronisation.groupType=groupOfNames + +# The person type in LDAP +ldap.synchronisation.personType=inetOrgPerson + +# The attribute in LDAP on group objects that defines the DN for its members +ldap.synchronisation.groupMemberAttributeName=member + +# The cron expression defining when people imports should take place +ldap.synchronisation.import.person.cron=0 0 * * * ? + +# The cron expression defining when group imports should take place +ldap.synchronisation.import.group.cron=0 30 * * * ? + +# Should all groups be cleared out at import time? +# - this is safe as groups are not used in Alfresco for other things (unlike person objects which you should never clear out during an import) +# - setting this to true means old group definitions will be tidied up. +ldap.synchronisation.import.group.clearAllChildren=true + + + diff --git a/config/alfresco/model/contentModel.xml b/config/alfresco/model/contentModel.xml index 91b7857084..7024f83836 100644 --- a/config/alfresco/model/contentModel.xml +++ b/config/alfresco/model/contentModel.xml @@ -219,6 +219,7 @@ false true + false diff --git a/config/alfresco/ownable-services-context.xml b/config/alfresco/ownable-services-context.xml index a2bbab152b..9e2848e0c2 100644 --- a/config/alfresco/ownable-services-context.xml +++ b/config/alfresco/ownable-services-context.xml @@ -7,10 +7,13 @@ - + + + + \ No newline at end of file diff --git a/config/alfresco/public-services-security-context.xml b/config/alfresco/public-services-security-context.xml index e09f634d42..6e0b4cc6d3 100644 --- a/config/alfresco/public-services-security-context.xml +++ b/config/alfresco/public-services-security-context.xml @@ -204,7 +204,7 @@ - + ${system.acl.maxPermissionCheckTimeMillis} diff --git a/config/alfresco/rule-services-context.xml b/config/alfresco/rule-services-context.xml index b8e669c6c5..e8deb83ebe 100644 --- a/config/alfresco/rule-services-context.xml +++ b/config/alfresco/rule-services-context.xml @@ -101,6 +101,9 @@ + + + @@ -166,7 +169,7 @@ - + false diff --git a/source/java/org/alfresco/jcr/test/TestData.java b/source/java/org/alfresco/jcr/test/TestData.java index c0b329f47e..ed0075cfb7 100644 --- a/source/java/org/alfresco/jcr/test/TestData.java +++ b/source/java/org/alfresco/jcr/test/TestData.java @@ -76,7 +76,7 @@ public class TestData public Object execute() throws Exception { // Bootstrap Users - MutableAuthenticationDao authDAO = (MutableAuthenticationDao) applicationContext.getBean("alfDaoImpl"); + MutableAuthenticationDao authDAO = (MutableAuthenticationDao) applicationContext.getBean("authenticationDao"); if (authDAO.userExists("superuser") == false) { authDAO.createUser("superuser", "".toCharArray()); diff --git a/source/java/org/alfresco/repo/audit/AuditServiceTest.java b/source/java/org/alfresco/repo/audit/AuditServiceTest.java index 05643eaa3e..1bfe1938e0 100644 --- a/source/java/org/alfresco/repo/audit/AuditServiceTest.java +++ b/source/java/org/alfresco/repo/audit/AuditServiceTest.java @@ -120,7 +120,7 @@ public class AuditServiceTest extends BaseSpringTest authorityService = (AuthorityService) applicationContext.getBean("authorityService"); authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName()); - authenticationDAO = (MutableAuthenticationDao) applicationContext.getBean("alfDaoImpl"); + authenticationDAO = (MutableAuthenticationDao) applicationContext.getBean("authenticationDao"); auditService = (AuditService) applicationContext.getBean("AuditService"); auditEntry = (AuditEntry) applicationContext.getBean("auditModel"); diff --git a/source/java/org/alfresco/repo/avm/wf/AVMSubmitPackageHandler.java b/source/java/org/alfresco/repo/avm/wf/AVMSubmitPackageHandler.java index 813fd26b91..622d9ce896 100644 --- a/source/java/org/alfresco/repo/avm/wf/AVMSubmitPackageHandler.java +++ b/source/java/org/alfresco/repo/avm/wf/AVMSubmitPackageHandler.java @@ -177,7 +177,7 @@ public class AVMSubmitPackageHandler Map list = fAVMService.getDirectoryListing(desc, true); for (AVMNodeDescriptor child : list.values()) { - recursivelyRemoveLocks(webProject, child.getVersionID(), child.getPath()); + recursivelyRemoveLocks(webProject, version, child.getPath()); } } } diff --git a/source/java/org/alfresco/repo/content/metadata/xml/XPathMetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/xml/XPathMetadataExtracter.java index f657bc76a4..bb59db11a9 100644 --- a/source/java/org/alfresco/repo/content/metadata/xml/XPathMetadataExtracter.java +++ b/source/java/org/alfresco/repo/content/metadata/xml/XPathMetadataExtracter.java @@ -57,6 +57,8 @@ import org.alfresco.util.PropertyCheck; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; /** * An extracter that pulls values from XML documents using configurable XPath @@ -248,7 +250,30 @@ public class XPathMetadataExtracter extends AbstractMappingMetadataExtracter imp String documentProperty = element.getKey(); XPathExpression xpathExpression = element.getValue(); // Execute it - String value = (String) xpathExpression.evaluate(document, XPathConstants.STRING); + NodeList nodeList = (NodeList) xpathExpression.evaluate(document, XPathConstants.NODESET); + // Convert the value + Serializable value = null; + int nodeCount = nodeList.getLength(); + if (nodeCount == 0) + { + // No result + } + else if (nodeCount == 1) + { + Node node = nodeList.item(0); + // Get the string value + value = node.getTextContent(); + } + else + { + // Make a collection of the values + ArrayList stringValues = new ArrayList(5); + for (int i = 0; i < nodeCount; i++) + { + stringValues.add(nodeList.item(i).getTextContent()); + } + value = stringValues; + } // Put the value rawProperties.put(documentProperty, value); } @@ -305,7 +330,7 @@ public class XPathMetadataExtracter extends AbstractMappingMetadataExtracter imp xpathExpressionMapping.put(documentProperty, xpathExpression); if (logger.isDebugEnabled()) { - logger.debug("Added mapping from " + documentProperty + " to " + xpathExpression); + logger.debug("Added mapping from " + documentProperty + " to " + xpathStr); } } // Done diff --git a/source/java/org/alfresco/repo/ownable/impl/OwnableServiceImpl.java b/source/java/org/alfresco/repo/ownable/impl/OwnableServiceImpl.java index 8ed945a724..81868d6a4c 100644 --- a/source/java/org/alfresco/repo/ownable/impl/OwnableServiceImpl.java +++ b/source/java/org/alfresco/repo/ownable/impl/OwnableServiceImpl.java @@ -26,49 +26,65 @@ package org.alfresco.repo.ownable.impl; import java.io.Serializable; import java.util.HashMap; +import java.util.Map; import org.alfresco.model.ContentModel; import org.alfresco.repo.cache.SimpleCache; +import org.alfresco.repo.node.NodeServicePolicies; +import org.alfresco.repo.policy.JavaBehaviour; +import org.alfresco.repo.policy.PolicyComponent; +import org.alfresco.service.cmr.repository.ChildAssociationRef; 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.OwnableService; +import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; +import org.alfresco.util.EqualsHelper; import org.springframework.beans.factory.InitializingBean; /** - * Ownership service support. Use in permissions framework as dynamic authority. + * Ownership service support. Use in permissions framework as dynamic authority. * * @author Andy Hind */ -public class OwnableServiceImpl implements OwnableService, InitializingBean +public class OwnableServiceImpl implements OwnableService, InitializingBean, NodeServicePolicies.OnAddAspectPolicy, NodeServicePolicies.OnUpdatePropertiesPolicy, + NodeServicePolicies.OnRemoveAspectPolicy, NodeServicePolicies.OnDeleteNodePolicy { private NodeService nodeService; - + private AuthenticationService authenticationService; - + private SimpleCache nodeOwnerCache; + private PolicyComponent policyComponent; + public OwnableServiceImpl() { super(); } // IOC - + public void setNodeService(NodeService nodeService) { this.nodeService = nodeService; } - + public void setAuthenticationService(AuthenticationService authenticationService) { this.authenticationService = authenticationService; } - + + public void setPolicyComponent(PolicyComponent policyComponent) + { + this.policyComponent = policyComponent; + } + /** - * @param ownerCache a transactionally-safe cache of node owners + * @param ownerCache + * a transactionally-safe cache of node owners */ public void setNodeOwnerCache(SimpleCache ownerCache) { @@ -89,14 +105,31 @@ public class OwnableServiceImpl implements OwnableService, InitializingBean { throw new IllegalArgumentException("Property 'nodeOwnerCache' has not been set"); } + if (policyComponent == null) + { + throw new IllegalArgumentException("Property 'policyComponent' has not been set"); + } + + policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onAddAspect"), ContentModel.ASPECT_OWNABLE, new JavaBehaviour(this, "onAddAspect")); + policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"), ContentModel.ASPECT_OWNABLE, new JavaBehaviour(this, "onUpdateProperties")); + policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onRemoveAspect"), ContentModel.ASPECT_OWNABLE, new JavaBehaviour(this, + "onRemoveAspect")); + policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onDeleteNode"), ContentModel.ASPECT_OWNABLE, new JavaBehaviour(this, "onDeleteNode")); + + policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onAddAspect"), ContentModel.ASPECT_AUDITABLE, new JavaBehaviour(this, "onAddAspect")); + policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"), ContentModel.ASPECT_AUDITABLE, new JavaBehaviour(this, "onUpdateProperties")); + policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onRemoveAspect"), ContentModel.ASPECT_AUDITABLE, new JavaBehaviour(this, + "onRemoveAspect")); + policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onDeleteNode"), ContentModel.ASPECT_AUDITABLE, new JavaBehaviour(this, "onDeleteNode")); + } - + // OwnableService implmentation - + public String getOwner(NodeRef nodeRef) { String userName = nodeOwnerCache.get(nodeRef); - + if (userName == null) { // If ownership is not explicitly set then we fall back to the creator @@ -104,13 +137,13 @@ public class OwnableServiceImpl implements OwnableService, InitializingBean { userName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(nodeRef, ContentModel.PROP_OWNER)); } - else if(nodeService.hasAspect(nodeRef, ContentModel.ASPECT_AUDITABLE)) + else if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_AUDITABLE)) { userName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(nodeRef, ContentModel.PROP_CREATOR)); } nodeOwnerCache.put(nodeRef, userName); } - + return userName; } @@ -138,4 +171,41 @@ public class OwnableServiceImpl implements OwnableService, InitializingBean { return getOwner(nodeRef) != null; } + + public void onAddAspect(NodeRef nodeRef, QName aspectTypeQName) + { + nodeOwnerCache.remove(nodeRef); + } + + public void onRemoveAspect(NodeRef nodeRef, QName aspectTypeQName) + { + nodeOwnerCache.remove(nodeRef); + } + + public void onDeleteNode(ChildAssociationRef childAssocRef, boolean isNodeArchived) + { + nodeOwnerCache.remove(childAssocRef.getChildRef()); + } + + public void onUpdateProperties(NodeRef nodeRef, Map before, Map after) + { + Serializable pb = before.get(ContentModel.PROP_OWNER); + Serializable pa = after.get(ContentModel.PROP_OWNER); + + if (!EqualsHelper.nullSafeEquals(pb, pa)) + { + nodeOwnerCache.remove(nodeRef); + return; + } + + pb = before.get(ContentModel.PROP_CREATOR); + pa = after.get(ContentModel.PROP_CREATOR); + + if (!EqualsHelper.nullSafeEquals(pb, pa)) + { + nodeOwnerCache.remove(nodeRef); + return; + } + + } } diff --git a/source/java/org/alfresco/repo/ownable/impl/OwnableServiceTest.java b/source/java/org/alfresco/repo/ownable/impl/OwnableServiceTest.java index c888393f2f..137340d3a3 100644 --- a/source/java/org/alfresco/repo/ownable/impl/OwnableServiceTest.java +++ b/source/java/org/alfresco/repo/ownable/impl/OwnableServiceTest.java @@ -24,6 +24,9 @@ */ package org.alfresco.repo.ownable.impl; +import java.io.Serializable; +import java.util.HashMap; + import javax.transaction.UserTransaction; import junit.framework.TestCase; @@ -40,6 +43,7 @@ import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.cmr.security.OwnableService; import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.namespace.QName; import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.ApplicationContextHelper; import org.springframework.context.ApplicationContext; @@ -85,7 +89,7 @@ public class OwnableServiceTest extends TestCase permissionService = (PermissionService) ctx.getBean("permissionService"); authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName()); - authenticationDAO = (MutableAuthenticationDao) ctx.getBean("alfDaoImpl"); + authenticationDAO = (MutableAuthenticationDao) ctx.getBean("authenticationDao"); TransactionService transactionService = (TransactionService) ctx.getBean(ServiceRegistry.TRANSACTION_SERVICE.getLocalName()); @@ -147,6 +151,14 @@ public class OwnableServiceTest extends TestCase assertFalse(nodeService.hasAspect(testNode, ContentModel.ASPECT_OWNABLE)); assertTrue(dynamicAuthority.hasAuthority(testNode, "andy")); + assertEquals("andy", ownableService.getOwner(testNode)); + + nodeService.setProperty(testNode, ContentModel.PROP_CREATOR, "woof"); + assertEquals("woof", ownableService.getOwner(testNode)); + + nodeService.setProperty(testNode, ContentModel.PROP_CREATOR, "andy"); + assertEquals("andy", ownableService.getOwner(testNode)); + permissionService.setInheritParentPermissions(testNode, false); @@ -189,6 +201,16 @@ public class OwnableServiceTest extends TestCase assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(testNode, PermissionService.TAKE_OWNERSHIP)); assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(testNode, PermissionService.SET_OWNER)); + nodeService.setProperty(testNode, ContentModel.PROP_OWNER, "muppet"); + assertEquals("muppet", ownableService.getOwner(testNode)); + nodeService.removeAspect(testNode, ContentModel.ASPECT_OWNABLE); + assertEquals("andy", ownableService.getOwner(testNode)); + + HashMap aspectProperties = new HashMap(); + aspectProperties.put(ContentModel.PROP_OWNER, "muppet"); + nodeService.addAspect(testNode, ContentModel.ASPECT_OWNABLE, aspectProperties); + assertEquals("muppet", ownableService.getOwner(testNode)); + } diff --git a/source/java/org/alfresco/repo/rule/ruletrigger/OnContentUpdateRuleTrigger.java b/source/java/org/alfresco/repo/rule/ruletrigger/OnContentUpdateRuleTrigger.java index f4a57af465..94ee0688db 100644 --- a/source/java/org/alfresco/repo/rule/ruletrigger/OnContentUpdateRuleTrigger.java +++ b/source/java/org/alfresco/repo/rule/ruletrigger/OnContentUpdateRuleTrigger.java @@ -26,9 +26,12 @@ package org.alfresco.repo.rule.ruletrigger; import java.util.List; +import org.alfresco.model.ContentModel; import org.alfresco.repo.content.ContentServicePolicies; +import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.NodeRef; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -87,9 +90,24 @@ public class OnContentUpdateRuleTrigger extends RuleTriggerAbstractBase */ public void onContentUpdate(NodeRef nodeRef, boolean newContent) { - if (newContent == this.onNewContent) + + // Check the new content and make sure that we do indeed want to trigger the rule + boolean fail = false; + if (newContent == true) + { + ContentReader contentReader = this.contentService.getReader(nodeRef, ContentModel.PROP_CONTENT); + if (contentReader == null || + contentReader.exists() == false || + isZeroLengthOfficeDoc(contentReader) == true) + { + fail = true; + } + } + + // Trigger the rules in the appropriate way + if (fail == false && newContent == this.onNewContent) { - if (triggerParentRules == true) + if (triggerParentRules == true) { if (logger.isDebugEnabled() == true) { @@ -108,5 +126,24 @@ public class OnContentUpdateRuleTrigger extends RuleTriggerAbstractBase } } } + + /** + * Indicates whether we are dealing with a zero length office document or not + * + * @param contentReader the content reader + * @return boolean true if zero length office document, false otherwise + */ + private boolean isZeroLengthOfficeDoc(ContentReader contentReader) + { + boolean result = false; + if (contentReader.getSize() == 0 && + (MimetypeMap.MIMETYPE_WORD.equals(contentReader.getMimetype()) == true || + MimetypeMap.MIMETYPE_EXCEL.equals(contentReader.getMimetype()) == true || + MimetypeMap.MIMETYPE_PPT.equals(contentReader.getMimetype()) == true)) + { + result = true; + } + return result; + } } diff --git a/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerAbstractBase.java b/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerAbstractBase.java index 3f905590da..9affdee83b 100644 --- a/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerAbstractBase.java +++ b/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerAbstractBase.java @@ -30,12 +30,13 @@ import java.util.Set; import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.rule.RuleType; /** - * Rule trigger abstract base + * Rule trigger abstract base * * @author Roy Wetherall */ @@ -55,6 +56,11 @@ public abstract class RuleTriggerAbstractBase implements RuleTrigger * The node service */ protected NodeService nodeService; + + /** + * The content service + */ + protected ContentService contentService; /** * The authentication Component @@ -91,6 +97,16 @@ public abstract class RuleTriggerAbstractBase implements RuleTrigger { this.nodeService = nodeService; } + + /** + * Set the content service + * + * @param contentService the content service + */ + public void setContentService(ContentService contentService) + { + this.contentService = contentService; + } /** * Set the authenticationComponent @@ -123,6 +139,7 @@ public abstract class RuleTriggerAbstractBase implements RuleTrigger /** * Registration of an interested rule type + * */ public void registerRuleType(RuleType ruleType) { @@ -131,7 +148,7 @@ public abstract class RuleTriggerAbstractBase implements RuleTrigger /** * Trigger the rules that relate to any interested rule types for the node - * references passed. + * references passed. * * @param nodeRef * the node reference who rules are to be triggered diff --git a/source/java/org/alfresco/repo/search/SearchServiceTest.java b/source/java/org/alfresco/repo/search/SearchServiceTest.java index 1a2cb079b9..6e30d0c463 100644 --- a/source/java/org/alfresco/repo/search/SearchServiceTest.java +++ b/source/java/org/alfresco/repo/search/SearchServiceTest.java @@ -98,7 +98,7 @@ public class SearchServiceTest extends TestCase nodeService = (NodeService) ctx.getBean("dbNodeService"); authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent"); authenticationService = (AuthenticationService) ctx.getBean("authenticationService"); - authenticationDAO = (MutableAuthenticationDao) ctx.getBean("alfDaoImpl"); + authenticationDAO = (MutableAuthenticationDao) ctx.getBean("authenticationDao"); pubSearchService = (SearchService) ctx.getBean("SearchService"); pubPermissionService = (PermissionService) ctx.getBean("PermissionService"); diff --git a/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationComponent.java b/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationComponent.java index baa5b6b4e9..b7e31a3803 100644 --- a/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationComponent.java +++ b/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationComponent.java @@ -28,10 +28,6 @@ import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.GrantedAuthority; import net.sf.acegisecurity.GrantedAuthorityImpl; import net.sf.acegisecurity.UserDetails; -import net.sf.acegisecurity.context.Context; -import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.security.SecureContext; -import net.sf.acegisecurity.context.security.SecureContextImpl; import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken; import net.sf.acegisecurity.providers.dao.User; @@ -46,11 +42,9 @@ import org.alfresco.service.cmr.security.PermissionService; */ public abstract class AbstractAuthenticationComponent implements AuthenticationComponent { - - // Name of the system user - - static final String SYSTEM_USER_NAME = "System"; - + /** + * The abstract class keeps track of support for guest login + */ private Boolean allowGuestLogin = null; public AbstractAuthenticationComponent() @@ -58,6 +52,11 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC super(); } + /** + * Set if guest login is supported. + * + * @param allowGuestLogin + */ public void setAllowGuestLogin(Boolean allowGuestLogin) { this.allowGuestLogin = allowGuestLogin; @@ -65,6 +64,7 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC public void authenticate(String userName, char[] password) throws AuthenticationException { + // Support guest login from the login screen if ((userName != null) && (userName.equalsIgnoreCase(PermissionService.GUEST_AUTHORITY))) { setGuestUserAsCurrentUser(); @@ -75,6 +75,14 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC } } + /** + * Default unsupported authentication implementation + * - as of 2.1 this is the best way to implement your own authentication component as it will support guest login + * - prior to this direct over ride for authenticate(String , char[]) was used. This will still work. + * + * @param userName + * @param password + */ protected void authenticateImpl(String userName, char[] password) { throw new UnsupportedOperationException(); @@ -97,11 +105,11 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC try { UserDetails ud = null; - if (userName.equals(SYSTEM_USER_NAME)) + if (userName.equals(AuthenticationUtil.SYSTEM_USER_NAME)) { GrantedAuthority[] gas = new GrantedAuthority[1]; gas[0] = new GrantedAuthorityImpl("ROLE_SYSTEM"); - ud = new User(SYSTEM_USER_NAME, "", true, true, true, true, gas); + ud = new User(AuthenticationUtil.SYSTEM_USER_NAME, "", true, true, true, true, gas); } else if (userName.equalsIgnoreCase(PermissionService.GUEST_AUTHORITY)) { @@ -173,28 +181,6 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC return AuthenticationUtil.getCurrentUserName(); } - /** - * Get the current user name - * - * @param authentication - * Authentication - * @return String - */ - private String getUserName(Authentication authentication) - { - String username; - if (authentication.getPrincipal() instanceof UserDetails) - { - username = ((UserDetails) authentication.getPrincipal()).getUsername(); - } - else - { - username = authentication.getPrincipal().toString(); - } - - return username; - } - /** * Set the system user as the current user. * @@ -202,7 +188,7 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC */ public Authentication setSystemUserAsCurrentUser() { - return setCurrentUser(SYSTEM_USER_NAME); + return setCurrentUser(AuthenticationUtil.SYSTEM_USER_NAME); } /** @@ -212,7 +198,7 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC */ public String getSystemUserName() { - return SYSTEM_USER_NAME; + return AuthenticationUtil.SYSTEM_USER_NAME; } /** diff --git a/source/java/org/alfresco/repo/security/authentication/AuthenticationTest.java b/source/java/org/alfresco/repo/security/authentication/AuthenticationTest.java index 23f345cdd5..7e28fa99aa 100644 --- a/source/java/org/alfresco/repo/security/authentication/AuthenticationTest.java +++ b/source/java/org/alfresco/repo/security/authentication/AuthenticationTest.java @@ -135,7 +135,7 @@ public class AuthenticationTest extends TestCase // ctx.getBean("permissionService"); ticketsCache = (SimpleCache) ctx.getBean("ticketsCache"); - dao = (MutableAuthenticationDao) ctx.getBean("alfDaoImpl"); + dao = (MutableAuthenticationDao) ctx.getBean("authenticationDao"); authenticationManager = (AuthenticationManager) ctx.getBean("authenticationManager"); saltSource = (SaltSource) ctx.getBean("saltSource"); diff --git a/source/java/org/alfresco/repo/security/authentication/AuthenticationUtil.java b/source/java/org/alfresco/repo/security/authentication/AuthenticationUtil.java index a83ef0a637..65fef412a8 100644 --- a/source/java/org/alfresco/repo/security/authentication/AuthenticationUtil.java +++ b/source/java/org/alfresco/repo/security/authentication/AuthenticationUtil.java @@ -231,7 +231,6 @@ public abstract class AuthenticationUtil private static String getUserName(Authentication authentication) { String username; - if (authentication.getPrincipal() instanceof UserDetails) { username = ((UserDetails) authentication.getPrincipal()).getUsername(); diff --git a/source/java/org/alfresco/repo/security/authentication/ChainingAuthenticationComponentImpl.java b/source/java/org/alfresco/repo/security/authentication/ChainingAuthenticationComponentImpl.java new file mode 100644 index 0000000000..74cf50fdce --- /dev/null +++ b/source/java/org/alfresco/repo/security/authentication/ChainingAuthenticationComponentImpl.java @@ -0,0 +1,400 @@ +/* + * 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.authentication; + +import java.util.ArrayList; +import java.util.List; + +import net.sf.acegisecurity.Authentication; + +import org.alfresco.service.cmr.security.PermissionService; + +/** + * A chaining authentication component is required for all the beans that qire up an authentication component and not an + * authentication service. It supports chaining in much the same way and wires up components in the same way asthe + * chaining authentication service wires up services. + * + * @author andyh + */ +public class ChainingAuthenticationComponentImpl implements AuthenticationComponent +{ + /** + * NLTM authentication mode - if unset - finds the first component that supports NTLM - if set - finds the first + * component that supports the specified mode. + */ + private NTLMMode ntlmMode = null; + + /** + * The authentication components + */ + private List authenticationComponents; + + /** + * An authentication service that supports change (as wired in to the authentication service). It is never used for + * change it is to ensure it is at the top of the list (as required by the chaining authentication service) + */ + private AuthenticationComponent mutableAuthenticationComponent; + + /** + * Get the authentication components + * + * @return - a list of authentication components + */ + public List getAuthenticationComponents() + { + return authenticationComponents; + } + + /** + * Set a list of authentication components + * + * @param authenticationComponents + */ + public void setAuthenticationComponents(List authenticationComponents) + { + this.authenticationComponents = authenticationComponents; + } + + /** + * Get the authentication service thta must be at the top of the list (this may be null) + * + * @return + */ + public AuthenticationComponent getMutableAuthenticationComponent() + { + return mutableAuthenticationComponent; + } + + /** + * Set the authentication component at the top of the list. + * + * @param mutableAuthenticationComponent + */ + public void setMutableAuthenticationComponent(AuthenticationComponent mutableAuthenticationComponent) + { + this.mutableAuthenticationComponent = mutableAuthenticationComponent; + } + + + + public void setNtlmMode(NTLMMode ntlmMode) + { + this.ntlmMode = ntlmMode; + } + + /** + * Chain authentication with user name and password - tries all in order until one works, or fails. + */ + public void authenticate(String userName, char[] password) throws AuthenticationException + { + for (AuthenticationComponent authComponent : getUsableAuthenticationComponents()) + { + try + { + authComponent.authenticate(userName, password); + return; + } + catch (AuthenticationException e) + { + // Ignore and chain + } + } + throw new AuthenticationException("Failed to authenticate"); + } + + /** + * NTLM passthrough authentication - if a mode is defined - the first PASS_THROUGH provider is used - if not, the + * first component that supports NTLM is used if it supports PASS_THROUGH + */ + public Authentication authenticate(Authentication token) throws AuthenticationException + { + if (ntlmMode != null) + { + switch (ntlmMode) + { + case NONE: + throw new AuthenticationException("NTLM is not supported"); + case MD4_PROVIDER: + throw new AuthenticationException("NTLM passthrough is not supported then configured for MD4 hashing"); + case PASS_THROUGH: + for (AuthenticationComponent authComponent : getUsableAuthenticationComponents()) + { + if (authComponent.getNTLMMode() == NTLMMode.PASS_THROUGH) + { + return authComponent.authenticate(token); + } + } + throw new AuthenticationException("No NTLM passthrough authentication to use"); + default: + throw new AuthenticationException("No NTLM passthrough authentication to use"); + } + } + else + { + for (AuthenticationComponent authComponent : getUsableAuthenticationComponents()) + { + if (authComponent.getNTLMMode() != NTLMMode.NONE) + { + if (authComponent.getNTLMMode() == NTLMMode.PASS_THROUGH) + { + return authComponent.authenticate(token); + } + else + { + throw new AuthenticationException("The first authentication component to support NTLM supports MD4 hashing"); + } + } + } + throw new AuthenticationException("No NTLM passthrough authentication to use"); + } + + } + + /** + * Clear the security context + */ + public void clearCurrentSecurityContext() + { + AuthenticationUtil.clearCurrentSecurityContext(); + } + + /** + * Get the current authentication + */ + public Authentication getCurrentAuthentication() throws AuthenticationException + { + return AuthenticationUtil.getCurrentAuthentication(); + } + + /** + * Get the current user name + */ + public String getCurrentUserName() throws AuthenticationException + { + return AuthenticationUtil.getCurrentUserName(); + } + + /** + * Get the guest user name + */ + public String getGuestUserName() + { + return PermissionService.GUEST_AUTHORITY.toLowerCase(); + } + + /** + * Get the MD4 password hash + */ + public String getMD4HashedPassword(String userName) + { + if (ntlmMode != null) + { + switch (ntlmMode) + { + case NONE: + throw new AuthenticationException("NTLM is not supported"); + case PASS_THROUGH: + throw new AuthenticationException("NTLM passthrough is not supported then configured for MD4 hashing"); + case MD4_PROVIDER: + for (AuthenticationComponent authComponent : getUsableAuthenticationComponents()) + { + if (authComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER) + { + return authComponent.getMD4HashedPassword(userName); + } + } + throw new AuthenticationException("No MD4 provider available"); + default: + throw new AuthenticationException("No MD4 provider available"); + } + } + else + { + for (AuthenticationComponent authComponent : getUsableAuthenticationComponents()) + { + if (authComponent.getNTLMMode() != NTLMMode.NONE) + { + if (authComponent.getNTLMMode() == NTLMMode.PASS_THROUGH) + { + throw new AuthenticationException("The first authentication component to support NTLM supports passthrough"); + } + else + { + return authComponent.getMD4HashedPassword(userName); + } + } + } + throw new AuthenticationException("No MD4 provider available"); + } + + } + + /** + * Get the NTLM mode - this is only what is set if one of the implementations provides support for that mode. + */ + public NTLMMode getNTLMMode() + { + if (ntlmMode != null) + { + switch (ntlmMode) + { + case NONE: + return NTLMMode.NONE; + case PASS_THROUGH: + for (AuthenticationComponent authComponent : getUsableAuthenticationComponents()) + { + if (authComponent.getNTLMMode() == NTLMMode.PASS_THROUGH) + { + return NTLMMode.PASS_THROUGH; + } + } + return NTLMMode.NONE; + case MD4_PROVIDER: + for (AuthenticationComponent authComponent : getUsableAuthenticationComponents()) + { + if (authComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER) + { + return NTLMMode.MD4_PROVIDER; + } + } + return NTLMMode.NONE; + default: + return NTLMMode.NONE; + } + } + else + { + for (AuthenticationComponent authComponent : getUsableAuthenticationComponents()) + { + if (authComponent.getNTLMMode() != NTLMMode.NONE) + { + return authComponent.getNTLMMode(); + } + } + return NTLMMode.NONE; + } + } + + /** + * Get the system user name + */ + public String getSystemUserName() + { + return AuthenticationUtil.SYSTEM_USER_NAME; + } + + /** + * If any implementation supoprts guest then huest is allowed + */ + public boolean guestUserAuthenticationAllowed() + { + for (AuthenticationComponent authComponent : getUsableAuthenticationComponents()) + { + if (authComponent.guestUserAuthenticationAllowed()) + { + return true; + } + } + return false; + } + + /** + * Ste the current authentication + */ + public Authentication setCurrentAuthentication(Authentication authentication) + { + return AuthenticationUtil.setCurrentAuthentication(authentication); + } + + /** + * Set the current user - try all implementations - as some may check the user exists + */ + public Authentication setCurrentUser(String userName) + { + for (AuthenticationComponent authComponent : getUsableAuthenticationComponents()) + { + try + { + return authComponent.setCurrentUser(userName); + } + catch (AuthenticationException e) + { + // Ignore and chain + } + } + throw new AuthenticationException("Failed to set current user " + userName); + } + + /** + * Authenticate as guest - try all in the cahin + */ + public Authentication setGuestUserAsCurrentUser() + { + for (AuthenticationComponent authComponent : getUsableAuthenticationComponents()) + { + try + { + return authComponent.setGuestUserAsCurrentUser(); + } + catch (AuthenticationException e) + { + // Ignore and chain + } + } + throw new AuthenticationException("Guest authentication is not allowed"); + } + + /** + * Set the system user + */ + public Authentication setSystemUserAsCurrentUser() + { + return setCurrentUser(getSystemUserName()); + } + + /** + * Helper to get authentication components + * + * @return + */ + private List getUsableAuthenticationComponents() + { + if (mutableAuthenticationComponent == null) + { + return authenticationComponents; + } + else + { + ArrayList services = new ArrayList(authenticationComponents == null ? 1 : (authenticationComponents.size() + 1)); + services.add(mutableAuthenticationComponent); + if (authenticationComponents != null) + { + services.addAll(authenticationComponents); + } + return services; + } + } + +} diff --git a/source/java/org/alfresco/repo/security/authority/SimpleAuthorityServiceTest.java b/source/java/org/alfresco/repo/security/authority/SimpleAuthorityServiceTest.java index a5663cd9cf..a7dcb1e0f7 100644 --- a/source/java/org/alfresco/repo/security/authority/SimpleAuthorityServiceTest.java +++ b/source/java/org/alfresco/repo/security/authority/SimpleAuthorityServiceTest.java @@ -72,7 +72,7 @@ public class SimpleAuthorityServiceTest extends TestCase authorityService = (AuthorityService) ctx.getBean("authorityService"); pubAuthorityService = (AuthorityService) ctx.getBean("AuthorityService"); personService = (PersonService) ctx.getBean("personService"); - authenticationDAO = (MutableAuthenticationDao) ctx.getBean("alfDaoImpl"); + authenticationDAO = (MutableAuthenticationDao) ctx.getBean("authenticationDao"); this.authenticationComponent.setSystemUserAsCurrentUser(); diff --git a/source/java/org/alfresco/repo/security/permissions/dynamic/LockOwnerDynamicAuthorityTest.java b/source/java/org/alfresco/repo/security/permissions/dynamic/LockOwnerDynamicAuthorityTest.java index 06fbc55505..d6f48fe8b7 100644 --- a/source/java/org/alfresco/repo/security/permissions/dynamic/LockOwnerDynamicAuthorityTest.java +++ b/source/java/org/alfresco/repo/security/permissions/dynamic/LockOwnerDynamicAuthorityTest.java @@ -90,7 +90,7 @@ public class LockOwnerDynamicAuthorityTest extends TestCase authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent"); lockService = (LockService) ctx.getBean("lockService"); permissionService = (PermissionService) ctx.getBean("permissionService"); - authenticationDAO = (MutableAuthenticationDao) ctx.getBean("alfDaoImpl"); + authenticationDAO = (MutableAuthenticationDao) ctx.getBean("authenticationDao"); checkOutCheckInService = (CheckOutCheckInService) ctx.getBean("checkOutCheckInService"); ownableService = (OwnableService) ctx.getBean("ownableService"); diff --git a/source/java/org/alfresco/repo/security/permissions/impl/AbstractPermissionTest.java b/source/java/org/alfresco/repo/security/permissions/impl/AbstractPermissionTest.java index c4a9065ae4..07bf39195a 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/AbstractPermissionTest.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/AbstractPermissionTest.java @@ -102,7 +102,7 @@ public class AbstractPermissionTest extends BaseSpringTest authorityService = (AuthorityService) applicationContext.getBean("authorityService"); authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName()); - authenticationDAO = (MutableAuthenticationDao) applicationContext.getBean("alfDaoImpl"); + authenticationDAO = (MutableAuthenticationDao) applicationContext.getBean("authenticationDao"); StoreRef storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.nanoTime()); diff --git a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java index 5bd47bead8..2034d2c51f 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java @@ -70,8 +70,8 @@ import org.springframework.beans.factory.InitializingBean; public class PermissionServiceImpl implements PermissionServiceSPI, InitializingBean { - static SimplePermissionReference OLD_ALL_PERMISSIONS_REFERENCE = new SimplePermissionReference(QName.createQName( - "", PermissionService.ALL_PERMISSIONS), PermissionService.ALL_PERMISSIONS); + static SimplePermissionReference OLD_ALL_PERMISSIONS_REFERENCE = new SimplePermissionReference(QName.createQName("", PermissionService.ALL_PERMISSIONS), + PermissionService.ALL_PERMISSIONS); private static Log log = LogFactory.getLog(PermissionServiceImpl.class); @@ -228,8 +228,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing throw new IllegalArgumentException("Property 'policyComponent' has not been set"); } - policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onMoveNode"), - ContentModel.TYPE_BASE, new JavaBehaviour(this, "onMoveNode")); + policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onMoveNode"), ContentModel.TYPE_BASE, new JavaBehaviour(this, "onMoveNode")); } @@ -263,8 +262,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing NodePermissionEntry nodePremissionEntry = getSetPermissions(nodeRef); for (PermissionEntry pe : nodePremissionEntry.getPermissionEntries()) { - accessPermissions.add(new AccessPermissionImpl(getPermission(pe.getPermissionReference()), pe - .getAccessStatus(), pe.getAuthority())); + accessPermissions.add(new AccessPermissionImpl(getPermission(pe.getPermissionReference()), pe.getAccessStatus(), pe.getAuthority())); } return accessPermissions; } @@ -390,8 +388,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing if (log.isDebugEnabled()) { log.debug("Permission <" - + perm + "> is " + (result ? "allowed" : "denied") + " for " - + authenticationComponent.getCurrentUserName() + " on node " + nodeService.getPath(nodeRef)); + + perm + "> is " + (result ? "allowed" : "denied") + " for " + authenticationComponent.getCurrentUserName() + " on node " + nodeService.getPath(nodeRef)); } status = result ? AccessStatus.ALLOWED : AccessStatus.DENIED; @@ -649,21 +646,16 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing // Set the required node permissions if (required.equals(getPermissionReference(ALL_PERMISSIONS))) { - nodeRequirements = modelDAO.getRequiredPermissions( - getPermissionReference(PermissionService.FULL_CONTROL), typeQName, aspectQNames, - RequiredPermission.On.NODE); + nodeRequirements = modelDAO.getRequiredPermissions(getPermissionReference(PermissionService.FULL_CONTROL), typeQName, aspectQNames, RequiredPermission.On.NODE); } else { - nodeRequirements = modelDAO.getRequiredPermissions(required, typeQName, aspectQNames, - RequiredPermission.On.NODE); + nodeRequirements = modelDAO.getRequiredPermissions(required, typeQName, aspectQNames, RequiredPermission.On.NODE); } - parentRequirements = modelDAO.getRequiredPermissions(required, typeQName, aspectQNames, - RequiredPermission.On.PARENT); + parentRequirements = modelDAO.getRequiredPermissions(required, typeQName, aspectQNames, RequiredPermission.On.PARENT); - childrenRequirements = modelDAO.getRequiredPermissions(required, typeQName, aspectQNames, - RequiredPermission.On.CHILDREN); + childrenRequirements = modelDAO.getRequiredPermissions(required, typeQName, aspectQNames, RequiredPermission.On.CHILDREN); // Find all the permissions that grant the allowed permission // All permissions are treated specially. @@ -695,8 +687,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing * @param recursiveIn * @return */ - boolean evaluate(Set authorisations, NodeRef nodeRef, Set> denied, - MutableBoolean recursiveIn) + boolean evaluate(Set authorisations, NodeRef nodeRef, Set> denied, MutableBoolean recursiveIn) { // Do we defer our required test to a parent (yes if not null) MutableBoolean recursiveOut = null; @@ -771,8 +762,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing if (pr.equals(required)) { // Recursive permission - success &= this.evaluate(authorisations, car.getParentRef(), locallyDenied, - recursiveOut); + success &= this.evaluate(authorisations, car.getParentRef(), locallyDenied, recursiveOut); if ((recursiveOut != null) && recursiveOut.getValue()) { if (recursiveIn != null) @@ -848,8 +838,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing } - public boolean hasSinglePermission(Set authorisations, NodeRef nodeRef, - Set> denied) + public boolean hasSinglePermission(Set authorisations, NodeRef nodeRef, Set> denied) { nodeRef = tenantService.getName(nodeRef); @@ -974,8 +963,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing // All the sets that grant this permission must be // denied // Note that granters includes the orginal permission - Set granters = modelDAO - .getGrantingPermissions(pe.getPermissionReference()); + Set granters = modelDAO.getGrantingPermissions(pe.getPermissionReference()); for (PermissionReference granter : granters) { deniedSet.add(new Pair(pe.getAuthority(), granter)); @@ -991,8 +979,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing // All permission excludes all permissions available for // the node. - if (pe.getPermissionReference().equals(getAllPermissionReference()) - || pe.getPermissionReference().equals(OLD_ALL_PERMISSIONS_REFERENCE)) + if (pe.getPermissionReference().equals(getAllPermissionReference()) || pe.getPermissionReference().equals(OLD_ALL_PERMISSIONS_REFERENCE)) { for (PermissionReference deny : modelDAO.getAllPermissions(nodeRef)) { @@ -1048,8 +1035,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing * the set of denied permissions/authority pais * @return */ - private boolean isGranted(PermissionEntry pe, Set authorisations, - Set> denied) + private boolean isGranted(PermissionEntry pe, Set authorisations, Set> denied) { // If the permission entry denies then we just deny if (pe.isDenied()) @@ -1059,16 +1045,41 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing // The permission is allowed but we deny it as it is in the denied // set + if (denied != null) { - Pair specific = new Pair(pe.getAuthority(), - required); + Pair specific = new Pair(pe.getAuthority(), required); if (denied.contains(specific)) { return false; } } + // any deny denies + + if (false) + { + if (denied != null) + { + for (String auth : authorisations) + { + Pair specific = new Pair(auth, required); + if (denied.contains(specific)) + { + return false; + } + for (PermissionReference perm : granters) + { + specific = new Pair(auth, perm); + if (denied.contains(specific)) + { + return false; + } + } + } + } + } + // If the permission has a match in both the authorities and // granters list it is allowed // It applies to the current user and it is granted @@ -1124,8 +1135,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing return false; } Pair other = (Pair) o; - return EqualsHelper.nullSafeEquals(this.getA(), other.getA()) - && EqualsHelper.nullSafeEquals(this.getB(), other.getB()); + return EqualsHelper.nullSafeEquals(this.getA(), other.getA()) && EqualsHelper.nullSafeEquals(this.getB(), other.getB()); } @Override @@ -1167,15 +1177,13 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing return permissionsDaoComponent.getAllSetPermissions(authority); } - public Set findNodesByAssignedPermissionForCurrentUser(String permission, boolean allow, boolean includeContainingAuthorities, - boolean exactPermissionMatch) + public Set findNodesByAssignedPermissionForCurrentUser(String permission, boolean allow, boolean includeContainingAuthorities, boolean exactPermissionMatch) { String currentUser = authenticationComponent.getCurrentUserName(); return findNodesByAssignedPermission(currentUser, permission, allow, includeContainingAuthorities, exactPermissionMatch); } - public Set findNodesByAssignedPermission(String authority, String permission, boolean allow, - boolean includeContainingAuthorities, boolean includeContainingPermissions) + public Set findNodesByAssignedPermission(String authority, String permission, boolean allow, boolean includeContainingAuthorities, boolean includeContainingPermissions) { // TODO: owned nodes and add owner rights ?? // Does not include dynamic permissions (they would have to be done by query - e.g. owership and OWNER rights) diff --git a/source/java/org/alfresco/repo/version/BaseVersionStoreTest.java b/source/java/org/alfresco/repo/version/BaseVersionStoreTest.java index a6cfb5e9ca..7d92be6f87 100644 --- a/source/java/org/alfresco/repo/version/BaseVersionStoreTest.java +++ b/source/java/org/alfresco/repo/version/BaseVersionStoreTest.java @@ -149,7 +149,7 @@ public abstract class BaseVersionStoreTest extends BaseSpringTest this.authenticationService = (AuthenticationService)applicationContext.getBean("authenticationService"); this.transactionService = (TransactionService)this.applicationContext.getBean("transactionComponent"); this.txnHelper = (RetryingTransactionHelper) applicationContext.getBean("retryingTransactionHelper"); - this.authenticationDAO = (MutableAuthenticationDao) applicationContext.getBean("alfDaoImpl"); + this.authenticationDAO = (MutableAuthenticationDao) applicationContext.getBean("authenticationDao"); this.nodeArchiveService = (NodeArchiveService) applicationContext.getBean("nodeArchiveService"); this.nodeService = (NodeService)applicationContext.getBean("nodeService"); diff --git a/source/test-resources/xml-metadata/eclipse-project-mappings.properties b/source/test-resources/xml-metadata/eclipse-project-mappings.properties index c68df82456..23ca69a138 100644 --- a/source/test-resources/xml-metadata/eclipse-project-mappings.properties +++ b/source/test-resources/xml-metadata/eclipse-project-mappings.properties @@ -5,7 +5,11 @@ # Namespaces namespace.prefix.cm=http://www.alfresco.org/model/content/1.0 +namespace.prefix.test=http://www.alfresco.org/model/test/1.0 # Mappings name=cm:title description=cm:description +multi-value-text=test:multi-value-text +multi-value-node=test:multi-value-node +complex-node=test:complex-node diff --git a/source/test-resources/xml-metadata/eclipse-project-xpath-mappings.properties b/source/test-resources/xml-metadata/eclipse-project-xpath-mappings.properties index 3299d1ffea..15f384d335 100644 --- a/source/test-resources/xml-metadata/eclipse-project-xpath-mappings.properties +++ b/source/test-resources/xml-metadata/eclipse-project-xpath-mappings.properties @@ -8,3 +8,6 @@ # Mappings name=/projectDescription/name/text() description=/projectDescription/comment/text() +multi-value-text=/projectDescription/natures/nature/text() +multi-value-node=/projectDescription/natures/nature +complex-node=/projectDescription/natures \ No newline at end of file