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

Source Code of org.apache.jackrabbit.oak.spi.security.authorization.permission.CompositePermissionProvider$CompositeRepositoryPermission

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

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
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.core.ImmutableRoot;
import org.apache.jackrabbit.oak.plugins.tree.ImmutableTree;
import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBits;
import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBitsProvider;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.util.Text;

/**
* Permission provider implementation that aggregates a list of different
* provider implementations. Note, that the implementations *must* implement
* the {@link org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider}
* interface.
*/
public class CompositePermissionProvider implements PermissionProvider {

    private final Root root;
    private final List<AggregatedPermissionProvider> pps;
    private final CompositeRepositoryPermission repositoryPermission;

    private ImmutableRoot immutableRoot;
    private PrivilegeBitsProvider pbp;

    public CompositePermissionProvider(@Nonnull Root root, @Nonnull List<AggregatedPermissionProvider> pps) {
        this.root = root;
        this.pps = pps;

        repositoryPermission = new CompositeRepositoryPermission();
        immutableRoot = (root instanceof ImmutableRoot) ? (ImmutableRoot) root : new ImmutableRoot(root);
        pbp = new PrivilegeBitsProvider(immutableRoot);
    }

    @Override
    public void refresh() {
        immutableRoot = (root instanceof ImmutableRoot) ? (ImmutableRoot) root : new ImmutableRoot(root);
        pbp = new PrivilegeBitsProvider(immutableRoot);

        for (PermissionProvider pp : pps) {
            pp.refresh();
        }
    }

    @Override
    public Set<String> getPrivileges(@Nullable Tree tree) {
        return pbp.getPrivilegeNames(getPrivilegeBits(tree));
    }

    @Override
    public boolean hasPrivileges(@Nullable Tree tree, @Nonnull String... privilegeNames) {
        return getPrivilegeBits(tree).includes(pbp.getBits(privilegeNames));
    }

    @Override
    public RepositoryPermission getRepositoryPermission() {
        return repositoryPermission;
    }

    @Override
    public TreePermission getTreePermission(@Nonnull Tree tree, @Nonnull TreePermission parentPermission) {
        ImmutableTree immTree = (tree instanceof ImmutableTree) ? (ImmutableTree) tree : immutableRoot.getTree(tree.getPath());
        if (tree.isRoot()) {
            return new CompositeTreePermission(immTree, new CompositeTreePermission());
        } else {
            if (!(parentPermission instanceof CompositeTreePermission)) {
                throw new IllegalArgumentException("Illegal parent permission instance. Expected CompositeTreePermission.");
            }
            return new CompositeTreePermission(immTree, (CompositeTreePermission) parentPermission);
        }
    }

    @Override
    public boolean isGranted(final @Nonnull Tree parent, @Nullable PropertyState property, final long permissions) {
        if (Permissions.isAggregate(permissions)) {
            for (final long permission : Permissions.aggregates(permissions)) {
                Iterable<AggregatedPermissionProvider> providers = Iterables.filter(pps, new Predicate<AggregatedPermissionProvider>() {
                    @Override
                    public boolean apply(@Nullable AggregatedPermissionProvider pp) {
                        return pp != null && pp.handles(parent, permission);
                    }
                });
                if (!grantsPermission(parent, property, permission, providers)) {
                    return false;
                }
            }
            return true;
        } else {
            Iterable<AggregatedPermissionProvider> providers = Iterables.filter(pps, new Predicate<AggregatedPermissionProvider>() {
                @Override
                public boolean apply(@Nullable AggregatedPermissionProvider pp) {
                    return pp != null && pp.handles(parent, permissions);
                }
            });
            return grantsPermission(parent, property, permissions, providers);
        }
    }

    @Override
    public boolean isGranted(final @Nonnull String oakPath, final @Nonnull String jcrActions) {
        String[] actions = Text.explode(jcrActions, ',', false);
        switch (actions.length) {
            case 0: return true;
            case 1:
                Iterable<AggregatedPermissionProvider> providers = Iterables.filter(pps, new Predicate<AggregatedPermissionProvider>() {
                    @Override
                    public boolean apply(@Nullable AggregatedPermissionProvider pp) {
                        return pp != null && pp.handles(oakPath, jcrActions);
                    }
                });
                return grantsAction(oakPath, actions[0], providers);
            default:
                for (final String action : actions) {
                    providers = Iterables.filter(pps, new Predicate<AggregatedPermissionProvider>() {
                        @Override
                        public boolean apply(@Nullable AggregatedPermissionProvider pp) {
                            return pp != null && pp.handles(oakPath, action);
                        }
                    });
                    if (!grantsAction(oakPath, action, providers)) {
                        return false;
                    }
                }
                return true;
        }
    }

