From a7766b82d9ddd2d45e6171a11bf7994c2f43876a Mon Sep 17 00:00:00 2001 From: Alan Davis Date: Tue, 23 Sep 2014 16:11:26 +0000 Subject: [PATCH] ACE-936: Merged HEAD-BUG-FIX (5.0/Cloud) to HEAD (5.0/Cloud) 85515: Merged DEV to HEAD-BUG-FIX (5.0/Cloud). 63635: ALF-20865 Consumers should not be able to share/unshare a document Unshare action can perform consumer/contributer who performed Share action or a user with another role. 84859: ACE-936 Consumers should not be able to share/unshare a document In QuickShareRestApiTest was added testUnshareContributer() test. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@85533 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../web-scripts-application-context.xml | 3 + .../quickshare/UnshareContentDelete.java | 56 +++++++ .../quickshare/QuickShareRestApiTest.java | 142 ++++++++++++++---- 3 files changed, 174 insertions(+), 27 deletions(-) diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml index 5d75a1ff3d..c1e3a18a4d 100644 --- a/config/alfresco/web-scripts-application-context.xml +++ b/config/alfresco/web-scripts-application-context.xml @@ -1769,6 +1769,9 @@ + + + diff --git a/source/java/org/alfresco/repo/web/scripts/quickshare/UnshareContentDelete.java b/source/java/org/alfresco/repo/web/scripts/quickshare/UnshareContentDelete.java index c41d544680..2a462b139b 100644 --- a/source/java/org/alfresco/repo/web/scripts/quickshare/UnshareContentDelete.java +++ b/source/java/org/alfresco/repo/web/scripts/quickshare/UnshareContentDelete.java @@ -23,7 +23,14 @@ import java.util.Map; import javax.servlet.http.HttpServletResponse; +import org.alfresco.model.ContentModel; +import org.alfresco.model.QuickShareModel; +import org.alfresco.repo.site.SiteModel; import org.alfresco.service.cmr.repository.InvalidNodeRefException; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.site.SiteService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.extensions.webscripts.Cache; @@ -46,6 +53,21 @@ public class UnshareContentDelete extends AbstractQuickShareContent { private static final Log logger = LogFactory.getLog(ShareContentPost.class); + private NodeService nodeService; + private SiteService siteService; + private AuthenticationService authenticationService; + + public void setNodeService(NodeService nodeService) { + this.nodeService = nodeService; + } + + public void setSiteService(SiteService siteService) { + this.siteService = siteService; + } + + public void setAuthenticationService(AuthenticationService authenticationService) { + this.authenticationService = authenticationService; + } @Override protected Map executeImpl(WebScriptRequest req, Status status, Cache cache) @@ -63,6 +85,20 @@ public class UnshareContentDelete extends AbstractQuickShareContent throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "A valid sharedId must be specified !"); } + NodeRef nodeRef = quickShareService.getTenantNodeRefFromSharedId(sharedId).getSecond(); + String currentUser = authenticationService.getCurrentUserName(); + + String siteName = getSiteName(nodeRef); + String sharedBy = (String) nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDBY); + if (!currentUser.equals(sharedBy) && siteName != null) + { + String role = siteService.getMembersRole(siteName, currentUser); + if (role.equals(SiteModel.SITE_CONSUMER) || role.equals(SiteModel.SITE_CONTRIBUTOR)) + { + throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "Can't perform unshare action: "+sharedId); + } + } + try { quickShareService.unshareContent(sharedId); @@ -77,4 +113,24 @@ public class UnshareContentDelete extends AbstractQuickShareContent throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find: "+sharedId); } } + + private String getSiteName(NodeRef nodeRef) + { + NodeRef parent = nodeService.getPrimaryParent(nodeRef).getParentRef(); + while (parent != null && !nodeService.getType(parent).equals(SiteModel.TYPE_SITE)) + { + String parentName = (String) nodeService.getProperty(parent, ContentModel.PROP_NAME); + if (nodeService.getPrimaryParent(nodeRef) != null) + { + parent = nodeService.getPrimaryParent(parent).getParentRef(); + } + } + + if (parent == null) + { + return null; + } + + return nodeService.getProperty(parent, ContentModel.PROP_NAME).toString(); + } } \ No newline at end of file diff --git a/source/test-java/org/alfresco/repo/web/scripts/quickshare/QuickShareRestApiTest.java b/source/test-java/org/alfresco/repo/web/scripts/quickshare/QuickShareRestApiTest.java index d647bef2f2..7b43bc3d41 100644 --- a/source/test-java/org/alfresco/repo/web/scripts/quickshare/QuickShareRestApiTest.java +++ b/source/test-java/org/alfresco/repo/web/scripts/quickshare/QuickShareRestApiTest.java @@ -33,8 +33,11 @@ import org.alfresco.repo.content.transform.AbstractContentTransformerTest; import org.alfresco.repo.content.transform.ContentTransformer; import org.alfresco.repo.content.transform.magick.ImageTransformationOptions; import org.alfresco.repo.model.Repository; +import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.site.SiteModel; import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.repo.web.scripts.BaseWebScriptTest; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentService; @@ -45,6 +48,9 @@ import org.alfresco.service.cmr.security.AccessStatus; 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.site.SiteInfo; +import org.alfresco.service.cmr.site.SiteService; +import org.alfresco.service.cmr.site.SiteVisibility; import org.alfresco.service.namespace.QName; import org.alfresco.util.PropertyMap; import org.json.JSONArray; @@ -78,6 +84,8 @@ public class QuickShareRestApiTest extends BaseWebScriptTest private final static String SHARE_CONTENT_URL = "/api/internal/shared/node/{shared_id}/content"; private final static String SHARE_CONTENT_THUMBNAIL_URL = "/api/internal/shared/node/{shared_id}/content/thumbnails/{thumbnailname}?c=force"; + private static final String SITES_URL = "/api/sites"; + // note: node_ref_3 => three segments, eg. store_protocol/store_id/node_uuid private final static String AUTH_METADATA_URL = "/api/node/{node_ref_3}/metadata"; private final static String AUTH_CONTENT_URL = "/api/node/{node_ref_3}/content"; @@ -90,12 +98,15 @@ public class QuickShareRestApiTest extends BaseWebScriptTest private static byte[] TEST_CONTENT = null; private final static String TEST_MIMETYPE_JPEG = MimetypeMap.MIMETYPE_IMAGE_JPEG; private final static String TEST_MIMETYPE_PNG = MimetypeMap.MIMETYPE_IMAGE_PNG; + private static File quickFile = null; private MutableAuthenticationService authenticationService; + private AuthenticationComponent authenticationComponent; private NodeService nodeService; private PersonService personService; private PermissionService permissionService; private ContentService contentService; + private SiteService siteService; private Repository repositoryHelper; private RetryingTransactionHelper transactionHelper; @@ -106,10 +117,12 @@ public class QuickShareRestApiTest extends BaseWebScriptTest { super.setUp(); authenticationService = (MutableAuthenticationService) getServer().getApplicationContext().getBean("AuthenticationService"); + authenticationComponent = (AuthenticationComponent) getServer().getApplicationContext().getBean("AuthenticationComponent"); nodeService = (NodeService) getServer().getApplicationContext().getBean("NodeService"); contentService = (ContentService) getServer().getApplicationContext().getBean("ContentService"); personService = (PersonService) getServer().getApplicationContext().getBean("PersonService"); permissionService = (PermissionService) getServer().getApplicationContext().getBean("PermissionService"); + siteService = (SiteService) getServer().getApplicationContext().getBean("SiteService"); repositoryHelper = (Repository) getServer().getApplicationContext().getBean("repositoryHelper"); transactionHelper = (RetryingTransactionHelper)getServer().getApplicationContext().getBean("retryingTransactionHelper"); @@ -120,33 +133,12 @@ public class QuickShareRestApiTest extends BaseWebScriptTest AuthenticationUtil.setFullyAuthenticatedUser(USER_ONE); - testNode = transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() - { - public NodeRef execute() throws Throwable - { - // no pun intended - File quickFile = AbstractContentTransformerTest.loadQuickTestFile("jpg"); - - - TEST_CONTENT = new byte[new Long(quickFile.length()).intValue()]; - - new FileInputStream(quickFile).read(TEST_CONTENT); - - Map props = new HashMap(1); - props.put(ContentModel.PROP_NAME, TEST_NAME); - userOneHome = repositoryHelper.getUserHome(personService.getPerson(USER_ONE)); - ChildAssociationRef result = nodeService.createNode(userOneHome, - ContentModel.ASSOC_CONTAINS, ContentModel.ASSOC_CONTAINS, - ContentModel.TYPE_CONTENT, props); - - NodeRef nodeRef = result.getChildRef(); - ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true); - writer.setMimetype(TEST_MIMETYPE_JPEG); - writer.putContent(quickFile); - - return nodeRef; - } - }); + userOneHome = repositoryHelper.getUserHome(personService.getPerson(USER_ONE)); + // no pun intended + quickFile = AbstractContentTransformerTest.loadQuickTestFile("jpg"); + TEST_CONTENT = new byte[new Long(quickFile.length()).intValue()]; + new FileInputStream(quickFile).read(TEST_CONTENT); + testNode = createTestFile(userOneHome, TEST_NAME, quickFile); AuthenticationUtil.setFullyAuthenticatedUser(USER_TWO); @@ -284,6 +276,40 @@ public class QuickShareRestApiTest extends BaseWebScriptTest rsp = sendRequest(new GetRequest(SHARE_CONTENT_THUMBNAIL_URL.replace("{shared_id}", sharedId).replace("{thumbnailname}", "doclib")), expectedStatusNotFound, USER_TWO); } + public void testUnshareContributer() throws UnsupportedEncodingException, IOException, JSONException + { + final int expectedStatusOK = 200; + final int expectedStatusForbidden = 403; + + authenticationComponent.setCurrentUser("admin"); + + SiteInfo siteInfo = createSite("site" + RUN_ID); + siteService.setMembership(siteInfo.getShortName(), USER_ONE, SiteModel.SITE_CONSUMER); + siteService.setMembership(siteInfo.getShortName(), USER_TWO, SiteModel.SITE_CONTRIBUTOR); + + NodeRef siteDocLib = siteService.getContainer(siteInfo.getShortName(), SiteService.DOCUMENT_LIBRARY); + NodeRef testFile = createTestFile(siteDocLib, "unshare-test" + RUN_ID, quickFile); + + String strTestNodeRef = testFile.toString().replace("://", "/"); + + authenticationComponent.setCurrentUser(USER_ONE); + + // share + Response rsp= sendRequest(new PostRequest(SHARE_URL.replace("{node_ref_3}", strTestNodeRef), "", APPLICATION_JSON), expectedStatusOK, USER_ONE); + JSONObject jsonRsp = new JSONObject(new JSONTokener(rsp.getContentAsString())); + String sharedId = jsonRsp.getString("sharedId"); + assertNotNull(sharedId); + + // unshare + authenticationComponent.setCurrentUser(USER_TWO); + rsp = sendRequest(new DeleteRequest(UNSHARE_URL.replace("{shared_id}", sharedId)), expectedStatusForbidden, USER_ONE); + authenticationComponent.setCurrentUser(USER_ONE); + rsp = sendRequest(new DeleteRequest(UNSHARE_URL.replace("{shared_id}", sharedId)), expectedStatusOK, USER_ONE); + + authenticationComponent.setCurrentUser("admin"); + deleteSite(siteInfo.getShortName()); + } + /** * This test verifies that copying a shared node does not across the shared aspect and it's associated properties. * @throws IOException @@ -351,4 +377,66 @@ public class QuickShareRestApiTest extends BaseWebScriptTest personService.deletePerson(userName); } } + + private NodeRef createTestFile(final NodeRef parent, final String name, final File quickFile) + { + return transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + public NodeRef execute() throws Throwable + { + Map props = new HashMap(1); + props.put(ContentModel.PROP_NAME, name); + ChildAssociationRef result = nodeService.createNode(parent, + ContentModel.ASSOC_CONTAINS, ContentModel.ASSOC_CONTAINS, + ContentModel.TYPE_CONTENT, props); + + NodeRef nodeRef = result.getChildRef(); + ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true); + writer.setMimetype(TEST_MIMETYPE_JPEG); + writer.putContent(quickFile); + + return nodeRef; + } + }); + } + + private SiteInfo createSite(final String shortName) + { + return transactionHelper.doInTransaction(new RetryingTransactionCallback() + { + @Override + public SiteInfo execute() throws Throwable + { + SiteInfo siteInfo = siteService.getSite(shortName); + if (siteInfo != null) + { + // Tidy up after failed earlier run + siteService.deleteSite(shortName); + } + + // Do the create + SiteInfo site = siteService.createSite("Testing", shortName, shortName, null, SiteVisibility.PUBLIC); + + // Ensure we have a doclib + siteService.createContainer(shortName, SiteService.DOCUMENT_LIBRARY, ContentModel.TYPE_FOLDER, null); + + // All done + return site; + } + }, false, true + ); + } + + private void deleteSite(final String shortName) + { + transactionHelper.doInTransaction(new RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + siteService.deleteSite(shortName); + return null; + } + }, false, true); + } }