blob: a6b5d019c2b3b7007ab907f4ed6aaed52104934e [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.jackrabbit.oak.jcr.security.authorization;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.jcr.AccessDeniedException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.query.Query;
import javax.jcr.security.Privilege;
import com.google.common.collect.Lists;
import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
import org.apache.jackrabbit.api.security.user.Authorizable;
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.commons.JcrUtils;
import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
import org.apache.jackrabbit.oak.spi.security.principal.PrincipalImpl;
import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
import org.apache.jackrabbit.util.Text;
import org.junit.Before;
import org.junit.Test;
/**
* Testing permission evaluation for user management operations.
*
* @since OAK 1.0 As of OAK user mgt related operations require a specific
* user management permission (unless the system in configured to behave like
* jackrabbit 2x).
*/
public class UserManagementTest extends AbstractEvaluationTest {
private final String userId = "testUser2";
private final String groupId = "testGroup2";
private List<String> authorizablesToRemove = Lists.newArrayList(userId, groupId);
@Override
protected void setUp() throws Exception {
super.setUp();
// setup default permissions
String authPath = "/rep:security/rep:authorizables";
AccessControlUtils.addAccessControlEntry(superuser, authPath, EveryonePrincipal.getInstance(), privilegesFromName(Privilege.JCR_READ), true);
superuser.save();
}
@Override
@Before
public void tearDown() throws Exception {
try {
testSession.refresh(false);
superuser.refresh(false);
UserManager userMgr = getUserManager(superuser);
for (String id : authorizablesToRemove) {
Authorizable a = userMgr.getAuthorizable(id);
if (a != null) {
a.remove();
}
}
superuser.save();
} finally {
super.tearDown();
}
}
private void createUser(String userId) throws Exception {
getUserManager(superuser).createUser(userId, "pw");
superuser.save();
testSession.refresh(false);
}
@Test
public void testCreateUserWithoutPermission() throws Exception {
UserManager testUserMgr = getUserManager(testSession);
// testSession has read-only access
try {
testUserMgr.createUser(userId, "pw");
testSession.save();
fail("Test session doesn't have sufficient permission -> creating user should fail.");
} catch (AccessDeniedException e) {
// success
}
// testSession has write permission but no user-mgt permission
// -> should still fail
modify("/", PrivilegeConstants.REP_WRITE, true);
try {
testUserMgr.createUser(userId, "pw");
testSession.save();
fail("Test session doesn't have sufficient permission -> creating user should fail.");
} catch (AccessDeniedException e) {
// success
}
}
@Test
public void testCreateUser() throws Exception {
UserManager testUserMgr = getUserManager(testSession);
modify("/", PrivilegeConstants.REP_USER_MANAGEMENT, true);
// creating user should succeed
testUserMgr.createUser(userId, "pw");
testSession.save();
}
@Test
public void testCreateUser2() throws Exception {
UserManager testUserMgr = getUserManager(testSession);
Privilege[] privs = privilegesFromNames(new String[]{PrivilegeConstants.REP_USER_MANAGEMENT, PrivilegeConstants.REP_WRITE});
allow("/", privs);
// creating user should succeed
testUserMgr.createUser(userId, "pw");
testSession.save();
}
@Test
public void testCreateGroup() throws Exception {
UserManager testUserMgr = getUserManager(testSession);
modify("/", PrivilegeConstants.REP_USER_MANAGEMENT, true);
// creating group should succeed
Group gr = testUserMgr.createGroup(groupId);
testSession.save();
}
@Test
public void testCreateGroup2() throws Exception {
UserManager testUserMgr = getUserManager(testSession);
Privilege[] privs = privilegesFromNames(new String[]{PrivilegeConstants.REP_USER_MANAGEMENT, PrivilegeConstants.REP_WRITE});
allow("/", privs);
// creating group should succeed
Group gr = testUserMgr.createGroup(groupId);
testSession.save();
}
@Test
public void testCreateWithoutReadAccess() throws Exception {
UserManager testUserMgr = getUserManager(testSession);
deny("/", privilegesFromName(PrivilegeConstants.JCR_READ));
allow("/", privilegesFromName(PrivilegeConstants.REP_USER_MANAGEMENT));
try {
Group gr = testUserMgr.createGroup(groupId);
testSession.save();
fail("Creating group without read-access on the folder node should fail");
} catch (AccessDeniedException e) {
// success
}
}
@Test
public void testCreateWithIntermediateReadDeny() throws Exception {
String path = UserConstants.DEFAULT_GROUP_PATH + "/a/b/c";
Node groupRoot = JcrUtils.getOrCreateByPath(path, UserConstants.NT_REP_AUTHORIZABLE_FOLDER, superuser);
superuser.save();
try {
deny(UserConstants.DEFAULT_GROUP_PATH, privilegesFromName(Privilege.JCR_READ));
Privilege[] privs = privilegesFromNames(new String[]{Privilege.JCR_READ, PrivilegeConstants.REP_USER_MANAGEMENT, PrivilegeConstants.REP_WRITE});
allow(path, privs);
Group gr = getUserManager(testSession).createGroup(groupId, new PrincipalImpl(groupId), "a/b/c");
testSession.save();
} finally {
superuser.refresh(false);
superuser.getNode(UserConstants.DEFAULT_GROUP_PATH + "/a").remove();
JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(acMgr, UserConstants.DEFAULT_GROUP_PATH);
if (acl != null) {
acMgr.removePolicy(UserConstants.DEFAULT_GROUP_PATH, acl);
}
superuser.save();
}
}
@Test
public void testCreateWithIntermediateReadDeny2() throws Exception {
String path = UserConstants.DEFAULT_GROUP_PATH + "/a";
JcrUtils.getOrCreateByPath(path, UserConstants.NT_REP_AUTHORIZABLE_FOLDER, superuser);
superuser.save();
try {
deny(UserConstants.DEFAULT_GROUP_PATH, privilegesFromName(Privilege.JCR_READ));
Privilege[] privs = privilegesFromNames(new String[]{Privilege.JCR_READ, PrivilegeConstants.REP_USER_MANAGEMENT, PrivilegeConstants.REP_WRITE});
allow(path, privs);
Group gr = getUserManager(testSession).createGroup(groupId, new PrincipalImpl(groupId), "a/b/c");
testSession.save();
} finally {
superuser.refresh(false);
superuser.getNode(UserConstants.DEFAULT_GROUP_PATH + "/a").remove();
JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(acMgr, UserConstants.DEFAULT_GROUP_PATH);
if (acl != null) {
acMgr.removePolicy(UserConstants.DEFAULT_GROUP_PATH, acl);
}
superuser.save();
}
}
@Test
public void testChangePasswordWithoutPermission() throws Exception {
createUser(userId);
UserManager testUserMgr = getUserManager(testSession);
User user = (User) testUserMgr.getAuthorizable(userId);
try {
user.changePassword("pw2");
testSession.save();
fail();
} catch (AccessDeniedException e) {
// success
}
}
@Test
public void testChangePasswordWithoutPermission2() throws Exception {
createUser(userId);
modify("/", PrivilegeConstants.REP_WRITE, true);
UserManager testUserMgr = getUserManager(testSession);
User user = (User) testUserMgr.getAuthorizable(userId);
try {
user.changePassword("pw2");
testSession.save();
fail();
} catch (AccessDeniedException e) {
// success
}
}
@Test
public void testChangePassword() throws Exception {
createUser(userId);
// after granting user-mgt privilege changing the pw must succeed.
modify("/", PrivilegeConstants.REP_USER_MANAGEMENT, true);
UserManager testUserMgr = getUserManager(testSession);
User user = (User) testUserMgr.getAuthorizable(userId);
user.changePassword("pw2");
testSession.save();
}
@Test
public void testDisableUserWithoutPermission() throws Exception {
createUser(userId);
UserManager testUserMgr = getUserManager(testSession);
User user = (User) testUserMgr.getAuthorizable(userId);
try {
user.disable("disabled!");
testSession.save();
fail();
} catch (AccessDeniedException e) {
// success
}
}
@Test
public void testDisableUserWithoutPermission2() throws Exception {
createUser(userId);
modify("/", PrivilegeConstants.REP_WRITE, true);
UserManager testUserMgr = getUserManager(testSession);
User user = (User) testUserMgr.getAuthorizable(userId);
try {
user.disable("disabled!");
testSession.save();
fail();
} catch (AccessDeniedException e) {
// success
}
}
@Test
public void testDisableUser() throws Exception {
createUser(userId);
// after granting user-mgt privilege changing the pw must succeed.
modify("/", PrivilegeConstants.REP_USER_MANAGEMENT, true);
UserManager testUserMgr = getUserManager(testSession);
User user = (User) testUserMgr.getAuthorizable(userId);
user.disable("disabled!");
testSession.save();
}
@Test
public void testRemoveUserWithoutPermission() throws Exception {
createUser(userId);
UserManager testUserMgr = getUserManager(testSession);
// testSession has read-only access
try {
Authorizable a = testUserMgr.getAuthorizable(userId);
a.remove();
testSession.save();
fail("Test session doesn't have sufficient permission to remove a user.");
} catch (AccessDeniedException e) {
// success
}
// testSession has write permission but no user-mgt permission
// -> should still fail
modify("/", PrivilegeConstants.REP_WRITE, true);
try {
Authorizable a = testUserMgr.getAuthorizable(userId);
a.remove();
testSession.save();
fail("Test session doesn't have sufficient permission to remove a user.");
} catch (AccessDeniedException e) {
// success
}
}
@Test
public void testRemoveUser() throws Exception {
createUser(userId);
// testSession has user-mgt permission -> removal should succeed.
modify("/", PrivilegeConstants.REP_USER_MANAGEMENT, true);
UserManager testUserMgr = getUserManager(testSession);
Authorizable a = testUserMgr.getAuthorizable(userId);
a.remove();
testSession.save();
}
@Test
public void testRemoveUser2() throws Exception {
createUser(userId);
// testSession has user-mgt permission -> removal should succeed.
Privilege[] privs = privilegesFromNames(new String[]{
PrivilegeConstants.REP_USER_MANAGEMENT,
PrivilegeConstants.REP_WRITE});
allow("/", privs);
UserManager testUserMgr = getUserManager(testSession);
Authorizable a = testUserMgr.getAuthorizable(userId);
a.remove();
testSession.save();
}
@Test
public void testChangeUserPropertiesWithoutPermission() throws Exception {
createUser(userId);
// testSession has read-only access
UserManager testUserMgr = getUserManager(testSession);
try {
Authorizable a = testUserMgr.getAuthorizable(userId);
a.setProperty("someProp", testSession.getValueFactory().createValue("value"));
testSession.save();
fail("Test session doesn't have sufficient permission to alter user properties.");
} catch (AccessDeniedException e) {
// success
}
}
@Test
public void testChangeUserPropertiesWithoutPermission2() throws Exception {
createUser(userId);
// testSession has read and user-mgt permission but lacks permission to
// alter regular properties
modify("/", PrivilegeConstants.REP_USER_MANAGEMENT, true);
UserManager testUserMgr = getUserManager(testSession);
try {
Authorizable a = testUserMgr.getAuthorizable(userId);
a.setProperty("someProp", testSession.getValueFactory().createValue("value"));
testSession.save();
fail("Test session doesn't have sufficient permission to alter user properties.");
} catch (AccessDeniedException e) {
// success
}
}
@Test
public void testChangeUserProperties() throws Exception {
createUser(userId);
// make sure user can create/modify/remove regular properties
modify("/", PrivilegeConstants.JCR_MODIFY_PROPERTIES, true);
UserManager testUserMgr = getUserManager(testSession);
Authorizable a = testUserMgr.getAuthorizable(userId);
a.setProperty("someProp", testSession.getValueFactory().createValue("value"));
testSession.save();
a.setProperty("someProperty", testSession.getValueFactory().createValue("modified"));
testSession.save();
a.removeProperty("someProperty");
testSession.save();
}
/**
* @see <a href="https://issues.apache.org/jira/browse/JCR-3412">JCR-3412 :
* UserManager.findAuthorizables() does not work, if session does not have
* read access to common root of all user and groups. </a>
*/
@Test
public void testFindAuthorizables() throws Exception {
String home = Text.getRelativeParent(UserConstants.DEFAULT_USER_PATH, 1);
deny(home, privilegesFromName(PrivilegeConstants.JCR_READ));
allow(getUserManager(superuser).getAuthorizable(testSession.getUserID()).getPath(), privilegesFromName(PrivilegeConstants.JCR_ALL));
UserManager testUserMgr = getUserManager(testSession);
Iterator<Authorizable> result = testUserMgr.findAuthorizables(UserConstants.REP_PRINCIPAL_NAME, null, UserManager.SEARCH_TYPE_USER);
Set<String> ids = new HashSet<String>();
while (result.hasNext()) {
ids.add(result.next().getID());
}
assertFalse(ids.isEmpty());
NodeIterator nodeIterator = testSession.getWorkspace().getQueryManager().createQuery("/jcr:root//element(*,rep:User)", Query.XPATH).execute().getNodes();
assertTrue(nodeIterator.hasNext());
while (nodeIterator.hasNext()) {
String userId = nodeIterator.nextNode().getProperty(UserConstants.REP_AUTHORIZABLE_ID).getString();
if (!ids.remove(userId)) {
fail("UserId " + userId + " missing in result set.");
}
}
assertTrue("Result mismatch", ids.isEmpty());
}
@Test
public void testGlobRestriction() throws Exception {
String groupHome = Text.getRelativeParent(UserConstants.DEFAULT_GROUP_PATH, 1);
Privilege[] privs = privilegesFromName(PrivilegeConstants.REP_USER_MANAGEMENT);
allow(groupHome, privs);
deny(groupHome, privs, createGlobRestriction("*/" + UserConstants.REP_MEMBERS));
UserManager testUserMgr = getUserManager(testSession);
// creating a new group must be allow
Group gr = testUserMgr.createGroup(groupId);
testSession.save();
// modifying group membership must be denied
try {
gr.addMember(testUserMgr.getAuthorizable(testSession.getUserID()));
testSession.save();
fail();
} catch (AccessDeniedException e) {
// success
} finally {
testSession.refresh(false);
}
}
}