blob: 6f285ffdb21eb81031bb6a7ddf54a6ddfb113c66 [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.security.user;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.Group;
import org.apache.jackrabbit.oak.AbstractSecurityTest;
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.ContentSession;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Root;
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
import org.apache.jackrabbit.oak.plugins.tree.TreeUtil;
import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
import org.apache.jackrabbit.oak.spi.commit.Validator;
import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants;
import org.apache.jackrabbit.oak.spi.security.authentication.SystemSubject;
import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import javax.jcr.RepositoryException;
import javax.security.auth.Subject;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class CacheValidatorProviderTest extends AbstractSecurityTest {
private Group testGroup;
private Authorizable[] authorizables;
@Override
public void before() throws Exception {
super.before();
testGroup = getUserManager(root).createGroup("testGroup_" + UUID.randomUUID());
root.commit();
authorizables = new Authorizable[] {getTestUser(), testGroup};
}
@Override
public void after() throws Exception {
try {
root.refresh();
if (testGroup != null) {
testGroup.remove();
root.commit();
}
} finally {
super.after();
}
}
private Tree getAuthorizableTree(@NotNull Authorizable authorizable) throws RepositoryException {
return root.getTree(authorizable.getPath());
}
private Tree getCache(@NotNull Authorizable authorizable) throws Exception {
try (ContentSession cs = Subject.doAs(SystemSubject.INSTANCE, (PrivilegedExceptionAction<ContentSession>) () -> login(null))) {
Root r = cs.getLatestRoot();
Tree n = r.getTree(authorizable.getPath());
Tree c = TreeUtil.getOrAddChild(n, CacheConstants.REP_CACHE, CacheConstants.NT_REP_CACHE);
c.setProperty(CacheConstants.REP_EXPIRATION, 1L, Type.LONG);
r.commit(CacheValidatorProvider.asCommitAttributes());
}
root.refresh();
return root.getTree(authorizable.getPath()).getChild(CacheConstants.REP_CACHE);
}
@Test
public void testCreateCacheByName() throws RepositoryException {
for (Authorizable a : authorizables) {
try {
Tree node = getAuthorizableTree(a);
TreeUtil.addChild(node, CacheConstants.REP_CACHE, JcrConstants.NT_UNSTRUCTURED);
root.commit();
fail("Creating rep:cache node below a user or group must fail.");
} catch (CommitFailedException e) {
assertTrue(e.isConstraintViolation());
assertEquals(34, e.getCode());
}
}
}
@Test
public void testCreateCacheByNodeType() throws RepositoryException {
for (Authorizable a : authorizables) {
try {
Tree node = getAuthorizableTree(a);
Tree cache = TreeUtil.addChild(node, "childNode", CacheConstants.NT_REP_CACHE);
cache.setProperty(CacheConstants.REP_EXPIRATION, 1L, Type.LONG);
root.commit();
fail("Creating node with nt rep:Cache below a user or group must fail.");
} catch (CommitFailedException e) {
assertTrue(e.isConstraintViolation());
assertEquals(34, e.getCode());
}
}
}
@Test
public void testChangePrimaryTypeUser() throws Exception {
for (Authorizable a : authorizables) {
try {
Tree node = getAuthorizableTree(a);
Tree cache = TreeUtil.addChild(node, "childNode", JcrConstants.NT_UNSTRUCTURED);
root.commit();
cache.setProperty(JCR_PRIMARYTYPE, CacheConstants.NT_REP_CACHE, Type.NAME);
cache.setProperty(CacheConstants.REP_EXPIRATION, 1L, Type.LONG);
root.commit();
fail("Changing primary type of residual node below an user/group to rep:Cache must fail.");
} catch (CommitFailedException e) {
assertTrue(e.isConstraintViolation());
assertEquals(34, e.getCode());
}
}
}
@Test
public void testCreateCacheWithCommitInfo() throws RepositoryException {
for (Authorizable a : authorizables) {
try {
Tree node = getAuthorizableTree(a);
Tree cache = TreeUtil.addChild(node, CacheConstants.REP_CACHE, CacheConstants.NT_REP_CACHE);
cache.setProperty(CacheConstants.REP_EXPIRATION, 1L, Type.LONG);
root.commit(CacheValidatorProvider.asCommitAttributes());
fail("Creating rep:cache node below a user or group must fail.");
} catch (CommitFailedException e) {
assertTrue(e.isConstraintViolation());
assertEquals(34, e.getCode());
}
}
}
@Test
public void testCreateCacheBelowProfile() throws Exception {
try {
Tree node = getAuthorizableTree(getTestUser());
Tree child = TreeUtil.addChild(node, "profile", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
TreeUtil.addChild(child, CacheConstants.REP_CACHE, CacheConstants.NT_REP_CACHE).setProperty(CacheConstants.REP_EXPIRATION, 23L, Type.LONG);
root.commit(CacheValidatorProvider.asCommitAttributes());
fail("Creating rep:cache node below a user or group must fail.");
} catch (CommitFailedException e) {
assertTrue(e.isConstraintViolation());
assertEquals(34, e.getCode());
}
}
@Test
public void testCreateCacheBelowPersistedProfile() throws Exception {
Tree node = getAuthorizableTree(getTestUser());
Tree child = TreeUtil.addChild(node, "profile", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
root.commit();
try {
TreeUtil.addChild(child, CacheConstants.REP_CACHE, CacheConstants.NT_REP_CACHE).setProperty(CacheConstants.REP_EXPIRATION, 23L, Type.LONG);
root.commit(CacheValidatorProvider.asCommitAttributes());
fail("Creating rep:cache node below a user or group must fail.");
} catch (CommitFailedException e) {
assertTrue(e.isConstraintViolation());
assertEquals(34, e.getCode());
}
}
@Test
public void testModifyCache() throws Exception {
List<PropertyState> props = new ArrayList<>();
props.add(PropertyStates.createProperty(CacheConstants.REP_EXPIRATION, 25));
props.add(PropertyStates.createProperty(CacheConstants.REP_GROUP_PRINCIPAL_NAMES, EveryonePrincipal.NAME));
props.add(PropertyStates.createProperty(JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED, Type.NAME));
props.add(PropertyStates.createProperty("residualProp", "anyvalue"));
Tree cache = getCache(getTestUser());
for (PropertyState prop : props) {
try {
cache.setProperty(prop);
root.commit(CacheValidatorProvider.asCommitAttributes());
fail("Modifying rep:cache node below a user or group must fail.");
} catch (CommitFailedException e) {
assertTrue(e.isConstraintViolation());
assertEquals(34, e.getCode());
} finally {
root.refresh();
}
}
}
@Test
public void testNestedCache() throws Exception {
Tree cache = getCache(getTestUser());
try {
Tree c = TreeUtil.getOrAddChild(cache, CacheConstants.REP_CACHE, CacheConstants.NT_REP_CACHE);
c.setProperty(CacheConstants.REP_EXPIRATION, 223L, Type.LONG);
root.commit(CacheValidatorProvider.asCommitAttributes());
fail("Creating nested cache must fail.");
} catch (CommitFailedException e) {
assertTrue(e.isConstraintViolation());
assertEquals(34, e.getCode());
}
}
@Test
public void testRemoveCache() throws Exception {
Tree cache = getCache(getTestUser());
cache.remove();
root.commit();
assertFalse(getAuthorizableTree(getTestUser()).hasChild(CacheConstants.REP_CACHE));
}
@Test
public void testCreateCacheOutsideOfAuthorizable() throws Exception {
Tree n = root.getTree(PathUtils.ROOT_PATH);
try {
Tree child = TreeUtil.addChild(n, CacheConstants.REP_CACHE, CacheConstants.NT_REP_CACHE);
child.setProperty(CacheConstants.REP_EXPIRATION, 1L, Type.LONG);
root.commit();
fail("Using rep:cache/rep:Cache outside a user or group must fail.");
} catch (CommitFailedException e) {
assertTrue(e.isConstraintViolation());
assertEquals(34, e.getCode());
} finally {
root.refresh();
Tree c = n.getChild(CacheConstants.REP_CACHE);
if (c.exists()) {
c.remove();
root.commit();
}
}
}
@Test(expected = CommitFailedException.class)
public void testChangeAuthorizableChildToCache() throws Exception {
Tree authorizableTree = getAuthorizableTree(getTestUser());
TreeUtil.addChild(authorizableTree, "child", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
root.commit();
try {
Tree child = getAuthorizableTree(getTestUser()).getChild("child");
child.setProperty(JCR_PRIMARYTYPE, CacheConstants.NT_REP_CACHE, Type.NAME);
root.commit();
} catch (CommitFailedException e) {
assertTrue(e.isConstraintViolation());
assertEquals(34, e.getCode());
throw e;
}
}
@Test(expected = CommitFailedException.class)
public void testChildNodeAddedToCache() throws Exception {
try {
Tree cache = getCache(getTestUser());
Tree child = TreeUtil.addChild(cache, "child", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
Validator validator = createCacheValidator(cache);
validator.childNodeAdded("child", getTreeProvider().asNodeState(child));
} catch (CommitFailedException e) {
assertTrue(e.isConstraintViolation());
assertEquals(34, e.getCode());
throw e;
}
}
@Test(expected = CommitFailedException.class)
public void testChildNodeChangedToCache() throws Exception {
try {
Tree cache = getCache(getTestUser());
Tree child = TreeUtil.addChild(cache, "child", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
Validator validator = createCacheValidator(cache);
NodeState ns = getTreeProvider().asNodeState(child);
validator.childNodeChanged("child", ns, ns);
} catch (CommitFailedException e) {
assertTrue(e.isConstraintViolation());
assertEquals(34, e.getCode());
throw e;
}
}
private Validator createCacheValidator(@NotNull Tree rootTree) {
CacheValidatorProvider provider = new CacheValidatorProvider(root.getContentSession().getAuthInfo().getPrincipals(), getTreeProvider());
NodeState nodeState = getTreeProvider().asNodeState(rootTree);
return provider.getRootValidator(nodeState, nodeState, new CommitInfo("sid", "uid"));
}
}