/* * 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.web.dao.impl; import org.apache.nifi.authorization.AbstractPolicyBasedAuthorizer; import org.apache.nifi.authorization.AccessPolicy; import org.apache.nifi.authorization.Authorizer; import org.apache.nifi.authorization.AuthorizerConfigurationContext; import org.apache.nifi.authorization.AuthorizerInitializationContext; import org.apache.nifi.authorization.Group; import org.apache.nifi.authorization.RequestAction; import org.apache.nifi.authorization.User; import org.apache.nifi.authorization.UsersAndAccessPolicies; import org.apache.nifi.authorization.exception.AuthorizationAccessException; import org.apache.nifi.authorization.exception.AuthorizerCreationException; import org.apache.nifi.authorization.exception.AuthorizerDestructionException; import org.apache.nifi.authorization.resource.Authorizable; import org.apache.nifi.web.ResourceNotFoundException; import org.apache.nifi.web.api.dto.AccessPolicyDTO; import org.apache.nifi.web.api.dto.UserDTO; import org.apache.nifi.web.api.dto.UserGroupDTO; import org.apache.nifi.web.api.entity.ComponentEntity; import org.apache.nifi.web.api.entity.TenantEntity; import org.apache.nifi.web.dao.AccessPolicyDAO; import org.apache.nifi.web.dao.UserDAO; import org.apache.nifi.web.dao.UserGroupDAO; import java.util.Set; import java.util.stream.Collectors; public class StandardPolicyBasedAuthorizerDAO implements AccessPolicyDAO, UserGroupDAO, UserDAO { private final AbstractPolicyBasedAuthorizer authorizer; private final boolean supportsConfigurableAuthorizer; public StandardPolicyBasedAuthorizerDAO(final Authorizer authorizer) { if (authorizer instanceof AbstractPolicyBasedAuthorizer) { this.authorizer = (AbstractPolicyBasedAuthorizer) authorizer; this.supportsConfigurableAuthorizer = true; } else { this.authorizer = new AbstractPolicyBasedAuthorizer() { @Override public Group doAddGroup(final Group group) throws AuthorizationAccessException { throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); } @Override public Group getGroup(final String identifier) throws AuthorizationAccessException { throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); } @Override public Group doUpdateGroup(final Group group) throws AuthorizationAccessException { throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); } @Override public Group deleteGroup(final Group group) throws AuthorizationAccessException { throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); } @Override public Set<Group> getGroups() throws AuthorizationAccessException { throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); } @Override public User doAddUser(final User user) throws AuthorizationAccessException { throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); } @Override public User getUser(final String identifier) throws AuthorizationAccessException { throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); } @Override public User getUserByIdentity(final String identity) throws AuthorizationAccessException { throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); } @Override public User doUpdateUser(final User user) throws AuthorizationAccessException { throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); } @Override public User deleteUser(final User user) throws AuthorizationAccessException { throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); } @Override public Set<User> getUsers() throws AuthorizationAccessException { throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); } @Override public AccessPolicy doAddAccessPolicy(final AccessPolicy accessPolicy) throws AuthorizationAccessException { throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); } @Override public AccessPolicy getAccessPolicy(final String identifier) throws AuthorizationAccessException { throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); } @Override public AccessPolicy updateAccessPolicy(final AccessPolicy accessPolicy) throws AuthorizationAccessException { throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); } @Override public AccessPolicy deleteAccessPolicy(final AccessPolicy policy) throws AuthorizationAccessException { throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); } @Override public Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException { throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); } @Override public UsersAndAccessPolicies getUsersAndAccessPolicies() throws AuthorizationAccessException { throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); } @Override public void initialize(final AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException { } @Override public void doOnConfigured(final AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException { } @Override public void preDestruction() throws AuthorizerDestructionException { } }; this.supportsConfigurableAuthorizer = false; } } private AccessPolicy findAccessPolicy(final RequestAction requestAction, final String resource) { return authorizer.getAccessPolicies().stream() .filter(policy -> policy.getAction().equals(requestAction) && policy.getResource().equals(resource)) .findFirst() .orElse(null); } @Override public boolean supportsConfigurableAuthorizer() { return supportsConfigurableAuthorizer; } @Override public boolean hasAccessPolicy(final String accessPolicyId) { return authorizer.getAccessPolicy(accessPolicyId) != null; } @Override public AccessPolicy createAccessPolicy(final AccessPolicyDTO accessPolicyDTO) { return authorizer.addAccessPolicy(buildAccessPolicy(accessPolicyDTO.getId(), accessPolicyDTO.getResource(), RequestAction.valueOfValue(accessPolicyDTO.getAction()), accessPolicyDTO)); } @Override public AccessPolicy getAccessPolicy(final String accessPolicyId) { final AccessPolicy accessPolicy = authorizer.getAccessPolicy(accessPolicyId); if (accessPolicy == null) { throw new ResourceNotFoundException(String.format("Unable to find access policy with id '%s'.", accessPolicyId)); } return accessPolicy; } @Override public AccessPolicy getAccessPolicy(final RequestAction requestAction, final String resource) { return findAccessPolicy(requestAction, resource); } @Override public AccessPolicy getAccessPolicy(final RequestAction requestAction, final Authorizable authorizable) { final String resource = authorizable.getResource().getIdentifier(); final AccessPolicy accessPolicy = findAccessPolicy(requestAction, authorizable.getResource().getIdentifier()); if (accessPolicy == null) { final Authorizable parentAuthorizable = authorizable.getParentAuthorizable(); if (parentAuthorizable == null) { throw new ResourceNotFoundException(String.format("Unable to find access policy for %s on %s", requestAction.toString(), resource)); } else { return getAccessPolicy(requestAction, parentAuthorizable); } } return accessPolicy; } @Override public AccessPolicy updateAccessPolicy(final AccessPolicyDTO accessPolicyDTO) { final AccessPolicy currentAccessPolicy = getAccessPolicy(accessPolicyDTO.getId()); return authorizer.updateAccessPolicy(buildAccessPolicy(currentAccessPolicy.getIdentifier(), currentAccessPolicy.getResource(), currentAccessPolicy.getAction(), accessPolicyDTO)); } @Override public AccessPolicy deleteAccessPolicy(final String accessPolicyId) { return authorizer.deleteAccessPolicy(getAccessPolicy(accessPolicyId)); } private AccessPolicy buildAccessPolicy(final String identifier, final String resource, final RequestAction action, final AccessPolicyDTO accessPolicyDTO) { final Set<TenantEntity> userGroups = accessPolicyDTO.getUserGroups(); final Set<TenantEntity> users = accessPolicyDTO.getUsers(); final AccessPolicy.Builder builder = new AccessPolicy.Builder() .identifier(identifier) .resource(resource); if (userGroups != null) { builder.addGroups(userGroups.stream().map(ComponentEntity::getId).collect(Collectors.toSet())); } if (users != null) { builder.addUsers(users.stream().map(ComponentEntity::getId).collect(Collectors.toSet())); } builder.action(action); return builder.build(); } @Override public boolean hasUserGroup(final String userGroupId) { return authorizer.getGroup(userGroupId) != null; } @Override public Group createUserGroup(final UserGroupDTO userGroupDTO) { return authorizer.addGroup(buildUserGroup(userGroupDTO.getId(), userGroupDTO)); } @Override public Group getUserGroup(final String userGroupId) { final Group userGroup = authorizer.getGroup(userGroupId); if (userGroup == null) { throw new ResourceNotFoundException(String.format("Unable to find user group with id '%s'.", userGroupId)); } return userGroup; } @Override public Set<Group> getUserGroupsForUser(String userId) { return authorizer.getGroups().stream() .filter(g -> g.getUsers().contains(userId)) .collect(Collectors.toSet()); } @Override public Set<AccessPolicy> getAccessPoliciesForUser(String userId) { return authorizer.getAccessPolicies().stream() .filter(p -> { // policy contains the user if (p.getUsers().contains(userId)) { return true; } // policy contains a group with the user return !p.getGroups().stream().filter(g -> authorizer.getGroup(g).getUsers().contains(userId)).collect(Collectors.toSet()).isEmpty(); }) .collect(Collectors.toSet()); } @Override public Set<AccessPolicy> getAccessPoliciesForUserGroup(String userGroupId) { return authorizer.getAccessPolicies().stream() .filter(p -> { // policy contains the user group return p.getGroups().contains(userGroupId); }) .collect(Collectors.toSet()); } @Override public Set<Group> getUserGroups() { return authorizer.getGroups(); } @Override public Group updateUserGroup(final UserGroupDTO userGroupDTO) { return authorizer.updateGroup(buildUserGroup(getUserGroup(userGroupDTO.getId()).getIdentifier(), userGroupDTO)); } @Override public Group deleteUserGroup(final String userGroupId) { return authorizer.deleteGroup(getUserGroup(userGroupId)); } private Group buildUserGroup(final String identifier, final UserGroupDTO userGroupDTO) { final Set<TenantEntity> users = userGroupDTO.getUsers(); final Group.Builder builder = new Group.Builder().identifier(identifier).name(userGroupDTO.getIdentity()); if (users != null) { builder.addUsers(users.stream().map(ComponentEntity::getId).collect(Collectors.toSet())); } return builder.build(); } @Override public boolean hasUser(final String userId) { return authorizer.getUser(userId) != null; } @Override public User createUser(final UserDTO userDTO) { return authorizer.addUser(buildUser(userDTO.getId(), userDTO)); } @Override public User getUser(final String userId) { final User user = authorizer.getUser(userId); if (user == null) { throw new ResourceNotFoundException(String.format("Unable to find user with id '%s'.", userId)); } return user; } @Override public Set<User> getUsers() { return authorizer.getUsers(); } @Override public User updateUser(final UserDTO userDTO) { return authorizer.updateUser(buildUser(getUser(userDTO.getId()).getIdentifier(), userDTO)); } @Override public User deleteUser(final String userId) { final User user = getUser(userId); return authorizer.deleteUser(user); } private User buildUser(final String identifier, final UserDTO userDTO) { final User.Builder builder = new User.Builder().identifier(identifier).identity(userDTO.getIdentity()); return builder.build(); } }