You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@asterixdb.apache.org by im...@apache.org on 2020/03/26 21:21:39 UTC

[asterixdb] branch master updated: [NO ISSUE] HTTP Basic Auth servlet wrapper

This is an automated email from the ASF dual-hosted git repository.

imaxon pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/asterixdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 694ffd1  [NO ISSUE] HTTP Basic Auth servlet wrapper
694ffd1 is described below

commit 694ffd194ce5c6e610f61368c1511778d0bff254
Author: Ian Maxon <ia...@maxons.email>
AuthorDate: Mon Mar 9 19:08:05 2020 -0700

    [NO ISSUE] HTTP Basic Auth servlet wrapper
    
    - Basic auth servlet that checks a /etc/passwd style file on the CC
    - Only enabled for UDF API servlet for now
    - Associated code in client helper for adding file to CC path
    - Config variable to manually set path if desired
    
    Change-Id: Ibea23a2e8308937f343d80eff04ede9a235aa0d1
    Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/5204
    Contrib: Jenkins <je...@fulliautomatix.ics.uci.edu>
    Integration-Tests: Jenkins <je...@fulliautomatix.ics.uci.edu>
    Tested-by: Jenkins <je...@fulliautomatix.ics.uci.edu>
    Reviewed-by: Michael Blow <mb...@apache.org>
---
 asterixdb/asterix-app/pom.xml                      |   8 ++
 .../asterix/api/http/server/BasicAuthServlet.java  | 105 +++++++++++++++++++++
 .../asterix/api/http/server/ServletConstants.java  |   1 +
 .../asterix/api/http/server/UdfApiServlet.java     |   3 +-
 .../asterix/hyracks/bootstrap/CCApplication.java   |  29 ++++++
 .../api/common/AsterixHyracksIntegrationUtil.java  |   8 +-
 .../asterix/app/external/ExternalUDFLibrarian.java |  38 ++++++--
 .../app/external/IExternalUDFLibrarian.java        |   7 +-
 .../apache/asterix/test/common/TestExecutor.java   |  13 ++-
 .../asterix/test/runtime/SqlppExecutionIT.java     |   2 +-
 asterixdb/asterix-app/src/test/resources/cc.conf   |   1 +
 .../deterministic/deterministic.1.lib.sqlpp        |   2 +-
 .../deterministic/deterministic.5.lib.sqlpp        |   2 +-
 .../getCapital/getCapital.1.lib.sqlpp              |   2 +-
 .../getCapital/getCapital.4.lib.sqlpp              |   2 +-
 .../getCapital_open/getCapital_open.1.lib.sqlpp    |   2 +-
 .../getCapital_open/getCapital_open.4.lib.sqlpp    |   2 +-
 .../keyword_detector/keyword_detector.1.lib.sqlpp  |   2 +-
 .../my_array_sum/my_array_sum.1.lib.sqlpp          |   2 +-
 .../my_array_sum/my_array_sum.4.lib.sqlpp          |   2 +-
 .../external-library/mysum/mysum.1.lib.sqlpp       |   2 +-
 .../external-library/mysum/mysum.7.lib.sqlpp       |   2 +-
 .../mysum_bad_credential.0.ddl.sqlpp}              |   3 +-
 .../mysum_bad_credential.1.lib.sqlpp}              |   2 +-
 .../mysum_bad_credential.2.lib.sqlpp}              |   2 +-
 .../mysum_bad_credential.3.lib.sqlpp}              |   2 +-
 .../mysum_bad_credential.4.lib.sqlpp}              |   2 +-
 .../mysum_bad_credential.5.lib.sqlpp}              |   2 +-
 .../mysum_bad_credential.6.lib.sqlpp}              |   2 +-
 .../return_invalid_type.1.lib.sqlpp                |   2 +-
 .../type_validation/type_validation.1.lib.sqlpp    |   2 +-
 .../type_validation/type_validation.4.lib.sqlpp    |   2 +-
 .../udf_filter_on_feed.3.lib.sqlpp                 |   2 +-
 .../udf_metadata/udf_metadata.1.lib.sqlpp          |   2 +-
 .../udf_metadata/udf_metadata.4.lib.sqlpp          |   2 +-
 .../upperCase/upperCase.1.lib.sqlpp                |   2 +-
 .../upperCase/upperCase.4.lib.sqlpp                |   2 +-
 .../feed-with-external-function.1.lib.sqlpp        |   2 +-
 .../feed-with-external-function.6.lib.sqlpp        |   2 +-
 ...ith-external-parser-with-open-index.2.lib.sqlpp |   2 +-
 ...ith-external-parser-with-open-index.6.lib.sqlpp |   2 +-
 ...ternal-parser-with-two-open-indexes.2.lib.sqlpp |   2 +-
 ...ternal-parser-with-two-open-indexes.6.lib.sqlpp |   2 +-
 .../feed-with-external-parser.2.lib.sqlpp          |   2 +-
 .../feed-with-external-parser.6.lib.sqlpp          |   2 +-
 .../feed-with-multiple-indexes.2.lib.sqlpp         |   2 +-
 .../feed-with-multiple-indexes.6.lib.sqlpp         |   2 +-
 .../resources/runtimets/testsuite_it_sqlpp.xml     |   9 ++
 .../asterix-app/src/test/resources/security/passwd |   1 +
 asterixdb/asterix-client-helper/pom.xml            |  12 +++
 .../java/org/apache/asterix/clienthelper/Args.java |  21 +++++
 .../clienthelper/AsterixHelperExecution.java       |   3 +
 .../clienthelper/commands/ClientCommand.java       |   5 +-
 .../commands/GenerateCredentialCommand.java        |  57 +++++++++++
 .../asterix/common/config/ExternalProperties.java  |  17 +++-
 asterixdb/asterix-server/pom.xml                   |  10 ++
 asterixdb/pom.xml                                  |  10 ++
 .../appended-resources/supplemental-models.xml     |  12 +++
 .../opensource.org_licenses_isc-license.txt        |   3 +
 .../www.mindrot.org_files_jBCrypt_LICENSE.txt      |  17 ++++
 .../control/common/controllers/CCConfig.java       |   1 +
 61 files changed, 405 insertions(+), 61 deletions(-)

diff --git a/asterixdb/asterix-app/pom.xml b/asterixdb/asterix-app/pom.xml
index ac2c303..e39bb1f 100644
--- a/asterixdb/asterix-app/pom.xml
+++ b/asterixdb/asterix-app/pom.xml
@@ -699,5 +699,13 @@
         </exclusion>
       </exclusions>
     </dependency>
