You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by ym...@apache.org on 2017/07/24 19:52:59 UTC

[2/3] nifi git commit: NIFI-4032: - Introducing the ManagedRangerAuthorizer. - Introducing the AuthorizationAuditor. - Updating authorization requests to utilize Authorizable where ever possible so allow for a singular place to audit resource not found a

http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProvenanceResource.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/ProvenanceResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProvenanceResource.java
index c17ad85..55ed489 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProvenanceResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProvenanceResource.java
@@ -22,16 +22,9 @@ import com.wordnik.swagger.annotations.ApiParam;
 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.AccessDeniedException;
-import org.apache.nifi.authorization.AuthorizationRequest;
-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.UserContextKeys;
-import org.apache.nifi.authorization.resource.ResourceFactory;
-import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.resource.Authorizable;
 import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.web.NiFiServiceFacade;
 import org.apache.nifi.web.api.dto.provenance.ProvenanceDTO;
@@ -101,31 +94,10 @@ public class ProvenanceResource extends ApplicationResource {
     }
 
     private void authorizeProvenanceRequest() {
-        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(ResourceFactory.getProvenanceResource())
-                .identity(user.getIdentity())
-                .groups(user.getGroups())
-                .anonymous(user.isAnonymous())
-                .accessAttempt(true)
-                .action(RequestAction.READ)
-                .userContext(userContext)
-                .explanationSupplier(() -> "Unable to query provenance.")
-                .build();
-
-        final AuthorizationResult result = authorizer.authorize(request);
-        if (!Result.Approved.equals(result.getResult())) {
-            throw new AccessDeniedException(result.getExplanation());
-        }
+        serviceFacade.authorizeAccess(lookup -> {
+            final Authorizable provenance = lookup.getProvenance();
+            provenance.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
+        });
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ResourceResource.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/ResourceResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ResourceResource.java
index 1c91e5e..f957302 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ResourceResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ResourceResource.java
@@ -21,16 +21,9 @@ import com.wordnik.swagger.annotations.ApiOperation;
 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.AccessDeniedException;
-import org.apache.nifi.authorization.AuthorizationRequest;
-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.UserContextKeys;
-import org.apache.nifi.authorization.resource.ResourceFactory;
-import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.resource.Authorizable;
 import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.web.NiFiServiceFacade;
 import org.apache.nifi.web.api.dto.ResourceDTO;
@@ -43,9 +36,7 @@ import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 /**
  * RESTful endpoint for retrieving system diagnostics.
@@ -61,31 +52,10 @@ public class ResourceResource extends ApplicationResource {
     private Authorizer authorizer;
 
     private void authorizeResource() {
-        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(ResourceFactory.getResourceResource())
-                .identity(user.getIdentity())
-                .groups(user.getGroups())
-                .anonymous(user.isAnonymous())
-                .accessAttempt(true)
-                .action(RequestAction.READ)
-                .userContext(userContext)
-                .explanationSupplier(() -> "Unable to retrieve resources.")
-                .build();
-
-        final AuthorizationResult result = authorizer.authorize(request);
-        if (!Result.Approved.equals(result.getResult())) {
-            throw new AccessDeniedException(result.getExplanation());
-        }
+        serviceFacade.authorizeAccess(lookup -> {
+            final Authorizable resource = lookup.getResource();
+            resource.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
+        });
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SiteToSiteResource.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/SiteToSiteResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SiteToSiteResource.java
index fc6d4dd..2e17637 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SiteToSiteResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SiteToSiteResource.java
@@ -22,16 +22,9 @@ import com.wordnik.swagger.annotations.ApiOperation;
 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.AccessDeniedException;
-import org.apache.nifi.authorization.AuthorizationRequest;
-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.UserContextKeys;
-import org.apache.nifi.authorization.resource.ResourceFactory;
-import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.resource.Authorizable;
 import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.cluster.coordination.ClusterCoordinator;
 import org.apache.nifi.cluster.coordination.node.NodeWorkload;
@@ -63,7 +56,6 @@ import java.io.IOException;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -99,31 +91,10 @@ public class SiteToSiteResource extends ApplicationResource {
      * Note: Protected for testing purposes
      */
     protected void authorizeSiteToSite() {
-        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(ResourceFactory.getSiteToSiteResource())
-                .identity(user.getIdentity())
-                .groups(user.getGroups())
-                .anonymous(user.isAnonymous())
-                .accessAttempt(true)
-                .action(RequestAction.READ)
-                .userContext(userContext)
-                .explanationSupplier(() -> "Unable to retrieve site to site details.")
-                .build();
-
-        final AuthorizationResult result = authorizer.authorize(request);
-        if (!Result.Approved.equals(result.getResult())) {
-            throw new AccessDeniedException(result.getExplanation());
-        }
+        serviceFacade.authorizeAccess(lookup -> {
+            final Authorizable siteToSite = lookup.getSiteToSite();
+            siteToSite.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
+        });
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SystemDiagnosticsResource.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/SystemDiagnosticsResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SystemDiagnosticsResource.java
index 063f96c..ff69e60 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SystemDiagnosticsResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SystemDiagnosticsResource.java
@@ -22,16 +22,9 @@ import com.wordnik.swagger.annotations.ApiParam;
 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.AccessDeniedException;
-import org.apache.nifi.authorization.AuthorizationRequest;
-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.UserContextKeys;
-import org.apache.nifi.authorization.resource.ResourceFactory;
-import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.resource.Authorizable;
 import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.cluster.manager.NodeResponse;
 import org.apache.nifi.web.NiFiServiceFacade;
@@ -47,8 +40,6 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import java.util.HashMap;
-import java.util.Map;
 
 /**
  * RESTful endpoint for retrieving system diagnostics.
@@ -64,31 +55,10 @@ public class SystemDiagnosticsResource extends ApplicationResource {
     private Authorizer authorizer;
 
     private void authorizeSystem() {
-        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(ResourceFactory.getSystemResource())
-                .identity(user.getIdentity())
-                .groups(user.getGroups())
-                .anonymous(user.isAnonymous())
-                .accessAttempt(true)
-                .action(RequestAction.READ)
-                .userContext(userContext)
-                .explanationSupplier(() -> "Unable to view system diagnostics.")
-                .build();
-
-        final AuthorizationResult result = authorizer.authorize(request);
-        if (!Result.Approved.equals(result.getResult())) {
-            throw new AccessDeniedException(result.getExplanation());
-        }
+        serviceFacade.authorizeAccess(lookup -> {
+            final Authorizable system = lookup.getSystem();
+            system.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
+        });
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/NiFiWebApiTest.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/NiFiWebApiTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/NiFiWebApiTest.java
index 556c6bc..ce8f18a 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/NiFiWebApiTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/NiFiWebApiTest.java
@@ -84,6 +84,7 @@ public class NiFiWebApiTest {
         processorEntity = response.getEntity(ProcessorEntity.class);
         processorDTO = processorEntity.getComponent();
         String localSelectionId = processorDTO.getId();
+        String localSelectionGroupId = processorDTO.getParentGroupId();
 
         // -----------------------------------------------
         // Create a termination processor
@@ -114,6 +115,7 @@ public class NiFiWebApiTest {
         processorEntity = response.getEntity(ProcessorEntity.class);
         processorDTO = processorEntity.getComponent();
         String terminationId = processorDTO.getId();
+        String terminationGroupId = processorDTO.getParentGroupId();
 
         // -----------------------------------------------
         // Connect the two processors
@@ -121,10 +123,12 @@ public class NiFiWebApiTest {
 
         ConnectableDTO source = new ConnectableDTO();
         source.setId(localSelectionId);
+        source.setGroupId(localSelectionGroupId);
         source.setType(ConnectableType.PROCESSOR.name());
 
         ConnectableDTO target = new ConnectableDTO();
         target.setId(terminationId);
+        target.setGroupId(terminationGroupId);
         target.setType(ConnectableType.PROCESSOR.name());
 
         // create the relationships

http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ITConnectionAccessControl.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ITConnectionAccessControl.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ITConnectionAccessControl.java
index dcc00d9..bb2d4eb 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ITConnectionAccessControl.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ITConnectionAccessControl.java
@@ -358,11 +358,13 @@ public class ITConnectionAccessControl {
         // create the source connectable
         ConnectableDTO source = new ConnectableDTO();
         source.setId(one.getId());
+        source.setGroupId(one.getComponent().getParentGroupId());
         source.setType(ConnectableType.PROCESSOR.name());
 
         // create the target connectable
         ConnectableDTO target = new ConnectableDTO();
         target.setId(two.getId());
+        target.setGroupId(two.getComponent().getParentGroupId());
         target.setType(ConnectableType.PROCESSOR.name());
 
         // create the relationships

http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationProvider.java
index 5636c2d..ec162c7 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationProvider.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationProvider.java
@@ -46,6 +46,7 @@ public abstract class NiFiAuthenticationProvider implements AuthenticationProvid
     public NiFiAuthenticationProvider(final NiFiProperties properties, final Authorizer authorizer) {
         this.properties = properties;
         this.mappings = Collections.unmodifiableList(IdentityMappingUtil.getIdentityMappings(properties));
+        this.authorizer = authorizer;
     }
 
     public List<IdentityMapping> getMappings() {

http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.java
index 510e136..564171f 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.java
@@ -18,12 +18,12 @@ package org.apache.nifi.web.security.x509;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authentication.AuthenticationResponse;
-import org.apache.nifi.authorization.AuthorizationRequest;
-import org.apache.nifi.authorization.AuthorizationResult;
-import org.apache.nifi.authorization.AuthorizationResult.Result;
+import org.apache.nifi.authorization.AccessDeniedException;
 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;
 import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.authorization.user.NiFiUserDetails;
@@ -50,6 +50,18 @@ import java.util.Set;
  */
 public class X509AuthenticationProvider extends NiFiAuthenticationProvider {
 
+    private static final Authorizable PROXY_AUTHORIZABLE = new Authorizable() {
+        @Override
+        public Authorizable getParentAuthorizable() {
+            return null;
+        }
+
+        @Override
+        public Resource getResource() {
+            return ResourceFactory.getProxyResource();
+        }
+    };
+
     private X509IdentityProvider certificateIdentityProvider;
     private Authorizer authorizer;
 
@@ -94,27 +106,17 @@ public class X509AuthenticationProvider extends NiFiAuthenticationProvider {
 
                 final Set<String> groups = getUserGroups(identity);
 
+                // Only set the client address for client making the request because we don't know the clientAddress of the proxied entities
+                String clientAddress = (proxy == null) ? request.getClientAddress() : null;
+                proxy = createUser(identity, groups, proxy, clientAddress, isAnonymous);
+
                 if (chainIter.hasPrevious()) {
-                    // authorize this proxy in order to authenticate this user
-                    final AuthorizationRequest proxyAuthorizationRequest = new AuthorizationRequest.Builder()
-                            .identity(identity)
-                            .groups(groups)
-                            .anonymous(isAnonymous)
-                            .accessAttempt(true)
-                            .action(RequestAction.WRITE)
-                            .resource(ResourceFactory.getProxyResource())
-                            .userContext(proxy == null ? getUserContext(request) : null) // only set the context for the real user
-                            .build();
-
-                    final AuthorizationResult proxyAuthorizationResult = authorizer.authorize(proxyAuthorizationRequest);
-                    if (!Result.Approved.equals(proxyAuthorizationResult.getResult())) {
+                    try {
+                        PROXY_AUTHORIZABLE.authorize(authorizer, RequestAction.WRITE, proxy);
+                    } catch (final AccessDeniedException e) {
                         throw new UntrustedProxyException(String.format("Untrusted proxy %s", identity));
                     }
                 }
-
-                // Only set the client address for user making the request because we don't know the client address of the proxies
-                String clientAddress = (proxy == null) ? request.getClientAddress() : null;
-                proxy = createUser(identity, groups, proxy, clientAddress, isAnonymous);
             }
 
             return new NiFiAuthenticationToken(new NiFiUserDetails(proxy));

http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/ManagedRangerAuthorizer.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/ManagedRangerAuthorizer.java b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/ManagedRangerAuthorizer.java
new file mode 100644
index 0000000..7c16a80
--- /dev/null
+++ b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/ManagedRangerAuthorizer.java
@@ -0,0 +1,205 @@
+/*
+ * 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.ranger.authorization;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.nifi.authorization.AccessPolicy;
+import org.apache.nifi.authorization.AccessPolicyProvider;
+import org.apache.nifi.authorization.AccessPolicyProviderInitializationContext;
+import org.apache.nifi.authorization.AuthorizerConfigurationContext;
+import org.apache.nifi.authorization.AuthorizerInitializationContext;
+import org.apache.nifi.authorization.ConfigurableUserGroupProvider;
+import org.apache.nifi.authorization.ManagedAuthorizer;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.UserGroupProvider;
+import org.apache.nifi.authorization.UserGroupProviderLookup;
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.authorization.exception.AuthorizerCreationException;
+import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
+import org.apache.nifi.authorization.exception.UninheritableAuthorizationsException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.Set;
+
+public class ManagedRangerAuthorizer extends RangerNiFiAuthorizer implements ManagedAuthorizer {
+
+    private static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
+
+    private static final String USER_GROUP_PROVIDER_ELEMENT = "userGroupProvider";
+
+    private UserGroupProviderLookup userGroupProviderLookup;
+    private UserGroupProvider userGroupProvider;
+    private RangerBasePluginWithPolicies nifiPlugin;
+
+    @Override
+    public void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException {
+        userGroupProviderLookup = initializationContext.getUserGroupProviderLookup();
+
+        super.initialize(initializationContext);
+    }
+
+    @Override
+    public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
+        final String userGroupProviderKey = configurationContext.getProperty("User Group Provider").getValue();
+        userGroupProvider = userGroupProviderLookup.getUserGroupProvider(userGroupProviderKey);
+
+        // ensure the desired access policy provider has a user group provider
+        if (userGroupProvider == null) {
+            throw new AuthorizerCreationException(String.format("Unable to locate configured User Group Provider: %s", userGroupProviderKey));
+        }
+
+        super.onConfigured(configurationContext);
+    }
+
+    @Override
+    protected RangerBasePluginWithPolicies createRangerBasePlugin(final String serviceType, final String appId) {
+        // override the method for creating the ranger base plugin so a user group provider can be specified
+        nifiPlugin = new RangerBasePluginWithPolicies(serviceType, appId, userGroupProvider);
+        return nifiPlugin;
+    }
+
+    @Override
+    public AccessPolicyProvider getAccessPolicyProvider() {
+        return new AccessPolicyProvider() {
+            @Override
+            public Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException {
+                return nifiPlugin.getAccessPolicies();
+            }
+
+            @Override
+            public AccessPolicy getAccessPolicy(String identifier) throws AuthorizationAccessException {
+                return nifiPlugin.getAccessPolicy(identifier);
+            }
+
+            @Override
+            public AccessPolicy getAccessPolicy(String resourceIdentifier, RequestAction action) throws AuthorizationAccessException {
+                return nifiPlugin.getAccessPolicy(resourceIdentifier, action);
+            }
+
+            @Override
+            public UserGroupProvider getUserGroupProvider() {
+                return userGroupProvider;
+            }
+
+            @Override
+            public void initialize(AccessPolicyProviderInitializationContext initializationContext) throws AuthorizerCreationException {
+            }
+
+            @Override
+            public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
+            }
+
+            @Override
+            public void preDestruction() throws AuthorizerDestructionException {
+            }
+        };
+    }
+
+    @Override
+    public String getFingerprint() throws AuthorizationAccessException {
+        final StringWriter out = new StringWriter();
+        try {
+            // create the document
+            final DocumentBuilder documentBuilder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
+            final Document document = documentBuilder.newDocument();
+
+            // create the root element
+            final Element managedRangerAuthorizationsElement = document.createElement("managedRangerAuthorizations");
+            document.appendChild(managedRangerAuthorizationsElement);
+
+            // create the user group provider element
+            final Element userGroupProviderElement = document.createElement(USER_GROUP_PROVIDER_ELEMENT);
+            managedRangerAuthorizationsElement.appendChild(userGroupProviderElement);
+
+            // append fingerprint if the provider is configurable
+            if (userGroupProvider instanceof ConfigurableUserGroupProvider) {
+                userGroupProviderElement.appendChild(document.createTextNode(((ConfigurableUserGroupProvider) userGroupProvider).getFingerprint()));
+            }
+
+            final Transformer transformer = TransformerFactory.newInstance().newTransformer();
+            transformer.transform(new DOMSource(document), new StreamResult(out));
+        } catch (ParserConfigurationException | TransformerException e) {
+            throw new AuthorizationAccessException("Unable to generate fingerprint", e);
+        }
+
+        return out.toString();
+    }
+
+    @Override
+    public void inheritFingerprint(String fingerprint) throws AuthorizationAccessException {
+        if (StringUtils.isBlank(fingerprint)) {
+            return;
+        }
+
+        final String userGroupFingerprint = parseFingerprint(fingerprint);
+
+        if (StringUtils.isNotBlank(userGroupFingerprint) && userGroupProvider instanceof ConfigurableUserGroupProvider) {
+            ((ConfigurableUserGroupProvider) userGroupProvider).inheritFingerprint(userGroupFingerprint);
+        }
+    }
+
+    @Override
+    public void checkInheritability(String proposedFingerprint) throws AuthorizationAccessException, UninheritableAuthorizationsException {
+        final String userGroupFingerprint = parseFingerprint(proposedFingerprint);
+
+        if (StringUtils.isNotBlank(userGroupFingerprint)) {
+            if (userGroupProvider instanceof ConfigurableUserGroupProvider) {
+                ((ConfigurableUserGroupProvider) userGroupProvider).checkInheritability(userGroupFingerprint);
+            } else {
+                throw new UninheritableAuthorizationsException("User/Group fingerprint is not blank and the configured UserGroupProvider does not support fingerprinting.");
+            }
+        }
+    }
+
+    private final String parseFingerprint(final String fingerprint) throws AuthorizationAccessException {
+        final byte[] fingerprintBytes = fingerprint.getBytes(StandardCharsets.UTF_8);
+
+        try (final ByteArrayInputStream in = new ByteArrayInputStream(fingerprintBytes)) {
+            final DocumentBuilder docBuilder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
+            final Document document = docBuilder.parse(in);
+            final Element rootElement = document.getDocumentElement();
+
+            final NodeList userGroupProviderList = rootElement.getElementsByTagName(USER_GROUP_PROVIDER_ELEMENT);
+            if (userGroupProviderList.getLength() != 1) {
+                throw new AuthorizationAccessException(String.format("Only one %s element is allowed: %s", USER_GROUP_PROVIDER_ELEMENT, fingerprint));
+            }
+
+            final Node userGroupProvider = userGroupProviderList.item(0);
+            return userGroupProvider.getTextContent();
+        } catch (SAXException | ParserConfigurationException | IOException e) {
+            throw new AuthorizationAccessException("Unable to parse fingerprint", e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerBasePluginWithPolicies.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerBasePluginWithPolicies.java b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerBasePluginWithPolicies.java
index 8b664de..c74a7d1 100644
--- a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerBasePluginWithPolicies.java
+++ b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerBasePluginWithPolicies.java
@@ -18,38 +18,55 @@
  */
 package org.apache.nifi.ranger.authorization;
 
+import org.apache.nifi.authorization.AccessPolicy;
+import org.apache.nifi.authorization.Group;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.User;
+import org.apache.nifi.authorization.UserGroupProvider;
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.util.StringUtils;
 import org.apache.ranger.plugin.service.RangerBasePlugin;
 import org.apache.ranger.plugin.util.ServicePolicies;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 /**
- * Extends the base plugin to add ability to check if a policy exists for a given resource.
+ * Extends the base plugin to convert service policies into NiFi policy domain model.
  */
 public class RangerBasePluginWithPolicies extends RangerBasePlugin {
 
-    private AtomicReference<Set<String>> resources = new AtomicReference<>(new HashSet<>());
+    private static final Logger logger = LoggerFactory.getLogger(RangerBasePluginWithPolicies.class);
 
-    public RangerBasePluginWithPolicies(String serviceType, String appId) {
+    private UserGroupProvider userGroupProvider;
+    private AtomicReference<PolicyLookup> policies = new AtomicReference<>(new PolicyLookup());
+
+    public RangerBasePluginWithPolicies(final String serviceType, final String appId) {
+        this(serviceType, appId, null);
+    }
+
+    public RangerBasePluginWithPolicies(final String serviceType, final String appId, final UserGroupProvider userGroupProvider) {
         super(serviceType, appId);
+        this.userGroupProvider = userGroupProvider; // will be null if used outside of the ManagedRangerAuthorizer
     }
 
     @Override
-    public void setPolicies(ServicePolicies policies) {
+    public void setPolicies(final ServicePolicies policies) {
         super.setPolicies(policies);
 
         if (policies == null || policies.getPolicies() == null) {
-            this.resources.set(new HashSet<>());
+            this.policies.set(new PolicyLookup());
         } else {
-            final Set<String> newResources = policies.getPolicies().stream()
-                    .flatMap(p -> p.getResources().values().stream())
-                    .flatMap(r -> r.getValues().stream())
-                    .collect(Collectors.toSet());
-
-            this.resources.set(newResources);
+            this.policies.set(createPolicyLookup(policies));
         }
     }
 
@@ -60,16 +77,197 @@ public class RangerBasePluginWithPolicies extends RangerBasePlugin {
      *
      * @return true if a policy exists for the given resource, false otherwise
      */
-    public boolean doesPolicyExist(String resourceIdentifier) {
+    public boolean doesPolicyExist(final String resourceIdentifier, final RequestAction requestAction) {
         if (resourceIdentifier == null) {
             return false;
         }
 
-        final Set<String> currResources = resources.get();
-        if (currResources == null) {
-            return false;
+        final PolicyLookup policyLookup = policies.get();
+        return policyLookup.getAccessPolicy(resourceIdentifier, requestAction) != null;
+    }
+
+    public Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException {
+        return policies.get().getAccessPolicies();
+    }
+
+    public AccessPolicy getAccessPolicy(String identifier) throws AuthorizationAccessException {
+        return policies.get().getAccessPolicy(identifier);
+    }
+
+    public AccessPolicy getAccessPolicy(String resourceIdentifier, RequestAction action) throws AuthorizationAccessException {
+        return policies.get().getAccessPolicy(resourceIdentifier, action);
+    }
+
+    private PolicyLookup createPolicyLookup(final ServicePolicies servicePolicies) {
+        final Map<String, AccessPolicy> policiesByIdentifier = new HashMap<>();
+        final Map<String, Map<RequestAction, AccessPolicy>> policiesByResource = new HashMap<>();
+
+        logger.info("Converting Ranger ServicePolicies model into NiFi policy model for viewing purposes in NiFi UI.");
+
+        servicePolicies.getPolicies().stream().forEach(policy -> {
+            // only consider policies that are enabled
+            if (Boolean.TRUE.equals(policy.getIsEnabled())) {
+                // get all the resources for this policy - excludes/recursive support disabled
+                final Set<String> resources = policy.getResources().values().stream()
+                        .filter(resource -> {
+                            final boolean isExclude = Boolean.TRUE.equals(resource.getIsExcludes());
+                            final boolean isRecursive =  Boolean.TRUE.equals(resource.getIsRecursive());
+
+                            if (isExclude) {
+                                logger.warn(String.format("Resources [%s] marked as an exclude policy. Skipping policy for viewing purposes. "
+                                        + "Will still be used for access decisions.", StringUtils.join(resource.getValues(), ", ")));
+                            }
+                            if (isRecursive) {
+                                logger.warn(String.format("Resources [%s] marked as a recursive policy. Skipping policy for viewing purposes. "
+                                        + "Will still be used for access decisions.", StringUtils.join(resource.getValues(), ", ")));
+                            }
+
+                            return !isExclude && !isRecursive;
+                        })
+                        .flatMap(resource -> resource.getValues().stream())
+                        .collect(Collectors.toSet());
+
+                policy.getPolicyItems().forEach(policyItem -> {
+                    // get all the users for this policy item, excluding unknown users
+                    final Set<String> userIds = policyItem.getUsers().stream()
+                            .map(userIdentity -> getUser(userIdentity))
+                            .filter(Objects::nonNull)
+                            .map(user -> user.getIdentifier())
+                            .collect(Collectors.toSet());
+
+                    // get all groups for this policy item, excluding unknown groups
+                    final Set<String> groupIds = policyItem.getGroups().stream()
+                            .map(groupName -> getGroup(groupName))
+                            .filter(Objects::nonNull)
+                            .map(group -> group.getIdentifier())
+                            .collect(Collectors.toSet());
+
+                    // check if this policy item is a delegate admin
+                    final boolean isDelegateAdmin = Boolean.TRUE.equals(policyItem.getDelegateAdmin());
+
+                    policyItem.getAccesses().forEach(access -> {
+                        try {
+                            // interpret the request action
+                            final RequestAction action = RequestAction.valueOf(access.getType());
+
+                            // function for creating an access policy
+                            final Function<String, AccessPolicy> createPolicy = resource -> new AccessPolicy.Builder()
+                                    .identifierGenerateFromSeed(resource + access.getType())
+                                    .resource(resource)
+                                    .action(action)
+                                    .addUsers(userIds)
+                                    .addGroups(groupIds)
+                                    .build();
+
+                            resources.forEach(resource -> {
+                                // create the access policy for the specified resource
+                                final AccessPolicy accessPolicy = createPolicy.apply(resource);
+                                policiesByIdentifier.put(accessPolicy.getIdentifier(), accessPolicy);
+                                policiesByResource.computeIfAbsent(resource, r -> new HashMap<>()).put(action, accessPolicy);
+
+                                // if this is a delegate admin, also create the admin policy for the specified resource
+                                if (isDelegateAdmin) {
+                                    //  build the admin resource identifier
+                                    final String adminResource;
+                                    if (resource.startsWith("/")) {
+                                        adminResource = "/policies" + resource;
+                                    } else {
+                                        adminResource = "/policies/" + resource;
+                                    }
+
+                                    final AccessPolicy adminAccessPolicy = createPolicy.apply(adminResource);
+                                    policiesByIdentifier.put(adminAccessPolicy.getIdentifier(), adminAccessPolicy);
+                                    policiesByResource.computeIfAbsent(adminResource, ar -> new HashMap<>()).put(action, adminAccessPolicy);
+                                }
+                            });
+                        } catch (final IllegalArgumentException e) {
+                            logger.warn(String.format("Unrecognized request action '%s'. Skipping policy for viewing purposes. Will still be used for access decisions.", access.getType()));
+                        }
+                    });
+                });
+            }
+        });
+
+        return new PolicyLookup(policiesByIdentifier, policiesByResource);
+    }
+
+    private User getUser(final String identity) {
+        if (userGroupProvider == null) {
+            // generate the user deterministically when running outside of the ManagedRangerAuthorizer
+            return new User.Builder().identifierGenerateFromSeed(identity).identity(identity).build();
+        } else {
+            // find the user in question
+            final User user = userGroupProvider.getUserByIdentity(identity);
+
+            if (user == null) {
+                logger.warn(String.format("Cannot find user '%s' in the configured User Group Provider. Skipping user for viewing purposes. Will still be used for access decisions.", identity));
+            }
+
+            return user;
+        }
+    }
+
+    private Group getGroup(final String name) {
+        if (userGroupProvider == null) {
+            // generate the group deterministically when running outside of the ManagedRangerAuthorizer
+            return new Group.Builder().identifierGenerateFromSeed(name).name(name).build();
         } else {
-            return currResources.contains(resourceIdentifier);
+            // find the group in question
+            final Group group = userGroupProvider.getGroups().stream().filter(g -> g.getName().equals(name)).findFirst().orElse(null);
+
+            if (group == null) {
+                logger.warn(String.format("Cannot find group '%s' in the configured User Group Provider. Skipping group for viewing purposes. Will still be used for access decisions.", name));
+            }
+
+            return group;
+        }
+    }
+
+    private static class PolicyLookup {
+
+        private final Map<String, AccessPolicy> policiesByIdentifier;
+        private final Map<String, Map<RequestAction, AccessPolicy>> policiesByResource;
+        private final Set<AccessPolicy> allPolicies;
+
+        private PolicyLookup() {
+            this(null, null);
+        }
+
+        private PolicyLookup(final Map<String, AccessPolicy> policiesByIdentifier, final Map<String, Map<RequestAction, AccessPolicy>> policiesByResource) {
+            if (policiesByIdentifier == null) {
+                allPolicies = Collections.EMPTY_SET;
+            } else {
+                allPolicies = Collections.unmodifiableSet(new HashSet<>(policiesByIdentifier.values()));
+            }
+
+            this.policiesByIdentifier = policiesByIdentifier;
+            this.policiesByResource = policiesByResource;
+        }
+
+        private Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException {
+            return allPolicies;
+        }
+
+        private AccessPolicy getAccessPolicy(String identifier) throws AuthorizationAccessException {
+            if (policiesByIdentifier == null) {
+                return null;
+            }
+
+            return policiesByIdentifier.get(identifier);
+        }
+
+        private AccessPolicy getAccessPolicy(String resourceIdentifier, RequestAction action) throws AuthorizationAccessException {
+            if (policiesByResource == null) {
+                return null;
+            }
+
+            final Map<RequestAction, AccessPolicy> policiesForResource = policiesByResource.get(resourceIdentifier);
+
+            if (policiesForResource != null) {
+                return policiesForResource.get(action);
+            }
+
+            return null;
         }
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerNiFiAuthorizer.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerNiFiAuthorizer.java b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerNiFiAuthorizer.java
index 41b8106..8b98d53 100644
--- a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerNiFiAuthorizer.java
+++ b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerNiFiAuthorizer.java
@@ -21,6 +21,7 @@ package org.apache.nifi.ranger.authorization;
 import org.apache.commons.lang.StringUtils;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.nifi.authorization.AuthorizationAuditor;
 import org.apache.nifi.authorization.AuthorizationRequest;
 import org.apache.nifi.authorization.AuthorizationResult;
 import org.apache.nifi.authorization.Authorizer;
@@ -33,23 +34,26 @@ import org.apache.nifi.authorization.exception.AuthorizerCreationException;
 import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
 import org.apache.nifi.components.PropertyValue;
 import org.apache.nifi.util.NiFiProperties;
+import org.apache.ranger.audit.model.AuthzAuditEvent;
 import org.apache.ranger.authorization.hadoop.config.RangerConfiguration;
 import org.apache.ranger.plugin.audit.RangerDefaultAuditHandler;
 import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl;
 import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl;
 import org.apache.ranger.plugin.policyengine.RangerAccessResult;
-import org.apache.ranger.plugin.policyengine.RangerAccessResultProcessor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.File;
 import java.net.MalformedURLException;
 import java.util.Date;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 /**
  * Authorizer implementation that uses Apache Ranger to make authorization decisions.
  */
-public class RangerNiFiAuthorizer implements Authorizer {
+public class RangerNiFiAuthorizer implements Authorizer, AuthorizationAuditor {
 
     private static final Logger logger = LoggerFactory.getLogger(RangerNiFiAuthorizer.class);
 
@@ -67,6 +71,8 @@ public class RangerNiFiAuthorizer implements Authorizer {
     static final String HADOOP_SECURITY_AUTHENTICATION = "hadoop.security.authentication";
     static final String KERBEROS_AUTHENTICATION = "kerberos";
 
+    private final ConcurrentMap<AuthorizationRequest, RangerAccessResult> resultLookup = new ConcurrentHashMap<>();
+
     private volatile RangerBasePluginWithPolicies nifiPlugin = null;
     private volatile RangerDefaultAuditHandler defaultAuditHandler = null;
     private volatile String rangerAdminIdentity = null;
@@ -135,6 +141,7 @@ public class RangerNiFiAuthorizer implements Authorizer {
     @Override
     public AuthorizationResult authorize(final AuthorizationRequest request) throws AuthorizationAccessException {
         final String identity = request.getIdentity();
+        final Set<String> userGroups = request.getGroups();
         final String resourceIdentifier = request.getResource().getIdentifier();
 
         // if a ranger admin identity was provided, and it equals the identity making the request,
@@ -159,24 +166,25 @@ public class RangerNiFiAuthorizer implements Authorizer {
         rangerRequest.setAction(request.getAction().name());
         rangerRequest.setAccessType(request.getAction().name());
         rangerRequest.setUser(identity);
+        rangerRequest.setUserGroups(userGroups);
         rangerRequest.setAccessTime(new Date());
 
         if (!StringUtils.isBlank(clientIp)) {
             rangerRequest.setClientIPAddress(clientIp);
         }
 
-        // for a direct access request use the default audit handler so we generate audit logs
-        // for non-direct access provide a null result processor so no audit logs get generated
-        final RangerAccessResultProcessor resultProcessor = request.isAccessAttempt() ?  defaultAuditHandler : null;
-
-        final RangerAccessResult result = nifiPlugin.isAccessAllowed(rangerRequest, resultProcessor);
+        final RangerAccessResult result = nifiPlugin.isAccessAllowed(rangerRequest);
 
         if (result != null && result.getIsAllowed()) {
+            // store the result for auditing purposes later
+            resultLookup.put(request, result);
+
+            // return approved
             return AuthorizationResult.approved();
         } else {
             // if result.getIsAllowed() is false, then we need to determine if it was because no policy exists for the
             // given resource, or if it was because a policy exists but not for the given user or action
-            final boolean doesPolicyExist = nifiPlugin.doesPolicyExist(request.getResource().getIdentifier());
+            final boolean doesPolicyExist = nifiPlugin.doesPolicyExist(request.getResource().getIdentifier(), request.getAction());
 
             if (doesPolicyExist) {
                 final String reason = result == null ? null : result.getReason();
@@ -184,6 +192,9 @@ public class RangerNiFiAuthorizer implements Authorizer {
                     logger.debug(String.format("Unable to authorize %s due to %s", identity, reason));
                 }
 
+                // store the result for auditing purposes later
+                resultLookup.put(request, result);
+
                 // a policy does exist for the resource so we were really denied access here
                 return AuthorizationResult.denied(request.getExplanationSupplier().get());
             } else {
@@ -194,6 +205,21 @@ public class RangerNiFiAuthorizer implements Authorizer {
     }
 
     @Override
+    public void auditAccessAttempt(final AuthorizationRequest request, final AuthorizationResult result) {
+        final RangerAccessResult rangerResult = resultLookup.remove(request);
+
+        if (rangerResult != null && rangerResult.getIsAudited()) {
+            AuthzAuditEvent event = defaultAuditHandler.getAuthzEvents(rangerResult);
+
+            // update the event with the originally requested resource
+            event.setResourceType(RANGER_NIFI_RESOURCE_NAME);
+            event.setResourcePath(request.getRequestedResource().getIdentifier());
+
+            defaultAuditHandler.logAuthzAudit(event);
+        }
+    }
+
+    @Override
     public void preDestruction() throws AuthorizerDestructionException {
         if (nifiPlugin != null) {
             try {

http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/resources/META-INF/services/org.apache.nifi.authorization.Authorizer
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/resources/META-INF/services/org.apache.nifi.authorization.Authorizer b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/resources/META-INF/services/org.apache.nifi.authorization.Authorizer
index 607d979..34d8797 100755
--- a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/resources/META-INF/services/org.apache.nifi.authorization.Authorizer
+++ b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/resources/META-INF/services/org.apache.nifi.authorization.Authorizer
@@ -13,3 +13,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 org.apache.nifi.ranger.authorization.RangerNiFiAuthorizer
+org.apache.nifi.ranger.authorization.ManagedRangerAuthorizer

http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/test/java/org/apache/nifi/ranger/authorization/ManagedRangerAuthorizerTest.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/test/java/org/apache/nifi/ranger/authorization/ManagedRangerAuthorizerTest.java b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/test/java/org/apache/nifi/ranger/authorization/ManagedRangerAuthorizerTest.java
new file mode 100644
index 0000000..bd1f6e1
--- /dev/null
+++ b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/test/java/org/apache/nifi/ranger/authorization/ManagedRangerAuthorizerTest.java
@@ -0,0 +1,200 @@
+/*
+ * 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.ranger.authorization;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.nifi.authorization.AuthorizerConfigurationContext;
+import org.apache.nifi.authorization.AuthorizerInitializationContext;
+import org.apache.nifi.authorization.ConfigurableUserGroupProvider;
+import org.apache.nifi.authorization.UserGroupProvider;
+import org.apache.nifi.authorization.UserGroupProviderLookup;
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.authorization.exception.UninheritableAuthorizationsException;
+import org.apache.nifi.util.MockPropertyValue;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class ManagedRangerAuthorizerTest {
+
+    private static final String TENANT_FINGERPRINT =
+            "<tenants>"
+                + "<user identifier=\"user-id-1\" identity=\"user-1\"></user>"
+                + "<group identifier=\"group-id-1\" name=\"group-1\">"
+                    + "<groupUser identifier=\"user-id-1\"></groupUser>"
+                + "</group>"
+            + "</tenants>";
+
+    private static final String EMPTY_FINGERPRINT = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"
+            + "<managedRangerAuthorizations>"
+                + "<userGroupProvider/>"
+            + "</managedRangerAuthorizations>";
+
+    private static final String NON_EMPTY_FINGERPRINT = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"
+            + "<managedRangerAuthorizations>"
+                + "<userGroupProvider>"
+                    + "&lt;tenants&gt;"
+                        + "&lt;user identifier=\"user-id-1\" identity=\"user-1\"&gt;&lt;/user&gt;"
+                        + "&lt;group identifier=\"group-id-1\" name=\"group-1\"&gt;"
+                            + "&lt;groupUser identifier=\"user-id-1\"&gt;&lt;/groupUser&gt;"
+                        + "&lt;/group&gt;"
+                    + "&lt;/tenants&gt;"
+                + "</userGroupProvider>"
+            + "</managedRangerAuthorizations>";
+
+    private final String serviceType = "nifiService";
+    private final String appId = "nifiAppId";
+
+    @Before
+    public void setup() {
+        // have to initialize this system property before anything else
+        File krb5conf = new File("src/test/resources/krb5.conf");
+        assertTrue(krb5conf.exists());
+        System.setProperty("java.security.krb5.conf", krb5conf.getAbsolutePath());
+
+        // rest the authentication to simple in case any tests set it to kerberos
+        final Configuration securityConf = new Configuration();
+        securityConf.set(RangerNiFiAuthorizer.HADOOP_SECURITY_AUTHENTICATION, "simple");
+        UserGroupInformation.setConfiguration(securityConf);
+
+        assertFalse(UserGroupInformation.isSecurityEnabled());
+    }
+
+    @Test
+    public void testNonConfigurableFingerPrint() throws Exception {
+        final UserGroupProvider userGroupProvider = mock(UserGroupProvider.class);
+
+        final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
+        Assert.assertEquals(EMPTY_FINGERPRINT, managedRangerAuthorizer.getFingerprint());
+    }
+
+    @Test
+    public void testConfigurableEmptyFingerPrint() throws Exception {
+        final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
+        when(userGroupProvider.getFingerprint()).thenReturn("");
+
+        final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
+        Assert.assertEquals(EMPTY_FINGERPRINT, managedRangerAuthorizer.getFingerprint());
+    }
+
+    @Test
+    public void testConfigurableFingerPrint() throws Exception {
+        final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
+        when(userGroupProvider.getFingerprint()).thenReturn(TENANT_FINGERPRINT);
+
+        final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
+        Assert.assertEquals(NON_EMPTY_FINGERPRINT, managedRangerAuthorizer.getFingerprint());
+    }
+
+    @Test
+    public void testInheritEmptyFingerprint() throws Exception {
+        final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
+
+        final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
+        managedRangerAuthorizer.inheritFingerprint(EMPTY_FINGERPRINT);
+
+        verify(userGroupProvider, times(0)).inheritFingerprint(anyString());
+    }
+
+    @Test(expected = AuthorizationAccessException.class)
+    public void testInheritInvalidFingerprint() throws Exception {
+        final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
+
+        final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
+        managedRangerAuthorizer.inheritFingerprint("not a valid fingerprint");
+    }
+
+    @Test
+    public void testInheritNonEmptyFingerprint() throws Exception {
+        final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
+
+        final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
+        managedRangerAuthorizer.inheritFingerprint(NON_EMPTY_FINGERPRINT);
+
+        verify(userGroupProvider, times(1)).inheritFingerprint(TENANT_FINGERPRINT);
+    }
+
+    @Test
+    public void testCheckInheritEmptyFingerprint() throws Exception {
+        final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
+
+        final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
+        managedRangerAuthorizer.checkInheritability(EMPTY_FINGERPRINT);
+
+        verify(userGroupProvider, times(0)).inheritFingerprint(anyString());
+    }
+
+    @Test(expected = AuthorizationAccessException.class)
+    public void testCheckInheritInvalidFingerprint() throws Exception {
+        final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
+
+        final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
+        managedRangerAuthorizer.checkInheritability("not a valid fingerprint");
+    }
+
+    @Test
+    public void testCheckInheritNonEmptyFingerprint() throws Exception {
+        final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
+
+        final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
+        managedRangerAuthorizer.checkInheritability(NON_EMPTY_FINGERPRINT);
+
+        verify(userGroupProvider, times(1)).checkInheritability(TENANT_FINGERPRINT);
+    }
+
+    @Test(expected = UninheritableAuthorizationsException.class)
+    public void testCheckInheritNonConfigurableUserGroupProvider() throws Exception {
+        final UserGroupProvider userGroupProvider = mock(UserGroupProvider.class);
+
+        final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
+        managedRangerAuthorizer.checkInheritability(NON_EMPTY_FINGERPRINT);
+    }
+
+    private ManagedRangerAuthorizer getStandardManagedAuthorizer(final UserGroupProvider userGroupProvider) {
+        final ManagedRangerAuthorizer managedAuthorizer = new ManagedRangerAuthorizer();
+
+        final AuthorizerConfigurationContext configurationContext = mock(AuthorizerConfigurationContext.class);
+        when(configurationContext.getProperty(eq("User Group Provider"))).thenReturn(new MockPropertyValue("user-group-provider", null));
+        when(configurationContext.getProperty(eq(RangerNiFiAuthorizer.RANGER_SECURITY_PATH_PROP))).thenReturn(new MockPropertyValue("src/test/resources/ranger/ranger-nifi-security.xml"));
+        when(configurationContext.getProperty(eq(RangerNiFiAuthorizer.RANGER_AUDIT_PATH_PROP))).thenReturn(new MockPropertyValue("src/test/resources/ranger/ranger-nifi-audit.xml"));
+        when(configurationContext.getProperty(eq(RangerNiFiAuthorizer.RANGER_APP_ID_PROP))).thenReturn(new MockPropertyValue(appId));
+        when(configurationContext.getProperty(eq(RangerNiFiAuthorizer.RANGER_SERVICE_TYPE_PROP))).thenReturn(new MockPropertyValue(serviceType));
+
+        final UserGroupProviderLookup userGroupProviderLookup = mock(UserGroupProviderLookup.class);
+        when(userGroupProviderLookup.getUserGroupProvider("user-group-provider")).thenReturn(userGroupProvider);
+
+        final AuthorizerInitializationContext initializationContext = mock(AuthorizerInitializationContext.class);
+        when(initializationContext.getUserGroupProviderLookup()).thenReturn(userGroupProviderLookup);
+
+        managedAuthorizer.initialize(initializationContext);
+        managedAuthorizer.onConfigured(configurationContext);
+
+        return managedAuthorizer;
+    }
+}
\ No newline at end of file