    //--------------------------------------------------------------------------
    private PrivilegeBits getPrivilegeBits(@Nullable final Tree tree) {
        PrivilegeBits sufficient = PrivilegeBits.getInstance();
        PrivilegeBits required = null;

        Iterable<AggregatedPermissionProvider> providers = Iterables.filter(pps, new Predicate<AggregatedPermissionProvider>() {
            @Override
            public boolean apply(@Nullable AggregatedPermissionProvider pp) {
                return pp != null && ((tree == null) ? pp.handlesRepositoryPermissions() : pp.handles(tree));
            }
        });
        for (AggregatedPermissionProvider pp : providers) {
            PrivilegeBits privs = pbp.getBits(pp.getPrivileges(tree));
            ControlFlag flag = pp.getFlag();
            if (ControlFlag.SUFFICIENT == flag) {
                sufficient.add(privs);
                if (required != null) {
                    sufficient.retain(required);
                }
            } else if (ControlFlag.REQUISITE == flag) {
                if (required == null) {
                    required = PrivilegeBits.getInstance();
                    required.add(privs);
                } else {
                    required.retain(privs);
                }
            }
        }
        if (required != null) {
            sufficient.add(required);
        }
        return sufficient;
    }

    private static boolean grantsPermission(@Nonnull final Tree parent,
                                            @Nullable PropertyState property,
                                            final long permission,
                                            @Nonnull Iterable<AggregatedPermissionProvider> providers) {
        Iterator<AggregatedPermissionProvider> it = providers.iterator();
        while (it.hasNext()) {
            AggregatedPermissionProvider pp = it.next();
            boolean isGranted = pp.isGranted(parent, property, permission);
            if (!it.hasNext() || evalComplete(isGranted, pp.getFlag())) {
                return isGranted;
            }
        }
        return false;
    }

    private static boolean grantsAction(@Nonnull final String oakPath,
                                        @Nonnull final String action,
                                        @Nonnull Iterable<AggregatedPermissionProvider> providers) {
        Iterator<AggregatedPermissionProvider> it = providers.iterator();
        while (it.hasNext()) {
            AggregatedPermissionProvider pp = it.next();
            boolean isGranted = pp.isGranted(oakPath, action);
            if (!it.hasNext() || evalComplete(isGranted, pp.getFlag())) {
                return isGranted;
            }
        }
        return false;
    }

    private static boolean grantsRepoPermission(long permission, @Nonnull Iterable<AggregatedPermissionProvider> providers) {
        Iterator<AggregatedPermissionProvider> it = providers.iterator();
        while (it.hasNext()) {
            AggregatedPermissionProvider pp = it.next();
            boolean isGranted = pp.getRepositoryPermission().isGranted(permission);
            if (!it.hasNext() || evalComplete(isGranted, pp.getFlag())) {
                return isGranted;
            }

        }
        return false;
    }

    private static boolean evalComplete(boolean isGranted, ControlFlag flag) {
        switch (flag) {
            case SUFFICIENT:
                if (isGranted) {
                    return true;
                }
                break;
            case REQUISITE:
                if (!isGranted) {
                    return true;
                }
                break;
            default:
                throw new IllegalArgumentException("Unsupported PermissionProvider Control Flag " + flag);

        }
        return false;
    }

    //--------------------------------------------------------------------------

    private final class CompositeTreePermission implements TreePermission {

        private final ImmutableTree tree;
        private final CompositeTreePermission parentPermission;

        private final Map<AggregatedPermissionProvider, TreePermission> map;

        private Boolean canRead;

        private CompositeTreePermission() {
            tree = null;
            parentPermission = null;

            map = ImmutableMap.of();
        }

        private CompositeTreePermission(final @Nonnull ImmutableTree tree, @Nonnull CompositeTreePermission parentPermission) {
            this.tree = tree;
            this.parentPermission = parentPermission;

            map = new LinkedHashMap<AggregatedPermissionProvider, TreePermission>(pps.size());
            for (AggregatedPermissionProvider provider : pps) {
                TreePermission tp = provider.getTreePermission(tree, getParentPermission(provider));
                map.put(provider, tp);
            }
        }

