Repository: nifi
Updated Branches:
  refs/heads/master 5e4ba0458 -> da238b16e


NIFI-2122: - Merging responses for the current user and the flow configuration. 
- Returning whether NiFi is configured with a policy based authorizer in the 
flow configuration. - Only showing the users and policy icons when configured 
with a policy based authorizer. - Failing faster when invoking the users or 
policies endpoint when not configured with a configurable authorizer.

This closes #736

Signed-off-by: jpercivall <[email protected]>


Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/da238b16
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/da238b16
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/da238b16

Branch: refs/heads/master
Commit: da238b16efacb46cb78847027de07b197f3f88d0
Parents: 5e4ba04
Author: Matt Gilman <[email protected]>
Authored: Thu Jul 28 16:22:58 2016 -0400
Committer: jpercivall <[email protected]>
Committed: Thu Jul 28 16:51:40 2016 -0400

----------------------------------------------------------------------
 .../nifi/web/api/dto/FlowConfigurationDTO.java  | 16 +++++
 .../http/StandardHttpResponseMerger.java        |  4 ++
 .../endpoints/CurrentUserEndpointMerger.java    | 65 ++++++++++++++++++++
 .../FlowConfigurationEndpointMerger.java        | 58 +++++++++++++++++
 .../nifi/web/api/AccessPolicyResource.java      | 27 ++++++++
 .../org/apache/nifi/web/api/FlowResource.java   |  8 +++
 .../apache/nifi/web/api/TenantsResource.java    | 61 +++++++++++++++++-
 .../org/apache/nifi/web/api/dto/DtoFactory.java |  2 +
 .../apache/nifi/web/dao/AccessPolicyDAO.java    |  2 +
 .../impl/StandardPolicyBasedAuthorizerDAO.java  |  1 -
 .../WEB-INF/partials/canvas/canvas-header.jsp   |  8 +--
 .../WEB-INF/partials/canvas/navigation.jsp      |  4 +-
 .../src/main/webapp/css/policy-management.css   |  2 +-
 .../src/main/webapp/js/nf/canvas/nf-canvas.js   | 11 ++++
 .../js/nf/canvas/nf-controller-services.js      |  6 +-
 .../src/main/webapp/js/nf/canvas/nf-settings.js |  6 +-
 .../js/nf/templates/nf-templates-table.js       |  9 +--
 17 files changed, 272 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowConfigurationDTO.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowConfigurationDTO.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowConfigurationDTO.java
