You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by kd...@apache.org on 2018/09/22 02:11:36 UTC
[37/51] [partial] nifi-registry git commit: NIFIREG-201 Refactoring
project structure to better isolate extensions
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AbstractPolicyBasedAuthorizer.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AbstractPolicyBasedAuthorizer.java b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AbstractPolicyBasedAuthorizer.java
new file mode 100644
index 0000000..3e721de
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AbstractPolicyBasedAuthorizer.java
@@ -0,0 +1,824 @@
+/*
+ * 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.security.authorization;
+
+import org.apache.nifi.registry.security.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.registry.security.authorization.exception.UninheritableAuthorizationsException;
+import org.apache.nifi.registry.security.exception.SecurityProviderCreationException;
+import org.apache.nifi.registry.security.exception.SecurityProviderDestructionException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * An Authorizer that provides management of users, groups, and policies.
+ */
+public abstract class AbstractPolicyBasedAuthorizer implements ManagedAuthorizer {
+
+ static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
+ static final XMLOutputFactory XML_OUTPUT_FACTORY = XMLOutputFactory.newInstance();
+
+ static final String USER_ELEMENT = "user";
+ static final String GROUP_USER_ELEMENT = "groupUser";
+ static final String GROUP_ELEMENT = "group";
+ static final String POLICY_ELEMENT = "policy";
+ static final String POLICY_USER_ELEMENT = "policyUser";
+ static final String POLICY_GROUP_ELEMENT = "policyGroup";
+ static final String IDENTIFIER_ATTR = "identifier";
+ static final String IDENTITY_ATTR = "identity";
+ static final String NAME_ATTR = "name";
+ static final String RESOURCE_ATTR = "resource";
+ static final String ACTIONS_ATTR = "actions";
+
+ @Override
+ public final void onConfigured(final AuthorizerConfigurationContext configurationContext) throws SecurityProviderCreationException {
+ doOnConfigured(configurationContext);
+ }
+
+ /**
+ * Allows sub-classes to take action when onConfigured is called.
+ *
+ * @param configurationContext the configuration context
+ * @throws SecurityProviderCreationException if an error occurs during onConfigured process
+ */
+ protected abstract void doOnConfigured(final AuthorizerConfigurationContext configurationContext) throws SecurityProviderCreationException;
+
+ @Override
+ public final AuthorizationResult authorize(AuthorizationRequest request) throws AuthorizationAccessException {
+ final UsersAndAccessPolicies usersAndAccessPolicies = getUsersAndAccessPolicies();
+ final String resourceIdentifier = request.getResource().getIdentifier();
+
+ final AccessPolicy policy = usersAndAccessPolicies.getAccessPolicy(resourceIdentifier, request.getAction());
+ if (policy == null) {
+ return AuthorizationResult.resourceNotFound();
+ }
+
+ final User user = usersAndAccessPolicies.getUser(request.getIdentity());
+ if (user == null) {
+ return AuthorizationResult.denied(String.format("Unknown user with identity '%s'.", request.getIdentity()));
+ }
+
+ final Set<Group> userGroups = usersAndAccessPolicies.getGroups(user.getIdentity());
+ if (policy.getUsers().contains(user.getIdentifier()) || containsGroup(userGroups, policy)) {
+ return AuthorizationResult.approved();
+ }
+
+ return AuthorizationResult.denied(request.getExplanationSupplier().get());
+ }
+
+ /**
+ * Determines if the policy contains one of the user's groups.
+ *
+ * @param userGroups the set of the user's groups
+ * @param policy the policy
+ * @return true if one of the Groups in userGroups is contained in the policy
+ */
+ private boolean containsGroup(final Set<Group> userGroups, final AccessPolicy policy) {
+ if (userGroups.isEmpty() || policy.getGroups().isEmpty()) {
+ return false;
+ }
+
+ for (Group userGroup : userGroups) {
+ if (policy.getGroups().contains(userGroup.getIdentifier())) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Adds a new group.
+ *
+ * @param group the Group to add
+ * @return the added Group
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ * @throws IllegalStateException if a group with the same name already exists
+ */
+ public final synchronized Group addGroup(Group group) throws AuthorizationAccessException {
+ return doAddGroup(group);
+ }
+
+ /**
+ * Adds a new group.
+ *
+ * @param group the Group to add
+ * @return the added Group
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ */
+ public abstract Group doAddGroup(Group group) throws AuthorizationAccessException;
+
+ /**
+ * Retrieves a Group by id.
+ *
+ * @param identifier the identifier of the Group to retrieve
+ * @return the Group with the given identifier, or null if no matching group was found
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ */
+ public abstract Group getGroup(String identifier) throws AuthorizationAccessException;
+
+ /**
+ * The group represented by the provided instance will be updated based on the provided instance.
+ *
+ * @param group an updated group instance
+ * @return the updated group instance, or null if no matching group was found
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ * @throws IllegalStateException if there is already a group with the same name
+ */
+ public final synchronized Group updateGroup(Group group) throws AuthorizationAccessException {
+ return doUpdateGroup(group);
+ }
+
+ /**
+ * The group represented by the provided instance will be updated based on the provided instance.
+ *
+ * @param group an updated group instance
+ * @return the updated group instance, or null if no matching group was found
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ */
+ public abstract Group doUpdateGroup(Group group) throws AuthorizationAccessException;
+
+ /**
+ * Deletes the given group.
+ *
+ * @param group the group to delete
+ * @return the deleted group, or null if no matching group was found
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ */
+ public abstract Group deleteGroup(Group group) throws AuthorizationAccessException;
+
+ /**
+ * Deletes the group with the given identifier.
+ *
+ * @param groupIdentifier the id of the group to delete
+ * @return the deleted group, or null if no matching group was found
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ */
+ public abstract Group deleteGroup(String groupIdentifier) throws AuthorizationAccessException;
+
+ /**
+ * Retrieves all groups.
+ *
+ * @return a list of groups
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ */
+ public abstract Set<Group> getGroups() throws AuthorizationAccessException;
+
+
+ /**
+ * Adds the given user.
+ *
+ * @param user the user to add
+ * @return the user that was added
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ * @throws IllegalStateException if there is already a user with the same identity
+ */
+ public final synchronized User addUser(User user) throws AuthorizationAccessException {
+ return doAddUser(user);
+ }
+
+ /**
+ * Adds the given user.
+ *
+ * @param user the user to add
+ * @return the user that was added
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ */
+ public abstract User doAddUser(User user) throws AuthorizationAccessException;
+
+ /**
+ * Retrieves the user with the given identifier.
+ *
+ * @param identifier the id of the user to retrieve
+ * @return the user with the given id, or null if no matching user was found
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ */
+ public abstract User getUser(String identifier) throws AuthorizationAccessException;
+
+ /**
+ * Retrieves the user with the given identity.
+ *
+ * @param identity the identity of the user to retrieve
+ * @return the user with the given identity, or null if no matching user was found
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ */
+ public abstract User getUserByIdentity(String identity) throws AuthorizationAccessException;
+
+ /**
+ * The user represented by the provided instance will be updated based on the provided instance.
+ *
+ * @param user an updated user instance
+ * @return the updated user instance, or null if no matching user was found
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ * @throws IllegalStateException if there is already a user with the same identity
+ */
+ public final synchronized User updateUser(final User user) throws AuthorizationAccessException {
+ return doUpdateUser(user);
+ }
+
+ /**
+ * The user represented by the provided instance will be updated based on the provided instance.
+ *
+ * @param user an updated user instance
+ * @return the updated user instance, or null if no matching user was found
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ */
+ public abstract User doUpdateUser(User user) throws AuthorizationAccessException;
+
+ /**
+ * Deletes the given user.
+ *
+ * @param user the user to delete
+ * @return the user that was deleted, or null if no matching user was found
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ */
+ public abstract User deleteUser(User user) throws AuthorizationAccessException;
+
+ /**
+ * Deletes the user with the given id.
+ *
+ * @param userIdentifier the identifier of the user to delete
+ * @return the user that was deleted, or null if no matching user was found
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ */
+ public abstract User deleteUser(String userIdentifier) throws AuthorizationAccessException;
+
+ /**
+ * Retrieves all users.
+ *
+ * @return a list of users
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ */
+ public abstract Set<User> getUsers() throws AuthorizationAccessException;
+
+ /**
+ * Adds the given policy ensuring that multiple policies can not be added for the same resource and action.
+ *
+ * @param accessPolicy the policy to add
+ * @return the policy that was added
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ */
+ public final synchronized AccessPolicy addAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException {
+ return doAddAccessPolicy(accessPolicy);
+ }
+
+ /**
+ * Adds the given policy.
+ *
+ * @param accessPolicy the policy to add
+ * @return the policy that was added
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ */
+ protected abstract AccessPolicy doAddAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException;
+
+ /**
+ * Retrieves the policy with the given identifier.
+ *
+ * @param identifier the id of the policy to retrieve
+ * @return the policy with the given id, or null if no matching policy exists
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ */
+ public abstract AccessPolicy getAccessPolicy(String identifier) throws AuthorizationAccessException;
+
+ /**
+ * The policy represented by the provided instance will be updated based on the provided instance.
+ *
+ * @param accessPolicy an updated policy
+ * @return the updated policy, or null if no matching policy was found
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ */
+ public abstract AccessPolicy updateAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException;
+
+ /**
+ * Deletes the given policy.
+ *
+ * @param policy the policy to delete
+ * @return the deleted policy, or null if no matching policy was found
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ */
+ public abstract AccessPolicy deleteAccessPolicy(AccessPolicy policy) throws AuthorizationAccessException;
+
+ /**
+ * Deletes the policy with the given id.
+ *
+ * @param policyIdentifier the id of the policy to delete
+ * @return the deleted policy, or null if no matching policy was found
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ */
+ public abstract AccessPolicy deleteAccessPolicy(String policyIdentifier) throws AuthorizationAccessException;
+
+ /**
+ * Retrieves all access policies.
+ *
+ * @return a list of policies
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ */
+ public abstract Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException;
+
+ /**
+ * Returns the UserAccessPolicies instance.
+ *
+ * @return the UserAccessPolicies instance
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ */
+ public abstract UsersAndAccessPolicies getUsersAndAccessPolicies() throws AuthorizationAccessException;
+
+ /**
+ * Returns whether the proposed fingerprint is inheritable.
+ *
+ * @param proposedFingerprint the proposed fingerprint
+ * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+ * @throws UninheritableAuthorizationsException if the proposed fingerprint was uninheritable
+ */
+ @Override
+ public final void checkInheritability(String proposedFingerprint) throws AuthorizationAccessException, UninheritableAuthorizationsException {
+ try {
+ // ensure we understand the proposed fingerprint
+ parsePoliciesUsersAndGroups(proposedFingerprint);
+ } catch (final AuthorizationAccessException e) {
+ throw new UninheritableAuthorizationsException("Unable to parse proposed fingerprint: " + e);
+ }
+
+ final List<User> users = getSortedUsers();
+ final List<Group> groups = getSortedGroups();
+ final List<AccessPolicy> accessPolicies = getSortedAccessPolicies();
+
+ // ensure we're in a state to inherit
+ if (!users.isEmpty() || !groups.isEmpty() || !accessPolicies.isEmpty()) {
+ throw new UninheritableAuthorizationsException("Proposed fingerprint is not inheritable because the current Authorizations is not empty..");
+ }
+ }
+
+ /**
+ * Parses the fingerprint and adds any users, groups, and policies to the current Authorizer.
+ *
+ * @param fingerprint the fingerprint that was obtained from calling getFingerprint() on another Authorizer.
+ */
+ @Override
+ public final void inheritFingerprint(final String fingerprint) throws AuthorizationAccessException {
+ if (fingerprint == null || fingerprint.trim().isEmpty()) {
+ return;
+ }
+
+ final PoliciesUsersAndGroups policiesUsersAndGroups = parsePoliciesUsersAndGroups(fingerprint);
+ policiesUsersAndGroups.getUsers().forEach(user -> addUser(user));
+ policiesUsersAndGroups.getGroups().forEach(group -> addGroup(group));
+ policiesUsersAndGroups.getAccessPolicies().forEach(policy -> addAccessPolicy(policy));
+ }
+
+ private PoliciesUsersAndGroups parsePoliciesUsersAndGroups(final String fingerprint) {
+ final List<AccessPolicy> accessPolicies = new ArrayList<>();
+ final List<User> users = new ArrayList<>();
+ final List<Group> groups = new ArrayList<>();
+
+ final byte[] fingerprintBytes = fingerprint.getBytes(StandardCharsets.UTF_8);
+ try (final ByteArrayInputStream in = new ByteArrayInputStream(fingerprintBytes)) {
+ final DocumentBuilder docBuilder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
+ final Document document = docBuilder.parse(in);
+ final Element rootElement = document.getDocumentElement();
+
+ // parse all the users and add them to the current authorizer
+ NodeList userNodes = rootElement.getElementsByTagName(USER_ELEMENT);
+ for (int i=0; i < userNodes.getLength(); i++) {
+ Node userNode = userNodes.item(i);
+ users.add(parseUser((Element) userNode));
+ }
+
+ // parse all the groups and add them to the current authorizer
+ NodeList groupNodes = rootElement.getElementsByTagName(GROUP_ELEMENT);
+ for (int i=0; i < groupNodes.getLength(); i++) {
+ Node groupNode = groupNodes.item(i);
+ groups.add(parseGroup((Element) groupNode));
+ }
+
+ // parse all the policies and add them to the current authorizer
+ NodeList policyNodes = rootElement.getElementsByTagName(POLICY_ELEMENT);
+ for (int i=0; i < policyNodes.getLength(); i++) {
+ Node policyNode = policyNodes.item(i);
+ accessPolicies.add(parsePolicy((Element) policyNode));
+ }
+ } catch (SAXException | ParserConfigurationException | IOException e) {
+ throw new AuthorizationAccessException("Unable to parse fingerprint", e);
+ }
+
+ return new PoliciesUsersAndGroups(accessPolicies, users, groups);
+ }
+
+ private User parseUser(final Element element) {
+ final User.Builder builder = new User.Builder()
+ .identifier(element.getAttribute(IDENTIFIER_ATTR))
+ .identity(element.getAttribute(IDENTITY_ATTR));
+
+ return builder.build();
+ }
+
+ private Group parseGroup(final Element element) {
+ final Group.Builder builder = new Group.Builder()
+ .identifier(element.getAttribute(IDENTIFIER_ATTR))
+ .name(element.getAttribute(NAME_ATTR));
+
+ NodeList groupUsers = element.getElementsByTagName(GROUP_USER_ELEMENT);
+ for (int i=0; i < groupUsers.getLength(); i++) {
+ Element groupUserNode = (Element) groupUsers.item(i);
+ builder.addUser(groupUserNode.getAttribute(IDENTIFIER_ATTR));
+ }
+
+ return builder.build();
+ }
+
+ private AccessPolicy parsePolicy(final Element element) {
+ final AccessPolicy.Builder builder = new AccessPolicy.Builder()
+ .identifier(element.getAttribute(IDENTIFIER_ATTR))
+ .resource(element.getAttribute(RESOURCE_ATTR));
+
+ final String actions = element.getAttribute(ACTIONS_ATTR);
+ if (actions.equals(RequestAction.READ.name())) {
+ builder.action(RequestAction.READ);
+ } else if (actions.equals(RequestAction.WRITE.name())) {
+ builder.action(RequestAction.WRITE);
+ } else if (actions.equals(RequestAction.DELETE.name())) {
+ builder.action(RequestAction.DELETE);
+ } else {
+ throw new IllegalStateException("Unknown Policy Action: " + actions);
+ }
+
+ NodeList policyUsers = element.getElementsByTagName(POLICY_USER_ELEMENT);
+ for (int i=0; i < policyUsers.getLength(); i++) {
+ Element policyUserNode = (Element) policyUsers.item(i);
+ builder.addUser(policyUserNode.getAttribute(IDENTIFIER_ATTR));
+ }
+
+ NodeList policyGroups = element.getElementsByTagName(POLICY_GROUP_ELEMENT);
+ for (int i=0; i < policyGroups.getLength(); i++) {
+ Element policyGroupNode = (Element) policyGroups.item(i);
+ builder.addGroup(policyGroupNode.getAttribute(IDENTIFIER_ATTR));
+ }
+
+ return builder.build();
+ }
+
+ @Override
+ public final AccessPolicyProvider getAccessPolicyProvider() {
+ return new ConfigurableAccessPolicyProvider() {
+ @Override
+ public Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException {
+ return AbstractPolicyBasedAuthorizer.this.getAccessPolicies();
+ }
+
+ @Override
+ public AccessPolicy getAccessPolicy(String identifier) throws AuthorizationAccessException {
+ return AbstractPolicyBasedAuthorizer.this.getAccessPolicy(identifier);
+ }
+
+ @Override
+ public AccessPolicy addAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException {
+ return AbstractPolicyBasedAuthorizer.this.addAccessPolicy(accessPolicy);
+ }
+
+ @Override
+ public AccessPolicy updateAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException {
+ return AbstractPolicyBasedAuthorizer.this.updateAccessPolicy(accessPolicy);
+ }
+
+ @Override
+ public AccessPolicy deleteAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException {
+ return AbstractPolicyBasedAuthorizer.this.deleteAccessPolicy(accessPolicy);
+ }
+
+ @Override
+ public AccessPolicy deleteAccessPolicy(String accessPolicyIdentifier) throws AuthorizationAccessException {
+ return AbstractPolicyBasedAuthorizer.this.deleteAccessPolicy(accessPolicyIdentifier);
+ }
+
+ @Override
+ public AccessPolicy getAccessPolicy(String resourceIdentifier, RequestAction action) throws AuthorizationAccessException {
+ final UsersAndAccessPolicies usersAndAccessPolicies = AbstractPolicyBasedAuthorizer.this.getUsersAndAccessPolicies();
+ return usersAndAccessPolicies.getAccessPolicy(resourceIdentifier, action);
+ }
+
+ @Override
+ public String getFingerprint() throws AuthorizationAccessException {
+ // fingerprint is managed by the encapsulating class
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void inheritFingerprint(String fingerprint) throws AuthorizationAccessException {
+ // fingerprint is managed by the encapsulating class
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void checkInheritability(String proposedFingerprint) throws AuthorizationAccessException, UninheritableAuthorizationsException {
+ // fingerprint is managed by the encapsulating class
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public UserGroupProvider getUserGroupProvider() {
+ return new ConfigurableUserGroupProvider() {
+ @Override
+ public User addUser(User user) throws AuthorizationAccessException {
+ return AbstractPolicyBasedAuthorizer.this.addUser(user);
+ }
+
+ @Override
+ public User updateUser(User user) throws AuthorizationAccessException {
+ return AbstractPolicyBasedAuthorizer.this.updateUser(user);
+ }
+
+ @Override
+ public User deleteUser(User user) throws AuthorizationAccessException {
+ return AbstractPolicyBasedAuthorizer.this.deleteUser(user);
+ }
+
+ @Override
+ public User deleteUser(String userIdentifier) throws AuthorizationAccessException {
+ return AbstractPolicyBasedAuthorizer.this.deleteUser(userIdentifier);
+ }
+
+ @Override
+ public Group addGroup(Group group) throws AuthorizationAccessException {
+ return AbstractPolicyBasedAuthorizer.this.addGroup(group);
+ }
+
+ @Override
+ public Group updateGroup(Group group) throws AuthorizationAccessException {
+ return AbstractPolicyBasedAuthorizer.this.updateGroup(group);
+ }
+
+ @Override
+ public Group deleteGroup(Group group) throws AuthorizationAccessException {
+ return AbstractPolicyBasedAuthorizer.this.deleteGroup(group);
+ }
+
+ @Override
+ public Group deleteGroup(String groupIdentifier) throws AuthorizationAccessException {
+ return AbstractPolicyBasedAuthorizer.this.deleteGroup(groupIdentifier);
+ }
+
+ @Override
+ public Set<User> getUsers() throws AuthorizationAccessException {
+ return AbstractPolicyBasedAuthorizer.this.getUsers();
+ }
+
+ @Override
+ public User getUser(String identifier) throws AuthorizationAccessException {
+ return AbstractPolicyBasedAuthorizer.this.getUser(identifier);
+ }
+
+ @Override
+ public User getUserByIdentity(String identity) throws AuthorizationAccessException {
+ return AbstractPolicyBasedAuthorizer.this.getUserByIdentity(identity);
+ }
+
+ @Override
+ public Set<Group> getGroups() throws AuthorizationAccessException {
+ return AbstractPolicyBasedAuthorizer.this.getGroups();
+ }
+
+ @Override
+ public Group getGroup(String identifier) throws AuthorizationAccessException {
+ return AbstractPolicyBasedAuthorizer.this.getGroup(identifier);
+ }
+
+ @Override
+ public UserAndGroups getUserAndGroups(String identity) throws AuthorizationAccessException {
+ final UsersAndAccessPolicies usersAndAccessPolicies = AbstractPolicyBasedAuthorizer.this.getUsersAndAccessPolicies();
+ final User user = usersAndAccessPolicies.getUser(identity);
+ final Set<Group> groups = usersAndAccessPolicies.getGroups(identity);
+
+ return new UserAndGroups() {
+ @Override
+ public User getUser() {
+ return user;
+ }
+
+ @Override
+ public Set<Group> getGroups() {
+ return groups;
+ }
+ };
+ }
+
+ @Override
+ public String getFingerprint() throws AuthorizationAccessException {
+ // fingerprint is managed by the encapsulating class
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void inheritFingerprint(String fingerprint) throws AuthorizationAccessException {
+ // fingerprint is managed by the encapsulating class
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void checkInheritability(String proposedFingerprint) throws AuthorizationAccessException, UninheritableAuthorizationsException {
+ // fingerprint is managed by the encapsulating class
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void initialize(UserGroupProviderInitializationContext initializationContext) throws SecurityProviderCreationException {
+ }
+
+ @Override
+ public void onConfigured(AuthorizerConfigurationContext configurationContext) throws SecurityProviderCreationException {
+ }
+
+ @Override
+ public void preDestruction() throws SecurityProviderDestructionException {
+ }
+ };
+ }
+
+ @Override
+ public void initialize(AccessPolicyProviderInitializationContext initializationContext) throws SecurityProviderCreationException {
+ }
+
+ @Override
+ public void onConfigured(AuthorizerConfigurationContext configurationContext) throws SecurityProviderCreationException {
+ }
+
+ @Override
+ public void preDestruction() throws SecurityProviderDestructionException {
+ }
+ };
+ }
+
+ /**
+ * Returns a fingerprint representing the authorizations managed by this authorizer. The fingerprint will be
+ * used for comparison to determine if two policy-based authorizers represent a compatible set of users,
+ * groups, and policies.
+ *
+ * @return the fingerprint for this Authorizer
+ */
+ @Override
+ public final String getFingerprint() throws AuthorizationAccessException {
+ final List<User> users = getSortedUsers();
+ final List<Group> groups = getSortedGroups();
+ final List<AccessPolicy> policies = getSortedAccessPolicies();
+
+ XMLStreamWriter writer = null;
+ final StringWriter out = new StringWriter();
+ try {
+ writer = XML_OUTPUT_FACTORY.createXMLStreamWriter(out);
+ writer.writeStartDocument();
+ writer.writeStartElement("authorizations");
+
+ for (User user : users) {
+ writeUser(writer, user);
+ }
+ for (Group group : groups) {
+ writeGroup(writer, group);
+ }
+ for (AccessPolicy policy : policies) {
+ writePolicy(writer, policy);
+ }
+
+ writer.writeEndElement();
+ writer.writeEndDocument();
+ writer.flush();
+ } catch (XMLStreamException e) {
+ throw new AuthorizationAccessException("Unable to generate fingerprint", e);
+ } finally {
+ if (writer != null) {
+ try {
+ writer.close();
+ } catch (XMLStreamException e) {
+ // nothing to do here
+ }
+ }
+ }
+
+ return out.toString();
+ }
+
+ private void writeUser(final XMLStreamWriter writer, final User user) throws XMLStreamException {
+ writer.writeStartElement(USER_ELEMENT);
+ writer.writeAttribute(IDENTIFIER_ATTR, user.getIdentifier());
+ writer.writeAttribute(IDENTITY_ATTR, user.getIdentity());
+ writer.writeEndElement();
+ }
+
+ private void writeGroup(final XMLStreamWriter writer, final Group group) throws XMLStreamException {
+ List<String> users = new ArrayList<>(group.getUsers());
+ Collections.sort(users);
+
+ writer.writeStartElement(GROUP_ELEMENT);
+ writer.writeAttribute(IDENTIFIER_ATTR, group.getIdentifier());
+ writer.writeAttribute(NAME_ATTR, group.getName());
+
+ for (String user : users) {
+ writer.writeStartElement(GROUP_USER_ELEMENT);
+ writer.writeAttribute(IDENTIFIER_ATTR, user);
+ writer.writeEndElement();
+ }
+
+ writer.writeEndElement();
+ }
+
+ private void writePolicy(final XMLStreamWriter writer, final AccessPolicy policy) throws XMLStreamException {
+ // sort the users for the policy
+ List<String> policyUsers = new ArrayList<>(policy.getUsers());
+ Collections.sort(policyUsers);
+
+ // sort the groups for this policy
+ List<String> policyGroups = new ArrayList<>(policy.getGroups());
+ Collections.sort(policyGroups);
+
+ writer.writeStartElement(POLICY_ELEMENT);
+ writer.writeAttribute(IDENTIFIER_ATTR, policy.getIdentifier());
+ writer.writeAttribute(RESOURCE_ATTR, policy.getResource());
+ writer.writeAttribute(ACTIONS_ATTR, policy.getAction().name());
+
+ for (String policyUser : policyUsers) {
+ writer.writeStartElement(POLICY_USER_ELEMENT);
+ writer.writeAttribute(IDENTIFIER_ATTR, policyUser);
+ writer.writeEndElement();
+ }
+
+ for (String policyGroup : policyGroups) {
+ writer.writeStartElement(POLICY_GROUP_ELEMENT);
+ writer.writeAttribute(IDENTIFIER_ATTR, policyGroup);
+ writer.writeEndElement();
+ }
+
+ writer.writeEndElement();
+ }
+
+ private List<AccessPolicy> getSortedAccessPolicies() {
+ final List<AccessPolicy> policies = new ArrayList<>(getAccessPolicies());
+ Collections.sort(policies, Comparator.comparing(AccessPolicy::getIdentifier));
+ return policies;
+ }
+
+ private List<Group> getSortedGroups() {
+ final List<Group> groups = new ArrayList<>(getGroups());
+ Collections.sort(groups, Comparator.comparing(Group::getIdentifier));
+ return groups;
+ }
+
+ private List<User> getSortedUsers() {
+ final List<User> users = new ArrayList<>(getUsers());
+ Collections.sort(users, Comparator.comparing(User::getIdentifier));
+ return users;
+ }
+
+ private static class PoliciesUsersAndGroups {
+ final List<AccessPolicy> accessPolicies;
+ final List<User> users;
+ final List<Group> groups;
+
+ public PoliciesUsersAndGroups(List<AccessPolicy> accessPolicies, List<User> users, List<Group> groups) {
+ this.accessPolicies = accessPolicies;
+ this.users = users;
+ this.groups = groups;
+ }
+
+ public List<AccessPolicy> getAccessPolicies() {
+ return accessPolicies;
+ }
+
+ public List<User> getUsers() {
+ return users;
+ }
+
+ public List<Group> getGroups() {
+ return groups;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AuthorizableLookup.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AuthorizableLookup.java b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AuthorizableLookup.java
new file mode 100644
index 0000000..49db37a
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AuthorizableLookup.java
@@ -0,0 +1,84 @@
+/*
+ * 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.security.authorization;
+
+import org.apache.nifi.registry.security.authorization.resource.Authorizable;
+
+public interface AuthorizableLookup {
+
+ /**
+ * Get the authorizable for /actuator.
+ *
+ * @return authorizable
+ */
+ Authorizable getActuatorAuthorizable();
+
+ /**
+ * Get the authorizable for /swagger.
+ *
+ * @return authorizable
+ */
+ Authorizable getSwaggerAuthorizable();
+
+ /**
+ * Get the authorizable for /proxy.
+ *
+ * @return authorizable
+ */
+ Authorizable getProxyAuthorizable();
+
+ /**
+ * Get the authorizable for all tenants.
+ *
+ * Get the {@link Authorizable} that represents the resource of users and user groups.
+ * @return authorizable
+ */
+ Authorizable getTenantsAuthorizable();
+
+ /**
+ * Get the authorizable for all access policies.
+ *
+ * @return authorizable
+ */
+ Authorizable getPoliciesAuthorizable();
+
+ /**
+ * Get the authorizable for all Buckets.
+ *
+ * @return authorizable
+ */
+ Authorizable getBucketsAuthorizable();
+
+ /**
+ * Get the authorizable for the Bucket with the bucket id.
+ *
+ * @param bucketIdentifier bucket id
+ * @return authorizable
+ */
+ Authorizable getBucketAuthorizable(String bucketIdentifier);
+
+ /**
+ * Get the authorizable of the specified resource.
+ * If the resource is authorized by its base/top-level
+ * resource type, the authorizable for the base type will be returned.
+ *
+ * @param resource resource
+ * @return authorizable
+ */
+ Authorizable getAuthorizableByResource(final String resource);
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AuthorizerCapabilityDetection.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AuthorizerCapabilityDetection.java b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AuthorizerCapabilityDetection.java
new file mode 100644
index 0000000..0652583
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AuthorizerCapabilityDetection.java
@@ -0,0 +1,75 @@
+/*
+ * 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.security.authorization;
+
+public final class AuthorizerCapabilityDetection {
+
+ public static boolean isManagedAuthorizer(final Authorizer authorizer) {
+ return authorizer instanceof ManagedAuthorizer;
+ }
+
+ public static boolean isConfigurableAccessPolicyProvider(final Authorizer authorizer) {
+ if (!isManagedAuthorizer(authorizer)) {
+ return false;
+ }
+
+ final ManagedAuthorizer managedAuthorizer = (ManagedAuthorizer) authorizer;
+ return managedAuthorizer.getAccessPolicyProvider() instanceof ConfigurableAccessPolicyProvider;
+ }
+
+ public static boolean isConfigurableUserGroupProvider(final Authorizer authorizer) {
+ if (!isManagedAuthorizer(authorizer)) {
+ return false;
+ }
+
+ final ManagedAuthorizer managedAuthorizer = (ManagedAuthorizer) authorizer;
+ final AccessPolicyProvider accessPolicyProvider = managedAuthorizer.getAccessPolicyProvider();
+ return accessPolicyProvider.getUserGroupProvider() instanceof ConfigurableUserGroupProvider;
+ }
+
+ public static boolean isUserConfigurable(final Authorizer authorizer, final User user) {
+ if (!isConfigurableUserGroupProvider(authorizer)) {
+ return false;
+ }
+
+ final ManagedAuthorizer managedAuthorizer = (ManagedAuthorizer) authorizer;
+ final ConfigurableUserGroupProvider configurableUserGroupProvider = (ConfigurableUserGroupProvider) managedAuthorizer.getAccessPolicyProvider().getUserGroupProvider();
+ return configurableUserGroupProvider.isConfigurable(user);
+ }
+
+ public static boolean isGroupConfigurable(final Authorizer authorizer, final Group group) {
+ if (!isConfigurableUserGroupProvider(authorizer)) {
+ return false;
+ }
+
+ final ManagedAuthorizer managedAuthorizer = (ManagedAuthorizer) authorizer;
+ final ConfigurableUserGroupProvider configurableUserGroupProvider = (ConfigurableUserGroupProvider) managedAuthorizer.getAccessPolicyProvider().getUserGroupProvider();
+ return configurableUserGroupProvider.isConfigurable(group);
+ }
+
+ public static boolean isAccessPolicyConfigurable(final Authorizer authorizer, final AccessPolicy accessPolicy) {
+ if (!isConfigurableAccessPolicyProvider(authorizer)) {
+ return false;
+ }
+
+ final ManagedAuthorizer managedAuthorizer = (ManagedAuthorizer) authorizer;
+ final ConfigurableAccessPolicyProvider configurableAccessPolicyProvider = (ConfigurableAccessPolicyProvider) managedAuthorizer.getAccessPolicyProvider();
+ return configurableAccessPolicyProvider.isConfigurable(accessPolicy);
+ }
+
+ private AuthorizerCapabilityDetection() {}
+}