/*
* (C) Copyright 2006-2016 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Nuxeo - initial API and implementation
*/
package org.nuxeo.ecm.platform.userworkspace.core.tests;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.security.Principal;
import java.util.Arrays;
import javax.inject.Inject;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.DocumentSecurityException;
import org.nuxeo.ecm.core.api.PathRef;
import org.nuxeo.ecm.core.api.pathsegment.PathSegmentService;
import org.nuxeo.ecm.core.api.security.ACE;
import org.nuxeo.ecm.core.api.security.ACL;
import org.nuxeo.ecm.core.api.security.ACP;
import org.nuxeo.ecm.core.api.security.SecurityConstants;
import org.nuxeo.ecm.core.api.security.impl.ACLImpl;
import org.nuxeo.ecm.core.api.security.impl.ACPImpl;
import org.nuxeo.ecm.core.test.CoreFeature;
import org.nuxeo.ecm.platform.test.PlatformFeature;
import org.nuxeo.ecm.platform.userworkspace.api.UserWorkspaceService;
import org.nuxeo.ecm.platform.userworkspace.core.service.AbstractUserWorkspaceImpl;
import org.nuxeo.runtime.test.runner.Deploy;
import org.nuxeo.runtime.test.runner.Features;
import org.nuxeo.runtime.test.runner.FeaturesRunner;
import org.nuxeo.runtime.test.runner.RuntimeHarness;
@RunWith(FeaturesRunner.class)
@Features(PlatformFeature.class)
@Deploy({ "org.nuxeo.ecm.platform.userworkspace.api", //
"org.nuxeo.ecm.platform.userworkspace.types", //
"org.nuxeo.ecm.platform.userworkspace.core", //
})
public class TestUserWorkspace {
@Inject
protected RuntimeHarness harness;
@Inject
protected CoreFeature coreFeature;
@Inject
protected CoreSession session;
@Inject
protected UserWorkspaceService uwm;
@Inject
protected PathSegmentService pathSegments;
@Test
public void testRestrictedAccess() throws Exception {
try (CoreSession userSession = coreFeature.openCoreSession("toto")) {
DocumentModel uw = uwm.getCurrentUserPersonalWorkspace(userSession, null);
assertNotNull(uw);
// check creator
String creator = (String) uw.getProperty("dublincore", "creator");
assertEquals("toto", creator);
// check write access
uw.setProperty("dublibore", "description", "Toto's workspace");
userSession.saveDocument(uw);
userSession.save();
}
}
@Test
public void testMultiDomains() throws Exception {
ACE ace = new ACE("Everyone", "Read", true);
ACL acl = new ACLImpl();
acl.add(ace);
ACP acp = new ACPImpl();
acp.addACL(acl);
DocumentModel ws1 = session.createDocumentModel("/default-domain/workspaces", "ws1", "Workspace");
ws1 = session.createDocument(ws1);
ws1.setACP(acp, true);
ws1 = session.saveDocument(ws1);
DocumentModel alternate = session.createDocumentModel("/", "alternate-domain", "Domain");
alternate = session.createDocument(alternate);
DocumentModel ws2 = session.createDocumentModel("/alternate-domain/workspaces", "ws2", "Workspace");
ws2 = session.createDocument(ws2);
ws2.setACP(acp, true);
ws2 = session.saveDocument(ws2);
session.save();
try (CoreSession userSession = coreFeature.openCoreSession("toto")) {
// access from root
DocumentModel context = userSession.getRootDocument();
DocumentModel uw = uwm.getCurrentUserPersonalWorkspace(userSession, null);
assertNotNull(uw);
assertTrue(uw.getPathAsString().startsWith("/default-domain"));
// access form default domain
context = userSession.getDocument(ws1.getRef());
uw = uwm.getCurrentUserPersonalWorkspace(userSession, context);
assertNotNull(uw);
assertTrue(uw.getPathAsString().startsWith("/default-domain"));
// access form alternate domain
context = userSession.getDocument(ws2.getRef());
uw = uwm.getCurrentUserPersonalWorkspace(userSession, context);
assertNotNull(uw);
assertTrue(uw.getPathAsString(), uw.getPathAsString().startsWith("/default-domain"));
// now delete the default-domain
session.removeDocument(new PathRef("/default-domain"));
session.save();
userSession.save();
uw = uwm.getCurrentUserPersonalWorkspace(userSession, context);
assertNotNull(uw);
assertTrue(uw.getPathAsString().startsWith("/alternate-domain"));
}
}
@Test
public void testAnotherUserWorkspaceFinder() {
DocumentModel context = session.getRootDocument();
DocumentModel uw = uwm.getCurrentUserPersonalWorkspace("user1", context);
session.save();
assertNotNull(uw);
String user1WorkspacePath = uw.getPathAsString();
assertTrue(user1WorkspacePath.contains("user1"));
session.save();
try (CoreSession userSession = coreFeature.openCoreSession("user2")) {
context = userSession.getRootDocument();
try {
// Assert that it throws
uwm.getCurrentUserPersonalWorkspace("user1", context);
assertTrue("user2 is not allow to read user1 workspace", false);
} catch (DocumentSecurityException e) {
// Nothing to do
}
uw = uwm.getUserPersonalWorkspace("user1", context);
assertNotNull(uw);
assertTrue(uw.getPathAsString().contains("user1"));
assertEquals(user1WorkspacePath, uw.getPathAsString());
assertNull("Document is correctly detached", uw.getSessionId());
}
}
@Test
public void testPathSegmentMapping() {
DocumentModel context = session.getRootDocument();
// Automatically create the user workspace
DocumentModel uw = uwm.getUserPersonalWorkspace("AC/DC", context);
assertNotNull(uw);
// Check the document name was mapped
assertEquals(uw.getPath().lastSegment(), "AC~2fDC");
}
@Test
public void testWorkspaceNameCollision() {
try (CoreSession userSession = coreFeature.openCoreSession(alongname("user1"))) {
DocumentModel uw = uwm.getCurrentUserPersonalWorkspace(userSession, userSession.getRootDocument());
assertNotNull(uw);
}
try (CoreSession userSession = coreFeature.openCoreSession(alongname("user2"))) {
DocumentModel uw = uwm.getCurrentUserPersonalWorkspace(userSession, userSession.getRootDocument());
assertNotNull(uw);
}
}
String alongname(String name) {
return StringUtils.repeat("a", pathSegments.getMaxSize()).concat(name);
}
@Test
public void testUserWorkspaceFinderCompat() {
DocumentModel context = session.getRootDocument();
// Manually create the user workspace as if the old max size still stands
DocumentModel user1W = uwm.getCurrentUserPersonalWorkspace("user1", context);
String parentPath = user1W.getPathAsString().replace("/user1", "");
DocumentModel uw = session.createDocumentModel(parentPath, "John-Von-Verylonglastname", "Workspace");
uw = session.createDocument(uw);
ACP acp = new ACPImpl();
ACE grantEverything = new ACE("John Von Verylonglastname", SecurityConstants.EVERYTHING, true);
ACL acl = new ACLImpl();
acl.setACEs(new ACE[] { grantEverything });
acp.addACL(acl);
uw.setACP(acp, true);
assertTrue(uw.getPath().lastSegment().length() > pathSegments.getMaxSize());
session.save();
assertNotNull(uw);
String johnWorkspacePath = uw.getPathAsString();
assertTrue(johnWorkspacePath.endsWith("/John-Von-Verylonglastname"));
uw = uwm.getUserPersonalWorkspace("John Von Verylonglastname", context);
assertNotNull(uw);
// Check the user workspace with the old name format is retrieved
assertTrue(uw.getPathAsString().endsWith("/John-Von-Verylonglastname"));
assertEquals(johnWorkspacePath, uw.getPathAsString());
assertNull("Document is correctly detached", uw.getSessionId());
}
@Test
public void testUnrestrictedFinderCorrectlyCreateWorkspace() {
DocumentModel context = session.getRootDocument();
DocumentModel uw = uwm.getUserPersonalWorkspace("user1", context);
assertNotNull(uw);
String user1WorkspacePath = uw.getPathAsString();
session.save();
try (CoreSession userSession = coreFeature.openCoreSession("user1")) {
context = userSession.getRootDocument();
uw = uwm.getCurrentUserPersonalWorkspace(userSession, context);
assertNotNull(uw);
assertEquals(user1WorkspacePath, uw.getPathAsString());
}
}
@Test
public void testCandidateNames() {
expectCandidateNames("user", //
"user");
expectCandidateNames("Dr. John Doe", //
"Dr. John Doe", //
"Dr-John-Doe");
expectCandidateNames("user@example.com", //
"user~40example.com", //
"user-example-com");
expectCandidateNames("a/b@c~d?f&g", //
"a~2fb~40c~7ed~3ff~26g", //
"a-b-c-d-f-g");
// 23 chars
expectCandidateNames("useruseruseruseruseruse", //
"useruseruseruseruseruse");
// 24 chars
expectCandidateNames("useruseruseruseruseruser", //
"useruseruseruseruseruser", //
"useruseruseruser37fcb8c6");
// 26 chars
expectCandidateNames("useruseruseruseruseruserus", //
"useruseruseruseruseruserus", //
"useruseruseruseruseruser", //
"useruseruserusercc1f8605");
// 30 chars
expectCandidateNames("useruseruseruseruseruseruserus", //
"useruseruseruseruseruseruserus", //
"useruseruseruseruseruser", //
"useruseruseruserbe8cd76e", //
"useruseruseruseruserusbe8cd76e");
// 32 chars
expectCandidateNames("useruseruseruseruseruseruseruser", //
"useruseruseruseruseruseruseruser", //
"useruseruseruseruseruser", //
"useruseruseruser13980873", //
"useruseruseruseruseruseruserus", //
"useruseruseruseruserus13980873");
}
protected void expectCandidateNames(String username, String... expected) {
assertEquals(Arrays.asList(expected),
((AbstractUserWorkspaceImpl) uwm).getCandidateUserWorkspaceNames(username));
}
@Test
public void testIsUnderUserWorkspace() {
doTestIsUnderUserWorkspace("user1");
}
@Test
public void testIsUnderUserWorkspaceWithMangledName() {
doTestIsUnderUserWorkspace("user1@example.com");
}
protected void doTestIsUnderUserWorkspace(String username) {
DocumentModel foo = session.createDocumentModel("/", "foo" + username, "File");
foo = session.createDocument(foo);
ACP acp = new ACPImpl();
acp.addACE(ACL.LOCAL_ACL, new ACE(username, SecurityConstants.READ, true));
foo.setACP(acp, true);
session.save();
try (CoreSession userSession = coreFeature.openCoreSession(username)) {
Principal principal = userSession.getPrincipal();
DocumentModel uw = uwm.getCurrentUserPersonalWorkspace(userSession, userSession.getRootDocument());
DocumentModel bar = userSession.createDocumentModel(uw.getPathAsString(), "bar", "File");
bar = userSession.createDocument(bar);
userSession.save();
assertTrue(uwm.isUnderUserWorkspace(principal, null, uw));
assertTrue(uwm.isUnderUserWorkspace(principal, null, bar));
assertFalse(uwm.isUnderUserWorkspace(principal, null, userSession.getRootDocument()));
assertFalse(uwm.isUnderUserWorkspace(principal, null, userSession.getDocument(foo.getRef())));
}
}
}