com.thinkbiganalytics.metadata.modeshape.security.role.JcrAbstractRoleMembership.java Source code

Java tutorial

Introduction

Here is the source code for com.thinkbiganalytics.metadata.modeshape.security.role.JcrAbstractRoleMembership.java

Source

/**
 * 
 */
package com.thinkbiganalytics.metadata.modeshape.security.role;

/*-
 * #%L
 * kylo-metadata-modeshape
 * %%
 * Copyright (C) 2017 ThinkBig Analytics
 * %%
 * Licensed 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.
 * #L%
 */

import java.security.Principal;
import java.util.Arrays;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.jcr.Node;

import org.apache.commons.lang3.ArrayUtils;

import com.thinkbiganalytics.metadata.api.security.RoleMembership;
import com.thinkbiganalytics.metadata.modeshape.common.JcrObject;
import com.thinkbiganalytics.metadata.modeshape.security.action.JcrAllowedActions;
import com.thinkbiganalytics.metadata.modeshape.support.JcrPropertyUtil;
import com.thinkbiganalytics.metadata.modeshape.support.JcrUtil;
import com.thinkbiganalytics.security.GroupPrincipal;
import com.thinkbiganalytics.security.UsernamePrincipal;
import com.thinkbiganalytics.security.action.Action;
import com.thinkbiganalytics.security.action.AllowableAction;
import com.thinkbiganalytics.security.action.AllowedActions;
import com.thinkbiganalytics.security.role.SecurityRole;

/**
 *
 */
public abstract class JcrAbstractRoleMembership extends JcrObject implements RoleMembership {

    private static final UsernamePrincipal[] NO_USERS = new UsernamePrincipal[0];
    private static final GroupPrincipal[] NO_GROUPS = new GroupPrincipal[0];
    public static final String NODE_NAME = "tba:roleMemberships";
    public static final String NODE_TYPE = "tba:roleMembership";
    public static final String ROLE = "tba:role";
    public static final String GROUPS = "tba:groups";
    public static final String USERS = "tba:users";

    public static <M extends JcrAbstractRoleMembership> M create(Node parentNode, Node roleNode,
            Class<M> memberClass, Object... args) {
        Object[] argsWithRole = ArrayUtils.add(args, 0, roleNode);
        // Returns the membership if it already exists in the SNS nodes; otherwise it creates it.
        return JcrUtil.getNodeList(parentNode, NODE_NAME).stream()
                .map(node -> JcrUtil.getJcrObject(node, memberClass, args))
                .filter(memshp -> memshp.getRole().getSystemName().equals(JcrUtil.getName(roleNode))).findFirst()
                .orElseGet(() -> {
                    return JcrUtil.addJcrObject(parentNode, NODE_NAME, NODE_TYPE, memberClass, argsWithRole);
                });
    }

    public static void remove(Node parentNode, Node roleNode,
            Class<? extends JcrAbstractRoleMembership> memberClass) {
        JcrUtil.getNodeList(parentNode, NODE_NAME).forEach(node -> {
            JcrAbstractRoleMembership membership = JcrUtil.getJcrObject(node, memberClass, roleNode,
                    (JcrAllowedActions) null);

            if (membership.getRole().getSystemName().equals(JcrUtil.getName(roleNode))) {
                JcrUtil.removeNode(node);
            }
        });
    }

    public static void removeAll(Node parentNode) {
        JcrUtil.getNodeList(parentNode, NODE_NAME).forEach(node -> JcrUtil.removeNode(node));
    }

    public static <M extends JcrAbstractRoleMembership> Optional<M> find(Node parentNode, String roleName,
            Class<M> memberClass, Object... args) {
        return JcrUtil.getNodeList(parentNode, NODE_NAME).stream()
                .map(node -> JcrUtil.getJcrObject(node, memberClass, args))
                .filter(memshp -> memshp.getRole().getSystemName().equals(roleName)).findFirst();
    }

    public JcrAbstractRoleMembership(Node node) {
        super(node);
    }

