diff --git a/config/alfresco/subsystems/fileServers/default/network-protocol-context.xml b/config/alfresco/subsystems/fileServers/default/network-protocol-context.xml index 5b7eaedf0e..c5f2fedcb8 100644 --- a/config/alfresco/subsystems/fileServers/default/network-protocol-context.xml +++ b/config/alfresco/subsystems/fileServers/default/network-protocol-context.xml @@ -203,12 +203,13 @@ HIGH + - ^Backup.*.doc[x] + ^Backup.*.do[ct]{1}[x]?[m]? 20000 MEDIUM true - + diff --git a/source/java/org/alfresco/cmis/mapping/AbstractVersioningProperty.java b/source/java/org/alfresco/cmis/mapping/AbstractVersioningProperty.java index 94aae8bfa9..e5d9b9a1b5 100644 --- a/source/java/org/alfresco/cmis/mapping/AbstractVersioningProperty.java +++ b/source/java/org/alfresco/cmis/mapping/AbstractVersioningProperty.java @@ -71,6 +71,8 @@ public abstract class AbstractVersioningProperty extends AbstractProperty public boolean hasWorkingCopy(NodeRef nodeRef) { - return getServiceRegistry().getLockService().getLockType(nodeRef) == LockType.READ_ONLY_LOCK; + final ServiceRegistry serviceRegistry = getServiceRegistry(); + return serviceRegistry.getLockService().getLockType(nodeRef) == LockType.READ_ONLY_LOCK + && serviceRegistry.getCheckOutCheckInService().getWorkingCopy(nodeRef) != null; } } diff --git a/source/java/org/alfresco/repo/copy/CopyServiceImpl.java b/source/java/org/alfresco/repo/copy/CopyServiceImpl.java index 5fda1c780a..14de29ac3e 100644 --- a/source/java/org/alfresco/repo/copy/CopyServiceImpl.java +++ b/source/java/org/alfresco/repo/copy/CopyServiceImpl.java @@ -677,12 +677,11 @@ public class CopyServiceImpl implements CopyService scratchProperties.clear(); for (QName propertyQName : propertyDefs.keySet()) { - Serializable value = sourceNodeProperties.get(propertyQName); - if (value == null) + if (sourceNodeProperties.containsKey(propertyQName)) { - continue; + Serializable value = sourceNodeProperties.get(propertyQName); + scratchProperties.put(propertyQName, value); } - scratchProperties.put(propertyQName, value); } // What does the behaviour do with properties? Map propsToCopy = callback.getCopyProperties(classQName, copyDetails, scratchProperties); diff --git a/source/java/org/alfresco/repo/copy/CopyServiceImplTest.java b/source/java/org/alfresco/repo/copy/CopyServiceImplTest.java index 8c72eb30c6..5abf08b5aa 100644 --- a/source/java/org/alfresco/repo/copy/CopyServiceImplTest.java +++ b/source/java/org/alfresco/repo/copy/CopyServiceImplTest.java @@ -159,6 +159,10 @@ public class CopyServiceImplTest extends TestCase private static final String USER_1 = "User1"; private static final String USER_2 = "User2"; + private static final QName TYPE_CUSTOM_CMIS_DOCUMENT = QName.createQName("{http://www.alfresco.org/model/cmis/custom}document"); + private static final QName PROP_CUSTOM_STRING = QName.createQName("{http://www.alfresco.org/model/cmis/custom}docprop_string"); + + /** * Test content */ @@ -1337,4 +1341,27 @@ public class CopyServiceImplTest extends TestCase } } } + + public void testCopyNullPropertyForAlf10712() throws Exception + { + nodeService.setType(sourceNodeRef, TYPE_CUSTOM_CMIS_DOCUMENT); + nodeService.setType(targetNodeRef, TYPE_CUSTOM_CMIS_DOCUMENT); + + Map customProperties = new HashMap(); + + customProperties.put(PROP_CUSTOM_STRING, null); + nodeService.setProperties(sourceNodeRef, customProperties); + + Serializable customPropValue = nodeService.getProperty(sourceNodeRef, PROP_CUSTOM_STRING); + assertNull((PROP_CUSTOM_STRING.toString() + " property must be set to NULL on the source node!"), customPropValue); + + customProperties.put(PROP_CUSTOM_STRING, TEST_VALUE_1); + nodeService.setProperties(targetNodeRef, customProperties); + Serializable customProp = nodeService.getProperty(targetNodeRef, PROP_CUSTOM_STRING); + assertEquals((PROP_CUSTOM_STRING.toString() + " must be set to '" + TEST_VALUE_1 + "' on the target node!"), TEST_VALUE_1, customProp ); + + copyService.copy(sourceNodeRef, targetNodeRef); + Serializable updatedCustomProp = nodeService.getProperty(targetNodeRef, PROP_CUSTOM_STRING); + assertNull((PROP_CUSTOM_STRING.toString() + " property must be set to NULL on the target node after copying!"), updatedCustomProp ); + } } diff --git a/source/java/org/alfresco/repo/remotecredentials/RemoteCredentialsServiceImpl.java b/source/java/org/alfresco/repo/remotecredentials/RemoteCredentialsServiceImpl.java index 94ed8126ba..0a3e1b8d5a 100644 --- a/source/java/org/alfresco/repo/remotecredentials/RemoteCredentialsServiceImpl.java +++ b/source/java/org/alfresco/repo/remotecredentials/RemoteCredentialsServiceImpl.java @@ -144,12 +144,20 @@ public class RemoteCredentialsServiceImpl implements RemoteCredentialsService credentialsFactories.put(credentialsType, factory); } + /** + * Provides a read only copy of the credentials factories, useful in unit tests + */ + protected Map getCredentialsFactories() + { + return Collections.unmodifiableMap(credentialsFactories); + } + // -------------------------------------------------------- private static QName SYSTEM_FOLDER_QNAME = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "system"); private static QName SHARED_CREDENTIALS_CONTAINER_QNAME = - QName.createQName(RemoteCredentialsModel.REMOTE_CREDENTIALS_MODEL_URL, SHARED_CREDENTIALS_CONTAINER_NAME); + QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, SHARED_CREDENTIALS_CONTAINER_NAME); /** * Gets the NodeRef of the holder of shared credentials remote systems. * diff --git a/source/java/org/alfresco/repo/remotecredentials/RemoteCredentialsServicesTest.java b/source/java/org/alfresco/repo/remotecredentials/RemoteCredentialsServicesTest.java index 28a31792b1..0f04f65606 100644 --- a/source/java/org/alfresco/repo/remotecredentials/RemoteCredentialsServicesTest.java +++ b/source/java/org/alfresco/repo/remotecredentials/RemoteCredentialsServicesTest.java @@ -23,11 +23,13 @@ import static org.junit.Assert.assertNotNull; import java.util.ArrayList; import java.util.List; +import java.util.Map.Entry; import java.util.Set; import org.alfresco.model.ContentModel; import org.alfresco.query.PagingRequest; import org.alfresco.query.PagingResults; +import org.alfresco.repo.model.Repository; import org.alfresco.repo.policy.BehaviourFilter; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper; @@ -38,7 +40,6 @@ import org.alfresco.service.cmr.remotecredentials.RemoteCredentialsService; 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.security.AuthorityService; import org.alfresco.service.cmr.security.MutableAuthenticationService; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PersonService; @@ -60,7 +61,8 @@ import org.springframework.context.ApplicationContext; /** * Test cases for {@link RemoteCredentialsServiceImpl} and friends. * - * Note - this test will zap any existing shared credentials! + * Note - this test will largely use a test shared credentials + * container, but one test puts things into the real credentials folder * * @author Nick Burch * @since Odin @@ -95,6 +97,8 @@ public class RemoteCredentialsServicesTest private static DictionaryService DICTIONARY_SERVICE; private static NodeService NODE_SERVICE; private static NodeService PUBLIC_NODE_SERVICE; + private static NamespaceService NAMESPACE_SERVICE; + private static Repository REPOSITORY_HELPER; private static PersonService PERSON_SERVICE; private static RetryingTransactionHelper TRANSACTION_HELPER; private static TransactionService TRANSACTION_SERVICE; @@ -115,6 +119,8 @@ public class RemoteCredentialsServicesTest AUTHENTICATION_SERVICE = (MutableAuthenticationService)testContext.getBean("authenticationService"); BEHAVIOUR_FILTER = (BehaviourFilter)testContext.getBean("policyBehaviourFilter"); DICTIONARY_SERVICE = (DictionaryService)testContext.getBean("dictionaryService"); + NAMESPACE_SERVICE = (NamespaceService)testContext.getBean("namespaceService"); + REPOSITORY_HELPER = (Repository)testContext.getBean("repositoryHelper"); NODE_SERVICE = (NodeService)testContext.getBean("nodeService"); PUBLIC_NODE_SERVICE = (NodeService)testContext.getBean("NodeService"); PERSON_SERVICE = (PersonService)testContext.getBean("personService"); @@ -802,6 +808,70 @@ public class RemoteCredentialsServicesTest assertEquals(1, creds.getPage().size()); } + /** + * Most of the shared credentials container tests work on the test one, + * so that things are in a known and empty state. + * We have this one test that uses the real shared container, just to check + * that it's correctly setup and available + */ + @Test public void testRealSharedCredentialsContainer() throws Exception + { + // Create a new instance, using the real container + RemoteCredentialsServiceImpl realService = new RemoteCredentialsServiceImpl(); + realService.setDictionaryService(DICTIONARY_SERVICE); + realService.setNamespaceService(NAMESPACE_SERVICE); + realService.setNodeService(PUBLIC_NODE_SERVICE); + realService.setRepositoryHelper(REPOSITORY_HELPER); + + for (Entry e : ((RemoteCredentialsServiceImpl)PRIVATE_REMOTE_CREDENTIALS_SERVICE).getCredentialsFactories().entrySet() ) + { + realService.registerCredentialsFactory(e.getKey(), e.getValue()); + } + + + // Run as a test user + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_ONE); + + // Do a create / fetch / delete step + PasswordCredentialsInfoImpl pwCredI = new PasswordCredentialsInfoImpl(); + pwCredI.setRemoteUsername(TEST_REMOTE_USERNAME_ONE); + pwCredI.setRemotePassword(TEST_USER_THREE); + BaseCredentialsInfo credentials = null; + + try + { + // Create + credentials = realService.createSharedCredentials(TEST_REMOTE_SYSTEM_ONE, pwCredI); + assertEquals(TEST_REMOTE_USERNAME_ONE, credentials.getRemoteUsername()); + + // Update + ((PasswordCredentialsInfoImpl)credentials).setRemoteUsername(TEST_REMOTE_USERNAME_TWO); + ((PasswordCredentialsInfoImpl)credentials).setRemotePassword(TEST_USER_ONE); + credentials = realService.updateCredentials(credentials); + assertEquals(TEST_REMOTE_USERNAME_TWO, credentials.getRemoteUsername()); + + // Delete + realService.deleteCredentials(credentials); + + // Tidy, and zap the test parent + PUBLIC_NODE_SERVICE.deleteNode(credentials.getRemoteSystemContainerNodeRef()); + credentials = null; + } + finally + { + // Tidy up if needed + if (credentials != null) + { + AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser(); + + // Zap the credentials themselves + PUBLIC_NODE_SERVICE.deleteNode(credentials.getNodeRef()); + + // And their test parent + PUBLIC_NODE_SERVICE.deleteNode(credentials.getRemoteSystemContainerNodeRef()); + } + } + } // -------------------------------------------------------------------------------- diff --git a/source/java/org/alfresco/repo/security/authentication/AbstractChainingAuthenticationService.java b/source/java/org/alfresco/repo/security/authentication/AbstractChainingAuthenticationService.java index 2d4a89de68..23a59792de 100644 --- a/source/java/org/alfresco/repo/security/authentication/AbstractChainingAuthenticationService.java +++ b/source/java/org/alfresco/repo/security/authentication/AbstractChainingAuthenticationService.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2010 Alfresco Software Limited. + * Copyright (C) 2005-2012 Alfresco Software Limited. * * This file is part of Alfresco * @@ -25,6 +25,8 @@ import java.util.TreeSet; import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.cmr.security.MutableAuthenticationService; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; /** * A base class for chaining authentication services. Where appropriate, methods will 'chain' across multiple @@ -34,6 +36,8 @@ import org.alfresco.service.cmr.security.MutableAuthenticationService; */ public abstract class AbstractChainingAuthenticationService extends AbstractAuthenticationService implements MutableAuthenticationService { + private static final Log logger = LogFactory.getLog(AbstractChainingAuthenticationService.class); + /** * Instantiates a new abstract chaining authentication service. */ @@ -173,15 +177,26 @@ public abstract class AbstractChainingAuthenticationService extends AbstractAuth public void authenticate(String userName, char[] password) throws AuthenticationException { preAuthenticationCheck(userName); - for (AuthenticationService authService : getUsableAuthenticationServices()) + List usableAuthenticationServices = getUsableAuthenticationServices(); + int counter = usableAuthenticationServices.size(); + for (AuthenticationService authService : usableAuthenticationServices) { try { + counter--; authService.authenticate(userName, password); + if (logger.isDebugEnabled()) + { + logger.debug("authenticate "+userName+" with "+getId(authService)+" SUCCEEDED"); + } return; } catch (AuthenticationException e) { + if (logger.isDebugEnabled()) + { + logger.debug("authenticate "+userName+" with "+getId(authService)+(counter == 0 ? " FAILED (end of chain)" : " failed (try next in chain)")); + } // Ignore and chain } } @@ -189,6 +204,17 @@ public abstract class AbstractChainingAuthenticationService extends AbstractAuth } + /** + * Should be overridden to returns the ID of the authService for use in debug. + * @param authService in question. + * @return the ID of the authService. This implementation has no way to work + * this out so returns the simple class name. + */ + protected String getId(AuthenticationService authService) + { + return authService.getClass().getSimpleName(); + } + /** * {@inheritDoc} */ diff --git a/source/java/org/alfresco/repo/security/authentication/subsystems/SubsystemChainingAuthenticationService.java b/source/java/org/alfresco/repo/security/authentication/subsystems/SubsystemChainingAuthenticationService.java index 31b3c76d20..09c120044c 100644 --- a/source/java/org/alfresco/repo/security/authentication/subsystems/SubsystemChainingAuthenticationService.java +++ b/source/java/org/alfresco/repo/security/authentication/subsystems/SubsystemChainingAuthenticationService.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2010 Alfresco Software Limited. + * Copyright (C) 2005-2012 Alfresco Software Limited. * * This file is part of Alfresco * @@ -193,4 +193,24 @@ public class SubsystemChainingAuthenticationService extends AbstractChainingAuth } } + @Override + protected String getId(AuthenticationService authService) + { + this.lock.readLock().lock(); + try + { + for (String instance : this.instanceIds) + { + if (authService.equals(this.sourceBeans.get(instance))) + { + return instance; + } + } + } + finally + { + this.lock.readLock().unlock(); + } + return super.getId(authService); + } }