org.apache.nifi.registry.ranger.RangerBasePluginWithPolicies.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.nifi.registry.ranger.RangerBasePluginWithPolicies.java

Source

/*
 * 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.nifi.registry.ranger;

import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.registry.security.authorization.AccessPolicy;
import org.apache.nifi.registry.security.authorization.Group;
import org.apache.nifi.registry.security.authorization.RequestAction;
import org.apache.nifi.registry.security.authorization.User;
import org.apache.nifi.registry.security.authorization.UserGroupProvider;
import org.apache.nifi.registry.security.authorization.exception.AuthorizationAccessException;
import org.apache.ranger.plugin.service.RangerBasePlugin;
import org.apache.ranger.plugin.util.ServicePolicies;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Extends the base plugin to convert service policies into NiFi Registry policy domain model.
 */
public class RangerBasePluginWithPolicies extends RangerBasePlugin {

    private static final Logger logger = LoggerFactory.getLogger(RangerBasePluginWithPolicies.class);

    private final static String WILDCARD_ASTERISK = "*";

    private UserGroupProvider userGroupProvider;
    private AtomicReference<PolicyLookup> policies = new AtomicReference<>(new PolicyLookup());

    public RangerBasePluginWithPolicies(final String serviceType, final String appId) {
        this(serviceType, appId, null);
    }

    public RangerBasePluginWithPolicies(final String serviceType, final String appId,
            final UserGroupProvider userGroupProvider) {
        super(serviceType, appId);
        this.userGroupProvider = userGroupProvider; // will be null if used outside of the managed RangerAuthorizer
    }

    @Override
    public void setPolicies(final ServicePolicies policies) {
        super.setPolicies(policies);

        if (policies == null || policies.getPolicies() == null) {
            this.policies.set(new PolicyLookup());
        } else {
            this.policies.set(createPolicyLookup(policies));
        }
    }

    /**
     * Determines if a policy exists for the given resource.
     *
     * @param resourceIdentifier the id of the resource
     *
     * @return true if a policy exists for the given resource, false otherwise
     */
    public boolean doesPolicyExist(final String resourceIdentifier, final RequestAction requestAction) {
        if (resourceIdentifier == null) {
            return false;
        }

        final PolicyLookup policyLookup = policies.get();
        return policyLookup.getAccessPolicy(resourceIdentifier, requestAction) != null;
    }

    public Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException {
        return policies.get().getAccessPolicies();
    }

    public AccessPolicy getAccessPolicy(String identifier) throws AuthorizationAccessException {
        return policies.get().getAccessPolicy(identifier);
    }

    public AccessPolicy getAccessPolicy(String resourceIdentifier, RequestAction action)
            throws AuthorizationAccessException {
        return policies.get().getAccessPolicy(resourceIdentifier, action);
    }

