You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by rm...@apache.org on 2018/09/18 22:31:57 UTC

ranger git commit: RANGER-2157: Added NiFi Registry service

Repository: ranger
Updated Branches:
  refs/heads/master 9f639f3c5 -> c18b3717e


RANGER-2157: Added NiFi Registry service

Incorporated review comments

Signed-off-by: rmani <rm...@hortonworks.com>


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

Branch: refs/heads/master
Commit: c18b3717e35de2dd8b7aa069494f7b7f50dd6ce1
Parents: 9f639f3
Author: Koji Kawamura <ij...@gmail.com>
Authored: Fri Feb 16 17:31:37 2018 +0900
Committer: rmani <rm...@hortonworks.com>
Committed: Tue Sep 18 15:32:10 2018 -0700

----------------------------------------------------------------------
 .../plugin/store/EmbeddedServiceDefsUtil.java   |  11 +-
 .../ranger-servicedef-nifi-registry.json        | 167 ++++++++++++++
 plugin-nifi-registry/.gitignore                 |   1 +
 plugin-nifi-registry/pom.xml                    |  65 ++++++
 .../registry/RangerServiceNiFiRegistry.java     |  71 ++++++
 .../registry/client/NiFiRegistryAuthType.java   |  29 +++
 .../registry/client/NiFiRegistryClient.java     | 217 +++++++++++++++++++
 .../registry/client/NiFiRegistryConfigs.java    |  37 ++++
 .../client/NiFiRegistryConnectionMgr.java       | 159 ++++++++++++++
 .../registry/client/TestNiFiRegistryClient.java | 168 ++++++++++++++
 .../client/TestNiFiRegistryConnectionMgr.java   | 124 +++++++++++
 .../src/test/resources/resources-response.json  |  34 +++
 pom.xml                                         |   5 +-
 src/main/assembly/admin-web.xml                 |  13 ++
 14 files changed, 1097 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ranger/blob/c18b3717/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 5e74da8..75dc128 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
