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 2020/03/17 17:00:28 UTC
[ranger] branch master updated: RANGER-2748: Schema Registry -
service-def and resource-lookup implementation
This is an automated email from the ASF dual-hosted git repository.
madhan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git
The following commit(s) were added to refs/heads/master by this push:
new 6d6682c RANGER-2748: Schema Registry - service-def and resource-lookup implementation
6d6682c is described below
commit 6d6682cbf12c04f76545b9e2451c6ba3de06ac74
Author: vomoshkovskyi <vo...@cloudera.com>
AuthorDate: Fri Jan 17 11:58:47 2020 +0200
RANGER-2748: Schema Registry - service-def and resource-lookup implementation
Signed-off-by: Madhan Neethiraj <ma...@apache.org>
---
.../plugin/store/EmbeddedServiceDefsUtil.java | 8 +
.../ranger-servicedef-schema-registry.json | 259 ++++++++++++++++++
distro/pom.xml | 31 +++
.../src/main/assembly/plugin-schema-registry.xml | 39 +++
plugin-schema-registry/.gitignore | 3 +
plugin-schema-registry/pom.xml | 245 +++++++++++++++++
.../registry/RangerServiceSchemaRegistry.java | 88 ++++++
.../registry/client/AutocompletionAgent.java | 144 ++++++++++
.../registry/client/SchemaRegistryResourceMgr.java | 134 ++++++++++
.../connection/DefaultSchemaRegistryClient.java | 294 +++++++++++++++++++++
.../client/connection/ISchemaRegistryClient.java | 28 ++
.../client/connection/util/SecurityUtils.java | 228 ++++++++++++++++
.../registry/client/AutocompletionAgentTest.java | 194 ++++++++++++++
.../client/SchemaRegistryResourceMgrTest.java | 108 ++++++++
.../DefaultSchemaRegistryClientTest.java | 190 +++++++++++++
.../client/connection/util/SecurityUtilsTest.java | 121 +++++++++
.../client/util/AcceptAllHostnameVerifier.java | 28 ++
.../DefaultSchemaRegistryClientForTesting.java | 46 ++++
.../client/util/TestAutocompletionAgent.java | 59 +++++
.../src/test/resources/keystore.jks | Bin 0 -> 2272 bytes
.../src/test/resources/schema-text3.avcs | 9 +
.../test/resources/ssl-schema-registry-client.yaml | 27 ++
.../src/test/resources/ssl-schema-registry.yaml | 79 ++++++
.../src/test/resources/truststore.jks | Bin 0 -> 982 bytes
pom.xml | 5 +
25 files changed, 2367 insertions(+)
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 882ca2f..072c803 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
@@ -61,6 +61,7 @@ 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_SCHEMA_REGISTRY_NAME = "schema-registry";
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";
@@ -84,6 +85,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 SCHEMA_REGISTRY_IMPL_CLASS_NAME = "org.apache.ranger.services.schemaregistry.RangerServiceSchemaRegistry";
public static final String NIFI_IMPL_CLASS_NAME = "org.apache.ranger.services.nifi.RangerServiceNiFi";
public static final String ATLAS_IMPL_CLASS_NAME = "org.apache.ranger.services.atlas.RangerServiceAtlas";
public static final String PRESTO_IMPL_CLASS_NAME = "org.apache.ranger.services.presto.RangerServicePresto";
@@ -102,6 +104,7 @@ public class EmbeddedServiceDefsUtil {
private RangerServiceDef yarnServiceDef;
private RangerServiceDef kafkaServiceDef;
private RangerServiceDef solrServiceDef;
+ private RangerServiceDef schemaRegistryServiceDef;
private RangerServiceDef nifiServiceDef;
private RangerServiceDef nifiRegistryServiceDef;
private RangerServiceDef atlasServiceDef;
@@ -149,6 +152,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);
+ schemaRegistryServiceDef = getOrCreateServiceDef(store, EMBEDDED_SERVICEDEF_SCHEMA_REGISTRY_NAME);
nifiServiceDef = getOrCreateServiceDef(store, EMBEDDED_SERVICEDEF_NIFI_NAME);
nifiRegistryServiceDef = getOrCreateServiceDef(store, EMBEDDED_SERVICEDEF_NIFI_REGISTRY_NAME);
atlasServiceDef = getOrCreateServiceDef(store, EMBEDDED_SERVICEDEF_ATLAS_NAME);
@@ -208,6 +212,10 @@ public class EmbeddedServiceDefsUtil {
return getId(solrServiceDef);
}
+ public long getSchemaRegistryServiceDefId() {
+ return getId(schemaRegistryServiceDef);
+ }
+
public long getNiFiServiceDefId() {
return getId(nifiServiceDef);
}
diff --git a/agents-common/src/main/resources/service-defs/ranger-servicedef-schema-registry.json b/agents-common/src/main/resources/service-defs/ranger-servicedef-schema-registry.json
new file mode 100644
index 0000000..3997cc2
--- /dev/null
+++ b/agents-common/src/main/resources/service-defs/ranger-servicedef-schema-registry.json
@@ -0,0 +1,259 @@
+{
+ "name": "schema-registry",
+ "implClass": "org.apache.ranger.services.schema.registry.RangerServiceSchemaRegistry",
+ "label": "Schema Registry",
+ "description": "Schema Registry",
+ "resources":
+ [
+
+ {
+ "itemId": 0,
+ "name": "registry-service",
+ "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": "Schema Registry Service",
+ "description": "Schema Registry Service"
+ },
+
+ {
+ "itemId": 1,
+ "name": "schema-group",
+ "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": "Schema Group",
+ "description": "Schema Group"
+ },
+
+ {
+ "itemId": 22,
+ "name": "schema-metadata",
+ "type": "string",
+ "level": 20,
+ "parent": "schema-group",
+ "mandatory": true,
+ "lookupSupported": true,
+ "recursiveSupported": false,
+ "excludesSupported": true,
+ "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher",
+ "matcherOptions": {
+ "wildCard":true,
+ "ignoreCase":true
+ },
+ "validationRegEx":"",
+ "validationMessage": "",
+ "uiHint":"",
+ "label": "Schema Name",
+ "description": "Schema Name",
+ "isValidLeaf": "true"
+ },
+
+
+ {
+ "itemId": 32,
+ "name": "schema-branch",
+ "type": "string",
+ "level": 30,
+ "parent": "schema-metadata",
+ "mandatory": true,
+ "lookupSupported": true,
+ "recursiveSupported": false,
+ "excludesSupported": true,
+ "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher",
+ "matcherOptions": {
+ "wildCard":true,
+ "ignoreCase":true
+ },
+ "validationRegEx":"",
+ "validationMessage": "",
+ "uiHint":"",
+ "label": "Schema Branch",
+ "description": "Schema Branch",
+ "isValidLeaf": "true"
+ },
+
+ {
+ "itemId": 42,
+ "name": "schema-version",
+ "type": "string",
+ "level": 40,
+ "parent": "schema-branch",
+ "mandatory": true,
+ "lookupSupported": true,
+ "recursiveSupported": false,
+ "excludesSupported": true,
+ "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher",
+ "matcherOptions": {
+ "wildCard":true,
+ "ignoreCase":true
+ },
+ "validationRegEx": "^\\*$",
+ "validationMessage": "",
+ "uiHint":"",
+ "label": "Schema Version",
+ "description": "Schema Version"
+ },
+
+ {
+ "itemId": 5,
+ "name": "serde",
+ "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": "Serializer/Deserializer",
+ "description": "Serializer/Deserializer"
+ }
+
+ ],
+
+ "accessTypes":
+ [
+ {
+ "itemId": 1,
+ "name": "create",
+ "label": "Create"
+ },
+
+ {
+ "itemId": 2,
+ "name": "read",
+ "label": "Read"
+ },
+
+ {
+ "itemId": 3,
+ "name": "update",
+ "label": "Update"
+ },
+
+ {
+ "itemId": 4,
+ "name": "delete",
+ "label": "Delete"
+ }
+ ],
+
+ "configs":
+ [
+ {
+ "itemId": 1,
+ "name": "schema.registry.url",
+ "type": "string",
+ "mandatory": true,
+ "defaultValue": "",
+ "validationRegEx":"",
+ "validationMessage": "",
+ "uiHint":"",
+ "label": "Schema Registry URL"
+ },
+
+ {
+ "itemId": 2,
+ "name": "schema-registry.authentication",
+ "type": "enum",
+ "subType": "authType",
+ "mandatory": true,
+ "validationRegEx":"",
+ "validationMessage": "",
+ "uiHint":"",
+ "label": "Authentication Type",
+ "defaultValue": "KERBEROS"
+ },
+
+ {
+ "itemId": 3,
+ "name": "commonNameForCertificate",
+ "type": "string",
+ "mandatory": false,
+ "validationRegEx":"",
+ "validationMessage": "",
+ "uiHint":"",
+ "label": "Ranger Plugin SSL CName"
+ }
+
+ ],
+
+ "enums":
+ [
+ {
+ "itemId": 1,
+ "name": "authType",
+ "elements":
+ [
+ {
+ "itemId": 1,
+ "name": "NONE",
+ "label": "None"
+ },
+ {
+ "itemId": 2,
+ "name": "KERBEROS",
+ "label": "Kerberos"
+ }
+ ],
+
+ "defaultIndex": 0
+ }
+ ],
+
+ "contextEnrichers":
+ [
+
+ ],
+
+ "policyConditions":
+ [
+
+ {
+ "itemId":4,
+ "name":"ip-range",
+ "evaluator":"org.apache.ranger.plugin.conditionevaluator.RangerIpMatcher",
+ "evaluatorOptions":{
+
+ },
+ "validationRegEx":"",
+ "validationMessage":"",
+ "uiHint":"",
+ "label":"IP Address Range",
+ "description":"IP Address Range"
+ }
+
+ ]
+}
diff --git a/distro/pom.xml b/distro/pom.xml
index 49faefc..6c4fdae 100644
--- a/distro/pom.xml
+++ b/distro/pom.xml
@@ -73,6 +73,7 @@
<descriptor>src/main/assembly/plugin-sqoop.xml</descriptor>
<descriptor>src/main/assembly/plugin-kylin.xml</descriptor>
<descriptor>src/main/assembly/plugin-elasticsearch.xml</descriptor>
+ <descriptor>src/main/assembly/plugin-schema-registry.xml</descriptor>
<descriptor>src/main/assembly/plugin-presto.xml</descriptor>
</descriptors>
</configuration>
@@ -553,6 +554,35 @@
</build>
</profile>
<profile>
+ <id>ranger-schema-registry-plugin</id>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>${assembly.plugin.version}</version>
+ <configuration>
+ <finalName>ranger-${project.version}</finalName>
+ <outputDirectory>../target</outputDirectory>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <phase>package</phase>
+ <configuration>
+ <skipAssembly>false</skipAssembly>
+ <descriptors>
+ <descriptor>src/main/assembly/plugin-schema-registry.xml</descriptor>
+ </descriptors>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
<id>linux</id>
<activation>
<os>
@@ -598,6 +628,7 @@
<descriptor>src/main/assembly/plugin-sqoop.xml</descriptor>
<descriptor>src/main/assembly/plugin-kylin.xml</descriptor>
<descriptor>src/main/assembly/plugin-elasticsearch.xml</descriptor>
+ <descriptor>src/main/assembly/plugin-schema-registry.xml</descriptor>
<descriptor>src/main/assembly/plugin-presto.xml</descriptor>
</descriptors>
</configuration>
diff --git a/distro/src/main/assembly/plugin-schema-registry.xml b/distro/src/main/assembly/plugin-schema-registry.xml
new file mode 100644
index 0000000..03f01ae
--- /dev/null
+++ b/distro/src/main/assembly/plugin-schema-registry.xml
@@ -0,0 +1,39 @@
+<!--
+ Copyright 2016-2019 Cloudera, Inc.
+
+ Licensed 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.
+-->
+
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
+ <id>schema-registry-plugin</id>
+ <formats>
+ <format>jar</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+
+ <!-- put deps in the lib folder -->
+ <dependencySets>
+ <dependencySet>
+ <useProjectArtifact>true</useProjectArtifact>
+ <outputDirectory>/</outputDirectory>
+ <scope>runtime</scope>
+ <unpack>true</unpack>
+ <excludes>
+ <exclude>
+ org.slf4j:*
+ </exclude>
+ </excludes>
+ </dependencySet>
+ </dependencySets>
+</assembly>
diff --git a/plugin-schema-registry/.gitignore b/plugin-schema-registry/.gitignore
new file mode 100644
index 0000000..02f68bb
--- /dev/null
+++ b/plugin-schema-registry/.gitignore
@@ -0,0 +1,3 @@
+/target/
+/bin/
+.settings/
diff --git a/plugin-schema-registry/pom.xml b/plugin-schema-registry/pom.xml
new file mode 100644
index 0000000..6bd2d97
--- /dev/null
+++ b/plugin-schema-registry/pom.xml
@@ -0,0 +1,245 @@
+<?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-schema-registry-plugin</artifactId>
+ <name>SchemaRegistry Security Plugin</name>
+ <description>SchemaRegistry Security Plugin</description>
+ <packaging>jar</packaging>
+
+ <parent>
+ <groupId>org.apache.ranger</groupId>
+ <artifactId>ranger</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+
+ <properties>
+ <hadoop.version>3.1.1</hadoop.version>
+ <kafka.version>2.1.0</kafka.version>
+ <kafkaArtifact>kafka_2.11</kafkaArtifact>
+ <jersey.version>2.22.1</jersey.version>
+ <junit.version>4.5</junit.version>
+ <schema.registry.version>0.8.1</schema.registry.version>
+ <jettison.version>1.1</jettison.version>
+ <servlet-api.version>3.0.1</servlet-api.version>
+ </properties>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.hadoop</groupId>
+ <artifactId>hadoop-hdfs</artifactId>
+ <version>${hadoop.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.sun.jersey</groupId>
+ <artifactId>jersey-core</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.sun.jersey</groupId>
+ <artifactId>jersey-json</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.hadoop</groupId>
+ <artifactId>hadoop-client</artifactId>
+ <version>${hadoop.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.sun.jersey</groupId>
+ <artifactId>jersey-core</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.sun.jersey</groupId>
+ <artifactId>jersey-client</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.apache.hadoop</groupId>
+ <artifactId>hadoop-yarn-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.apache.hadoop</groupId>
+ <artifactId>hadoop-yarn-common</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.apache.hadoop</groupId>
+ <artifactId>hadoop-mapreduce-client</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.apache.hadoop</groupId>
+ <artifactId>hadoop-mapreduce-client-app</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.apache.hadoop</groupId>
+ <artifactId>hadoop-mapreduce-client-core</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.apache.hadoop</groupId>
+ <artifactId>hadoop-mapreduce-client-jobclient</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.kafka</groupId>
+ <artifactId>${kafkaArtifact}</artifactId>
+ <version>${kafka.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.apache.zookeeper</groupId>
+ <artifactId>zookeeper</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.core</groupId>
+ <artifactId>jersey-client</artifactId>
+ <version>${jersey.version}</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.hortonworks.registries</groupId>
+ <artifactId>common-auth</artifactId>
+ <version>${schema.registry.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.hortonworks.registries</groupId>
+ <artifactId>schema-registry-client</artifactId>
+ <version>${schema.registry.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>log4j</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.ranger</groupId>
+ <artifactId>ranger-plugins-common</artifactId>
+ <version>${project.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>javax.servlet</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.sun.jersey</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>log4j</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>javax.servlet.jsp</groupId>
+ <artifactId>jsp-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.glassfish.jersey.*</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jettison</groupId>
+ <artifactId>jettison</artifactId>
+ <version>${jettison.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>${junit.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.hortonworks.registries</groupId>
+ <artifactId>schema-registry-webservice</artifactId>
+ <version>${schema.registry.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <version>${servlet-api.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>**/src/test/resources/**/*.yaml</exclude>
+ <exclude>**/src/test/resources/**/*.avcs</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/plugin-schema-registry/src/main/java/org/apache/ranger/services/schema/registry/RangerServiceSchemaRegistry.java b/plugin-schema-registry/src/main/java/org/apache/ranger/services/schema/registry/RangerServiceSchemaRegistry.java
new file mode 100644
index 0000000..8306b51
--- /dev/null
+++ b/plugin-schema-registry/src/main/java/org/apache/ranger/services/schema/registry/RangerServiceSchemaRegistry.java
@@ -0,0 +1,88 @@
+/*
+ * 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.schema.registry;
+
+import org.apache.ranger.services.schema.registry.client.AutocompletionAgent;
+import org.apache.ranger.services.schema.registry.client.SchemaRegistryResourceMgr;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.plugin.model.RangerService;
+import org.apache.ranger.plugin.model.RangerServiceDef;
+import org.apache.ranger.plugin.service.RangerBaseService;
+import org.apache.ranger.plugin.service.ResourceLookupContext;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class RangerServiceSchemaRegistry extends RangerBaseService {
+
+ private static final Log LOG = LogFactory.getLog(RangerServiceSchemaRegistry.class);
+
+
+ @Override
+ public void init(RangerServiceDef serviceDef, RangerService service) {
+ super.init(serviceDef, service);
+ }
+
+ @Override
+ public HashMap<String, Object> validateConfig() {
+ HashMap<String, Object> ret = new HashMap<String, Object>();
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==> RangerServiceSchemaRegistry.validateConfig(" + serviceName + ")");
+ }
+
+ if (configs != null) {
+ try {
+ AutocompletionAgent autocompletionAgent = new AutocompletionAgent(serviceName, configs);
+ ret = autocompletionAgent.connectionTest();
+ } catch (Exception e) {
+ LOG.error("<== RangerServiceSchemaRegistry.validateConfig Error:" + e);
+ throw e;
+ }
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<== RangerServiceSchemaRegistry.validateConfig(" + serviceName + "): ret=" + ret);
+ }
+
+ return ret;
+ }
+
+ @Override
+ public List<String> lookupResource(ResourceLookupContext context) throws Exception {
+ List<String> ret = new ArrayList<String>();
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==> RangerServiceSchemaRegistry.lookupResource(" + serviceName + ")");
+ }
+
+ if (configs != null) {
+ AutocompletionAgent autocompletionAgent = new AutocompletionAgent(serviceName, configs);
+ ret = SchemaRegistryResourceMgr.getSchemaRegistryResources(serviceName, configs, context, autocompletionAgent);
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<== RangerServiceSchemaRegistry.lookupResource(" + serviceName + "): ret=" + ret);
+ }
+
+ return ret;
+ }
+
+}
diff --git a/plugin-schema-registry/src/main/java/org/apache/ranger/services/schema/registry/client/AutocompletionAgent.java b/plugin-schema-registry/src/main/java/org/apache/ranger/services/schema/registry/client/AutocompletionAgent.java
new file mode 100644
index 0000000..3bb107e
--- /dev/null
+++ b/plugin-schema-registry/src/main/java/org/apache/ranger/services/schema/registry/client/AutocompletionAgent.java
@@ -0,0 +1,144 @@
+/*
+ * 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.schema.registry.client;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.plugin.client.BaseClient;
+import org.apache.ranger.services.schema.registry.client.connection.DefaultSchemaRegistryClient;
+import org.apache.ranger.services.schema.registry.client.connection.ISchemaRegistryClient;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * The class that is used to get needed information for auto completion feature.
+ */
+public class AutocompletionAgent {
+ private static final Log LOG = LogFactory.getLog(AutocompletionAgent.class);
+
+ private ISchemaRegistryClient client;
+ private String serviceName;
+
+ private static final String errMessage = "You can still save the repository and start creating "
+ + "policies, but you would not be able to use autocomplete for "
+ + "resource names. Check server logs for more info.";
+
+ private static final String successMsg = "ConnectionTest Successful";
+
+
+ public AutocompletionAgent(String serviceName, Map<String, String> configs) {
+ this(serviceName, new DefaultSchemaRegistryClient(configs));
+ }
+
+ public AutocompletionAgent(String serviceName, ISchemaRegistryClient client) {
+ this.serviceName = serviceName;
+ this.client = client;
+ }
+
+ public HashMap<String, Object> connectionTest() {
+ HashMap<String, Object> responseData = new HashMap<String, Object>();
+
+ try {
+ client.checkConnection();
+ // If it doesn't throw exception, then assume the instance is
+ // reachable
+ BaseClient.generateResponseDataMap(true, successMsg,
+ successMsg, null, null, responseData);
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("ConnectionTest Successful.");
+ }
+ } catch (Exception e) {
+ LOG.error("Error connecting to SchemaRegistry. schemaRegistryClient=" + this, e);
+ BaseClient.generateResponseDataMap(false, errMessage,
+ errMessage, null, null, responseData);
+ }
+
+ return responseData;
+ }
+
+ public List<String> getSchemaGroupList(String lookupGroupName, List<String> groupList) {
+ List<String> res = groupList;
+ Collection<String> schemaGroups = client.getSchemaGroups();
+ schemaGroups.forEach(gName -> {
+ if (!res.contains(gName) && gName.contains(lookupGroupName)) {
+ res.add(gName);
+ }
+ });
+
+ return res;
+ }
+
+ public List<String> getSchemaMetadataList(String lookupSchemaMetadataName,
+ List<String> schemaGroupList,
+ List<String> schemaMetadataList) {
+ List<String> res = schemaMetadataList;
+
+ Collection<String> schemas = client.getSchemaNames(schemaGroupList);
+ schemas.forEach(sName -> {
+ if (!res.contains(sName) && sName.contains(lookupSchemaMetadataName)) {
+ res.add(sName);
+ }
+ });
+
+ return res;
+ }
+
+ public List<String> getBranchList(String lookupBranchName,
+ List<String> groupList,
+ List<String> schemaList,
+ List<String> branchList) {
+ List<String> res = branchList;
+ List<String> expandedSchemaList = schemaList.stream().flatMap(
+ schemaName -> expandSchemaMetadataNameRegex(groupList, schemaName).stream())
+ .collect(Collectors.toList());
+ expandedSchemaList.forEach(schemaMetadataName -> {
+ Collection<String> branches = client.getSchemaBranches(schemaMetadataName);
+ branches.forEach(bName -> {
+ if (!res.contains(bName) && bName.contains(lookupBranchName)) {
+ res.add(bName);
+ }
+ });
+ });
+
+ return res;
+ }
+
+ List<String> expandSchemaMetadataNameRegex(List<String> schemaGroupList, String lookupSchemaMetadataName) {
+ List<String> res = new ArrayList<>();
+
+ Collection<String> schemas = client.getSchemaNames(schemaGroupList);
+ schemas.forEach(sName -> {
+ if (sName.matches(lookupSchemaMetadataName)) {
+ res.add(sName);
+ }
+ });
+
+ return res;
+ }
+
+ @Override
+ public String toString() {
+ return "AutocompletionAgent [serviceName=" + serviceName + "]";
+ }
+
+}
diff --git a/plugin-schema-registry/src/main/java/org/apache/ranger/services/schema/registry/client/SchemaRegistryResourceMgr.java b/plugin-schema-registry/src/main/java/org/apache/ranger/services/schema/registry/client/SchemaRegistryResourceMgr.java
new file mode 100644
index 0000000..3cc1199
--- /dev/null
+++ b/plugin-schema-registry/src/main/java/org/apache/ranger/services/schema/registry/client/SchemaRegistryResourceMgr.java
@@ -0,0 +1,134 @@
+/*
+ * 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.schema.registry.client;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.plugin.service.ResourceLookupContext;
+import org.apache.ranger.plugin.util.TimedEventUtil;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+
+public class SchemaRegistryResourceMgr {
+
+ private static final Log LOG = LogFactory.getLog(SchemaRegistryResourceMgr.class);
+
+ private static final String REGISTRY_SERVICE = "registry-service";
+ private static final String SERDE = "serde";
+ private static final String SCHEMA_GROUP = "schema-group";
+ private static final String SCHEMA_METADATA = "schema-metadata";
+ private static final String SCHEMA_BRANCH = "schema-branch";
+ private static final String SCHEMA_VERSION = "schema-version";
+
+ private static final List<String> asteriskList = Collections.singletonList("*");
+
+ private static final int LOOKUP_TIMEOUT_SEC = 5;
+
+
+ public static List<String> getSchemaRegistryResources(String serviceName,
+ Map<String, String> configs,
+ ResourceLookupContext context,
+ AutocompletionAgent registryClient) throws Exception {
+
+ String userInput = context.getUserInput();
+ String resource = context.getResourceName();
+ Map<String, List<String>> resourceMap = context.getResources();
+ List<String> resultList = null;
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==> SchemaRegistryResourceMgr.getSchemaRegistryResources() UserInput: \"" + userInput + "\" resource : " + resource + " resourceMap: " + resourceMap);
+ }
+
+ if (userInput != null
+ && !userInput.isEmpty()
+ && serviceName != null
+ && resource != null
+ && resourceMap != null
+ && !resourceMap.isEmpty()) {
+ if (registryClient != null) {
+ Callable<List<String>> callableObj = null;
+ try {
+ switch (resource.trim().toLowerCase()) {
+ case SCHEMA_GROUP: {
+ List<String> schemaGroupList = resourceMap.get(SCHEMA_GROUP);
+ // get the SchemaGroupList for given Input
+ final String finalSchemaGroupName = userInput;
+ callableObj = ()
+ -> registryClient.getSchemaGroupList(finalSchemaGroupName, schemaGroupList);
+ break;
+ }
+ case SCHEMA_METADATA: {
+ List<String> schemaGroupList = resourceMap.get(SCHEMA_GROUP);
+ List<String> schemaMeatadataList = resourceMap.get(SCHEMA_METADATA);
+ // get the SchemaMetadataList for the given Input
+ final String finalSchemaName = userInput;
+ callableObj = ()
+ -> registryClient.getSchemaMetadataList(finalSchemaName,
+ schemaGroupList,
+ schemaMeatadataList);
+ break;
+ }
+ case SCHEMA_BRANCH: {
+ List<String> schemaGroupList = resourceMap.get(SCHEMA_GROUP);
+ List<String> schemaMeatadataList = resourceMap.get(SCHEMA_METADATA);
+ List<String> branchList = resourceMap.get(SCHEMA_BRANCH);
+ // get the SchemaBranchList for given Input
+ final String finalBranchName = userInput;
+ callableObj = ()
+ -> registryClient.getBranchList(finalBranchName,
+ schemaGroupList,
+ schemaMeatadataList,
+ branchList);
+ break;
+ }
+ case SCHEMA_VERSION: case SERDE: case REGISTRY_SERVICE: {
+ return asteriskList;
+ }
+ default:
+ break;
+ }
+ } catch (Exception e) {
+ LOG.error("Unable to get Schema Registry resources.", e);
+ throw e;
+ }
+ if (callableObj != null) {
+ synchronized (registryClient) {
+ resultList = TimedEventUtil.timedTask(callableObj, LOOKUP_TIMEOUT_SEC,
+ TimeUnit.SECONDS);
+ }
+ } else {
+ LOG.error("Could not initiate at timedTask");
+ }
+ }
+ }
+
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("<== SchemaRegistryResourceMgr.getSchemaRegistryResources() UserInput: "
+ + userInput
+ + " configs: " + configs
+ + "Result :" + resultList );
+
+ }
+
+ return resultList;
+ }
+}
diff --git a/plugin-schema-registry/src/main/java/org/apache/ranger/services/schema/registry/client/connection/DefaultSchemaRegistryClient.java b/plugin-schema-registry/src/main/java/org/apache/ranger/services/schema/registry/client/connection/DefaultSchemaRegistryClient.java
new file mode 100644
index 0000000..3a46436
--- /dev/null
+++ b/plugin-schema-registry/src/main/java/org/apache/ranger/services/schema/registry/client/connection/DefaultSchemaRegistryClient.java
@@ -0,0 +1,294 @@
+/*
+ * 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.schema.registry.client.connection;
+
+import com.hortonworks.registries.auth.Login;
+import com.hortonworks.registries.schemaregistry.client.LoadBalancedFailoverUrlSelector;
+import com.hortonworks.registries.schemaregistry.client.UrlSelector;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.services.schema.registry.client.connection.util.SecurityUtils;
+import org.codehaus.jettison.json.JSONArray;
+import org.codehaus.jettison.json.JSONObject;
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.client.ClientProperties;
+import org.glassfish.jersey.client.JerseyClientBuilder;
+
+import javax.net.ssl.SSLContext;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import com.hortonworks.registries.schemaregistry.client.SchemaRegistryClient.Configuration;
+
+import static com.hortonworks.registries.schemaregistry.client.SchemaRegistryClient.Configuration.DEFAULT_CONNECTION_TIMEOUT;
+import static com.hortonworks.registries.schemaregistry.client.SchemaRegistryClient.Configuration.DEFAULT_READ_TIMEOUT;
+
+
+public class DefaultSchemaRegistryClient implements ISchemaRegistryClient {
+
+ private static final Log LOG = LogFactory.getLog(DefaultSchemaRegistryClient.class);
+
+ private static final String SCHEMA_REGISTRY_PATH = "/api/v1/schemaregistry";
+ private static final String SCHEMAS_PATH = SCHEMA_REGISTRY_PATH + "/schemas/";
+ private static final String SCHEMA_REGISTRY_VERSION_PATH = SCHEMA_REGISTRY_PATH + "/version";
+ private static final String SSL_ALGORITHM = "TLS";
+ private final javax.ws.rs.client.Client client;
+ private final Login login;
+ private final UrlSelector urlSelector;
+ private final Map<String, SchemaRegistryTargets> urlWithTargets;
+ private final Configuration configuration;
+
+ public DefaultSchemaRegistryClient(Map<String, ?> conf) {
+ configuration = new Configuration(conf);
+ login = SecurityUtils.initializeSecurityContext(conf);
+ ClientConfig config = createClientConfig(conf);
+ final boolean SSLEnabled = SecurityUtils.isHttpsConnection(conf);
+ ClientBuilder clientBuilder = JerseyClientBuilder.newBuilder()
+ .withConfig(config)
+ .property(ClientProperties.FOLLOW_REDIRECTS, Boolean.TRUE);
+ if (SSLEnabled) {
+ SSLContext ctx;
+ try {
+ ctx = SecurityUtils.createSSLContext(conf, SSL_ALGORITHM);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ clientBuilder.sslContext(ctx);
+ }
+ client = clientBuilder.build();
+
+ // get list of urls and create given or default UrlSelector.
+ urlSelector = createUrlSelector();
+ urlWithTargets = new ConcurrentHashMap<>();
+ }
+
+ private ClientConfig createClientConfig(Map<String, ?> conf) {
+ ClientConfig config = new ClientConfig();
+ config.property(ClientProperties.CONNECT_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT);
+ config.property(ClientProperties.READ_TIMEOUT, DEFAULT_READ_TIMEOUT);
+ config.property(ClientProperties.FOLLOW_REDIRECTS, true);
+ for (Map.Entry<String, ?> entry : conf.entrySet()) {
+ config.property(entry.getKey(), entry.getValue());
+ }
+ return config;
+ }
+
+ private UrlSelector createUrlSelector() {
+ UrlSelector urlSelector = null;
+ String rootCatalogURL = configuration.getValue(Configuration.SCHEMA_REGISTRY_URL.name());
+ String urlSelectorClass = configuration.getValue(Configuration.URL_SELECTOR_CLASS.name());
+ if (urlSelectorClass == null) {
+ urlSelector = new LoadBalancedFailoverUrlSelector(rootCatalogURL);
+ } else {
+ try {
+ urlSelector = (UrlSelector) Class.forName(urlSelectorClass)
+ .getConstructor(String.class)
+ .newInstance(rootCatalogURL);
+ } catch (InstantiationException | IllegalAccessException | ClassNotFoundException | NoSuchMethodException
+ | InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ urlSelector.init(configuration.getConfig());
+
+ return urlSelector;
+ }
+
+ private static class SchemaRegistryTargets {
+ private final WebTarget schemaRegistryVersion;
+ private final WebTarget schemasTarget;
+
+ SchemaRegistryTargets(WebTarget rootResource) {
+ schemaRegistryVersion = rootResource.path(SCHEMA_REGISTRY_VERSION_PATH);
+ schemasTarget = rootResource.path(SCHEMAS_PATH);
+ }
+ }
+
+ private SchemaRegistryTargets currentSchemaRegistryTargets() {
+ String url = urlSelector.select();
+ urlWithTargets.computeIfAbsent(url, s -> new SchemaRegistryTargets(client.target(s)));
+ return urlWithTargets.get(url);
+ }
+
+ private static String encode(String schemaName) {
+ try {
+ return URLEncoder.encode(schemaName, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public List<String> getSchemaGroups() {
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("==> DefaultSchemaRegistryClient.getSchemaGroups()");
+ }
+
+ ArrayList<String> res = new ArrayList<>();
+ WebTarget webResource = currentSchemaRegistryTargets().schemasTarget;
+ try {
+ Response response = login.doAction(() ->
+ webResource.request(MediaType.APPLICATION_JSON_TYPE).get(Response.class));
+
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("DefaultSchemaRegistryClient.getSchemaGroups(): response statusCode = " + response.getStatus());
+ }
+
+ JSONArray mDataList = new JSONObject(response.readEntity(String.class)).getJSONArray("entities");
+ int len = mDataList.length();
+ for(int i = 0; i < len; i++) {
+ JSONObject entity = mDataList.getJSONObject(i);
+ JSONObject schemaMetadata = (JSONObject)entity.get("schemaMetadata");
+ String group = (String) schemaMetadata.get("schemaGroup");
+ res.add(group);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("<== DefaultSchemaRegistryClient.getSchemaGroups(): "
+ + res.size()
+ + " schemaGroups found");
+ }
+
+ return res;
+ }
+
+ @Override
+ public List<String> getSchemaNames(List<String> schemaGroups) {
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("==> DefaultSchemaRegistryClient.getSchemaNames( " + schemaGroups + " )");
+ }
+
+ ArrayList<String> res = new ArrayList<>();
+ WebTarget webTarget = currentSchemaRegistryTargets().schemasTarget;
+ try {
+ Response response = login.doAction(() ->
+ webTarget.request(MediaType.APPLICATION_JSON_TYPE).get(Response.class));
+
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("DefaultSchemaRegistryClient.getSchemaNames(): response statusCode = " + response.getStatus());
+ }
+
+ JSONArray mDataList = new JSONObject(response.readEntity(String.class)).getJSONArray("entities");
+ int len = mDataList.length();
+ for(int i = 0; i < len; i++) {
+ JSONObject entity = mDataList.getJSONObject(i);
+ JSONObject schemaMetadata = (JSONObject)entity.get("schemaMetadata");
+ String group = (String) schemaMetadata.get("schemaGroup");
+ for(String schemaGroup: schemaGroups) {
+ if(group.matches(schemaGroup)) {
+ String name = (String) schemaMetadata.get("name");
+ res.add(name);
+ }
+ }
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("<== DefaultSchemaRegistryClient.getSchemaNames( " + schemaGroups + " ): "
+ + res.size()
+ + " schemaNames found");
+ }
+
+ return res;
+ }
+
+ @Override
+ public List<String> getSchemaBranches(String schemaMetadataName) {
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("==> DefaultSchemaRegistryClient.getSchemaBranches( " + schemaMetadataName + " )");
+ }
+
+ ArrayList<String> res = new ArrayList<>();
+ WebTarget target = currentSchemaRegistryTargets().schemasTarget.path(encode(schemaMetadataName) + "/branches");
+ try {
+ Response response = login.doAction(() ->
+ target.request(MediaType.APPLICATION_JSON_TYPE).get(Response.class));
+
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("DefaultSchemaRegistryClient.getSchemaBranches(): response statusCode = " + response.getStatus());
+ }
+
+ JSONArray mDataList = new JSONObject(response.readEntity(String.class)).getJSONArray("entities");
+ int len = mDataList.length();
+ for(int i = 0; i < len; i++) {
+ JSONObject entity = mDataList.getJSONObject(i);
+ JSONObject branchInfo = entity;
+ String smName = (String) branchInfo.get("schemaMetadataName");
+ if (smName.matches(schemaMetadataName)) {
+ String bName = (String) branchInfo.get("name");
+ res.add(bName);
+ }
+
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("<== DefaultSchemaRegistryClient.getSchemaBranches( " + schemaMetadataName + " ): "
+ + res.size()
+ + " branches found.");
+ }
+
+ return res;
+ }
+
+ @Override
+ public void checkConnection() throws Exception {
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("==> DefaultSchemaRegistryClient.checkConnection(): trying to connect to the SR server... ");
+ }
+
+ WebTarget webTarget = currentSchemaRegistryTargets().schemaRegistryVersion;
+ Response responce = login.doAction(() ->
+ webTarget.request(MediaType.APPLICATION_JSON_TYPE).get(Response.class));
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("DefaultSchemaRegistryClient.checkConnection(): response statusCode = " + responce.getStatus());
+ }
+ if(responce.getStatus() != Response.Status.OK.getStatusCode()) {
+ LOG.error("DefaultSchemaRegistryClient.checkConnection(): Connection failed. Response StatusCode = "
+ + responce.getStatus());
+ throw new Exception("Connection failed. StatusCode = " + responce.getStatus());
+ }
+
+ String respStr = responce.readEntity(String.class);
+ if (!(respStr.contains("version") && respStr.contains("revision"))) {
+ LOG.error("DefaultSchemaRegistryClient.checkConnection(): Connection failed. Bad response body.");
+ throw new Exception("Connection failed. Bad response body.");
+ }
+
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("<== DefaultSchemaRegistryClient.checkConnection(): connection test successfull ");
+ }
+ }
+
+}
diff --git a/plugin-schema-registry/src/main/java/org/apache/ranger/services/schema/registry/client/connection/ISchemaRegistryClient.java b/plugin-schema-registry/src/main/java/org/apache/ranger/services/schema/registry/client/connection/ISchemaRegistryClient.java
new file mode 100644
index 0000000..98009ce
--- /dev/null
+++ b/plugin-schema-registry/src/main/java/org/apache/ranger/services/schema/registry/client/connection/ISchemaRegistryClient.java
@@ -0,0 +1,28 @@
+/*
+ * 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.schema.registry.client.connection;
+
+import java.util.List;
+
+public interface ISchemaRegistryClient {
+ List<String> getSchemaGroups();
+ List<String> getSchemaNames(List<String> schemaGroup);
+ List<String> getSchemaBranches(String schemaMetadataName);
+ void checkConnection() throws Exception;
+}
+
diff --git a/plugin-schema-registry/src/main/java/org/apache/ranger/services/schema/registry/client/connection/util/SecurityUtils.java b/plugin-schema-registry/src/main/java/org/apache/ranger/services/schema/registry/client/connection/util/SecurityUtils.java
new file mode 100644
index 0000000..13eaf8e
--- /dev/null
+++ b/plugin-schema-registry/src/main/java/org/apache/ranger/services/schema/registry/client/connection/util/SecurityUtils.java
@@ -0,0 +1,228 @@
+/*
+ * 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.schema.registry.client.connection.util;
+
+import com.hortonworks.registries.auth.KerberosLogin;
+import com.hortonworks.registries.auth.Login;
+import com.hortonworks.registries.auth.NOOPLogin;
+import com.hortonworks.registries.auth.util.JaasConfiguration;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+import javax.security.auth.login.LoginException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import static com.hortonworks.registries.schemaregistry.client.SchemaRegistryClient.Configuration.SCHEMA_REGISTRY_URL;
+import static org.apache.ranger.plugin.client.HadoopConfigHolder.HADOOP_SECURITY_AUTHENTICATION_METHOD;
+import static org.apache.ranger.plugin.client.HadoopConfigHolder.RANGER_AUTH_TYPE;
+import static org.apache.ranger.plugin.client.HadoopConfigHolder.RANGER_LOOKUP_KEYTAB;
+import static org.apache.ranger.plugin.client.HadoopConfigHolder.RANGER_LOOKUP_PRINCIPAL;
+
+public class SecurityUtils {
+
+ private static final Log LOG = LogFactory.getLog(SecurityUtils.class);
+ private static final long KERBEROS_SYNCHRONIZATION_TIMEOUT_MS = 180000;
+ private static final String REGISTY_CLIENT_JAAS_SECTION = "RegistryClient";
+
+ public static boolean isHttpsConnection(Map<String, ?> conf) {
+ String urls = conf.get(SCHEMA_REGISTRY_URL.name()).toString();
+ return urls.trim().startsWith("https://");
+ }
+
+ public static SSLContext createSSLContext(Map<String, ?> sslConfigurations, String sslAlgorithm) throws Exception {
+ SSLContext context = SSLContext.getInstance(sslAlgorithm);
+ KeyManager[] km = null;
+ String keyStorePath = (String)sslConfigurations.get("keyStorePath");
+ if (keyStorePath == null || keyStorePath.isEmpty()) {
+ keyStorePath = System.getProperty("javax.net.ssl.keyStore");
+ }
+ String keyStorePassword = (String)sslConfigurations.get("keyStorePassword");
+ if (keyStorePassword == null || keyStorePath.isEmpty()) {
+ keyStorePassword = Optional.ofNullable(System.getProperty("javax.net.ssl.keyStorePassword")).orElse("");
+ }
+ String keyStoreType = (String)sslConfigurations.get("keyStoreType");
+ if (keyStoreType == null || keyStoreType.isEmpty()) {
+ keyStoreType = System.getProperty("javax.net.ssl.keyStoreType");
+ }
+
+ String trustStorePath = (String)sslConfigurations.get("trustStorePath");
+ if (trustStorePath == null || trustStorePath.isEmpty()) {
+ trustStorePath = System.getProperty("javax.net.ssl.trustStore");
+ }
+ String trustStorePassword = (String)sslConfigurations.get("trustStorePassword");
+ if (trustStorePassword == null || trustStorePassword.isEmpty()) {
+ trustStorePassword = Optional.ofNullable(System.getProperty("javax.net.ssl.trustStorePassword")).orElse("");
+ }
+ String trustStoreType = (String)sslConfigurations.get("trustStoreType");
+ if (trustStoreType == null || trustStoreType.isEmpty()) {
+ trustStoreType = System.getProperty("javax.net.ssl.trustStoreType");
+ }
+
+ Object obj = sslConfigurations.get("serverCertValidation");
+ boolean serverCertValidation = (obj == null) || Boolean.parseBoolean(obj.toString());
+
+ if (keyStorePath != null) {
+ KeyStore ks = KeyStore.getInstance(keyStoreType != null ?
+ keyStoreType : KeyStore.getDefaultType());
+
+ InputStream in = getFileInputStream(keyStorePath);
+
+ try {
+ ks.load(in, keyStorePassword.toCharArray());
+ } finally {
+ if (in != null) {
+ in.close();
+ }
+ }
+
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(ks, keyStorePassword.toCharArray());
+ km = kmf.getKeyManagers();
+ }
+ TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ TrustManager[] tm = null;
+ if (serverCertValidation) {
+ if (trustStorePath != null) {
+ KeyStore trustStore = KeyStore.getInstance(trustStoreType != null ?
+ trustStoreType : KeyStore.getDefaultType());
+ InputStream in = getFileInputStream(trustStorePath);
+ try {
+ trustStore.load(in, trustStorePassword.toCharArray());
+
+ trustManagerFactory.init(trustStore);
+
+ tm = trustManagerFactory.getTrustManagers();
+
+ } finally {
+ if (in != null) {
+ in.close();
+ }
+ }
+ }
+ } else {
+ TrustManager ignoreValidationTM = new X509TrustManager() {
+ public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ // Ignore Server Certificate Validation
+ }
+
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[0];
+ }
+
+ public void checkServerTrusted(X509Certificate[] chain,
+ String authType)
+ throws CertificateException {
+ // Ignore Server Certificate Validation
+ }
+ };
+
+ tm = new TrustManager[] {ignoreValidationTM};
+ }
+ SecureRandom random = new SecureRandom();
+ context.init(km, tm, random);
+
+ return context;
+ }
+
+ static private InputStream getFileInputStream(String path) throws FileNotFoundException {
+ InputStream ret;
+ File f = new File(path);
+ if (f.exists()) {
+ ret = new FileInputStream(f);
+ } else {
+ ret = SecurityUtils.class.getResourceAsStream(path);
+
+ if (ret == null) {
+ if (! path.startsWith("/")) {
+ ret = SecurityUtils.class.getResourceAsStream("/" + path);
+ }
+ }
+
+ if (ret == null) {
+ ret = ClassLoader.getSystemClassLoader().getResourceAsStream(path);
+ if (ret == null) {
+ if (! path.startsWith("/")) {
+ ret = ClassLoader.getSystemResourceAsStream("/" + path);
+ }
+ }
+ }
+ }
+ return ret;
+ }
+
+ static String getJaasConfigForClientPrincipal(Map<String, ?> conf) {
+ String keytabFile = (String)conf.get(RANGER_LOOKUP_KEYTAB);
+ String principal = (String)conf.get(RANGER_LOOKUP_PRINCIPAL);
+
+ if(keytabFile == null || keytabFile.isEmpty()
+ || principal == null || principal.isEmpty()) {
+ return null;
+ }
+
+ return "com.sun.security.auth.module.Krb5LoginModule required useTicketCache=false principal=\""
+ + principal
+ + "\" useKeyTab=true keyTab=\""
+ + keytabFile
+ + "\";";
+ }
+
+ public static Login initializeSecurityContext(Map<String, ?> conf) {
+ String saslJaasConfig = getJaasConfigForClientPrincipal(conf);
+ boolean kerberosOn = isKerberosEnabled(conf);
+ if (kerberosOn && saslJaasConfig != null) {
+ KerberosLogin kerberosLogin = new KerberosLogin(KERBEROS_SYNCHRONIZATION_TIMEOUT_MS);
+ try {
+ kerberosLogin.configure(new HashMap<>(), REGISTY_CLIENT_JAAS_SECTION, new JaasConfiguration(REGISTY_CLIENT_JAAS_SECTION, saslJaasConfig));
+ kerberosLogin.login();
+ return kerberosLogin;
+ } catch (LoginException e) {
+ LOG.error("Failed to initialize the dynamic JAAS config: " + saslJaasConfig + ". Attempting static JAAS config.");
+ } catch (Exception e) {
+ LOG.error("Failed to parse the dynamic JAAS config. Attempting static JAAS config.", e);
+ }
+ }
+
+ return new NOOPLogin();
+ }
+
+ static boolean isKerberosEnabled(Map<String, ?> conf) {
+ String rangerAuthType = (String) conf.get(RANGER_AUTH_TYPE);
+ String pluginAuthType = (String) conf.get("schema-registry.authentication");
+
+ return rangerAuthType != null
+ && pluginAuthType != null
+ && rangerAuthType.equals(HADOOP_SECURITY_AUTHENTICATION_METHOD)
+ && pluginAuthType.equalsIgnoreCase(HADOOP_SECURITY_AUTHENTICATION_METHOD);
+ }
+}
diff --git a/plugin-schema-registry/src/test/java/org/apache/ranger/services/schema/registry/client/AutocompletionAgentTest.java b/plugin-schema-registry/src/test/java/org/apache/ranger/services/schema/registry/client/AutocompletionAgentTest.java
new file mode 100644
index 0000000..beafae3
--- /dev/null
+++ b/plugin-schema-registry/src/test/java/org/apache/ranger/services/schema/registry/client/AutocompletionAgentTest.java
@@ -0,0 +1,194 @@
+/*
+ * 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.schema.registry.client;
+
+import org.apache.ranger.services.schema.registry.client.connection.ISchemaRegistryClient;
+import org.apache.ranger.services.schema.registry.client.util.DefaultSchemaRegistryClientForTesting;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+
+
+public class AutocompletionAgentTest {
+
+
+ @Test
+ public void connectionTest() {
+ ISchemaRegistryClient client = new DefaultSchemaRegistryClientForTesting();
+
+ AutocompletionAgent autocompletionAgent =
+ new AutocompletionAgent("schema-registry", client);
+
+ HashMap<String, Object> res = autocompletionAgent.connectionTest();
+ assertEquals(res.get("connectivityStatus"), true);
+ assertEquals(res.get("message"), "ConnectionTest Successful");
+ assertEquals(res.get("description"), "ConnectionTest Successful");
+ assertNull(res.get("objectId"));
+ assertNull(res.get("fieldName"));
+
+
+ client = new DefaultSchemaRegistryClientForTesting() {
+ public void checkConnection() throws Exception {
+ throw new Exception("Cannot connect to the SR server");
+ }
+ };
+ autocompletionAgent =
+ new AutocompletionAgent("schema-registry", client);
+
+ res = autocompletionAgent.connectionTest();
+ String errMessage = "You can still save the repository and start creating "
+ + "policies, but you would not be able to use autocomplete for "
+ + "resource names. Check server logs for more info.";
+ assertEquals(res.get("connectivityStatus"), false);
+ assertThat(res.get("message"), is(errMessage));
+ assertThat(res.get("description"), is(errMessage));
+ assertNull(res.get("objectId"));
+ assertNull(res.get("fieldName"));
+
+ }
+
+ @Test
+ public void getSchemaGroupList() {
+ ISchemaRegistryClient client = new DefaultSchemaRegistryClientForTesting(){
+ public List<String> getSchemaGroups() {
+ List<String> groups = new ArrayList<>();
+ groups.add("testGroup");
+ return groups;
+ }
+ };
+
+ AutocompletionAgent autocompletionAgent =
+ new AutocompletionAgent("schema-registry", client);
+
+ // Empty initialGroups and the list of groups returned by ISchemaRegistryClient
+ // doesn't contain any groups that starts with 'tesSome'
+ List<String> initialGroups = new ArrayList<>();
+ List<String> res = autocompletionAgent.getSchemaGroupList("tesSome", initialGroups);
+ assertEquals(0, res.size());
+
+ // Empty initialGroups and the list of groups returned by ISchemaRegistryClient
+ // contains a group that starts with 'tes'
+ initialGroups = new ArrayList<>();
+ res = autocompletionAgent.getSchemaGroupList("tes", initialGroups);
+ List<String> expected = new ArrayList<>();
+ expected.add("testGroup");
+ assertEquals(1, res.size());
+ assertThat(res, is(expected));
+
+ // initialGroups contains one element, list of the groups returned by ISchemaRegistryClient
+ // contains the same values that are already present in initialGroups
+ initialGroups = new ArrayList<>();
+ initialGroups.add("testGroup");
+ res = autocompletionAgent.getSchemaGroupList("tes", initialGroups);
+ expected = new ArrayList<>();
+ expected.add("testGroup");
+ assertEquals(1, res.size());
+ assertThat(res, is(expected));
+
+ // initialGroups contains one element, list of the groups returned by ISchemaRegistryClient
+ // contains one element too, that is not equal to the element in initialGroups
+ initialGroups = new ArrayList<>();
+ initialGroups.add("testGroup2");
+ res = autocompletionAgent.getSchemaGroupList("tes", initialGroups);
+ expected = new ArrayList<>();
+ expected.add("testGroup2");
+ expected.add("testGroup");
+ assertEquals(2, res.size());
+ assertThat(res, is(expected));
+
+ }
+
+ @Test
+ public void getSchemaMetadataList() {
+ ISchemaRegistryClient client = new DefaultSchemaRegistryClientForTesting(){
+
+ public List<String> getSchemaNames(List<String> schemaGroup) {
+ if(!schemaGroup.contains("Group1")) {
+ return new ArrayList<>();
+ }
+ List<String> schemas = new ArrayList<>();
+ schemas.add("testSchema");
+ return schemas;
+ }
+ };
+
+ AutocompletionAgent autocompletionAgent =
+ new AutocompletionAgent("schema-registry", client);
+
+ List<String> groupList = new ArrayList<>();
+ groupList.add("Group1");
+ groupList.add("Group2");
+ List<String> res = autocompletionAgent.getSchemaMetadataList("tes", groupList, new ArrayList<>());
+ List<String> expected = new ArrayList<>();
+ expected.add("testSchema");
+ assertEquals(1, res.size());
+ assertThat(res, is(expected));
+
+ res = autocompletionAgent.getSchemaMetadataList("tesSome", groupList, new ArrayList<>());
+ assertEquals(0, res.size());
+ }
+
+ @Test
+ public void getBranchList() {
+ ISchemaRegistryClient client = new DefaultSchemaRegistryClientForTesting(){
+
+ public List<String> getSchemaBranches(String schemaMetadataName) {
+ if(!schemaMetadataName.equals("Schema1")) {
+ return new ArrayList<>();
+ }
+ List<String> branches = new ArrayList<>();
+ branches.add("testBranch");
+ return branches;
+ }
+
+
+ public List<String> getSchemaNames(List<String> schemaGroup) {
+ if(!schemaGroup.contains("Group1")) {
+ return new ArrayList<>();
+ }
+ List<String> schemas = new ArrayList<>();
+ schemas.add("Schema1");
+ return schemas;
+ }
+ };
+
+ AutocompletionAgent autocompletionAgent =
+ new AutocompletionAgent("schema-registry", client);
+
+ List<String> schemaList = new ArrayList<>();
+ schemaList.add("Schema1");
+ schemaList.add("Schema2");
+ List<String> groups = new ArrayList<>();
+ groups.add("Group1");
+ List<String> res = autocompletionAgent.getBranchList("tes", groups, schemaList, new ArrayList<>());
+ List<String> expected = new ArrayList<>();
+ expected.add("testBranch");
+ assertEquals(1, res.size());
+ assertThat(res, is(expected));
+
+ res = autocompletionAgent.getSchemaMetadataList("tesSome", schemaList, new ArrayList<>());
+ assertEquals(0, res.size());
+ }
+}
\ No newline at end of file
diff --git a/plugin-schema-registry/src/test/java/org/apache/ranger/services/schema/registry/client/SchemaRegistryResourceMgrTest.java b/plugin-schema-registry/src/test/java/org/apache/ranger/services/schema/registry/client/SchemaRegistryResourceMgrTest.java
new file mode 100644
index 0000000..33860b3
--- /dev/null
+++ b/plugin-schema-registry/src/test/java/org/apache/ranger/services/schema/registry/client/SchemaRegistryResourceMgrTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.schema.registry.client;
+
+import org.apache.ranger.plugin.service.ResourceLookupContext;
+import org.apache.ranger.services.schema.registry.client.util.TestAutocompletionAgent;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+
+public class SchemaRegistryResourceMgrTest {
+
+ @Test
+ public void getSchemaRegistryResources() throws Exception {
+ String serviceName = "schema-registry";
+ Map<String, String> configs = new HashMap<>();
+ configs.put("schema.registry.url", "http://dummyname:8081");
+ AutocompletionAgent client = new TestAutocompletionAgent("schema-registry", configs);
+
+
+ ResourceLookupContext lookupContext = new ResourceLookupContext();
+ lookupContext.setResources(new HashMap<>());
+ List<String> groups = new ArrayList<>(), schemas = new ArrayList<>(), branches = new ArrayList<>();
+ groups.add("Group1");
+ schemas.add("Schema1");
+ branches.add("Branch1");
+
+ lookupContext.getResources().put("schema-group", groups);
+ lookupContext.getResources().put("schema-metadata", schemas);
+ lookupContext.getResources().put("schema-branch", branches);
+
+ lookupContext.setResourceName("schema-group");
+ lookupContext.setUserInput("test");
+ List<String> res = SchemaRegistryResourceMgr.getSchemaRegistryResources(serviceName,
+ configs,
+ lookupContext,
+ client);
+ List<String> expected = new ArrayList<>();
+ expected.add("Group1"); expected.add("testGroup");
+ assertThat(res, is(expected));
+
+ lookupContext.setResourceName("schema-metadata");
+ lookupContext.setUserInput("testS");
+ res = SchemaRegistryResourceMgr.getSchemaRegistryResources(serviceName,
+ configs,
+ lookupContext,
+ client);
+ expected = new ArrayList<>();
+ expected.add("Schema1"); expected.add("testSchema");
+ assertThat(res, is(expected));
+
+ lookupContext.setResourceName("schema-branch");
+ lookupContext.setUserInput("testB");
+ res = SchemaRegistryResourceMgr.getSchemaRegistryResources(serviceName,
+ configs,
+ lookupContext,
+ client);
+ expected = new ArrayList<>();
+ expected.add("Branch1"); expected.add("testBranch");
+ assertThat(res, is(expected));
+
+ lookupContext.setResourceName("schema-version");
+ lookupContext.setUserInput("*");
+ res = SchemaRegistryResourceMgr.getSchemaRegistryResources(serviceName,
+ configs,
+ lookupContext,
+ client);
+ expected = new ArrayList<>();
+ expected.add("*");
+ assertThat(res, is(expected));
+
+ lookupContext.setResourceName("serde");
+ res = SchemaRegistryResourceMgr.getSchemaRegistryResources(serviceName,
+ configs,
+ lookupContext,
+ client);
+ assertThat(res, is(expected));
+
+ lookupContext.setResourceName("registry-service");
+ res = SchemaRegistryResourceMgr.getSchemaRegistryResources(serviceName,
+ configs,
+ lookupContext,
+ client);
+ assertThat(res, is(expected));
+
+ }
+}
\ No newline at end of file
diff --git a/plugin-schema-registry/src/test/java/org/apache/ranger/services/schema/registry/client/connection/DefaultSchemaRegistryClientTest.java b/plugin-schema-registry/src/test/java/org/apache/ranger/services/schema/registry/client/connection/DefaultSchemaRegistryClientTest.java
new file mode 100644
index 0000000..7eaaab9
--- /dev/null
+++ b/plugin-schema-registry/src/test/java/org/apache/ranger/services/schema/registry/client/connection/DefaultSchemaRegistryClientTest.java
@@ -0,0 +1,190 @@
+/*
+ * 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.schema.registry.client.connection;
+
+import com.google.common.io.Resources;
+import com.hortonworks.registries.schemaregistry.SchemaMetadata;
+import com.hortonworks.registries.schemaregistry.SchemaVersion;
+import com.hortonworks.registries.schemaregistry.webservice.LocalSchemaRegistryServer;
+import org.apache.commons.io.IOUtils;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static com.hortonworks.registries.schemaregistry.client.SchemaRegistryClient.Configuration.SCHEMA_REGISTRY_URL;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+
+public class DefaultSchemaRegistryClientTest {
+
+ private static final String V1_API_PATH = "api/v1";
+
+ private static LocalSchemaRegistryServer localSchemaRegistryServer;
+
+ private static ISchemaRegistryClient client;
+
+ @BeforeClass
+ public static void init() throws Exception {
+ localSchemaRegistryServer =
+ new LocalSchemaRegistryServer(getFilePath("ssl-schema-registry.yaml"));
+
+ try {
+ localSchemaRegistryServer.start();
+ } catch (Exception e){
+ localSchemaRegistryServer.stop();
+ throw e;
+ }
+
+ SchemaMetadata schemaMetadata1 = new SchemaMetadata
+ .Builder("Schema1")
+ .type("avro")
+ .schemaGroup("Group1")
+ .description("description")
+ .build();
+
+ SchemaMetadata schemaMetadata2 = new SchemaMetadata
+ .Builder("Schema2")
+ .type("avro")
+ .schemaGroup("Group2")
+ .description("description")
+ .build();
+
+ SchemaMetadata schemaMetadata3 = new SchemaMetadata
+ .Builder("Schema3")
+ .type("avro")
+ .schemaGroup("Group3")
+ .description("description")
+ .build();
+
+ com.hortonworks.registries.schemaregistry.client.SchemaRegistryClient client = getClient("ssl-schema-registry-client.yaml");
+
+ client.registerSchemaMetadata(schemaMetadata1);
+ client.registerSchemaMetadata(schemaMetadata2);
+ client.registerSchemaMetadata(schemaMetadata3);
+
+ SchemaVersion sv = new SchemaVersion(getSchema("schema-text3.avcs"),
+ "Initial version of the schema");
+ client.addSchemaVersion(schemaMetadata3, sv);
+
+ ///////////////////////////////////////////////
+ Map<String, Object> conf = new HashMap<>();
+ conf.put(SCHEMA_REGISTRY_URL.name(), "https://localhost:" + localSchemaRegistryServer.getLocalPort());
+ String keyStorePath = "./src/test/resources/keystore.jks";
+ String keyStorePassword = "password";
+ String keyStoreType = "jks";
+
+ String trustStorePath = "./src/test/resources/truststore.jks";
+ String trustStorePassword = "password";
+ String trustStoreType = "jks";
+ conf.put("keyStorePath", keyStorePath);
+ conf.put("keyStorePassword", keyStorePassword);
+ conf.put("keyStoreType", keyStoreType);
+
+ conf.put("trustStorePath", trustStorePath);
+ conf.put("trustStorePassword", trustStorePassword);
+ conf.put("trustStoreType", trustStoreType);
+
+ DefaultSchemaRegistryClientTest.client = new DefaultSchemaRegistryClient(conf);
+
+ }
+
+ private static String getSchema(String schemaFileName) throws Exception {
+ try (FileInputStream fis = new FileInputStream(getFilePath(schemaFileName))) {
+ org.apache.avro.Schema.Parser parser = new org.apache.avro.Schema.Parser();
+ return parser.parse(fis).toString();
+ } catch (Exception e) {
+ throw new Exception("Failed to read schema text from : "
+ + getFilePath(schemaFileName), e);
+ }
+
+ }
+
+ private static String getFilePath(String serverYAMLFileName) throws URISyntaxException {
+ return new File(Resources.getResource(serverYAMLFileName)
+ .toURI())
+ .getAbsolutePath();
+ }
+
+ private static com.hortonworks.registries.schemaregistry.client.SchemaRegistryClient getClient(String clientYAMLFileName) throws Exception {
+ String registryURL = localSchemaRegistryServer.getLocalURL() + V1_API_PATH;
+ Map<String, Object> conf = new HashMap<>();
+ try (FileInputStream fis = new FileInputStream(getFilePath(clientYAMLFileName))) {
+ conf = (Map<String, Object>) new Yaml().load(IOUtils.toString(fis, "UTF-8"));
+ conf.put("schema.registry.url", registryURL);
+ } catch(Exception e) {
+ throw new Exception("Failed to export schema client configuration for yaml : " + getFilePath(clientYAMLFileName), e);
+ }
+ conf.put(SCHEMA_REGISTRY_URL.name(), registryURL);
+
+ return new com.hortonworks.registries.schemaregistry.client.SchemaRegistryClient(conf);
+ }
+
+ @Test
+ public void getSchemaGroups() {
+ List<String> groups = client.getSchemaGroups();
+ assertThat(groups.size(), is(3));
+ assertTrue(groups.contains("Group1"));
+ assertTrue(groups.contains("Group2"));
+ assertTrue(groups.contains("Group3"));
+ }
+
+ @Test
+ public void getSchemaNames() {
+ List<String> groups = new ArrayList<>();
+ groups.add("Group1");
+ groups.add("Group2");
+ List<String> schemas = client.getSchemaNames(groups);
+ assertThat(schemas.size(), is(2));
+ assertTrue(schemas.contains("Schema1"));
+ assertTrue(schemas.contains("Schema2"));
+ }
+
+ @Test
+ public void getSchemaBranches() {
+ List<String> branches = client.getSchemaBranches("Schema1");
+ assertTrue(branches.isEmpty());
+ branches = client.getSchemaBranches("Schema3");
+ assertThat(branches.size(), is(1));
+ assertThat(branches.get(0), is("MASTER"));
+ }
+
+ @Test
+ public void checkConnection() {
+ try {
+ client.checkConnection();
+ } catch (Exception e) {
+ fail("No Exception should be thrown");
+ }
+ }
+
+ @Test(expected = Exception.class)
+ public void checkConnection2() throws Exception {
+ new DefaultSchemaRegistryClient(new HashMap<>()).checkConnection();
+ }
+}
\ No newline at end of file
diff --git a/plugin-schema-registry/src/test/java/org/apache/ranger/services/schema/registry/client/connection/util/SecurityUtilsTest.java b/plugin-schema-registry/src/test/java/org/apache/ranger/services/schema/registry/client/connection/util/SecurityUtilsTest.java
new file mode 100644
index 0000000..541056c
--- /dev/null
+++ b/plugin-schema-registry/src/test/java/org/apache/ranger/services/schema/registry/client/connection/util/SecurityUtilsTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.schema.registry.client.connection.util;
+
+import org.junit.Test;
+
+import javax.net.ssl.SSLContext;
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.hortonworks.registries.schemaregistry.client.SchemaRegistryClient.Configuration.SCHEMA_REGISTRY_URL;
+import static org.apache.ranger.plugin.client.HadoopConfigHolder.RANGER_AUTH_TYPE;
+import static org.apache.ranger.plugin.client.HadoopConfigHolder.RANGER_LOOKUP_KEYTAB;
+import static org.apache.ranger.plugin.client.HadoopConfigHolder.RANGER_LOOKUP_PRINCIPAL;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class SecurityUtilsTest {
+
+ @Test
+ public void isHttpsConnection() {
+ Map<String, String> conf = new HashMap();
+ conf.put(SCHEMA_REGISTRY_URL.name(), "https://dummy:8081");
+ assertTrue(SecurityUtils.isHttpsConnection(conf));
+
+ conf = new HashMap();
+ conf.put(SCHEMA_REGISTRY_URL.name(), "http://dummy:8081");
+ assertFalse(SecurityUtils.isHttpsConnection(conf));
+ }
+
+ @Test
+ public void createSSLContext() throws Exception {
+ String keyStorePath = "keystore.jks";
+ String keyStorePassword = "password";
+ String keyStoreType = "jks";
+
+ String trustStorePath = "trustsrore.jks";
+ String trustStorePassword = "password";
+ String trustStoreType = "jks";
+
+ Map<String, String> conf = new HashMap();
+ SSLContext sslContext = SecurityUtils.createSSLContext(conf, "TLS");
+ assertTrue(sslContext != null);
+
+ conf.put("keyStorePath", keyStorePath);
+ conf.put("keyStorePassword", keyStorePassword);
+ conf.put("keyStoreType", keyStoreType);
+
+ conf.put("trustStorePath", trustStorePath);
+ conf.put("trustStorePassword", trustStorePassword);
+ conf.put("trustStoreType", trustStoreType);
+ sslContext = SecurityUtils.createSSLContext(conf, "TLS");
+
+ assertTrue(sslContext != null);
+
+ }
+
+ @Test
+ public void getJaasConfigForClientPrincipal() {
+ Map<String, String> conf = new HashMap();
+ assertNull(SecurityUtils.getJaasConfigForClientPrincipal(conf));
+ conf.put(RANGER_LOOKUP_KEYTAB, "/tmp/rangerlookup.keytab");
+ assertNull(SecurityUtils.getJaasConfigForClientPrincipal(conf));
+ conf.put(RANGER_LOOKUP_PRINCIPAL, "rangerlookup");
+
+ String expected = "com.sun.security.auth.module.Krb5LoginModule" +
+ " required useTicketCache=false principal=\"rangerlookup\" " +
+ "useKeyTab=true keyTab=\"/tmp/rangerlookup.keytab\";";
+ String actual = SecurityUtils.getJaasConfigForClientPrincipal(conf);
+ assertEquals(actual, expected);
+ }
+
+
+ @Test
+ public void isKerberosEnabled() {
+ Map<String, String> conf = new HashMap();
+
+ conf.put(RANGER_AUTH_TYPE, "kerberos");
+ conf.put("schema-registry.authentication", "kerberos");
+ assertTrue(SecurityUtils.isKerberosEnabled(conf));
+
+ conf = new HashMap();
+ assertFalse(SecurityUtils.isKerberosEnabled(conf));
+
+ conf = new HashMap();
+ conf.put(RANGER_AUTH_TYPE, "kerberos");
+ assertFalse(SecurityUtils.isKerberosEnabled(conf));
+
+ conf = new HashMap();
+ conf.put("schema-registry.authentication", "kerberos");
+ assertFalse(SecurityUtils.isKerberosEnabled(conf));
+
+ conf = new HashMap();
+ conf.put(RANGER_AUTH_TYPE, "kerberos");
+ conf.put("schema-registry.authentication", "Something wrong");
+ assertFalse(SecurityUtils.isKerberosEnabled(conf));
+
+ conf = new HashMap();
+ conf.put("schema-registry.authentication", "kerberos");
+ conf.put(RANGER_AUTH_TYPE, "Something wrong");
+ assertFalse(SecurityUtils.isKerberosEnabled(conf));
+
+ }
+}
\ No newline at end of file
diff --git a/plugin-schema-registry/src/test/java/org/apache/ranger/services/schema/registry/client/util/AcceptAllHostnameVerifier.java b/plugin-schema-registry/src/test/java/org/apache/ranger/services/schema/registry/client/util/AcceptAllHostnameVerifier.java
new file mode 100644
index 0000000..7d01860
--- /dev/null
+++ b/plugin-schema-registry/src/test/java/org/apache/ranger/services/schema/registry/client/util/AcceptAllHostnameVerifier.java
@@ -0,0 +1,28 @@
+/*
+ * 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.schema.registry.client.util;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLSession;
+
+public class AcceptAllHostnameVerifier implements HostnameVerifier {
+ @Override
+ public boolean verify(String s, SSLSession sslSession) {
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/plugin-schema-registry/src/test/java/org/apache/ranger/services/schema/registry/client/util/DefaultSchemaRegistryClientForTesting.java b/plugin-schema-registry/src/test/java/org/apache/ranger/services/schema/registry/client/util/DefaultSchemaRegistryClientForTesting.java
new file mode 100644
index 0000000..083dd6b
--- /dev/null
+++ b/plugin-schema-registry/src/test/java/org/apache/ranger/services/schema/registry/client/util/DefaultSchemaRegistryClientForTesting.java
@@ -0,0 +1,46 @@
+/*
+ * 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.schema.registry.client.util;
+
+import org.apache.ranger.services.schema.registry.client.connection.ISchemaRegistryClient;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class DefaultSchemaRegistryClientForTesting implements ISchemaRegistryClient {
+
+ @Override
+ public List<String> getSchemaGroups() {
+ return new ArrayList<>();
+ }
+
+ @Override
+ public List<String> getSchemaNames(List<String> schemaGroup) {
+ return new ArrayList<>();
+ }
+
+ @Override
+ public List<String> getSchemaBranches(String schemaMetadataName) {
+ return new ArrayList<>();
+ }
+
+ @Override
+ public void checkConnection() throws Exception {
+
+ }
+}
diff --git a/plugin-schema-registry/src/test/java/org/apache/ranger/services/schema/registry/client/util/TestAutocompletionAgent.java b/plugin-schema-registry/src/test/java/org/apache/ranger/services/schema/registry/client/util/TestAutocompletionAgent.java
new file mode 100644
index 0000000..3dd8748
--- /dev/null
+++ b/plugin-schema-registry/src/test/java/org/apache/ranger/services/schema/registry/client/util/TestAutocompletionAgent.java
@@ -0,0 +1,59 @@
+/*
+ * 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.schema.registry.client.util;
+
+import org.apache.ranger.services.schema.registry.client.AutocompletionAgent;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class TestAutocompletionAgent extends AutocompletionAgent {
+ public TestAutocompletionAgent(String serviceName, Map<String, String> configs) {
+ super(serviceName, configs);
+ }
+
+ @Override
+ public List<String> getSchemaGroupList(String lookupGroupName, List<String> groupList) {
+ List<String> res = new ArrayList<>(groupList);
+ res.add("testGroup");
+
+ return res;
+ }
+
+ @Override
+ public List<String> getSchemaMetadataList(String finalSchemaMetadataName,
+ List<String> schemaGroupList,
+ List<String> schemaMetadataList) {
+ List<String> res = new ArrayList<>(schemaMetadataList);
+ res.add("testSchema");
+
+ return res;
+ }
+
+ @Override
+ public List<String> getBranchList(String lookupBranchName,
+ List<String> groups,
+ List<String> schemaList,
+ List<String> branchList) {
+ List<String> res = new ArrayList<>(branchList);
+ res.add("testBranch");
+
+ return res;
+ }
+}
diff --git a/plugin-schema-registry/src/test/resources/keystore.jks b/plugin-schema-registry/src/test/resources/keystore.jks
new file mode 100644
index 0000000..8e8a4c7
Binary files /dev/null and b/plugin-schema-registry/src/test/resources/keystore.jks differ
diff --git a/plugin-schema-registry/src/test/resources/schema-text3.avcs b/plugin-schema-registry/src/test/resources/schema-text3.avcs
new file mode 100644
index 0000000..21d9c2a
--- /dev/null
+++ b/plugin-schema-registry/src/test/resources/schema-text3.avcs
@@ -0,0 +1,9 @@
+{
+ "type": "record",
+ "namespace": "com.example",
+ "name": "FullName",
+ "fields": [
+ { "name": "first", "type": "string" },
+ { "name": "last", "type": "string" }
+ ]
+}
\ No newline at end of file
diff --git a/plugin-schema-registry/src/test/resources/ssl-schema-registry-client.yaml b/plugin-schema-registry/src/test/resources/ssl-schema-registry-client.yaml
new file mode 100644
index 0000000..ff46570
--- /dev/null
+++ b/plugin-schema-registry/src/test/resources/ssl-schema-registry-client.yaml
@@ -0,0 +1,27 @@
+schema.registry.url : "__registry_url"
+schema.registry.client.local.jars.path : "/tmp/schema-registry/local-jars"
+schema.registry.client.class.loader.cache.size : 1024
+schema.registry.client.class.loader.cache.expiry.interval : 3600
+schema.registry.client.schema.version.cache.size : 1024
+schema.registry.client.schema.version.cache.expiry.interval : 300
+schema.registry.client.schema.metadata.cache.expiry.interval : 300
+schema.registry.client.schema.text.cache.size : 1024
+schema.registry.client.schema.text.cache.expiry.interval : 300
+schema.registry.client.url.selector : "com.hortonworks.registries.schemaregistry.client.FailoverUrlSelector"
+
+schema.registry.client.ssl:
+ protocol: SSL
+ hostnameVerifierClass: org.apache.ranger.services.schema.registry.client.util.AcceptAllHostnameVerifier
+ keyStoreType: JKS
+ keyStorePath: ./src/test/resources/keystore.jks
+ keyStorePassword: password
+# keyPassword:
+# keyStoreProvider:
+# keyManagerFactoryProvider:
+# keyManagerFactoryAlgorithm:
+ trustStoreType: JKS
+ trustStorePath: ./src/test/resources/truststore.jks
+ trustStorePassword: password
+# trustStoreProvider:
+# trustManagerFactoryProvider:
+# trustManagerFactoryAlgorithm:
\ No newline at end of file
diff --git a/plugin-schema-registry/src/test/resources/ssl-schema-registry.yaml b/plugin-schema-registry/src/test/resources/ssl-schema-registry.yaml
new file mode 100644
index 0000000..dc84998
--- /dev/null
+++ b/plugin-schema-registry/src/test/resources/ssl-schema-registry.yaml
@@ -0,0 +1,79 @@
+# registries configuration
+modules:
+ - name: schema-registry
+ className: com.hortonworks.registries.schemaregistry.webservice.SchemaRegistryModule
+ config:
+ schemaProviders:
+ - providerClass: "com.hortonworks.registries.schemaregistry.avro.AvroSchemaProvider"
+ defaultSerializerClass: "com.hortonworks.registries.schemaregistry.serdes.avro.AvroSnapshotSerializer"
+ defaultDeserializerClass: "com.hortonworks.registries.schemaregistry.serdes.avro.AvroSnapshotDeserializer"
+ # schema cache properties
+ # inmemory schema versions cache size
+ schemaCacheSize: 10000
+ # inmemory schema version cache entry expiry interval after access
+ schemaCacheExpiryInterval: 3600
+
+
+servletFilters:
+ - className: "com.hortonworks.registries.schemaregistry.webservice.RewriteUriFilter"
+ params:
+ # value format is [<targetpath>,<paths-should-be-redirected-to>,*|]*
+ # below /subjects and /schemas/ids are forwarded to /api/v1/confluent
+ forwardPaths: "/api/v1/confluent,/subjects/*,/schemas/ids/*"
+ redirectPaths: "/ui/,/"
+
+
+fileStorageConfiguration:
+ className: "com.hortonworks.registries.common.util.LocalFileSystemStorage"
+ properties:
+ directory: "/tmp/storage"
+
+
+storageProviderConfiguration:
+ providerClass: "com.hortonworks.registries.storage.impl.memory.InMemoryStorageManager"
+
+#enable CORS, may want to disable in production
+enableCors: true
+
+## swagger configuration
+swagger:
+ resourcePackage: com.hortonworks.registries.schemaregistry.webservice
+
+
+server:
+ applicationConnectors:
+ - type: https
+ port: 0
+ keyStorePath: ./src/test/resources/keystore.jks
+ keyStorePassword: password
+ trustStorePath: ./src/test/resources/truststore.jks
+ trustStorePassword: password
+ needClientAuth: true
+ validateCerts: false
+ validatePeers: false
+ adminConnectors:
+ - type: https
+ port: 0
+ keyStorePath: ./src/test/resources/keystore.jks
+ keyStorePassword: password
+ trustStorePath: ./src/test/resources/truststore.jks
+ trustStorePassword: password
+ needClientAuth: true
+ validateCerts: false
+ validatePeers: false
+
+# Logging settings.
+logging:
+
+ # The default level of all loggers. Can be OFF, ERROR, WARN, INFO, DEBUG, TRACE, or ALL.
+ level: INFO
+
+ # Logger-specific levels.
+ loggers:
+
+ # Sets the level for 'com.example.app' to DEBUG.
+ com.hortonworks.registries: DEBUG
+
+
+ appenders:
+ - type: console
diff --git a/plugin-schema-registry/src/test/resources/truststore.jks b/plugin-schema-registry/src/test/resources/truststore.jks
new file mode 100644
index 0000000..3d81722
Binary files /dev/null and b/plugin-schema-registry/src/test/resources/truststore.jks differ
diff --git a/pom.xml b/pom.xml
index dde449d..22926fd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -267,6 +267,7 @@
<module>ranger-examples</module>
<module>ranger-tools</module>
<module>plugin-atlas</module>
+ <module>plugin-schema-registry</module>
<module>plugin-sqoop</module>
<module>ranger-sqoop-plugin-shim</module>
<module>plugin-kylin</module>
@@ -549,6 +550,7 @@
<module>ranger-examples</module>
<module>ranger-tools</module>
<module>plugin-atlas</module>
+ <module>plugin-schema-registry</module>
<module>plugin-sqoop</module>
<module>ranger-sqoop-plugin-shim</module>
<module>plugin-kylin</module>
@@ -631,6 +633,7 @@
<module>ranger-examples</module>
<module>ranger-tools</module>
<module>plugin-atlas</module>
+ <module>plugin-schema-registry</module>
<module>plugin-sqoop</module>
<module>ranger-sqoop-plugin-shim</module>
<module>plugin-kylin</module>
@@ -965,6 +968,8 @@
<exclude>**/test/resources/**/*.json</exclude>
<exclude>**/test/resources/**/*.txt</exclude>
<exclude>**/test/resources/**/*.csv</exclude>
+ <exclude>**/test/resources/**/*.yaml</exclude>
+ <exclude>**/test/resources/**/*.avcs</exclude>
<exclude>**/main/resources/**/*.json</exclude>
<exclude>**/samples/**/*.json</exclude>
<exclude>**/.externalToolBuilders/*</exclude>