    public JcrAbstractRoleMembership(Node node, Node roleNode) {
        super(node);
        JcrPropertyUtil.setProperty(node, ROLE, roleNode);
    }

    @Override
    public SecurityRole getRole() {
        return JcrUtil.getReferencedObject(getNode(), ROLE, JcrSecurityRole.class);
    }

    @Override
    public Set<Principal> getMembers() {
        Stream<? extends Principal> groups = streamGroups();
        Stream<? extends Principal> users = streamUsers();
        return Stream.concat(groups, users).collect(Collectors.toSet());
    }

    @Override
    public void setMemebers(UsernamePrincipal... principals) {
        Set<UsernamePrincipal> newMembers = Arrays.stream(principals).collect(Collectors.toSet());
        Set<UsernamePrincipal> oldMembers = streamUsers().collect(Collectors.toSet());

        newMembers.stream().filter(u -> !oldMembers.contains(u)).forEach(this::addMember);

        oldMembers.stream().filter(u -> !newMembers.contains(u)).forEach(this::removeMember);
    }

    @Override
    public void setMemebers(GroupPrincipal... principals) {
        Set<GroupPrincipal> newMembers = Arrays.stream(principals).collect(Collectors.toSet());
        Set<GroupPrincipal> oldMembers = streamGroups().collect(Collectors.toSet());

        newMembers.stream().filter(u -> !oldMembers.contains(u)).forEach(this::addMember);

        oldMembers.stream().filter(u -> !newMembers.contains(u)).forEach(this::removeMember);
    }

    @Override
    public void addMember(GroupPrincipal principal) {
        JcrPropertyUtil.addToSetProperty(getNode(), GROUPS, principal.getName());
        enable(principal);
    }

    @Override
    public void addMember(UsernamePrincipal principal) {
        JcrPropertyUtil.addToSetProperty(getNode(), USERS, principal.getName());
        enable(principal);
    }

    @Override
    public void removeMember(GroupPrincipal principal) {
        JcrPropertyUtil.removeFromSetProperty(getNode(), GROUPS, principal.getName());
        disable(principal);
    }

    @Override
    public void removeMember(UsernamePrincipal principal) {
        JcrPropertyUtil.removeFromSetProperty(getNode(), USERS, principal.getName());
        disable(principal);
    }

    @Override
    public void removeAllMembers() {
        setMemebers(NO_USERS);
        setMemebers(NO_GROUPS);
    }

    /**
     * Enable any permissions for this principal after it was added as a role member of this RoleMembership.
     * @param principal the added principal
     */
    protected abstract void enable(Principal principal);

    /**
     * Disable any permissions for this principal after it was removed as a role member of this RoleMembership.
     * @param principal the removed principal
     */
    protected abstract void disable(Principal principal);

    /**
     * A convenience method for enabling only the permissions granted by the role memberships among the passed in set
     * of which the given principal is a member.
     * @param principal the principal involved
     * @param allMemberships a stream of all potential role memberships that may be involved in enabling permissions for this principal
     * @param allowed the allowed actions that should be updated to permit with the new permissions
     */
    protected void enableOnly(Principal principal, Stream<RoleMembership> allMemberships, AllowedActions allowed) {
        // Get a union of all actions allowed by all role memberships containing the principal as a member.
        Set<Action> actions = allMemberships.filter(membership -> membership.getMembers().contains(principal))
                .map(membership -> membership.getRole())
                .flatMap(role -> role.getAllowedActions().getAvailableActions().stream())
                .flatMap(avail -> avail.stream()).collect(Collectors.toSet());

        // Update the given allowed actions to enable only the derived set of permitted actions based
        // on the current set of role memberships of the principal.
        allowed.enableOnly(principal, actions);
    }

    protected Stream<UsernamePrincipal> streamUsers() {
        return JcrPropertyUtil.<String>getSetProperty(getNode(), USERS).stream().map(UsernamePrincipal::new);
    }

    protected Stream<GroupPrincipal> streamGroups() {
        return JcrPropertyUtil.<String>getSetProperty(getNode(), GROUPS).stream().map(GroupPrincipal::new);
    }
}