You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by ma...@apache.org on 2016/05/13 19:11:21 UTC

incubator-ranger git commit: RANGER-938 Adding NiFi service-definition and the NiFiClient for resource lookups

Repository: incubator-ranger
Updated Branches:
  refs/heads/master 608776712 -> b64218a34


RANGER-938 Adding NiFi service-definition and the NiFiClient for resource lookups

Signed-off-by: Madhan Neethiraj <ma...@apache.org>


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

Branch: refs/heads/master
Commit: b64218a347e54aff132f821946de63133258d407
Parents: 6087767
Author: Bryan Bende <bb...@apache.org>
Authored: Thu Mar 31 10:59:17 2016 -0400
Committer: Madhan Neethiraj <ma...@apache.org>
Committed: Fri May 13 11:36:55 2016 -0700

----------------------------------------------------------------------
 .../plugin/store/EmbeddedServiceDefsUtil.java   |   9 +
 .../service-defs/ranger-servicedef-nifi.json    | 162 ++++++++++++++
 plugin-nifi/.gitignore                          |   1 +
 plugin-nifi/pom.xml                             |  62 ++++++
 .../ranger/services/nifi/RangerServiceNiFi.java |  71 ++++++
 .../services/nifi/client/NiFiAuthType.java      |  29 +++
 .../ranger/services/nifi/client/NiFiClient.java | 217 +++++++++++++++++++
 .../services/nifi/client/NiFiConfigs.java       |  37 ++++
 .../services/nifi/client/NiFiConnectionMgr.java | 157 ++++++++++++++
 .../services/nifi/client/TestNiFiClient.java    | 196 +++++++++++++++++
 .../nifi/client/TestNiFiConnectionMgr.java      | 124 +++++++++++
 pom.xml                                         |   1 +
 src/main/assembly/admin-web.xml                 |  13 ++
 13 files changed, 1079 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b64218a3/agents-common/src/main/java/org/apache/ranger/plugin/store/EmbeddedServiceDefsUtil.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/store/EmbeddedServiceDefsUtil.java b/agents-common/src/main/java/org/apache/ranger/plugin/store/EmbeddedServiceDefsUtil.java
