/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco * * 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 * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Alfresco is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Alfresco. If not, see . */ package org.alfresco.repo.rendition; import java.io.File; import java.io.Serializable; import java.net.URL; import java.util.HashMap; import java.util.Map; import org.alfresco.model.ContentModel; import org.alfresco.model.RenditionModel; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.model.Repository; import org.alfresco.repo.rendition.executer.ImageRenderingEngine; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.service.cmr.rendition.RenditionDefinition; import org.alfresco.service.cmr.rendition.RenditionService; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.util.BaseAlfrescoSpringTest; import org.alfresco.util.PropertyMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * @author Neil McErlean * @since 3.3 */ public class RenditionServicePermissionsTest extends BaseAlfrescoSpringTest { /** Logger */ private static Log logger = LogFactory.getLog(RenditionServicePermissionsTest.class); private final static QName RESCALE_RENDER_DEFN_NAME = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, ImageRenderingEngine.NAME + System.currentTimeMillis()); private NodeRef nodeWithImageContent; private NodeRef testFolder; private PermissionService permissionService; private PersonService personService; private RenditionService renditionService; private Repository repositoryHelper; private RetryingTransactionHelper transactionHelper; private String testFolderName; @SuppressWarnings("deprecation") @Override protected void onSetUpInTransaction() throws Exception { super.onSetUpInTransaction(); this.permissionService = (PermissionService)this.applicationContext.getBean("PermissionService"); this.personService = (PersonService)this.applicationContext.getBean("PersonService"); this.renditionService = (RenditionService) this.applicationContext.getBean("renditionService"); this.repositoryHelper = (Repository) this.applicationContext.getBean("repositoryHelper"); this.transactionHelper = (RetryingTransactionHelper) this.applicationContext .getBean("retryingTransactionHelper"); NodeRef companyHome = this.repositoryHelper.getCompanyHome(); // Create the test folder used for these tests this.testFolderName= "Test-folder-"+ System.currentTimeMillis(); this.testFolder = nodeService.createNode(companyHome, ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.APP_MODEL_1_0_URI,testFolderName), ContentModel.TYPE_FOLDER).getChildRef(); nodeService.setProperty(testFolder, ContentModel.PROP_NAME, testFolderName); // Create the node used as a content supplier for tests Map props = new HashMap(); props.put(ContentModel.PROP_NAME, "Test-image-node-" + System.currentTimeMillis()); String testImageNodeName = "testImageNode" + System.currentTimeMillis(); this.nodeWithImageContent = nodeService.createNode(companyHome, ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.APP_MODEL_1_0_URI, testImageNodeName), ContentModel.TYPE_CONTENT, props).getChildRef(); // Stream some well-known image content into the node. URL url = RenditionServicePermissionsTest.class.getClassLoader().getResource("images/gray21.512.png"); assertNotNull("url of test image was null", url); File imageFile = new File(url.getFile()); assertTrue(imageFile.exists()); nodeService.setProperty(nodeWithImageContent, ContentModel.PROP_CONTENT, new ContentData(null, MimetypeMap.MIMETYPE_IMAGE_PNG, 0L, null)); ContentWriter writer = contentService.getWriter(nodeWithImageContent, ContentModel.PROP_CONTENT, true); writer.setMimetype(MimetypeMap.MIMETYPE_IMAGE_PNG); writer.setEncoding("UTF-8"); writer.putContent(imageFile); } @Override protected void onTearDownInTransaction() throws Exception { nodeService.deleteNode(nodeWithImageContent); nodeService.deleteNode(testFolder); } /** * This test method uses the RenditionService to render a test document and place the * rendition under a folder for which the user does not have write permissions. * This should be allowed as all renditions are performed as system. */ @SuppressWarnings("deprecation") public void testRenditionAccessPermissions() throws Exception { this.setComplete(); this.endTransaction(); final String normalUser = "renditionUser"; // As admin, create a user who has read-only access to the testFolder transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { public Void execute() throws Throwable { // Set the current security context as admin AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); assertEquals("admin", authenticationService.getCurrentUserName()); if (authenticationService.authenticationExists(normalUser) == false) { authenticationService.createAuthentication(normalUser, "PWD".toCharArray()); PropertyMap personProperties = new PropertyMap(); personProperties.put(ContentModel.PROP_USERNAME, normalUser); personProperties.put(ContentModel.PROP_AUTHORITY_DISPLAY_NAME, "title" + normalUser); personProperties.put(ContentModel.PROP_FIRSTNAME, "firstName"); personProperties.put(ContentModel.PROP_LASTNAME, "lastName"); personProperties.put(ContentModel.PROP_EMAIL, "email@email.com"); personProperties.put(ContentModel.PROP_JOBTITLE, "jobTitle"); personService.createPerson(personProperties); } // Restrict write access to the test folder permissionService.setPermission(testFolder, normalUser, PermissionService.CONSUMER, true); return null; } }); // As the user, render a piece of content with the rendition going to testFolder final NodeRef rendition = transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { public NodeRef execute() throws Throwable { // Set the current security context as a rendition user AuthenticationUtil.setFullyAuthenticatedUser(normalUser); assertEquals(normalUser, authenticationService.getCurrentUserName()); assertFalse("Source node has unexpected renditioned aspect.", nodeService.hasAspect(nodeWithImageContent, RenditionModel.ASPECT_RENDITIONED)); String path = testFolderName+"/testRendition.png"; // Create the rendering action. RenditionDefinition action = makeRescaleImageAction(); action.setParameterValue(RenditionService.PARAM_DESTINATION_PATH_TEMPLATE, path); // Perform the action with an explicit destination folder logger.debug("Creating rendition of: " + nodeWithImageContent); ChildAssociationRef renditionAssoc = renditionService.render(nodeWithImageContent, action); logger.debug("Created rendition: " + renditionAssoc.getChildRef()); NodeRef renditionNode = renditionAssoc.getChildRef(); assertEquals("The parent node was not correct", nodeWithImageContent, renditionAssoc.getParentRef()); logger.debug("rendition's primary parent: " + nodeService.getPrimaryParent(renditionNode)); assertEquals("The parent node was not correct", testFolder, nodeService.getPrimaryParent(renditionNode).getParentRef()); // Now the source content node should have the rn:renditioned aspect assertTrue("Source node is missing renditioned aspect.", nodeService.hasAspect(nodeWithImageContent, RenditionModel.ASPECT_RENDITIONED)); return renditionNode; } }); transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { public Void execute() throws Throwable { // Set the current security context as admin AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); final Serializable renditionCreator = nodeService.getProperty(rendition, ContentModel.PROP_CREATOR); assertEquals("Incorrect creator", normalUser, renditionCreator); return null; } }); } /** * Creates a RenditionDefinition for the RescaleImageActionExecutor. * * @return A new RenderingAction. */ private RenditionDefinition makeRescaleImageAction() { RenditionDefinition result = renditionService.createRenditionDefinition(RESCALE_RENDER_DEFN_NAME, ImageRenderingEngine.NAME); result.setParameterValue(ImageRenderingEngine.PARAM_RESIZE_WIDTH, 42); return result; } }