        @Override
        public TreePermission getChildPermission(String childName, NodeState childState) {
            ImmutableTree childTree = new ImmutableTree(tree, childName, childState);
            return new CompositeTreePermission(childTree, this);
        }

        @Override
        public boolean canRead() {
            if (canRead == null) {
                canRead = false;
                Iterator<Map.Entry<AggregatedPermissionProvider, TreePermission>> it = map.entrySet().iterator();
                while (it.hasNext()) {
                    Map.Entry<AggregatedPermissionProvider, TreePermission> entry = it.next();
                    TreePermission tp = entry.getValue();
                    if (entry.getKey().handles(tp, Permissions.READ_NODE)) {
                        boolean isGranted = entry.getValue().canRead();
                        if (!it.hasNext() || evalComplete(isGranted, entry.getKey().getFlag())) {
                            this.canRead = isGranted;
                            break;
                        }
                    }
                }
            }
            return canRead;
        }

        @Override
        public boolean canRead(@Nonnull PropertyState property) {
            Iterator<Map.Entry<AggregatedPermissionProvider, TreePermission>> it = map.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<AggregatedPermissionProvider, TreePermission> entry = it.next();
                TreePermission tp = entry.getValue();
                if (entry.getKey().handles(tp, Permissions.READ_PROPERTY)) {
                    boolean isGranted = entry.getValue().canRead(property);
                    if (!it.hasNext() || evalComplete(isGranted, entry.getKey().getFlag())) {
                        return isGranted;
                    }
                }
            }
            return false;
        }

        @Override
        public boolean canReadAll() {
            return false;
        }

        @Override
        public boolean canReadProperties() {
            return false;
        }

        @Override
        public boolean isGranted(long permissions) {
            if (Permissions.isAggregate(permissions)) {
                for (long permission : Permissions.aggregates(permissions)) {
                    if (!grantsPermission(permission, null)) {
                        return false;
                    }
                }
                return true;
            } else {
                return grantsPermission(permissions, null);
            }
        }

        @Override
        public boolean isGranted(long permissions, @Nonnull PropertyState property) {
            if (Permissions.isAggregate(permissions)) {
                for (long permission : Permissions.aggregates(permissions)) {
                    if (!grantsPermission(permission, property)) {
                        return false;
                    }
                }
                return true;
            } else {
                return grantsPermission(permissions, property);
            }
        }

        private boolean grantsPermission(long permission, @Nullable PropertyState property) {
            Iterator<Map.Entry<AggregatedPermissionProvider, TreePermission>> it = map.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<AggregatedPermissionProvider, TreePermission> entry = it.next();
                if (entry.getKey().handles(this, permission)) {
                    TreePermission tp = entry.getValue();
                    boolean isGranted = (property == null) ? tp.isGranted(permission) : tp.isGranted(permission, property);
                    if (!it.hasNext() || evalComplete(isGranted, entry.getKey().getFlag())) {
                        return isGranted;
                    }
                }
            }
            return false;
        }

        @Nonnull
        private TreePermission getParentPermission(AggregatedPermissionProvider provider) {
            TreePermission parent = null;
            if (parentPermission != null) {
                parent = parentPermission.map.get(provider);
            }
            return (parent == null) ? TreePermission.EMPTY : parent;
        }


    }

    private class CompositeRepositoryPermission implements RepositoryPermission {

        @Override
        public boolean isGranted(long repositoryPermissions) {
            Iterable<AggregatedPermissionProvider> providers = Iterables.filter(pps, new Predicate<AggregatedPermissionProvider>() {
                @Override
                public boolean apply(@Nullable AggregatedPermissionProvider provider) {
                    return provider != null && provider.handlesRepositoryPermissions();
                }
            });
            if (Permissions.isAggregate(repositoryPermissions)) {
                for (long permission : Permissions.aggregates(repositoryPermissions)) {
                    if (!grantsRepoPermission(permission, providers)) {
                        return false;
                    }
                }
                return true;
            } else {
                return grantsRepoPermission(repositoryPermissions, providers);
            }
        }
    }
}
TOP

Related Classes of org.apache.jackrabbit.oak.spi.security.authorization.permission.CompositePermissionProvider$CompositeRepositoryPermission

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.