This is an automated email from the ASF dual-hosted git repository.
ngangam pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hive.git
The following commit(s) were added to refs/heads/master by this push:
new 78db8e93e7e HIVE-29112: HMS embedded servlets https support (#6002)
78db8e93e7e is described below
commit 78db8e93e7e713e0ba7d5dcb9fc7792d12cae38c
Author: Henrib <[email protected]>
AuthorDate: Fri Aug 15 04:52:38 2025 +0200
HIVE-29112: HMS embedded servlets https support (#6002)
HIVE-29912: added configuration variable
hive.metastore.httpserver.use.https that drives if catalog/property servlets
are using https;
- requires the same keystore/truststore configuration than useSSL;
- added tests & self signed certificates (good for 10 years);
- renamed conditional version of createSslContextFactory to
createSslContextFactoryIf;
- addressing review comments;
- USE_SSL drive https endpoint creation;
- refactored ServletServerBuilder#createConnector();
- removed useless method ServletServerBuilder#createSslContextFactory() and
ServletSecurity#createSslContextFactory();
- removed junit.jupiter.* that break compilation (?!);
---
.../metastore/properties/HMSPropertyManager.java | 8 +-
.../hadoop/hive/metastore/ServletSecurity.java | 4 +-
.../hive/metastore/ServletServerBuilder.java | 65 +++---
...ServletTest1.java => HMSHttpClientSslTest.java} | 145 ++++++++++++--
...MSServletTest1A.java => HMSHttpClientTest.java} | 14 +-
...SServletTest.java => HMSJsonClientSslTest.java} | 221 ++++++++-------------
...HMSServletTestA.java => HMSJsonClientTest.java} | 20 +-
.../hive/metastore/properties/HMSTestBase.java | 90 ++++++++-
.../src/test/resources/hive_keystore.p12 | Bin 0 -> 2708 bytes
.../src/test/resources/hive_truststore.p12 | Bin 0 -> 1238 bytes
10 files changed, 344 insertions(+), 223 deletions(-)
diff --git
a/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/HMSPropertyManager.java
b/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/HMSPropertyManager.java
index 065a73dc06a..c1166bd28ed 100644
---
a/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/HMSPropertyManager.java
+++
b/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/HMSPropertyManager.java
@@ -31,7 +31,7 @@
* <ul>
* <li>name : when it refers to a cluster property named 'name'</li>
* <li>db.name : when it refers to a database property named 'name' for the
database 'db'</li>
- * <li>db.table.name : when it refers to a table property named 'name' for
the table 'table' in the database 'db</li>
+ * <li>db.table.name : when it refers to a table property named 'name' for
the table 'table' in the database 'db'</li>
* </ul>
*/
public class HMSPropertyManager extends PropertyManager {
@@ -80,7 +80,8 @@ public enum MaintenanceOpStatus {
CLEANUP_NEEDED,
FAILED
}
- /** The map form ordinal to OpStatus. */
+
+ /** The map from ordinal to OpStatus. */
private static final Map<Integer, MaintenanceOpStatus> MOS;
static {
MOS = new HashMap<>(MaintenanceOpStatus.values().length);
@@ -111,6 +112,7 @@ public static MaintenanceOpStatus findOpStatus(int ordinal)
{
}
return parse(value.toString());
}
+
@Override public MaintenanceOpType parse(String str) {
if (str == null) {
return null;
@@ -142,12 +144,14 @@ public static MaintenanceOpStatus findOpStatus(int
ordinal) {
}
return parse(value.toString());
}
+
@Override public MaintenanceOpStatus parse(String str) {
if (str == null) {
return null;
}
return MaintenanceOpStatus.valueOf(str.toUpperCase());
}
+
@Override public String format(Object value) {
if (value instanceof MaintenanceOpStatus) {
return value.toString();
diff --git
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/ServletSecurity.java
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/ServletSecurity.java
index 677e814e8c1..22985875f22 100644
---
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/ServletSecurity.java
+++
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/ServletSecurity.java
@@ -304,13 +304,13 @@ static void loginServerPrincipal(Configuration conf)
throws IOException {
}
/**
- * Creates an SSL context factory if configuration states so.
+ * Creates an SSL context factory if the configuration states so.
* @param conf the configuration
* @return null if no ssl in config, an instance otherwise
* @throws IOException if getting password fails
*/
static SslContextFactory createSslContextFactory(Configuration conf) throws
IOException {
- final boolean useSsl = MetastoreConf.getBoolVar(conf,
MetastoreConf.ConfVars.USE_SSL);
+ final boolean useSsl = MetastoreConf.getBoolVar(conf,
MetastoreConf.ConfVars.USE_SSL);
if (!useSsl) {
return null;
}
diff --git
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/ServletServerBuilder.java
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/ServletServerBuilder.java
index 7323845ae35..67f9c9961b6 100644
---
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/ServletServerBuilder.java
+++
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/ServletServerBuilder.java
@@ -18,10 +18,14 @@
*/
package org.apache.hadoop.hive.metastore;
+import static org.eclipse.jetty.util.URIUtil.HTTP;
+import static org.eclipse.jetty.util.URIUtil.HTTPS;
+
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hive.metastore.conf.MetastoreConf;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
@@ -32,6 +36,7 @@
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.servlet.Servlet;
import javax.servlet.http.HttpServlet;
@@ -46,10 +51,11 @@
import java.util.function.Function;
/**
- * Helper class to ease creation of embedded Jetty serving servlets on
+ * Helper class to ease the creation of embedded Jetty serving servlets on
* different ports.
*/
public class ServletServerBuilder {
+ private static final Logger LOGGER =
LoggerFactory.getLogger(ServletServerBuilder.class);
/**
* The configuration instance.
*/
@@ -94,7 +100,7 @@ public static ServletServerBuilder builder(Configuration
conf,
}
/**
- * Helper for generic use case.
+ * Helper for the generic use case.
*
* @param logger the logger
* @param conf the configuration
@@ -116,7 +122,7 @@ public Configuration getConfiguration() {
/**
* Adds a servlet instance.
* <p>The servlet port can be shared between servlets; if 0, the system will
provide
- * a port. If the port is < 0, the system will provide a port dedicated
(ie non-shared)
+ * a port. If the port is < 0, the system will provide a port dedicated
(i.e., non-shared)
* to the servlet.</p>
*
* @param port the servlet port
@@ -159,24 +165,32 @@ private Server createServer() {
}
/**
- * Creates a server instance and a connector on a given port.
+ * Create an HTTP or HTTPS connector.
*
- * @param server the server instance
- * @param sslContextFactory the ssl factory
- * @param port the port
- * @return the server connector listening to the port
+ * @param server The server to create the connector for
+ * @param sslContextFactory The ssl context factory to use;
+ * if null, the connector will be HTTP; if not
null, the connector will be HTTPS
+ * @param port The port to bind the connector to
+ * @return The created ServerConnector
*/
private ServerConnector createConnector(Server server, SslContextFactory
sslContextFactory, int port) {
- final ServerConnector connector = new ServerConnector(server,
sslContextFactory);
+ final ServerConnector connector;
+ HttpConfiguration httpConf = new HttpConfiguration();
+ // Do not leak information
+ httpConf.setSendServerVersion(false);
+ httpConf.setSendXPoweredBy(false);
+ if (sslContextFactory != null) {
+ httpConf.setSecureScheme(HTTPS);
+ httpConf.setSecurePort(port);
+ httpConf.addCustomizer(new SecureRequestCustomizer());
+ connector = new ServerConnector(server, sslContextFactory, new
HttpConnectionFactory(httpConf));
+ connector.setName(HTTPS);
+ } else {
+ connector = new ServerConnector(server, new
HttpConnectionFactory(httpConf));
+ connector.setName(HTTP);
+ }
connector.setPort(port);
connector.setReuseAddress(true);
- HttpConnectionFactory httpFactory =
connector.getConnectionFactory(HttpConnectionFactory.class);
- // do not leak information
- if (httpFactory != null) {
- HttpConfiguration httpConf = httpFactory.getHttpConfiguration();
- httpConf.setSendServerVersion(false);
- httpConf.setSendXPoweredBy(false);
- }
return connector;
}
@@ -204,7 +218,7 @@ private void addServlet(Map<Integer, ServletContextHandler>
handlersMap, Descrip
}
/**
- * Convenience method to start a http server that serves all configured
+ * Convenience method to start an http server that serves all configured
* servlets.
*
* @return the server instance or null if no servlet was configured
@@ -222,7 +236,7 @@ public Server startServer() throws Exception {
}
final Server server = createServer();
// create the connectors
- final SslContextFactory sslFactory =
ServletSecurity.createSslContextFactory(configuration);
+ final SslContextFactory sslContextFactory =
ServletSecurity.createSslContextFactory(configuration);
final ServerConnector[] connectors = new ServerConnector[size];
final ServletContextHandler[] handlers = new ServletContextHandler[size];
Iterator<Map.Entry<Integer, ServletContextHandler>> it =
handlersMap.entrySet().iterator();
@@ -230,7 +244,8 @@ public Server startServer() throws Exception {
Map.Entry<Integer, ServletContextHandler> entry = it.next();
int key = entry.getKey();
int port = Math.max(key, 0);
- ServerConnector connector = createConnector(server, sslFactory, port);
+ ServerConnector connector = createConnector(server, sslContextFactory,
port);
+ LOGGER.info("Adding {} servlet connector on port {}",
connector.getName(), port);
connectors[c] = connector;
ServletContextHandler handler = entry.getValue();
handlers[c] = handler;
@@ -268,7 +283,7 @@ public Server startServer() throws Exception {
* Creates and starts the server.
*
* @param logger a logger to output info
- * @return the server instance (or null if error)
+ * @return the server instance (or null if an error occurred)
*/
public Server start(Logger logger) {
try {
@@ -278,21 +293,21 @@ public Server start(Logger logger) {
logger.error("Unable to start servlet server on {}",
server.getURI());
} else {
descriptorsMap.values().forEach(descriptor -> logger.info("Started
{} servlet on {}:{}",
- descriptor.toString(),
+ descriptor,
descriptor.getPort(),
descriptor.getPath()));
}
}
return server;
- } catch (Throwable throwable) {
- logger.error("Unable to start servlet server", throwable);
+ } catch (Exception e) {
+ logger.error("Unable to start servlet server", e);
return null;
}
}
/**
* A descriptor of a servlet.
- * <p>After server is started, unspecified port will be updated to reflect
+ * <p>After the server is started, unspecified port will be updated to
reflect
* what the system allocated.</p>
*/
public static class Descriptor {
@@ -303,7 +318,7 @@ public static class Descriptor {
/**
* Create a servlet descriptor.
*
- * @param port the servlet port (or 0 if system allocated)
+ * @param port the servlet port (or 0 if the port is to be chosen by
the system)
* @param path the servlet path
* @param servlet the servlet instance
*/
diff --git
a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSServletTest1.java
b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSHttpClientSslTest.java
similarity index 50%
rename from
standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSServletTest1.java
rename to
standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSHttpClientSslTest.java
index b1c8b803dff..3be4038bf7c 100644
---
a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSServletTest1.java
+++
b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSHttpClientSslTest.java
@@ -22,11 +22,13 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
-import java.net.URL;
+import java.net.MalformedURLException;
+import java.net.URI;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
+import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletResponse;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hive.metastore.annotation.MetastoreUnitTest;
@@ -34,17 +36,24 @@
import org.apache.hadoop.hive.metastore.utils.MetaStoreUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
+import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+import org.junit.Assert;
+import org.junit.Test;
import org.junit.experimental.categories.Category;
@Category(MetastoreUnitTest.class)
-public class HMSServletTest1 extends HMSServletTest {
+public class HMSHttpClientSslTest extends HMSJsonClientSslTest {
@Override
public void tearDown() throws Exception {
if (client instanceof AutoCloseable) {
@@ -57,23 +66,31 @@ public void tearDown() throws Exception {
@Override
protected PropertyClient createClient(Configuration conf, int sport) throws
Exception {
String path = MetastoreConf.getVar(conf,
MetastoreConf.ConfVars.PROPERTIES_SERVLET_PATH);
- URL url = new URL("http://hive@localhost:" + sport + "/" + path + "/" +
NS);
+ String scheme = getScheme(conf);
+ URI uri = new URI(scheme + "://hive@localhost:" + sport + "/" + path + "/"
+ NS);
String jwt = generateJWT();
- return new JSonHttpClient(jwt, url.toString());
+ return new JsonHttpClient(conf, jwt, uri);
+ }
+
+ protected static HttpClient createHttpClient(Configuration conf) {
+ SSLContext sslCtxt = clientSSLContextFactory(conf);
+ return sslCtxt != null
+ ?
HttpClients.custom().setSSLContext(sslCtxt).setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build()
+ : HttpClients.createDefault();
}
/**
* A property client that uses Apache HttpClient as base.
*/
- public static class JSonHttpClient implements HttpPropertyClient,
AutoCloseable {
- private final String uri;
+ private static class JsonHttpClient implements HttpPropertyClient,
AutoCloseable {
+ private final URI uri;
private final HttpClient client;
private final String jwt;
- JSonHttpClient(String token, String uri) {
+ JsonHttpClient(Configuration conf, String token, URI uri) throws
MalformedURLException {
this.jwt = token;
this.uri = uri;
- this.client = HttpClients.createDefault();
+ this.client = createHttpClient(conf);
}
@Override
public void close() throws Exception {
@@ -108,21 +125,21 @@ private Object clientPost(Object args) throws IOException
{
HttpPost post = prepareMethod(new HttpPost(uri), new
Gson().toJson(args));
HttpResponse response = client.execute(post);
try {
- if (HttpServletResponse.SC_OK ==
response.getStatusLine().getStatusCode()) {
- HttpEntity entity = response.getEntity();
- if (entity != null) {
- Gson gson = new GsonBuilder().create();
- ContentType contentType = ContentType.getOrDefault(entity);
- Charset charset = contentType.getCharset();
- Reader reader = new InputStreamReader(entity.getContent(), charset);
- return gson.fromJson(reader,Object.class);
+ if (HttpServletResponse.SC_OK ==
response.getStatusLine().getStatusCode()) {
+ HttpEntity entity = response.getEntity();
+ if (entity != null) {
+ Gson gson = new GsonBuilder().create();
+ ContentType contentType = ContentType.getOrDefault(entity);
+ Charset charset = contentType.getCharset();
+ Reader reader = new InputStreamReader(entity.getContent(),
charset);
+ return gson.fromJson(reader,Object.class);
+ }
}
+ } finally {
+ if (response instanceof Closeable) {
+ ((Closeable) response).close();
+ }
}
- } finally {
- if (response instanceof Closeable) {
- ((Closeable) response).close();
- }
- }
return null;
}
@@ -167,4 +184,90 @@ public Map<String, String> getProperties(List<String>
selection) throws IOExcept
}
}
+ @Test
+ public void testPropertiesFilter() throws Exception {
+ HttpClient httpClient = createHttpClient(conf);
+ String jwt = generateJWT();
+ NameValuePair[] nvp = new NameValuePair[]{
+ new BasicNameValuePair("key", "db0.table01.fillFactor"),
+ new BasicNameValuePair("key", "db0.table04.fillFactor")
+ };
+ String scheme = getScheme(conf);
+ URI uri = new URIBuilder()
+ .setScheme(scheme)
+ .setUserInfo("hive")
+ .setHost("localhost")
+ .setPort(servletPort)
+ .setPath("/" + path + "/" + NS)
+ .setParameters(nvp)
+ .build();
+ HttpGet get = new HttpGet(uri);
+ get.addHeader("Authorization", "Bearer " + jwt);
+ get.addHeader("Content-Type", "application/json");
+ get.addHeader("Accept", "application/json");
+ get.addHeader(MetaStoreUtils.USER_NAME_HTTP_HEADER, "hive");
+
+ Map<String,String> result = null;
+ HttpResponse response = httpClient.execute(get);
+ try {
+ Assert.assertEquals(HttpServletResponse.SC_OK,
response.getStatusLine().getStatusCode());
+ HttpEntity entity = response.getEntity();
+ if (entity != null) {
+ Gson gson = new GsonBuilder().create();
+ ContentType contentType = ContentType.getOrDefault(entity);
+ Charset charset = contentType.getCharset();
+ Reader reader = new InputStreamReader(entity.getContent(), charset);
+ result = (Map<String, String>) gson.fromJson(reader, Object.class);
+ }
+ Assert.assertNotNull(result);
+ Assert.assertEquals(2, result.size());
+ } finally {
+ if (response instanceof AutoCloseable) {
+ ((AutoCloseable) response).close();
+ }
+ if (httpClient instanceof AutoCloseable) {
+ ((AutoCloseable) httpClient).close();
+ }
+ }
+ }
+
+
+ @Test
+ public void testEchoHttpClient() throws Exception {
+ HttpClient client = createHttpClient(conf);
+ String path = MetastoreConf.getVar(conf,
MetastoreConf.ConfVars.PROPERTIES_SERVLET_PATH);
+ String scheme = getScheme(conf);
+ URI uri = new URI(scheme + "://hive@localhost:" + servletPort + "/" + path
+ "/" + NS);
+ HttpResponse response = null;
+ try {
+ String jwt = generateJWT();
+ String msgBody = "{\"method\":\"echo\"}";
+ HttpPost post = new HttpPost(uri);
+ post.addHeader("Authorization", "Bearer " + jwt);
+ post.addHeader("Content-Type", "application/json");
+ post.addHeader("Accept", "application/json");
+ StringEntity sre = new StringEntity(msgBody,
ContentType.APPLICATION_JSON);
+ post.setEntity(sre);
+ response = client.execute(post);
+ Assert.assertEquals(HttpServletResponse.SC_OK,
response.getStatusLine().getStatusCode());
+ String resp = null;
+ HttpEntity entity = response.getEntity();
+ if (entity != null) {
+ ContentType contentType = ContentType.getOrDefault(entity);
+ Charset charset = contentType.getCharset();
+ Reader reader = new InputStreamReader(entity.getContent(), charset);
+ resp = readString(reader);
+ }
+ Assert.assertNotNull(resp);
+ Assert.assertEquals(msgBody, resp);
+ } finally {
+ if (response instanceof AutoCloseable) {
+ ((AutoCloseable) response).close();
+ }
+ if (client instanceof AutoCloseable) {
+ ((AutoCloseable) client).close();
+ }
+ }
+ }
+
}
diff --git
a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSServletTest1A.java
b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSHttpClientTest.java
similarity index 77%
rename from
standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSServletTest1A.java
rename to
standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSHttpClientTest.java
index fd58d53e1f1..4cef48a5b71 100644
---
a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSServletTest1A.java
+++
b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSHttpClientTest.java
@@ -20,12 +20,9 @@
import static com.github.tomakehurst.wiremock.client.WireMock.ok;
import java.nio.file.Files;
import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.hive.metastore.HiveMetaStore;
import org.apache.hadoop.hive.metastore.MetaStoreTestUtils;
import org.apache.hadoop.hive.metastore.annotation.MetastoreUnitTest;
import org.apache.hadoop.hive.metastore.conf.MetastoreConf;
-import org.apache.hadoop.hive.metastore.security.HadoopThriftAuthBridge;
-import org.junit.Assert;
import org.junit.experimental.categories.Category;
/**
@@ -33,11 +30,11 @@
* the client based on Apache HttpClient.
*/
@Category(MetastoreUnitTest.class)
-public class HMSServletTest1A extends HMSServletTest1 {
+public class HMSHttpClientTest extends HMSHttpClientSslTest {
protected int thriftPort;
@Override
- protected int createServer(Configuration conf) throws Exception {
+ protected void setConf(Configuration conf) throws Exception {
MetastoreConf.setVar(conf, MetastoreConf.ConfVars.PROPERTIES_SERVLET_AUTH,
"JWT");
MetastoreConf.setLongVar(conf,
MetastoreConf.ConfVars.PROPERTIES_SERVLET_PORT, 0);
MetastoreConf.setVar(conf,
MetastoreConf.ConfVars.THRIFT_METASTORE_AUTHENTICATION_JWT_JWKS_URL,
@@ -45,13 +42,6 @@ protected int createServer(Configuration conf) throws
Exception {
MOCK_JWKS_SERVER.stubFor(get("/jwks")
.willReturn(ok()
.withBody(Files.readAllBytes(jwtVerificationJWKSFile.toPath()))));
- thriftPort =
MetaStoreTestUtils.startMetaStoreWithRetry(HadoopThriftAuthBridge.getBridge(),
conf);
- servletServer = HiveMetaStore.getServletServer();
- if (servletServer == null || !servletServer.isStarted()) {
- Assert.fail("http server did not start");
- }
- servletPort = HiveMetaStore.getPropertyServletPort();
- return servletPort;
}
@Override
diff --git
a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSServletTest.java
b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSJsonClientSslTest.java
similarity index 54%
rename from
standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSServletTest.java
rename to
standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSJsonClientSslTest.java
index f196d66c33b..699cbc19df3 100644
---
a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSServletTest.java
+++
b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSJsonClientSslTest.java
@@ -16,8 +16,9 @@
*/
package org.apache.hadoop.hive.metastore.properties;
+import static org.eclipse.jetty.util.URIUtil.HTTP;
+import static org.eclipse.jetty.util.URIUtil.HTTPS;
import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
@@ -26,29 +27,19 @@
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
-import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletResponse;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hive.metastore.PropertyServlet;
import org.apache.hadoop.hive.metastore.annotation.MetastoreUnitTest;
import org.apache.hadoop.hive.metastore.conf.MetastoreConf;
import org.apache.hadoop.hive.metastore.utils.MetaStoreUtils;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.NameValuePair;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.client.utils.URIBuilder;
-import org.apache.http.entity.ContentType;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.HttpClients;
-import org.apache.http.message.BasicNameValuePair;
import org.eclipse.jetty.server.Server;
import org.junit.Assert;
import org.junit.Before;
@@ -56,20 +47,26 @@
import org.junit.experimental.categories.Category;
@Category(MetastoreUnitTest.class)
-public class HMSServletTest extends HMSTestBase {
+public class HMSJsonClientSslTest extends HMSTestBase {
String path = null;
Server servletServer = null;
int servletPort = -1;
-
+
+ @Override
@Before
public void setUp() throws Exception {
super.setUp();
path = MetastoreConf.getVar(conf,
MetastoreConf.ConfVars.PROPERTIES_SERVLET_PATH);
}
+ protected void setConf(Configuration conf) throws Exception {
+ setHttpsConf(conf);
+ }
+
@Override
protected int createServer(Configuration conf) throws Exception {
if (servletServer == null) {
+ setConf(conf);
servletServer = PropertyServlet.startServer(conf);
if (servletServer == null || !servletServer.isStarted()) {
Assert.fail("http server did not start");
@@ -92,30 +89,34 @@ protected void stopServer(int port) throws Exception {
}
}
+ protected static String getScheme(Configuration conf) {
+ return MetastoreConf.getBoolVar(conf, MetastoreConf.ConfVars.USE_SSL) ?
HTTPS : HTTP;
+ }
@Override
- protected PropertyClient createClient(Configuration conf, int sport) throws
Exception {
- String path = MetastoreConf.getVar(conf,
MetastoreConf.ConfVars.PROPERTIES_SERVLET_PATH);
- URL url = new URL("http://hive@localhost:" + sport + "/" + path + "/" +
NS);
+ protected PropertyClient createClient(Configuration conf, int port) throws
Exception {
+ String servletPath = MetastoreConf.getVar(conf,
MetastoreConf.ConfVars.PROPERTIES_SERVLET_PATH);
+ String scheme = getScheme(conf);
+ URI uri = new URI(scheme + "://hive@localhost:" + port + "/" + servletPath
+ "/" + NS);
String jwt = generateJWT();
- return new JSonClient(jwt, url);
+ return new JsonClient(jwt, uri);
}
/**
* A property client that uses http as transport.
*/
@SuppressWarnings("unchecked")
- public static class JSonClient implements HttpPropertyClient {
- private final URL url;
+ public class JsonClient implements HttpPropertyClient {
+ private final URI uri;
private final String jwt;
- JSonClient(String token, URL url) {
+ JsonClient(String token, URI uri) {
this.jwt = token;
- this.url = url;
+ this.uri = uri;
}
public boolean setProperties(Map<String, String> properties) {
try {
- clientCall(jwt, url, "PUT", properties);
+ clientCall(jwt, uri, "PUT", properties);
return true;
} catch(IOException xio) {
return false;
@@ -133,7 +134,7 @@ public Map<String, Map<String, String>>
getProperties(String mapPrefix, String m
args.put("selection", selection);
}
try {
- Object result = clientCall(jwt, url, "POST", args);
+ Object result = clientCall(jwt, uri, "POST", args);
return result instanceof Map? (Map<String, Map<String, String>>)
result : null ;
} catch(IOException xio) {
return null;
@@ -146,7 +147,7 @@ public Map<String, String> getProperties(List<String>
selection) {
Map<String, Object> args = new TreeMap<>();
args.put("method", "fetchProperties");
args.put("keys", selection);
- Object result = clientCall(jwt, url, "POST", args);
+ Object result = clientCall(jwt, uri, "POST", args);
return result instanceof Map? (Map<String, String>) result : null ;
} catch(IOException xio) {
return null;
@@ -154,77 +155,15 @@ public Map<String, String> getProperties(List<String>
selection) {
}
}
- @Test
- public void testServletEchoA() throws Exception {
- URL url = new URL("http://hive@localhost:" + servletPort + "/" + path +
"/" + NS);
- Map<String, String> json = Collections.singletonMap("method", "echo");
- String jwt = generateJWT();
- // succeed
- Object response = clientCall(jwt, url, "POST", json);
- Assert.assertNotNull(response);
- Assert.assertEquals(json, response);
- // fail (bad jwt)
- String badJwt = generateJWT(jwtUnauthorizedKeyFile.toPath());
- response = clientCall(badJwt, url, "POST", json);
- Assert.assertNull(response);
- }
-
- @Test
- public void testProperties1() throws Exception {
- runOtherProperties1(client);
- }
-
- @Test
- public void testProperties0() throws Exception {
- runOtherProperties0(client);
-
- HttpClient client = HttpClients.createDefault();
- String jwt = generateJWT();
- NameValuePair[] nvp = new NameValuePair[]{
- new BasicNameValuePair("key", "db0.table01.fillFactor"),
- new BasicNameValuePair("key", "db0.table04.fillFactor")
- };
- URI uri = new URIBuilder()
- .setScheme("http")
- .setUserInfo("hive")
- .setHost("localhost")
- .setPort(servletPort)
- .setPath("/" + path + "/" + NS)
- .setParameters(nvp)
- .build();
- HttpGet get = new HttpGet(uri);
- get.addHeader("Authorization", "Bearer " + jwt);
- get.addHeader("Content-Type", "application/json");
- get.addHeader("Accept", "application/json");
- get.addHeader(MetaStoreUtils.USER_NAME_HTTP_HEADER, "hive");
-
- Map<String,String> result = null;
- HttpResponse response = client.execute(get);
- try {
- Assert.assertEquals(HttpServletResponse.SC_OK,
response.getStatusLine().getStatusCode());
- HttpEntity entity = response.getEntity();
- if (entity != null) {
- Gson gson = new GsonBuilder().create();
- ContentType contentType = ContentType.getOrDefault(entity);
- Charset charset = contentType.getCharset();
- Reader reader = new InputStreamReader(entity.getContent(), charset);
- result = (Map<String, String>) gson.fromJson(reader, Object.class);
- }
- Assert.assertNotNull(result);
- Assert.assertEquals(2, result.size());
- } finally {
- if (response instanceof AutoCloseable) {
- ((AutoCloseable) response).close();
- }
- if (client instanceof AutoCloseable) {
- ((AutoCloseable) client).close();
- }
- }
- }
-
- private String readString(Reader reader) throws IOException {
+ /**
+ * Reads the content of a Reader into a String.
+ * @param reader the reader to read from
+ * @return the content as a String
+ * @throws IOException if an I/O error occurs
+ */
+ protected static String readString(Reader reader) throws IOException {
BufferedReader in = new BufferedReader(reader);
- String line = null;
+ String line;
StringBuilder rslt = new StringBuilder();
while ((line = in.readLine()) != null) {
rslt.append(line);
@@ -232,50 +171,38 @@ private String readString(Reader reader) throws
IOException {
return rslt.toString();
}
- @Test
- public void testServletEchoB() throws Exception {
- HttpClient client = HttpClients.createDefault();
- HttpResponse response = null;
- try {
- String jwt = generateJWT();
- String msgBody = "{\"method\":\"echo\"}";
- HttpPost post = createPost(jwt, msgBody);
-
- response = client.execute(post);
- Assert.assertEquals(HttpServletResponse.SC_OK,
response.getStatusLine().getStatusCode());
- String resp = null;
- HttpEntity entity = response.getEntity();
- if (entity != null) {
- ContentType contentType = ContentType.getOrDefault(entity);
- Charset charset = contentType.getCharset();
- Reader reader = new InputStreamReader(entity.getContent(), charset);
- resp = readString(reader);
- }
- Assert.assertNotNull(resp);
- Assert.assertEquals(msgBody, resp);
- } finally {
- if (response instanceof AutoCloseable) {
- ((AutoCloseable) response).close();
- }
- if (client instanceof AutoCloseable) {
- ((AutoCloseable) client).close();
+ /**
+ * Opens a connection to the given URL.
+ * <p>This handles setting a socket factory suitable for https/ssl tests.</p>
+ * @param url the URL to connect to
+ * @return the HttpURLConnection
+ * @throws IOException if an I/O error occurs
+ */
+ private HttpURLConnection openConnection(URL url) throws IOException {
+ HttpURLConnection con = (HttpURLConnection) url.openConnection();
+ if (con instanceof HttpsURLConnection httpsConnection) {
+ SSLContext sslContext = clientSSLContextFactory(conf);
+ if (sslContext != null) {
+ httpsConnection.setSSLSocketFactory(sslContext.getSocketFactory());
+ httpsConnection.setHostnameVerifier((hostname, session) -> true);
}
}
+ return con;
}
/**
* Performs a Json client call.
* @param jwt the jwt token
- * @param url the url
+ * @param uri the url
* @param method the http method
* @param arg the argument that will be transported as JSon
* @return the result the was returned through Json
* @throws IOException if marshalling the request/response fail
*/
- public static Object clientCall(String jwt, URL url, String method, Object
arg) throws IOException {
- HttpURLConnection con = (HttpURLConnection) url.openConnection();
+ public Object clientCall(String jwt, URI uri, String method, Object arg)
throws IOException {
+ final HttpURLConnection con = openConnection(uri.toURL());
con.setRequestMethod(method);
- con.setRequestProperty(MetaStoreUtils.USER_NAME_HTTP_HEADER,
url.getUserInfo());
+ con.setRequestProperty(MetaStoreUtils.USER_NAME_HTTP_HEADER,
uri.getUserInfo());
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Accept", "application/json");
if (jwt != null) {
@@ -290,29 +217,37 @@ public static Object clientCall(String jwt, URL url,
String method, Object arg)
int responseCode = con.getResponseCode();
if (responseCode == HttpServletResponse.SC_OK) {
try (Reader reader = new BufferedReader(
- new InputStreamReader(con.getInputStream(),
StandardCharsets.UTF_8))) {
+ new InputStreamReader(con.getInputStream(),
StandardCharsets.UTF_8))) {
return new Gson().fromJson(reader, Object.class);
}
}
return null;
}
- /**
- * Create a PostMethod populated with the expected attributes.
- * @param jwt the security token
- * @param msgBody the actual (json) payload
- * @return the method to be executed by a Http client
- * @throws Exception
- */
- private HttpPost createPost(String jwt, String msgBody) {
- HttpPost method = new HttpPost("http://hive@localhost:" + servletPort +
"/" + path + "/" + NS);
- method.addHeader("Authorization", "Bearer " + jwt);
- method.addHeader("Content-Type", "application/json");
- method.addHeader("Accept", "application/json");
+ @Test
+ public void testEcho() throws Exception {
+ String path = MetastoreConf.getVar(conf,
MetastoreConf.ConfVars.PROPERTIES_SERVLET_PATH);
+ String scheme = getScheme(conf);
+ URI uri = new URI(scheme + "://hive@localhost:" + servletPort + "/" + path
+ "/" + NS);
+ Map<String, String> json = Collections.singletonMap("method", "echo");
+ String jwt = generateJWT();
+ // succeed
+ Object response = clientCall(jwt, uri, "POST", json);
+ Assert.assertNotNull(response);
+ Assert.assertEquals(json, response);
+ // fail (bad jwt)
+ String badJwt = generateJWT(jwtUnauthorizedKeyFile.toPath());
+ response = clientCall(badJwt, uri, "POST", json);
+ Assert.assertNull(response);
+ }
- StringEntity sre = new StringEntity(msgBody, ContentType.APPLICATION_JSON);
- method.setEntity(sre);
- return method;
+ @Test
+ public void testProperties1() throws Exception {
+ runOtherProperties1(client);
}
+ @Test
+ public void testProperties0() throws Exception {
+ runOtherProperties0(client);
+ }
}
diff --git
a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSServletTestA.java
b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSJsonClientTest.java
similarity index 70%
rename from
standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSServletTestA.java
rename to
standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSJsonClientTest.java
index 3a8fb16028f..40b833842bc 100644
---
a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSServletTestA.java
+++
b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSJsonClientTest.java
@@ -20,37 +20,27 @@
import static com.github.tomakehurst.wiremock.client.WireMock.ok;
import java.nio.file.Files;
import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.hive.metastore.HiveMetaStore;
import org.apache.hadoop.hive.metastore.MetaStoreTestUtils;
import org.apache.hadoop.hive.metastore.annotation.MetastoreUnitTest;
import org.apache.hadoop.hive.metastore.conf.MetastoreConf;
-import org.apache.hadoop.hive.metastore.security.HadoopThriftAuthBridge;
-import org.junit.Assert;
import org.junit.experimental.categories.Category;
/**
* Test using the servlet server created by the MetaStore.
*/
@Category(MetastoreUnitTest.class)
-public class HMSServletTestA extends HMSServletTest {
+public class HMSJsonClientTest extends HMSJsonClientSslTest {
protected int thriftPort;
@Override
- protected int createServer(Configuration conf) throws Exception {
+ protected void setConf(Configuration conf) throws Exception {
MetastoreConf.setVar(conf, MetastoreConf.ConfVars.PROPERTIES_SERVLET_AUTH,
"JWT");
MetastoreConf.setLongVar(conf,
MetastoreConf.ConfVars.PROPERTIES_SERVLET_PORT, 0);
MetastoreConf.setVar(conf,
MetastoreConf.ConfVars.THRIFT_METASTORE_AUTHENTICATION_JWT_JWKS_URL,
- "http://localhost:" + MOCK_JWKS_SERVER_PORT + "/jwks");
+ "http://localhost:" + MOCK_JWKS_SERVER_PORT + "/jwks");
MOCK_JWKS_SERVER.stubFor(get("/jwks")
- .willReturn(ok()
- .withBody(Files.readAllBytes(jwtVerificationJWKSFile.toPath()))));
- thriftPort =
MetaStoreTestUtils.startMetaStoreWithRetry(HadoopThriftAuthBridge.getBridge(),
conf);
- servletServer = HiveMetaStore.getServletServer();
- if (servletServer == null || !servletServer.isStarted()) {
- Assert.fail("http server did not start");
- }
- servletPort = HiveMetaStore.getPropertyServletPort();
- return servletPort;
+ .willReturn(ok()
+
.withBody(Files.readAllBytes(jwtVerificationJWKSFile.toPath()))));
}
@Override
diff --git
a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSTestBase.java
b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSTestBase.java
index cded98bd07c..3a72e5a9712 100644
---
a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSTestBase.java
+++
b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/properties/HMSTestBase.java
@@ -29,10 +29,17 @@
import com.nimbusds.jwt.SignedJWT;
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -65,6 +72,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManagerFactory;
+
public abstract class HMSTestBase {
protected static final String baseDir = System.getProperty("basedir");
private static final File jwtAuthorizedKeyFile =
@@ -145,6 +156,80 @@ public synchronized void tearDown() throws Exception {
}
}
+ /**
+ * This is how we created a self-signed certificate for localhost needed for
https (ssl) configuration
+ * The keystore and truststore were generated using the following commands:
+ * % keytool -genkeypair -alias Hive -keyalg RSA -keysize 2048 -validity 3650
+ * -storetype PKCS12 -keystore hive_keystore.p12 -storepass apache
-keypass apache
+ * % keytool -export -alias Hive -file hive.crt -keystore hive_keystore.p12
-storepass apache
+ * % keytool -import -alias Hive -file hive.crt -keystore hive_truststore.p12
+ * -storepass apache -noprompt -storetype PKCS12
+ */
+ private static final String LOCALHOST_KEY_STORE_NAME = "hive_keystore.p12";
+ private static final String KEY_STORE_TRUST_STORE_PASSWORD = "apache";
+ private static final String TRUST_STORE_NAME = "hive_truststore.p12";
+ private static final String STORES_DIR = "src/test/resources";
+
+ /**
+ * Sets the metastore configuration to use SSL.
+ * This method adds configuration variables needed to use HTTPS with a
self-signed certificate.
+ * @param conf the configuration to set
+ */
+ public static void setHttpsConf(Configuration conf) {
+ MetastoreConf.setBoolVar(conf, MetastoreConf.ConfVars.USE_SSL, true);
+ MetastoreConf.setVar(conf, MetastoreConf.ConfVars.SSL_KEYSTORE_PATH,
+ STORES_DIR + File.separator + LOCALHOST_KEY_STORE_NAME);
+ MetastoreConf.setVar(conf, MetastoreConf.ConfVars.SSL_KEYSTORE_PASSWORD,
+ KEY_STORE_TRUST_STORE_PASSWORD);
+ MetastoreConf.setVar(conf, MetastoreConf.ConfVars.SSL_KEYSTORE_TYPE,
"PKCS12");
+ MetastoreConf.setVar(conf,
MetastoreConf.ConfVars.SSL_KEYMANAGERFACTORY_ALGORITHM,
+ KeyManagerFactory.getDefaultAlgorithm());
+ MetastoreConf.setVar(conf, MetastoreConf.ConfVars.SSL_TRUSTSTORE_PATH,
+ STORES_DIR + File.separator + TRUST_STORE_NAME);
+ MetastoreConf.setVar(conf, MetastoreConf.ConfVars.SSL_TRUSTSTORE_PASSWORD,
+ KEY_STORE_TRUST_STORE_PASSWORD);
+ LOG.info("Metastore SSL configuration set with keystore {} and truststore
{}",
+ MetastoreConf.getVar(conf,
MetastoreConf.ConfVars.SSL_KEYSTORE_PATH),
+ MetastoreConf.getVar(conf,
MetastoreConf.ConfVars.SSL_TRUSTSTORE_PATH));
+ }
+
+
+ /**
+ * Returns a client socket factory that uses the truststore defined in the
configuration.
+ * This is used to connect to the server using SSL.
+ * @return the SSLSocketFactory
+ */
+ protected static SSLContext clientSSLContextFactory(Configuration conf) {
+ try {
+ boolean sslEnabled = MetastoreConf.getBoolVar(conf,
MetastoreConf.ConfVars.USE_SSL);
+ if (!sslEnabled) {
+ // SSL is not enabled in configuration
+ return null;
+ }
+ LOG.info("Creating client SSLContext with truststore from
configuration");
+ String storePath = MetastoreConf.getVar(conf,
MetastoreConf.ConfVars.SSL_TRUSTSTORE_PATH);
+ if (storePath == null || storePath.isEmpty()) {
+ throw new IllegalArgumentException("SSL truststore path is not set in
configuration");
+ }
+ String password = MetastoreConf.getPassword(conf,
MetastoreConf.ConfVars.SSL_TRUSTSTORE_PASSWORD);
+ // Load custom truststore containing the server certificate
+ KeyStore trustStore = KeyStore.getInstance("PKCS12");
+ try (InputStream tsStream = Files.newInputStream(Paths.get(storePath))) {
+ trustStore.load(tsStream, password.toCharArray());
+ }
+ // Initialize TrustManager with the truststore
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(
+ TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init(trustStore);
+ // Create isolated SSLContext using only our truststore
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(null, tmf.getTrustManagers(), null);
+ return sslContext;
+ } catch (IOException | KeyStoreException | CertificateException |
KeyManagementException | NoSuchAlgorithmException e) {
+ throw new IllegalArgumentException("Client socket factory creation
failed", e);
+ }
+ }
+
protected String generateJWT() throws Exception {
return generateJWT(jwtAuthorizedKeyFile.toPath());
}
@@ -153,7 +238,7 @@ protected String generateJWT(Path path) throws Exception {
}
private static String generateJWT(String user, Path keyFile, long
lifeTimeMillis) throws Exception {
- RSAKey rsaKeyPair = RSAKey.parse(new
String(java.nio.file.Files.readAllBytes(keyFile), StandardCharsets.UTF_8));
+ RSAKey rsaKeyPair = RSAKey.parse(Files.readString(keyFile));
// Create RSA-signer with the private key
JWSSigner signer = new RSASSASigner(rsaKeyPair);
JWSHeader header = new JWSHeader
@@ -271,8 +356,7 @@ void runOtherProperties1(PropertyClient client) throws
Exception {
Assert.assertNotNull(maps);
Assert.assertEquals(5, maps.size());
- if (client instanceof HttpPropertyClient) {
- HttpPropertyClient httpClient = (HttpPropertyClient) client;
+ if (client instanceof HttpPropertyClient httpClient) {
// get fillfactors using getProperties, create args array from previous
result
List<String> keys = new ArrayList<>(maps.keySet());
keys.replaceAll(s -> s + ".fillFactor");
diff --git
a/standalone-metastore/metastore-server/src/test/resources/hive_keystore.p12
b/standalone-metastore/metastore-server/src/test/resources/hive_keystore.p12
new file mode 100644
index 00000000000..69347650a63
Binary files /dev/null and
b/standalone-metastore/metastore-server/src/test/resources/hive_keystore.p12
differ
diff --git
a/standalone-metastore/metastore-server/src/test/resources/hive_truststore.p12
b/standalone-metastore/metastore-server/src/test/resources/hive_truststore.p12
new file mode 100644
index 00000000000..847908d676d
Binary files /dev/null and
b/standalone-metastore/metastore-server/src/test/resources/hive_truststore.p12
differ