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);
+ }
}