diff --git a/config/alfresco/web-publishing-context.xml b/config/alfresco/web-publishing-context.xml
index daa5a314b6..2a6b42b1c9 100644
--- a/config/alfresco/web-publishing-context.xml
+++ b/config/alfresco/web-publishing-context.xml
@@ -66,6 +66,7 @@
+
@@ -75,6 +76,7 @@
+
diff --git a/source/java/org/alfresco/repo/publishing/AbstractPublishingIntegrationTest.java b/source/java/org/alfresco/repo/publishing/AbstractPublishingIntegrationTest.java
index e1b18ebd26..83387544f5 100644
--- a/source/java/org/alfresco/repo/publishing/AbstractPublishingIntegrationTest.java
+++ b/source/java/org/alfresco/repo/publishing/AbstractPublishingIntegrationTest.java
@@ -62,8 +62,6 @@ public abstract class AbstractPublishingIntegrationTest extends BaseSpringTest
protected Environment environment;
protected NodeRef docLib;
- protected UserTransaction transaction;
-
@Override
@Before
public void onSetUp() throws Exception
@@ -76,10 +74,6 @@ public abstract class AbstractPublishingIntegrationTest extends BaseSpringTest
this.fileFolderService = serviceRegistry.getFileFolderService();
this.nodeService = serviceRegistry.getNodeService();
- transaction = serviceRegistry.getTransactionService().getUserTransaction();
- transaction.begin();
- transaction.setRollbackOnly();
-
this.siteId = GUID.generate();
siteService.createSite("test", siteId,
"Site created by publishing test",
@@ -89,30 +83,21 @@ public abstract class AbstractPublishingIntegrationTest extends BaseSpringTest
this.environment = rootObject.getEnvironment();
this.queue = rootObject.getPublishingQueue();
+ AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser();
}
@After
public void onTearDown() throws Exception
{
AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser();
- siteService.deleteSite(siteId);
try
{
- if (transaction.getStatus() == Status.STATUS_MARKED_ROLLBACK)
- {
- transaction.rollback();
- }
- else
- {
- transaction.commit();
- }
+ siteService.deleteSite(siteId);
}
- catch (Exception e)
+ finally
{
- e.printStackTrace();
- throw new RuntimeException(e);
+ super.onTearDown();
}
- super.onTearDown();
}
protected ChannelType mockChannelType()
diff --git a/source/java/org/alfresco/repo/publishing/MutablePublishingPackageImpl.java b/source/java/org/alfresco/repo/publishing/MutablePublishingPackageImpl.java
index f6cdeabb94..8767d02f5e 100644
--- a/source/java/org/alfresco/repo/publishing/MutablePublishingPackageImpl.java
+++ b/source/java/org/alfresco/repo/publishing/MutablePublishingPackageImpl.java
@@ -26,6 +26,8 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import org.alfresco.repo.security.authentication.AuthenticationUtil;
+import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.transfer.manifest.TransferManifestNodeFactory;
import org.alfresco.repo.transfer.manifest.TransferManifestNormalNode;
import org.alfresco.service.cmr.publishing.MutablePublishingPackage;
@@ -68,7 +70,20 @@ public class MutablePublishingPackageImpl implements MutablePublishingPackage
/**
* {@inheritDoc}
*/
- public void addNodesToPublish(Collection nodesToAdd)
+ public void addNodesToPublish(final Collection nodesToAdd)
+ {
+ AuthenticationUtil.runAs(new RunAsWork()
+ {
+ public Void doWork() throws Exception
+ {
+ versionNodes(nodesToAdd);
+ return null;
+ }
+ }, AuthenticationUtil.getSystemUserName());
+ nodesToPublish.addAll(nodesToAdd);
+ }
+
+ private void versionNodes(Collection nodesToAdd)
{
for (NodeRef nodeRef : nodesToAdd)
{
@@ -85,7 +100,6 @@ public class MutablePublishingPackageImpl implements MutablePublishingPackage
entryMap.put(nodeRef, publishingPackage);
}
}
- nodesToPublish.addAll(nodesToAdd);
}
/**
diff --git a/source/java/org/alfresco/repo/publishing/PublishingEventHelper.java b/source/java/org/alfresco/repo/publishing/PublishingEventHelper.java
index a5663d6999..842fefeacc 100644
--- a/source/java/org/alfresco/repo/publishing/PublishingEventHelper.java
+++ b/source/java/org/alfresco/repo/publishing/PublishingEventHelper.java
@@ -59,6 +59,7 @@ import java.util.TimeZone;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.node.NodeUtils;
+import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.repo.workflow.WorkflowModel;
import org.alfresco.service.cmr.publishing.PublishingEvent;
import org.alfresco.service.cmr.publishing.PublishingEventFilter;
@@ -72,6 +73,8 @@ import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.security.AccessStatus;
+import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.workflow.WorkflowDefinition;
import org.alfresco.service.cmr.workflow.WorkflowPath;
import org.alfresco.service.cmr.workflow.WorkflowService;
@@ -98,6 +101,7 @@ public class PublishingEventHelper
private ContentService contentService;
private WorkflowService workflowService;
private PublishingPackageSerializer serializer;
+ private PermissionService permissionService;
private String workflowEngineId;
@@ -143,6 +147,14 @@ public class PublishingEventHelper
this.serializer = serializer;
}
+ /**
+ * @param permissionService the permissionService to set
+ */
+ public void setPermissionService(PermissionService permissionService)
+ {
+ this.permissionService = permissionService;
+ }
+
public PublishingEvent getPublishingEvent(NodeRef eventNode) throws AlfrescoRuntimeException
{
if(eventNode == null)
@@ -198,6 +210,12 @@ public class PublishingEventHelper
public NodeRef createNode(NodeRef queueNode, PublishingPackage publishingPackage, String channelId, Calendar schedule, String comment, StatusUpdate statusUpdate)
throws Exception
{
+ checkChannelAccess(channelId);
+ if(statusUpdate != null && isEmpty(statusUpdate.getChannelIds())==false )
+ for (String statusChannelId : statusUpdate.getChannelIds())
+ {
+ checkChannelAccess(statusChannelId);
+ }
if (schedule == null)
{
schedule = Calendar.getInstance();
@@ -214,6 +232,16 @@ public class PublishingEventHelper
return eventNode;
}
+ private void checkChannelAccess(String channelId)
+ {
+ NodeRef channelNode = new NodeRef(channelId);
+ AccessStatus accessStatus = permissionService.hasPermission(channelNode, PermissionService.ADD_CHILDREN);
+ if(AccessStatus.ALLOWED != accessStatus)
+ {
+ throw new AccessDeniedException("You do not have access to channel: " + channelId);
+ }
+ }
+
private Map buildPublishingEventProperties(PublishingPackage publishingPackage,
String channelId, Calendar schedule, String comment, StatusUpdate statusUpdate, String name)
{
diff --git a/source/java/org/alfresco/repo/publishing/PublishingEventHelperTest.java b/source/java/org/alfresco/repo/publishing/PublishingEventHelperTest.java
index 6e1a1b7f9d..fa20244e3f 100644
--- a/source/java/org/alfresco/repo/publishing/PublishingEventHelperTest.java
+++ b/source/java/org/alfresco/repo/publishing/PublishingEventHelperTest.java
@@ -32,6 +32,7 @@ import static org.alfresco.repo.publishing.PublishingModel.PROP_PUBLISHING_EVENT
import static org.alfresco.repo.publishing.PublishingModel.TYPE_PUBLISHING_EVENT;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyMap;
+import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -59,6 +60,8 @@ import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.security.AccessStatus;
+import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -84,6 +87,9 @@ public class PublishingEventHelperTest
@Resource(name="ContentService")
ContentService contentService;
+ @Resource(name="PermissionService")
+ PermissionService permissionService;
+
@Test
public void testGetPublishingEventNode() throws Exception
{
@@ -168,6 +174,7 @@ public class PublishingEventHelperTest
@Test
public void testCreateNode() throws Exception
{
+ when(permissionService.hasPermission(any(NodeRef.class), anyString())).thenReturn(AccessStatus.ALLOWED);
// Mock serializer since this behaviour is already tested in PublishingPackageSerializerTest.
ContentWriter writer = mock(ContentWriter.class);
when(contentService.getWriter(any(NodeRef.class), eq(PROP_PUBLISHING_EVENT_PAYLOAD), eq(true)))
@@ -186,7 +193,7 @@ public class PublishingEventHelperTest
Map entires = Collections.emptyMap();
PublishingPackage pckg = new PublishingPackageImpl(entires);
- String channelName = "The channel";
+ String channelName = "test://channel/id";
Calendar schedule = Calendar.getInstance();
String comment = "The comment";
diff --git a/source/java/org/alfresco/repo/publishing/PublishingQueueImplTest.java b/source/java/org/alfresco/repo/publishing/PublishingQueueImplTest.java
index 4e6d62531b..f8d7299139 100644
--- a/source/java/org/alfresco/repo/publishing/PublishingQueueImplTest.java
+++ b/source/java/org/alfresco/repo/publishing/PublishingQueueImplTest.java
@@ -32,8 +32,12 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
+import org.alfresco.repo.security.permissions.AccessDeniedException;
+import org.alfresco.repo.security.person.TestPersonManager;
+import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.publishing.MutablePublishingPackage;
import org.alfresco.service.cmr.publishing.PublishingEvent;
import org.alfresco.service.cmr.publishing.PublishingPackage;
@@ -41,11 +45,17 @@ import org.alfresco.service.cmr.publishing.PublishingPackageEntry;
import org.alfresco.service.cmr.publishing.PublishingService;
import org.alfresco.service.cmr.publishing.Status;
import org.alfresco.service.cmr.publishing.StatusUpdate;
+import org.alfresco.service.cmr.publishing.channels.Channel;
+import org.alfresco.service.cmr.publishing.channels.ChannelType;
import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.security.MutableAuthenticationService;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.cmr.workflow.WorkflowInstance;
import org.alfresco.service.cmr.workflow.WorkflowPath;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.namespace.QName;
+import org.alfresco.util.GUID;
import org.junit.Test;
/**
@@ -58,10 +68,12 @@ public class PublishingQueueImplTest extends AbstractPublishingIntegrationTest
private static final String channelId = "test://channel/node";
private static final String comment = "The Comment";
- protected PublishingService publishingService;
-
+ private PublishingService publishingService;
private WorkflowService workflowService;
-
+ private PermissionService permissionService;
+ private TestPersonManager personManager;
+ private ChannelServiceImpl channelService;
+
private String eventId;
@Test
@@ -142,7 +154,7 @@ public class PublishingQueueImplTest extends AbstractPublishingIntegrationTest
NodeRef firstNode = createContent("First");
NodeRef secondNode = createContent("Second");
- List channelNames = Arrays.asList("Channel1", "Channel2", "Channel3" );
+ List channelNames = Arrays.asList("test://channel/Channel1", "test://channel/Channel2", "test://channel/Channel3" );
String message = "The message";
StatusUpdate update = queue.createStatusUpdate(message, secondNode, channelNames);
@@ -162,6 +174,74 @@ public class PublishingQueueImplTest extends AbstractPublishingIntegrationTest
assertTrue(names.containsAll(channelNames));
}
+ @Test
+ public void testScheduleNewEventPermissions() throws Exception
+ {
+ // Create Channels as Admin
+ ChannelType channelType = mockChannelType();
+ channelService.register(channelType);
+ Channel publishChannel = channelService.createChannel(channelType.getId(), "Channel1", null);
+ NodeRef publishChannelNode = new NodeRef(publishChannel.getId());
+ Channel statusChannel = channelService.createChannel(channelType.getId(), "Channel2", null);
+ NodeRef statusChannelNode = new NodeRef(statusChannel.getId());
+
+ NodeRef firstNode = createContent("First");
+ NodeRef secondNode = createContent("Second");
+
+ // Create User1, add read permissions and set as current user.
+ String user1 = GUID.generate();
+ personManager.createPerson(user1);
+ permissionService.setPermission(publishChannelNode, user1, PermissionService.READ, true);
+ permissionService.setPermission(statusChannelNode, user1, PermissionService.READ, true);
+ personManager.setUser(user1);
+
+ // Publish an event
+ MutablePublishingPackage publishingPackage = queue.createPublishingPackage();
+ publishingPackage.addNodesToPublish(firstNode, secondNode);
+ Calendar schedule = Calendar.getInstance();
+ schedule.add(Calendar.HOUR, 2);
+ try
+ {
+ this.eventId = queue.scheduleNewEvent(publishingPackage, publishChannel.getId(), schedule, comment, null);
+ fail("shceduleNewEvent should have thrown an AccessDeniedException!");
+ }
+ catch(AlfrescoRuntimeException e)
+ {
+ //NOOP
+ }
+
+ // Set Add Child permission on publish channel.
+ AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser();
+ permissionService.setPermission(publishChannelNode, user1, PermissionService.ADD_CHILDREN, true);
+ personManager.setUser(user1);
+
+ // Check publish works now.
+ this.eventId = queue.scheduleNewEvent(publishingPackage, publishChannel.getId(), schedule, comment, null);
+ assertNotNull(eventId);
+ publishingService.cancelPublishingEvent(eventId);
+
+ String message = "The message";
+ StatusUpdate update = queue.createStatusUpdate(message, secondNode, statusChannel.getId());
+ try
+ {
+ this.eventId = queue.scheduleNewEvent(publishingPackage, publishChannel.getId(), schedule, comment, update);
+ fail("shceduleNewEvent with status update should have thrown an AccessDeniedException!");
+ }
+ catch(AlfrescoRuntimeException e)
+ {
+ //NOOP
+ }
+
+ // Set Add Child permission on status channel.
+ AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser();
+ permissionService.setPermission(statusChannelNode, user1, PermissionService.ADD_CHILDREN, true);
+ personManager.setUser(user1);
+
+ // Check publish works now.
+ this.eventId = queue.scheduleNewEvent(publishingPackage, publishChannel.getId(), schedule, comment, null);
+ assertNotNull(eventId);
+ }
+
private NodeRef createContent(String name)
{
return fileFolderService.create(docLib, name, ContentModel.TYPE_CONTENT).getNodeRef();
@@ -176,6 +256,13 @@ public class PublishingQueueImplTest extends AbstractPublishingIntegrationTest
super.onSetUp();
this.workflowService = serviceRegistry.getWorkflowService();
this.publishingService = (PublishingService) getApplicationContext().getBean("publishingService");
+ this.channelService = (ChannelServiceImpl) getApplicationContext().getBean("channelService");
+
+ this.permissionService = (PermissionService) getApplicationContext().getBean(ServiceRegistry.PERMISSIONS_SERVICE.getLocalName());
+ MutableAuthenticationService authenticationService= (MutableAuthenticationService) getApplicationContext().getBean(ServiceRegistry.AUTHENTICATION_SERVICE.getLocalName());
+ PersonService personService= (PersonService) getApplicationContext().getBean(ServiceRegistry.PERSON_SERVICE.getLocalName());
+
+ this.personManager = new TestPersonManager(authenticationService, personService, nodeService);
}
/**
@@ -185,6 +272,7 @@ public class PublishingQueueImplTest extends AbstractPublishingIntegrationTest
@Override
public void onTearDown() throws Exception
{
+ AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser();
if(eventId!=null)
{
try
diff --git a/source/java/org/alfresco/repo/publishing/PublishingRootObject.java b/source/java/org/alfresco/repo/publishing/PublishingRootObject.java
index b5b7529d61..92d6461bac 100644
--- a/source/java/org/alfresco/repo/publishing/PublishingRootObject.java
+++ b/source/java/org/alfresco/repo/publishing/PublishingRootObject.java
@@ -38,6 +38,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.SearchService;
+import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.version.VersionService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
@@ -62,12 +63,11 @@ public class PublishingRootObject
private VersionService versionService;
private TransferManifestNodeFactory transferManifestNodeFactory;
private RetryingTransactionHelper retryingTransactionHelper;
-// private TenantAdminService tenantAdminService;
+ private PermissionService permissionService;
private StoreRef publishingStore;
private String publishingRootPath;
-// private Map environments = new HashMap();
/**
* @return the approprieate {@link Environment} for the current domain.
@@ -75,15 +75,6 @@ public class PublishingRootObject
*/
public Environment getEnvironment() throws BeansException
{
-// String tenantDomain = tenantAdminService.getCurrentUserDomain();
-// Environment environment = environments.get(tenantDomain);
-// if(environment != null)
-// {
-// return environment;
-// }
-// environment = createEnvironment();
-// environments.put(tenantDomain, environment);
-// return environment;
return createEnvironment();
}
@@ -145,6 +136,7 @@ public class PublishingRootObject
ASSOC_PUBLISHING_QUEUE,
QName.createQName(NAMESPACE, "publishingQueue"),
TYPE_PUBLISHING_QUEUE).getChildRef();
+ permissionService.setPermission(queueNode, PermissionService.ALL_AUTHORITIES, PermissionService.ADD_CHILDREN, true);
}
return queueNode;
}
@@ -228,14 +220,6 @@ public class PublishingRootObject
this.searchService = searchService;
}
-// /**
-// * @param tenantAdminService the tenantAdminService to set
-// */
-// public void setTenantAdminService(TenantAdminService tenantAdminService)
-// {
-// this.tenantAdminService = tenantAdminService;
-// }
-
/**
* @param transferManifestNodeFactory the transferManifestNodeFactory to set
*/
@@ -251,4 +235,12 @@ public class PublishingRootObject
{
this.versionService = versionService;
}
+
+ /**
+ * @param permissionService the permissionService to set
+ */
+ public void setPermissionService(PermissionService permissionService)
+ {
+ this.permissionService = permissionService;
+ }
}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/publishing/PublishingRootObjectTest.java b/source/java/org/alfresco/repo/publishing/PublishingRootObjectTest.java
index 9a59a32a8d..0578ab3ff5 100644
--- a/source/java/org/alfresco/repo/publishing/PublishingRootObjectTest.java
+++ b/source/java/org/alfresco/repo/publishing/PublishingRootObjectTest.java
@@ -41,7 +41,6 @@ public class PublishingRootObjectTest extends AbstractPublishingIntegrationTest
{
super.onSetUp();
this.rootObject = (PublishingRootObject) getApplicationContext().getBean(PublishingRootObject.NAME);
- AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
}
@Test
diff --git a/source/java/org/alfresco/service/cmr/publishing/PublishingQueue.java b/source/java/org/alfresco/service/cmr/publishing/PublishingQueue.java
index b0668dc4d4..c7269961ff 100644
--- a/source/java/org/alfresco/service/cmr/publishing/PublishingQueue.java
+++ b/source/java/org/alfresco/service/cmr/publishing/PublishingQueue.java
@@ -42,7 +42,7 @@ public interface PublishingQueue
* @param channelId The name of the channel that the package is to be published to
* @param schedule The time at which the new publishing event should be scheduled (optional - null
indicates "as soon as possible")
* @param comment A comment to be stored with this new event (optional - may be null
)
- * @param statusUpdate TODO
+ * @param statusUpdate defines the status update (if any). If null
then no status update is sent.
* @return The identifier of the newly scheduled event
*/
String scheduleNewEvent(PublishingPackage publishingPackage, String channelId, Calendar schedule, String comment, StatusUpdate statusUpdate);