index d5028d2..969168c 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowConfigurationDTO.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowConfigurationDTO.java
@@ -29,6 +29,7 @@ import java.util.Date;
 @XmlType(name = "flowConfiguration")
 public class FlowConfigurationDTO {
 
+    private Boolean supportsConfigurableAuthorizer;
     private Long autoRefreshIntervalSeconds;
 
     private Date currentTime;
@@ -50,6 +51,21 @@ public class FlowConfigurationDTO {
     }
 
     /**
+     * @return whether this NiFi supports a configurable authorizer. This 
value is read only
+     */
+    @ApiModelProperty(
+            value = "Whether this NiFi supports a configurable authorizer.",
+            readOnly = true
+    )
+    public Boolean getSupportsConfigurableAuthorizer() {
+        return supportsConfigurableAuthorizer;
+    }
+
+    public void setSupportsConfigurableAuthorizer(Boolean 
supportsConfigurableAuthorizer) {
+        this.supportsConfigurableAuthorizer = supportsConfigurableAuthorizer;
+    }
+
+    /**
      * @return current time on the server
      */
     @XmlJavaTypeAdapter(TimeAdapter.class)

http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/StandardHttpResponseMerger.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/StandardHttpResponseMerger.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/StandardHttpResponseMerger.java
index 8ff321d..ad9f33f 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/StandardHttpResponseMerger.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/StandardHttpResponseMerger.java
@@ -28,7 +28,9 @@ import 
org.apache.nifi.cluster.coordination.http.endpoints.ControllerServiceRefe
 import 
org.apache.nifi.cluster.coordination.http.endpoints.ControllerServicesEndpointMerger;
 import 
org.apache.nifi.cluster.coordination.http.endpoints.ControllerStatusEndpointMerger;
 import 
org.apache.nifi.cluster.coordination.http.endpoints.CountersEndpointMerger;
+import 
org.apache.nifi.cluster.coordination.http.endpoints.CurrentUserEndpointMerger;
 import 
org.apache.nifi.cluster.coordination.http.endpoints.DropRequestEndpiontMerger;
+import 
org.apache.nifi.cluster.coordination.http.endpoints.FlowConfigurationEndpointMerger;
 import org.apache.nifi.cluster.coordination.http.endpoints.FlowMerger;
 import 
org.apache.nifi.cluster.coordination.http.endpoints.FlowSnippetEndpointMerger;
 import 
org.apache.nifi.cluster.coordination.http.endpoints.GroupStatusEndpointMerger;
@@ -105,6 +107,8 @@ public class StandardHttpResponseMerger implements 
HttpResponseMerger {
         endpointMergers.add(new SystemDiagnosticsEndpointMerger());
         endpointMergers.add(new CountersEndpointMerger());
         endpointMergers.add(new FlowMerger());
+        endpointMergers.add(new CurrentUserEndpointMerger());
+        endpointMergers.add(new FlowConfigurationEndpointMerger());
         endpointMergers.add(new TemplatesEndpointMerger());
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/CurrentUserEndpointMerger.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/CurrentUserEndpointMerger.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/CurrentUserEndpointMerger.java
new file mode 100644
index 0000000..4a97d7a
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/CurrentUserEndpointMerger.java
@@ -0,0 +1,65 @@
+/*
+ * 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.cluster.coordination.http.endpoints;
+
+import org.apache.nifi.cluster.manager.NodeResponse;
+import org.apache.nifi.cluster.protocol.NodeIdentifier;
+import org.apache.nifi.web.api.dto.PermissionsDTO;
+import org.apache.nifi.web.api.entity.CurrentUserEntity;
+
+import java.net.URI;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+public class CurrentUserEndpointMerger extends 
AbstractSingleEntityEndpoint<CurrentUserEntity> {
+    public static final Pattern CURRENT_USER_URI_PATTERN = 
Pattern.compile("/nifi-api/flow/current-user");
+
+    @Override
+    public boolean canHandle(URI uri, String method) {
+        return "GET".equalsIgnoreCase(method) && 
CURRENT_USER_URI_PATTERN.matcher(uri.getPath()).matches();
+    }
+
+    @Override
+    protected Class<CurrentUserEntity> getEntityClass() {
+        return CurrentUserEntity.class;
+    }
+
+
+    @Override
+    protected void mergeResponses(final CurrentUserEntity clientEntity, final 
Map<NodeIdentifier, CurrentUserEntity> entityMap,
+                                  final Set<NodeResponse> successfulResponses, 
final Set<NodeResponse> problematicResponses) {
+
+        for (final Map.Entry<NodeIdentifier, CurrentUserEntity> entry : 
entityMap.entrySet()) {
+            final CurrentUserEntity entity = entry.getValue();
+            if (entity != clientEntity) {
+                mergePermissions(clientEntity.getControllerPermissions(), 
entity.getControllerPermissions());
+                mergePermissions(clientEntity.getCountersPermissions(), 
entity.getCountersPermissions());
+                mergePermissions(clientEntity.getPoliciesPermissions(), 
entity.getPoliciesPermissions());
+                mergePermissions(clientEntity.getProvenancePermissions(), 
entity.getProvenancePermissions());
+                mergePermissions(clientEntity.getTenantsPermissions(), 
entity.getTenantsPermissions());
+            }
+        }
+    }
+
+    private void mergePermissions(PermissionsDTO clientPermissions, 
PermissionsDTO permissions) {
+        clientPermissions.setCanRead(clientPermissions.getCanRead() && 
permissions.getCanRead());
+        clientPermissions.setCanWrite(clientPermissions.getCanWrite() && 
permissions.getCanWrite());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/FlowConfigurationEndpointMerger.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/FlowConfigurationEndpointMerger.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/FlowConfigurationEndpointMerger.java
new file mode 100644
index 0000000..22fa684
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/FlowConfigurationEndpointMerger.java
@@ -0,0 +1,58 @@
+/*
+ * 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.cluster.coordination.http.endpoints;
+
+import org.apache.nifi.cluster.protocol.NodeIdentifier;
+import org.apache.nifi.web.api.dto.FlowConfigurationDTO;
+import org.apache.nifi.web.api.entity.FlowConfigurationEntity;
+
+import java.net.URI;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+public class FlowConfigurationEndpointMerger extends 
AbstractNodeStatusEndpoint<FlowConfigurationEntity, FlowConfigurationDTO> {
+    public static final Pattern FLOW_CONFIGURATION_URI_PATTERN = 
Pattern.compile("/nifi-api/flow/config");
+
+    @Override
+    public boolean canHandle(URI uri, String method) {
+        return "GET".equalsIgnoreCase(method) && 
FLOW_CONFIGURATION_URI_PATTERN.matcher(uri.getPath()).matches();
+    }
+
+    @Override
+    protected Class<FlowConfigurationEntity> getEntityClass() {
+        return FlowConfigurationEntity.class;
+    }
+
+    @Override
+    protected FlowConfigurationDTO getDto(FlowConfigurationEntity entity) {
+        return entity.getFlowConfiguration();
+    }
+
+    @Override
+    protected void mergeResponses(FlowConfigurationDTO clientDto, 
Map<NodeIdentifier, FlowConfigurationDTO> dtoMap, NodeIdentifier 
selectedNodeId) {
+
+        for (final Map.Entry<NodeIdentifier, FlowConfigurationDTO> entry : 
dtoMap.entrySet()) {
+            final NodeIdentifier nodeId = entry.getKey();
+            final FlowConfigurationDTO toMerge = entry.getValue();
+            if (toMerge != clientDto) {
+                
clientDto.setSupportsConfigurableAuthorizer(clientDto.getSupportsConfigurableAuthorizer()
 && toMerge.getSupportsConfigurableAuthorizer());
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessPolicyResource.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/AccessPolicyResource.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessPolicyResource.java
index 8a03dbf..54f98f1 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessPolicyResource.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessPolicyResource.java
@@ -23,6 +23,7 @@ import com.wordnik.swagger.annotations.ApiResponse;
 import com.wordnik.swagger.annotations.ApiResponses;
 import com.wordnik.swagger.annotations.Authorization;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.authorization.AbstractPolicyBasedAuthorizer;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.Authorizable;
@@ -37,6 +38,7 @@ import org.apache.nifi.web.api.dto.RevisionDTO;
 import org.apache.nifi.web.api.entity.AccessPolicyEntity;
 import org.apache.nifi.web.api.request.ClientIdParameter;
 import org.apache.nifi.web.api.request.LongParameter;
+import org.apache.nifi.web.dao.AccessPolicyDAO;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
@@ -130,6 +132,11 @@ public class AccessPolicyResource extends 
ApplicationResource {
                     required = true
             ) @PathParam("resource") String rawResource) {
 
+        // ensure we're running with a configurable authorizer
+        if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) {
+            throw new 
IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
+        }
+
         // parse the action and resource type
         final RequestAction requestAction = RequestAction.valueOfValue(action);
         final String resource = "/" + rawResource;
@@ -189,6 +196,11 @@ public class AccessPolicyResource extends 
ApplicationResource {
                     required = true
             ) final AccessPolicyEntity accessPolicyEntity) {
 
+        // ensure we're running with a configurable authorizer
+        if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) {
+            throw new 
IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
+        }
+
         if (accessPolicyEntity == null || accessPolicyEntity.getComponent() == 
null) {
             throw new IllegalArgumentException("Access policy details must be 
specified.");
         }
@@ -277,6 +289,11 @@ public class AccessPolicyResource extends 
ApplicationResource {
             )
             @PathParam("id") final String id) {
 
+        // ensure we're running with a configurable authorizer
+        if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) {
+            throw new 
IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
+        }
+
         if (isReplicateRequest()) {
             return replicate(HttpMethod.GET);
         }
@@ -335,6 +352,11 @@ public class AccessPolicyResource extends 
ApplicationResource {
                     required = true
             ) final AccessPolicyEntity accessPolicyEntity) {
 
+        // ensure we're running with a configurable authorizer
+        if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) {
+            throw new 
IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
+        }
+
         if (accessPolicyEntity == null || accessPolicyEntity.getComponent() == 
null) {
             throw new IllegalArgumentException("Access policy details must be 
specified.");
         }
@@ -425,6 +447,11 @@ public class AccessPolicyResource extends 
ApplicationResource {
             )
             @PathParam("id") final String id) {
 
+        // ensure we're running with a configurable authorizer
+        if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) {
+            throw new 
IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
+        }
+
         if (isReplicateRequest()) {
             return replicate(HttpMethod.DELETE);
         }

http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/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 f9c6708..96e7dbc 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
@@ -300,6 +300,10 @@ public class FlowResource extends ApplicationResource {
 
         authorizeFlow();
 
+        if (isReplicateRequest()) {
+            return replicate(HttpMethod.GET);
+        }
+
         final FlowConfigurationEntity entity = 
serviceFacade.getFlowConfiguration();
         return clusterContext(generateOkResponse(entity)).build();
     }
@@ -321,6 +325,10 @@ public class FlowResource extends ApplicationResource {
 
         authorizeFlow();
 
+        if (isReplicateRequest()) {
+            return replicate(HttpMethod.GET);
+        }
+
         // note that the cluster manager will handle this request directly
         final NiFiUser user = NiFiUserUtils.getNiFiUser();
         if (user == null) {

http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TenantsResource.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/TenantsResource.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TenantsResource.java
index 860bf7f..b944bf7 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TenantsResource.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TenantsResource.java
@@ -23,6 +23,7 @@ import com.wordnik.swagger.annotations.ApiResponse;
 import com.wordnik.swagger.annotations.ApiResponses;
 import com.wordnik.swagger.annotations.Authorization;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.authorization.AbstractPolicyBasedAuthorizer;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.Authorizable;
@@ -45,6 +46,7 @@ import org.apache.nifi.web.api.entity.UserGroupsEntity;
 import org.apache.nifi.web.api.entity.UsersEntity;
 import org.apache.nifi.web.api.request.ClientIdParameter;
 import org.apache.nifi.web.api.request.LongParameter;
+import org.apache.nifi.web.dao.AccessPolicyDAO;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
@@ -105,7 +107,7 @@ public class TenantsResource extends ApplicationResource {
      * @return userEntity
      */
     public UserEntity populateRemainingUserEntityContent(UserEntity 
userEntity) {
-        userEntity.setUri(generateResourceUri("tenants/users", 
userEntity.getId()));
+        userEntity.setUri(generateResourceUri("tenants", "users", 
userEntity.getId()));
         return userEntity;
     }
 
@@ -144,6 +146,11 @@ public class TenantsResource extends ApplicationResource {
                     required = true
             ) final UserEntity userEntity) {
 
+        // ensure we're running with a configurable authorizer
+        if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) {
+            throw new 
IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
+        }
+
         if (userEntity == null || userEntity.getComponent() == null) {
             throw new IllegalArgumentException("User details must be 
specified.");
         }
@@ -224,6 +231,11 @@ public class TenantsResource extends ApplicationResource {
             )
             @PathParam("id") final String id) {
 
+        // ensure we're running with a configurable authorizer
+        if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) {
+            throw new 
IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
+        }
+
         if (isReplicateRequest()) {
             return replicate(HttpMethod.GET);
         }
@@ -271,6 +283,11 @@ public class TenantsResource extends ApplicationResource {
     )
     public Response getUsers() {
 
+        // ensure we're running with a configurable authorizer
+        if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) {
+            throw new 
IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
+        }
+
         if (isReplicateRequest()) {
             return replicate(HttpMethod.GET);
         }
@@ -334,6 +351,11 @@ public class TenantsResource extends ApplicationResource {
                     required = true
             ) final UserEntity userEntity) {
 
+        // ensure we're running with a configurable authorizer
+        if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) {
+            throw new 
IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
+        }
+
         if (userEntity == null || userEntity.getComponent() == null) {
             throw new IllegalArgumentException("User details must be 
specified.");
         }
@@ -424,6 +446,11 @@ public class TenantsResource extends ApplicationResource {
             )
             @PathParam("id") final String id) {
 
+        // ensure we're running with a configurable authorizer
+        if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) {
+            throw new 
IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
+        }
+
         if (isReplicateRequest()) {
             return replicate(HttpMethod.DELETE);
         }