@@ -48,7 +48,7 @@ public class EmbeddedServiceDefsUtil {
 
 
 	// following servicedef list should be reviewed/updated whenever a new embedded service-def is added
-	private static final String DEFAULT_BOOTSTRAP_SERVICEDEF_LIST = "tag,hdfs,hbase,hive,kms,knox,storm,yarn,kafka,solr,atlas,nifi,sqoop,kylin";
+	private static final String DEFAULT_BOOTSTRAP_SERVICEDEF_LIST = "tag,hdfs,hbase,hive,kms,knox,storm,yarn,kafka,solr,atlas,nifi,nifi-registry,sqoop,kylin";
 	private static final String PROPERTY_SUPPORTED_SERVICE_DEFS = "ranger.supportedcomponents";
 	private Set<String> supportedServiceDefs;
 	public static final String EMBEDDED_SERVICEDEF_TAG_NAME  = "tag";
@@ -62,6 +62,7 @@ public class EmbeddedServiceDefsUtil {
 	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 EMBEDDED_SERVICEDEF_NIFI_REGISTRY_NAME  = "nifi-registry";
 	public static final String EMBEDDED_SERVICEDEF_ATLAS_NAME  = "atlas";
 	public static final String EMBEDDED_SERVICEDEF_WASB_NAME  = "wasb";
 	public static final String EMBEDDED_SERVICEDEF_SQOOP_NAME = "sqoop";
@@ -94,6 +95,7 @@ public class EmbeddedServiceDefsUtil {
 	private RangerServiceDef kafkaServiceDef;
 	private RangerServiceDef solrServiceDef;
 	private RangerServiceDef nifiServiceDef;
+	private RangerServiceDef nifiRegistryServiceDef;
 	private RangerServiceDef atlasServiceDef;
 	private RangerServiceDef wasbServiceDef;
 	private RangerServiceDef sqoopServiceDef;
@@ -133,6 +135,7 @@ public class EmbeddedServiceDefsUtil {
 			kafkaServiceDef = getOrCreateServiceDef(store, EMBEDDED_SERVICEDEF_KAFKA_NAME);
 			solrServiceDef  = getOrCreateServiceDef(store, EMBEDDED_SERVICEDEF_SOLR_NAME);
 			nifiServiceDef  = getOrCreateServiceDef(store, EMBEDDED_SERVICEDEF_NIFI_NAME);
+			nifiRegistryServiceDef = getOrCreateServiceDef(store, EMBEDDED_SERVICEDEF_NIFI_REGISTRY_NAME);
 			atlasServiceDef = getOrCreateServiceDef(store, EMBEDDED_SERVICEDEF_ATLAS_NAME);
 
 			tagServiceDef = getOrCreateServiceDef(store, EMBEDDED_SERVICEDEF_TAG_NAME);
@@ -189,7 +192,11 @@ public class EmbeddedServiceDefsUtil {
 		return getId(nifiServiceDef);
 	}
 
-    public long getAtlasServiceDefId() {
+	public long getNiFiRegistryServiceDefId() {
+		return getId(nifiRegistryServiceDef);
+	}
+
+	public long getAtlasServiceDefId() {
         return getId(atlasServiceDef);
     }
 

http://git-wip-us.apache.org/repos/asf/ranger/blob/c18b3717/agents-common/src/main/resources/service-defs/ranger-servicedef-nifi-registry.json
----------------------------------------------------------------------
diff --git a/agents-common/src/main/resources/service-defs/ranger-servicedef-nifi-registry.json b/agents-common/src/main/resources/service-defs/ranger-servicedef-nifi-registry.json
new file mode 100644
index 0000000..868543d
--- /dev/null
+++ b/agents-common/src/main/resources/service-defs/ranger-servicedef-nifi-registry.json
@@ -0,0 +1,167 @@
+{
+  "id":13,
+  "name":"nifi-registry",
+  "implClass":"org.apache.ranger.services.nifi.registry.RangerServiceNiFiRegistry",
+  "label":"NIFI Registry",
+  "description":"NiFi Registry",
+  "resources":[
+    {
+      "itemId":100,
+      "name":"nifi-registry-resource",
+      "type":"string",
+      "level":10,
+      "parent":"",
+      "mandatory":true,
+      "lookupSupported":true,
+      "recursiveSupported":false,
+      "excludesSupported":false,
+      "matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher",
+      "matcherOptions":{
+        "wildCard":true,
+        "ignoreCase":true
+      },
+      "validationRegEx":"",
+      "validationMessage":"",
+      "uiHint":"",
+      "label":"NiFi Registry Resource Identifier",
+      "description":"NiFi Registry Resource"
+    }
+
+  ],
+  "accessTypes":[
+    {
+      "itemId":100,
+      "name":"READ",
+      "label":"Read"
+    },
+    {
+      "itemId":200,
+      "name":"WRITE",
+      "label":"Write"
+    },
+    {
+      "itemId":300,
+      "name":"DELETE",
+      "label":"Delete"
+    }
+  ],
+  "configs":[
+    {
+      "itemId":400,
+      "name":"nifi.registry.url",
+      "type":"string",
+      "mandatory":true,
+      "defaultValue":"http://localhost:18080/nifi-registry-api/policies/resources",
+      "validationRegEx":"",
+      "validationMessage":"",
+      "uiHint":"{\"TextFieldWithIcon\":true, \"info\": \"The URL of the NiFi Registry REST API that provides the available resources.\"}",
+      "label":"NiFi Registry URL"
+    },
+    {
+      "itemId": 410,
+      "name": "nifi.registry.authentication",
+      "type": "enum",
+      "subType": "authType",
+      "mandatory": true,
+      "validationRegEx":"",
+      "validationMessage": "",
+      "uiHint":"",
+      "label": "Authentication Type",
+      "defaultValue": "NONE"
+    },
+    {
+      "itemId":500,
+      "name":"nifi.registry.ssl.keystore",
+      "type":"string",
+      "mandatory":false,
+      "defaultValue":"",
+      "validationRegEx":"",
+      "validationMessage":"",
+      "uiHint":"",
+      "label":"Keystore"
+    },
+    {
+      "itemId":510,
+      "name":"nifi.registry.ssl.keystoreType",
+      "type":"string",
+      "mandatory":false,
+      "defaultValue":"",
+      "validationRegEx":"",
+      "validationMessage":"",
+      "uiHint":"",
+      "label":"Keystore Type"
+    },
+    {
+      "itemId":520,
+      "name":"nifi.registry.ssl.keystorePassword",
+      "type":"password",
+      "mandatory":false,
+      "defaultValue":"",
+      "validationRegEx":"",
+      "validationMessage":"",
+      "uiHint":"",
+      "label":"Keystore Password"
+    },
+    {
+      "itemId":530,
+      "name":"nifi.registry.ssl.truststore",
+      "type":"string",
+      "mandatory":false,
+      "defaultValue":"",
+      "validationRegEx":"",
+      "validationMessage":"",
+      "uiHint":"",
+      "label":"Truststore"
+    },
+    {
+      "itemId":540,
+      "name":"nifi.registry.ssl.truststoreType",
+      "type":"string",
+      "mandatory":false,
+      "defaultValue":"",
+      "validationRegEx":"",
+      "validationMessage":"",
+      "uiHint":"",
+      "label":"Truststore Type"
+    },
+    {
+      "itemId":550,
+      "name":"nifi.registry.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/ranger/blob/c18b3717/plugin-nifi-registry/.gitignore
----------------------------------------------------------------------
diff --git a/plugin-nifi-registry/.gitignore b/plugin-nifi-registry/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/plugin-nifi-registry/.gitignore
@@ -0,0 +1 @@
+/target

http://git-wip-us.apache.org/repos/asf/ranger/blob/c18b3717/plugin-nifi-registry/pom.xml
----------------------------------------------------------------------
diff --git a/plugin-nifi-registry/pom.xml b/plugin-nifi-registry/pom.xml
new file mode 100644
index 0000000..3e99f04
--- /dev/null
+++ b/plugin-nifi-registry/pom.xml
@@ -0,0 +1,65 @@
+<?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-registry-plugin</artifactId>
+    <name>NiFi Registry Security Plugin</name>
+    <description>NiFi Registry Security Plugin</description>
+    <packaging>jar</packaging>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+    <parent>
+        <artifactId>ranger</artifactId>
+        <groupId>org.apache.ranger</groupId>
+        <version>2.0.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-core</artifactId>
+            <version>${mockito.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>

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

http://git-wip-us.apache.org/repos/asf/ranger/blob/c18b3717/plugin-nifi-registry/src/main/java/org/apache/ranger/services/nifi/registry/client/NiFiRegistryAuthType.java
----------------------------------------------------------------------
diff --git a/plugin-nifi-registry/src/main/java/org/apache/ranger/services/nifi/registry/client/NiFiRegistryAuthType.java b/plugin-nifi-registry/src/main/java/org/apache/ranger/services/nifi/registry/client/NiFiRegistryAuthType.java
new file mode 100644
index 0000000..2956afe
--- /dev/null
+++ b/plugin-nifi-registry/src/main/java/org/apache/ranger/services/nifi/registry/client/NiFiRegistryAuthType.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.registry.client;
+
+/**
+ * Possible authentication types for NiFi Registry.
+ */
+public enum NiFiRegistryAuthType {
+
+    NONE,
+    SSL
+
+}

http://git-wip-us.apache.org/repos/asf/ranger/blob/c18b3717/plugin-nifi-registry/src/main/java/org/apache/ranger/services/nifi/registry/client/NiFiRegistryClient.java
----------------------------------------------------------------------
diff --git a/plugin-nifi-registry/src/main/java/org/apache/ranger/services/nifi/registry/client/NiFiRegistryClient.java b/plugin-nifi-registry/src/main/java/org/apache/ranger/services/nifi/registry/client/NiFiRegistryClient.java
new file mode 100644
index 0000000..7eff5f3
--- /dev/null
+++ b/plugin-nifi-registry/src/main/java/org/apache/ranger/services/nifi/registry/client/NiFiRegistryClient.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.registry.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 Registry and retrieve available resources.
+ */
+public class NiFiRegistryClient {
+
+    private static final Log LOG = LogFactory.getLog(NiFiRegistryClient.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 NiFiRegistryClient(final String url, final SSLContext sslContext) {
+        this.url = url;
+        this.sslContext = sslContext;
+        this.hostnameVerifier = new NiFiRegistryHostnameVerifier();
+    }
+
+    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 Registry due to: " + errorMsg);
+        }
+
+        JsonNode rootNode = mapper.readTree(response.getEntityInputStream());
+        if (rootNode == null) {
+            throw new Exception("Unable to retrieve resources from NiFi Registry");
+        }
+
+        List<String> identifiers = rootNode.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 NiFiRegistryHostnameVerifier 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 List<String> result = new ArrayList<>();
+            final Collection<List<?>> altNames = certificate.getSubjectAlternativeNames();
+            if (altNames == null) {
+                return result;
+            }
+
+			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.
+                 */
+				if (generalName.size() > 1) {
+					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/ranger/blob/c18b3717/plugin-nifi-registry/src/main/java/org/apache/ranger/services/nifi/registry/client/NiFiRegistryConfigs.java
----------------------------------------------------------------------
diff --git a/plugin-nifi-registry/src/main/java/org/apache/ranger/services/nifi/registry/client/NiFiRegistryConfigs.java b/plugin-nifi-registry/src/main/java/org/apache/ranger/services/nifi/registry/client/NiFiRegistryConfigs.java
new file mode 100644
index 0000000..ea91ca4
--- /dev/null
+++ b/plugin-nifi-registry/src/main/java/org/apache/ranger/services/nifi/registry/client/NiFiRegistryConfigs.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.registry.client;
+
+/**
+ * Config property names from the NiFi Registry service definition.
+ */
+public interface NiFiRegistryConfigs {
+
+    String NIFI_REG_URL = "nifi.registry.url";
+    String NIFI_REG_AUTHENTICATION_TYPE = "nifi.registry.authentication";
+
+    String NIFI_REG_SSL_KEYSTORE = "nifi.registry.ssl.keystore";
+    String NIFI_REG_SSL_KEYSTORE_TYPE = "nifi.registry.ssl.keystoreType";
+    String NIFI_REG_SSL_KEYSTORE_PASSWORD = "nifi.registry.ssl.keystorePassword";
+
+    String NIFI_REG_SSL_TRUSTSTORE = "nifi.registry.ssl.truststore";
+    String NIFI_REG_SSL_TRUSTSTORE_TYPE = "nifi.registry.ssl.truststoreType";
+    String NIFI_REG_SSL_TRUSTSTORE_PASSWORD = "nifi.registry.ssl.truststorePassword";
+
+}

http://git-wip-us.apache.org/repos/asf/ranger/blob/c18b3717/plugin-nifi-registry/src/main/java/org/apache/ranger/services/nifi/registry/client/NiFiRegistryConnectionMgr.java
----------------------------------------------------------------------
diff --git a/plugin-nifi-registry/src/main/java/org/apache/ranger/services/nifi/registry/client/NiFiRegistryConnectionMgr.java b/plugin-nifi-registry/src/main/java/org/apache/ranger/services/nifi/registry/client/NiFiRegistryConnectionMgr.java
new file mode 100644
index 0000000..d606d25
--- /dev/null
+++ b/plugin-nifi-registry/src/main/java/org/apache/ranger/services/nifi/registry/client/NiFiRegistryConnectionMgr.java
@@ -0,0 +1,159 @@
+/*
+ * 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.registry.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.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 NiFiRegistryClient and provides method to test a connection to NiFi Registry.
+ */
+public class NiFiRegistryConnectionMgr {
+
+    private static final Log LOG = LogFactory.getLog(NiFiRegistryConnectionMgr.class);
+
+    private static final String API_RESOURCES_PATH = "/nifi-registry-api/policies/resources";
+    static final String INVALID_URL_MSG =  "NiFi Registry URL must be a valid URL of the form " +
+            "http(s)://<hostname>(:<port>)" + API_RESOURCES_PATH;
+
+
+    static public NiFiRegistryClient getNiFiRegistryClient(String serviceName, Map<String, String> configs) throws Exception {
+        final String url = configs.get(NiFiRegistryConfigs.NIFI_REG_URL);
+        validateNotBlank(url, "NiFi Registry URL is required for " + serviceName);
+        validateUrl(url);
+
+        final String authTypeStr = configs.get(NiFiRegistryConfigs.NIFI_REG_AUTHENTICATION_TYPE);
+        validateNotBlank(authTypeStr, "Authentication Type is required for " + serviceName);
+
+        final NiFiRegistryAuthType authType = NiFiRegistryAuthType.valueOf(authTypeStr);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("NiFiRegistryAuthType is " + authType.name());
+        }
+
+        SSLContext sslContext = null;
+
+        if (authType == NiFiRegistryAuthType.SSL) {
+
+            if (!url.startsWith("https")) {
+                throw new IllegalArgumentException("Authentication Type of SSL requires an https URL");
+            }
+
+            final String keystore = configs.get(NiFiRegistryConfigs.NIFI_REG_SSL_KEYSTORE);
+            final String keystoreType = configs.get(NiFiRegistryConfigs.NIFI_REG_SSL_KEYSTORE_TYPE);
+            final String keystorePassword = configs.get(NiFiRegistryConfigs.NIFI_REG_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(NiFiRegistryConfigs.NIFI_REG_SSL_TRUSTSTORE);
+            final String truststoreType = configs.get(NiFiRegistryConfigs.NIFI_REG_SSL_TRUSTSTORE_TYPE);
+            final String truststorePassword = configs.get(NiFiRegistryConfigs.NIFI_REG_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 Registry connection");
+
+            sslContext = createSslContext(
+                    keystore.trim(),
+                    keystorePassword.trim().toCharArray(),
+                    keystoreType.trim(),
+                    truststore.trim(),
+                    truststorePassword.trim().toCharArray(),
+                    truststoreType.trim(),
+                    "TLS");
+        }
+
+        return new NiFiRegistryClient(url.trim(), sslContext);
+    }
+
+    public static HashMap<String, Object> connectionTest(String serviceName, Map<String, String> configs) throws Exception {
+        NiFiRegistryClient client = getNiFiRegistryClient(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(API_RESOURCES_PATH)) {
+                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/ranger/blob/c18b3717/plugin-nifi-registry/src/test/java/org/apache/ranger/services/nifi/registry/client/TestNiFiRegistryClient.java
----------------------------------------------------------------------
diff --git a/plugin-nifi-registry/src/test/java/org/apache/ranger/services/nifi/registry/client/TestNiFiRegistryClient.java b/plugin-nifi-registry/src/test/java/org/apache/ranger/services/nifi/registry/client/TestNiFiRegistryClient.java
new file mode 100644
index 0000000..7db646f
--- /dev/null
+++ b/plugin-nifi-registry/src/test/java/org/apache/ranger/services/nifi/registry/client/TestNiFiRegistryClient.java
@@ -0,0 +1,168 @@
+/*
+ * 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.registry.client;
+
+import com.google.common.io.Resources;
+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.io.IOException;
+import java.net.URL;
+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 TestNiFiRegistryClient {
+
+    private NiFiRegistryClient registryClient;
+
+    @Before
+    public void setup() throws IOException {
+        final URL responseFile = TestNiFiRegistryClient.class.getResource("/resources-response.json");
+        final String resourcesResponse = Resources.toString(responseFile, StandardCharsets.UTF_8);
+        registryClient = new MockNiFiRegistryClient(resourcesResponse, 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("/policies");
+        expectedResources.add("/tenants");
+        expectedResources.add("/proxy");
+        expectedResources.add("/actuator");
+        expectedResources.add("/swagger");
+        expectedResources.add("/buckets");
+        expectedResources.add("/buckets/fc0625e4-a9ae-4277-bab7-a2bc984f6c4f");
+        expectedResources.add("/buckets/0b5edba5-da83-4839-b64a-adf5f21abaf4");
+
+        List<String> resources = registryClient.getResources(resourceLookupContext);
+        Assert.assertNotNull(resources);
+        Assert.assertEquals(expectedResources.size(), resources.size());
+
+        Assert.assertTrue(resources.containsAll(expectedResources));
+    }
+
+    @Test
+    public void testGetResourcesWithUserInputBeginning() throws Exception {
+        ResourceLookupContext resourceLookupContext = Mockito.mock(ResourceLookupContext.class);
+        when(resourceLookupContext.getUserInput()).thenReturn("/p");
+
+        final List<String> expectedResources = new ArrayList<>();
+        expectedResources.add("/policies");
+        expectedResources.add("/proxy");
+
+        List<String> resources = registryClient.getResources(resourceLookupContext);
+        Assert.assertNotNull(resources);
+        Assert.assertEquals(expectedResources.size(), resources.size());
+
+        Assert.assertTrue(resources.containsAll(expectedResources));
+    }
+
+    @Test
+    public void testGetResourcesWithUserInputAnywhere() throws Exception {
+        ResourceLookupContext resourceLookupContext = Mockito.mock(ResourceLookupContext.class);
+        when(resourceLookupContext.getUserInput()).thenReturn("ant");
+
+        final List<String> expectedResources = new ArrayList<>();
+        expectedResources.add("/tenants");
+
+        List<String> resources = registryClient.getResources(resourceLookupContext);
+        Assert.assertNotNull(resources);
+        Assert.assertEquals(expectedResources.size(), resources.size());
+
+        Assert.assertTrue(resources.containsAll(expectedResources));
+    }
+
+    @Test
+    public void testGetResourcesErrorResponse() {
+        final String errorMsg = "unknown error";
+        registryClient = new MockNiFiRegistryClient(errorMsg, Response.Status.BAD_REQUEST.getStatusCode());
+
+        ResourceLookupContext resourceLookupContext = Mockito.mock(ResourceLookupContext.class);
+        when(resourceLookupContext.getUserInput()).thenReturn("");
+
+        try {
+            registryClient.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 = registryClient.connectionTest();
+        Assert.assertNotNull(ret);
+        Assert.assertEquals(NiFiRegistryClient.SUCCESS_MSG, ret.get("message"));
+    }
+
+    @Test
+    public void testConnectionTestFailure() {
+        final String errorMsg = "unknown error";
+        registryClient = new MockNiFiRegistryClient(errorMsg, Response.Status.BAD_REQUEST.getStatusCode());
+
+        HashMap<String, Object> ret = registryClient.connectionTest();
+        Assert.assertNotNull(ret);
+        Assert.assertEquals(NiFiRegistryClient.FAILURE_MSG, ret.get("message"));
+    }
+
+
+    /**
+     * Extend NiFiRegistryClient to return mock responses.
+     */
+    private static final class MockNiFiRegistryClient extends NiFiRegistryClient {
+
+        private int statusCode;
+        private String responseEntity;
+
+        private MockNiFiRegistryClient(String responseEntity, int statusCode) {
+            super("http://localhost:18080/nifi-registry-api/policiesresources", 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/ranger/blob/c18b3717/plugin-nifi-registry/src/test/java/org/apache/ranger/services/nifi/registry/client/TestNiFiRegistryConnectionMgr.java
----------------------------------------------------------------------
diff --git a/plugin-nifi-registry/src/test/java/org/apache/ranger/services/nifi/registry/client/TestNiFiRegistryConnectionMgr.java b/plugin-nifi-registry/src/test/java/org/apache/ranger/services/nifi/registry/client/TestNiFiRegistryConnectionMgr.java
new file mode 100644
index 0000000..95a7999
--- /dev/null
+++ b/plugin-nifi-registry/src/test/java/org/apache/ranger/services/nifi/registry/client/TestNiFiRegistryConnectionMgr.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.registry.client;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.FileNotFoundException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class TestNiFiRegistryConnectionMgr {
+
+    @Test (expected = IllegalArgumentException.class)
+    public void testValidURLWithWrongEndPoint() throws Exception {
+        final String nifiRegistryUrl = "http://localhost:18080/nifi-registry";
+
+        Map<String,String> configs = new HashMap<>();
+        configs.put(NiFiRegistryConfigs.NIFI_REG_URL, nifiRegistryUrl);
+        configs.put(NiFiRegistryConfigs.NIFI_REG_AUTHENTICATION_TYPE, NiFiRegistryAuthType.NONE.name());
+
+        NiFiRegistryConnectionMgr.getNiFiRegistryClient("nifi-registry", configs);
+    }
+
+    @Test (expected = IllegalArgumentException.class)
+    public void testInvalidURL() throws Exception {
+        final String nifiRegistryUrl = "not a url";
+
+        Map<String,String> configs = new HashMap<>();
+        configs.put(NiFiRegistryConfigs.NIFI_REG_URL, nifiRegistryUrl);
+        configs.put(NiFiRegistryConfigs.NIFI_REG_AUTHENTICATION_TYPE, NiFiRegistryAuthType.NONE.name());
+
+        NiFiRegistryConnectionMgr.getNiFiRegistryClient("nifi-registry", configs);
+    }
+
+    @Test
+    public void testAuthTypeNone() throws Exception {
+        final String nifiRegistryUrl = "http://localhost:18080/nifi-registry-api/policies/resources";
+
+        Map<String,String> configs = new HashMap<>();
+        configs.put(NiFiRegistryConfigs.NIFI_REG_URL, nifiRegistryUrl);
+        configs.put(NiFiRegistryConfigs.NIFI_REG_AUTHENTICATION_TYPE, NiFiRegistryAuthType.NONE.name());
+
+        NiFiRegistryClient client = NiFiRegistryConnectionMgr.getNiFiRegistryClient("nifi", configs);
+        Assert.assertNotNull(client);
+        Assert.assertEquals(nifiRegistryUrl, client.getUrl());
+        Assert.assertNull(client.getSslContext());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testAuthTypeNoneMissingURL() throws Exception {
+        Map<String,String> configs = new HashMap<>();
+        configs.put(NiFiRegistryConfigs.NIFI_REG_URL, null);
+        configs.put(NiFiRegistryConfigs.NIFI_REG_AUTHENTICATION_TYPE, NiFiRegistryAuthType.NONE.name());
+
+        NiFiRegistryConnectionMgr.getNiFiRegistryClient("nifi-registry", configs);
+    }
+
+    @Test(expected = FileNotFoundException.class)
+    public void testAuthTypeSSL() throws Exception {
+        final String nifiRegistryUrl = "https://localhost:18080/nifi-registry-api/policies/resources";
+
+        Map<String,String> configs = new HashMap<>();
+        configs.put(NiFiRegistryConfigs.NIFI_REG_URL, nifiRegistryUrl);
+        configs.put(NiFiRegistryConfigs.NIFI_REG_AUTHENTICATION_TYPE, NiFiRegistryAuthType.SSL.name());
+
+        configs.put(NiFiRegistryConfigs.NIFI_REG_SSL_KEYSTORE, "src/test/resources/missing.jks");
+        configs.put(NiFiRegistryConfigs.NIFI_REG_SSL_KEYSTORE_PASSWORD, "password");
+        configs.put(NiFiRegistryConfigs.NIFI_REG_SSL_KEYSTORE_TYPE, "JKS");
+
+        configs.put(NiFiRegistryConfigs.NIFI_REG_SSL_TRUSTSTORE, "src/test/resources/missing.jks");
+        configs.put(NiFiRegistryConfigs.NIFI_REG_SSL_TRUSTSTORE_PASSWORD, "password");
+        configs.put(NiFiRegistryConfigs.NIFI_REG_SSL_TRUSTSTORE_TYPE, "JKS");
+
+        NiFiRegistryConnectionMgr.getNiFiRegistryClient("nifi-registry", configs);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testAuthTypeSSLWithNonHttpsUrl() throws Exception {
+        final String nifiRegistryUrl = "http://localhost:18080/nifi-registry-api/policies/resources";
+
+        Map<String,String> configs = new HashMap<>();
+        configs.put(NiFiRegistryConfigs.NIFI_REG_URL, nifiRegistryUrl);
+        configs.put(NiFiRegistryConfigs.NIFI_REG_AUTHENTICATION_TYPE, NiFiRegistryAuthType.SSL.name());
+
+        configs.put(NiFiRegistryConfigs.NIFI_REG_SSL_KEYSTORE, "src/test/resources/missing.jks");
+        configs.put(NiFiRegistryConfigs.NIFI_REG_SSL_KEYSTORE_PASSWORD, "password");
+        configs.put(NiFiRegistryConfigs.NIFI_REG_SSL_KEYSTORE_TYPE, "JKS");
+
+        configs.put(NiFiRegistryConfigs.NIFI_REG_SSL_TRUSTSTORE, "src/test/resources/missing.jks");
+        configs.put(NiFiRegistryConfigs.NIFI_REG_SSL_TRUSTSTORE_PASSWORD, "password");
+        configs.put(NiFiRegistryConfigs.NIFI_REG_SSL_TRUSTSTORE_TYPE, "JKS");
+
+        NiFiRegistryConnectionMgr.getNiFiRegistryClient("nifi-registry", configs);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testAuthTypeSSLMissingConfigs() throws Exception {
+        final String nifiRegistryUrl = "http://localhost:18080/nifi-registry";
+
+        Map<String,String> configs = new HashMap<>();
+        configs.put(NiFiRegistryConfigs.NIFI_REG_URL, nifiRegistryUrl);
+        configs.put(NiFiRegistryConfigs.NIFI_REG_AUTHENTICATION_TYPE, NiFiRegistryAuthType.SSL.name());
+
+        NiFiRegistryConnectionMgr.getNiFiRegistryClient("nifi-registry", configs);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/ranger/blob/c18b3717/plugin-nifi-registry/src/test/resources/resources-response.json
----------------------------------------------------------------------
diff --git a/plugin-nifi-registry/src/test/resources/resources-response.json b/plugin-nifi-registry/src/test/resources/resources-response.json
new file mode 100644
index 0000000..38a8e6a
--- /dev/null
+++ b/plugin-nifi-registry/src/test/resources/resources-response.json
@@ -0,0 +1,34 @@
+[
+  {
+    "identifier": "/policies",
+    "name": "Access Policies"
+  },
+  {
+    "identifier": "/tenants",
+    "name": "Tenants"
+  },
+  {
+    "identifier": "/proxy",
+    "name": "Proxy User Requests"
+  },
+  {
+    "identifier": "/actuator",
+    "name": "Actuator"
+  },
+  {
+    "identifier": "/swagger",
+    "name": "Swagger"
+  },
+  {
+    "identifier": "/buckets",
+    "name": "Buckets"
+  },
+  {
+    "identifier": "/buckets/fc0625e4-a9ae-4277-bab7-a2bc984f6c4f",
+    "name": "Bucket A"
+  },
+  {
+    "identifier": "/buckets/0b5edba5-da83-4839-b64a-adf5f21abaf4",
+    "name": "Bucket B"
+  }
+]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ranger/blob/c18b3717/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 41bcd90..ebf5d48 100644
--- a/pom.xml
+++ b/pom.xml
@@ -86,7 +86,8 @@
         <module>security-admin</module>
         <module>plugin-kafka</module>
         <module>plugin-solr</module>
-	    <module>plugin-nifi</module>
+	      <module>plugin-nifi</module>
+        <module>plugin-nifi-registry</module>
         <module>ugsync</module>
         <module>ugsync/ldapconfigchecktool/ldapconfigcheck</module>
         <module>unixauthclient</module>
@@ -112,7 +113,7 @@
         <module>ranger-sqoop-plugin-shim</module>
         <module>plugin-kylin</module>
         <module>ranger-kylin-plugin-shim</module>
-  </modules>
+    </modules>
     <properties>
         <maven.version.required>3.3.3</maven.version.required>
         <java.version.required>1.8</java.version.required>

http://git-wip-us.apache.org/repos/asf/ranger/blob/c18b3717/src/main/assembly/admin-web.xml
----------------------------------------------------------------------
diff --git a/src/main/assembly/admin-web.xml b/src/main/assembly/admin-web.xml
index d0f3545..b3ec885 100644
--- a/src/main/assembly/admin-web.xml
+++ b/src/main/assembly/admin-web.xml
@@ -320,6 +320,19 @@
       <moduleSet>
           <binaries>
               <includeDependencies>true</includeDependencies>
+              <outputDirectory>/ews/webapp/WEB-INF/classes/ranger-plugins/nifi-registry</outputDirectory>
+              <unpack>false</unpack>
+              <directoryMode>755</directoryMode>
+              <fileMode>644</fileMode>
+          </binaries>
+          <includes>
+              <include>org.apache.ranger:ranger-nifi-registry-plugin</include>
+          </includes>
+      </moduleSet>
+
+      <moduleSet>
+          <binaries>
+              <includeDependencies>true</includeDependencies>
               <outputDirectory>/ews/webapp/WEB-INF/classes/ranger-plugins/atlas</outputDirectory>
               <unpack>false</unpack>
               <directoryMode>755</directoryMode>