<commit_before>/*
 * 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 static org.junit.Assert.assertArrayEquals;

import java.security.Principal;
import java.util.HashSet;
import java.util.Set;

import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.security.AccessControlEntry;
import javax.jcr.security.Privilege;
import javax.jcr.util.TraversingItemVisitor;

import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
import org.apache.jackrabbit.api.security.user.Group;
import org.apache.jackrabbit.oak.security.authorization.AccessControlUtils;
import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
import org.junit.Test;

/**
 * Permission evaluation tests related to {@link javax.jcr.security.Privilege#JCR_READ} privilege.
 */
public class ReadTest extends AbstractEvaluationTest {

    @Test
    public void testChildNodes() throws Exception {
        /* create some new nodes below 'path' */
        Node n = superuser.getNode(path);
        for (int i = 0; i < 5; i++) {
            n = n.addNode(nodeName4, testNodeType);
        }
        superuser.save();

        /* make sure the same privileges/permissions are granted as at path. */
        testSession.refresh(false);
        String childPath = n.getPath();
        assertArrayEquals(readPrivileges, testAcMgr.getPrivileges(childPath));
        testSession.checkPermission(childPath, Session.ACTION_READ);
    }

    @Test
    public void testNonExistingItem() throws Exception {
        /*
          precondition:
          testuser must have READ-only permission on the root node and below
        */
        String rootPath = testSession.getRootNode().getPath();
        assertReadOnly(rootPath);
        testSession.checkPermission(rootPath + "nonExistingItem", Session.ACTION_READ);
    }

    @Test
    public void testGetItem() throws Exception {
        // withdraw READ privilege to 'testUser' at 'path'
        deny(path, readPrivileges);
        allow(childNPath, readPrivileges);
        testSession.getItem(childNPath);
    }

    @Test
    public void testItemExists() throws Exception {
        // withdraw READ privilege to 'testUser' at 'path'
        deny(path, readPrivileges);
        allow(childNPath, readPrivileges);

        assertFalse(testSession.itemExists(path));
        assertTrue(testSession.itemExists(childNPath));
    }

    @Test
    public void testDeniedReadOnSubTree() throws Exception, InterruptedException {
        // withdraw READ privilege to 'testUser' at 'path'
        deny(childNPath, readPrivileges);
        /*
         testuser must now have
         - READ-only permission at path
         - READ-only permission for the child-props of path

         testuser must not have
         - any permission on child-node and all its subtree
        */

        // must still have read-access to path, ...
        assertTrue(testSession.hasPermission(path, Session.ACTION_READ));
        Node n = testSession.getNode(path);
        // ... siblings of childN
        testSession.getNode(childNPath2);
        // ... and props of path
        assertTrue(n.getProperties().hasNext());

        //testSession must not have access to 'childNPath'
        assertFalse(testSession.itemExists(childNPath));
        try {
            testSession.getNode(childNPath);
            fail("Read access has been denied -> cannot retrieve child node.");
        } catch (PathNotFoundException e) {
            // ok.
        }
        /*
        -> must not have access to subtree below 'childNPath'
        */
        assertFalse(testSession.itemExists(childchildPPath));
        try {
            testSession.getItem(childchildPPath);
            fail("Read access has been denied -> cannot retrieve prop below child node.");
        } catch (PathNotFoundException e) {
            // ok.
        }
    }

    @Test
    public void testAllowWriteDenyRead() throws Exception {
        // allow 'testUser' to write at 'path'
        allow(path, repWritePrivileges);
        // deny read access
        deny(path, readPrivileges);

        // testuser must not be able to access that node
        assertFalse(testSession.nodeExists(path));
    }

    @Test
    public void testDenyRoot() throws Exception {
        try {
            deny("/", readPrivileges);
            testSession.getRootNode();
            fail("root should not be accessible");
        } catch (Exception e) {
            // expected exception
        } finally {
            allow("/", readPrivileges);
        }
    }

    @Test
    public void testDenyPath() throws Exception {
        try {
            deny(path, readPrivileges);
            testSession.getNode(path);
            fail("nodet should not be accessible");
        } catch (Exception e) {
            // expected exception
        } finally {
            allow(path, readPrivileges);
        }
    }