@@ -466,7 +493,7 @@ public class TenantsResource extends ApplicationResource {
      * @return userGroupEntity
      */
     public UserGroupEntity 
populateRemainingUserGroupEntityContent(UserGroupEntity userGroupEntity) {
-        userGroupEntity.setUri(generateResourceUri("tenants/user-groups", 
userGroupEntity.getId()));
+        userGroupEntity.setUri(generateResourceUri("tenants", "user-groups", 
userGroupEntity.getId()));
         return userGroupEntity;
     }
 
@@ -505,6 +532,11 @@ public class TenantsResource extends ApplicationResource {
                     required = true
             ) final UserGroupEntity userGroupEntity) {
 
+        // ensure we're running with a configurable authorizer
+        if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) {
+            throw new 
IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
+        }
+
         if (userGroupEntity == null || userGroupEntity.getComponent() == null) 
{
             throw new IllegalArgumentException("User group details must be 
specified.");
         }
@@ -585,6 +617,11 @@ public class TenantsResource extends ApplicationResource {
             )
             @PathParam("id") final String id) {
 
+        // ensure we're running with a configurable authorizer
+        if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) {
+            throw new 
IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
+        }
+
         if (isReplicateRequest()) {
             return replicate(HttpMethod.GET);
         }
@@ -632,6 +669,11 @@ public class TenantsResource extends ApplicationResource {
     )
     public Response getUserGroups() {
 
+        // ensure we're running with a configurable authorizer
+        if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) {
+            throw new 
IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
+        }
+
         if (isReplicateRequest()) {
             return replicate(HttpMethod.GET);
         }
