Package org.apache.jackrabbit.oak.security.authorization.permission

Source Code of org.apache.jackrabbit.oak.security.authorization.permission.PermissionHook$Diff

/*
* 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.authorization.permission;

import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nonnull;

import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.core.ImmutableRoot;
import org.apache.jackrabbit.oak.plugins.nodetype.TypePredicate;
import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
import org.apache.jackrabbit.oak.spi.commit.PostValidationHook;
import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants;
import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBitsProvider;
import org.apache.jackrabbit.oak.spi.state.DefaultNodeStateDiff;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;

/**
* {@code CommitHook} implementation that processes any modification made to
* access control content and updates persisted permission store associated
* with access control related data stored in the repository.
* <p>
* The permission entries are grouped by principal and stored below the store root based on the hash value of the
* access controllable path. hash collisions are handled by adding subnodes accordingly.
* <pre>
*   /jcr:system/rep:permissionStore/workspace-name
*      /everyone
*          /552423  [rep:PermissionStore]
*              /0     [rep:Permissions]
*              /1     [rep:Permissions]
*              /c0     [rep:PermissionStore]
*                  /0      [rep:Permissions]
*                  /1      [rep:Permissions]
*                  /2      [rep:Permissions]
*              /c1     [rep:PermissionStore]
*                  /0      [rep:Permissions]
*                  /1      [rep:Permissions]
*                  /2      [rep:Permissions]
* </pre>
*/
public class PermissionHook implements PostValidationHook, AccessControlConstants, PermissionConstants {

    private static final Logger log = LoggerFactory.getLogger(PermissionHook.class);

    private final RestrictionProvider restrictionProvider;
    private final String workspaceName;

    private NodeBuilder permissionRoot;
    private PrivilegeBitsProvider bitsProvider;

    private TypePredicate isACL;
    private TypePredicate isACE;
    private TypePredicate isGrantACE;

    private Map<String, PermissionStoreEditor> modified = new HashMap<String, PermissionStoreEditor>();
    private Map<String, PermissionStoreEditor> deleted = new HashMap<String, PermissionStoreEditor>();

    public PermissionHook(String workspaceName, RestrictionProvider restrictionProvider) {
        this.workspaceName = workspaceName;
        this.restrictionProvider = restrictionProvider;
    }

    @Nonnull
    @Override
    public NodeState processCommit(
            NodeState before, NodeState after, CommitInfo info)
            throws CommitFailedException {
        NodeBuilder rootAfter = after.builder();

        permissionRoot = getPermissionRoot(rootAfter);
        bitsProvider = new PrivilegeBitsProvider(new ImmutableRoot(after));

        isACL = new TypePredicate(after, NT_REP_ACL);
        isACE = new TypePredicate(after, NT_REP_ACE);
        isGrantACE = new TypePredicate(after, NT_REP_GRANT_ACE);

        Diff diff = new Diff("");
        after.compareAgainstBaseState(before, diff);
        apply();
        return rootAfter.getNodeState();
    }

    private void apply() {
        for (Map.Entry<String, PermissionStoreEditor> entry : deleted.entrySet()) {
            entry.getValue().removePermissionEntries();
        }
        for (Map.Entry<String, PermissionStoreEditor> entry : modified.entrySet()) {
            entry.getValue().updatePermissionEntries();
        }
    }

    @Nonnull
    private NodeBuilder getPermissionRoot(NodeBuilder rootBuilder) {
        // permission root has been created during workspace initialization
        return rootBuilder.getChildNode(JCR_SYSTEM).getChildNode(REP_PERMISSION_STORE).getChildNode(workspaceName);
    }

    private class Diff extends DefaultNodeStateDiff {

        private final String parentPath;

        private Diff(String parentPath) {
            this.parentPath = parentPath;
        }

        @Override
        public boolean childNodeAdded(String name, NodeState after) {
            if (NodeStateUtils.isHidden(name)) {
                // ignore hidden nodes
                return true;
            }
            String path = parentPath + '/' + name;
            if (isACL.apply(after)) {
                PermissionStoreEditor psEditor = createPermissionStoreEditor(name, after);
                modified.put(psEditor.accessControlledPath, psEditor);
            } else {
                after.compareAgainstBaseState(EMPTY_NODE, new Diff(path));
            }
            return true;
        }

        @Override
        public boolean childNodeChanged(String name, NodeState before, NodeState after) {
            if (NodeStateUtils.isHidden(name)) {
                // ignore hidden nodes
                return true;
            }
            String path = parentPath + '/' + name;
            if (isACL.apply(before)) {
                if (isACL.apply(after)) {
                    PermissionStoreEditor psEditor = createPermissionStoreEditor(name, after);
                    modified.put(psEditor.accessControlledPath, psEditor);

                    // also consider to remove the ACL from removed entries of other principals
                    PermissionStoreEditor beforeEditor = createPermissionStoreEditor(name, before);
                    beforeEditor.entries.keySet().removeAll(psEditor.entries.keySet());
                    if (!beforeEditor.entries.isEmpty()) {
                        deleted.put(parentPath, beforeEditor);
                    }

                } else {
                    PermissionStoreEditor psEditor = createPermissionStoreEditor(name, before);
                    deleted.put(psEditor.accessControlledPath, psEditor);
                }
            } else if (isACL.apply(after)) {
                PermissionStoreEditor psEditor = createPermissionStoreEditor(name, after);
                modified.put(psEditor.accessControlledPath, psEditor);
            } else {
                after.compareAgainstBaseState(before, new Diff(path));
            }
            return true;
        }

        @Override
        public boolean childNodeDeleted(String name, NodeState before) {
            if (NodeStateUtils.isHidden(name)) {
                // ignore hidden nodes
                return true;
            }
            String path = parentPath + '/' + name;
            if (isACL.apply(before)) {
                PermissionStoreEditor psEditor = createPermissionStoreEditor(name, before);
                deleted.put(psEditor.accessControlledPath, psEditor);
            } else {
                EMPTY_NODE.compareAgainstBaseState(before, new Diff(path));
            }
            return true;
        }

        private PermissionStoreEditor createPermissionStoreEditor(@Nonnull String nodeName, @Nonnull NodeState nodeState) {
            return new PermissionStoreEditor(parentPath, nodeName, nodeState, permissionRoot, isACE, isGrantACE, bitsProvider, restrictionProvider);
        }
    }
}
TOP

Related Classes of org.apache.jackrabbit.oak.security.authorization.permission.PermissionHook$Diff

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.