You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by jo...@apache.org on 2016/07/14 22:33:11 UTC
[05/10] nifi git commit: NIFI-1896 This closes #650. Refactored
nifi-api into nifi-framework-api and other locations. The nifi-api is
specific to that which is needed for intended extension points.
http://git-wip-us.apache.org/repos/asf/nifi/blob/d1129706/nifi-framework-api/src/main/java/org/apache/nifi/authentication/exception/ProviderDestructionException.java
----------------------------------------------------------------------
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authentication/exception/ProviderDestructionException.java b/nifi-framework-api/src/main/java/org/apache/nifi/authentication/exception/ProviderDestructionException.java
new file mode 100644
index 0000000..1e12146
--- /dev/null
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/authentication/exception/ProviderDestructionException.java
@@ -0,0 +1,39 @@
+/*
+ * 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.authentication.exception;
+
+/**
+ * Represents the exceptional case when an AuthorityProvider fails destruction.
+ *
+ */
+public class ProviderDestructionException extends RuntimeException {
+
+ public ProviderDestructionException() {
+ }
+
+ public ProviderDestructionException(String msg) {
+ super(msg);
+ }
+
+ public ProviderDestructionException(Throwable cause) {
+ super(cause);
+ }
+
+ public ProviderDestructionException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d1129706/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AbstractPolicyBasedAuthorizer.java
----------------------------------------------------------------------
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AbstractPolicyBasedAuthorizer.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AbstractPolicyBasedAuthorizer.java
new file mode 100644
index 0000000..8fbe0fb
--- /dev/null
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AbstractPolicyBasedAuthorizer.java
@@ -0,0 +1,552 @@
+/*
+ * 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.authorization;
+
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.authorization.exception.AuthorizerCreationException;
+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 Authorizer {
+
+ 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";
+
+ public static final String EMPTY_FINGERPRINT = "EMPTY";
+
+ @Override
+ public final void onConfigured(final AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
+ doOnConfigured(configurationContext);
+
+ // ensure that only one policy per resource-action exists
+ for (AccessPolicy accessPolicy : getAccessPolicies()) {
+ if (policyExists(accessPolicy)) {
+ throw new AuthorizerCreationException("Found multiple policies for " + accessPolicy.getResource()
+ + " with " + accessPolicy.getAction());
+ }
+ }
+ }
+
+ /**
+ * Allows sub-classes to take action when onConfigured is called.
+ *
+ * @param configurationContext the configuration context
+ * @throws AuthorizerCreationException if an error occurs during onConfigured process
+ */
+ protected abstract void doOnConfigured(final AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException;
+
+ /**
+ * Checks if another policy exists with the same resource and action as the given policy.
+ *
+ * @param checkAccessPolicy an access policy being checked
+ * @return true if another access policy exists with the same resource and action, false otherwise
+ */
+ private boolean policyExists(final AccessPolicy checkAccessPolicy) {
+ for (AccessPolicy accessPolicy : getAccessPolicies()) {
+ if (!accessPolicy.getIdentifier().equals(checkAccessPolicy.getIdentifier())
+ && accessPolicy.getResource().equals(checkAccessPolicy.getResource())
+ && accessPolicy.getAction().equals(checkAccessPolicy.getAction())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @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("Unknown user with identity " + 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();
+ }
+
+ /**
+ * 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
+ */
+ public abstract Group addGroup(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
+ */
+ public abstract Group updateGroup(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;
+
+ /**
+ * 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
+ */
+ public abstract User addUser(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
+ */
+ public abstract User updateUser(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;
+
+ /**
+ * 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 {
+ if (policyExists(accessPolicy)) {
+ throw new IllegalStateException("Found multiple policies for " + accessPolicy.getResource()
+ + " with " + accessPolicy.getAction());
+ }
+ 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;
+
+ /**
+ * 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;
+
+ /**
+ * 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.
+ */
+ public final void inheritFingerprint(final String fingerprint) throws AuthorizationAccessException {
+ if (fingerprint == null || fingerprint.trim().isEmpty()) {
+ return;
+ }
+
+ 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);
+ User user = parseUser((Element) userNode);
+ addUser(user);
+ }
+
+ // 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);
+ Group group = parseGroup((Element) groupNode);
+ addGroup(group);
+ }
+
+ // 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);
+ AccessPolicy policy = parsePolicy((Element) policyNode);
+ addAccessPolicy(policy);
+ }
+
+ } catch (SAXException | ParserConfigurationException | IOException e) {
+ throw new AuthorizationAccessException("Unable to parse fingerprint", e);
+ }
+ }
+
+ 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 {
+ 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();
+ }
+
+ /**
+ * 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
+ */
+ public final String getFingerprint() throws AuthorizationAccessException {
+ final List<User> users = getSortedUsers();
+ final List<Group> groups = getSortedGroups();
+ final List<AccessPolicy> policies = getSortedAccessPolicies();
+
+ // when there are no users, groups, policies we want to always return a simple indicator so
+ // it can easily be determined when comparing fingerprints
+ if (users.isEmpty() && groups.isEmpty() && policies.isEmpty()) {
+ return EMPTY_FINGERPRINT;
+ }
+
+ 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, new Comparator<AccessPolicy>() {
+ @Override
+ public int compare(AccessPolicy p1, AccessPolicy p2) {
+ return p1.getIdentifier().compareTo(p2.getIdentifier());
+ }
+ });
+ return policies;
+ }
+
+ private List<Group> getSortedGroups() {
+ final List<Group> groups = new ArrayList<>(getGroups());
+
+ Collections.sort(groups, new Comparator<Group>() {
+ @Override
+ public int compare(Group g1, Group g2) {
+ return g1.getIdentifier().compareTo(g2.getIdentifier());
+ }
+ });
+ return groups;
+ }
+
+ private List<User> getSortedUsers() {
+ final List<User> users = new ArrayList<>(getUsers());
+
+ Collections.sort(users, new Comparator<User>() {
+ @Override
+ public int compare(User u1, User u2) {
+ return u1.getIdentifier().compareTo(u2.getIdentifier());
+ }
+ });
+ return users;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d1129706/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java
----------------------------------------------------------------------
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java
new file mode 100644
index 0000000..8712d28
--- /dev/null
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java
@@ -0,0 +1,39 @@
+/*
+ * 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.authorization;
+
+/**
+ * Represents any error that might occur while authorizing user requests.
+ */
+public class AccessDeniedException extends RuntimeException {
+ private static final long serialVersionUID = -5683444815269084134L;
+
+ public AccessDeniedException(Throwable cause) {
+ super(cause);
+ }
+
+ public AccessDeniedException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public AccessDeniedException(String message) {
+ super(message);
+ }
+
+ public AccessDeniedException() {
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d1129706/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AccessPolicy.java
----------------------------------------------------------------------
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AccessPolicy.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AccessPolicy.java
new file mode 100644
index 0000000..93cabb2
--- /dev/null
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AccessPolicy.java
@@ -0,0 +1,330 @@
+/*
+ * 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.authorization;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Defines a policy for a set of userIdentifiers to perform a set of actions on a given resource.
+ */
+public class AccessPolicy {
+
+ private final String identifier;
+
+ private final String resource;
+
+ private final Set<String> users;
+
+ private final Set<String> groups;
+
+ private final RequestAction action;
+
+ private AccessPolicy(final Builder builder) {
+ this.identifier = builder.identifier;
+ this.resource = builder.resource;
+ this.action = builder.action;
+ this.users = Collections.unmodifiableSet(new HashSet<>(builder.users));
+ this.groups = Collections.unmodifiableSet(new HashSet<>(builder.groups));
+
+ if (this.identifier == null || this.identifier.trim().isEmpty()) {
+ throw new IllegalArgumentException("Identifier can not be null or empty");
+ }
+
+ if (this.resource == null) {
+ throw new IllegalArgumentException("Resource can not be null");
+ }
+
+ if (this.action == null) {
+ throw new IllegalArgumentException("Action can not be null");
+ }
+ }
+
+ /**
+ * @return the identifier for this policy
+ */
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ /**
+ * @return the resource for this policy
+ */
+ public String getResource() {
+ return resource;
+ }
+
+ /**
+ * @return an unmodifiable set of user ids for this policy
+ */
+ public Set<String> getUsers() {
+ return users;
+ }
+
+ /**
+ * @return an unmodifiable set of group ids for this policy
+ */
+ public Set<String> getGroups() {
+ return groups;
+ }
+
+ /**
+ * @return the action for this policy
+ */
+ public RequestAction getAction() {
+ return action;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ final AccessPolicy other = (AccessPolicy) obj;
+ return Objects.equals(this.identifier, other.identifier);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(this.identifier);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("identifier[%s], resource[%s], users[%s], groups[%s], action[%s]",
+ getIdentifier(), getResource(), getUsers(), getGroups(), getAction());
+ }
+
+ /**
+ * Builder for Access Policies.
+ */
+ public static class Builder {
+
+ private String identifier;
+ private String resource;
+ private RequestAction action;
+ private Set<String> users = new HashSet<>();
+ private Set<String> groups = new HashSet<>();
+ private final boolean fromPolicy;
+
+ /**
+ * Default constructor for building a new AccessPolicy.
+ */
+ public Builder() {
+ this.fromPolicy = false;
+ }
+
+ /**
+ * Initializes the builder with the state of the provided policy. When using this constructor
+ * the identifier field of the builder can not be changed and will result in an IllegalStateException
+ * if attempting to do so.
+ *
+ * @param other the existing access policy to initialize from
+ */
+ public Builder(final AccessPolicy other) {
+ if (other == null) {
+ throw new IllegalArgumentException("Can not initialize builder with a null access policy");
+ }
+
+ this.identifier = other.getIdentifier();
+ this.resource = other.getResource();
+ this.action = other.getAction();
+ this.users.clear();
+ this.users.addAll(other.getUsers());
+ this.groups.clear();
+ this.groups.addAll(other.getGroups());
+ this.fromPolicy = true;
+ }
+
+ /**
+ * Sets the identifier of the builder.
+ *
+ * @param identifier the identifier to set
+ * @return the builder
+ * @throws IllegalStateException if this method is called when this builder was constructed from an existing Policy
+ */
+ public Builder identifier(final String identifier) {
+ if (fromPolicy) {
+ throw new IllegalStateException(
+ "Identifier can not be changed when initialized from an existing policy");
+ }
+
+ this.identifier = identifier;
+ return this;
+ }
+
+ /**
+ * Sets the resource of the builder.
+ *
+ * @param resource the resource to set
+ * @return the builder
+ */
+ public Builder resource(final String resource) {
+ this.resource = resource;
+ return this;
+ }
+
+ /**
+ * Adds all the users from the provided set to the builder's set of users.
+ *
+ * @param users the users to add
+ * @return the builder
+ */
+ public Builder addUsers(final Set<String> users) {
+ if (users != null) {
+ this.users.addAll(users);
+ }
+ return this;
+ }
+
+ /**
+ * Adds the given user to the builder's set of users.
+ *
+ * @param user the user to add
+ * @return the builder
+ */
+ public Builder addUser(final String user) {
+ if (user != null) {
+ this.users.add(user);
+ }
+ return this;
+ }
+
+ /**
+ * Removes all users in the provided set from the builder's set of users.
+ *
+ * @param users the users to remove
+ * @return the builder
+ */
+ public Builder removeUsers(final Set<String> users) {
+ if (users != null) {
+ this.users.removeAll(users);
+ }
+ return this;
+ }
+
+ /**
+ * Removes the provided user from the builder's set of users.
+ *
+ * @param user the user to remove
+ * @return the builder
+ */
+ public Builder removeUser(final String user) {
+ if (user != null) {
+ this.users.remove(user);
+ }
+ return this;
+ }
+
+ /**
+ * Clears the builder's set of users so that it is non-null and size == 0.
+ *
+ * @return the builder
+ */
+ public Builder clearUsers() {
+ this.users.clear();
+ return this;
+ }
+
+ /**
+ * Adds all the groups from the provided set to the builder's set of groups.
+ *
+ * @param groups the groups to add
+ * @return the builder
+ */
+ public Builder addGroups(final Set<String> groups) {
+ if (groups != null) {
+ this.groups.addAll(groups);
+ }
+ return this;
+ }
+
+ /**
+ * Adds the given group to the builder's set of groups.
+ *
+ * @param group the group to add
+ * @return the builder
+ */
+ public Builder addGroup(final String group) {
+ if (group != null) {
+ this.groups.add(group);
+ }
+ return this;
+ }
+
+ /**
+ * Removes all groups in the provided set from the builder's set of groups.
+ *
+ * @param groups the groups to remove
+ * @return the builder
+ */
+ public Builder removeGroups(final Set<String> groups) {
+ if (groups != null) {
+ this.groups.removeAll(groups);
+ }
+ return this;
+ }
+
+ /**
+ * Removes the provided groups from the builder's set of groups.
+ *
+ * @param group the group to remove
+ * @return the builder
+ */
+ public Builder removeGroup(final String group) {
+ if (group != null) {
+ this.groups.remove(group);
+ }
+ return this;
+ }
+
+ /**
+ * Clears the builder's set of groups so that it is non-null and size == 0.
+ *
+ * @return the builder
+ */
+ public Builder clearGroups() {
+ this.groups.clear();
+ return this;
+ }
+
+ /**
+ * Sets the action for this builder.
+ *
+ * @param action the action to set
+ * @return the builder
+ */
+ public Builder action(final RequestAction action) {
+ this.action = action;
+ return this;
+ }
+
+ /**
+ * @return a new AccessPolicy constructed from the state of the builder
+ */
+ public AccessPolicy build() {
+ return new AccessPolicy(this);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d1129706/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AuthorizationRequest.java
----------------------------------------------------------------------
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AuthorizationRequest.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AuthorizationRequest.java
new file mode 100644
index 0000000..da0a276
--- /dev/null
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AuthorizationRequest.java
@@ -0,0 +1,171 @@
+/*
+ * 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.authorization;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Represents an authorization request for a given user/entity performing an action against a resource within some userContext.
+ */
+public class AuthorizationRequest {
+
+ private final Resource resource;
+ private final String identity;
+ private final RequestAction action;
+ private final boolean isAccessAttempt;
+ private final boolean isAnonymous;
+ private final Map<String, String> userContext;
+ private final Map<String, String> resourceContext;
+
+ private AuthorizationRequest(final Builder builder) {
+ Objects.requireNonNull(builder.resource, "The resource is required when creating an authorization request");
+ Objects.requireNonNull(builder.action, "The action is required when creating an authorization request");
+ Objects.requireNonNull(builder.isAccessAttempt, "Whether this request is an access attempt is request");
+ Objects.requireNonNull(builder.isAnonymous, "Whether this request is being performed by an anonymous user is required");
+
+ this.resource = builder.resource;
+ this.identity = builder.identity;
+ this.action = builder.action;
+ this.isAccessAttempt = builder.isAccessAttempt;
+ this.isAnonymous = builder.isAnonymous;
+ this.userContext = builder.userContext == null ? null : Collections.unmodifiableMap(builder.userContext);
+ this.resourceContext = builder.resourceContext == null ? null : Collections.unmodifiableMap(builder.resourceContext);
+ }
+
+ /**
+ * The Resource being authorized. Not null.
+ *
+ * @return The resource
+ */
+ public Resource getResource() {
+ return resource;
+ }
+
+ /**
+ * The identity accessing the Resource. May be null if the user could not authenticate.
+ *
+ * @return The identity
+ */
+ public String getIdentity() {
+ return identity;
+ }
+
+ /**
+ * Whether this is a direct access attempt of the Resource if if it's being checked as part of another response.
+ *
+ * @return if this is a direct access attempt
+ */
+ public boolean isAccessAttempt() {
+ return isAccessAttempt;
+ }
+
+ /**
+ * Whether the entity accessing is anonymous.
+ *
+ * @return whether the entity is anonymous
+ */
+ public boolean isAnonymous() {
+ return isAnonymous;
+ }
+
+ /**
+ * The action being taken against the Resource. Not null.
+ *
+ * @return The action
+ */
+ public RequestAction getAction() {
+ return action;
+ }
+
+ /**
+ * The userContext of the user request to make additional access decisions. May be null.
+ *
+ * @return The userContext of the user request
+ */
+ public Map<String, String> getUserContext() {
+ return userContext;
+ }
+
+ /**
+ * The event attributes to make additional access decisions for provenance events. May be null.
+ *
+ * @return The event attributes
+ */
+ public Map<String, String> getResourceContext() {
+ return resourceContext;
+ }
+
+ /**
+ * AuthorizationRequest builder.
+ */
+ public static final class Builder {
+
+ private Resource resource;
+ private String identity;
+ private Boolean isAnonymous;
+ private Boolean isAccessAttempt;
+ private RequestAction action;
+ private Map<String, String> userContext;
+ private Map<String, String> resourceContext;
+
+ public Builder resource(final Resource resource) {
+ this.resource = resource;
+ return this;
+ }
+
+ public Builder identity(final String identity) {
+ this.identity = identity;
+ return this;
+ }
+
+ public Builder anonymous(final Boolean isAnonymous) {
+ this.isAnonymous = isAnonymous;
+ return this;
+ }
+
+ public Builder accessAttempt(final Boolean isAccessAttempt) {
+ this.isAccessAttempt = isAccessAttempt;
+ return this;
+ }
+
+ public Builder action(final RequestAction action) {
+ this.action = action;
+ return this;
+ }
+
+ public Builder userContext(final Map<String, String> userContext) {
+ if (userContext != null) {
+ this.userContext = new HashMap<>(userContext);
+ }
+ return this;
+ }
+
+ public Builder resourceContext(final Map<String, String> resourceContext) {
+ if (resourceContext != null) {
+ this.resourceContext = new HashMap<>(resourceContext);
+ }
+ return this;
+ }
+
+ public AuthorizationRequest build() {
+ return new AuthorizationRequest(this);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d1129706/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AuthorizationResult.java
----------------------------------------------------------------------
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AuthorizationResult.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AuthorizationResult.java
new file mode 100644
index 0000000..a3f520c
--- /dev/null
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AuthorizationResult.java
@@ -0,0 +1,99 @@
+/*
+ * 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.authorization;
+
+/**
+ * Represents a decision whether authorization is granted.
+ */
+public class AuthorizationResult {
+
+ public enum Result {
+ Approved,
+ Denied,
+ ResourceNotFound
+ }
+
+ private static final AuthorizationResult APPROVED = new AuthorizationResult(Result.Approved, null);
+ private static final AuthorizationResult RESOURCE_NOT_FOUND = new AuthorizationResult(Result.ResourceNotFound, null);
+
+ private final Result result;
+ private final String explanation;
+
+ /**
+ * Creates a new AuthorizationResult with the specified result and explanation.
+ *
+ * @param result of the authorization
+ * @param explanation for the authorization attempt
+ */
+ private AuthorizationResult(Result result, String explanation) {
+ if (Result.Denied.equals(result) && explanation == null) {
+ throw new IllegalArgumentException("An explanation is required when the authorization request is denied.");
+ }
+
+ this.result = result;
+ this.explanation = explanation;
+ }
+
+ /**
+ * @return Whether or not the request is approved
+ */
+ public Result getResult() {
+ return result;
+ }
+
+ /**
+ * @return If the request is denied, the reason why. Null otherwise
+ */
+ public String getExplanation() {
+ return explanation;
+ }
+
+ /**
+ * @return a new approved AuthorizationResult
+ */
+ public static AuthorizationResult approved() {
+ return APPROVED;
+ }
+
+ /**
+ * Resource not found will indicate that there are no specific authorization rules for this resource.
+ * @return a new resource not found AuthorizationResult
+ */
+ public static AuthorizationResult resourceNotFound() {
+ return RESOURCE_NOT_FOUND;
+ }
+
+ /**
+ * Creates a new denied AuthorizationResult with a message indicating 'Access is denied'.
+ *
+ * @return a new denied AuthorizationResult
+ */
+ public static AuthorizationResult denied() {
+ return denied("Access is denied");
+ }
+
+ /**
+ * Creates a new denied AuthorizationResult with the specified explanation.
+ *
+ * @param explanation for why it was denied
+ * @return a new denied AuthorizationResult with the specified explanation
+ * @throws IllegalArgumentException if explanation is null
+ */
+ public static AuthorizationResult denied(String explanation) {
+ return new AuthorizationResult(Result.Denied, explanation);
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d1129706/nifi-framework-api/src/main/java/org/apache/nifi/authorization/Authorizer.java
----------------------------------------------------------------------
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/Authorizer.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/Authorizer.java
new file mode 100644
index 0000000..cb8c7f1
--- /dev/null
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/Authorizer.java
@@ -0,0 +1,59 @@
+/*
+ * 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.authorization;
+
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.authorization.exception.AuthorizerCreationException;
+import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
+
+/**
+ * Authorizes user requests.
+ */
+public interface Authorizer {
+
+ /**
+ * Determines if the specified user/entity is authorized to access the specified resource within the given context.
+ *
+ * @param request The authorization request
+ * @return the authorization result
+ * @throws AuthorizationAccessException if unable to access the policies
+ */
+ AuthorizationResult authorize(AuthorizationRequest request) throws AuthorizationAccessException;
+
+ /**
+ * Called immediately after instance creation for implementers to perform additional setup
+ *
+ * @param initializationContext in which to initialize
+ */
+ void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException;
+
+ /**
+ * Called to configure the Authorizer.
+ *
+ * @param configurationContext at the time of configuration
+ * @throws AuthorizerCreationException for any issues configuring the provider
+ */
+ void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException;
+
+ /**
+ * Called immediately before instance destruction for implementers to release resources.
+ *
+ * @throws AuthorizerDestructionException If pre-destruction fails.
+ */
+ void preDestruction() throws AuthorizerDestructionException;
+
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d1129706/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AuthorizerConfigurationContext.java
----------------------------------------------------------------------
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AuthorizerConfigurationContext.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AuthorizerConfigurationContext.java
new file mode 100644
index 0000000..3721ab4
--- /dev/null
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AuthorizerConfigurationContext.java
@@ -0,0 +1,50 @@
+/*
+ * 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.authorization;
+
+import org.apache.nifi.components.PropertyValue;
+
+import java.util.Map;
+
+/**
+ *
+ */
+public interface AuthorizerConfigurationContext {
+
+ /**
+ * @return identifier for the authorizer
+ */
+ String getIdentifier();
+
+ /**
+ * Retrieves all properties the component currently understands regardless
+ * of whether a value has been set for them or not. If no value is present
+ * then its value is null and thus any registered default for the property
+ * descriptor applies.
+ *
+ * @return Map of all properties
+ */
+ Map<String, String> getProperties();
+
+ /**
+ * @param property to lookup the descriptor and value of
+ * @return the value the component currently understands for the given
+ * PropertyDescriptor. This method does not substitute default
+ * PropertyDescriptor values, so the value returned will be null if not set
+ */
+ PropertyValue getProperty(String property);
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d1129706/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AuthorizerInitializationContext.java
----------------------------------------------------------------------
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AuthorizerInitializationContext.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AuthorizerInitializationContext.java
new file mode 100644
index 0000000..4b3d77c
--- /dev/null
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AuthorizerInitializationContext.java
@@ -0,0 +1,37 @@
+/*
+ * 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.authorization;
+
+/**
+ * Initialization content for Authorizers.
+ */
+public interface AuthorizerInitializationContext {
+
+ /**
+ * The identifier of the Authorizer.
+ *
+ * @return The identifier
+ */
+ public String getIdentifier();
+
+ /**
+ * The lookup for accessing other configured Authorizers.
+ *
+ * @return The Authorizer lookup
+ */
+ public AuthorizerLookup getAuthorizerLookup();
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d1129706/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AuthorizerLookup.java
----------------------------------------------------------------------
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AuthorizerLookup.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AuthorizerLookup.java
new file mode 100644
index 0000000..9669976
--- /dev/null
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AuthorizerLookup.java
@@ -0,0 +1,31 @@
+/*
+ * 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.authorization;
+
+/**
+ *
+ */
+public interface AuthorizerLookup {
+
+ /**
+ * Looks up the Authorizer with the specified identifier
+ *
+ * @param identifier The identifier of the Authorizer
+ * @return The Authorizer
+ */
+ Authorizer getAuthorizer(String identifier);
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d1129706/nifi-framework-api/src/main/java/org/apache/nifi/authorization/Group.java
----------------------------------------------------------------------
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/Group.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/Group.java
new file mode 100644
index 0000000..7db619a
--- /dev/null
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/Group.java
@@ -0,0 +1,226 @@
+/*
+ * 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.authorization;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * A group that users can belong to.
+ */
+public class Group { // TODO rename to UserGroup
+
+ private final String identifier;
+
+ private final String name;
+
+ private final Set<String> users;
+
+ private Group(final Builder builder) {
+ this.identifier = builder.identifier;
+ this.name = builder.name;
+ this.users = Collections.unmodifiableSet(new HashSet<>(builder.users));
+
+ if (this.identifier == null || this.identifier.trim().isEmpty()) {
+ throw new IllegalArgumentException("Identifier can not be null or empty");
+ }
+
+ if (this.name == null || this.name.trim().isEmpty()) {
+ throw new IllegalArgumentException("Name can not be null or empty");
+ }
+ }
+
+ /**
+ * @return the identifier of the group
+ */
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ /**
+ * @return the name of the group
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @return an unmodifiable set of user identifiers that belong to this group
+ */
+ public Set<String> getUsers() {
+ return users;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ final Group other = (Group) obj;
+ return Objects.equals(this.identifier, other.identifier);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(this.identifier);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("identifier[%s], name[%s]", getIdentifier(), getName());
+ }
+
+
+ /**
+ * Builder for creating Groups.
+ */
+ public static class Builder {
+
+ private String identifier;
+ private String name;
+ private Set<String> users = new HashSet<>();
+ private final boolean fromGroup;
+
+ public Builder() {
+ this.fromGroup = false;
+ }
+
+ /**
+ * Initializes the builder with the state of the provided group. When using this constructor
+ * the identifier field of the builder can not be changed and will result in an IllegalStateException
+ * if attempting to do so.
+ *
+ * @param other the existing access policy to initialize from
+ */
+ public Builder(final Group other) {
+ if (other == null) {
+ throw new IllegalArgumentException("Provided group can not be null");
+ }
+
+ this.identifier = other.getIdentifier();
+ this.name = other.getName();
+ this.users.clear();
+ this.users.addAll(other.getUsers());
+ this.fromGroup = true;
+ }
+
+ /**
+ * Sets the identifier of the builder.
+ *
+ * @param identifier the identifier
+ * @return the builder
+ * @throws IllegalStateException if this method is called when this builder was constructed from an existing Group
+ */
+ public Builder identifier(final String identifier) {
+ if (fromGroup) {
+ throw new IllegalStateException(
+ "Identifier can not be changed when initialized from an existing group");
+ }
+
+ this.identifier = identifier;
+ return this;
+ }
+
+ /**
+ * Sets the name of the builder.
+ *
+ * @param name the name
+ * @return the builder
+ */
+ public Builder name(final String name) {
+ this.name = name;
+ return this;
+ }
+
+ /**
+ * Adds all users from the provided set to the builder's set of users.
+ *
+ * @param users a set of users to add
+ * @return the builder
+ */
+ public Builder addUsers(final Set<String> users) {
+ if (users != null) {
+ this.users.addAll(users);
+ }
+ return this;
+ }
+
+ /**
+ * Adds the given user to the builder's set of users.
+ *
+ * @param user the user to add
+ * @return the builder
+ */
+ public Builder addUser(final String user) {
+ if (user != null) {
+ this.users.add(user);
+ }
+ return this;
+ }
+
+ /**
+ * Removes the given user from the builder's set of users.
+ *
+ * @param user the user to remove
+ * @return the builder
+ */
+ public Builder removeUser(final String user) {
+ if (user != null) {
+ this.users.remove(user);
+ }
+ return this;
+ }
+
+ /**
+ * Removes all users from the provided set from the builder's set of users.
+ *
+ * @param users the users to remove
+ * @return the builder
+ */
+ public Builder removeUsers(final Set<String> users) {
+ if (users != null) {
+ this.users.removeAll(users);
+ }
+ return this;
+ }
+
+ /**
+ * Clears the builder's set of users so that users is non-null with size 0.
+ *
+ * @return the builder
+ */
+ public Builder clearUsers() {
+ this.users.clear();
+ return this;
+ }
+
+ /**
+ * @return a new Group constructed from the state of the builder
+ */
+ public Group build() {
+ return new Group(this);
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d1129706/nifi-framework-api/src/main/java/org/apache/nifi/authorization/RequestAction.java
----------------------------------------------------------------------
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/RequestAction.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/RequestAction.java
new file mode 100644
index 0000000..3e28a67
--- /dev/null
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/RequestAction.java
@@ -0,0 +1,46 @@
+/*
+ * 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.authorization;
+
+/**
+ * Actions a user/entity can take on a resource.
+ */
+public enum RequestAction {
+ READ("read"),
+ WRITE("write");
+
+ private String value;
+
+ RequestAction(String value) {
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+ return value.toLowerCase();
+ }
+
+ public static RequestAction valueOfValue(final String action) {
+ if (RequestAction.READ.toString().equals(action)) {
+ return RequestAction.READ;
+ } else if (RequestAction.WRITE.toString().equals(action)) {
+ return RequestAction.WRITE;
+ } else {
+ throw new IllegalArgumentException("Action must be one of [" + READ.toString() + ", " + WRITE.toString() + "]");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d1129706/nifi-framework-api/src/main/java/org/apache/nifi/authorization/Resource.java
----------------------------------------------------------------------
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/Resource.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/Resource.java
new file mode 100644
index 0000000..661b326
--- /dev/null
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/Resource.java
@@ -0,0 +1,37 @@
+/*
+ * 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.authorization;
+
+/**
+ * Resource in an authorization request.
+ */
+public interface Resource {
+
+ /**
+ * The identifier for this resource.
+ *
+ * @return identifier for this resource
+ */
+ String getIdentifier();
+
+ /**
+ * The name of this resource. May be null.
+ *
+ * @return name of this resource
+ */
+ String getName();
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d1129706/nifi-framework-api/src/main/java/org/apache/nifi/authorization/User.java
----------------------------------------------------------------------
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/User.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/User.java
new file mode 100644
index 0000000..371241b
--- /dev/null
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/User.java
@@ -0,0 +1,151 @@
+/*
+ * 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.authorization;
+
+import java.util.Objects;
+
+/**
+ * A user to create authorization policies for.
+ */
+public class User {
+
+ private final String identifier;
+
+ private final String identity;
+
+ private User(final Builder builder) {
+ this.identifier = builder.identifier;
+ this.identity = builder.identity;
+
+ if (identifier == null || identifier.trim().isEmpty()) {
+ throw new IllegalArgumentException("Identifier can not be null or empty");
+ }
+
+ if (identity == null || identity.trim().isEmpty()) {
+ throw new IllegalArgumentException("Identity can not be null or empty");
+ }
+
+ }
+
+ /**
+ * @return the identifier of the user
+ */
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ /**
+ * @return the identity string of the user
+ */
+ public String getIdentity() {
+ return identity;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ final User other = (User) obj;
+ return Objects.equals(this.identifier, other.identifier);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(this.identifier);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("identifier[%s], identity[%s]", getIdentifier(), getIdentity());
+ }
+
+ /**
+ * Builder for Users.
+ */
+ public static class Builder {
+
+ private String identifier;
+ private String identity;
+ private final boolean fromUser;
+
+ /**
+ * Default constructor for building a new User.
+ */
+ public Builder() {
+ this.fromUser = false;
+ }
+
+ /**
+ * Initializes the builder with the state of the provided user. When using this constructor
+ * the identifier field of the builder can not be changed and will result in an IllegalStateException
+ * if attempting to do so.
+ *
+ * @param other the existing user to initialize from
+ */
+ public Builder(final User other) {
+ if (other == null) {
+ throw new IllegalArgumentException("Provided user can not be null");
+ }
+
+ this.identifier = other.getIdentifier();
+ this.identity = other.getIdentity();
+ this.fromUser = true;
+ }
+
+ /**
+ * Sets the identifier of the builder.
+ *
+ * @param identifier the identifier to set
+ * @return the builder
+ * @throws IllegalStateException if this method is called when this builder was constructed from an existing User
+ */
+ public Builder identifier(final String identifier) {
+ if (fromUser) {
+ throw new IllegalStateException(
+ "Identifier can not be changed when initialized from an existing user");
+ }
+
+ this.identifier = identifier;
+ return this;
+ }
+
+ /**
+ * Sets the identity of the builder.
+ *
+ * @param identity the identity to set
+ * @return the builder
+ */
+ public Builder identity(final String identity) {
+ this.identity = identity;
+ return this;
+ }
+
+ /**
+ * @return a new User constructed from the state of the builder
+ */
+ public User build() {
+ return new User(this);
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d1129706/nifi-framework-api/src/main/java/org/apache/nifi/authorization/UserContextKeys.java
----------------------------------------------------------------------
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/UserContextKeys.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/UserContextKeys.java
new file mode 100644
index 0000000..fca4b74
--- /dev/null
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/UserContextKeys.java
@@ -0,0 +1,26 @@
+/*
+ * 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.authorization;
+
+/**
+ * Constants for keys that can be passed in the AuthorizationRequest user context Map.
+ */
+public enum UserContextKeys {
+
+ CLIENT_ADDRESS;
+
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d1129706/nifi-framework-api/src/main/java/org/apache/nifi/authorization/UsersAndAccessPolicies.java
----------------------------------------------------------------------
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/UsersAndAccessPolicies.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/UsersAndAccessPolicies.java
new file mode 100644
index 0000000..552b753
--- /dev/null
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/UsersAndAccessPolicies.java
@@ -0,0 +1,52 @@
+/*
+ * 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.authorization;
+
+import java.util.Set;
+
+/**
+ * A holder object to provide atomic access to policies for a given resource and users by
+ * identity. Implementations must ensure consistent access to the data backing this instance.
+ */
+public interface UsersAndAccessPolicies {
+
+ /**
+ * Retrieves the set of access policies for a given resource and action.
+ *
+ * @param resourceIdentifier the resource identifier to retrieve policies for
+ * @param action the action to retrieve policies for
+ * @return the access policy for the given resource and action
+ */
+ public AccessPolicy getAccessPolicy(final String resourceIdentifier, final RequestAction action);
+
+ /**
+ * Retrieves a user by an identity string.
+ *
+ * @param identity the identity of the user to retrieve
+ * @return the user with the given identity
+ */
+ public User getUser(final String identity);
+
+ /**
+ * Retrieves the groups for a given user identity.
+ *
+ * @param userIdentity a user identity
+ * @return the set of groups for the given user identity
+ */
+ public Set<Group> getGroups(final String userIdentity);
+
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d1129706/nifi-framework-api/src/main/java/org/apache/nifi/authorization/annotation/AuthorizerContext.java
----------------------------------------------------------------------
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/annotation/AuthorizerContext.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/annotation/AuthorizerContext.java
new file mode 100644
index 0000000..b0d3f83
--- /dev/null
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/annotation/AuthorizerContext.java
@@ -0,0 +1,35 @@
+/*
+ * 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.authorization.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ *
+ */
+@Documented
+@Target({ElementType.FIELD, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface AuthorizerContext {
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d1129706/nifi-framework-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizationAccessException.java
----------------------------------------------------------------------
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizationAccessException.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizationAccessException.java
new file mode 100644
index 0000000..8b22d45
--- /dev/null
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizationAccessException.java
@@ -0,0 +1,32 @@
+/*
+ * 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.authorization.exception;
+
+/**
+ * Represents the case when an authorization decision could not be made because the Authorizer was unable to access the underlying data store.
+ */
+public class AuthorizationAccessException extends RuntimeException {
+
+ public AuthorizationAccessException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public AuthorizationAccessException(String message) {
+ super(message);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d1129706/nifi-framework-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizerCreationException.java
----------------------------------------------------------------------
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizerCreationException.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizerCreationException.java
new file mode 100644
index 0000000..4264202
--- /dev/null
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizerCreationException.java
@@ -0,0 +1,39 @@
+/*
+ * 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.authorization.exception;
+
+/**
+ * Represents the exceptional case when an Authorizer fails instantiation.
+ *
+ */
+public class AuthorizerCreationException extends RuntimeException {
+
+ public AuthorizerCreationException() {
+ }
+
+ public AuthorizerCreationException(String msg) {
+ super(msg);
+ }
+
+ public AuthorizerCreationException(Throwable cause) {
+ super(cause);
+ }
+
+ public AuthorizerCreationException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d1129706/nifi-framework-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizerDestructionException.java
----------------------------------------------------------------------
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizerDestructionException.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizerDestructionException.java
new file mode 100644
index 0000000..852eca1
--- /dev/null
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizerDestructionException.java
@@ -0,0 +1,39 @@
+/*
+ * 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.authorization.exception;
+
+/**
+ * Represents the exceptional case when an Authorizer fails destruction.
+ *
+ */
+public class AuthorizerDestructionException extends RuntimeException {
+
+ public AuthorizerDestructionException() {
+ }
+
+ public AuthorizerDestructionException(String msg) {
+ super(msg);
+ }
+
+ public AuthorizerDestructionException(Throwable cause) {
+ super(cause);
+ }
+
+ public AuthorizerDestructionException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+}