@@ -694,6 +736,11 @@ public class TenantsResource extends ApplicationResource {
                     required = true
             ) final UserGroupEntity userGroupEntity) {
 
+        // ensure we're running with a configurable authorizer
+        if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) {
+            throw new 
IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
+        }
+
         if (userGroupEntity == null || userGroupEntity.getComponent() == null) 
{
             throw new IllegalArgumentException("User group details must be 
specified.");
         }
@@ -784,6 +831,11 @@ public class TenantsResource extends ApplicationResource {
             )
             @PathParam("id") final String id) {
 
+        // ensure we're running with a configurable authorizer
+        if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) {
+            throw new 
IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
+        }
+
         if (isReplicateRequest()) {
             return replicate(HttpMethod.DELETE);
         }
@@ -846,6 +898,11 @@ public class TenantsResource extends ApplicationResource {
             )
             @QueryParam("q") @DefaultValue(StringUtils.EMPTY) String value) {
 
+        // ensure we're running with a configurable authorizer
+        if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) {
+            throw new 
IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
+        }
+
         if (isReplicateRequest()) {
             return replicate(HttpMethod.GET);
         }

http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.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/dto/DtoFactory.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
index 07d2143..93afccf 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
@@ -34,6 +34,7 @@ import org.apache.nifi.action.details.PurgeDetails;
 import org.apache.nifi.annotation.behavior.Stateful;
 import org.apache.nifi.annotation.documentation.CapabilityDescription;
 import org.apache.nifi.annotation.documentation.Tags;
