Repository: nifi
Updated Branches:
  refs/heads/master e916594b6 -> 91f40febe


NIFI-4925:
- Addressing memory leak from lingering authorization results that did not 
represent actual access attempts. This closes #2511.

Signed-off-by: Mark Payne <marka...@hotmail.com>


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

Branch: refs/heads/master
Commit: 91f40febebe7c199272375b02299bf2f678b123b
Parents: e916594
Author: Matt Gilman <matt.c.gil...@gmail.com>
Authored: Fri Mar 2 16:24:34 2018 -0500
Committer: Mark Payne <marka...@hotmail.com>
Committed: Mon Mar 5 15:37:31 2018 -0500

----------------------------------------------------------------------
 .../AuthorizationAuditorInvocationHandler.java  | 47 ++++++++++++++++++++
 .../nifi/authorization/AuthorizerFactory.java   | 20 +++++++--
 .../authorization/AuthorizerFactoryBean.java    |  4 +-
 .../authorization/AuthorizerFactoryTest.java    |  2 +
 .../authorization/RangerNiFiAuthorizer.java     | 24 +++++-----
 5 files changed, 83 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/91f40feb/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizationAuditorInvocationHandler.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizationAuditorInvocationHandler.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizationAuditorInvocationHandler.java
new file mode 100644
index 0000000..7f8d76c
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizationAuditorInvocationHandler.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class AuthorizationAuditorInvocationHandler implements 
InvocationHandler {
+
+    private final Authorizer authorizer;
+    private final AuthorizationAuditor auditor;
+
+    public AuthorizationAuditorInvocationHandler(final Authorizer authorizer, 
final AuthorizationAuditor auditor) {
+        this.authorizer = authorizer;
+        this.auditor = auditor;
+    }
+
+    @Override
+    public Object invoke(final Object proxy, final Method method, final 
Object[] args) throws Throwable {
+        try {
+            if (AuthorizationAuditor.class.getMethod("auditAccessAttempt", 
AuthorizationRequest.class, AuthorizationResult.class).equals(method)) {
+                return method.invoke(auditor, args);
+            } else {
+                return method.invoke(authorizer, args);
+            }
+        } catch (final InvocationTargetException e) {
+            // If the proxied instance throws an Exception, it'll be wrapped 
in an InvocationTargetException. We want
+            // to instead re-throw what the proxied instance threw, so we pull 
it out of the InvocationTargetException.
+            throw e.getCause();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/91f40feb/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactory.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactory.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactory.java
index 915bff0..812ea17 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactory.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactory.java
@@ -101,9 +101,11 @@ public final class AuthorizerFactory {
     }
 
     public static Authorizer installIntegrityChecks(final Authorizer 
baseAuthorizer) {
+        Authorizer authorizer;
+
         if (baseAuthorizer instanceof ManagedAuthorizer) {
             final ManagedAuthorizer baseManagedAuthorizer = 
(ManagedAuthorizer) baseAuthorizer;
-            return new ManagedAuthorizer() {
+            authorizer = new ManagedAuthorizer() {
                 @Override
                 public String getFingerprint() throws 
AuthorizationAccessException {
                     return baseManagedAuthorizer.getFingerprint();
@@ -395,7 +397,7 @@ public final class AuthorizerFactory {
                 }
             };
         } else {
-            return new Authorizer() {
+            authorizer = new Authorizer() {
                 @Override
                 public AuthorizationResult authorize(AuthorizationRequest 
request) throws AuthorizationAccessException {
                     final AuthorizationResult result = 
baseAuthorizer.authorize(request);
@@ -422,6 +424,19 @@ public final class AuthorizerFactory {
                 }
             };
         }
+
+        // conditionally add support for the audit methods
+        if (baseAuthorizer instanceof AuthorizationAuditor) {
+            final AuthorizationAuditorInvocationHandler invocationHandler = 
new AuthorizationAuditorInvocationHandler(authorizer, (AuthorizationAuditor) 
baseAuthorizer);
+
+            final List<Class<?>> interfaceList = 
ClassUtils.getAllInterfaces(authorizer.getClass());
+            interfaceList.add(AuthorizationAuditor.class);
+            final Class<?>[] interfaces = interfaceList.toArray(new 
Class<?>[interfaceList.size()]);
+
+            authorizer = (Authorizer) 
Proxy.newProxyInstance(authorizer.getClass().getClassLoader(), interfaces, 
invocationHandler);
+        }
+
+        return authorizer;
     }
 
     /**
@@ -433,7 +448,6 @@ public final class AuthorizerFactory {
     public static Authorizer withNarLoader(final Authorizer baseAuthorizer, 
final ClassLoader classLoader) {
         final AuthorizerInvocationHandler invocationHandler = new 
AuthorizerInvocationHandler(baseAuthorizer, classLoader);
 
-        // extract all interfaces... baseAuthorizer is non null so 
getAllInterfaces is non null
         final List<Class<?>> interfaceList = 
ClassUtils.getAllInterfaces(baseAuthorizer.getClass());
         final Class<?>[] interfaces = interfaceList.toArray(new 
Class<?>[interfaceList.size()]);
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/91f40feb/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java
index 7ece8eb..79d3757 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java
@@ -172,6 +172,8 @@ public class AuthorizerFactoryBean implements FactoryBean, 
DisposableBean, UserG
                     // ensure it was found
                     if (authorizer == null) {
                         throw new Exception(String.format("The specified 
authorizer '%s' could not be found.", authorizerIdentifier));
+                    } else {
+                        authorizer = 
AuthorizerFactory.installIntegrityChecks(authorizer);
                     }
                 }
             }
@@ -350,7 +352,7 @@ public class AuthorizerFactoryBean implements FactoryBean, 
DisposableBean, UserG
             authorizerClassLoader = new URLClassLoader(urls, 
authorizerClassLoader);
         }
 
-        return 
AuthorizerFactory.installIntegrityChecks(AuthorizerFactory.withNarLoader(instance,
 authorizerClassLoader));
+        return AuthorizerFactory.withNarLoader(instance, 
authorizerClassLoader);
     }
 
     private AuthorizerConfigurationContext loadAuthorizerConfiguration(final 
String identifier, final List<Property> properties) {

http://git-wip-us.apache.org/repos/asf/nifi/blob/91f40feb/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/test/java/org/apache/nifi/authorization/AuthorizerFactoryTest.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/test/java/org/apache/nifi/authorization/AuthorizerFactoryTest.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/test/java/org/apache/nifi/authorization/AuthorizerFactoryTest.java
index caae13f..167a7d4 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/test/java/org/apache/nifi/authorization/AuthorizerFactoryTest.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/test/java/org/apache/nifi/authorization/AuthorizerFactoryTest.java
@@ -289,6 +289,8 @@ public class AuthorizerFactoryTest {
         Authorizer authorizer = 
AuthorizerFactory.installIntegrityChecks(mockAuthorizer);
         authorizer.onConfigured(context);
 
+        assertTrue(authorizer instanceof AuthorizationAuditor);
+
         final AuthorizationRequest accessAttempt = new 
AuthorizationRequest.Builder()
                 .resource(new MockResource("resource1", "Resource 1"))
                 .identity("user-1")

http://git-wip-us.apache.org/repos/asf/nifi/blob/91f40feb/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 8b98d53..a49887b 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
@@ -46,9 +46,9 @@ import org.slf4j.LoggerFactory;
 import java.io.File;
 import java.net.MalformedURLException;
 import java.util.Date;
+import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
+import java.util.WeakHashMap;
 
 /**
  * Authorizer implementation that uses Apache Ranger to make authorization 
decisions.
@@ -71,7 +71,7 @@ public class RangerNiFiAuthorizer implements Authorizer, 
AuthorizationAuditor {
     static final String HADOOP_SECURITY_AUTHENTICATION = 
"hadoop.security.authentication";
     static final String KERBEROS_AUTHENTICATION = "kerberos";
 
-    private final ConcurrentMap<AuthorizationRequest, RangerAccessResult> 
resultLookup = new ConcurrentHashMap<>();
+    private final Map<AuthorizationRequest, RangerAccessResult> resultLookup = 
new WeakHashMap<>();
 
     private volatile RangerBasePluginWithPolicies nifiPlugin = null;
     private volatile RangerDefaultAuditHandler defaultAuditHandler = null;
@@ -175,10 +175,14 @@ public class RangerNiFiAuthorizer implements Authorizer, 
AuthorizationAuditor {
 
         final RangerAccessResult result = 
nifiPlugin.isAccessAllowed(rangerRequest);
 
-        if (result != null && result.getIsAllowed()) {
-            // store the result for auditing purposes later
-            resultLookup.put(request, result);
+        // store the result for auditing purposes later if appropriate
+        if (request.isAccessAttempt()) {
+            synchronized (resultLookup) {
+                resultLookup.put(request, result);
+            }
+        }
 
+        if (result != null && result.getIsAllowed()) {
             // return approved
             return AuthorizationResult.approved();
         } else {
@@ -192,9 +196,6 @@ public class RangerNiFiAuthorizer implements Authorizer, 
AuthorizationAuditor {
                     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 {
@@ -206,7 +207,10 @@ public class RangerNiFiAuthorizer implements Authorizer, 
AuthorizationAuditor {
 
     @Override
     public void auditAccessAttempt(final AuthorizationRequest request, final 
AuthorizationResult result) {
-        final RangerAccessResult rangerResult = resultLookup.remove(request);
+        final RangerAccessResult rangerResult;
+        synchronized (resultLookup) {
+            rangerResult = resultLookup.remove(request);
+        }
 
         if (rangerResult != null && rangerResult.getIsAudited()) {
             AuthzAuditEvent event = 
defaultAuditHandler.getAuthzEvents(rangerResult);

Reply via email to