    private PolicyLookup createPolicyLookup(final ServicePolicies servicePolicies) {
        final Map<String, AccessPolicy> policiesByIdentifier = new HashMap<>();
        final Map<String, Map<RequestAction, AccessPolicy>> policiesByResource = new HashMap<>();

        logger.debug(
                "Converting Ranger ServicePolicies model into NiFi Registry policy model for viewing purposes in NiFi Registry UI.");

        servicePolicies.getPolicies().stream().forEach(policy -> {
            // only consider policies that are enabled
            if (Boolean.TRUE.equals(policy.getIsEnabled())) {
                // get all the resources for this policy - excludes/recursive support disabled
                final Set<String> resources = policy.getResources().values().stream().filter(resource -> {
                    final boolean isMissingResource;
                    final boolean isWildcard;
                    if (resource.getValues() == null) {
                        isMissingResource = true;
                        isWildcard = false;
                    } else {
                        isMissingResource = false;
                        isWildcard = resource.getValues().stream()
                                .anyMatch(value -> value.contains(WILDCARD_ASTERISK));
                    }

                    final boolean isExclude = Boolean.TRUE.equals(resource.getIsExcludes());
                    final boolean isRecursive = Boolean.TRUE.equals(resource.getIsRecursive());

                    if (isMissingResource) {
                        logger.warn(
                                "Encountered resources missing values. Skipping policy for viewing purposes. Will still be used for access decisions.");
                    }
                    if (isWildcard) {
                        logger.warn(String.format(
                                "Resources [%s] include a wildcard value. Skipping policy for viewing purposes. "
                                        + "Will still be used for access decisions.",
                                StringUtils.join(resource.getValues(), ", ")));
                    }
                    if (isExclude) {
                        logger.warn(String.format(
                                "Resources [%s] marked as an exclude policy. Skipping policy for viewing purposes. "
                                        + "Will still be used for access decisions.",
                                StringUtils.join(resource.getValues(), ", ")));
                    }
                    if (isRecursive) {
                        logger.warn(String.format(
                                "Resources [%s] marked as a recursive policy. Skipping policy for viewing purposes. "
                                        + "Will still be used for access decisions.",
                                StringUtils.join(resource.getValues(), ", ")));
                    }

                    return !isMissingResource && !isWildcard && !isExclude && !isRecursive;
                }).flatMap(resource -> resource.getValues().stream()).collect(Collectors.toSet());

                policy.getPolicyItems().forEach(policyItem -> {
                    // get all the users for this policy item, excluding unknown users
                    final Set<String> userIds = policyItem.getUsers().stream()
                            .map(userIdentity -> getUser(userIdentity)).filter(Objects::nonNull)
                            .map(user -> user.getIdentifier()).collect(Collectors.toSet());

                    // get all groups for this policy item, excluding unknown groups
                    final Set<String> groupIds = policyItem.getGroups().stream()
                            .map(groupName -> getGroup(groupName)).filter(Objects::nonNull)
                            .map(group -> group.getIdentifier()).collect(Collectors.toSet());

                    // check if this policy item is a delegate admin
                    final boolean isDelegateAdmin = Boolean.TRUE.equals(policyItem.getDelegateAdmin());

                    policyItem.getAccesses().forEach(access -> {
                        try {
                            // interpret the request action
                            final RequestAction action = RequestAction.valueOf(access.getType());

                            // function for creating an access policy
                            final Function<String, AccessPolicy> createPolicy = resource -> new AccessPolicy.Builder()
                                    .identifierGenerateFromSeed(resource + access.getType()).resource(resource)
                                    .action(action).addUsers(userIds).addGroups(groupIds).build();

                            resources.forEach(resource -> {
                                // create the access policy for the specified resource
                                final AccessPolicy accessPolicy = createPolicy.apply(resource);
                                policiesByIdentifier.put(accessPolicy.getIdentifier(), accessPolicy);
                                policiesByResource.computeIfAbsent(resource, r -> new HashMap<>()).put(action,
                                        accessPolicy);

                                // if this is a delegate admin, also create the admin policy for the specified resource
                                if (isDelegateAdmin) {
                                    //  build the admin resource identifier
                                    final String adminResource;
                                    if (resource.startsWith("/")) {
                                        adminResource = "/policies" + resource;
                                    } else {
                                        adminResource = "/policies/" + resource;
                                    }

                                    final AccessPolicy adminAccessPolicy = createPolicy.apply(adminResource);
                                    policiesByIdentifier.put(adminAccessPolicy.getIdentifier(), adminAccessPolicy);
                                    policiesByResource.computeIfAbsent(adminResource, ar -> new HashMap<>())
                                            .put(action, adminAccessPolicy);
                                }
                            });
                        } catch (final IllegalArgumentException e) {
                            logger.warn(String.format(
                                    "Unrecognized request action '%s'. Skipping policy for viewing purposes. Will still be used for access decisions.",
                                    access.getType()));
                        }
                    });
                });
            }
        });

        return new PolicyLookup(policiesByIdentifier, policiesByResource);
    }

    private User getUser(final String identity) {
        if (userGroupProvider == null) {
            // generate the user deterministically when running outside of the ManagedRangerAuthorizer
            return new User.Builder().identifierGenerateFromSeed(identity).identity(identity).build();
        } else {
            // find the user in question
            final User user = userGroupProvider.getUserByIdentity(identity);

            if (user == null) {
                logger.warn(String.format(
                        "Cannot find user '%s' in the configured User Group Provider. Skipping user for viewing purposes. Will still be used for access decisions.",
                        identity));
            }

            return user;
        }
    }

    private Group getGroup(final String name) {
        if (userGroupProvider == null) {
            // generate the group deterministically when running outside of the ManagedRangerAuthorizer
            return new Group.Builder().identifierGenerateFromSeed(name).name(name).build();
        } else {
            // find the group in question
            final Group group = userGroupProvider.getGroups().stream().filter(g -> g.getName().equals(name))
                    .findFirst().orElse(null);

            if (group == null) {
                logger.warn(String.format(
                        "Cannot find group '%s' in the configured User Group Provider. Skipping group for viewing purposes. Will still be used for access decisions.",
                        name));
            }

            return group;
        }
    }

    private static class PolicyLookup {

        private final Map<String, AccessPolicy> policiesByIdentifier;
        private final Map<String, Map<RequestAction, AccessPolicy>> policiesByResource;
        private final Set<AccessPolicy> allPolicies;

        private PolicyLookup() {
            this(null, null);
        }

        private PolicyLookup(final Map<String, AccessPolicy> policiesByIdentifier,
                final Map<String, Map<RequestAction, AccessPolicy>> policiesByResource) {
            if (policiesByIdentifier == null) {
                allPolicies = Collections.EMPTY_SET;
            } else {
                allPolicies = Collections.unmodifiableSet(new HashSet<>(policiesByIdentifier.values()));
            }

            this.policiesByIdentifier = policiesByIdentifier;
            this.policiesByResource = policiesByResource;
        }

        private Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException {
            return allPolicies;
        }

        private AccessPolicy getAccessPolicy(String identifier) throws AuthorizationAccessException {
            if (policiesByIdentifier == null) {
                return null;
            }

            return policiesByIdentifier.get(identifier);
        }

        private AccessPolicy getAccessPolicy(String resourceIdentifier, RequestAction action)
                throws AuthorizationAccessException {
            if (policiesByResource == null) {
                return null;
            }

            final Map<RequestAction, AccessPolicy> policiesForResource = policiesByResource.get(resourceIdentifier);

            if (policiesForResource != null) {
                return policiesForResource.get(action);
            }

            return null;
        }
    }

}