+import org.apache.nifi.authorization.AbstractPolicyBasedAuthorizer;
 import org.apache.nifi.authorization.AccessPolicy;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.Group;
@@ -199,6 +200,7 @@ public final class DtoFactory {
         // get the refresh interval
         final long refreshInterval = 
FormatUtils.getTimeDuration(autoRefreshInterval, TimeUnit.SECONDS);
         dto.setAutoRefreshIntervalSeconds(refreshInterval);
+        dto.setSupportsConfigurableAuthorizer(authorizer instanceof 
AbstractPolicyBasedAuthorizer);
 
         final Date now = new Date();
         dto.setTimeOffset(TimeZone.getDefault().getOffset(now.getTime()));

http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/AccessPolicyDAO.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/AccessPolicyDAO.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/AccessPolicyDAO.java
index 009ec9c..1d48ee0 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/AccessPolicyDAO.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/AccessPolicyDAO.java
@@ -23,6 +23,8 @@ import org.apache.nifi.web.api.dto.AccessPolicyDTO;
 
 public interface AccessPolicyDAO {
 
+    String MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER = "This NiFi is not 
configured to internally manage users, groups, and policies.  Please contact 
your system administrator.";
+
     /**
      * Whether or not NiFi supports a configurable authorizer.
      *

http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAO.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAO.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAO.java
index 4c41584..24bcbef 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAO.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAO.java
@@ -44,7 +44,6 @@ import java.util.stream.Collectors;
 
 public class StandardPolicyBasedAuthorizerDAO implements AccessPolicyDAO, 
UserGroupDAO, UserDAO {
 
-    static final String MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER = "This NiFi 
is not configured to internally manage users, groups, and policies.  Please 
contact your system administrator.";
     private final AbstractPolicyBasedAuthorizer authorizer;
     private final boolean supportsConfigurableAuthorizer;
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp
index 7fc08a0..42bff59 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp
@@ -147,15 +147,15 @@
                             <i class="fa fa-history"></i>Flow Configuration 
History
                         </a>
                     </md-menu-item>
-                    <md-menu-divider></md-menu-divider>
-                    <md-menu-item layout-align="space-around center">
+                    <md-menu-divider 
ng-if="appCtrl.nf.Canvas.isConfigurableAuthorizer()"></md-menu-divider>
+                    <md-menu-item layout-align="space-around center" 
ng-if="appCtrl.nf.Canvas.isConfigurableAuthorizer()">
                         <a id="users-link" layout="row"
                            
ng-click="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.users.shell.launch();"
-                           ng-class="{disabled: 
!appCtrl.nf.Common.canAccessTenants()}">
+                           ng-class="{disabled: 
!(appCtrl.nf.Common.canAccessTenants())}">
                             <i class="fa fa-users"></i>Users
                         </a>
                     </md-menu-item>
-                    <md-menu-item layout-align="space-around center">
+                    <md-menu-item layout-align="space-around center" 
ng-if="appCtrl.nf.Canvas.isConfigurableAuthorizer()">
                         <a id="policies-link" layout="row"
                            
ng-click="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.policies.shell.launch();"
                            ng-class="{disabled: 
!(appCtrl.nf.Common.canAccessTenants() && 
appCtrl.nf.Common.canModifyPolicies())}">

http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/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 3e719e9..7babfa0 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
@@ -99,8 +99,8 @@
                                 
ng-disabled="!(appCtrl.serviceProvider.graphControlsCtrl.canConfigureOrOpenDetails())">
                             <div class="graph-control-action-icon fa 
fa-gear"></div></button>
                     </div>
-                    <div class="button-spacer-small">&nbsp;</div>
-                    <div id="operate-policy" class="action-button" 
title="Access Policies">
+                    <div class="button-spacer-small" 
ng-if="appCtrl.nf.Canvas.isConfigurableAuthorizer()">&nbsp;</div>
+                    <div id="operate-policy" class="action-button" 
title="Access Policies" ng-if="appCtrl.nf.Canvas.isConfigurableAuthorizer()">
                         <button 
ng-click="appCtrl.nf.Actions['managePolicies'](appCtrl.nf.CanvasUtils.getSelection());"
                                 
ng-disabled="!(appCtrl.serviceProvider.graphControlsCtrl.canManagePolicies())">
                             <div class="graph-control-action-icon fa 
fa-key"></div></button>

http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/policy-management.css
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/policy-management.css
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/policy-management.css
index 919f4c0..6259c4f 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/policy-management.css
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/policy-management.css
@@ -133,7 +133,7 @@ div.policy-selected-component-name {
     color: #262626;
     width: 300px;
     text-overflow: ellipsis;
-    overflow-x: hidden;
+    overflow: hidden;
     white-space: nowrap;
 }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
index 6f54962..54d5845 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
@@ -118,6 +118,7 @@ nf.Canvas = (function () {
     var parentGroupId = null;
     var clustered = false;
     var connectedToCluster = false;
+    var configurableAuthorizer = false;
     var svg = null;
     var canvas = null;
 
@@ -884,6 +885,9 @@ nf.Canvas = (function () {
                     // get the auto refresh interval
                     var autoRefreshIntervalSeconds = 
parseInt(configDetails.autoRefreshIntervalSeconds, 10);
 
+                    // record whether we can configure the authorizer
+                    configurableAuthorizer = 
configDetails.supportsConfigurableAuthorizer;
+
                     // init storage
                     nf.Storage.init();
 
@@ -1009,6 +1013,13 @@ nf.Canvas = (function () {
         },
 
         /**
+         * Returns whether the authorizer is configurable.
+         */
+        isConfigurableAuthorizer: function () {
+            return configurableAuthorizer;
+        },
+
+        /**
          * Whether the current user can write in this group.
          *
          * @returns {boolean}   can write

http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js
index e77ab19..fc00517 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js
@@ -605,8 +605,10 @@ nf.ControllerServices = (function () {
                 }
             }
 
-            // TODO - only if we can adminster policies
-            markup += '<div title="Access Policies" class="pointer 
edit-access-policies fa fa-key" style="margin-top: 2px;"></div>';
+            // allow policy configuration conditionally
+            if (nf.Canvas.isConfigurableAuthorizer() && 
nf.Common.canAccessTenants()) {
+                markup += '<div title="Access Policies" class="pointer 
edit-access-policies fa fa-key" style="margin-top: 2px;"></div>';
+            }
 
             return markup;
         };

http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js
index 74f1ea6..5456a02 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js
@@ -682,8 +682,10 @@ nf.Settings = (function () {
                 }
             }
 
-            // TODO - only if we can adminster policies
-            markup += '<div title="Access Policies" class="pointer 
edit-access-policies fa fa-key" style="margin-top: 2px;"></div>';
+            // allow policy configuration conditionally
+            if (nf.Canvas.isConfigurableAuthorizer() && 
nf.Common.canAccessTenants()) {
+                markup += '<div title="Access Policies" class="pointer 
edit-access-policies fa fa-key" style="margin-top: 2px;"></div>';
+            }
 
             return markup;
         };

http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/templates/nf-templates-table.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/templates/nf-templates-table.js
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/templates/nf-templates-table.js
index 272a1fe..6afba5e 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/templates/nf-templates-table.js
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/templates/nf-templates-table.js
@@ -283,10 +283,11 @@ nf.TemplatesTable = (function () {
                     markup += '<div title="Remove Template" class="pointer 
prompt-to-delete-template fa fa-trash" style="margin-top: 2px; margin-right: 
3px;"></div>';
                 }
 
-                // if we in the shell
-                // TODO - only if we can adminster policies
-                if (top !== window) {
-                    markup += '<div title="Access Policies" class="pointer 
edit-access-policies fa fa-key" style="margin-top: 2px;"></div>';
+                // allow policy configuration conditionally
+                if (top !== window && nf.Common.canAccessTenants()) {
+                    if (nf.Common.isDefinedAndNotNull(parent.nf) && 
nf.Common.isDefinedAndNotNull(parent.nf.Canvas) && 
parent.nf.Canvas.isConfigurableAuthorizer()) {
+                        markup += '<div title="Access Policies" class="pointer 
edit-access-policies fa fa-key" style="margin-top: 2px;"></div>';
+                    }
                 }
 
                 return markup;

Reply via email to