index 7ec8d98..bf29ee6 100755
--- a/agents-common/src/main/java/org/apache/ranger/plugin/store/EmbeddedServiceDefsUtil.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/store/EmbeddedServiceDefsUtil.java
@@ -60,6 +60,8 @@ public class EmbeddedServiceDefsUtil {
 	public static final String EMBEDDED_SERVICEDEF_YARN_NAME  = "yarn";
 	public static final String EMBEDDED_SERVICEDEF_KAFKA_NAME = "kafka";
 	public static final String EMBEDDED_SERVICEDEF_SOLR_NAME  = "solr";
+	public static final String EMBEDDED_SERVICEDEF_NIFI_NAME  = "nifi";
+
 	public static final String PROPERTY_CREATE_EMBEDDED_SERVICE_DEFS = "ranger.service.store.create.embedded.service-defs";
 
 	public static final String HDFS_IMPL_CLASS_NAME  = "org.apache.ranger.services.hdfs.RangerServiceHdfs";
@@ -71,6 +73,7 @@ public class EmbeddedServiceDefsUtil {
 	public static final String YARN_IMPL_CLASS_NAME  = "org.apache.ranger.services.yarn.RangerServiceYarn";
 	public static final String KAFKA_IMPL_CLASS_NAME = "org.apache.ranger.services.kafka.RangerServiceKafka";
 	public static final String SOLR_IMPL_CLASS_NAME  = "org.apache.ranger.services.solr.RangerServiceSolr";
+	public static final String NIFI_IMPL_CLASS_NAME  = "org.apache.ranger.services.nifi.RangerServiceNiFi";
 
 	private static EmbeddedServiceDefsUtil instance = new EmbeddedServiceDefsUtil();
 
@@ -84,6 +87,7 @@ public class EmbeddedServiceDefsUtil {
 	private RangerServiceDef yarnServiceDef  = null;
 	private RangerServiceDef kafkaServiceDef = null;
 	private RangerServiceDef solrServiceDef  = null;
+	private RangerServiceDef nifiServiceDef  = null;
 
 	private RangerServiceDef tagServiceDef = null;
 
@@ -120,6 +124,7 @@ public class EmbeddedServiceDefsUtil {
 			yarnServiceDef  = getOrCreateServiceDef(store, EMBEDDED_SERVICEDEF_YARN_NAME);
 			kafkaServiceDef = getOrCreateServiceDef(store, EMBEDDED_SERVICEDEF_KAFKA_NAME);
 			solrServiceDef  = getOrCreateServiceDef(store, EMBEDDED_SERVICEDEF_SOLR_NAME);
+			nifiServiceDef  = getOrCreateServiceDef(store, EMBEDDED_SERVICEDEF_NIFI_NAME);
 
 			tagServiceDef = getOrCreateServiceDef(store, EMBEDDED_SERVICEDEF_TAG_NAME);
 
@@ -168,6 +173,10 @@ public class EmbeddedServiceDefsUtil {
 		return getId(solrServiceDef);
 	}
 
+	public long getNiFiServiceDefId() {
+		return getId(nifiServiceDef);
+	}
+
 	public long getTagServiceDefId() { return getId(tagServiceDef); }
 
 	private long getId(RangerServiceDef serviceDef) {

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b64218a3/agents-common/src/main/resources/service-defs/ranger-servicedef-nifi.json
----------------------------------------------------------------------
diff --git a/agents-common/src/main/resources/service-defs/ranger-servicedef-nifi.json b/agents-common/src/main/resources/service-defs/ranger-servicedef-nifi.json
new file mode 100644
index 0000000..b81785d
--- /dev/null
+++ b/agents-common/src/main/resources/service-defs/ranger-servicedef-nifi.json
@@ -0,0 +1,162 @@
+{
+  "id":10,
+  "name":"nifi",
+  "implClass":"org.apache.ranger.services.nifi.RangerServiceNiFi",
+  "label":"NIFI",
+  "description":"NiFi",
+  "resources":[
+    {
+      "itemId":100,
+      "name":"nifi-resource",
+      "type":"string",
+      "level":10,
+      "parent":"",
+      "mandatory":true,
+      "lookupSupported":true,
+      "recursiveSupported":false,
+      "excludesSupported":true,
+      "matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher",
+      "matcherOptions":{
+        "wildCard":true,
+        "ignoreCase":true
+      },
+      "validationRegEx":"",
+      "validationMessage":"",
+      "uiHint":"",
+      "label":"NiFi Resource Identifier",
+      "description":"NiFi Resource"
+    }
+
+  ],
+  "accessTypes":[
+    {
+      "itemId":100,
+      "name":"READ",
+      "label":"Read"
+    },
+    {
+      "itemId":200,
+      "name":"WRITE",
+      "label":"Write"
+    }
+  ],
+  "configs":[
+    {
+      "itemId":400,
+      "name":"nifi.url",
+      "type":"string",
+      "mandatory":true,
+      "defaultValue":"http://localhost:8080/nifi-api/resources",
+      "validationRegEx":"",
+      "validationMessage":"",
+      "uiHint":"The URL of the NiFi REST API that provides the available resources.",
+      "label":"NiFi URL"
+    },
+    {
+      "itemId": 410,
+      "name": "nifi.authentication",
+      "type": "enum",
+      "subType": "authType",
+      "mandatory": true,
+      "validationRegEx":"",
+      "validationMessage": "",
+      "uiHint":"",
+      "label": "Authentication Type",
+      "defaultValue": "NONE"
+    },
+    {
+      "itemId":500,
+      "name":"nifi.ssl.keystore",
+      "type":"string",
+      "mandatory":false,
+      "defaultValue":"",
+      "validationRegEx":"",
+      "validationMessage":"",
+      "uiHint":"",
+      "label":"Keystore"
+    },
+    {
+      "itemId":510,
+      "name":"nifi.ssl.keystoreType",
+      "type":"string",
+      "mandatory":false,
+      "defaultValue":"",
+      "validationRegEx":"",
+      "validationMessage":"",
+      "uiHint":"",
+      "label":"Keystore Type"
+    },
+    {
+      "itemId":520,
+      "name":"nifi.ssl.keystorePassword",
+      "type":"password",
+      "mandatory":false,
+      "defaultValue":"",
+      "validationRegEx":"",
+      "validationMessage":"",
+      "uiHint":"",
+      "label":"Keystore Password"
+    },
+    {
+      "itemId":530,
+      "name":"nifi.ssl.truststore",
+      "type":"string",
+      "mandatory":false,
+      "defaultValue":"",
+      "validationRegEx":"",
+      "validationMessage":"",
+      "uiHint":"",
+      "label":"Truststore"
+    },
+    {
+      "itemId":540,
+      "name":"nifi.ssl.truststoreType",
+      "type":"string",
+      "mandatory":false,
+      "defaultValue":"",
+      "validationRegEx":"",
+      "validationMessage":"",
+      "uiHint":"",
+      "label":"Truststore Type"
+    },
+    {
+      "itemId":550,
+      "name":"nifi.ssl.truststorePassword",
+      "type":"password",
+      "mandatory":false,
+      "defaultValue":"",
+      "validationRegEx":"",
+      "validationMessage":"",
+      "uiHint":"",
+      "label":"Truststore Password"
+    }
+  ],
+  "enums":
+  [
+      {
+        "itemId": 1,
+        "name": "authType",
+        "elements":
+        [
+          {
+            "itemId": 1,
+            "name": "NONE",
+            "label": "None"
+          },
+          {
+            "itemId": 2,
+            "name": "SSL",
+            "label": "SSL"
+          }
+        ],
+
+        "defaultIndex": 0
+      }
+  ],
+  "contextEnrichers":[
+
+  ],
+  "policyConditions":[
+
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b64218a3/plugin-nifi/.gitignore
----------------------------------------------------------------------
diff --git a/plugin-nifi/.gitignore b/plugin-nifi/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/plugin-nifi/.gitignore
@@ -0,0 +1 @@
+/target

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b64218a3/plugin-nifi/pom.xml
----------------------------------------------------------------------
diff --git a/plugin-nifi/pom.xml b/plugin-nifi/pom.xml
new file mode 100644
index 0000000..740b7f9
--- /dev/null
+++ b/plugin-nifi/pom.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>ranger-nifi-plugin</artifactId>
+    <name>NiFi Security Plugin</name>
+    <description>NiFi Security Plugin</description>
+    <packaging>jar</packaging>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+    <parent>
+        <groupId>org.apache.ranger</groupId>
+        <artifactId>ranger</artifactId>
+        <version>0.6.0-SNAPSHOT</version>
+        <relativePath>..</relativePath>
+    </parent>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.ranger</groupId>
+            <artifactId>ranger-plugins-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ranger</groupId>
+            <artifactId>ranger-plugins-audit</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ranger</groupId>
+            <artifactId>credentialbuilder</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <version>${mockito.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b64218a3/plugin-nifi/src/main/java/org/apache/ranger/services/nifi/RangerServiceNiFi.java
----------------------------------------------------------------------
diff --git a/plugin-nifi/src/main/java/org/apache/ranger/services/nifi/RangerServiceNiFi.java b/plugin-nifi/src/main/java/org/apache/ranger/services/nifi/RangerServiceNiFi.java
new file mode 100644
index 0000000..4f38f42
--- /dev/null
+++ b/plugin-nifi/src/main/java/org/apache/ranger/services/nifi/RangerServiceNiFi.java
@@ -0,0 +1,71 @@
+/*
+ * 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.ranger.services.nifi;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.plugin.service.RangerBaseService;
+import org.apache.ranger.plugin.service.ResourceLookupContext;
+import org.apache.ranger.services.nifi.client.NiFiClient;
+import org.apache.ranger.services.nifi.client.NiFiConnectionMgr;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * RangerService for Apache NiFi.
+ */
+public class RangerServiceNiFi extends RangerBaseService {
+
+    private static final Log LOG = LogFactory.getLog(RangerServiceNiFi.class);
+
+    @Override
+    public HashMap<String, Object> validateConfig() throws Exception {
+        HashMap<String, Object> ret = new HashMap<>();
+        String serviceName = getServiceName();
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> RangerServiceNiFi.validateConfig Service: (" + serviceName + " )");
+        }
+
+        if (configs != null) {
+            try {
+                ret = NiFiConnectionMgr.connectionTest(serviceName, configs);
+            } catch (Exception e) {
+                LOG.error("<== RangerServiceNiFi.validateConfig Error:", e);
+                throw e;
+            }
+        } else {
+            throw new IllegalStateException("No Configuration found");
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<== RangerServiceNiFi.validateConfig Response : (" + ret + " )");
+        }
+
+        return ret;
+    }
+
+    @Override
+    public List<String> lookupResource(ResourceLookupContext context) throws Exception {
+        final NiFiClient client = NiFiConnectionMgr.getNiFiClient(serviceName, configs);
+        return client.getResources(context);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b64218a3/plugin-nifi/src/main/java/org/apache/ranger/services/nifi/client/NiFiAuthType.java
----------------------------------------------------------------------
diff --git a/plugin-nifi/src/main/java/org/apache/ranger/services/nifi/client/NiFiAuthType.java b/plugin-nifi/src/main/java/org/apache/ranger/services/nifi/client/NiFiAuthType.java
new file mode 100644
index 0000000..47267a4
--- /dev/null
+++ b/plugin-nifi/src/main/java/org/apache/ranger/services/nifi/client/NiFiAuthType.java
@@ -0,0 +1,29 @@
+/*
+ * 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.ranger.services.nifi.client;
+
+/**
+ * Possible authentication types for NiFi.
+ */
+public enum NiFiAuthType {
+
+    NONE,
+    SSL
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b64218a3/plugin-nifi/src/main/java/org/apache/ranger/services/nifi/client/NiFiClient.java
----------------------------------------------------------------------
diff --git a/plugin-nifi/src/main/java/org/apache/ranger/services/nifi/client/NiFiClient.java b/plugin-nifi/src/main/java/org/apache/ranger/services/nifi/client/NiFiClient.java
new file mode 100644
index 0000000..1c21c0e
--- /dev/null
+++ b/plugin-nifi/src/main/java/org/apache/ranger/services/nifi/client/NiFiClient.java
@@ -0,0 +1,217 @@
+/*
+ * 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.ranger.services.nifi.client;
+
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.api.client.config.ClientConfig;
+import com.sun.jersey.api.client.config.DefaultClientConfig;
+import com.sun.jersey.client.urlconnection.HTTPSProperties;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.plugin.client.BaseClient;
+import org.apache.ranger.plugin.service.ResourceLookupContext;
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.map.ObjectMapper;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.ws.rs.core.Response;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Client to communicate with NiFi and retrieve available resources.
+ */
+public class NiFiClient {
+
+    private static final Log LOG = LogFactory.getLog(NiFiClient.class) ;
+
+    static final String SUCCESS_MSG = "ConnectionTest Successful";
+    static final String FAILURE_MSG = "Unable to retrieve any resources using given parameters. ";
+
+    private final String url;
+    private final SSLContext sslContext;
+    private final HostnameVerifier hostnameVerifier;
+    private final ObjectMapper mapper = new ObjectMapper();
+
+    public NiFiClient(final String url, final SSLContext sslContext) {
+        this.url = url;
+        this.sslContext = sslContext;
+        this.hostnameVerifier = new NiFiHostnameVerifier();
+    }
+
+    public HashMap<String, Object> connectionTest() {
+        String errMsg = "";
+        boolean connectivityStatus;
+        HashMap<String, Object> responseData = new HashMap<>();
+
+        try {
+            final WebResource resource = getWebResource();
+            final ClientResponse response = getResponse(resource, "application/json");
+
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Got response from NiFi with status code " + response.getStatus());
+            }
+
+            if (Response.Status.OK.getStatusCode() == response.getStatus()) {
+                connectivityStatus = true;
+            } else {
+                connectivityStatus = false;
+                errMsg = "Status Code = " + response.getStatus();
+            }
+
+        } catch (Exception e) {
+            LOG.error("Connection to NiFi failed due to " + e.getMessage(), e);
+            connectivityStatus = false;
+            errMsg = e.getMessage();
+        }
+
+        if (connectivityStatus) {
+            BaseClient.generateResponseDataMap(connectivityStatus, SUCCESS_MSG, SUCCESS_MSG, null, null, responseData);
+        } else {
+            BaseClient.generateResponseDataMap(connectivityStatus, FAILURE_MSG, FAILURE_MSG + errMsg, null, null, responseData);
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Response Data - " + responseData);
+        }
+
+        return responseData;
+    }
+
+    public List<String> getResources(ResourceLookupContext context) throws Exception {
+        final WebResource resource = getWebResource();
+        final ClientResponse response = getResponse(resource, "application/json");
+
+        if (Response.Status.OK.getStatusCode() != response.getStatus()) {
+            String errorMsg = IOUtils.toString(response.getEntityInputStream());
+            throw new Exception("Unable to retrieve resources from NiFi due to: " + errorMsg);
+        }
+
+        JsonNode rootNode = mapper.readTree(response.getEntityInputStream());
+        if (rootNode == null) {
+            throw new Exception("Unable to retrieve resources from NiFi");
+        }
+
+        JsonNode resourcesNode = rootNode.findValue("resources");
+        List<String> identifiers = resourcesNode.findValuesAsText("identifier");
+
+        final String userInput = context.getUserInput();
+        if (StringUtils.isBlank(userInput)) {
+            return identifiers;
+        } else {
+            List<String> filteredIdentifiers = new ArrayList<>();
+
+            for (String identifier : identifiers) {
+                if (identifier.contains(userInput)) {
+                    filteredIdentifiers.add(identifier);
+                }
+            }
+
+            return filteredIdentifiers;
+        }
+    }
+
+    protected WebResource getWebResource() {
+        final ClientConfig config = new DefaultClientConfig();
+        if (sslContext != null) {
+            config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES,
+                    new HTTPSProperties(hostnameVerifier, sslContext));
+        }
+
+        final Client client = Client.create(config);
+        return client.resource(url);
+    }
+
+    protected ClientResponse getResponse(WebResource resource, String accept) {
+        return resource.accept(accept).get(ClientResponse.class);
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public SSLContext getSslContext() {
+        return sslContext;
+    }
+
+    public HostnameVerifier getHostnameVerifier() {
+        return hostnameVerifier;
+    }
+
+    /**
+     * Custom hostname verifier that checks subject alternative names against the hostname of the URI.
+     */
+    private static class NiFiHostnameVerifier implements HostnameVerifier {
+
+        @Override
+        public boolean verify(final String hostname, final SSLSession ssls) {
+            try {
+                for (final Certificate peerCertificate : ssls.getPeerCertificates()) {
+                    if (peerCertificate instanceof X509Certificate) {
+                        final X509Certificate x509Cert = (X509Certificate) peerCertificate;
+                        final List<String> subjectAltNames = getSubjectAlternativeNames(x509Cert);
+                        if (subjectAltNames.contains(hostname.toLowerCase())) {
+                            return true;
+                        }
+                    }
+                }
+            } catch (final SSLPeerUnverifiedException | CertificateParsingException ex) {
+                LOG.warn("Hostname Verification encountered exception verifying hostname due to: " + ex, ex);
+            }
+
+            return false;
+        }
+
+        private List<String> getSubjectAlternativeNames(final X509Certificate certificate) throws CertificateParsingException {
+            final Collection<List<?>> altNames = certificate.getSubjectAlternativeNames();
+            if (altNames == null) {
+                return new ArrayList<>();
+            }
+
+            final List<String> result = new ArrayList<>();
+            for (final List<?> generalName : altNames) {
+                /**
+                 * generalName has the name type as the first element a String or byte array for the second element. We return any general names that are String types.
+                 *
+                 * We don't inspect the numeric name type because some certificates incorrectly put IPs and DNS names under the wrong name types.
+                 */
+                final Object value = generalName.get(1);
+                if (value instanceof String) {
+                    result.add(((String) value).toLowerCase());
+                }
+
+            }
+
+            return result;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b64218a3/plugin-nifi/src/main/java/org/apache/ranger/services/nifi/client/NiFiConfigs.java
----------------------------------------------------------------------
diff --git a/plugin-nifi/src/main/java/org/apache/ranger/services/nifi/client/NiFiConfigs.java b/plugin-nifi/src/main/java/org/apache/ranger/services/nifi/client/NiFiConfigs.java
new file mode 100644
index 0000000..cc68710
--- /dev/null
+++ b/plugin-nifi/src/main/java/org/apache/ranger/services/nifi/client/NiFiConfigs.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ranger.services.nifi.client;
+
+/**
+ * Config property names from the NiFi service definition.
+ */
+public interface NiFiConfigs {
+
+    String NIFI_URL = "nifi.url";
+    String NIFI_AUTHENTICATION_TYPE = "nifi.authentication";
+
+    String NIFI_SSL_KEYSTORE = "nifi.ssl.keystore";
+    String NIFI_SSL_KEYSTORE_TYPE = "nifi.ssl.keystoreType";
+    String NIFI_SSL_KEYSTORE_PASSWORD = "nifi.ssl.keystorePassword";
+
+    String NIFI_SSL_TRUSTSTORE = "nifi.ssl.truststore";
+    String NIFI_SSL_TRUSTSTORE_TYPE = "nifi.ssl.truststoreType";
+    String NIFI_SSL_TRUSTSTORE_PASSWORD = "nifi.ssl.truststorePassword";
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b64218a3/plugin-nifi/src/main/java/org/apache/ranger/services/nifi/client/NiFiConnectionMgr.java
----------------------------------------------------------------------
diff --git a/plugin-nifi/src/main/java/org/apache/ranger/services/nifi/client/NiFiConnectionMgr.java b/plugin-nifi/src/main/java/org/apache/ranger/services/nifi/client/NiFiConnectionMgr.java
new file mode 100644
index 0000000..739bef6
--- /dev/null
+++ b/plugin-nifi/src/main/java/org/apache/ranger/services/nifi/client/NiFiConnectionMgr.java
@@ -0,0 +1,157 @@
+/*
+ * 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.ranger.services.nifi.client;
+
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Creates a NiFiClient and provides method to test a connection to NiFi.
+ */
+public class NiFiConnectionMgr {
+
+    private static final Log LOG = LogFactory.getLog(NiFiConnectionMgr.class);
+
+    static final String INVALID_URL_MSG =  "NiFi URL must be a valid URL of the form " +
+            "http(s)://<hostname>(:<port>)/nifi-api/resources";
+
+
+    static public NiFiClient getNiFiClient(String serviceName, Map<String, String> configs) throws Exception {
+        final String url = configs.get(NiFiConfigs.NIFI_URL);
+        validateNotBlank(url, "NiFi URL is required for " + serviceName);
+        validateUrl(url);
+
+        final String authTypeStr = configs.get(NiFiConfigs.NIFI_AUTHENTICATION_TYPE);
+        validateNotBlank(authTypeStr, "Authentication Type is required for " + serviceName);
+
+        final NiFiAuthType authType = NiFiAuthType.valueOf(authTypeStr);
+        LOG.debug("NiFiAuthType is " + authType.name());
+
+        SSLContext sslContext = null;
+
+        if (authType == NiFiAuthType.SSL) {
+
+            if (!url.startsWith("https")) {
+                throw new IllegalArgumentException("Authentication Type of SSL requires an https URL");
+            }
+
+            final String keystore = configs.get(NiFiConfigs.NIFI_SSL_KEYSTORE);
+            final String keystoreType = configs.get(NiFiConfigs.NIFI_SSL_KEYSTORE_TYPE);
+            final String keystorePassword = configs.get(NiFiConfigs.NIFI_SSL_KEYSTORE_PASSWORD);
+
+            validateNotBlank(keystore, "Keystore is required for " + serviceName + " with Authentication Type of SSL");
+            validateNotBlank(keystoreType, "Keystore Type is required for " + serviceName + " with Authentication Type of SSL");
+            validateNotBlank(keystorePassword, "Keystore Password is required for " + serviceName + " with Authentication Type of SSL");
+
+            final String truststore = configs.get(NiFiConfigs.NIFI_SSL_TRUSTSTORE);
+            final String truststoreType = configs.get(NiFiConfigs.NIFI_SSL_TRUSTSTORE_TYPE);
+            final String truststorePassword = configs.get(NiFiConfigs.NIFI_SSL_TRUSTSTORE_PASSWORD);
+
+            validateNotBlank(truststore, "Truststore is required for " + serviceName + " with Authentication Type of SSL");
+            validateNotBlank(truststoreType, "Truststore Type is required for " + serviceName + " with Authentication Type of SSL");
+            validateNotBlank(truststorePassword, "Truststore Password is required for " + serviceName + " with Authentication Type of SSL");
+
+            LOG.debug("Creating SSLContext for NiFi connection");
+
+            sslContext = createSslContext(
+                    keystore.trim(),
+                    keystorePassword.trim().toCharArray(),
+                    keystoreType.trim(),
+                    truststore.trim(),
+                    truststorePassword.trim().toCharArray(),
+                    truststoreType.trim(),
+                    "TLS");
+        }
+
+        return new NiFiClient(url.trim(), sslContext);
+    }
+
+    public static HashMap<String, Object> connectionTest(String serviceName, Map<String, String> configs) throws Exception {
+        NiFiClient client = getNiFiClient(serviceName, configs);
+        return client.connectionTest();
+    }
+
+    private static void validateNotBlank(final String input, final String message) {
+        if (input == null || input.trim().isEmpty()) {
+            throw new IllegalArgumentException(message);
+        }
+    }
+
+    private static void validateUrl(String url) {
+        URI nifiUri;
+        try {
+            nifiUri = new URI(url);
+            if (!nifiUri.getPath().endsWith("nifi-api/resources")) {
+                throw new IllegalArgumentException(INVALID_URL_MSG);
+            }
+        } catch (URISyntaxException urie) {
+            throw new IllegalArgumentException(INVALID_URL_MSG);
+        }
+    }
+
+    private static SSLContext createSslContext(
+            final String keystore, final char[] keystorePasswd, final String keystoreType,
+            final String truststore, final char[] truststorePasswd, final String truststoreType,
+            final String protocol)
+            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException,
+            UnrecoverableKeyException, KeyManagementException {
+
+        // prepare the keystore
+        final KeyStore keyStore = KeyStore.getInstance(keystoreType);
+        try (final InputStream keyStoreStream = new FileInputStream(keystore)) {
+            keyStore.load(keyStoreStream, keystorePasswd);
+        }
+        final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+        keyManagerFactory.init(keyStore, keystorePasswd);
+
+        // prepare the truststore
+        final KeyStore trustStore = KeyStore.getInstance(truststoreType);
+        try (final InputStream trustStoreStream = new FileInputStream(truststore)) {
+            trustStore.load(trustStoreStream, truststorePasswd);
+        }
+        final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+        trustManagerFactory.init(trustStore);
+
+        // initialize the ssl context
+        final SSLContext sslContext = SSLContext.getInstance(protocol);
+        sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
+        return sslContext;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b64218a3/plugin-nifi/src/test/java/org/apache/ranger/services/nifi/client/TestNiFiClient.java
----------------------------------------------------------------------
diff --git a/plugin-nifi/src/test/java/org/apache/ranger/services/nifi/client/TestNiFiClient.java b/plugin-nifi/src/test/java/org/apache/ranger/services/nifi/client/TestNiFiClient.java
new file mode 100644
index 0000000..051c940
--- /dev/null
+++ b/plugin-nifi/src/test/java/org/apache/ranger/services/nifi/client/TestNiFiClient.java
@@ -0,0 +1,196 @@
+/*
+ * 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.ranger.services.nifi.client;
+
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+import org.apache.ranger.plugin.service.ResourceLookupContext;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import javax.ws.rs.core.Response;
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import static org.mockito.Mockito.when;
+
+public class TestNiFiClient {
+
+    private static final String RESOURCES_RESPONSE = "{\n" +
+            "  \"revision\": {\n" +
+            "    \"clientId\": \"0daac173-025c-4aa7-b644-97f7b10435d2\"\n" +
+            "  },\n" +
+            "  \"resources\": [\n" +
+            "    {\n" +
+            "      \"identifier\": \"/system\",\n" +
+            "      \"name\": \"System\"\n" +
+            "    },\n" +
+            "    {\n" +
+            "      \"identifier\": \"/controller\",\n" +
+            "      \"name\": \"Controller\"\n" +
+            "    },\n" +
+            "    {\n" +
+            "      \"identifier\": \"/flow\",\n" +
+            "      \"name\": \"NiFi Flow\"\n" +
+            "    },\n" +
+            "    {\n" +
+            "      \"identifier\": \"/provenance\",\n" +
+            "      \"name\": \"Provenance\"\n" +
+            "    },\n" +
+            "    {\n" +
+            "      \"identifier\": \"/proxy\",\n" +
+            "      \"name\": \"Proxy User Requests\"\n" +
+            "    },\n" +
+            "    {\n" +
+            "      \"identifier\": \"/resources\",\n" +
+            "      \"name\": \"NiFi Resources\"\n" +
+            "    }\n" +
+            "  ]\n" +
+            "}";
+
+    private NiFiClient niFiClient;
+
+    @Before
+    public void setup() {
+        niFiClient = new MockNiFiClient(RESOURCES_RESPONSE, 200);
+    }
+
+    @Test
+    public void testGetResourcesNoUserInput() throws Exception {
+        ResourceLookupContext resourceLookupContext = Mockito.mock(ResourceLookupContext.class);
+        when(resourceLookupContext.getUserInput()).thenReturn("");
+
+        final List<String> expectedResources = new ArrayList<>();
+        expectedResources.add("/system");
+        expectedResources.add("/controller");
+        expectedResources.add("/flow");
+        expectedResources.add("/provenance");
+        expectedResources.add("/proxy");
+        expectedResources.add("/resources");
+
+        List<String> resources = niFiClient.getResources(resourceLookupContext);
+        Assert.assertNotNull(resources);
+        Assert.assertEquals(expectedResources.size(), resources.size());
+
+        resources.removeAll(expectedResources);
+        Assert.assertEquals(0, resources.size());
+    }
+
+    @Test
+    public void testGetResourcesWithUserInputBeginning() throws Exception {
+        ResourceLookupContext resourceLookupContext = Mockito.mock(ResourceLookupContext.class);
+        when(resourceLookupContext.getUserInput()).thenReturn("/pr");
+
+        final List<String> expectedResources = new ArrayList<>();
+        expectedResources.add("/provenance");
+        expectedResources.add("/proxy");
+
+        List<String> resources = niFiClient.getResources(resourceLookupContext);
+        Assert.assertNotNull(resources);
+        Assert.assertEquals(expectedResources.size(), resources.size());
+
+        resources.removeAll(expectedResources);
+        Assert.assertEquals(0, resources.size());
+    }
+
+    @Test
+    public void testGetResourcesWithUserInputAnywhere() throws Exception {
+        ResourceLookupContext resourceLookupContext = Mockito.mock(ResourceLookupContext.class);
+        when(resourceLookupContext.getUserInput()).thenReturn("trol");
+
+        final List<String> expectedResources = new ArrayList<>();
+        expectedResources.add("/controller");
+
+        List<String> resources = niFiClient.getResources(resourceLookupContext);
+        Assert.assertNotNull(resources);
+        Assert.assertEquals(expectedResources.size(), resources.size());
+
+        resources.removeAll(expectedResources);
+        Assert.assertEquals(0, resources.size());
+    }
+
+    @Test
+    public void testGetResourcesErrorResponse() throws Exception {
+        final String errorMsg = "unknown error";
+        niFiClient = new MockNiFiClient(errorMsg, Response.Status.BAD_REQUEST.getStatusCode());
+
+        ResourceLookupContext resourceLookupContext = Mockito.mock(ResourceLookupContext.class);
+        when(resourceLookupContext.getUserInput()).thenReturn("");
+
+        try {
+            niFiClient.getResources(resourceLookupContext);
+            Assert.fail("should have thrown exception");
+        } catch (Exception e) {
+            Assert.assertTrue(e.getMessage().contains(errorMsg));
+        }
+    }
+
+    @Test
+    public void testConnectionTestSuccess() {
+        HashMap<String, Object> ret = niFiClient.connectionTest();
+        Assert.assertNotNull(ret);
+        Assert.assertEquals(NiFiClient.SUCCESS_MSG, ret.get("message"));
+    }
+
+    @Test
+    public void testConnectionTestFailure() {
+        final String errorMsg = "unknown error";
+        niFiClient = new MockNiFiClient(errorMsg, Response.Status.BAD_REQUEST.getStatusCode());
+
+        HashMap<String, Object> ret = niFiClient.connectionTest();
+        Assert.assertNotNull(ret);
+        Assert.assertEquals(NiFiClient.FAILURE_MSG, ret.get("message"));
+    }
+
+
+    /**
+     * Extend NiFiClient to return mock responses.
+     */
+    private static final class MockNiFiClient extends NiFiClient {
+
+        private int statusCode;
+        private String responseEntity;
+
+        public MockNiFiClient(String responseEntity, int statusCode) {
+            super("http://localhost:8080/nifi-api/resources", null);
+            this.statusCode = statusCode;
+            this.responseEntity = responseEntity;
+        }
+
+        @Override
+        protected WebResource getWebResource() {
+            return Mockito.mock(WebResource.class);
+        }
+
+        @Override
+        protected ClientResponse getResponse(WebResource resource, String accept) {
+            ClientResponse response = Mockito.mock(ClientResponse.class);
+            when(response.getStatus()).thenReturn(statusCode);
+            when(response.getEntityInputStream()).thenReturn(new ByteArrayInputStream(
+                    responseEntity.getBytes(StandardCharsets.UTF_8)
+            ));
+            return response;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b64218a3/plugin-nifi/src/test/java/org/apache/ranger/services/nifi/client/TestNiFiConnectionMgr.java
----------------------------------------------------------------------
diff --git a/plugin-nifi/src/test/java/org/apache/ranger/services/nifi/client/TestNiFiConnectionMgr.java b/plugin-nifi/src/test/java/org/apache/ranger/services/nifi/client/TestNiFiConnectionMgr.java
new file mode 100644
index 0000000..1726854
--- /dev/null
+++ b/plugin-nifi/src/test/java/org/apache/ranger/services/nifi/client/TestNiFiConnectionMgr.java
@@ -0,0 +1,124 @@
+/*
+ * 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.ranger.services.nifi.client;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.FileNotFoundException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class TestNiFiConnectionMgr {
+
+    @Test (expected = IllegalArgumentException.class)
+    public void testValidURLWithWrongEndPoint() throws Exception {
+        final String nifiUrl = "http://localhost:8080/nifi";
+
+        Map<String,String> configs = new HashMap<>();
+        configs.put(NiFiConfigs.NIFI_URL, nifiUrl);
+        configs.put(NiFiConfigs.NIFI_AUTHENTICATION_TYPE, NiFiAuthType.NONE.name());
+
+        NiFiConnectionMgr.getNiFiClient("nifi", configs);
+    }
+
+    @Test (expected = IllegalArgumentException.class)
+    public void testInvalidURL() throws Exception {
+        final String nifiUrl = "not a url";
+
+        Map<String,String> configs = new HashMap<>();
+        configs.put(NiFiConfigs.NIFI_URL, nifiUrl);
+        configs.put(NiFiConfigs.NIFI_AUTHENTICATION_TYPE, NiFiAuthType.NONE.name());
+
+        NiFiConnectionMgr.getNiFiClient("nifi", configs);
+    }
+
+    @Test
+    public void testAuthTypeNone() throws Exception {
+        final String nifiUrl = "http://localhost:8080/nifi-api/resources";
+
+        Map<String,String> configs = new HashMap<>();
+        configs.put(NiFiConfigs.NIFI_URL, nifiUrl);
+        configs.put(NiFiConfigs.NIFI_AUTHENTICATION_TYPE, NiFiAuthType.NONE.name());
+
+        NiFiClient client = NiFiConnectionMgr.getNiFiClient("nifi", configs);
+        Assert.assertNotNull(client);
+        Assert.assertEquals(nifiUrl, client.getUrl());
+        Assert.assertNull(client.getSslContext());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testAuthTypeNoneMissingURL() throws Exception {
+        Map<String,String> configs = new HashMap<>();
+        configs.put(NiFiConfigs.NIFI_URL, null);
+        configs.put(NiFiConfigs.NIFI_AUTHENTICATION_TYPE, NiFiAuthType.NONE.name());
+
+        NiFiConnectionMgr.getNiFiClient("nifi", configs);
+    }
+
+    @Test(expected = FileNotFoundException.class)
+    public void testAuthTypeSSL() throws Exception {
+        final String nifiUrl = "https://localhost:8080/nifi-api/resources";
+
+        Map<String,String> configs = new HashMap<>();
+        configs.put(NiFiConfigs.NIFI_URL, nifiUrl);
+        configs.put(NiFiConfigs.NIFI_AUTHENTICATION_TYPE, NiFiAuthType.SSL.name());
+
+        configs.put(NiFiConfigs.NIFI_SSL_KEYSTORE, "src/test/resources/missing.jks");
+        configs.put(NiFiConfigs.NIFI_SSL_KEYSTORE_PASSWORD, "password");
+        configs.put(NiFiConfigs.NIFI_SSL_KEYSTORE_TYPE, "JKS");
+
+        configs.put(NiFiConfigs.NIFI_SSL_TRUSTSTORE, "src/test/resources/missing.jks");
+        configs.put(NiFiConfigs.NIFI_SSL_TRUSTSTORE_PASSWORD, "password");
+        configs.put(NiFiConfigs.NIFI_SSL_TRUSTSTORE_TYPE, "JKS");
+
+        NiFiConnectionMgr.getNiFiClient("nifi", configs);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testAuthTypeSSLWithNonHttpsUrl() throws Exception {
+        final String nifiUrl = "http://localhost:8080/nifi-api/resources";
+
+        Map<String,String> configs = new HashMap<>();
+        configs.put(NiFiConfigs.NIFI_URL, nifiUrl);
+        configs.put(NiFiConfigs.NIFI_AUTHENTICATION_TYPE, NiFiAuthType.SSL.name());
+
+        configs.put(NiFiConfigs.NIFI_SSL_KEYSTORE, "src/test/resources/missing.jks");
+        configs.put(NiFiConfigs.NIFI_SSL_KEYSTORE_PASSWORD, "password");
+        configs.put(NiFiConfigs.NIFI_SSL_KEYSTORE_TYPE, "JKS");
+
+        configs.put(NiFiConfigs.NIFI_SSL_TRUSTSTORE, "src/test/resources/missing.jks");
+        configs.put(NiFiConfigs.NIFI_SSL_TRUSTSTORE_PASSWORD, "password");
+        configs.put(NiFiConfigs.NIFI_SSL_TRUSTSTORE_TYPE, "JKS");
+
+        NiFiConnectionMgr.getNiFiClient("nifi", configs);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testAuthTypeSSLMissingConfigs() throws Exception {
+        final String nifiUrl = "http://localhost:8080/nifi";
+
+        Map<String,String> configs = new HashMap<>();
+        configs.put(NiFiConfigs.NIFI_URL, nifiUrl);
+        configs.put(NiFiConfigs.NIFI_AUTHENTICATION_TYPE, NiFiAuthType.SSL.name());
+
+        NiFiConnectionMgr.getNiFiClient("nifi", configs);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b64218a3/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index eda7d7d..d6aa833 100644
--- a/pom.xml
+++ b/pom.xml
@@ -87,6 +87,7 @@
         <module>security-admin</module>
         <module>plugin-kafka</module>
         <module>plugin-solr</module>
+	    <module>plugin-nifi</module>
         <module>ugsync</module>
         <module>ugsync/ldapconfigchecktool/ldapconfigcheck</module>
         <module>unixauthclient</module>

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b64218a3/src/main/assembly/admin-web.xml
----------------------------------------------------------------------
diff --git a/src/main/assembly/admin-web.xml b/src/main/assembly/admin-web.xml
index 6aeb397..7fd2abf 100644
--- a/src/main/assembly/admin-web.xml
+++ b/src/main/assembly/admin-web.xml
@@ -296,6 +296,19 @@
        				<include>org.apache.ranger:ranger-solr-plugin</include>
      			</includes>
     		</moduleSet>
+
+      <moduleSet>
+          <binaries>
+              <includeDependencies>true</includeDependencies>
+              <outputDirectory>/ews/webapp/WEB-INF/classes/ranger-plugins/nifi</outputDirectory>
+              <unpack>false</unpack>
+              <directoryMode>755</directoryMode>
+              <fileMode>644</fileMode>
+          </binaries>
+          <includes>
+              <include>org.apache.ranger:ranger-nifi-plugin</include>
+          </includes>
+      </moduleSet>
   </moduleSets> 	
 
   <fileSets>