diff --git a/source/java/org/alfresco/rest/api/impl/QuickShareLinksImpl.java b/source/java/org/alfresco/rest/api/impl/QuickShareLinksImpl.java index 9485273223..af19f2268d 100644 --- a/source/java/org/alfresco/rest/api/impl/QuickShareLinksImpl.java +++ b/source/java/org/alfresco/rest/api/impl/QuickShareLinksImpl.java @@ -128,16 +128,24 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean { checkEnabled(); - Pair pair = quickShareService.getTenantNodeRefFromSharedId(sharedId); - String networkTenantDomain = pair.getFirst(); - - return TenantUtil.runAsSystemTenant(new TenantUtil.TenantRunAsWork() + try { - public QuickShareLink doWork() throws Exception + Pair pair = quickShareService.getTenantNodeRefFromSharedId(sharedId); + String networkTenantDomain = pair.getFirst(); + + return TenantUtil.runAsSystemTenant(new TenantUtil.TenantRunAsWork() { - return getQuickShareInfo(sharedId); - } - }, networkTenantDomain); + public QuickShareLink doWork() throws Exception + { + return getQuickShareInfo(sharedId); + } + }, networkTenantDomain); + } + catch (InvalidSharedIdException ex) + { + logger.warn("Unable to find: " + sharedId); + throw new EntityNotFoundException("Unable to find: " + sharedId); + } } /** @@ -203,21 +211,21 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean checkEnabled(); checkValidShareId(sharedId); - NodeRef nodeRef = quickShareService.getTenantNodeRefFromSharedId(sharedId).getSecond(); - String currentUser = AuthenticationUtil.getFullyAuthenticatedUser(); - - // TODO site check - see ACE-XXX - //String siteName = getSiteName(nodeRef); - - String sharedBy = (String) nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDBY); - - if ((!currentUser.equals(sharedBy)) && (!authorityService.isAdminAuthority(currentUser))) - { - throw new PermissionDeniedException("Can't perform unshare action: " + sharedId); - } - try { + NodeRef nodeRef = quickShareService.getTenantNodeRefFromSharedId(sharedId).getSecond(); + String currentUser = AuthenticationUtil.getFullyAuthenticatedUser(); + + // TODO site check - see ACE-XXX + //String siteName = getSiteName(nodeRef); + + String sharedBy = (String) nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDBY); + + if ((!currentUser.equals(sharedBy)) && (!authorityService.isAdminAuthority(currentUser))) + { + throw new PermissionDeniedException("Can't perform unshare action: " + sharedId); + } + quickShareService.unshareContent(sharedId); } catch (InvalidSharedIdException ex) @@ -317,7 +325,7 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean try { - Map map = (Map) quickShareService.getMetaData(sharedId).get("item"); + Map map = (Map)quickShareService.getMetaData(sharedId).get("item"); NodeRef nodeRef = new NodeRef((String) map.get("nodeRef")); diff --git a/source/test-java/org/alfresco/rest/api/tests/SharedLinkApiTest.java b/source/test-java/org/alfresco/rest/api/tests/SharedLinkApiTest.java new file mode 100644 index 0000000000..33267dca44 --- /dev/null +++ b/source/test-java/org/alfresco/rest/api/tests/SharedLinkApiTest.java @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2005-2016 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.rest.api.tests; + +import org.alfresco.model.ContentModel; +import org.alfresco.model.ForumModel; +import org.alfresco.repo.content.ContentLimitProvider.SimpleFixedLimitProvider; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.node.archive.NodeArchiveService; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.rest.api.Nodes; +import org.alfresco.rest.api.QuickShareLinks; +import org.alfresco.rest.api.impl.QuickShareLinksImpl; +import org.alfresco.rest.api.model.NodeTarget; +import org.alfresco.rest.api.model.QuickShareLink; +import org.alfresco.rest.api.nodes.NodesEntityResource; +import org.alfresco.rest.api.quicksharelinks.QuickShareLinkEntityResource; +import org.alfresco.rest.api.tests.RepoService.TestNetwork; +import org.alfresco.rest.api.tests.RepoService.TestPerson; +import org.alfresco.rest.api.tests.RepoService.TestSite; +import org.alfresco.rest.api.tests.client.HttpResponse; +import org.alfresco.rest.api.tests.client.PublicApiClient.ExpectedPaging; +import org.alfresco.rest.api.tests.client.PublicApiClient.Paging; +import org.alfresco.rest.api.tests.client.PublicApiHttpClient.BinaryPayload; +import org.alfresco.rest.api.tests.client.RequestContext; +import org.alfresco.rest.api.tests.client.data.ContentInfo; +import org.alfresco.rest.api.tests.client.data.Document; +import org.alfresco.rest.api.tests.client.data.Folder; +import org.alfresco.rest.api.tests.client.data.Node; +import org.alfresco.rest.api.tests.client.data.PathInfo; +import org.alfresco.rest.api.tests.client.data.PathInfo.ElementInfo; +import org.alfresco.rest.api.tests.client.data.SiteRole; +import org.alfresco.rest.api.tests.client.data.UserInfo; +import org.alfresco.rest.api.tests.util.JacksonUtil; +import org.alfresco.rest.api.tests.util.MultiPartBuilder; +import org.alfresco.rest.api.tests.util.MultiPartBuilder.FileData; +import org.alfresco.rest.api.tests.util.MultiPartBuilder.MultiPartRequest; +import org.alfresco.rest.api.tests.util.RestApiUtil; +import org.alfresco.rest.framework.jacksonextensions.JacksonHelper; +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.security.MutableAuthenticationService; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.cmr.site.SiteVisibility; +import org.alfresco.util.TempFileProvider; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.Serializable; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.UUID; + +import static org.alfresco.rest.api.tests.util.RestApiUtil.parsePaging; +import static org.alfresco.rest.api.tests.util.RestApiUtil.toJsonAsStringNonNull; +import static org.junit.Assert.*; + +/** + * API tests for: + *
    + *
  • {@literal :/alfresco/api//public/alfresco/versions/1/shared-links}
  • + *
  • {@literal :/alfresco/api//public/alfresco/versions/1/shared-links/}
  • + *
+ * + * @author janv + */ +public class SharedLinkApiTest extends AbstractBaseApiTest +{ + private static final String URL_SHARED_LINKS = "shared-links"; + + private String user1; + private String user2; + private List users = new ArrayList<>(); + + protected MutableAuthenticationService authenticationService; + protected PersonService personService; + + private final String RUNID = System.currentTimeMillis()+""; + + + @Before + public void setup() throws Exception + { + authenticationService = applicationContext.getBean("authenticationService", MutableAuthenticationService.class); + personService = applicationContext.getBean("personService", PersonService.class); + + user1 = createUser("user1-" + RUNID); + user2 = createUser("user2-" + RUNID); + + // We just need to clean the on-premise-users, + // so the tests for the specific network would work. + users.add(user1); + users.add(user2); + } + + @After + public void tearDown() throws Exception + { + AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser(); + for (final String user : users) + { + transactionHelper.doInTransaction(new RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + if (personService.personExists(user)) + { + authenticationService.deleteAuthentication(user); + personService.deletePerson(user); + } + return null; + } + }); + } + users.clear(); + AuthenticationUtil.clearCurrentSecurityContext(); + } + + /** + * Tests shared links to file (content) + * + *

POST:

+ * {@literal :/alfresco/api//public/alfresco/versions/1/shared-links} + * + *

GET:

+ * {@literal :/alfresco/api//public/alfresco/versions/1/shared-links/} + * {@literal :/alfresco/api//public/alfresco/versions/1/shared-links//content} + * + *

DELETE:

+ * {@literal :/alfresco/api//public/alfresco/versions/1/shared-links/} + */ + @Test + public void testSharedLinkCreateGetDelete() throws Exception + { + // As user 1 ... + + AuthenticationUtil.setFullyAuthenticatedUser(user1); + + // create doc d1 + + String sharedFolderNodeId = getSharedNodeId(user1); + + String contentText = "The quick brown fox jumps over the lazy dog."; + + String docName1 = "content" + RUNID + "_1.txt"; + NodeRef d1Ref = repoService.createDocument(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, sharedFolderNodeId), + docName1, contentText); + String d1Id = d1Ref.getId(); + + // create doc d2 + + String myFolderNodeId = getMyNodeId(user1); + + String docName2 = "content" + RUNID + "_2.txt"; + NodeRef d2Ref = repoService.createDocument(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, myFolderNodeId), + docName2, contentText); + String d2Id = d2Ref.getId(); + + AuthenticationUtil.clearCurrentSecurityContext(); + + // As user 2 ... + + HttpResponse response = getSingle(NodesEntityResource.class, user2, d1Id, null, 200); + Node nodeResp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Node.class); + Date docModifiedAt = nodeResp.getModifiedAt(); + String docModifiedBy = nodeResp.getModifiedByUser().getId(); + + // create shared link + Map body = new HashMap<>(); + body.put("nodeId", d1Id); + + response = post(URL_SHARED_LINKS, user2, toJsonAsStringNonNull(body), 201); + QuickShareLink resp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), QuickShareLink.class); + + String sharedId = resp.getSharedId(); + assertNotNull(sharedId); + + assertEquals(d1Id, resp.getNodeId()); + assertEquals(docName1, resp.getName()); + assertEquals(docModifiedAt.getTime(), resp.getModifiedAt().getTime()); // ie. not changed + + assertEquals(user1+" "+user1, resp.getModifiedByUser().getDisplayName()); // ie. not user2 + assertEquals(user2+" "+user2, resp.getSharedByUser().getDisplayName()); + + // try to create again (same user) - should return previous shared id + response = post(URL_SHARED_LINKS, user2, toJsonAsStringNonNull(body), 201); + resp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), QuickShareLink.class); + + assertEquals(sharedId, resp.getSharedId()); + + + // unauth access to get shared link info + response = getSingle(QuickShareLinkEntityResource.class, null, sharedId, null, 200); + resp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), QuickShareLink.class); + + assertEquals(sharedId, resp.getSharedId()); + assertEquals(d1Id, resp.getNodeId()); + assertEquals(docName1, resp.getName()); + + + // unauth access to get shared link file content + response = getSingle(QuickShareLinkEntityResource.class, null, sharedId + "/content", null, 200); + + assertEquals(contentText, response.getResponse()); + assertEquals("attachment; filename=\"" + docName1 + "\"; filename*=UTF-8''" + docName1 + "", response.getHeaders().get("Content-Disposition")); + + + // TODO unauth access to get shared-link rendition content + + + // As user 2 ... + + // try to create again (different user, that has read permission) - should return previous shared id + response = post(URL_SHARED_LINKS, user1, toJsonAsStringNonNull(body), 201); + resp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), QuickShareLink.class); + + assertEquals(sharedId, resp.getSharedId()); + assertEquals(user2+" "+user2, resp.getSharedByUser().getDisplayName()); + + + // As user 1 ... + + // -ve test - user1 cannot delete shared link + delete(URL_SHARED_LINKS, user1, sharedId, 403); + + // As user 2 ... + + // delete shared link + delete(URL_SHARED_LINKS, user2, sharedId, 204); + + + + // -ve create tests + { + // -ve - create - unknown nodeId + body.put("nodeId", "dummy"); + post(URL_SHARED_LINKS, user1, toJsonAsStringNonNull(body), 404); + + // -ve - create - try to link to folder (ie. not a file) + String f1Id = createFolder(user1, myFolderNodeId, "f1 " + RUNID).getId(); + body.put("nodeId", f1Id); + post(URL_SHARED_LINKS, user1, toJsonAsStringNonNull(body), 404); + + // -ve test - cannot create if user does not have permission to read + body = new HashMap<>(); + body.put("nodeId", d2Id); + post(URL_SHARED_LINKS, user2, toJsonAsStringNonNull(body), 403); + } + + // -ve get tests + { + // try to get link that has been deleted (see above) + getSingle(QuickShareLinkEntityResource.class, null, sharedId, null, 404); + getSingle(QuickShareLinkEntityResource.class, null, sharedId + "/content", null, 404); + + // try to get non-existent link + getSingle(QuickShareLinkEntityResource.class, null, "dummy", null, 404); + getSingle(QuickShareLinkEntityResource.class, null, "dummy/content", null, 404); + } + + // -ve delete tests + { + // -ve test - delete - cannot delete non-existent link + delete(URL_SHARED_LINKS, user1, sharedId, 404); + + // -ve test - delete - cannot delete non-existent link + delete(URL_SHARED_LINKS, user1, "dummy", 404); + } + + + // TODO if and when these tests are optionally runnable via remote env then we could skip this part of the test + // (else need to verify test mechanism for enterprise admin via jmx ... etc) + + QuickShareLinksImpl quickShareLinks = applicationContext.getBean("quickShareLinks", QuickShareLinksImpl.class); + quickShareLinks.setEnabled(false); + + // -ve - disabled service tests + { + body.put("nodeId", "dummy"); + post(URL_SHARED_LINKS, user1, toJsonAsStringNonNull(body), 501); + + getSingle(QuickShareLinkEntityResource.class, null, "dummy", null, 501); + getSingle(QuickShareLinkEntityResource.class, null, "dummy/content", null, 501); + delete(URL_SHARED_LINKS, user1, "dummy", 501); + } + } + + @Override + public String getScope() + { + return "public"; + } +} diff --git a/source/test-java/org/alfresco/rest/api/tests/client/AuthenticatedHttp.java b/source/test-java/org/alfresco/rest/api/tests/client/AuthenticatedHttp.java index 38e1a7753f..2c3bec1d0d 100644 --- a/source/test-java/org/alfresco/rest/api/tests/client/AuthenticatedHttp.java +++ b/source/test-java/org/alfresco/rest/api/tests/client/AuthenticatedHttp.java @@ -131,7 +131,7 @@ public class AuthenticatedHttp extends AbstractHttp /** * Execute the given method, authenticated as the given user using Basic Authentication. * @param method method to execute - * @param userName name of user to authenticate + * @param userName name of user to authenticate (note: if null then attempts to run with no authentication - eq. Quick/Shared Link test) * @param callback called after http-call is executed. When callback returns, the * response stream is closed, so all respose-related operations should be done in the callback. Can be null. * @return result returned by the callback or null if no callback is given. @@ -141,9 +141,13 @@ public class AuthenticatedHttp extends AbstractHttp try { HttpState state = new HttpState(); - state.setCredentials( + + if (userName != null) + { + state.setCredentials( new AuthScope(null, AuthScope.ANY_PORT), new UsernamePasswordCredentials(userName, password)); + } httpProvider.getHttpClient().executeMethod(null, method, state); diff --git a/source/test-java/org/alfresco/rest/api/tests/client/UserAuthenticationDetailsProviderImpl.java b/source/test-java/org/alfresco/rest/api/tests/client/UserAuthenticationDetailsProviderImpl.java index eddcda958d..ec18670e8a 100644 --- a/source/test-java/org/alfresco/rest/api/tests/client/UserAuthenticationDetailsProviderImpl.java +++ b/source/test-java/org/alfresco/rest/api/tests/client/UserAuthenticationDetailsProviderImpl.java @@ -21,20 +21,26 @@ public class UserAuthenticationDetailsProviderImpl implements AuthenticationDeta public String getPasswordForUser(String userName) { - UserData user = userDataService.findUserByUserName(userName); - if(user != null) + if (userName != null) { - return user.getPassword(); + UserData user = userDataService.findUserByUserName(userName); + if (user != null) + { + return user.getPassword(); + } } return null; } public String getTicketForUser(String userName) { - UserData user = userDataService.findUserByUserName(userName); - if(user != null) + if (userName != null) { - return user.getTicket(); + UserData user = userDataService.findUserByUserName(userName); + if (user != null) + { + return user.getTicket(); + } } return null; } diff --git a/source/test-java/org/alfresco/rest/api/tests/client/data/Document.java b/source/test-java/org/alfresco/rest/api/tests/client/data/Document.java index c95be0e446..a72adacf39 100644 --- a/source/test-java/org/alfresco/rest/api/tests/client/data/Document.java +++ b/source/test-java/org/alfresco/rest/api/tests/client/data/Document.java @@ -28,31 +28,15 @@ import static org.junit.Assert.assertTrue; */ public class Document extends Node { - private ContentInfo contentInfo; - public Document() { super(); } - public ContentInfo getContent() - { - return contentInfo; - } - - public void setContent(ContentInfo contentInfo) - { - this.contentInfo = contentInfo; - } - @Override public void expected(Object o) { super.expected(o); assertTrue(o instanceof Document); - - Document other = (Document) o; - - contentInfo.expected(other.getContent()); } } diff --git a/source/test-java/org/alfresco/rest/api/tests/client/data/Node.java b/source/test-java/org/alfresco/rest/api/tests/client/data/Node.java index fc6f5039a3..e110ce6452 100644 --- a/source/test-java/org/alfresco/rest/api/tests/client/data/Node.java +++ b/source/test-java/org/alfresco/rest/api/tests/client/data/Node.java @@ -18,8 +18,6 @@ */ package org.alfresco.rest.api.tests.client.data; -import org.junit.Assert; - import java.util.Date; import java.util.List; import java.util.Map; @@ -56,6 +54,8 @@ public class Node protected Map properties; + protected ContentInfo contentInfo; + public Node() { } @@ -190,6 +190,16 @@ public class Node this.properties = properties; } + public void setContent(ContentInfo contentInfo) + { + this.contentInfo = contentInfo; + } + + public ContentInfo getContent() + { + return this.contentInfo; + } + public void expected(Object o) { Node other = (Node) o; @@ -276,8 +286,22 @@ public class Node AssertUtil.assertEquals("isFile", isFile, other.getIsFile()); AssertUtil.assertEquals("isLink", isLink, other.getIsLink()); - if (path != null) { + if (path != null) + { path.expected(other.getPath()); } + else + { + assertNull(other.getPath()); + } + + if (contentInfo != null) + { + contentInfo.expected(other.getContent()); + } + else + { + assertNull(other.getContent()); + } } } \ No newline at end of file