blob: fbc234758113dba59270cc95fd66f059e73ef0fe [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.sling.jcr.jackrabbit.usermanager.it;
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 static org.junit.Assert.fail;
import static org.ops4j.pax.exam.CoreOptions.options;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import javax.inject.Inject;
import javax.jcr.AccessDeniedException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.jcr.security.Privilege;
import org.apache.jackrabbit.api.security.user.Group;
import org.apache.jackrabbit.api.security.user.User;
import org.apache.jackrabbit.api.security.user.UserManager;
import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
import org.apache.jackrabbit.oak.spi.security.user.UserConfiguration;
import org.apache.sling.jackrabbit.usermanager.AuthorizablePrivilegesInfo;
import org.apache.sling.jackrabbit.usermanager.AuthorizablePrivilegesInfo.PropertyUpdateTypes;
import org.apache.sling.jackrabbit.usermanager.ChangeUserPassword;
import org.apache.sling.jackrabbit.usermanager.CreateGroup;
import org.apache.sling.jackrabbit.usermanager.CreateUser;
import org.apache.sling.jackrabbit.usermanager.DeleteGroup;
import org.apache.sling.jackrabbit.usermanager.DeleteUser;
import org.apache.sling.jackrabbit.usermanager.UpdateGroup;
import org.apache.sling.jackrabbit.usermanager.UpdateUser;
import org.apache.sling.jcr.api.SlingRepository;
import org.apache.sling.jcr.base.util.AccessControlUtil;
import org.apache.sling.jcr.jackrabbit.accessmanager.DeleteAces;
import org.apache.sling.jcr.jackrabbit.accessmanager.ModifyAce;
import org.apache.sling.servlets.post.Modification;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
import org.ops4j.pax.exam.spi.reactors.PerClass;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Basic test of AuthorizablePrivilegesInfo component
*/
@RunWith(PaxExam.class)
@ExamReactorStrategy(PerClass.class)
public class AuthorizablePrivilegesInfoIT extends UserManagerTestSupport {
private static AtomicLong counter = new AtomicLong(0);
private final Logger logger = LoggerFactory.getLogger(getClass());
@Inject
protected BundleContext bundleContext;
@Inject
protected SlingRepository repository;
@Inject
private AuthorizablePrivilegesInfo privilegesInfo;
@Inject
private UserConfiguration userConfig;
@Inject
private CreateUser createUser;
@Inject
private CreateGroup createGroup;
@Inject
private UpdateUser updateUser;
@Inject
private UpdateGroup updateGroup;
@Inject
private DeleteUser deleteUser;
@Inject
private DeleteGroup deleteGroup;
@Inject
private ModifyAce modifyAce;
@Inject
private DeleteAces deleteAces;
@Inject
private ChangeUserPassword changeUserPassword;
@Rule
public TestName testName = new TestName();
protected Session adminSession;
protected User user1;
protected Session user1Session;
@Configuration
public Option[] configuration() {
return options(
baseConfiguration()
);
}
@Before
public void setup() throws Exception {
adminSession = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));
assertNotNull("Expected adminSession to not be null", adminSession);
user1 = createUser.createUser(adminSession, createUniqueName("user"), "testPwd", "testPwd",
Collections.emptyMap(), new ArrayList<Modification>());
assertNotNull("Expected user1 to not be null", user1);
if (adminSession.hasPendingChanges()) {
adminSession.save();
}
user1Session = repository.login(new SimpleCredentials(user1.getID(), "testPwd".toCharArray()));
assertNotNull("Expected user1Session to not be null", user1Session);
}
@After
public void teardown() {
try {
adminSession.refresh(false);
if (user1 != null) {
deleteUser.deleteUser(adminSession, user1.getID(), new ArrayList<>());
}
if (adminSession.hasPendingChanges()) {
adminSession.save();
}
} catch (RepositoryException e) {
logger.warn("Failed to delete user: " + e.getMessage(), e);
}
user1Session.logout();
adminSession.logout();
}
protected String createUniqueName(String prefix) {
return String.format("%s_%s%d", prefix, testName.getMethodName(), counter.incrementAndGet());
}
/**
* Checks whether the current user has been granted privileges
* to add a new user. Equivalent of: #canAddUser(Session, PropertyUpdateTypes.addProperty, PropertyUpdateTypes.addNestedProperty)
*/
@Test
public void canAddUser() throws Exception {
assertNotNull("Expected privilegesInfo to not be null", privilegesInfo);
User user2 = null;
try {
// initially user can't do the operations
assertFalse("Should not be allowed to add user",
privilegesInfo.canAddUser(user1Session));
String usersPath = userConfig.getParameters().getConfigValue("usersPath", (String)null);
assertNotNull("Users Path should not be null", usersPath);
assertTrue("Users Path should exist",
adminSession.itemExists(usersPath));
// grant user1 rights
Map<String, String> privileges = new HashMap<>();
privileges.put(String.format("privilege@%s", Privilege.JCR_READ), "granted");
privileges.put(String.format("privilege@%s", Privilege.JCR_READ_ACCESS_CONTROL), "granted");
privileges.put(String.format("privilege@%s", Privilege.JCR_MODIFY_ACCESS_CONTROL), "granted");
privileges.put(String.format("privilege@%s", PrivilegeConstants.REP_WRITE), "granted");
privileges.put(String.format("privilege@%s", PrivilegeConstants.REP_USER_MANAGEMENT), "granted");
modifyAce.modifyAce(adminSession, usersPath, user1.getID(),
privileges,
"first");
assertTrue("Should be allowed to add user",
privilegesInfo.canAddUser(user1Session));
// verify that the user can actually add the user
try {
Map<String, String> propMap = new HashMap<>();
propMap.put("prop1", "value1");
propMap.put("nested/prop2", "value2");
user2 = createUser.createUser(user1Session, createUniqueName("user"), "testPwd", "testPwd",
propMap, new ArrayList<Modification>());
assertNotNull("Expected user2 to not be null", user2);
} catch (RepositoryException e) {
logger.error("Did not expect RepositoryException when adding user: " + e.getMessage(), e);
fail("Did not expect RepositoryException when adding user: " + e.getMessage());
}
} finally {
if (user2 != null) {
deleteUser.deleteUser(adminSession, user2.getID(), new ArrayList<>());
}
}
}
/**
* Checks whether the current user has been granted privileges
* to add a new group. Equivalent of: #canAddGroup(Session, PropertyUpdateTypes.addProperty, PropertyUpdateTypes.addNestedProperty)
*/
@Test
public void canAddGroup() throws Exception {
assertNotNull("Expected privilegesInfo to not be null", privilegesInfo);
workaroundMissingGroupsPath();
Group group1 = null;
try {
// initially user can't do the operations
assertFalse("Should not be allowed to add group",
privilegesInfo.canAddGroup(user1Session));
String groupsPath = userConfig.getParameters().getConfigValue("groupsPath", (String)null);
assertNotNull("Groups Path should not be null", groupsPath);
assertTrue("Groups Path should exist",
adminSession.itemExists(groupsPath));
// grant user1 rights
Map<String, String> privileges = new HashMap<>();
privileges.put(String.format("privilege@%s", Privilege.JCR_READ), "granted");
privileges.put(String.format("privilege@%s", Privilege.JCR_READ_ACCESS_CONTROL), "granted");
privileges.put(String.format("privilege@%s", Privilege.JCR_MODIFY_ACCESS_CONTROL), "granted");
privileges.put(String.format("privilege@%s", PrivilegeConstants.REP_WRITE), "granted");
privileges.put(String.format("privilege@%s", PrivilegeConstants.REP_USER_MANAGEMENT), "granted");
modifyAce.modifyAce(adminSession, groupsPath, user1.getID(),
privileges,
"first");
assertTrue("Should be allowed to add group",
privilegesInfo.canAddGroup(user1Session));
// verify that the user can actually add the user
try {
Map<String, String> propMap = new HashMap<>();
propMap.put("prop1", "value1");
propMap.put("nested/prop2", "value2");
group1 = createGroup.createGroup(user1Session, createUniqueName("group"),
propMap, new ArrayList<Modification>());
assertNotNull("Expected group1 to not be null", group1);
} catch (RepositoryException e) {
logger.error("Did not expect RepositoryException when adding group: " + e.getMessage(), e);
fail("Did not expect RepositoryException when adding group: " + e.getMessage());
}
} finally {
if (group1 != null) {
deleteGroup.deleteGroup(user1Session, group1.getID(), new ArrayList<>());
}
}
}
/**
* The oak groupsPath appears to be missing until the first group is created.
* So create a group as the admin user to get it bootstrapped. This makes it
* possible for non-admin users to create groups without requiring extra access
* rights to the intermediate parents of the groupsPath folder.
*/
protected void workaroundMissingGroupsPath() throws RepositoryException {
String groupsPath = userConfig.getParameters().getConfigValue("groupsPath", (String)null);
assertNotNull("Groups Path should not be null", groupsPath);
if (!adminSession.itemExists(groupsPath)) {
// create a group and the remove it
Group tempGroup = createGroup.createGroup(adminSession, createUniqueName("group"),
Collections.emptyMap(), new ArrayList<Modification>());
deleteGroup.deleteGroup(adminSession, tempGroup.getID(), new ArrayList<>());
}
assertTrue("Groups Path should exist",
adminSession.itemExists(groupsPath));
}
/**
* Checks whether the current user has been granted privileges
* to update the properties of the specified user or group.
*/
@Test
public void canUpdateProperties() throws Exception {
assertNotNull("Expected privilegesInfo to not be null", privilegesInfo);
workaroundMissingGroupsPath();
User user2 = null;
Group group1 = null;
try {
// create a couple of test users
user2 = createUser.createUser(adminSession, createUniqueName("user"), "testPwd", "testPwd",
Collections.singletonMap("prop1", "value1"), new ArrayList<Modification>());
assertNotNull("Expected user2 to not be null", user2);
group1 = createGroup.createGroup(adminSession, createUniqueName("group"),
Collections.singletonMap("prop1", "value1"), new ArrayList<Modification>());
assertNotNull("Expected group1 to not be null", group1);
String [] principalIds = new String[] { user2.getID(), group1.getID() };
// initially user can't do the operation
for (String pid : principalIds) {
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid));
}
// start with only read rights
Map<String, String> privileges = new HashMap<>();
privileges.put(String.format("privilege@%s", Privilege.JCR_READ), "granted");
modifyAce.modifyAce(adminSession, user2.getPath(), user1.getID(),
privileges,
"first");
modifyAce.modifyAce(adminSession, group1.getPath(), user1.getID(),
privileges,
"first");
for (String pid : principalIds) {
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty, PropertyUpdateTypes.addNestedProperty, PropertyUpdateTypes.removeProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty, PropertyUpdateTypes.addNestedProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty, PropertyUpdateTypes.removeProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addNestedProperty, PropertyUpdateTypes.removeProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addNestedProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.removeProperty));
}
// + grant user management rights
privileges.put(String.format("privilege@%s", PrivilegeConstants.REP_USER_MANAGEMENT), "granted");
modifyAce.modifyAce(adminSession, user2.getPath(), user1.getID(),
privileges,
"first");
modifyAce.modifyAce(adminSession, group1.getPath(), user1.getID(),
privileges,
"first");
for (String pid : principalIds) {
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty, PropertyUpdateTypes.addNestedProperty, PropertyUpdateTypes.removeProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty, PropertyUpdateTypes.addNestedProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty, PropertyUpdateTypes.removeProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addNestedProperty, PropertyUpdateTypes.removeProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addNestedProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.removeProperty));
}
// grant rights to only remove properties
privileges.put(String.format("privilege@%s", PrivilegeConstants.REP_ADD_PROPERTIES), "none");
privileges.put(String.format("privilege@%s", PrivilegeConstants.REP_ALTER_PROPERTIES), "none");
privileges.put(String.format("privilege@%s", Privilege.JCR_ADD_CHILD_NODES), "none");
privileges.put(String.format("privilege@%s", PrivilegeConstants.REP_REMOVE_PROPERTIES), "granted");
modifyAce.modifyAce(adminSession, user2.getPath(), user1.getID(),
privileges,
"first");
modifyAce.modifyAce(adminSession, group1.getPath(), user1.getID(),
privileges,
"first");
for (String pid : principalIds) {
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty, PropertyUpdateTypes.addNestedProperty, PropertyUpdateTypes.removeProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty, PropertyUpdateTypes.addNestedProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty, PropertyUpdateTypes.removeProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addNestedProperty, PropertyUpdateTypes.removeProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addNestedProperty));
assertTrue("Should be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.removeProperty));
}
// verify that the user can actually delete property
Map<String, Object> propsMap = new HashMap<>();
propsMap.put("prop1@Delete", "value1");
try {
updateUser.updateUser(user1Session, user2.getID(), propsMap, new ArrayList<>());
updateGroup.updateGroup(user1Session, group1.getID(), propsMap, new ArrayList<>());
assertTrue("Expected pending changes in the jcr session", user1Session.hasPendingChanges());
user1Session.save();
} catch (RepositoryException e) {
logger.error("Did not expect RepositoryException when deleting property: " + e.getMessage(), e);
fail("Did not expect RepositoryException when deleting property: " + e.getMessage());
}
// verify that the user can not add nested property
propsMap = new HashMap<>();
propsMap.put("nested/prop2", "value2");
updateUser.updateUser(user1Session, user2.getID(), propsMap, new ArrayList<>());
updateGroup.updateGroup(user1Session, group1.getID(), propsMap, new ArrayList<>());
assertTrue("Expected pending changes in the jcr session", user1Session.hasPendingChanges());
try {
user1Session.save();
fail("Expected AccessDeniedException when adding nested property");
} catch (AccessDeniedException e) {
// expected
user1Session.refresh(false);
}
// grant rights to only alter (non-nested) properties
privileges.put(String.format("privilege@%s", PrivilegeConstants.REP_ADD_PROPERTIES), "granted");
privileges.put(String.format("privilege@%s", Privilege.JCR_ADD_CHILD_NODES), "none");
privileges.put(String.format("privilege@%s", PrivilegeConstants.REP_REMOVE_PROPERTIES), "none");
modifyAce.modifyAce(adminSession, user2.getPath(), user1.getID(),
privileges,
"first");
modifyAce.modifyAce(adminSession, group1.getPath(), user1.getID(),
privileges,
"first");
for (String pid : principalIds) {
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty, PropertyUpdateTypes.addNestedProperty, PropertyUpdateTypes.removeProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty, PropertyUpdateTypes.addNestedProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty, PropertyUpdateTypes.removeProperty));
assertTrue("Should be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addNestedProperty, PropertyUpdateTypes.removeProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addNestedProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.removeProperty));
}
// verify that the user can actually add property
propsMap = new HashMap<>();
propsMap.put("prop1", "value1");
try {
updateUser.updateUser(user1Session, user2.getID(), propsMap, new ArrayList<>());
updateGroup.updateGroup(user1Session, group1.getID(), propsMap, new ArrayList<>());
assertTrue("Expected pending changes in the jcr session", user1Session.hasPendingChanges());
user1Session.save();
} catch (RepositoryException e) {
logger.error("Did not expect RepositoryException when adding property: " + e.getMessage(), e);
fail("Did not expect RepositoryException when adding property: " + e.getMessage());
}
// verify that the user can not add nested property
propsMap.put("nested/prop2", "value2");
updateUser.updateUser(user1Session, user2.getID(), propsMap, new ArrayList<>());
updateGroup.updateGroup(user1Session, group1.getID(), propsMap, new ArrayList<>());
assertTrue("Expected pending changes in the jcr session", user1Session.hasPendingChanges());
try {
user1Session.save();
fail("Expected AccessDeniedException when adding nested property");
} catch (AccessDeniedException e) {
// expected
user1Session.refresh(false);
}
// grant rights to alter (non-nested or nested) properties
privileges.put(String.format("privilege@%s", PrivilegeConstants.REP_ADD_PROPERTIES), "granted");
privileges.put(String.format("privilege@%s", PrivilegeConstants.REP_ALTER_PROPERTIES), "granted");
privileges.put(String.format("privilege@%s", Privilege.JCR_ADD_CHILD_NODES), "granted");
privileges.put(String.format("privilege@%s", PrivilegeConstants.REP_REMOVE_PROPERTIES), "none");
modifyAce.modifyAce(adminSession, user2.getPath(), user1.getID(),
privileges,
"first");
modifyAce.modifyAce(adminSession, group1.getPath(), user1.getID(),
privileges,
"first");
for (String pid : principalIds) {
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty, PropertyUpdateTypes.addNestedProperty, PropertyUpdateTypes.removeProperty));
assertTrue("Should be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty, PropertyUpdateTypes.addNestedProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty, PropertyUpdateTypes.removeProperty));
assertTrue("Should be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addNestedProperty, PropertyUpdateTypes.removeProperty));
assertTrue("Should be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addNestedProperty));
assertFalse("Should not be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.removeProperty));
}
// verify that the user can actually add property and nested property
propsMap = new HashMap<>();
propsMap.put("prop1", "value1");
propsMap.put("nested/prop2", "value2");
try {
updateUser.updateUser(user1Session, user2.getID(), propsMap, new ArrayList<>());
updateGroup.updateGroup(user1Session, group1.getID(), propsMap, new ArrayList<>());
assertTrue("Expected pending changes in the jcr session", user1Session.hasPendingChanges());
user1Session.save();
} catch (RepositoryException e) {
logger.error("Did not expect RepositoryException when adding properties: " + e.getMessage(), e);
fail("Did not expect RepositoryException when adding properties: " + e.getMessage());
}
// grant rights to alter (non-nested or nested) properties and remove properties
privileges.put(String.format("privilege@%s", PrivilegeConstants.REP_ADD_PROPERTIES), "granted");
privileges.put(String.format("privilege@%s", PrivilegeConstants.REP_ALTER_PROPERTIES), "granted");
privileges.put(String.format("privilege@%s", Privilege.JCR_ADD_CHILD_NODES), "granted");
privileges.put(String.format("privilege@%s", PrivilegeConstants.REP_REMOVE_PROPERTIES), "granted");
modifyAce.modifyAce(adminSession, user2.getPath(), user1.getID(),
privileges,
"first");
modifyAce.modifyAce(adminSession, group1.getPath(), user1.getID(),
privileges,
"first");
for (String pid : principalIds) {
assertTrue("Should be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid));
assertTrue("Should be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty, PropertyUpdateTypes.addNestedProperty, PropertyUpdateTypes.removeProperty));
assertTrue("Should be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty, PropertyUpdateTypes.addNestedProperty));
assertTrue("Should be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty, PropertyUpdateTypes.removeProperty));
assertTrue("Should be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addProperty));
assertTrue("Should be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addNestedProperty, PropertyUpdateTypes.removeProperty));
assertTrue("Should be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.addNestedProperty));
assertTrue("Should be allowed to update properties for: " + pid,
privilegesInfo.canUpdateProperties(user1Session, pid, PropertyUpdateTypes.removeProperty));
}
// verify that the user can actually add property and nested property
propsMap = new HashMap<>();
propsMap.put("prop3", "value3");
propsMap.put("nested/prop4", "value4");
propsMap.put("prop1@Delete", "value1");
propsMap.put("nested/prop2@Delete", "value1");
try {
updateUser.updateUser(user1Session, user2.getID(), propsMap, new ArrayList<>());
updateGroup.updateGroup(user1Session, group1.getID(), propsMap, new ArrayList<>());
assertTrue("Expected pending changes in the jcr session", user1Session.hasPendingChanges());
user1Session.save();
} catch (RepositoryException e) {
logger.error("Did not expect RepositoryException when adding or deleting properties: " + e.getMessage(), e);
fail("Did not expect RepositoryException when adding or deleting properties: " + e.getMessage());
}
} finally {
if (user2 != null) {
deleteUser.deleteUser(adminSession, user2.getID(), new ArrayList<>());
}
}
}
/**
* Checks whether the current user has been granted privileges
* to remove the specified user or group.
*/
@Test
public void canRemove() throws Exception {
assertNotNull("Expected privilegesInfo to not be null", privilegesInfo);
workaroundMissingGroupsPath();
User user2 = null;
Group group1 = null;
try {
user2 = createUser.createUser(adminSession, createUniqueName("user"), "testPwd", "testPwd",
Collections.singletonMap("prop1", "value1"), new ArrayList<Modification>());
assertNotNull("Expected user2 to not be null", user2);
group1 = createGroup.createGroup(adminSession, createUniqueName("group"),
Collections.singletonMap("prop1", "value1"), new ArrayList<Modification>());
assertNotNull("Expected group1 to not be null", group1);
// initially user can't do the operations
assertFalse("Should not be allowed to remove user",
privilegesInfo.canRemove(user1Session, user2.getID()));
assertFalse("Should not be allowed to remove group",
privilegesInfo.canRemove(user1Session, group1.getID()));
// grant user1 rights to user2 profile
Map<String, String> privileges = new HashMap<>();
privileges.put(String.format("privilege@%s", Privilege.JCR_READ), "granted");
modifyAce.modifyAce(adminSession, user2.getPath(), user1.getID(),
privileges,
"first");
modifyAce.modifyAce(adminSession, group1.getPath(), user1.getID(),
privileges,
"first");
assertFalse("Should not be allowed to remove user",
privilegesInfo.canRemove(user1Session, user2.getID()));
assertFalse("Should not be allowed to remove group",
privilegesInfo.canRemove(user1Session, group1.getID()));
privileges.put(String.format("privilege@%s", PrivilegeConstants.REP_USER_MANAGEMENT), "granted");
modifyAce.modifyAce(adminSession, user2.getPath(), user1.getID(),
privileges,
"first");
modifyAce.modifyAce(adminSession, group1.getPath(), user1.getID(),
privileges,
"first");
assertTrue("Should be allowed to remove user",
privilegesInfo.canRemove(user1Session, user2.getID()));
assertTrue("Should be allowed to remove group",
privilegesInfo.canRemove(user1Session, group1.getID()));
// verify that the user can actually delete the user
String user2Id = user2.getID();
deleteUser.deleteUser(user1Session, user2Id, new ArrayList<>());
user2 = null;
// verify the user is no longer there
UserManager um = AccessControlUtil.getUserManager(user1Session);
assertNull("Expected user to be gone: " + user2Id, um.getAuthorizable(user2Id));
// verify that the user can actually delete the group
String group1Id = group1.getID();
deleteGroup.deleteGroup(user1Session, group1Id, new ArrayList<>());
group1 = null;
assertNull("Expected group to be gone: " + group1Id, um.getAuthorizable(group1Id));
} finally {
if (user2 != null) {
deleteUser.deleteUser(adminSession, user2.getID(), new ArrayList<>());
}
if (group1 != null) {
deleteGroup.deleteGroup(adminSession, group1.getID(), new ArrayList<>());
}
}
}
/**
* Checks whether the current user has been granted privileges
* to update the membership of the specified group.
*/
@Test
public void canUpdateGroupMembers() throws Exception {
assertNotNull("Expected privilegesInfo to not be null", privilegesInfo);
workaroundMissingGroupsPath();
Group group1 = null;
try {
group1 = createGroup.createGroup(adminSession, createUniqueName("group"),
Collections.singletonMap("prop1", "value1"), new ArrayList<Modification>());
assertNotNull("Expected group1 to not be null", group1);
// initially user can't do the operations
assertFalse("Should not be allowed to update group members",
privilegesInfo.canUpdateGroupMembers(user1Session, group1.getID()));
// grant user1 rights to group1 profile
Map<String, String> privileges = new HashMap<>();
privileges.put(String.format("privilege@%s", Privilege.JCR_READ), "granted");
modifyAce.modifyAce(adminSession, group1.getPath(), user1.getID(),
privileges,
"first");
assertFalse("Should not be allowed to update group members",
privilegesInfo.canUpdateGroupMembers(user1Session, group1.getID()));
privileges.put(String.format("privilege@%s", PrivilegeConstants.REP_USER_MANAGEMENT), "granted");
modifyAce.modifyAce(adminSession, group1.getPath(), user1.getID(),
privileges,
"first");
assertTrue("Should be allowed to update group members",
privilegesInfo.canUpdateGroupMembers(user1Session, group1.getID()));
// verify that the user can actually change the group members
try {
Map<String, Object> propsMap = new HashMap<>();
propsMap.put(":member", user1.getID());
updateGroup.updateGroup(user1Session, group1.getID(), propsMap, new ArrayList<>());
assertTrue("Expected pending changes in the jcr session", user1Session.hasPendingChanges());
user1Session.save();
} catch (RepositoryException e) {
logger.error("Did not expect RepositoryException when adding member to group: " + e.getMessage(), e);
fail("Did not expect RepositoryException when adding member to group: " + e.getMessage());
}
} finally {
if (group1 != null) {
deleteGroup.deleteGroup(adminSession, group1.getID(), new ArrayList<>());
}
}
}
protected void configMinimumUserPrivileges(User user) throws RepositoryException {
//change the ACE for the user home folder to the minimum privileges
// and without rep:userManagement
deleteAces.deleteAces(adminSession, user.getPath(), new String[] {user.getID()});
Map<String, String> privileges = new HashMap<>();
privileges.put(String.format("privilege@%s", Privilege.JCR_READ), "granted");
privileges.put(String.format("privilege@%s", PrivilegeConstants.REP_ALTER_PROPERTIES), "granted");
modifyAce.modifyAce(adminSession, user.getPath(), user.getID(),
privileges,
"first");
if (adminSession.hasPendingChanges()) {
adminSession.save();
}
}
/**
* SLING-9814 Checks whether the current user has been granted privileges
* to disable a user.
*/
@Test
public void canDisableUser() throws Exception {
assertNotNull("Expected privilegesInfo to not be null", privilegesInfo);
User user2 = null;
try {
// setup the user privileges
configMinimumUserPrivileges(user1);
// create another test user
user2 = createUser.createUser(adminSession, createUniqueName("user"), "testPwd", "testPwd",
Collections.singletonMap("prop1", "value1"), new ArrayList<Modification>());
assertNotNull("Expected user2 to not be null", user2);
// setup the user privileges
configMinimumUserPrivileges(user2);
// initially user can't do the operations
assertFalse("Should not be allowed to disable yourself",
privilegesInfo.canDisable(user1Session, user1.getID()));
assertFalse("Should not be allowed to disable user",
privilegesInfo.canDisable(user1Session, user2.getID()));
// grant user1 rights to user2 profile
Map<String, String> privileges = new HashMap<>();
privileges.put(String.format("privilege@%s", Privilege.JCR_READ), "granted");
privileges.put(String.format("privilege@%s", PrivilegeConstants.REP_USER_MANAGEMENT), "granted");
modifyAce.modifyAce(adminSession, user2.getPath(), user1.getID(),
privileges,
"first");
assertTrue("Should be allowed to disable user",
privilegesInfo.canDisable(user1Session, user2.getID()));
// verify that the user can actually disable the other user
Map<String, Object> propsMap = new HashMap<>();
propsMap.put(":disabled", "true");
propsMap.put(":disabledReason", "Just a test");
try {
updateUser.updateUser(user1Session, user2.getID(), propsMap, new ArrayList<>());
assertTrue("Expected pending changes in the jcr session", user1Session.hasPendingChanges());
user1Session.save();
} catch (RepositoryException e) {
logger.error("Did not expect RepositoryException when disabling the user: " + e.getMessage(), e);
fail("Did not expect RepositoryException when disabling the user: " + e.getMessage());
}
} finally {
if (user2 != null) {
deleteUser.deleteUser(adminSession, user2.getID(), new ArrayList<>());
}
}
}
/**
* SLING-9814 Checks whether the current user has been granted privileges
* to change a user's password.
*/
@Test
public void canChangePassword() throws Exception {
assertNotNull("Expected privilegesInfo to not be null", privilegesInfo);
User user2 = null;
try {
// create another test user
user2 = createUser.createUser(adminSession, createUniqueName("user"), "testPwd", "testPwd",
Collections.singletonMap("prop1", "value1"), new ArrayList<Modification>());
assertNotNull("Expected user2 to not be null", user2);
// initially user can't do the operations
assertFalse("Should not be allowed to change the user password",
privilegesInfo.canChangePassword(user1Session, user2.getID()));
// grant user1 rights to user2 profile
Map<String, String> privileges = new HashMap<>();
privileges.put(String.format("privilege@%s", Privilege.JCR_READ), "granted");
privileges.put(String.format("privilege@%s", PrivilegeConstants.REP_USER_MANAGEMENT), "granted");
modifyAce.modifyAce(adminSession, user2.getPath(), user1.getID(),
privileges,
"first");
assertTrue("Should be allowed to change the user password user",
privilegesInfo.canChangePassword(user1Session, user2.getID()));
// verify that the user can actually change the password of the other user
try {
changeUserPassword.changePassword(user1Session, user2.getID(), "testPwd", "newPassword", "newPassword", new ArrayList<>());
assertTrue("Expected pending changes in the jcr session", user1Session.hasPendingChanges());
user1Session.save();
} catch (RepositoryException e) {
logger.error("Did not expect RepositoryException when changing the user password: " + e.getMessage(), e);
fail("Did not expect RepositoryException when changing the user password: " + e.getMessage());
}
} finally {
if (user2 != null) {
deleteUser.deleteUser(adminSession, user2.getID(), new ArrayList<>());
}
}
}
/**
* SLING-9814 Checks whether the current user has been granted privileges
* to change the anonymous user's password.
*/
@Test
public void cannotChangePassword_for_anonymous() throws Exception {
assertNotNull("Expected privilegesInfo to not be null", privilegesInfo);
// anonymous user has no password to change
assertFalse("Should not be allowed to change the user password",
privilegesInfo.canChangePassword(user1Session, "anonymous"));
assertFalse("Should not be allowed to change the user password",
privilegesInfo.canChangePassword(adminSession, "anonymous"));
}
/**
* SLING-9814 Checks whether the current user has been granted privileges
* to change the anonymous user's password.
*/
@Test
public void cannotChangePassword_for_service_user() throws Exception {
assertNotNull("Expected privilegesInfo to not be null", privilegesInfo);
// service user has no password to change
assertFalse("Should not be allowed to change the user password",
privilegesInfo.canChangePassword(user1Session, "sling-jcr-usermanager"));
assertFalse("Should not be allowed to change the user password",
privilegesInfo.canChangePassword(adminSession, "sling-jcr-usermanager"));
}
}