Merge branch 'develop' into fix/MNT-17971_activiti_signalAndBoundaryEvent

This commit is contained in:
Andrei Forascu
2017-09-25 11:11:16 +03:00
7 changed files with 639 additions and 522 deletions

4
.gitbugtraq Normal file
View File

@@ -0,0 +1,4 @@
# For SmartGit
[bugtraq "jira"]
url = https://issues.alfresco.com/jira/browse/%BUGID%
logRegex = ([A-Z]+-\\d+)

View File

@@ -43,6 +43,7 @@
<dependency.alfresco-data-model.version>6.18</dependency.alfresco-data-model.version> <dependency.alfresco-data-model.version>6.18</dependency.alfresco-data-model.version>
<dependency.alfresco-jlan.version>6.3</dependency.alfresco-jlan.version> <dependency.alfresco-jlan.version>6.3</dependency.alfresco-jlan.version>
<dependency.alfresco-pdf-renderer.version>1.0</dependency.alfresco-pdf-renderer.version> <dependency.alfresco-pdf-renderer.version>1.0</dependency.alfresco-pdf-renderer.version>
<dependency.alfresco-hb-data-sender.version>1.0.1</dependency.alfresco-hb-data-sender.version>
<dependency.spring.version>3.2.17.RELEASE</dependency.spring.version> <dependency.spring.version>3.2.17.RELEASE</dependency.spring.version>
@@ -99,7 +100,7 @@
<dependency> <dependency>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-heartbeat-data-sender</artifactId> <artifactId>alfresco-heartbeat-data-sender</artifactId>
<version>1.0.0</version> <version>${dependency.alfresco-hb-data-sender.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.sun.mail</groupId> <groupId>com.sun.mail</groupId>

View File

@@ -1,28 +1,28 @@
/* /*
* #%L * #%L
* Alfresco Repository * Alfresco Repository
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2016 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is * the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms: * provided under the following open source license terms:
* *
* Alfresco is free software: you can redistribute it and/or modify * Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* Alfresco is distributed in the hope that it will be useful, * Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. * GNU Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L% * #L%
*/ */
package org.alfresco.opencmis; package org.alfresco.opencmis;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
@@ -50,17 +50,17 @@ import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.TreeSet; import java.util.TreeSet;
import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.DatatypeFactory;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.events.types.ContentEvent; import org.alfresco.events.types.ContentEvent;
import org.alfresco.events.types.ContentEventImpl; import org.alfresco.events.types.ContentEventImpl;
import org.alfresco.events.types.ContentReadRangeEvent; import org.alfresco.events.types.ContentReadRangeEvent;
import org.alfresco.events.types.Event; import org.alfresco.events.types.Event;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.activities.ActivityInfo; import org.alfresco.service.cmr.activities.ActivityInfo;
import org.alfresco.opencmis.dictionary.CMISActionEvaluator; import org.alfresco.opencmis.dictionary.CMISActionEvaluator;
import org.alfresco.opencmis.dictionary.CMISAllowedActionEnum; import org.alfresco.opencmis.dictionary.CMISAllowedActionEnum;
import org.alfresco.opencmis.dictionary.CMISDictionaryService; import org.alfresco.opencmis.dictionary.CMISDictionaryService;
@@ -81,8 +81,8 @@ import org.alfresco.opencmis.search.CMISResultSetRow;
import org.alfresco.repo.Client; import org.alfresco.repo.Client;
import org.alfresco.repo.Client.ClientType; import org.alfresco.repo.Client.ClientType;
import org.alfresco.repo.action.executer.ContentMetadataExtracter; import org.alfresco.repo.action.executer.ContentMetadataExtracter;
import org.alfresco.repo.cache.SimpleCache; import org.alfresco.repo.cache.SimpleCache;
import org.alfresco.repo.coci.CheckOutCheckInServiceImpl; import org.alfresco.repo.coci.CheckOutCheckInServiceImpl;
import org.alfresco.repo.events.EventPreparator; import org.alfresco.repo.events.EventPreparator;
import org.alfresco.repo.events.EventPublisher; import org.alfresco.repo.events.EventPublisher;
import org.alfresco.repo.model.filefolder.GetChildrenCannedQuery; import org.alfresco.repo.model.filefolder.GetChildrenCannedQuery;
@@ -462,22 +462,22 @@ public class CMISConnector implements ApplicationContextAware, ApplicationListen
this.objectsDefaultDepth = objectsDefaultDepth; this.objectsDefaultDepth = objectsDefaultDepth;
} }
/** /**
* Set the default number of content changes to return if nothing is specified * Set the default number of content changes to return if nothing is specified
*/ */
public void setContentChangesDefaultMaxItems(int contentChangesDefaultMaxItems) public void setContentChangesDefaultMaxItems(int contentChangesDefaultMaxItems)
{ {
if (contentChangesDefaultMaxItems < 1) if (contentChangesDefaultMaxItems < 1)
{ {
throw new IllegalArgumentException("The default maximum number of content changes to retrieve must be greater than zero."); throw new IllegalArgumentException("The default maximum number of content changes to retrieve must be greater than zero.");
} }
else if (contentChangesDefaultMaxItems == Integer.MAX_VALUE) else if (contentChangesDefaultMaxItems == Integer.MAX_VALUE)
{ {
throw new IllegalArgumentException("The server cannot return " + Integer.MAX_VALUE + " content changes in a request!"); throw new IllegalArgumentException("The server cannot return " + Integer.MAX_VALUE + " content changes in a request!");
} }
this.contentChangesDefaultMaxItems = contentChangesDefaultMaxItems; this.contentChangesDefaultMaxItems = contentChangesDefaultMaxItems;
} }
/** /**
* Set rendition kind mapping. * Set rendition kind mapping.
*/ */
@@ -504,14 +504,14 @@ public class CMISConnector implements ApplicationContextAware, ApplicationListen
public void setServiceRegistry(ServiceRegistry serviceRegistry) public void setServiceRegistry(ServiceRegistry serviceRegistry)
{ {
this.serviceRegistry = serviceRegistry; this.serviceRegistry = serviceRegistry;
} }
/** /**
* Return the service registry * Return the service registry
*/ */
public final ServiceRegistry getServiceRegistry() public final ServiceRegistry getServiceRegistry()
{ {
return this.serviceRegistry; return this.serviceRegistry;
} }
/** /**
@@ -3098,12 +3098,13 @@ public class CMISConnector implements ApplicationContextAware, ApplicationListen
} }
} }
Boolean isOnWorkingCopy = checkOutCheckInService.isWorkingCopy(nodeRef);
Updatability updatability = propDef.getPropertyDefinition().getUpdatability(); Updatability updatability = propDef.getPropertyDefinition().getUpdatability();
if ((updatability == Updatability.READONLY) if (!isUpdatable(updatability, isOnWorkingCopy))
|| (updatability == Updatability.WHENCHECKEDOUT && !checkOutCheckInService.isWorkingCopy(nodeRef)))
{ {
throw new CmisInvalidArgumentException("Property " + property.getId() + " is read-only!"); throw new CmisInvalidArgumentException("Property " + propertyId + " is read-only!");
} }
TypeDefinitionWrapper propType = propDef.getOwningType(); TypeDefinitionWrapper propType = propDef.getOwningType();
Serializable value = getValue(property, propDef.getPropertyDefinition().getCardinality() == Cardinality.MULTI); Serializable value = getValue(property, propDef.getPropertyDefinition().getCardinality() == Cardinality.MULTI);
Pair<TypeDefinitionWrapper, Serializable> pair = new Pair<TypeDefinitionWrapper, Serializable>(propType, value); Pair<TypeDefinitionWrapper, Serializable> pair = new Pair<TypeDefinitionWrapper, Serializable>(propType, value);
@@ -3129,7 +3130,7 @@ public class CMISConnector implements ApplicationContextAware, ApplicationListen
for (String propertyId : propsMap.keySet()) for (String propertyId : propsMap.keySet())
{ {
if(propertyId.equals(PropertyIds.SECONDARY_OBJECT_TYPE_IDS)) if (propertyId.equals(PropertyIds.SECONDARY_OBJECT_TYPE_IDS))
{ {
// already handled above // already handled above
continue; continue;
@@ -3185,8 +3186,8 @@ public class CMISConnector implements ApplicationContextAware, ApplicationListen
Set<QName> ignore = new HashSet<QName>(); Set<QName> ignore = new HashSet<QName>();
ignore.add(ContentModel.ASPECT_REFERENCEABLE); ignore.add(ContentModel.ASPECT_REFERENCEABLE);
ignore.add(ContentModel.ASPECT_LOCALIZED); ignore.add(ContentModel.ASPECT_LOCALIZED);
ignore.add(ContentModel.ASPECT_WORKING_COPY); ignore.add(ContentModel.ASPECT_WORKING_COPY);
// aspects to add == the list of secondary types - existing aspects - ignored aspects // aspects to add == the list of secondary types - existing aspects - ignored aspects
Set<QName> toAdd = new HashSet<QName>(secondaryTypeAspects); Set<QName> toAdd = new HashSet<QName>(secondaryTypeAspects);
@@ -3213,39 +3214,12 @@ public class CMISConnector implements ApplicationContextAware, ApplicationListen
for(QName aspectQName : aspectsToRemove) for(QName aspectQName : aspectsToRemove)
{ {
nodeService.removeAspect(nodeRef, aspectQName); nodeService.removeAspect(nodeRef, aspectQName);
// aspect is being removed so remove all of its properties from the propsToAdd map
TypeDefinitionWrapper w = getOpenCMISDictionaryService().findNodeType(aspectQName);
for(PropertyDefinitionWrapper wr : w.getProperties())
{
String propertyId = wr.getPropertyId();
propsToAdd.remove(propertyId);
}
} }
// add aspects and properties // add aspects and properties
for(QName aspectQName : toAdd) for(QName aspectQName : toAdd)
{ {
nodeService.addAspect(nodeRef, aspectQName, null); nodeService.addAspect(nodeRef, aspectQName, null);
// get aspect properties
AspectDefinition aspectDef = dictionaryService.getAspect(aspectQName);
Map<QName, org.alfresco.service.cmr.dictionary.PropertyDefinition> aspectPropDefs = aspectDef.getProperties();
TypeDefinitionWrapper w = getOpenCMISDictionaryService().findNodeType(aspectQName);
// for each aspect property...
for(QName propQName : aspectPropDefs.keySet())
{
// find CMIS property id
PropertyDefinitionWrapper property = w.getPropertyByQName(propQName);
String propertyId = property.getPropertyId();
if(!propsToAdd.containsKey(propertyId))
{
TypeDefinitionWrapper propType = property.getOwningType();
// CMIS 1.1 secondary types specification requires that all secondary type properties are set
// property not included in propsToAdd, add it with null value
Pair<TypeDefinitionWrapper, Serializable> pair = new Pair<TypeDefinitionWrapper, Serializable>(propType, null);
propsToAdd.put(propertyId, pair);
}
}
} }
} }
@@ -3580,9 +3554,9 @@ public class CMISConnector implements ApplicationContextAware, ApplicationListen
throw new CmisInvalidArgumentException("Property " + propertyId + " is unknown!"); throw new CmisInvalidArgumentException("Property " + propertyId + " is unknown!");
} }
Boolean isOnWorkingCopy = checkOutCheckInService.isWorkingCopy(nodeRef);
Updatability updatability = propDef.getPropertyDefinition().getUpdatability(); Updatability updatability = propDef.getPropertyDefinition().getUpdatability();
if ((updatability == Updatability.READONLY) if (!isUpdatable(updatability, isOnWorkingCopy))
|| (updatability == Updatability.WHENCHECKEDOUT && !checkOutCheckInService.isWorkingCopy(nodeRef)))
{ {
throw new CmisInvalidArgumentException("Property " + propertyId + " is read-only!"); throw new CmisInvalidArgumentException("Property " + propertyId + " is read-only!");
} }
@@ -3607,21 +3581,21 @@ public class CMISConnector implements ApplicationContextAware, ApplicationListen
} }
try try
{ {
String newName = value.toString(); String newName = value.toString();
// If the node is checked out and the name property is set on the working copy, make sure the new name has the working copy format // If the node is checked out and the name property is set on the working copy, make sure the new name has the working copy format
if (checkOutCheckInService.isWorkingCopy(nodeRef)) if (isOnWorkingCopy)
{ {
String wcLabel = (String)this.nodeService.getProperty(nodeRef, ContentModel.PROP_WORKING_COPY_LABEL); String wcLabel = (String)this.nodeService.getProperty(nodeRef, ContentModel.PROP_WORKING_COPY_LABEL);
if (wcLabel == null) if (wcLabel == null)
{ {
wcLabel = CheckOutCheckInServiceImpl.getWorkingCopyLabel(); wcLabel = CheckOutCheckInServiceImpl.getWorkingCopyLabel();
} }
if (!newName.contains(wcLabel)) if (!newName.contains(wcLabel))
{ {
newName = CheckOutCheckInServiceImpl.createWorkingCopyName(newName, wcLabel); newName = CheckOutCheckInServiceImpl.createWorkingCopyName(newName, wcLabel);
} }
} }
fileFolderService.rename(nodeRef, newName); fileFolderService.rename(nodeRef, newName);
} }
@@ -3709,30 +3683,30 @@ public class CMISConnector implements ApplicationContextAware, ApplicationListen
params.setApplicationName(CMIS_CHANGELOG_AUDIT_APPLICATION); params.setApplicationName(CMIS_CHANGELOG_AUDIT_APPLICATION);
params.setForward(true); params.setForward(true);
params.setFromId(from); params.setFromId(from);
// So we have a BigInteger. We need to ensure that we cut it down to an integer smaller than Integer.MAX_VALUE // So we have a BigInteger. We need to ensure that we cut it down to an integer smaller than Integer.MAX_VALUE
int maxResults = (maxItems == null ? contentChangesDefaultMaxItems : maxItems.intValue()); int maxResults = (maxItems == null ? contentChangesDefaultMaxItems : maxItems.intValue());
maxResults = maxResults < 1 ? contentChangesDefaultMaxItems : maxResults; // Just a double check of the unbundled contents maxResults = maxResults < 1 ? contentChangesDefaultMaxItems : maxResults; // Just a double check of the unbundled contents
maxResults = maxResults > contentChangesDefaultMaxItems ? contentChangesDefaultMaxItems : maxResults; // cut it down maxResults = maxResults > contentChangesDefaultMaxItems ? contentChangesDefaultMaxItems : maxResults; // cut it down
int queryFor = maxResults + 1; // Query for 1 more so that we know if there are more results int queryFor = maxResults + 1; // Query for 1 more so that we know if there are more results
auditService.auditQuery(changeLogCollectingCallback, params, queryFor); auditService.auditQuery(changeLogCollectingCallback, params, queryFor);
String newChangeLogToken = null; String newChangeLogToken = null;
// Check if we got more than the client requested // Check if we got more than the client requested
if (result.getObjects().size() >= maxResults) if (result.getObjects().size() >= maxResults)
{ {
// Build the change log token from the last item // Build the change log token from the last item
StringBuilder clt = new StringBuilder(); StringBuilder clt = new StringBuilder();
newChangeLogToken = (from == null ? clt.append(maxItems.intValue() + 1).toString() : clt.append(from.longValue() + maxItems.intValue()).toString()); // TODO: Make this readable newChangeLogToken = (from == null ? clt.append(maxItems.intValue() + 1).toString() : clt.append(from.longValue() + maxItems.intValue()).toString()); // TODO: Make this readable
// Remove extra item that was not actually requested // Remove extra item that was not actually requested
result.getObjects().remove(result.getObjects().size() - 1).getId(); result.getObjects().remove(result.getObjects().size() - 1).getId();
// Note to client that there are more items // Note to client that there are more items
result.setHasMoreItems(true); result.setHasMoreItems(true);
} }
else else
{ {
// We got the same or fewer than the number requested, so there are no more items // We got the same or fewer than the number requested, so there are no more items
result.setHasMoreItems(false); result.setHasMoreItems(false);
} }
@@ -4110,4 +4084,23 @@ public class CMISConnector implements ApplicationContextAware, ApplicationListen
} }
return renditionMapping; return renditionMapping;
} }
/**
* Verify if a property is updatable.
* @param updatability
* @param isOnWorkingCopy
* @return
*/
private boolean isUpdatable(Updatability updatability, Boolean isOnWorkingCopy)
{
if ((updatability == Updatability.READONLY)
|| (updatability == Updatability.WHENCHECKEDOUT && !isOnWorkingCopy))
{
return false;
}
else
{
return true;
}
}
} }

