Java tutorial
/* * 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; } } }