+    <dependency>
+      <groupId>org.mindrot</groupId>
+      <artifactId>jbcrypt</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-csv</artifactId>
+    </dependency>
   </dependencies>
 </project>
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/BasicAuthServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/BasicAuthServlet.java
new file mode 100644
index 0000000..bac8d66
--- /dev/null
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/BasicAuthServlet.java
@@ -0,0 +1,105 @@
+/*
+ * 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.asterix.api.http.server;
+
+import static org.apache.asterix.api.http.server.ServletConstants.CREDENTIAL_MAP;
+
+import java.util.Base64;
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.hyracks.http.api.IServletRequest;
+import org.apache.hyracks.http.api.IServletResponse;
+import org.apache.hyracks.http.server.AbstractServlet;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.mindrot.jbcrypt.BCrypt;
+
+import io.netty.handler.codec.http.HttpHeaderNames;
+import io.netty.handler.codec.http.HttpResponseStatus;
+
+public abstract class BasicAuthServlet extends AbstractServlet {
+
+    private static final Logger LOGGER = LogManager.getLogger();
+    public static String BASIC_AUTH_METHOD_NAME = "Basic";
+    private Base64.Decoder b64Decoder;
+    Map<String, String> storedCredentials;
+
+    protected BasicAuthServlet(ConcurrentMap<String, Object> ctx, String... paths) {
+        super(ctx, paths);
+        b64Decoder = Base64.getDecoder();
+        storedCredentials = (Map<String, String>) ctx.get(CREDENTIAL_MAP);
+    }
+
+    @Override
+    public void handle(IServletRequest request, IServletResponse response) {
+
+        try {
+            boolean authorized = authorize(request);
+            if (!authorized) {
+                response.setStatus(HttpResponseStatus.UNAUTHORIZED);
+            } else {
+                super.handle(request, response);
+            }
+        } catch (Exception e) {
+            LOGGER.log(Level.WARN, "Unhandled exception", e);
+            response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
+        } catch (Throwable th) { //NOSONAR Just logging and then throwing again
+            try {
+                LOGGER.log(Level.WARN, "Unhandled throwable", th);
+            } catch (Throwable loggingFailure) {// NOSONAR... swallow logging failure
+            }
+            throw th;
+        }
+    }
+
+    private boolean authorize(IServletRequest request) {
+        String authVal = request.getHeader(HttpHeaderNames.AUTHORIZATION);
+        if (authVal == null) {
+            LOGGER.debug("Request missing Authorization header");
+            return false;
+        }
+        String[] authString = authVal.split(" ");
+        if (!BASIC_AUTH_METHOD_NAME.equals(authString[0]) || authString.length != 2) {
+            LOGGER.debug("Malformed Authorization header or unsupported Authentication method");
+            return false;
+        }
+        String credentialEncoded = authString[1];
+        String credential = new String(b64Decoder.decode(credentialEncoded));
+        String[] providedCredentials = credential.split(":");
+        if (providedCredentials.length != 2) {
+            LOGGER.debug("Invalid Basic credential format");
+            return false;
+        }
+        String providedUsername = providedCredentials[0];
+        String storedPw = storedCredentials.get(providedUsername);
+        if (storedPw == null) {
+            LOGGER.debug("Invalid username");
+            return false;
+        }
+        String givenPw = providedCredentials[1];
+        if (BCrypt.checkpw(givenPw, storedPw)) {
+            return true;
+        } else {
+            LOGGER.debug("Wrong password for user " + providedUsername);
+            return false;
+        }
+    }
+}
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ServletConstants.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ServletConstants.java
index f62d0c4..857faf0 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ServletConstants.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ServletConstants.java
@@ -25,6 +25,7 @@ public class ServletConstants {
     public static final String EXECUTOR_SERVICE_ATTR = "org.apache.asterix.EXECUTOR_SERVICE";
     public static final String RUNNING_QUERIES_ATTR = "org.apache.asterix.RUNINNG_QUERIES";
     public static final String SERVICE_CONTEXT_ATTR = "org.apache.asterix.SERVICE_CONTEXT";
+    public static final String CREDENTIAL_MAP = "org.apache.asterix.CREDENTIAL_MAP";
 
     private ServletConstants() {
     }
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/UdfApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/UdfApiServlet.java
index c3d6877..54a62df 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/UdfApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/UdfApiServlet.java
@@ -39,7 +39,6 @@ import org.apache.hyracks.api.client.IHyracksClientConnection;
 import org.apache.hyracks.api.deployment.DeploymentId;
 import org.apache.hyracks.http.api.IServletRequest;
 import org.apache.hyracks.http.api.IServletResponse;
-import org.apache.hyracks.http.server.AbstractServlet;
 import org.apache.hyracks.util.file.FileUtil;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -49,7 +48,7 @@ import io.netty.handler.codec.http.FullHttpRequest;
 import io.netty.handler.codec.http.HttpResponseStatus;
 import io.netty.handler.codec.http.QueryStringDecoder;
 
-public class UdfApiServlet extends AbstractServlet {
+public class UdfApiServlet extends BasicAuthServlet {
 
     private static final Logger LOGGER = LogManager.getLogger();
     private final ICcApplicationContext appCtx;
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java
index 13027ec..bc10d4f 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java
@@ -25,10 +25,14 @@ import static org.apache.asterix.api.http.server.ServletConstants.ASTERIX_APP_CO
 import static org.apache.asterix.api.http.server.ServletConstants.HYRACKS_CONNECTION_ATTR;
 import static org.apache.asterix.common.api.IClusterManagementWork.ClusterState.SHUTTING_DOWN;
 
+import java.io.File;
 import java.io.IOException;
+import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.ServiceLoader;
 import java.util.concurrent.ConcurrentMap;
 
@@ -86,6 +90,9 @@ import org.apache.asterix.runtime.utils.CcApplicationContext;
 import org.apache.asterix.translator.IStatementExecutorFactory;
 import org.apache.asterix.translator.Receptionist;
 import org.apache.asterix.util.MetadataBuiltinFunctions;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVParser;
+import org.apache.commons.csv.CSVRecord;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
 import org.apache.hyracks.api.application.IServiceContext;
 import org.apache.hyracks.api.client.IHyracksClientConnection;
@@ -181,6 +188,26 @@ public class CCApplication extends BaseCCApplication {
         jobCapacityController = new JobCapacityController(controllerService.getResourceManager());
     }
 
+    private Map<String, String> parseCredentialMap(String credPath) {
+        File credentialFile = new File(credPath);
+        Map<String, String> storedCredentials = new HashMap<>();
+        if (credentialFile.exists()) {
+            try (CSVParser p =
+                    CSVParser.parse(credentialFile, Charset.defaultCharset(), CSVFormat.DEFAULT.withDelimiter(':'))) {
+                List<CSVRecord> recs = p.getRecords();
+                for (CSVRecord r : recs) {
+                    if (r.size() != 2) {
+                        throw new IOException("Passwd file must have exactly two fields.");
+                    }
+                    storedCredentials.put(r.get(0), r.get(1));
+                }
+            } catch (IOException e) {
+                LOGGER.error("Malformed credential file", e);
+            }
+        }
+        return storedCredentials;
+    }
+
     protected ICcApplicationContext createApplicationContext(ILibraryManager libraryManager,
             IGlobalRecoveryManager globalRecoveryManager, INcLifecycleCoordinator lifecycleCoordinator,
             IReceptionistFactory receptionistFactory, IConfigValidatorFactory configValidatorFactory,
@@ -250,6 +277,8 @@ public class CCApplication extends BaseCCApplication {
         jsonAPIServer.setAttribute(ServletConstants.EXECUTOR_SERVICE_ATTR,
                 ccServiceCtx.getControllerService().getExecutor());
         jsonAPIServer.setAttribute(ServletConstants.SERVICE_CONTEXT_ATTR, ccServiceCtx);
+        jsonAPIServer.setAttribute(ServletConstants.CREDENTIAL_MAP,
+                parseCredentialMap(externalProperties.getCredentialFilePath()));
 
         // Other APIs.
         addServlet(jsonAPIServer, Servlets.QUERY_STATUS);
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/api/common/AsterixHyracksIntegrationUtil.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/api/common/AsterixHyracksIntegrationUtil.java
index df16daf..1079fb8 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/api/common/AsterixHyracksIntegrationUtil.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/api/common/AsterixHyracksIntegrationUtil.java
@@ -34,7 +34,6 @@ import java.util.concurrent.TimeUnit;
 import java.util.function.BiPredicate;
 import java.util.stream.Stream;
 
-import org.apache.asterix.app.external.ExternalUDFLibrarian;
 import org.apache.asterix.app.io.PersistedResourceRegistry;
 import org.apache.asterix.common.api.IClusterManagementWork.ClusterState;
 import org.apache.asterix.common.api.INcApplicationContext;
@@ -109,7 +108,7 @@ public class AsterixHyracksIntegrationUtil {
         AsterixHyracksIntegrationUtil integrationUtil = new AsterixHyracksIntegrationUtil();
         try {
             integrationUtil.run(Boolean.getBoolean("cleanup.start"), Boolean.getBoolean("cleanup.shutdown"),
-                    System.getProperty("external.lib", ""), System.getProperty("conf.path", DEFAULT_CONF_FILE));
+                    System.getProperty("conf.path", DEFAULT_CONF_FILE));
         } catch (Exception e) {
             LOGGER.fatal("Unexpected exception", e);
             System.exit(1);
@@ -197,7 +196,6 @@ public class AsterixHyracksIntegrationUtil {
 
     public void init(boolean deleteOldInstanceData, String externalLibPath, String confDir) throws Exception {
         List<ILibraryManager> libraryManagers = new ArrayList<>();
-        ExternalUDFLibrarian librarian = new ExternalUDFLibrarian();
         init(deleteOldInstanceData, confDir);
         if (externalLibPath != null && externalLibPath.length() != 0) {
             libraryManagers.add(((ICcApplicationContext) cc.getApplicationContext()).getLibraryManager());
@@ -205,8 +203,6 @@ public class AsterixHyracksIntegrationUtil {
                 INcApplicationContext runtimeCtx = (INcApplicationContext) nc.getApplicationContext();
                 libraryManagers.add(runtimeCtx.getLibraryManager());
             }
-            librarian.install(System.getProperty("external.lib.dataverse", "test"),
-                    System.getProperty("external.lib.libname", "testlib"), externalLibPath);
         }
     }
 
@@ -359,7 +355,7 @@ public class AsterixHyracksIntegrationUtil {
             }
         });
 
-        init(cleanupOnStart, loadExternalLibs, confFile);
+        init(cleanupOnStart, confFile);
         while (true) {
             Thread.sleep(10000);
         }
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/external/ExternalUDFLibrarian.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/app/external/ExternalUDFLibrarian.java
similarity index 60%
rename from asterixdb/asterix-app/src/main/java/org/apache/asterix/app/external/ExternalUDFLibrarian.java
rename to asterixdb/asterix-app/src/test/java/org/apache/asterix/app/external/ExternalUDFLibrarian.java
index 86588ea..fd40a01 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/external/ExternalUDFLibrarian.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/app/external/ExternalUDFLibrarian.java
@@ -23,13 +23,22 @@ import java.io.IOException;
 import java.net.URL;
 
 import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.http.HttpHost;
 import org.apache.http.HttpResponse;
-import org.apache.http.client.ClientProtocolException;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.AuthCache;
+import org.apache.http.client.CredentialsProvider;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpDelete;
 import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.http.entity.FileEntity;
+import org.apache.http.impl.auth.BasicScheme;
+import org.apache.http.impl.client.BasicAuthCache;
+import org.apache.http.impl.client.BasicCredentialsProvider;
 import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.hyracks.algebricks.common.utils.Pair;
 import org.apache.hyracks.api.exceptions.HyracksException;
 
 @SuppressWarnings("squid:S134")
@@ -50,11 +59,20 @@ public class ExternalUDFLibrarian implements IExternalUDFLibrarian {
     }
 
     @Override
-    public void install(String dataverse, String libName, String libPath) throws Exception {
+    public void install(String dataverse, String libName, String libPath, Pair<String, String> credentials)
+            throws Exception {
         URL url = new URL("http", host, port, "/admin/udf/" + dataverse + "/" + libName);
+        HttpHost h = new HttpHost(host, port, "http");
         HttpPost post = new HttpPost(url.toString());
+        CredentialsProvider cp = new BasicCredentialsProvider();
+        cp.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(credentials.first, credentials.second));
+        HttpClientContext hcCtx = HttpClientContext.create();
+        hcCtx.setCredentialsProvider(cp);
+        AuthCache ac = new BasicAuthCache();
+        ac.put(h, new BasicScheme());
+        hcCtx.setAuthCache(ac);
         post.setEntity(new FileEntity(new File(libPath), "application/octet-stream"));
-        HttpResponse response = hc.execute(post);
+        HttpResponse response = hc.execute(post, hcCtx);
         response.getEntity().consumeContent();
         if (response.getStatusLine().getStatusCode() != 200) {
             throw new HyracksException(response.getStatusLine().toString());
@@ -62,11 +80,19 @@ public class ExternalUDFLibrarian implements IExternalUDFLibrarian {
     }
 
     @Override
-    public void uninstall(String dataverse, String libName)
-            throws IOException, ClientProtocolException, AsterixException {
+    public void uninstall(String dataverse, String libName, Pair<String, String> credentials)
+            throws IOException, AsterixException {
         URL url = new URL("http", host, port, "/admin/udf/" + dataverse + "/" + libName);
+        CredentialsProvider cp = new BasicCredentialsProvider();
+        cp.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(credentials.first, credentials.second));
+        HttpClientContext hcCtx = HttpClientContext.create();
+        hcCtx.setCredentialsProvider(cp);
+        HttpHost h = new HttpHost(host, port, "http");
+        AuthCache ac = new BasicAuthCache();
+        ac.put(h, new BasicScheme());
+        hcCtx.setAuthCache(ac);
         HttpDelete del = new HttpDelete(url.toString());
-        HttpResponse response = hc.execute(del);
+        HttpResponse response = hc.execute(del, hcCtx);
         response.getEntity().consumeContent();
         if (response.getStatusLine().getStatusCode() != 200) {
             throw new AsterixException(response.getStatusLine().toString());
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/external/IExternalUDFLibrarian.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/app/external/IExternalUDFLibrarian.java
similarity index 80%
rename from asterixdb/asterix-app/src/main/java/org/apache/asterix/app/external/IExternalUDFLibrarian.java
rename to asterixdb/asterix-app/src/test/java/org/apache/asterix/app/external/IExternalUDFLibrarian.java
index a7a668a..1933f24 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/external/IExternalUDFLibrarian.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/app/external/IExternalUDFLibrarian.java
@@ -21,10 +21,11 @@ package org.apache.asterix.app.external;
 import java.io.IOException;
 
 import org.apache.asterix.common.exceptions.AsterixException;
-import org.apache.http.client.ClientProtocolException;
+import org.apache.hyracks.algebricks.common.utils.Pair;
 
 public interface IExternalUDFLibrarian {
-    void install(String dataverse, String libName, String libPath) throws Exception;
+    void install(String dataverse, String libName, String libPath, Pair<String, String> credentials) throws Exception;
 
-    void uninstall(String dataverse, String libName) throws IOException, ClientProtocolException, AsterixException;
+    void uninstall(String dataverse, String libName, Pair<String, String> credentials)
+            throws IOException, AsterixException;
 }
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
index 7ee499e..cedcc7f 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
@@ -109,6 +109,7 @@ import org.apache.http.impl.client.HttpClients;
 import org.apache.http.impl.client.StandardHttpRequestRetryHandler;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.util.EntityUtils;
+import org.apache.hyracks.algebricks.common.utils.Pair;
 import org.apache.hyracks.http.server.utils.HttpUtil;
 import org.apache.hyracks.util.StorageUtil;
 import org.apache.logging.log4j.Level;
@@ -1200,19 +1201,21 @@ public class TestExecutor {
                 }
                 String dataverse = command[1];
                 String library = command[2];
+                String username = command[3];
+                String pw = command[4];
                 switch (command[0]) {
                     case "install":
-                        if (command.length != 4) {
+                        if (command.length != 6) {
                             throw new Exception("invalid library format");
                         }
-                        String libPath = command[3];
-                        librarian.install(dataverse, library, libPath);
+                        String libPath = command[5];
+                        librarian.install(dataverse, library, libPath, new Pair(username, pw));
                         break;
                     case "uninstall":
-                        if (command.length != 3) {
+                        if (command.length != 5) {
                             throw new Exception("invalid library format");
                         }
-                        librarian.uninstall(dataverse, library);
+                        librarian.uninstall(dataverse, library, new Pair(username, pw));
                         break;
                     default:
                         throw new Exception("invalid library format");
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/SqlppExecutionIT.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/SqlppExecutionIT.java
index 334d6df..39f0948 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/SqlppExecutionIT.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/SqlppExecutionIT.java
@@ -35,7 +35,7 @@ import org.junit.runners.Parameterized.Parameters;
  */
 @RunWith(Parameterized.class)
 public class SqlppExecutionIT {
-    protected static final String TEST_CONFIG_FILE_NAME = "src/main/resources/cc.conf";
+    protected static final String TEST_CONFIG_FILE_NAME = "src/test/resources/cc.conf";
 
     @BeforeClass
     public static void setUp() throws Exception {
diff --git a/asterixdb/asterix-app/src/test/resources/cc.conf b/asterixdb/asterix-app/src/test/resources/cc.conf
index 10c0b99..a113e3a 100644
--- a/asterixdb/asterix-app/src/test/resources/cc.conf
+++ b/asterixdb/asterix-app/src/test/resources/cc.conf
@@ -44,6 +44,7 @@ address = 127.0.0.1
 app.class=org.apache.asterix.hyracks.bootstrap.CCApplication
 heartbeat.period=2000
 heartbeat.max.misses=25
+credential.file=src/test/resources/security/passwd
 
 [common]
 log.dir = logs/
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/deterministic/deterministic.1.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/deterministic/deterministic.1.lib.sqlpp
index d1e0e87..592653c 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/deterministic/deterministic.1.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/deterministic/deterministic.1.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-install externallibtest testlib target/data/externallib/asterix-external-data-testlib.zip
\ No newline at end of file
+install externallibtest testlib admin admin target/data/externallib/asterix-external-data-testlib.zip
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/deterministic/deterministic.5.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/deterministic/deterministic.5.lib.sqlpp
index 86af80f..172bed4 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/deterministic/deterministic.5.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/deterministic/deterministic.5.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-uninstall externallibtest testlib
\ No newline at end of file
+uninstall externallibtest testlib admin admin
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.1.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.1.lib.sqlpp
index d1e0e87..3dc6eb6 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.1.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.1.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-install externallibtest testlib target/data/externallib/asterix-external-data-testlib.zip
\ No newline at end of file
+install externallibtest testlib admin admin target/data/externallib/asterix-external-data-testlib.zip
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp
index 86af80f..41880cb 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-uninstall externallibtest testlib
\ No newline at end of file
+uninstall externallibtest testlib admin admin
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital_open/getCapital_open.1.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital_open/getCapital_open.1.lib.sqlpp
index d1e0e87..3dc6eb6 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital_open/getCapital_open.1.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital_open/getCapital_open.1.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-install externallibtest testlib target/data/externallib/asterix-external-data-testlib.zip
\ No newline at end of file
+install externallibtest testlib admin admin target/data/externallib/asterix-external-data-testlib.zip
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital_open/getCapital_open.4.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital_open/getCapital_open.4.lib.sqlpp
index 86af80f..41880cb 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital_open/getCapital_open.4.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital_open/getCapital_open.4.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-uninstall externallibtest testlib
\ No newline at end of file
+uninstall externallibtest testlib admin admin
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/keyword_detector/keyword_detector.1.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/keyword_detector/keyword_detector.1.lib.sqlpp
index dbdfe16..63efff4 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/keyword_detector/keyword_detector.1.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/keyword_detector/keyword_detector.1.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-install test testlib target/data/externallib/asterix-external-data-testlib.zip
\ No newline at end of file
+install test testlib admin admin target/data/externallib/asterix-external-data-testlib.zip
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/my_array_sum/my_array_sum.1.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/my_array_sum/my_array_sum.1.lib.sqlpp
index d1e0e87..3dc6eb6 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/my_array_sum/my_array_sum.1.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/my_array_sum/my_array_sum.1.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-install externallibtest testlib target/data/externallib/asterix-external-data-testlib.zip
\ No newline at end of file
+install externallibtest testlib admin admin target/data/externallib/asterix-external-data-testlib.zip
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/my_array_sum/my_array_sum.4.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/my_array_sum/my_array_sum.4.lib.sqlpp
index 86af80f..41880cb 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/my_array_sum/my_array_sum.4.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/my_array_sum/my_array_sum.4.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-uninstall externallibtest testlib
\ No newline at end of file
+uninstall externallibtest testlib admin admin
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum/mysum.1.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum/mysum.1.lib.sqlpp
index d1e0e87..3dc6eb6 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum/mysum.1.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum/mysum.1.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-install externallibtest testlib target/data/externallib/asterix-external-data-testlib.zip
\ No newline at end of file
+install externallibtest testlib admin admin target/data/externallib/asterix-external-data-testlib.zip
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum/mysum.7.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum/mysum.7.lib.sqlpp
index 86af80f..41880cb 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum/mysum.7.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum/mysum.7.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-uninstall externallibtest testlib
\ No newline at end of file
+uninstall externallibtest testlib admin admin
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum_bad_credential/mysum_bad_credential.0.ddl.sqlpp
similarity index 91%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum_bad_credential/mysum_bad_credential.0.ddl.sqlpp
index 86af80f..76cc70d 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum_bad_credential/mysum_bad_credential.0.ddl.sqlpp
@@ -16,4 +16,5 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-uninstall externallibtest testlib
\ No newline at end of file
+DROP DATAVERSE externallibtest if exists;
+CREATE DATAVERSE  externallibtest;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum_bad_credential/mysum_bad_credential.1.lib.sqlpp
similarity index 88%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum_bad_credential/mysum_bad_credential.1.lib.sqlpp
index 86af80f..c825a93 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum_bad_credential/mysum_bad_credential.1.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-uninstall externallibtest testlib
\ No newline at end of file
+install externallibtest testlib admin bad target/data/externallib/asterix-external-data-testlib.zip
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum_bad_credential/mysum_bad_credential.2.lib.sqlpp
similarity index 88%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum_bad_credential/mysum_bad_credential.2.lib.sqlpp
index 86af80f..35d6ef8 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum_bad_credential/mysum_bad_credential.2.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-uninstall externallibtest testlib
\ No newline at end of file
+install externallibtest testlib root admin target/data/externallib/asterix-external-data-testlib.zip
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum_bad_credential/mysum_bad_credential.3.lib.sqlpp
similarity index 88%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum_bad_credential/mysum_bad_credential.3.lib.sqlpp
index 86af80f..3dc6eb6 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum_bad_credential/mysum_bad_credential.3.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-uninstall externallibtest testlib
\ No newline at end of file
+install externallibtest testlib admin admin target/data/externallib/asterix-external-data-testlib.zip
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum_bad_credential/mysum_bad_credential.4.lib.sqlpp
similarity index 94%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum_bad_credential/mysum_bad_credential.4.lib.sqlpp
index 86af80f..4b33ef4 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum_bad_credential/mysum_bad_credential.4.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-uninstall externallibtest testlib
\ No newline at end of file
+uninstall externallibtest testlib admin bad
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum_bad_credential/mysum_bad_credential.5.lib.sqlpp
similarity index 94%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum_bad_credential/mysum_bad_credential.5.lib.sqlpp
index 86af80f..1b1b20e 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum_bad_credential/mysum_bad_credential.5.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-uninstall externallibtest testlib
\ No newline at end of file
+uninstall externallibtest testlib root admin
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum_bad_credential/mysum_bad_credential.6.lib.sqlpp
similarity index 94%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum_bad_credential/mysum_bad_credential.6.lib.sqlpp
index 86af80f..41880cb 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/getCapital/getCapital.4.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/mysum_bad_credential/mysum_bad_credential.6.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-uninstall externallibtest testlib
\ No newline at end of file
+uninstall externallibtest testlib admin admin
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/return_invalid_type/return_invalid_type.1.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/return_invalid_type/return_invalid_type.1.lib.sqlpp
index d1e0e87..3dc6eb6 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/return_invalid_type/return_invalid_type.1.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/return_invalid_type/return_invalid_type.1.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-install externallibtest testlib target/data/externallib/asterix-external-data-testlib.zip
\ No newline at end of file
+install externallibtest testlib admin admin target/data/externallib/asterix-external-data-testlib.zip
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/type_validation/type_validation.1.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/type_validation/type_validation.1.lib.sqlpp
index 25aff38..6bbdd0e 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/type_validation/type_validation.1.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/type_validation/type_validation.1.lib.sqlpp
@@ -17,4 +17,4 @@
  * under the License.
  */
 
-install externallibtest testlib target/data/externallib/asterix-external-data-testlib.zip
\ No newline at end of file
+install externallibtest testlib admin admin target/data/externallib/asterix-external-data-testlib.zip
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/type_validation/type_validation.4.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/type_validation/type_validation.4.lib.sqlpp
index ffde186..e44b339 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/type_validation/type_validation.4.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/type_validation/type_validation.4.lib.sqlpp
@@ -17,4 +17,4 @@
  * under the License.
  */
 
-uninstall externallibtest testlib
\ No newline at end of file
+uninstall externallibtest testlib admin admin
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_filter_on_feed/udf_filter_on_feed.3.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_filter_on_feed/udf_filter_on_feed.3.lib.sqlpp
index dbdfe16..63efff4 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_filter_on_feed/udf_filter_on_feed.3.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_filter_on_feed/udf_filter_on_feed.3.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-install test testlib target/data/externallib/asterix-external-data-testlib.zip
\ No newline at end of file
+install test testlib admin admin target/data/externallib/asterix-external-data-testlib.zip
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.1.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.1.lib.sqlpp
index d1e0e87..3dc6eb6 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.1.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.1.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-install externallibtest testlib target/data/externallib/asterix-external-data-testlib.zip
\ No newline at end of file
+install externallibtest testlib admin admin target/data/externallib/asterix-external-data-testlib.zip
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.4.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.4.lib.sqlpp
index 86af80f..41880cb 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.4.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.4.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-uninstall externallibtest testlib
\ No newline at end of file
+uninstall externallibtest testlib admin admin
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/upperCase/upperCase.1.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/upperCase/upperCase.1.lib.sqlpp
index d1e0e87..3dc6eb6 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/upperCase/upperCase.1.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/upperCase/upperCase.1.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-install externallibtest testlib target/data/externallib/asterix-external-data-testlib.zip
\ No newline at end of file
+install externallibtest testlib admin admin target/data/externallib/asterix-external-data-testlib.zip
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/upperCase/upperCase.4.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/upperCase/upperCase.4.lib.sqlpp
index 86af80f..41880cb 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/upperCase/upperCase.4.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/upperCase/upperCase.4.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-uninstall externallibtest testlib
\ No newline at end of file
+uninstall externallibtest testlib admin admin
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-function/feed-with-external-function.1.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-function/feed-with-external-function.1.lib.sqlpp
index 4f0c6d3..f3ea94f 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-function/feed-with-external-function.1.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-function/feed-with-external-function.1.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-install udfs testlib target/data/externallib/asterix-external-data-testlib.zip
\ No newline at end of file
+install udfs testlib admin admin target/data/externallib/asterix-external-data-testlib.zip
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-function/feed-with-external-function.6.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-function/feed-with-external-function.6.lib.sqlpp
index 98c334d..6b2fb1f 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-function/feed-with-external-function.6.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-function/feed-with-external-function.6.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-uninstall udfs testlib
\ No newline at end of file
+uninstall udfs testlib admin admin
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser-with-open-index/feed-with-external-parser-with-open-index.2.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser-with-open-index/feed-with-external-parser-with-open-index.2.lib.sqlpp
index 8dc902b..31bef13 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser-with-open-index/feed-with-external-parser-with-open-index.2.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser-with-open-index/feed-with-external-parser-with-open-index.2.lib.sqlpp
@@ -23,4 +23,4 @@
  * Expected Res : Success
  * Date         : Jul, 13, 2016
  */
-install externallibtest testlib target/data/externallib/asterix-external-data-testlib.zip
\ No newline at end of file
+install externallibtest testlib admin admin target/data/externallib/asterix-external-data-testlib.zip
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser-with-open-index/feed-with-external-parser-with-open-index.6.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser-with-open-index/feed-with-external-parser-with-open-index.6.lib.sqlpp
index 335f375..ddb0a3b 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser-with-open-index/feed-with-external-parser-with-open-index.6.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser-with-open-index/feed-with-external-parser-with-open-index.6.lib.sqlpp
@@ -23,4 +23,4 @@
  * Expected Res : Success
  * Date         : Jul, 13, 2016
  */
-uninstall externallibtest testlib
\ No newline at end of file
+uninstall externallibtest testlib admin admin
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser-with-two-open-indexes/feed-with-external-parser-with-two-open-indexes.2.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser-with-two-open-indexes/feed-with-external-parser-with-two-open-indexes.2.lib.sqlpp
index 99ccec3..f6d6e10 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser-with-two-open-indexes/feed-with-external-parser-with-two-open-indexes.2.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser-with-two-open-indexes/feed-with-external-parser-with-two-open-indexes.2.lib.sqlpp
@@ -23,4 +23,4 @@
  * Expected Res : Success
  * Date         : Jul, 13, 2016
  */
-install externallibtest testlib target/data/externallib/asterix-external-data-testlib.zip
\ No newline at end of file
+install externallibtest testlib admin admin target/data/externallib/asterix-external-data-testlib.zip
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser-with-two-open-indexes/feed-with-external-parser-with-two-open-indexes.6.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser-with-two-open-indexes/feed-with-external-parser-with-two-open-indexes.6.lib.sqlpp
index d972079..be87a91 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser-with-two-open-indexes/feed-with-external-parser-with-two-open-indexes.6.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser-with-two-open-indexes/feed-with-external-parser-with-two-open-indexes.6.lib.sqlpp
@@ -23,4 +23,4 @@
  * Expected Res : Success
  * Date         : Jul, 13, 2016
  */
-uninstall externallibtest testlib
\ No newline at end of file
+uninstall externallibtest testlib admin admin
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser/feed-with-external-parser.2.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser/feed-with-external-parser.2.lib.sqlpp
index d1e0e87..3dc6eb6 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser/feed-with-external-parser.2.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser/feed-with-external-parser.2.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-install externallibtest testlib target/data/externallib/asterix-external-data-testlib.zip
\ No newline at end of file
+install externallibtest testlib admin admin target/data/externallib/asterix-external-data-testlib.zip
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser/feed-with-external-parser.6.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser/feed-with-external-parser.6.lib.sqlpp
index 86af80f..41880cb 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser/feed-with-external-parser.6.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-external-parser/feed-with-external-parser.6.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-uninstall externallibtest testlib
\ No newline at end of file
+uninstall externallibtest testlib admin admin
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-multiple-indexes/feed-with-multiple-indexes.2.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-multiple-indexes/feed-with-multiple-indexes.2.lib.sqlpp
index d1e0e87..3dc6eb6 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-multiple-indexes/feed-with-multiple-indexes.2.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-multiple-indexes/feed-with-multiple-indexes.2.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-install externallibtest testlib target/data/externallib/asterix-external-data-testlib.zip
\ No newline at end of file
+install externallibtest testlib admin admin target/data/externallib/asterix-external-data-testlib.zip
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-multiple-indexes/feed-with-multiple-indexes.6.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-multiple-indexes/feed-with-multiple-indexes.6.lib.sqlpp
index 86af80f..41880cb 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-multiple-indexes/feed-with-multiple-indexes.6.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/feeds/feed-with-multiple-indexes/feed-with-multiple-indexes.6.lib.sqlpp
@@ -16,4 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-uninstall externallibtest testlib
\ No newline at end of file
+uninstall externallibtest testlib admin admin
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_it_sqlpp.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_it_sqlpp.xml
index 31b1c13..91d4969 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_it_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_it_sqlpp.xml
@@ -35,6 +35,15 @@
       </compilation-unit>
     </test-case>
     <test-case FilePath="external-library">
+      <compilation-unit name="mysum_bad_credential">
+        <output-dir compare="Text">mysum_bad_credential</output-dir>
+        <expected-error>HTTP/1.1 401 Unauthorized</expected-error>
+        <expected-error>HTTP/1.1 401 Unauthorized</expected-error>
+        <expected-error>HTTP/1.1 401 Unauthorized</expected-error>
+        <expected-error>HTTP/1.1 401 Unauthorized</expected-error>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="external-library">
       <compilation-unit name="my_array_sum">
         <output-dir compare="Text">my_array_sum</output-dir>
       </compilation-unit>
diff --git a/asterixdb/asterix-app/src/test/resources/security/passwd b/asterixdb/asterix-app/src/test/resources/security/passwd
new file mode 100644
index 0000000..a1ea5b0
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/security/passwd
@@ -0,0 +1 @@
+admin:$2a$12$JxgDzf/uOn1NS2Y3exhrDOf7JY/eUHQH7HeH90s5Ye2gALoO0FsQy
diff --git a/asterixdb/asterix-client-helper/pom.xml b/asterixdb/asterix-client-helper/pom.xml
index 92cf967..cf73b43 100644
--- a/asterixdb/asterix-client-helper/pom.xml
+++ b/asterixdb/asterix-client-helper/pom.xml
@@ -181,5 +181,17 @@
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-databind</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.mindrot</groupId>
+      <artifactId>jbcrypt</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-csv</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hyracks</groupId>
+      <artifactId>hyracks-util</artifactId>
+    </dependency>
   </dependencies>
 </project>
diff --git a/asterixdb/asterix-client-helper/src/main/java/org/apache/asterix/clienthelper/Args.java b/asterixdb/asterix-client-helper/src/main/java/org/apache/asterix/clienthelper/Args.java
index 5432df9..dd55143 100644
--- a/asterixdb/asterix-client-helper/src/main/java/org/apache/asterix/clienthelper/Args.java
+++ b/asterixdb/asterix-client-helper/src/main/java/org/apache/asterix/clienthelper/Args.java
@@ -46,6 +46,15 @@ public class Args {
     @Option(name = "-quiet", aliases = "-q", usage = "Suppress all normal output")
     protected boolean quiet;
 
+    @Option(name = "-username", aliases = "-u", usage = "Username for credential addition")
+    protected String username;
+
+    @Option(name = "-password", aliases = "-p", usage = "Password for credential addition")
+    protected String password;
+
+    @Option(name = "-credentialpath", aliases = "-cp", usage = "Path to credential file")
+    protected String credentialPath = "./passwd";
+
     @Argument
     protected List<String> arguments = new ArrayList<>();
 
@@ -76,4 +85,16 @@ public class Args {
     public String getShutdownPath() {
         return shutdownPath;
     }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public String getCredentialPath() {
+        return credentialPath;
+    }
 }
diff --git a/asterixdb/asterix-client-helper/src/main/java/org/apache/asterix/clienthelper/AsterixHelperExecution.java b/asterixdb/asterix-client-helper/src/main/java/org/apache/asterix/clienthelper/AsterixHelperExecution.java
index 326b1ca..c5783da 100644
--- a/asterixdb/asterix-client-helper/src/main/java/org/apache/asterix/clienthelper/AsterixHelperExecution.java
+++ b/asterixdb/asterix-client-helper/src/main/java/org/apache/asterix/clienthelper/AsterixHelperExecution.java
@@ -23,6 +23,7 @@ import java.io.PrintStream;
 
 import org.apache.asterix.clienthelper.commands.ClientCommand;
 import org.apache.asterix.clienthelper.commands.ClientCommand.Command;
+import org.apache.asterix.clienthelper.commands.GenerateCredentialCommand;
 import org.apache.asterix.clienthelper.commands.GetClusterStateCommand;
 import org.apache.asterix.clienthelper.commands.ShutdownAllCommand;
 import org.apache.asterix.clienthelper.commands.ShutdownCommand;
@@ -122,6 +123,8 @@ public class AsterixHelperExecution {
                 return new ShutdownAllCommand(args);
             case SLEEP:
                 return new SleepCommand(args);
+            case ADD_CREDENTIAL:
+                return new GenerateCredentialCommand(args);
             default:
                 throw new IllegalStateException("NYI: " + command);
         }
diff --git a/asterixdb/asterix-client-helper/src/main/java/org/apache/asterix/clienthelper/commands/ClientCommand.java b/asterixdb/asterix-client-helper/src/main/java/org/apache/asterix/clienthelper/commands/ClientCommand.java
index e02016c..3b9c8e4 100644
--- a/asterixdb/asterix-client-helper/src/main/java/org/apache/asterix/clienthelper/commands/ClientCommand.java
+++ b/asterixdb/asterix-client-helper/src/main/java/org/apache/asterix/clienthelper/commands/ClientCommand.java
@@ -32,7 +32,10 @@ public abstract class ClientCommand {
         WAIT_FOR_CLUSTER("Wait for cluster to be ready (errorcode 0 = ACTIVE, non-zero = UNKNOWN)"),
         SHUTDOWN_CLUSTER("Instructs the cluster to shut down, leaving NCService processes intact"),
         SHUTDOWN_CLUSTER_ALL("Instructs the cluster to shut down, including NCService processes"),
-        SLEEP("Sleep for specified -timeout seconds (-timeout must be set and greater than zero)");
+        SLEEP("Sleep for specified -timeout seconds (-timeout must be set and greater than zero)"),
+        ADD_CREDENTIAL(
+                "Generate passwd file for API endpoints that require authentication. "
+                        + "-username and -password must be specified.");
 
         private final String usage;
         private static final Map<String, Command> nameMap = new HashMap<>();
diff --git a/asterixdb/asterix-client-helper/src/main/java/org/apache/asterix/clienthelper/commands/GenerateCredentialCommand.java b/asterixdb/asterix-client-helper/src/main/java/org/apache/asterix/clienthelper/commands/GenerateCredentialCommand.java
new file mode 100644
index 0000000..76a210c
--- /dev/null
+++ b/asterixdb/asterix-client-helper/src/main/java/org/apache/asterix/clienthelper/commands/GenerateCredentialCommand.java
@@ -0,0 +1,57 @@
+/*
+ * 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.asterix.clienthelper.commands;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import org.apache.asterix.clienthelper.Args;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVPrinter;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.hyracks.util.file.FileUtil;
+import org.mindrot.jbcrypt.BCrypt;
+
+public class GenerateCredentialCommand extends ClientCommand {
+
+    private static String CREDENTIAL_FILE_NAME = "passwd";
+
+    public GenerateCredentialCommand(Args args) {
+        super(args);
+    }
+
+    @Override
+    public int execute() throws IOException {
+        String salt = BCrypt.gensalt(12);
+        String username = args.getUsername();
+        String password = args.getPassword();
+        String passwordHash = BCrypt.hashpw(password, salt);
+        File passwd =
+                new File(FilenameUtils.normalize(FileUtil.joinPath(args.getCredentialPath(), CREDENTIAL_FILE_NAME)));
+        if (!passwd.exists()) {
+            passwd.createNewFile();
+        }
+        try (CSVPrinter p =
+                new CSVPrinter(new FileWriter(passwd.getAbsolutePath(), true), CSVFormat.DEFAULT.withDelimiter(':'))) {
+            p.printRecord(username, passwordHash);
+        }
+        return 0;
+    }
+}
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/ExternalProperties.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/ExternalProperties.java
index 1533c9f..0acab5c 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/ExternalProperties.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/ExternalProperties.java
@@ -23,10 +23,15 @@ import static org.apache.hyracks.control.common.config.OptionTypes.POSITIVE_INTE
 import static org.apache.hyracks.control.common.config.OptionTypes.STRING;
 import static org.apache.hyracks.control.common.config.OptionTypes.UNSIGNED_INTEGER;
 
+import java.util.function.Function;
+
+import org.apache.hyracks.api.config.IApplicationConfig;
 import org.apache.hyracks.api.config.IOption;
 import org.apache.hyracks.api.config.IOptionType;
 import org.apache.hyracks.api.config.Section;
+import org.apache.hyracks.control.common.controllers.ControllerConfig;
 import org.apache.hyracks.util.StorageUtil;
+import org.apache.hyracks.util.file.FileUtil;
 import org.apache.logging.log4j.Level;
 
 public class ExternalProperties extends AbstractProperties {
@@ -49,7 +54,12 @@ public class ExternalProperties extends AbstractProperties {
                 UNSIGNED_INTEGER,
                 StorageUtil.getIntSizeInBytes(50, StorageUtil.StorageUnit.MEGABYTE),
                 "The maximum accepted web request size in bytes"),
-        REQUESTS_ARCHIVE_SIZE(UNSIGNED_INTEGER, 50, "The maximum number of archived requests to maintain");
+        REQUESTS_ARCHIVE_SIZE(UNSIGNED_INTEGER, 50, "The maximum number of archived requests to maintain"),
+        CREDENTIAL_FILE(
+                STRING,
+                (Function<IApplicationConfig, String>) appConfig -> FileUtil
+                        .joinPath(appConfig.getString(ControllerConfig.Option.DEFAULT_DIR), "passwd"),
+                ControllerConfig.Option.DEFAULT_DIR.cmdline() + "/passwd");
 
         private final IOptionType type;
         private final Object defaultValue;
@@ -69,6 +79,7 @@ public class ExternalProperties extends AbstractProperties {
                 case API_PORT:
                 case ACTIVE_PORT:
                 case REQUESTS_ARCHIVE_SIZE:
+                case CREDENTIAL_FILE:
                     return Section.CC;
                 case NC_API_PORT:
                     return Section.NC;
@@ -147,4 +158,8 @@ public class ExternalProperties extends AbstractProperties {
     public int getRequestsArchiveSize() {
         return accessor.getInt(Option.REQUESTS_ARCHIVE_SIZE);
     }
+
+    public String getCredentialFilePath() {
+        return accessor.getString(Option.CREDENTIAL_FILE);
+    }
 }
diff --git a/asterixdb/asterix-server/pom.xml b/asterixdb/asterix-server/pom.xml
index 409b13d..e6d7b69 100644
--- a/asterixdb/asterix-server/pom.xml
+++ b/asterixdb/asterix-server/pom.xml
@@ -172,6 +172,10 @@
               <gav>io.netty:netty-all:4.1.46.Final</gav>
               <noticeUrl>https://raw.githubusercontent.com/netty/netty/netty-4.1.46.Final/NOTICE.txt</noticeUrl>
             </override>
+            <override>
+              <gav>org.mindrot:jbcrypt:0.4</gav>
+              <url>http://www.mindrot.org/files/jBCrypt/LICENSE</url>
+            </override>
           </overrides>
           <licenses>
             <license>
@@ -256,6 +260,12 @@
               </aliasUrls>
             </license>
             <license>
+              <url>https://opensource.org/licenses/isc-license.txt</url>
+              <aliasUrls>
+                <aliasUrl>http://opensource.org/licenses/ISC</aliasUrl>
+              </aliasUrls>
+            </license>
+            <license>
               <url>https://opensource.org/licenses/bsd-license.php</url>
               <aliasUrls>http://www.opensource.org/licenses/bsd-license.php</aliasUrls>
             </license>
diff --git a/asterixdb/pom.xml b/asterixdb/pom.xml
index 25550bf..1538cbb 100644
--- a/asterixdb/pom.xml
+++ b/asterixdb/pom.xml
@@ -1340,6 +1340,16 @@
         <artifactId>reflections</artifactId>
         <version>0.9.12</version>
       </dependency>
+      <dependency>
+        <groupId>org.mindrot</groupId>
+        <artifactId>jbcrypt</artifactId>
+        <version>0.4</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.commons</groupId>
+        <artifactId>commons-csv</artifactId>
+        <version>1.8</version>
+      </dependency>
     </dependencies>
   </dependencyManagement>
 
diff --git a/asterixdb/src/main/appended-resources/supplemental-models.xml b/asterixdb/src/main/appended-resources/supplemental-models.xml
index d764e70..812c64a 100644
--- a/asterixdb/src/main/appended-resources/supplemental-models.xml
+++ b/asterixdb/src/main/appended-resources/supplemental-models.xml
@@ -271,4 +271,16 @@
       </properties>
     </project>
   </supplement>
+  <supplement>
+    <project>
+      <groupId>org.mindrot</groupId>
+      <artifactId>jbcrypt</artifactId>
+      <licenses>
+        <license>
+          <name>ISC License</name>
+          <url>http://www.mindrot.org/files/jBCrypt/LICENSE</url>
+        </license>
+      </licenses>
+    </project>
+  </supplement>
 </supplementalDataModels>
diff --git a/asterixdb/src/main/licenses/content/opensource.org_licenses_isc-license.txt b/asterixdb/src/main/licenses/content/opensource.org_licenses_isc-license.txt
new file mode 100644
index 0000000..a169aff
--- /dev/null
+++ b/asterixdb/src/main/licenses/content/opensource.org_licenses_isc-license.txt
@@ -0,0 +1,3 @@
+Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
\ No newline at end of file
diff --git a/asterixdb/src/main/licenses/content/www.mindrot.org_files_jBCrypt_LICENSE.txt b/asterixdb/src/main/licenses/content/www.mindrot.org_files_jBCrypt_LICENSE.txt
new file mode 100644
index 0000000..e0e23ed
--- /dev/null
+++ b/asterixdb/src/main/licenses/content/www.mindrot.org_files_jBCrypt_LICENSE.txt
@@ -0,0 +1,17 @@
+jBCrypt is subject to the following license:
+
+/*
+ * Copyright (c) 2006 Damien Miller <dj...@mindrot.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
\ No newline at end of file
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/CCConfig.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/CCConfig.java
index 0de75d9..bd84f11 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/CCConfig.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/CCConfig.java
@@ -467,4 +467,5 @@ public class CCConfig extends ControllerConfig {
     public void setTrustStorePath(String trustStorePath) {
         configManager.set(Option.TRUST_STORE_PATH, trustStorePath);
     }
+
 }