View File

@@ -33,6 +33,7 @@ import org.alfresco.repo.management.subsystems.ActivateableBean;
import org.alfresco.repo.security.authentication.AuthenticationComponent.UserNameValidationMode; import org.alfresco.repo.security.authentication.AuthenticationComponent.UserNameValidationMode;
import org.alfresco.repo.tenant.TenantContextHolder; import org.alfresco.repo.tenant.TenantContextHolder;
import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.util.GUID;
import org.alfresco.util.Pair; import org.alfresco.util.Pair;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@@ -42,7 +43,10 @@ public class AuthenticationServiceImpl extends AbstractAuthenticationService imp
private Log logger = LogFactory.getLog(AuthenticationServiceImpl.class); private Log logger = LogFactory.getLog(AuthenticationServiceImpl.class);
AuthenticationComponent authenticationComponent; AuthenticationComponent authenticationComponent;
TicketComponent ticketComponent; TicketComponent ticketComponent;
/** a serviceInstanceId identifying this unique instance */
private String serviceInstanceId;
private String domain; private String domain;
private boolean allowsUserCreation = true; private boolean allowsUserCreation = true;
private boolean allowsUserDeletion = true; private boolean allowsUserDeletion = true;
@@ -85,6 +89,8 @@ public class AuthenticationServiceImpl extends AbstractAuthenticationService imp
public AuthenticationServiceImpl() public AuthenticationServiceImpl()
{ {
super(); super();
this.serviceInstanceId = GUID.generate();
} }
public void setTicketComponent(TicketComponent ticketComponent) public void setTicketComponent(TicketComponent ticketComponent)
@@ -124,9 +130,10 @@ public class AuthenticationServiceImpl extends AbstractAuthenticationService imp
TenantContextHolder.setTenantDomain(tenant); TenantContextHolder.setTenantDomain(tenant);
if (protectionEnabled) if (protectionEnabled)
{ {
if (protectedUsersCache.get(userName) != null) final String protectedUserKey = getProtectedUserKey(userName);
if (protectedUsersCache.get(protectedUserKey) != null)
{ {
protectedUsersCache.remove(userName); protectedUsersCache.remove(protectedUserKey);
} }
} }
} }
@@ -148,7 +155,8 @@ public class AuthenticationServiceImpl extends AbstractAuthenticationService imp
boolean isProtected = false; boolean isProtected = false;
if (protectionEnabled) if (protectionEnabled)
{ {
ProtectedUser protectedUser = protectedUsersCache.get(userName); final String protectedUserKey = getProtectedUserKey(userName);
ProtectedUser protectedUser = protectedUsersCache.get(protectedUserKey);
if (protectedUser != null) if (protectedUser != null)
{ {
long currentTimeStamp = System.currentTimeMillis(); long currentTimeStamp = System.currentTimeMillis();
@@ -168,7 +176,8 @@ public class AuthenticationServiceImpl extends AbstractAuthenticationService imp
{ {
if (protectionEnabled) if (protectionEnabled)
{ {
ProtectedUser protectedUser = protectedUsersCache.get(userName); final String protectedUserKey = getProtectedUserKey(userName);
ProtectedUser protectedUser = protectedUsersCache.get(protectedUserKey);
if (protectedUser == null) if (protectedUser == null)
{ {
protectedUser = new ProtectedUser(userName); protectedUser = new ProtectedUser(userName);
@@ -186,10 +195,18 @@ public class AuthenticationServiceImpl extends AbstractAuthenticationService imp
} }
} }
} }
protectedUsersCache.put(userName, protectedUser); protectedUsersCache.put(protectedUserKey, protectedUser);
} }
} }
/**
* Creates a key by combining the service instance ID with the username. This are the type of keys maintained by protectedUsersCache map.
*/
public String getProtectedUserKey(String userName)
{
return serviceInstanceId + "@@" + userName;
}
public String getCurrentUserName() throws AuthenticationException public String getCurrentUserName() throws AuthenticationException
{ {
return authenticationComponent.getCurrentUserName(); return authenticationComponent.getCurrentUserName();

View File

@@ -729,7 +729,7 @@ cache.authorizationCache.readBackupData=false
cache.protectedUsersCache.maxItems=1000 cache.protectedUsersCache.maxItems=1000
cache.protectedUsersCache.timeToLiveSeconds=0 cache.protectedUsersCache.timeToLiveSeconds=0
cache.protectedUsersCache.maxIdleSeconds=0 cache.protectedUsersCache.maxIdleSeconds=0
cache.protectedUsersCache.cluster.type=fully-distributed cache.protectedUsersCache.cluster.type=local
cache.protectedUsersCache.backup-count=1 cache.protectedUsersCache.backup-count=1
cache.protectedUsersCache.eviction-policy=LRU cache.protectedUsersCache.eviction-policy=LRU
cache.protectedUsersCache.eviction-percentage=25 cache.protectedUsersCache.eviction-percentage=25

View File

@@ -1,172 +1,173 @@
/* /*
* #%L * #%L
* Alfresco Repository * Alfresco Repository
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2016 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is * the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms: * provided under the following open source license terms:
* *
* Alfresco is free software: you can redistribute it and/or modify * Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* Alfresco is distributed in the hope that it will be useful, * Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. * GNU Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L% * #L%
*/ */
package org.alfresco.opencmis; package org.alfresco.opencmis;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.Serializable; import java.io.Serializable;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID;
import org.alfresco.model.ContentModel;
import org.alfresco.opencmis.dictionary.CMISDictionaryService; import org.alfresco.model.ContentModel;
import org.alfresco.opencmis.dictionary.PropertyDefinitionWrapper; import org.alfresco.opencmis.dictionary.CMISDictionaryService;
import org.alfresco.opencmis.dictionary.TypeDefinitionWrapper; import org.alfresco.opencmis.dictionary.PropertyDefinitionWrapper;
import org.alfresco.opencmis.search.CMISQueryOptions; import org.alfresco.opencmis.dictionary.TypeDefinitionWrapper;
import org.alfresco.opencmis.search.CMISQueryOptions.CMISQueryMode; import org.alfresco.opencmis.search.CMISQueryOptions;
import org.alfresco.repo.action.evaluator.ComparePropertyValueEvaluator; import org.alfresco.opencmis.search.CMISQueryOptions.CMISQueryMode;
import org.alfresco.repo.action.executer.AddFeaturesActionExecuter; import org.alfresco.repo.action.evaluator.ComparePropertyValueEvaluator;
import org.alfresco.repo.audit.AuditComponent; import org.alfresco.repo.action.executer.AddFeaturesActionExecuter;
import org.alfresco.repo.audit.AuditComponentImpl; import org.alfresco.repo.audit.AuditComponent;
import org.alfresco.repo.audit.AuditServiceImpl; import org.alfresco.repo.audit.AuditComponentImpl;
import org.alfresco.repo.audit.UserAuditFilter; import org.alfresco.repo.audit.AuditServiceImpl;
import org.alfresco.repo.audit.model.AuditModelRegistryImpl; import org.alfresco.repo.audit.UserAuditFilter;
import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.audit.model.AuditModelRegistryImpl;
import org.alfresco.repo.dictionary.DictionaryDAO; import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.dictionary.M2Model; import org.alfresco.repo.dictionary.DictionaryDAO;
import org.alfresco.repo.domain.audit.AuditDAO; import org.alfresco.repo.dictionary.M2Model;
import org.alfresco.repo.domain.node.ContentDataWithId; import org.alfresco.repo.domain.audit.AuditDAO;
import org.alfresco.repo.domain.node.NodeDAO; import org.alfresco.repo.domain.node.ContentDataWithId;
import org.alfresco.repo.model.Repository; import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.node.archive.NodeArchiveService; import org.alfresco.repo.model.Repository;
import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.node.archive.NodeArchiveService;
import org.alfresco.repo.security.authentication.AuthenticationContext; import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationContext;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.tenant.TenantAdminService; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.tenant.TenantService; import org.alfresco.repo.tenant.TenantAdminService;
import org.alfresco.repo.tenant.TenantUtil; import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.tenant.TenantUtil.TenantRunAsWork; import org.alfresco.repo.tenant.TenantUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.tenant.TenantUtil.TenantRunAsWork;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.version.VersionableAspectTest; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.repo.workflow.WorkflowDeployer; import org.alfresco.repo.version.VersionableAspectTest;
import org.alfresco.service.ServiceRegistry; import org.alfresco.repo.workflow.WorkflowDeployer;
import org.alfresco.service.cmr.action.ActionCondition; import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.action.ActionService; import org.alfresco.service.cmr.action.ActionCondition;
import org.alfresco.service.cmr.dictionary.AspectDefinition; import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.lock.LockService; import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.lock.LockType; import org.alfresco.service.cmr.lock.LockService;
import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.lock.LockType;
import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.rule.Rule; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.rule.RuleService; import org.alfresco.service.cmr.rule.Rule;
import org.alfresco.service.cmr.rule.RuleType; import org.alfresco.service.cmr.rule.RuleService;
import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.rule.RuleType;
import org.alfresco.service.cmr.security.AccessPermission; import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.cmr.tagging.TaggingService; import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.version.Version; import org.alfresco.service.cmr.tagging.TaggingService;
import org.alfresco.service.cmr.version.VersionService; import org.alfresco.service.cmr.version.Version;
import org.alfresco.service.cmr.version.VersionType; import org.alfresco.service.cmr.version.VersionService;
import org.alfresco.service.cmr.workflow.WorkflowAdminService; import org.alfresco.service.cmr.version.VersionType;
import org.alfresco.service.cmr.workflow.WorkflowService; import org.alfresco.service.cmr.workflow.WorkflowAdminService;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.transaction.TransactionService; import org.alfresco.service.namespace.QName;
import org.alfresco.util.ApplicationContextHelper; import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.Pair; import org.alfresco.util.ApplicationContextHelper;
import org.apache.chemistry.opencmis.commons.PropertyIds; import org.alfresco.util.Pair;
import org.apache.chemistry.opencmis.commons.data.Ace; import org.apache.chemistry.opencmis.commons.PropertyIds;
import org.apache.chemistry.opencmis.commons.data.AllowableActions; import org.apache.chemistry.opencmis.commons.data.Ace;
import org.apache.chemistry.opencmis.commons.data.CmisExtensionElement; import org.apache.chemistry.opencmis.commons.data.AllowableActions;
import org.apache.chemistry.opencmis.commons.data.ContentStream; import org.apache.chemistry.opencmis.commons.data.CmisExtensionElement;
import org.apache.chemistry.opencmis.commons.data.FailedToDeleteData; import org.apache.chemistry.opencmis.commons.data.ContentStream;
import org.apache.chemistry.opencmis.commons.data.ObjectData; import org.apache.chemistry.opencmis.commons.data.FailedToDeleteData;
import org.apache.chemistry.opencmis.commons.data.ObjectInFolderData; import org.apache.chemistry.opencmis.commons.data.ObjectData;
import org.apache.chemistry.opencmis.commons.data.ObjectInFolderList; import org.apache.chemistry.opencmis.commons.data.ObjectInFolderData;
import org.apache.chemistry.opencmis.commons.data.ObjectList; import org.apache.chemistry.opencmis.commons.data.ObjectInFolderList;
import org.apache.chemistry.opencmis.commons.data.ObjectParentData; import org.apache.chemistry.opencmis.commons.data.ObjectList;
import org.apache.chemistry.opencmis.commons.data.Properties; import org.apache.chemistry.opencmis.commons.data.ObjectParentData;
import org.apache.chemistry.opencmis.commons.data.PropertyData; import org.apache.chemistry.opencmis.commons.data.Properties;
import org.apache.chemistry.opencmis.commons.data.RepositoryInfo; import org.apache.chemistry.opencmis.commons.data.PropertyData;
import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition; import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition; import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionContainer; import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
import org.apache.chemistry.opencmis.commons.enums.AclPropagation; import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionContainer;
import org.apache.chemistry.opencmis.commons.enums.Action; import org.apache.chemistry.opencmis.commons.enums.AclPropagation;
import org.apache.chemistry.opencmis.commons.enums.ChangeType; import org.apache.chemistry.opencmis.commons.enums.Action;
import org.apache.chemistry.opencmis.commons.enums.CmisVersion; import org.apache.chemistry.opencmis.commons.enums.ChangeType;
import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships; import org.apache.chemistry.opencmis.commons.enums.CmisVersion;
import org.apache.chemistry.opencmis.commons.enums.UnfileObject; import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
import org.apache.chemistry.opencmis.commons.enums.VersioningState; import org.apache.chemistry.opencmis.commons.enums.UnfileObject;
import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException; import org.apache.chemistry.opencmis.commons.enums.VersioningState;
import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException; import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException; import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisUpdateConflictException; import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlListImpl; import org.apache.chemistry.opencmis.commons.exceptions.CmisUpdateConflictException;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.CmisExtensionElementImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlListImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.CmisExtensionElementImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.ExtensionDataImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertiesImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.ExtensionDataImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyDecimalDefinitionImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertiesImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIdImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyDecimalDefinitionImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIntegerDefinitionImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIdImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIntegerImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIntegerDefinitionImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyStringImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIntegerImpl;
import org.apache.chemistry.opencmis.commons.impl.server.AbstractServiceFactory; import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyStringImpl;
import org.apache.chemistry.opencmis.commons.server.CallContext; import org.apache.chemistry.opencmis.commons.impl.server.AbstractServiceFactory;
import org.apache.chemistry.opencmis.commons.server.CmisService; import org.apache.chemistry.opencmis.commons.server.CallContext;
import org.apache.chemistry.opencmis.commons.spi.Holder; import org.apache.chemistry.opencmis.commons.server.CmisService;
import org.apache.commons.logging.Log; import org.apache.chemistry.opencmis.commons.spi.Holder;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.Log;
import org.junit.After; import org.apache.commons.logging.LogFactory;
import org.junit.Before; import org.junit.After;
import org.junit.Test; import org.junit.Before;
import org.springframework.context.ApplicationContext; import org.junit.Test;
import org.springframework.extensions.webscripts.GUID; import org.springframework.context.ApplicationContext;
import org.springframework.extensions.webscripts.GUID;
/** /**
* OpenCMIS tests. * OpenCMIS tests.
@@ -175,11 +176,11 @@ import org.springframework.extensions.webscripts.GUID;
* *
*/ */
public class CMISTest public class CMISTest
{ {
private static Log logger = LogFactory.getLog(CMISTest.class); private static Log logger = LogFactory.getLog(CMISTest.class);
private static final QName TEST_START_TASK = QName.createQName("http://www.alfresco.org/model/workflow/test/1.0", "startTaskVarScriptAssign"); private static final QName TEST_START_TASK = QName.createQName("http://www.alfresco.org/model/workflow/test/1.0", "startTaskVarScriptAssign");
private static final QName TEST_WORKFLOW_TASK = QName.createQName("http://www.alfresco.org/model/workflow/test/1.0", "assignVarTask"); private static final QName TEST_WORKFLOW_TASK = QName.createQName("http://www.alfresco.org/model/workflow/test/1.0", "assignVarTask");
private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(new String[]{ApplicationContextHelper.CONFIG_LOCATIONS[0],"classpath:test-cmisinteger_modell-context.xml"}); private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(new String[]{ApplicationContextHelper.CONFIG_LOCATIONS[0],"classpath:test-cmisinteger_modell-context.xml"});
@@ -209,7 +210,7 @@ public class CMISTest
private TenantService tenantService; private TenantService tenantService;
private SearchService searchService; private SearchService searchService;
private java.util.Properties globalProperties; private java.util.Properties globalProperties;
private AuditComponentImpl auditComponent; private AuditComponentImpl auditComponent;
private AlfrescoCmisServiceFactory factory; private AlfrescoCmisServiceFactory factory;
@@ -388,7 +389,7 @@ public class CMISTest
this.tenantAdminService = (TenantAdminService) ctx.getBean("tenantAdminService"); this.tenantAdminService = (TenantAdminService) ctx.getBean("tenantAdminService");
this.tenantService = (TenantService) ctx.getBean("tenantService"); this.tenantService = (TenantService) ctx.getBean("tenantService");
this.searchService = (SearchService) ctx.getBean("SearchService"); this.searchService = (SearchService) ctx.getBean("SearchService");
this.auditComponent = (AuditComponentImpl) ctx.getBean("auditComponent"); this.auditComponent = (AuditComponentImpl) ctx.getBean("auditComponent");
this.globalProperties = (java.util.Properties) ctx.getBean("global-properties"); this.globalProperties = (java.util.Properties) ctx.getBean("global-properties");
this.globalProperties.setProperty(VersionableAspectTest.AUTO_VERSION_PROPS_KEY, "true"); this.globalProperties.setProperty(VersionableAspectTest.AUTO_VERSION_PROPS_KEY, "true");
@@ -658,9 +659,9 @@ public class CMISTest
assertNotNull(startTaskTypeDefinition); assertNotNull(startTaskTypeDefinition);
assertNotNull(workflowTaskTypeDefinition); assertNotNull(workflowTaskTypeDefinition);
// caches are refreshed asynchronously // caches are refreshed asynchronously
Thread.sleep(5000); Thread.sleep(5000);
// check that loaded model is available via CMIS API // check that loaded model is available via CMIS API
CallContext context = new SimpleCallContext("admin", "admin", CmisVersion.CMIS_1_1); CallContext context = new SimpleCallContext("admin", "admin", CmisVersion.CMIS_1_1);
CmisService service = factory.getService(context); CmisService service = factory.getService(context);
@@ -799,12 +800,12 @@ public class CMISTest
*/ */
@Test @Test
public void testContentMimeTypeDetection() public void testContentMimeTypeDetection()
{ {
ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
FileFolderService ffs = serviceRegistry.getFileFolderService(); FileFolderService ffs = serviceRegistry.getFileFolderService();
AuthenticationComponent authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent"); AuthenticationComponent authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent");
final String isoEncoding = "ISO-8859-1"; final String isoEncoding = "ISO-8859-1";
final String utfEncoding = "UTF-8"; final String utfEncoding = "UTF-8";
// get repository id // get repository id
List<RepositoryInfo> repositories = withCmisService(new CmisServiceCallback<List<RepositoryInfo>>() List<RepositoryInfo> repositories = withCmisService(new CmisServiceCallback<List<RepositoryInfo>>()
@@ -875,16 +876,16 @@ public class CMISTest
return contentType; return contentType;
} }
}); });
assertEquals("Mimetype is not defined correctly.", MimetypeMap.MIMETYPE_HTML, contentType); assertEquals("Mimetype is not defined correctly.", MimetypeMap.MIMETYPE_HTML, contentType);
// check that the encoding is detected correctly // check that the encoding is detected correctly
checkEncoding(ffs, authenticationComponent, objectData, utfEncoding); checkEncoding(ffs, authenticationComponent, objectData, utfEncoding);
} }
// create content stream with mimetype and encoding as UTF-8 // create content stream with mimetype and encoding as UTF-8
{ {
String mimeType = MimetypeMap.MIMETYPE_TEXT_PLAIN + "; charset="+isoEncoding; String mimeType = MimetypeMap.MIMETYPE_TEXT_PLAIN + "; charset="+isoEncoding;
// NOTE that we intentionally specify the wrong charset here. // NOTE that we intentionally specify the wrong charset here.
// Alfresco will detect the encoding (as UTF-8 - given by the ContentStreamImpl constructor) // Alfresco will detect the encoding (as UTF-8 - given by the ContentStreamImpl constructor)
final ContentStreamImpl contentStreamHTML = new ContentStreamImpl(null, mimeType, "<html><head><title> Hello </title></head><body><p> Test html</p></body></html></body></html>"); final ContentStreamImpl contentStreamHTML = new ContentStreamImpl(null, mimeType, "<html><head><title> Hello </title></head><body><p> Test html</p></body></html></body></html>");
withCmisService(new CmisServiceCallback<Void>() withCmisService(new CmisServiceCallback<Void>()
@@ -917,68 +918,68 @@ public class CMISTest
return contentType; return contentType;
} }
}); });
assertEquals("Mimetype is not defined correctly.", MimetypeMap.MIMETYPE_TEXT_PLAIN, contentType); assertEquals("Mimetype is not defined correctly.", MimetypeMap.MIMETYPE_TEXT_PLAIN, contentType);
// check that the encoding is detected correctly // check that the encoding is detected correctly
checkEncoding(ffs, authenticationComponent, objectData, utfEncoding); checkEncoding(ffs, authenticationComponent, objectData, utfEncoding);
} }
// create content stream with mimetype and encoding as ISO-8859-1 // create content stream with mimetype and encoding as ISO-8859-1
{ {
String mimeType = MimetypeMap.MIMETYPE_TEXT_PLAIN + "; charset=" + utfEncoding; String mimeType = MimetypeMap.MIMETYPE_TEXT_PLAIN + "; charset=" + utfEncoding;
// NOTE that we intentionally specify the wrong charset here. // NOTE that we intentionally specify the wrong charset here.
// Alfresco will detect the encoding (as ISO-8859-1 - given by the ContentStreamImpl with streams) // Alfresco will detect the encoding (as ISO-8859-1 - given by the ContentStreamImpl with streams)
String content = "<html><head><title>aegif Mind Share Leader Generating New Paradigms by aegif corporation</title></head><body><p> Test html</p></body></html></body></html>"; String content = "<html><head><title>aegif Mind Share Leader Generating New Paradigms by aegif corporation</title></head><body><p> Test html</p></body></html></body></html>";
byte[] buf = null; byte[] buf = null;
try try
{ {
buf = content.getBytes(isoEncoding); // set the encoding here for the content stream buf = content.getBytes(isoEncoding); // set the encoding here for the content stream
} }
catch (UnsupportedEncodingException e) catch (UnsupportedEncodingException e)
{ {
e.printStackTrace(); e.printStackTrace();
} }
ByteArrayInputStream input = new ByteArrayInputStream(buf); ByteArrayInputStream input = new ByteArrayInputStream(buf);
final ContentStream contentStreamHTML = new ContentStreamImpl(null, BigInteger.valueOf(buf.length), mimeType, input); final ContentStream contentStreamHTML = new ContentStreamImpl(null, BigInteger.valueOf(buf.length), mimeType, input);
withCmisService(new CmisServiceCallback<Void>() withCmisService(new CmisServiceCallback<Void>()
{ {
@Override @Override
public Void execute(CmisService cmisService) public Void execute(CmisService cmisService)
{ {
Holder<String> latestObjectIdHolder = getHolderOfObjectOfLatestVersion(cmisService, repositoryId, Holder<String> latestObjectIdHolder = getHolderOfObjectOfLatestVersion(cmisService, repositoryId,
objectIdHolder); objectIdHolder);
cmisService.setContentStream(repositoryId, latestObjectIdHolder, true, null, contentStreamHTML, null); cmisService.setContentStream(repositoryId, latestObjectIdHolder, true, null, contentStreamHTML, null);
return null; return null;
} }
}); });
// check mimetype // check mimetype
final ObjectData objectData = withCmisService(new CmisServiceCallback<ObjectData>() final ObjectData objectData = withCmisService(new CmisServiceCallback<ObjectData>()
{ {
@Override @Override
public ObjectData execute(CmisService cmisService) public ObjectData execute(CmisService cmisService)
{ {
ObjectData objectData = cmisService.getObjectByPath(repositoryId, path, null, false, ObjectData objectData = cmisService.getObjectByPath(repositoryId, path, null, false,
IncludeRelationships.NONE, null, false, false, null); IncludeRelationships.NONE, null, false, false, null);
return objectData; return objectData;
} }
}); });
String contentType = withCmisService(new CmisServiceCallback<String>() String contentType = withCmisService(new CmisServiceCallback<String>()
{ {
@Override @Override
public String execute(CmisService cmisService) public String execute(CmisService cmisService)
{ {
String contentType = cmisService.getObjectInfo(repositoryId, objectData.getId()).getContentType(); String contentType = cmisService.getObjectInfo(repositoryId, objectData.getId()).getContentType();
return contentType; return contentType;
} }
}); });
assertEquals("Mimetype is not defined correctly.", MimetypeMap.MIMETYPE_TEXT_PLAIN, contentType); assertEquals("Mimetype is not defined correctly.", MimetypeMap.MIMETYPE_TEXT_PLAIN, contentType);
// check that the encoding is detected correctly // check that the encoding is detected correctly
checkEncoding(ffs, authenticationComponent, objectData, isoEncoding); checkEncoding(ffs, authenticationComponent, objectData, isoEncoding);
} }
// checkout/checkin object with mimetype and encoding // checkout/checkin object with mimetype and encoding
{ {
@@ -1033,50 +1034,50 @@ public class CMISTest
return contentType; return contentType;
} }
}); });
assertEquals("Mimetype is not defined correctly.", MimetypeMap.MIMETYPE_HTML, contentType); assertEquals("Mimetype is not defined correctly.", MimetypeMap.MIMETYPE_HTML, contentType);
checkEncoding(ffs, authenticationComponent, objectData, utfEncoding); checkEncoding(ffs, authenticationComponent, objectData, utfEncoding);
} }
}
protected void checkEncoding(FileFolderService ffs, AuthenticationComponent authenticationComponent,
final ObjectData objectData, String expectedEncoding)
{
// Authenticate as system to check the properties in alfresco
authenticationComponent.setSystemUserAsCurrentUser();
try
{
NodeRef doc1NodeRef = cmisIdToNodeRef(objectData.getId());
doc1NodeRef.getId();
FileInfo fileInfo = ffs.getFileInfo(doc1NodeRef);
Map<QName, Serializable> properties2 = fileInfo.getProperties();
ContentDataWithId contentData = (ContentDataWithId) properties2
.get(QName.createQName("{http://www.alfresco.org/model/content/1.0}content"));
String encoding = contentData.getEncoding();
assertEquals(expectedEncoding, encoding);
}
finally
{
authenticationComponent.clearCurrentSecurityContext();
}
} }
/**
* Turns a CMIS id into a node ref protected void checkEncoding(FileFolderService ffs, AuthenticationComponent authenticationComponent,
* @param nodeId final ObjectData objectData, String expectedEncoding)
* @return {
*/ // Authenticate as system to check the properties in alfresco
private NodeRef cmisIdToNodeRef(String nodeId) authenticationComponent.setSystemUserAsCurrentUser();
{ try
int idx = nodeId.indexOf(";"); {
if(idx != -1) NodeRef doc1NodeRef = cmisIdToNodeRef(objectData.getId());
{ doc1NodeRef.getId();
nodeId = nodeId.substring(0, idx);
} FileInfo fileInfo = ffs.getFileInfo(doc1NodeRef);
NodeRef nodeRef = new NodeRef(nodeId); Map<QName, Serializable> properties2 = fileInfo.getProperties();
return nodeRef;
ContentDataWithId contentData = (ContentDataWithId) properties2
.get(QName.createQName("{http://www.alfresco.org/model/content/1.0}content"));
String encoding = contentData.getEncoding();
assertEquals(expectedEncoding, encoding);
}
finally
{
authenticationComponent.clearCurrentSecurityContext();
}
}
/**
* Turns a CMIS id into a node ref
* @param nodeId
* @return
*/
private NodeRef cmisIdToNodeRef(String nodeId)
{
int idx = nodeId.indexOf(";");
if(idx != -1)
{
nodeId = nodeId.substring(0, idx);
}
NodeRef nodeRef = new NodeRef(nodeId);
return nodeRef;
} }
private Holder<String> getHolderOfObjectOfLatestVersion(CmisService cmisService, String repositoryId, Holder<String> currentHolder) private Holder<String> getHolderOfObjectOfLatestVersion(CmisService cmisService, String repositoryId, Holder<String> currentHolder)
{ {
@@ -1755,9 +1756,13 @@ public class CMISTest
List secondaryTypeIds = currentProperties.getProperties().get(PropertyIds.SECONDARY_OBJECT_TYPE_IDS).getValues(); List secondaryTypeIds = currentProperties.getProperties().get(PropertyIds.SECONDARY_OBJECT_TYPE_IDS).getValues();
assertTrue(secondaryTypeIds.contains(aspectName));
secondaryTypeIds.remove(aspectName); secondaryTypeIds.remove(aspectName);
final PropertiesImpl newProperties = new PropertiesImpl(); final PropertiesImpl newProperties = new PropertiesImpl();
newProperties.addProperty(new PropertyStringImpl(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, secondaryTypeIds)); newProperties.addProperty(new PropertyStringImpl(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, secondaryTypeIds));
final String updatedName = "My_new_name_"+UUID.randomUUID().toString();
newProperties.replaceProperty(new PropertyStringImpl(PropertyIds.NAME, updatedName));
withCmisService(new CmisServiceCallback<Void>() withCmisService(new CmisServiceCallback<Void>()
{ {
@@ -1765,6 +1770,8 @@ public class CMISTest
public Void execute(CmisService cmisService) public Void execute(CmisService cmisService)
{ {
Holder<String> latestObjectIdHolder = getHolderOfObjectOfLatestVersion(cmisService, repositoryId, objectIdHolder); Holder<String> latestObjectIdHolder = getHolderOfObjectOfLatestVersion(cmisService, repositoryId, objectIdHolder);
// This will result in aspectName being removed
// but that shouldn't mean that, for example, a cmis:name prop update gets ignored (MNT-18340)
cmisService.updateProperties(repositoryId, latestObjectIdHolder, null, newProperties, null); cmisService.updateProperties(repositoryId, latestObjectIdHolder, null, newProperties, null);
return null; return null;
} }
@@ -1775,12 +1782,15 @@ public class CMISTest
@Override @Override
public Properties execute(CmisService cmisService) public Properties execute(CmisService cmisService)
{ {
Properties properties = cmisService.getProperties(repositoryId, objectIdHolder.getValue(), null, null); Holder<String> latestObjectIdHolder = getHolderOfObjectOfLatestVersion(cmisService, repositoryId, objectIdHolder);
Properties properties = cmisService.getProperties(repositoryId, latestObjectIdHolder.getValue(), null, null);
return properties; return properties;
} }
}, CmisVersion.CMIS_1_1); }, CmisVersion.CMIS_1_1);
secondaryTypeIds = currentProperties1.getProperties().get(PropertyIds.SECONDARY_OBJECT_TYPE_IDS).getValues(); secondaryTypeIds = currentProperties1.getProperties().get(PropertyIds.SECONDARY_OBJECT_TYPE_IDS).getValues();
assertFalse(secondaryTypeIds.contains(aspectName));
assertEquals(updatedName, currentProperties1.getProperties().get(PropertyIds.NAME).getFirstValue());
} }
/** /**
@@ -2553,32 +2563,32 @@ public class CMISTest
{ {
TenantUtil.runAsUserTenant(new TenantRunAsWork<Void>() TenantUtil.runAsUserTenant(new TenantRunAsWork<Void>()
{ {
@Override @Override
public Void doWork() throws Exception public Void doWork() throws Exception
{ {
M2Model customModel = M2Model.createModel( M2Model customModel = M2Model.createModel(
Thread.currentThread().getContextClassLoader(). Thread.currentThread().getContextClassLoader().
getResourceAsStream("dictionary/dictionarydaotest_model1.xml")); getResourceAsStream("dictionary/dictionarydaotest_model1.xml"));
dictionaryDAO.putModel(customModel); dictionaryDAO.putModel(customModel);
assertNotNull(cmisDictionaryService.findType("P:cm:dublincore")); assertNotNull(cmisDictionaryService.findType("P:cm:dublincore"));
TypeDefinitionWrapper td = cmisDictionaryService.findType("D:daotest1:type1"); TypeDefinitionWrapper td = cmisDictionaryService.findType("D:daotest1:type1");
assertNotNull(td); assertNotNull(td);
return null; return null;
} }
}, "user1", "tenant1"); }, "user1", "tenant1");
TenantUtil.runAsUserTenant(new TenantRunAsWork<Void>() TenantUtil.runAsUserTenant(new TenantRunAsWork<Void>()
{ {
@Override @Override
public Void doWork() throws Exception public Void doWork() throws Exception
{ {
assertNotNull(cmisDictionaryService.findType("P:cm:dublincore")); assertNotNull(cmisDictionaryService.findType("P:cm:dublincore"));
TypeDefinitionWrapper td = cmisDictionaryService.findType("D:daotest1:type1"); TypeDefinitionWrapper td = cmisDictionaryService.findType("D:daotest1:type1");
assertNull(td); assertNull(td);
return null; return null;
} }
}, "user2", "tenant2"); }, "user2", "tenant2");
} }
/** /**
@@ -2706,32 +2716,32 @@ public class CMISTest
assertFalse("CMISChangeEvent " + changeType + " should store short form of objectId " + objectId, assertFalse("CMISChangeEvent " + changeType + " should store short form of objectId " + objectId,
objectId.toString().contains(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE.toString())); objectId.toString().contains(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE.toString()));
} }
int expectAtLeast = changes.getObjects().size(); int expectAtLeast = changes.getObjects().size();
// We should also be able to query without passing in any limit // We should also be able to query without passing in any limit
changes = cmisService.getContentChanges(repositoryId, new Holder<String>(changeToken), Boolean.TRUE, null, Boolean.FALSE, Boolean.FALSE, null, null); changes = cmisService.getContentChanges(repositoryId, new Holder<String>(changeToken), Boolean.TRUE, null, Boolean.FALSE, Boolean.FALSE, null, null);
assertTrue("Expected to still get changes", changes.getObjects().size() >= expectAtLeast); assertTrue("Expected to still get changes", changes.getObjects().size() >= expectAtLeast);
// and zero // and zero
changes = cmisService.getContentChanges(repositoryId, new Holder<String>(changeToken), Boolean.TRUE, null, Boolean.FALSE, Boolean.FALSE, BigInteger.valueOf(0), null); changes = cmisService.getContentChanges(repositoryId, new Holder<String>(changeToken), Boolean.TRUE, null, Boolean.FALSE, Boolean.FALSE, BigInteger.valueOf(0), null);
assertTrue("Expected to still get changes", changes.getObjects().size() >= expectAtLeast); assertTrue("Expected to still get changes", changes.getObjects().size() >= expectAtLeast);
// and one // and one
changes = cmisService.getContentChanges(repositoryId, new Holder<String>(changeToken), Boolean.TRUE, null, Boolean.FALSE, Boolean.FALSE, BigInteger.valueOf(1), null); changes = cmisService.getContentChanges(repositoryId, new Holder<String>(changeToken), Boolean.TRUE, null, Boolean.FALSE, Boolean.FALSE, BigInteger.valueOf(1), null);
assertEquals("Expected to still get changes", changes.getObjects().size(), 1); assertEquals("Expected to still get changes", changes.getObjects().size(), 1);
// Integery.MAX_VALUE must be handled // Integery.MAX_VALUE must be handled
// This will limit the number to a sane value // This will limit the number to a sane value
changes = cmisService.getContentChanges(repositoryId, new Holder<String>(changeToken), Boolean.TRUE, null, Boolean.FALSE, Boolean.FALSE, BigInteger.valueOf(Integer.MAX_VALUE), null); changes = cmisService.getContentChanges(repositoryId, new Holder<String>(changeToken), Boolean.TRUE, null, Boolean.FALSE, Boolean.FALSE, BigInteger.valueOf(Integer.MAX_VALUE), null);
assertTrue("Expected to still get changes", changes.getObjects().size() >= expectAtLeast); assertTrue("Expected to still get changes", changes.getObjects().size() >= expectAtLeast);
// but not negative // but not negative
try try
{ {
changes = cmisService.getContentChanges(repositoryId, new Holder<String>(changeToken), Boolean.TRUE, null, Boolean.FALSE, Boolean.FALSE, BigInteger.valueOf(-1), null); changes = cmisService.getContentChanges(repositoryId, new Holder<String>(changeToken), Boolean.TRUE, null, Boolean.FALSE, Boolean.FALSE, BigInteger.valueOf(-1), null);
fail("Negative maxItems is expected to fail"); fail("Negative maxItems is expected to fail");
} }
catch (CmisInvalidArgumentException e) catch (CmisInvalidArgumentException e)
{ {
// Expected // Expected
} }
return null; return null;
} }
@@ -3352,7 +3362,19 @@ public class CMISTest
cmisService.updateProperties(repositoryId, new Holder<String>(fileInfo.getNodeRef().toString()), null, properties, null); cmisService.updateProperties(repositoryId, new Holder<String>(fileInfo.getNodeRef().toString()), null, properties, null);
} }
//This extra check was added due to MNT-16641.
{
PropertiesImpl properties = new PropertiesImpl();
properties.addProperty(new PropertyStringImpl(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, "P:cm:lockable"));
Set<QName> existingAspects = nodeService.getAspects(docs.get(0).getNodeRef());
cmisService.updateProperties(repositoryId,new Holder<String>(docs.get(0).getNodeRef().toString()), null, properties, null);
Set<QName> updatedAspects = nodeService.getAspects(docs.get(0).getNodeRef());
updatedAspects.removeAll(existingAspects);
assertEquals(ContentModel.ASPECT_LOCKABLE, updatedAspects.iterator().next());
}
return repositoryId; return repositoryId;
} }
}, CmisVersion.CMIS_1_1); }, CmisVersion.CMIS_1_1);
@@ -3668,64 +3690,64 @@ public class CMISTest
AuthenticationUtil.popAuthentication(); AuthenticationUtil.popAuthentication();
} }
} }
@Test @Test
public void testCreateDocWithVersioningStateNone() throws Exception public void testCreateDocWithVersioningStateNone() throws Exception
{ {
AuthenticationUtil.pushAuthentication(); AuthenticationUtil.pushAuthentication();
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
try try
{ {
// get repository id // get repository id
final String repositoryId = withCmisService(new CmisServiceCallback<String>() final String repositoryId = withCmisService(new CmisServiceCallback<String>()
{ {
@Override @Override
public String execute(CmisService cmisService) public String execute(CmisService cmisService)
{ {
List<RepositoryInfo> repositories = cmisService.getRepositoryInfos(null); List<RepositoryInfo> repositories = cmisService.getRepositoryInfos(null);
assertTrue(repositories.size() > 0); assertTrue(repositories.size() > 0);
RepositoryInfo repo = repositories.get(0); RepositoryInfo repo = repositories.get(0);
final String repositoryId = repo.getId(); final String repositoryId = repo.getId();
return repositoryId; return repositoryId;
} }
}, CmisVersion.CMIS_1_1); }, CmisVersion.CMIS_1_1);
final NodeRef documentNodeRef = withCmisService(new CmisServiceCallback<NodeRef>() final NodeRef documentNodeRef = withCmisService(new CmisServiceCallback<NodeRef>()
{ {
@Override @Override
public NodeRef execute(CmisService cmisService) public NodeRef execute(CmisService cmisService)
{ {
final PropertiesImpl properties = new PropertiesImpl(); final PropertiesImpl properties = new PropertiesImpl();
String objectTypeId = "cmis:document"; String objectTypeId = "cmis:document";
properties.addProperty(new PropertyIdImpl(PropertyIds.OBJECT_TYPE_ID, objectTypeId)); properties.addProperty(new PropertyIdImpl(PropertyIds.OBJECT_TYPE_ID, objectTypeId));
String fileName = "textFile" + GUID.generate(); String fileName = "textFile" + GUID.generate();
properties.addProperty(new PropertyStringImpl(PropertyIds.NAME, fileName)); properties.addProperty(new PropertyStringImpl(PropertyIds.NAME, fileName));
final ContentStreamImpl contentStream = new ContentStreamImpl(fileName, MimetypeMap.MIMETYPE_TEXT_PLAIN, "Simple text plain document"); final ContentStreamImpl contentStream = new ContentStreamImpl(fileName, MimetypeMap.MIMETYPE_TEXT_PLAIN, "Simple text plain document");
String nodeId = cmisService.create(repositoryId, properties, repositoryHelper.getCompanyHome().getId(), contentStream, VersioningState.NONE, null, null); String nodeId = cmisService.create(repositoryId, properties, repositoryHelper.getCompanyHome().getId(), contentStream, VersioningState.NONE, null, null);
return new NodeRef(nodeId.substring(0, nodeId.indexOf(';'))); return new NodeRef(nodeId.substring(0, nodeId.indexOf(';')));
} }
}, CmisVersion.CMIS_1_1); }, CmisVersion.CMIS_1_1);
// check versioning properties // check versioning properties
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<List<Void>>() transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<List<Void>>()
{ {
@Override @Override
public List<Void> execute() throws Throwable public List<Void> execute() throws Throwable
{ {
assertTrue(nodeService.exists(documentNodeRef)); assertTrue(nodeService.exists(documentNodeRef));
assertFalse(nodeService.hasAspect(documentNodeRef, ContentModel.ASPECT_VERSIONABLE)); assertFalse(nodeService.hasAspect(documentNodeRef, ContentModel.ASPECT_VERSIONABLE));
return null; return null;
} }
}); });
} }
finally finally
{ {
AuthenticationUtil.popAuthentication(); AuthenticationUtil.popAuthentication();
} }
} }
/** /**
* MNT-14951: Test that the list of parents can be retrieved for a folder. * MNT-14951: Test that the list of parents can be retrieved for a folder.
@@ -3792,5 +3814,5 @@ public class CMISTest
auditSubsystem.destroy(); auditSubsystem.destroy();
AuthenticationUtil.popAuthentication(); AuthenticationUtil.popAuthentication();
} }
} }
} }

View File

@@ -34,6 +34,7 @@ import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static junit.framework.TestCase.assertNotNull;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
@@ -57,6 +58,7 @@ public class AuthenticationServiceImplTest
private SimpleCache<String, ProtectedUser> cache; private SimpleCache<String, ProtectedUser> cache;
private TicketComponent ticketComponent = mock(TicketComponent.class); private TicketComponent ticketComponent = mock(TicketComponent.class);
private AuthenticationServiceImpl authService; private AuthenticationServiceImpl authService;
private AuthenticationServiceImpl authService2;
private static final String USERNAME = "username"; private static final String USERNAME = "username";
private static final char[] PASSWORD = "password".toCharArray(); private static final char[] PASSWORD = "password".toCharArray();
@@ -69,6 +71,11 @@ public class AuthenticationServiceImplTest
authService.setTicketComponent(ticketComponent); authService.setTicketComponent(ticketComponent);
cache = new MockCache<>(); cache = new MockCache<>();
authService.setProtectedUsersCache(cache); authService.setProtectedUsersCache(cache);
authService2 = new AuthenticationServiceImpl();
authService2.setAuthenticationComponent(authenticationComponent);
authService2.setTicketComponent(ticketComponent);
authService2.setProtectedUsersCache(cache);
} }
@Test @Test
@@ -104,7 +111,9 @@ public class AuthenticationServiceImplTest
} }
verify(authenticationComponent, times(limit)).authenticate(USERNAME, PASSWORD); verify(authenticationComponent, times(limit)).authenticate(USERNAME, PASSWORD);
assertTrue("The user should be protected.", authService.isUserProtected(USERNAME)); assertTrue("The user should be protected.", authService.isUserProtected(USERNAME));
assertEquals("The number of recorded logins did not match.", attempts, cache.get(USERNAME).getNumLogins());
final String protectedUserKey = authService.getProtectedUserKey(USERNAME);
assertEquals("The number of recorded logins did not match.", attempts, cache.get(protectedUserKey).getNumLogins());
// test that the protection is still in place even if the password is correct // test that the protection is still in place even if the password is correct
doNothing().when(authenticationComponent).authenticate(USERNAME, PASSWORD); doNothing().when(authenticationComponent).authenticate(USERNAME, PASSWORD);
@@ -118,7 +127,7 @@ public class AuthenticationServiceImplTest
// normal // normal
} }
verify(authenticationComponent, times(limit)).authenticate(USERNAME, PASSWORD); verify(authenticationComponent, times(limit)).authenticate(USERNAME, PASSWORD);
assertEquals("The number of recorded logins did not match.", attempts + 1, cache.get(USERNAME).getNumLogins()); assertEquals("The number of recorded logins did not match.", attempts + 1, cache.get(protectedUserKey).getNumLogins());
} }
@Test @Test
@@ -145,11 +154,13 @@ public class AuthenticationServiceImplTest
} }
} }
assertTrue("The user should be protected.", authService.isUserProtected(USERNAME)); assertTrue("The user should be protected.", authService.isUserProtected(USERNAME));
assertEquals("The number of recorded logins did not match.", attempts, cache.get(USERNAME).getNumLogins());
final String protectedUserKey = authService.getProtectedUserKey(USERNAME);
assertEquals("The number of recorded logins did not match.", attempts, cache.get(protectedUserKey).getNumLogins());
Thread.sleep(timeLimit*1000 + 1); Thread.sleep(timeLimit*1000 + 1);
assertFalse("The user should not be protected any more.", authService.isUserProtected(USERNAME)); assertFalse("The user should not be protected any more.", authService.isUserProtected(USERNAME));
assertEquals("The number of recorded logins should stay the same after protection period ends.", assertEquals("The number of recorded logins should stay the same after protection period ends.",
attempts, cache.get(USERNAME).getNumLogins()); attempts, cache.get(protectedUserKey).getNumLogins());
doNothing().when(authenticationComponent).authenticate(USERNAME, PASSWORD); doNothing().when(authenticationComponent).authenticate(USERNAME, PASSWORD);
try try
@@ -161,9 +172,78 @@ public class AuthenticationServiceImplTest
fail("An " + AuthenticationException.class.getName() + " should not be thrown."); fail("An " + AuthenticationException.class.getName() + " should not be thrown.");
} }
assertNull("The user should be removed from the cache after successful login.", assertNull("The user should be removed from the cache after successful login.",
cache.get(USERNAME)); cache.get(protectedUserKey));
} }
@Test
public void testAuthChainWorksIfFirstAuthFails() throws Exception
{
int timeLimit = 1;
int attempts = 2;
authService.setProtectionPeriodSeconds(timeLimit);
authService.setProtectionLimit(attempts);
authService.setProtectionEnabled(true);
authService2.setProtectionPeriodSeconds(timeLimit);
authService2.setProtectionLimit(attempts);
authService2.setProtectionEnabled(true);
AuthenticationServiceImpl[] authenticationChain = {authService, authService2};
doThrow(new AuthenticationException("Bad password"))
.when(authenticationComponent).authenticate(USERNAME, PASSWORD);
// Authentication fails on first run.
for (int i = 0; i < attempts; i++) {
for (AuthenticationServiceImpl authentication : authenticationChain) {
try {
authentication.authenticate(USERNAME, PASSWORD);
fail("An " + AuthenticationException.class.getName() + " should be thrown.");
} catch (AuthenticationException ae) {
// normal
}
}
}
for (AuthenticationServiceImpl authentication : authenticationChain)
{
assertTrue("The user should be protected.", authentication.isUserProtected(USERNAME));
}
Thread.sleep(timeLimit*1000 + 1);
for (AuthenticationServiceImpl authentication : authenticationChain)
{
assertFalse("The user should not be protected any more.", authentication.isUserProtected(USERNAME));
}
// Authentication always fails on first authentication service in the chain.
try
{
authenticationChain[0].authenticate(USERNAME, PASSWORD);
fail("An " + AuthenticationException.class.getName() + " should be thrown.");
} catch (AuthenticationException ae) {
// normal
}
// Authentication should succeed on second authentication service in the chain.
doNothing().when(authenticationComponent).authenticate(USERNAME, PASSWORD);
try
{
authenticationChain[1].authenticate(USERNAME, PASSWORD);
}
catch (AuthenticationException ae)
{
fail("An " + AuthenticationException.class.getName() + " should not be thrown.");
}
assertNotNull("The user should not be removed from the cache for the corresponding authorization service after a failed login.",
cache.get(authenticationChain[0].getProtectedUserKey(USERNAME)));
assertNull("The user should be removed from the cache for the corresponding authorization service after successful login.",
cache.get(authenticationChain[1].getProtectedUserKey(USERNAME)));
}
@Test @Test
public void testProtectionDisabledBadPassword() public void testProtectionDisabledBadPassword()
{ {