    @Test
    public void testReadDenied() throws Exception {
        /* deny READ privilege for testUser at 'path' */
        deny(path, readPrivileges);
        /*
         allow READ privilege for testUser at 'childNPath'
         */<commit_msg>OAK-929: Permission changes not visible on root after refresh Cleanup root node after test run<commit_after>/*
 * 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 static org.junit.Assert.assertArrayEquals;

import java.security.Principal;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.security.AccessControlEntry;
import javax.jcr.security.AccessControlList;
import javax.jcr.security.Privilege;
import javax.jcr.util.TraversingItemVisitor;

import com.google.common.collect.Sets;
import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
import org.apache.jackrabbit.api.security.user.Group;
import org.apache.jackrabbit.oak.security.authorization.AccessControlUtils;
import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
import org.junit.Test;

/**
 * Permission evaluation tests related to {@link javax.jcr.security.Privilege#JCR_READ} privilege.
 */
public class ReadTest extends AbstractEvaluationTest {

    @Test
    public void testChildNodes() throws Exception {
        /* create some new nodes below 'path' */
        Node n = superuser.getNode(path);
        for (int i = 0; i < 5; i++) {
            n = n.addNode(nodeName4, testNodeType);
        }
        superuser.save();

        /* make sure the same privileges/permissions are granted as at path. */
        testSession.refresh(false);
        String childPath = n.getPath();
        assertArrayEquals(readPrivileges, testAcMgr.getPrivileges(childPath));
        testSession.checkPermission(childPath, Session.ACTION_READ);
    }

    @Test
    public void testNonExistingItem() throws Exception {
        /*
          precondition:
          testuser must have READ-only permission on the root node and below
        */
        String rootPath = testSession.getRootNode().getPath();
        assertReadOnly(rootPath);
        testSession.checkPermission(rootPath + "nonExistingItem", Session.ACTION_READ);
    }

    @Test
    public void testGetItem() throws Exception {
        // withdraw READ privilege to 'testUser' at 'path'
        deny(path, readPrivileges);
        allow(childNPath, readPrivileges);
        testSession.getItem(childNPath);
    }

    @Test
    public void testItemExists() throws Exception {
        // withdraw READ privilege to 'testUser' at 'path'
        deny(path, readPrivileges);
        allow(childNPath, readPrivileges);

        assertFalse(testSession.itemExists(path));
        assertTrue(testSession.itemExists(childNPath));
    }

    @Test
    public void testDeniedReadOnSubTree() throws Exception, InterruptedException {
        // withdraw READ privilege to 'testUser' at 'path'
        deny(childNPath, readPrivileges);
        /*
         testuser must now have
         - READ-only permission at path
         - READ-only permission for the child-props of path

         testuser must not have
         - any permission on child-node and all its subtree
        */

        // must still have read-access to path, ...
        assertTrue(testSession.hasPermission(path, Session.ACTION_READ));
        Node n = testSession.getNode(path);
        // ... siblings of childN
        testSession.getNode(childNPath2);
        // ... and props of path
        assertTrue(n.getProperties().hasNext());

        //testSession must not have access to 'childNPath'
        assertFalse(testSession.itemExists(childNPath));
        try {
            testSession.getNode(childNPath);
            fail("Read access has been denied -> cannot retrieve child node.");
        } catch (PathNotFoundException e) {
            // ok.
        }
        /*
        -> must not have access to subtree below 'childNPath'
        */
        assertFalse(testSession.itemExists(childchildPPath));
        try {
            testSession.getItem(childchildPPath);
            fail("Read access has been denied -> cannot retrieve prop below child node.");
        } catch (PathNotFoundException e) {
            // ok.
        }
    }

    @Test
    public void testAllowWriteDenyRead() throws Exception {
        // allow 'testUser' to write at 'path'
        allow(path, repWritePrivileges);
        // deny read access
        deny(path, readPrivileges);

        // testuser must not be able to access that node
        assertFalse(testSession.nodeExists(path));
    }

    @Test
    public void testDenyRoot() throws Exception {
        Set<AccessControlEntry> acesBefore = getACEs("/");
        try {
            deny("/", readPrivileges);
            testSession.getRootNode();
            fail("root should not be accessible");
        } catch (Exception e) {
            // expected exception
        } finally {
            restoreAces("/", acesBefore);
        }
    }

    private Set<AccessControlEntry> getACEs(String path) throws RepositoryException {
        AccessControlList acl = AccessControlUtils.getAccessControlList(superuser, path);
        Set<AccessControlEntry> acesBefore = Sets.newHashSet();
        if (acl != null) {
            Collections.addAll(acesBefore, acl.getAccessControlEntries());
        }
        return acesBefore;
    }

    private void restoreAces(String path, Set<AccessControlEntry> acesToKeep) throws RepositoryException {
        AccessControlList acl = AccessControlUtils.getAccessControlList(superuser, path);
        if (acl != null) {
            for (AccessControlEntry ace : acl.getAccessControlEntries()) {
                if (!acesToKeep.contains(ace)) {
                    acl.removeAccessControlEntry(ace);
                }
            }
            acMgr.setPolicy("/", acl);
            superuser.save();
        }
    }

    @Test
    public void testDenyPath() throws Exception {
        try {
            deny(path, readPrivileges);
            testSession.getNode(path);
            fail("nodet should not be accessible");
        } catch (Exception e) {
            // expected exception
        }
    }

    @Test
    public void testReadDenied() throws Exception {
        /* deny READ privilege for testUser at 'path' */
        deny(path, readPrivileges);
        /*
         allow READ privilege for testUser at 'childNPath'
         */
{'fraction_non_alphanumeric': 0.09027355623100304, 'fraction_numerical': 0.0014437689969604864, 'mean_word_length': 2.563769293257514, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4158450', 'n_tokens_mistral': 3462, 'n_tokens_neox': 3432, 'n_words': 1021}