You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by ma...@apache.org on 2016/07/18 19:06:14 UTC
nifi git commit: NIFI-2272: - Ensuring the appropriate visibilty of
the action in the policy management page. NIFI-2273: - Ensuring we load the
policy or inform the user of the appropriate permissions of the effective
policy. NIFI-2239: - Providing help
Repository: nifi
Updated Branches:
refs/heads/master 5c8636edf -> aa91032cd
NIFI-2272:
- Ensuring the appropriate visibilty of the action in the policy management page.
NIFI-2273:
- Ensuring we load the policy or inform the user of the appropriate permissions of the effective policy.
NIFI-2239:
- Providing help tooltips for the policies in the management page.
NIFI-2283:
- Adding auditing for access policies, users, and groups.
NIFI-2263:
- Not replicating history requests throughout the cluster.
NIFI-2096:
- Fixing upload template file input in Firefox.
NIFI-2301:
- Removing relevant policies after component deletion.
Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/aa91032c
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/aa91032c
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/aa91032c
Branch: refs/heads/master
Commit: aa91032cde8ad1cf2caf18fc0f02b5f678e1f3a7
Parents: 5c8636e
Author: Matt Gilman <ma...@gmail.com>
Authored: Mon Jul 18 14:05:04 2016 -0400
Committer: Mark Payne <ma...@hotmail.com>
Committed: Mon Jul 18 15:05:54 2016 -0400
----------------------------------------------------------------------
.../java/org/apache/nifi/action/Component.java | 5 +-
.../apache/nifi/audit/AccessPolicyAuditor.java | 274 +++++++++++++++++++
.../java/org/apache/nifi/audit/UserAuditor.java | 245 +++++++++++++++++
.../org/apache/nifi/audit/UserGroupAuditor.java | 259 ++++++++++++++++++
.../nifi/web/StandardNiFiServiceFacade.java | 65 +++--
.../apache/nifi/web/api/ControllerResource.java | 4 +-
.../org/apache/nifi/web/api/FlowResource.java | 39 +--
.../src/main/resources/nifi-web-api-context.xml | 15 +
.../WEB-INF/partials/canvas/navigation.jsp | 2 +-
.../partials/canvas/policy-management.jsp | 2 +-
.../partials/canvas/upload-template-dialog.jsp | 5 +-
.../webapp/js/nf/canvas/nf-policy-management.js | 158 +++++++----
12 files changed, 961 insertions(+), 112 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/nifi/blob/aa91032c/nifi-api/src/main/java/org/apache/nifi/action/Component.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/action/Component.java b/nifi-api/src/main/java/org/apache/nifi/action/Component.java
index dcd23ee..a25525f 100644
--- a/nifi-api/src/main/java/org/apache/nifi/action/Component.java
+++ b/nifi-api/src/main/java/org/apache/nifi/action/Component.java
@@ -30,5 +30,8 @@ public enum Component {
Funnel,
Connection,
ControllerService,
- ReportingTask;
+ ReportingTask,
+ AccessPolicy,
+ User,
+ UserGroup;
}
http://git-wip-us.apache.org/repos/asf/nifi/blob/aa91032c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/AccessPolicyAuditor.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/AccessPolicyAuditor.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/AccessPolicyAuditor.java
new file mode 100644
index 0000000..9636e5a
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/AccessPolicyAuditor.java
@@ -0,0 +1,274 @@
+/*
+ * 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.audit;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.action.Action;
+import org.apache.nifi.action.Component;
+import org.apache.nifi.action.FlowChangeAction;
+import org.apache.nifi.action.Operation;
+import org.apache.nifi.action.details.ActionDetails;
+import org.apache.nifi.action.details.FlowChangeConfigureDetails;
+import org.apache.nifi.authorization.AccessPolicy;
+import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
+import org.apache.nifi.web.api.dto.AccessPolicyDTO;
+import org.apache.nifi.web.dao.AccessPolicyDAO;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Audits policy creation/removal and configuration changes.
+ */
+@Aspect
+public class AccessPolicyAuditor extends NiFiAuditor {
+
+ private static final Logger logger = LoggerFactory.getLogger(AccessPolicyAuditor.class);
+
+ private static final String USERS = "Users";
+ private static final String USER_GROUPS = "User Groups";
+
+ /**
+ * Audits the creation of policies via createAccessPolicy().
+ *
+ * This method only needs to be run 'after returning'. However, in Java 7 the order in which these methods are returned from Class.getDeclaredMethods (even though there is no order guaranteed)
+ * seems to differ from Java 6. SpringAOP depends on this ordering to determine advice precedence. By normalizing all advice into Around advice we can alleviate this issue.
+ *
+ * @param proceedingJoinPoint join point
+ * @return node
+ * @throws Throwable ex
+ */
+ @Around("within(org.apache.nifi.web.dao.AccessPolicyDAO+) && "
+ + "execution(org.apache.nifi.authorization.AccessPolicy createAccessPolicy(org.apache.nifi.web.api.dto.AccessPolicyDTO))")
+ public AccessPolicy createAccessPolicyAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
+ // create the access policy
+ AccessPolicy policy = (AccessPolicy) proceedingJoinPoint.proceed();
+
+ // if no exceptions were thrown, add the policy action...
+ final Action action = generateAuditRecord(policy, Operation.Add);
+
+ // save the actions
+ if (action != null) {
+ saveAction(action, logger);
+ }
+
+ return policy;
+ }
+
+ /**
+ * Audits the configuration of a single policy.
+ *
+ * @param proceedingJoinPoint join point
+ * @param accessPolicyDTO dto
+ * @param accessPolicyDAO dao
+ * @return node
+ * @throws Throwable ex
+ */
+ @Around("within(org.apache.nifi.web.dao.AccessPolicyDAO+) && "
+ + "execution(org.apache.nifi.authorization.AccessPolicy updateAccessPolicy(org.apache.nifi.web.api.dto.AccessPolicyDTO)) && "
+ + "args(accessPolicyDTO) && "
+ + "target(accessPolicyDAO)")
+ public AccessPolicy updateAccessPolicyAdvice(ProceedingJoinPoint proceedingJoinPoint, AccessPolicyDTO accessPolicyDTO, AccessPolicyDAO accessPolicyDAO) throws Throwable {
+ // determine the initial values for each property/setting thats changing
+ AccessPolicy accessPolicy = accessPolicyDAO.getAccessPolicy(accessPolicyDTO.getId());
+ final Map<String, String> values = extractConfiguredPropertyValues(accessPolicy, accessPolicyDTO);
+
+ // update the policy state
+ final AccessPolicy updatedAccessPolicy = (AccessPolicy) proceedingJoinPoint.proceed();
+
+ // if no exceptions were thrown, add the policy action...
+ // get the updated verbose state
+ accessPolicy = accessPolicyDAO.getAccessPolicy(updatedAccessPolicy.getIdentifier());
+
+ // get the current user
+ NiFiUser user = NiFiUserUtils.getNiFiUser();
+
+ // ensure the user was found
+ if (user != null) {
+ // determine the updated values
+ Map<String, String> updatedValues = extractConfiguredPropertyValues(accessPolicy, accessPolicyDTO);
+
+ // create a policy action
+ Date actionTimestamp = new Date();
+ Collection<Action> actions = new ArrayList<>();
+
+ // go through each updated value
+ for (String property : updatedValues.keySet()) {
+ String newValue = updatedValues.get(property);
+ String oldValue = values.get(property);
+ Operation operation = null;
+
+ // determine the type of operation
+ if (oldValue == null || newValue == null || !newValue.equals(oldValue)) {
+ operation = Operation.Configure;
+ }
+
+ // create a configuration action accordingly
+ if (operation != null) {
+ final FlowChangeConfigureDetails actionDetails = new FlowChangeConfigureDetails();
+ actionDetails.setName(property);
+ actionDetails.setValue(newValue);
+ actionDetails.setPreviousValue(oldValue);
+
+ // create a configuration action
+ FlowChangeAction configurationAction = new FlowChangeAction();
+ configurationAction.setUserIdentity(user.getIdentity());
+ configurationAction.setOperation(operation);
+ configurationAction.setTimestamp(actionTimestamp);
+ configurationAction.setSourceId(accessPolicy.getIdentifier());
+ configurationAction.setSourceName(formatPolicyName(accessPolicy));
+ configurationAction.setSourceType(Component.AccessPolicy);
+ configurationAction.setActionDetails(actionDetails);
+ actions.add(configurationAction);
+ }
+ }
+
+ // ensure there are actions to record
+ if (!actions.isEmpty()) {
+ // save the actions
+ saveActions(actions, logger);
+ }
+ }
+
+ return updatedAccessPolicy;
+ }
+
+ /**
+ * Audits the removal of a policy via deleteAccessPolicy().
+ *
+ * @param proceedingJoinPoint join point
+ * @param policyId policy id
+ * @param accessPolicyDAO dao
+ * @throws Throwable ex
+ */
+ @Around("within(org.apache.nifi.web.dao.AccessPolicyDAO+) && "
+ + "execution(org.apache.nifi.authorization.AccessPolicy deleteAccessPolicy(java.lang.String)) && "
+ + "args(policyId) && "
+ + "target(accessPolicyDAO)")
+ public AccessPolicy removePolicyAdvice(ProceedingJoinPoint proceedingJoinPoint, String policyId, AccessPolicyDAO accessPolicyDAO) throws Throwable {
+ // get the policy before removing it
+ AccessPolicy accessPolicy = accessPolicyDAO.getAccessPolicy(policyId);
+
+ // remove the policy
+ final AccessPolicy removedAccessPolicy = (AccessPolicy)proceedingJoinPoint.proceed();
+
+ // if no exceptions were thrown, add removal actions...
+ // audit the policy removal
+ final Action action = generateAuditRecord(accessPolicy, Operation.Remove);
+
+ // save the actions
+ if (action != null) {
+ saveAction(action, logger);
+ }
+
+ return removedAccessPolicy;
+ }
+
+ /**
+ * Generates an audit record for the creation of a policy.
+ *
+ * @param policy policy
+ * @param operation operation
+ * @return action
+ */
+ public Action generateAuditRecord(AccessPolicy policy, Operation operation) {
+ return generateAuditRecord(policy, operation, null);
+ }
+
+ /**
+ * Generates an audit record for the creation of a policy.
+ *
+ * @param policy policy
+ * @param operation operation
+ * @param actionDetails details
+ * @return action
+ */
+ public Action generateAuditRecord(AccessPolicy policy, Operation operation, ActionDetails actionDetails) {
+ FlowChangeAction action = null;
+
+ // get the current user
+ NiFiUser user = NiFiUserUtils.getNiFiUser();
+
+ // ensure the user was found
+ if (user != null) {
+ // create the policy action for adding this policy
+ action = new FlowChangeAction();
+ action.setUserIdentity(user.getIdentity());
+ action.setOperation(operation);
+ action.setTimestamp(new Date());
+ action.setSourceId(policy.getIdentifier());
+ action.setSourceName(formatPolicyName(policy));
+ action.setSourceType(Component.AccessPolicy);
+
+ if (actionDetails != null) {
+ action.setActionDetails(actionDetails);
+ }
+ }
+
+ return action;
+ }
+
+ /**
+ * Formats the name of the specified policy.
+ *
+ * @param policy policy
+ * @return formatted name
+ */
+ private String formatPolicyName(final AccessPolicy policy) {
+ return policy.getAction().toString() + " " + policy.getResource();
+ }
+
+ /**
+ * Extracts the values for the configured properties from the specified policy.
+ */
+ private Map<String, String> extractConfiguredPropertyValues(AccessPolicy policy, AccessPolicyDTO policyDTO) {
+ Map<String, String> values = new HashMap<>();
+
+ if (policyDTO.getUsers() != null) {
+ // get each of the auto terminated relationship names
+ final List<String> currentUsers = new ArrayList<>(policy.getUsers());
+
+ // sort them and include in the configuration
+ Collections.sort(currentUsers, Collator.getInstance(Locale.US));
+ values.put(USERS, StringUtils.join(currentUsers, ", "));
+ }
+ if (policyDTO.getUserGroups() != null) {
+ // get each of the auto terminated relationship names
+ final List<String> currentUserGroups = new ArrayList<>(policy.getGroups());
+
+ // sort them and include in the configuration
+ Collections.sort(currentUserGroups, Collator.getInstance(Locale.US));
+ values.put(USER_GROUPS, StringUtils.join(currentUserGroups, ", "));
+ }
+
+ return values;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/aa91032c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/UserAuditor.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/UserAuditor.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/UserAuditor.java
new file mode 100644
index 0000000..843184d
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/UserAuditor.java
@@ -0,0 +1,245 @@
+/*
+ * 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.audit;
+
+import org.apache.nifi.action.Action;
+import org.apache.nifi.action.Component;
+import org.apache.nifi.action.FlowChangeAction;
+import org.apache.nifi.action.Operation;
+import org.apache.nifi.action.details.ActionDetails;
+import org.apache.nifi.action.details.FlowChangeConfigureDetails;
+import org.apache.nifi.authorization.User;
+import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
+import org.apache.nifi.web.api.dto.UserDTO;
+import org.apache.nifi.web.dao.UserDAO;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Audits user creation/removal and configuration changes.
+ */
+@Aspect
+public class UserAuditor extends NiFiAuditor {
+
+ private static final Logger logger = LoggerFactory.getLogger(UserAuditor.class);
+
+ private static final String IDENTITY = "Identity";
+
+ /**
+ * Audits the creation of policies via createUser().
+ *
+ * This method only needs to be run 'after returning'. However, in Java 7 the order in which these methods are returned from Class.getDeclaredMethods (even though there is no order guaranteed)
+ * seems to differ from Java 6. SpringAOP depends on this ordering to determine advice precedence. By normalizing all advice into Around advice we can alleviate this issue.
+ *
+ * @param proceedingJoinPoint join point
+ * @return node
+ * @throws Throwable ex
+ */
+ @Around("within(org.apache.nifi.web.dao.UserDAO+) && "
+ + "execution(org.apache.nifi.authorization.User createUser(org.apache.nifi.web.api.dto.UserDTO))")
+ public User createUserAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
+ // create the access user
+ User user = (User) proceedingJoinPoint.proceed();
+
+ // if no exceptions were thrown, add the user action...
+ final Action action = generateAuditRecord(user, Operation.Add);
+
+ // save the actions
+ if (action != null) {
+ saveAction(action, logger);
+ }
+
+ return user;
+ }
+
+ /**
+ * Audits the configuration of a single user.
+ *
+ * @param proceedingJoinPoint join point
+ * @param userDTO dto
+ * @param userDAO dao
+ * @return node
+ * @throws Throwable ex
+ */
+ @Around("within(org.apache.nifi.web.dao.UserDAO+) && "
+ + "execution(org.apache.nifi.authorization.User updateUser(org.apache.nifi.web.api.dto.UserDTO)) && "
+ + "args(userDTO) && "
+ + "target(userDAO)")
+ public User updateUserAdvice(ProceedingJoinPoint proceedingJoinPoint, UserDTO userDTO, UserDAO userDAO) throws Throwable {
+ // determine the initial values for each property/setting thats changing
+ User user = userDAO.getUser(userDTO.getId());
+ final Map<String, String> values = extractConfiguredPropertyValues(user, userDTO);
+
+ // update the user state
+ final User updatedUser = (User) proceedingJoinPoint.proceed();
+
+ // if no exceptions were thrown, add the user action...
+ // get the updated verbose state
+ user = userDAO.getUser(updatedUser.getIdentifier());
+
+ // get the current user
+ NiFiUser niFiUser = NiFiUserUtils.getNiFiUser();
+
+ // ensure the user was found
+ if (niFiUser != null) {
+ // determine the updated values
+ Map<String, String> updatedValues = extractConfiguredPropertyValues(user, userDTO);
+
+ // create a user action
+ Date actionTimestamp = new Date();
+ Collection<Action> actions = new ArrayList<>();
+
+ // go through each updated value
+ for (String property : updatedValues.keySet()) {
+ String newValue = updatedValues.get(property);
+ String oldValue = values.get(property);
+ Operation operation = null;
+
+ // determine the type of operation
+ if (oldValue == null || newValue == null || !newValue.equals(oldValue)) {
+ operation = Operation.Configure;
+ }
+
+ // create a configuration action accordingly
+ if (operation != null) {
+ final FlowChangeConfigureDetails actionDetails = new FlowChangeConfigureDetails();
+ actionDetails.setName(property);
+ actionDetails.setValue(newValue);
+ actionDetails.setPreviousValue(oldValue);
+
+ // create a configuration action
+ FlowChangeAction configurationAction = new FlowChangeAction();
+ configurationAction.setUserIdentity(niFiUser.getIdentity());
+ configurationAction.setOperation(operation);
+ configurationAction.setTimestamp(actionTimestamp);
+ configurationAction.setSourceId(user.getIdentifier());
+ configurationAction.setSourceName(user.getIdentity());
+ configurationAction.setSourceType(Component.User);
+ configurationAction.setActionDetails(actionDetails);
+ actions.add(configurationAction);
+ }
+ }
+
+ // ensure there are actions to record
+ if (!actions.isEmpty()) {
+ // save the actions
+ saveActions(actions, logger);
+ }
+ }
+
+ return updatedUser;
+ }
+
+ /**
+ * Audits the removal of a user via deleteUser().
+ *
+ * @param proceedingJoinPoint join point
+ * @param userId user id
+ * @param userDAO dao
+ * @throws Throwable ex
+ */
+ @Around("within(org.apache.nifi.web.dao.UserDAO+) && "
+ + "execution(org.apache.nifi.authorization.User deleteUser(java.lang.String)) && "
+ + "args(userId) && "
+ + "target(userDAO)")
+ public User removeUserAdvice(ProceedingJoinPoint proceedingJoinPoint, String userId, UserDAO userDAO) throws Throwable {
+ // get the user before removing it
+ User user = userDAO.getUser(userId);
+
+ // remove the user
+ final User removedUser = (User) proceedingJoinPoint.proceed();
+
+ // if no exceptions were thrown, add removal actions...
+ // audit the user removal
+ final Action action = generateAuditRecord(user, Operation.Remove);
+
+ // save the actions
+ if (action != null) {
+ saveAction(action, logger);
+ }
+
+ return removedUser;
+ }
+
+ /**
+ * Generates an audit record for the creation of a user.
+ *
+ * @param user user
+ * @param operation operation
+ * @return action
+ */
+ public Action generateAuditRecord(User user, Operation operation) {
+ return generateAuditRecord(user, operation, null);
+ }
+
+ /**
+ * Generates an audit record for the creation of a user.
+ *
+ * @param user user
+ * @param operation operation
+ * @param actionDetails details
+ * @return action
+ */
+ public Action generateAuditRecord(User user, Operation operation, ActionDetails actionDetails) {
+ FlowChangeAction action = null;
+
+ // get the current user
+ NiFiUser niFiUser = NiFiUserUtils.getNiFiUser();
+
+ // ensure the user was found
+ if (niFiUser != null) {
+ // create the user action for adding this user
+ action = new FlowChangeAction();
+ action.setUserIdentity(niFiUser.getIdentity());
+ action.setOperation(operation);
+ action.setTimestamp(new Date());
+ action.setSourceId(user.getIdentifier());
+ action.setSourceName(user.getIdentity());
+ action.setSourceType(Component.User);
+
+ if (actionDetails != null) {
+ action.setActionDetails(actionDetails);
+ }
+ }
+
+ return action;
+ }
+
+ /**
+ * Extracts the values for the configured properties from the specified user.
+ */
+ private Map<String, String> extractConfiguredPropertyValues(User user, UserDTO userDTO) {
+ Map<String, String> values = new HashMap<>();
+
+ if (userDTO.getIdentity() != null) {
+ values.put(IDENTITY, user.getIdentity());
+ }
+
+ return values;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/aa91032c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/UserGroupAuditor.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/UserGroupAuditor.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/UserGroupAuditor.java
new file mode 100644
index 0000000..f039d88
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/UserGroupAuditor.java
@@ -0,0 +1,259 @@
+/*
+ * 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.audit;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.action.Action;
+import org.apache.nifi.action.Component;
+import org.apache.nifi.action.FlowChangeAction;
+import org.apache.nifi.action.Operation;
+import org.apache.nifi.action.details.ActionDetails;
+import org.apache.nifi.action.details.FlowChangeConfigureDetails;
+import org.apache.nifi.authorization.Group;
+import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
+import org.apache.nifi.web.api.dto.UserGroupDTO;
+import org.apache.nifi.web.dao.UserGroupDAO;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Audits user creation/removal and configuration changes.
+ */
+@Aspect
+public class UserGroupAuditor extends NiFiAuditor {
+
+ private static final Logger logger = LoggerFactory.getLogger(UserGroupAuditor.class);
+
+ private static final String NAME = "Name";
+ private static final String USERS = "Users";
+
+ /**
+ * Audits the creation of policies via createUser().
+ *
+ * This method only needs to be run 'after returning'. However, in Java 7 the order in which these methods are returned from Class.getDeclaredMethods (even though there is no order guaranteed)
+ * seems to differ from Java 6. SpringAOP depends on this ordering to determine advice precedence. By normalizing all advice into Around advice we can alleviate this issue.
+ *
+ * @param proceedingJoinPoint join point
+ * @return node
+ * @throws Throwable ex
+ */
+ @Around("within(org.apache.nifi.web.dao.UserGroupDAO+) && "
+ + "execution(org.apache.nifi.authorization.Group createUserGroup(org.apache.nifi.web.api.dto.UserGroupDTO))")
+ public Group createUserGroupAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
+ // create the access user group
+ Group userGroup = (Group) proceedingJoinPoint.proceed();
+
+ // if no exceptions were thrown, add the user action...
+ final Action action = generateAuditRecord(userGroup, Operation.Add);
+
+ // save the actions
+ if (action != null) {
+ saveAction(action, logger);
+ }
+
+ return userGroup;
+ }
+
+ /**
+ * Audits the configuration of a single user.
+ *
+ * @param proceedingJoinPoint join point
+ * @param userGroupDTO dto
+ * @param userGroupDAO dao
+ * @return node
+ * @throws Throwable ex
+ */
+ @Around("within(org.apache.nifi.web.dao.UserGroupDAO+) && "
+ + "execution(org.apache.nifi.authorization.Group updateUserGroup(org.apache.nifi.web.api.dto.UserGroupDTO)) && "
+ + "args(userGroupDTO) && "
+ + "target(userGroupDAO)")
+ public Group updateUserAdvice(ProceedingJoinPoint proceedingJoinPoint, UserGroupDTO userGroupDTO, UserGroupDAO userGroupDAO) throws Throwable {
+ // determine the initial values for each property/setting thats changing
+ Group user = userGroupDAO.getUserGroup(userGroupDTO.getId());
+ final Map<String, String> values = extractConfiguredPropertyValues(user, userGroupDTO);
+
+ // update the user state
+ final Group updatedUserGroup = (Group) proceedingJoinPoint.proceed();
+
+ // if no exceptions were thrown, add the user group action...
+ // get the updated verbose state
+ user = userGroupDAO.getUserGroup(updatedUserGroup.getIdentifier());
+
+ // get the current user
+ NiFiUser niFiUser = NiFiUserUtils.getNiFiUser();
+
+ // ensure the user was found
+ if (niFiUser != null) {
+ // determine the updated values
+ Map<String, String> updatedValues = extractConfiguredPropertyValues(user, userGroupDTO);
+
+ // create a user action
+ Date actionTimestamp = new Date();
+ Collection<Action> actions = new ArrayList<>();
+
+ // go through each updated value
+ for (String property : updatedValues.keySet()) {
+ String newValue = updatedValues.get(property);
+ String oldValue = values.get(property);
+ Operation operation = null;
+
+ // determine the type of operation
+ if (oldValue == null || newValue == null || !newValue.equals(oldValue)) {
+ operation = Operation.Configure;
+ }
+
+ // create a configuration action accordingly
+ if (operation != null) {
+ final FlowChangeConfigureDetails actionDetails = new FlowChangeConfigureDetails();
+ actionDetails.setName(property);
+ actionDetails.setValue(newValue);
+ actionDetails.setPreviousValue(oldValue);
+
+ // create a configuration action
+ FlowChangeAction configurationAction = new FlowChangeAction();
+ configurationAction.setUserIdentity(niFiUser.getIdentity());
+ configurationAction.setOperation(operation);
+ configurationAction.setTimestamp(actionTimestamp);
+ configurationAction.setSourceId(user.getIdentifier());
+ configurationAction.setSourceName(user.getName());
+ configurationAction.setSourceType(Component.UserGroup);
+ configurationAction.setActionDetails(actionDetails);
+ actions.add(configurationAction);
+ }
+ }
+
+ // ensure there are actions to record
+ if (!actions.isEmpty()) {
+ // save the actions
+ saveActions(actions, logger);
+ }
+ }
+
+ return updatedUserGroup;
+ }
+
+ /**
+ * Audits the removal of a user via deleteUser().
+ *
+ * @param proceedingJoinPoint join point
+ * @param userGroupId user id
+ * @param userGroupDAO dao
+ * @throws Throwable ex
+ */
+ @Around("within(org.apache.nifi.web.dao.UserGroupDAO+) && "
+ + "execution(org.apache.nifi.authorization.Group deleteUserGroup(java.lang.String)) && "
+ + "args(userGroupId) && "
+ + "target(userGroupDAO)")
+ public Group removeUserAdvice(ProceedingJoinPoint proceedingJoinPoint, String userGroupId, UserGroupDAO userGroupDAO) throws Throwable {
+ // get the user group before removing it
+ Group userGroup = userGroupDAO.getUserGroup(userGroupId);
+
+ // remove the user group
+ final Group removedUserGroup = (Group) proceedingJoinPoint.proceed();
+
+ // if no exceptions were thrown, add removal actions...
+ // audit the user removal
+ final Action action = generateAuditRecord(userGroup, Operation.Remove);
+
+ // save the actions
+ if (action != null) {
+ saveAction(action, logger);
+ }
+
+ return removedUserGroup;
+ }
+
+ /**
+ * Generates an audit record for the creation of a user group.
+ *
+ * @param userGroup userGroup
+ * @param operation operation
+ * @return action
+ */
+ public Action generateAuditRecord(Group userGroup, Operation operation) {
+ return generateAuditRecord(userGroup, operation, null);
+ }
+
+ /**
+ * Generates an audit record for the creation of a user group.
+ *
+ * @param userGroup userGroup
+ * @param operation operation
+ * @param actionDetails details
+ * @return action
+ */
+ public Action generateAuditRecord(Group userGroup, Operation operation, ActionDetails actionDetails) {
+ FlowChangeAction action = null;
+
+ // get the current user
+ NiFiUser niFiUser = NiFiUserUtils.getNiFiUser();
+
+ // ensure the user was found
+ if (niFiUser != null) {
+ // create the user action for adding this user
+ action = new FlowChangeAction();
+ action.setUserIdentity(niFiUser.getIdentity());
+ action.setOperation(operation);
+ action.setTimestamp(new Date());
+ action.setSourceId(userGroup.getIdentifier());
+ action.setSourceName(userGroup.getName());
+ action.setSourceType(Component.UserGroup);
+
+ if (actionDetails != null) {
+ action.setActionDetails(actionDetails);
+ }
+ }
+
+ return action;
+ }
+
+ /**
+ * Extracts the values for the configured properties from the specified user group.
+ */
+ private Map<String, String> extractConfiguredPropertyValues(Group group, UserGroupDTO userGroupDTO) {
+ Map<String, String> values = new HashMap<>();
+
+ if (userGroupDTO.getIdentity() != null) {
+ values.put(NAME, group.getName());
+ }
+ if (userGroupDTO.getUsers() != null) {
+ // get each of the auto terminated relationship names
+ final List<String> currentUsers = new ArrayList<>(group.getUsers());
+
+ // sort them and include in the configuration
+ Collections.sort(currentUsers, Collator.getInstance(Locale.US));
+ values.put(USERS, StringUtils.join(currentUsers, ", "));
+ }
+
+ return values;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/aa91032c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
index 892718e..2988e99 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
@@ -16,28 +16,7 @@
*/
package org.apache.nifi.web;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.UUID;
-import java.util.function.Function;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Response;
-
+import com.google.common.collect.Sets;
import org.apache.nifi.action.Action;
import org.apache.nifi.action.Component;
import org.apache.nifi.action.FlowChangeAction;
@@ -215,7 +194,26 @@ import org.apache.nifi.web.util.SnippetUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.collect.Sets;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.UUID;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
/**
* Implementation of NiFiServiceFacade that performs revision checking.
@@ -978,6 +976,20 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
controllerFacade.save();
logger.debug("Deletion of component {} was successful", authorizable);
+ try {
+ // since the component is being deleted, also delete any relevant access policies
+ final AccessPolicy readPolicy = accessPolicyDAO.getAccessPolicy(RequestAction.READ, authorizable);
+ if (authorizable.getResource().getIdentifier().equals(readPolicy.getResource())) {
+ accessPolicyDAO.deleteAccessPolicy(readPolicy.getIdentifier());
+ }
+ final AccessPolicy writePolicy = accessPolicyDAO.getAccessPolicy(RequestAction.WRITE, authorizable);
+ if (authorizable.getResource().getIdentifier().equals(writePolicy.getResource())) {
+ accessPolicyDAO.deleteAccessPolicy(writePolicy.getIdentifier());
+ }
+ } catch (final Exception e) {
+ logger.warn(String.format("Unable to remove access policy for %s after component removal.", authorizable.getResource().getIdentifier()), e);
+ }
+
return dto;
}
});
@@ -2650,6 +2662,13 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
case Connection:
authorizable = authorizableLookup.getConnection(sourceId);
break;
+ case AccessPolicy:
+ authorizable = authorizableLookup.getAccessPolicyById(sourceId);
+ break;
+ case User:
+ case UserGroup:
+ authorizable = authorizableLookup.getTenant();
+ break;
default:
throw new WebApplicationException(Response.serverError().entity("An unexpected type of component is the source of this action.").build());
}
http://git-wip-us.apache.org/repos/asf/nifi/blob/aa91032c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
index 346f5a4..7a87e6e 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
@@ -646,9 +646,7 @@ public class ControllerResource extends ApplicationResource {
throw new IllegalArgumentException("The end date must be specified.");
}
- if (isReplicateRequest()) {
- return replicate(HttpMethod.DELETE);
- }
+ // Note: History requests are not replicated throughout the cluster and are instead handled by the nodes independently
// handle expects request (usually from the cluster manager)
final boolean validationPhase = isValidationPhase(httpServletRequest);
http://git-wip-us.apache.org/repos/asf/nifi/blob/aa91032c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java
index 8df6c17..8a17e65 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java
@@ -30,7 +30,6 @@ import org.apache.nifi.authorization.AuthorizationResult;
import org.apache.nifi.authorization.AuthorizationResult.Result;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.RequestAction;
-import org.apache.nifi.authorization.Resource;
import org.apache.nifi.authorization.UserContextKeys;
import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.authorization.resource.ResourceFactory;
@@ -50,8 +49,8 @@ import org.apache.nifi.web.api.dto.AboutDTO;
import org.apache.nifi.web.api.dto.BannerDTO;
import org.apache.nifi.web.api.dto.BulletinBoardDTO;
import org.apache.nifi.web.api.dto.BulletinQueryDTO;
-import org.apache.nifi.web.api.dto.ClusterSummaryDTO;
import org.apache.nifi.web.api.dto.ClusterDTO;
+import org.apache.nifi.web.api.dto.ClusterSummaryDTO;
import org.apache.nifi.web.api.dto.NodeDTO;
import org.apache.nifi.web.api.dto.ProcessGroupDTO;
import org.apache.nifi.web.api.dto.RevisionDTO;
@@ -237,30 +236,6 @@ public class FlowResource extends ApplicationResource {
}
}
- private boolean isAuthorized(final RequestAction action, final Resource resource) {
- final NiFiUser user = NiFiUserUtils.getNiFiUser();
-
- final Map<String,String> userContext;
- if (!StringUtils.isBlank(user.getClientAddress())) {
- userContext = new HashMap<>();
- userContext.put(UserContextKeys.CLIENT_ADDRESS.name(), user.getClientAddress());
- } else {
- userContext = null;
- }
-
- final AuthorizationRequest request = new AuthorizationRequest.Builder()
- .resource(resource)
- .identity(user.getIdentity())
- .anonymous(user.isAnonymous())
- .accessAttempt(false)
- .action(action)
- .userContext(userContext)
- .build();
-
- final AuthorizationResult result = authorizer.authorize(request);
- return Result.Approved.equals(result.getResult());
- }
-
// ----
// flow
// ----
@@ -2146,9 +2121,7 @@ public class FlowResource extends ApplicationResource {
}
}
- if (isReplicateRequest()) {
- return replicate(HttpMethod.GET);
- }
+ // Note: History requests are not replicated throughout the cluster and are instead handled by the nodes independently
// create a history query
final HistoryQueryDTO query = new HistoryQueryDTO();
@@ -2231,9 +2204,7 @@ public class FlowResource extends ApplicationResource {
throw new IllegalArgumentException("The action id must be specified.");
}
- if (isReplicateRequest()) {
- return replicate(HttpMethod.GET);
- }
+ // Note: History requests are not replicated throughout the cluster and are instead handled by the nodes independently
// get the specified action
final ActionDTO action = serviceFacade.getAction(id.getInteger());
@@ -2284,9 +2255,7 @@ public class FlowResource extends ApplicationResource {
authorizeFlow();
- if (isReplicateRequest()) {
- return replicate(HttpMethod.GET);
- }
+ // Note: History requests are not replicated throughout the cluster and are instead handled by the nodes independently
// create the response entity
final ComponentHistoryEntity entity = new ComponentHistoryEntity();
http://git-wip-us.apache.org/repos/asf/nifi/blob/aa91032c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
index 85983ca..6e8de79 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
@@ -491,6 +491,21 @@
<property name="auditService" ref="auditService"/>
<property name="processGroupDAO" ref="processGroupDAO"/>
</bean>
+ <bean id="policyAuditor" class="org.apache.nifi.audit.AccessPolicyAuditor">
+ <property name="serviceFacade" ref="serviceFacade"/>
+ <property name="auditService" ref="auditService"/>
+ <property name="processGroupDAO" ref="processGroupDAO"/>
+ </bean>
+ <bean id="userAuditor" class="org.apache.nifi.audit.UserAuditor">
+ <property name="serviceFacade" ref="serviceFacade"/>
+ <property name="auditService" ref="auditService"/>
+ <property name="processGroupDAO" ref="processGroupDAO"/>
+ </bean>
+ <bean id="userGroupAuditor" class="org.apache.nifi.audit.UserGroupAuditor">
+ <property name="serviceFacade" ref="serviceFacade"/>
+ <property name="auditService" ref="auditService"/>
+ <property name="processGroupDAO" ref="processGroupDAO"/>
+ </bean>
<!-- NiFi locking -->
<bean id="serviceFacadeLock" class="org.apache.nifi.web.NiFiServiceFacadeLock"/>
http://git-wip-us.apache.org/repos/asf/nifi/blob/aa91032c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/navigation.jsp
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/navigation.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/navigation.jsp
index a15dee1..01ab413 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/navigation.jsp
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/navigation.jsp
@@ -102,7 +102,7 @@
<div class="button-spacer-small"> </div>
<div id="operate-policy" class="action-button" title="Access Policies">
<button ng-click="appCtrl.nf.Actions['managePolicies'](appCtrl.nf.CanvasUtils.getSelection());"
- ng-disabled="appCtrl.nf.CanvasUtils.getSelection().size() > 1">
+ ng-disabled="!(appCtrl.nf.CanvasUtils.getSelection().size() <= 1 && appCtrl.nf.Common.canAccessTenants())">
<div class="graph-control-action-icon fa fa-key"></div></button>
</div>
<div class="button-spacer-large"> </div>
http://git-wip-us.apache.org/repos/asf/nifi/blob/aa91032c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/policy-management.jsp
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/policy-management.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/policy-management.jsp
index 926b6f1..b0e10e9 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/policy-management.jsp
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/policy-management.jsp
@@ -28,7 +28,7 @@
</div>
<div id="global-policy-controls" class="hidden policy-controls">
<div id="policy-type-list"></div>
- <div id="controller-policy-target"></div>
+ <div id="controller-policy-target" class="hidden"></div>
<div class="clear"></div>
</div>
<div id="component-policy-controls" class="hidden policy-controls">
http://git-wip-us.apache.org/repos/asf/nifi/blob/aa91032c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/upload-template-dialog.jsp
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/upload-template-dialog.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/upload-template-dialog.jsp
index 3c63209..0469885 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/upload-template-dialog.jsp
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/upload-template-dialog.jsp
@@ -20,11 +20,12 @@
<div id="select-template-container">
<div id="template-browse-container">
<span id="select-template-label">Select Template</span>
- <button id="select-template-button" class="fa fa-search">
+ <div id="select-template-button">
+ <button class="fa fa-search"></button>
<form id="template-upload-form" enctype="multipart/form-data" method="post">
<input type="file" name="template" id="template-file-field"/>
</form>
- </button>
+ </div>
</div>
</div>
<div id="submit-template-container">
http://git-wip-us.apache.org/repos/asf/nifi/blob/aa91032c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-policy-management.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-policy-management.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-policy-management.js
index dbadf00..e88e93c 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-policy-management.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-policy-management.js
@@ -213,29 +213,41 @@ nf.PolicyManagement = (function () {
// policy type listing
$('#policy-type-list').combo({
options: [{
- text: 'access the user interface',
- value: 'flow'
+ text: 'view the user interface',
+ value: 'flow',
+ description: 'Allows users to view the user interface'
}, {
text: 'access the controller',
- value: 'controller'
+ value: 'controller',
+ description: 'Allows users to view/modify the controller including Reporting Tasks, Controller Services, and Nodes in the Cluster'
}, {
text: 'query provenance',
- value: 'provenance'
+ value: 'provenance',
+ description: 'Allows users to submit a Provenance Search and request Event Lineage'
}, {
text: 'access all policies',
- value: 'policies'
+ value: 'policies',
+ description: 'Allows users to view/modify the policies for all components'
+ }, {
+ text: 'access users/user groups',
+ value: 'tenants',
+ description: 'Allows users to view/modify the users and user groups'
}, {
text: 'retrieve site-to-site details',
- value: 'site-to-site'
+ value: 'site-to-site',
+ description: 'Allows other NiFi instances to retrieve Site-To-Site details of this NiFi'
}, {
text: 'view system diagnostics',
- value: 'system'
+ value: 'system',
+ description: 'Allows users to view System Diagnostics'
}, {
text: 'proxy user requests',
- value: 'proxy'
+ value: 'proxy',
+ description: 'Allows proxy machines to send requests on the behalf of others'
}, {
text: 'access counters',
- value: 'counters'
+ value: 'counters',
+ description: 'Allows users to view/modify Counters'
}],
select: function (option) {
if (initialized) {
@@ -243,7 +255,7 @@ nf.PolicyManagement = (function () {
$('#selected-policy-type').text(option.value);
// if the option is for a specific component
- if (option.value === 'controller' || option.value === 'counters' || option.value === 'policies') {
+ if (option.value === 'controller' || option.value === 'counters' || option.value === 'policies' || option.value === 'tenants') {
// update the policy target and let it relaod the policy
$('#controller-policy-target').combo('setSelectedOption', {
'value': 'read'
@@ -289,26 +301,33 @@ nf.PolicyManagement = (function () {
$('#component-policy-target').combo({
options: [{
text: 'view the component',
- value: 'read-component'
+ value: 'read-component',
+ description: 'Allows users to view component configuration details'
}, {
text: 'modify the component',
- value: 'write-component'
+ value: 'write-component',
+ description: 'Allows users to modify component configuration details'
}, {
text: 'view the provenance events',
- value: 'read-provenance-events'
+ value: 'read-provenance-events',
+ description: 'Allows users to access provenance events and content for this component'
}, {
text: 'view the policies',
- value: 'read-policies'
+ value: 'read-policies',
+ description: 'Allows users to view the list of users who can view/modify this component'
}, {
text: 'modify the policies',
- value: 'write-policies'
+ value: 'write-policies',
+ description: 'Allows users to modify the list of users who can view/modify this component'
}, {
text: 'receive data via site-to-site',
value: 'write-receive-data',
+ description: 'Allows this port to receive data from these NiFi instances',
disabled: true
- }, {
+ }, {
text: 'send data via site-to-site',
value: 'write-send-data',
+ description: 'Allows this port to send data to these NiFi instances',
disabled: true
}],
select: function (option) {
@@ -618,9 +637,6 @@ nf.PolicyManagement = (function () {
// allow removal and modification as the policy is not inherited
$('#new-policy-user-button').prop('disabled', false);
-
- // update the refresh timestamp
- $('#policy-last-refreshed').text(policyEntity.generated);
// see if the policy is for this resource
if (resourceAndAction.resource === policy.resource) {
@@ -651,33 +667,54 @@ nf.PolicyManagement = (function () {
url: '../nifi-api/policies/' + resourceAndAction.action + resourceAndAction.resource,
dataType: 'json'
}).done(function (policyEntity) {
- var policy = policyEntity.component;
+ // return OK so we either have access to the policy or we don't have access to an inherited policy
+
+ // update the refresh timestamp
+ $('#policy-last-refreshed').text(policyEntity.generated);
- $('#policy-message').text(policy.resource);
+ // ensure appropriate actions for the loaded policy
+ if (policyEntity.permissions.canRead === true && policyEntity.permissions.canWrite === true) {
+ var policy = policyEntity.component;
- // populate the policy details
- populatePolicy(policyEntity);
+ $('#policy-message').text(policy.resource);
+
+ // populate the policy details
+ populatePolicy(policyEntity);
+ } else {
+ // reset the policy
+ resetPolicy();
+
+ // show an appropriate message
+ $('#policy-message').text('No policy for the specified resource and not authorized to access the inherited policy. ');
+ $('#new-policy-message').hide();
+ $('#override-policy-message').show();
+ }
deferred.resolve();
}).fail(function (xhr, status, error) {
if (xhr.status === 404) {
- // show an appropriate messate
- $('#policy-message').text('No policy for the specified resource. ');
+ // reset the policy
+ resetPolicy();
+
+ // show an appropriate message
+ $('#policy-message').text('No policy for the specified resource.');
$('#new-policy-message').show();
$('#override-policy-message').hide();
- // reset the current policy
- $('#policy-table').removeData('policy');
-
- // require non inherited policy for removal and modification
- $('#new-policy-user-button').prop('disabled', true);
- $('#delete-policy-button').prop('disabled', true);
+ deferred.resolve();
+ } else if (xhr.status === 403) {
+ // reset the policy
+ resetPolicy();
- // populate the table with no users
- populateTable([], []);
+ // show an appropriate message
+ $('#policy-message').text('Not authorized to access the policy for the specified resource.');
+ $('#new-policy-message').hide();
+ $('#override-policy-message').hide();
deferred.resolve();
} else {
+ resetPolicy();
+
deferred.reject();
nf.Common.handleAjaxError(xhr, status, error);
}
@@ -754,7 +791,23 @@ nf.PolicyManagement = (function () {
dataType: 'json',
contentType: 'application/json'
}).done(function (policyEntity) {
- populatePolicy(policyEntity);
+ // ensure appropriate actions for the loaded policy
+ if (policyEntity.permissions.canRead === true && policyEntity.permissions.canWrite === true) {
+ var policy = policyEntity.component;
+
+ $('#policy-message').text(policy.resource);
+
+ // populate the policy details
+ populatePolicy(policyEntity);
+ } else {
+ // reset the policy
+ resetPolicy();
+
+ // show an appropriate message
+ $('#policy-message').text('No policy for the specified resource and not authorized to access the inherited policy. ');
+ $('#new-policy-message').hide();
+ $('#override-policy-message').show();
+ }
}).fail(nf.Common.handleAjaxError);
} else {
nf.Dialog.showOkDialog({
@@ -769,7 +822,7 @@ nf.PolicyManagement = (function () {
*/
var showPolicy = function () {
// show the configuration dialog
- nf.Shell.showContent('#policy-management').done(function () {
+ nf.Shell.showContent('#policy-management').always(function () {
reset();
});
@@ -787,10 +840,27 @@ nf.PolicyManagement = (function () {
};
/**
+ * Reset the policy.
+ */
+ var resetPolicy = function () {
+ resetPolicyMessage();
+
+ // reset button state
+ $('#delete-policy-button').prop('disabled', true);
+ $('#new-policy-user-button').prop('disabled', true);
+
+ // reset the current policy
+ $('#policy-table').removeData('policy');
+
+ // populate the table with no users
+ populateTable([], []);
+ }
+
+ /**
* Resets the policy management dialog.
*/
var reset = function () {
- resetPolicyMessage();
+ resetPolicy();
// clear the selected policy details
$('#selected-policy-type').text('');
@@ -800,10 +870,6 @@ nf.PolicyManagement = (function () {
// clear the selected component details
$('div.policy-selected-component-container').hide();
-
- // reset button state
- $('#delete-policy-button').prop('disabled', false);
- $('#new-policy-user-button').prop('disabled', false);
};
/**
@@ -885,7 +951,7 @@ nf.PolicyManagement = (function () {
$('#selected-policy-component-id').text(d.id);
populateComponentResource('controller-services');
- return loadPolicy().done(showPolicy);
+ return loadPolicy().always(showPolicy);
},
/**
@@ -913,7 +979,7 @@ nf.PolicyManagement = (function () {
$('#selected-policy-component-id').text(d.id);
populateComponentResource('reporting-tasks');
- return loadPolicy().done(showPolicy);
+ return loadPolicy().always(showPolicy);
},
/**
@@ -941,7 +1007,7 @@ nf.PolicyManagement = (function () {
$('#selected-policy-component-id').text(d.id);
populateComponentResource('templates');
- return loadPolicy().done(showPolicy);
+ return loadPolicy().always(showPolicy);
},
/**
@@ -995,7 +1061,7 @@ nf.PolicyManagement = (function () {
// populate the initial resource
populateComponentResource(resource);
- return loadPolicy().done(showPolicy);
+ return loadPolicy().always(showPolicy);
},
/**
@@ -1021,7 +1087,7 @@ nf.PolicyManagement = (function () {
$('#selected-policy-action').text('read');
}
- return loadPolicy().done(showPolicy);
- },
+ return loadPolicy().always(showPolicy);
+ }
};
}());
\ No newline at end of file