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

apucher pushed a commit to branch basic-auth-controller
in repository https://gitbox.apache.org/repos/asf/incubator-pinot.git

commit 29c3cc0be45ca18d4dd0a530d41bf309da8f02d3
Author: Alexander Pucher <a...@alexpucher.com>
AuthorDate: Tue Feb 9 14:43:31 2021 -0800

    progress
---
 .../apache/pinot/controller/ControllerStarter.java |   1 +
 .../api/access/AccessControlFactory.java           |   4 +
 .../api/access/BasicAuthAccessControlFactory.java  | 163 +++++++++++++++++++++
 .../batch/spec/SegmentGenerationJobSpec.java       |  13 ++
 .../org/apache/pinot/tools/BootstrapTableTool.java |  14 +-
 .../admin/command/AbstractBaseAdminCommand.java    |  25 +++-
 .../tools/admin/command/AddSchemaCommand.java      |  22 ++-
 .../pinot/tools/admin/command/AddTableCommand.java |  23 ++-
 .../tools/admin/command/AddTenantCommand.java      |  22 ++-
 .../tools/admin/command/BootstrapTableCommand.java |   9 +-
 .../tools/admin/command/ChangeTableState.java      |  10 +-
 .../tools/admin/command/ImportDataCommand.java     |  26 +++-
 .../admin/command/OperateClusterConfigCommand.java |  22 ++-
 .../tools/admin/command/PostQueryCommand.java      |  18 ++-
 .../tools/admin/command/QuickstartRunner.java      |   4 +-
 .../tools/admin/command/UploadSegmentCommand.java  |  23 ++-
 .../apache/pinot/tools/utils/PinotConfigUtils.java |   6 +
 17 files changed, 377 insertions(+), 28 deletions(-)

diff --git 
a/pinot-controller/src/main/java/org/apache/pinot/controller/ControllerStarter.java
 
b/pinot-controller/src/main/java/org/apache/pinot/controller/ControllerStarter.java
index 233f85e..a07ca29 100644
--- 
a/pinot-controller/src/main/java/org/apache/pinot/controller/ControllerStarter.java
+++ 
b/pinot-controller/src/main/java/org/apache/pinot/controller/ControllerStarter.java
@@ -388,6 +388,7 @@ public class ControllerStarter implements ServiceStartable {
     final AccessControlFactory accessControlFactory;
     try {
       accessControlFactory = (AccessControlFactory) 
Class.forName(accessControlFactoryClass).newInstance();
+      accessControlFactory.init(_config);
     } catch (Exception e) {
       throw new RuntimeException("Caught exception while creating new 
AccessControlFactory instance", e);
     }
diff --git 
a/pinot-controller/src/main/java/org/apache/pinot/controller/api/access/AccessControlFactory.java
 
b/pinot-controller/src/main/java/org/apache/pinot/controller/api/access/AccessControlFactory.java
index 5b3d8d0..2c79784 100644
--- 
a/pinot-controller/src/main/java/org/apache/pinot/controller/api/access/AccessControlFactory.java
+++ 
b/pinot-controller/src/main/java/org/apache/pinot/controller/api/access/AccessControlFactory.java
@@ -20,11 +20,15 @@ package org.apache.pinot.controller.api.access;
 
 import org.apache.pinot.spi.annotations.InterfaceAudience;
 import org.apache.pinot.spi.annotations.InterfaceStability;
+import org.apache.pinot.spi.env.PinotConfiguration;
 
 
 @InterfaceAudience.Public
 @InterfaceStability.Stable
 public interface AccessControlFactory {
+  default void init(PinotConfiguration pinotConfiguration) {
+    // left blank
+  }
 
   AccessControl create();
 }
diff --git 
a/pinot-controller/src/main/java/org/apache/pinot/controller/api/access/BasicAuthAccessControlFactory.java
 
b/pinot-controller/src/main/java/org/apache/pinot/controller/api/access/BasicAuthAccessControlFactory.java
new file mode 100644
index 0000000..0b2c00a
--- /dev/null
+++ 
b/pinot-controller/src/main/java/org/apache/pinot/controller/api/access/BasicAuthAccessControlFactory.java
@@ -0,0 +1,163 @@
+/**
+ * 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.pinot.controller.api.access;
+
+import com.google.common.base.Preconditions;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.pinot.spi.env.PinotConfiguration;
+
+import javax.ws.rs.core.HttpHeaders;
+import java.util.*;
+import java.util.stream.Collectors;
+
+
+/**
+ * Basic Authentication based on http headers. Configured via the 
"controller.admin.access.control" family of properties.
+ *
+ * <pre>
+ *     Example:
+ *     controller.admin.access.control.principals=admin123,user456
+ *     controller.admin.access.control.principals.admin123.password=verysecret
+ *     controller.admin.access.control.principals.user456.password=kindasecret
+ *     
controller.admin.access.control.principals.user456.tables=stuff,lessImportantStuff
+ *     
controller.admin.access.control.principals.user456.permissions=read,update
+ * </pre>
+ */
+public class BasicAuthAccessControlFactory implements AccessControlFactory {
+  private static final String PREFIX = 
"controller.admin.access.control.principals";
+  private static final String PASSWORD = "password";
+  private static final String PERMISSIONS = "permissions";
+  private static final String TABLES = "tables";
+  private static final String ALL = "*";
+
+  private static final String HEADER_AUTHORIZATION = "Authorization";
+
+  private AccessControl _accessControl;
+
+  public void init(PinotConfiguration configuration) {
+    String principalNames = configuration.getProperty(PREFIX);
+    Preconditions.checkArgument(StringUtils.isNotBlank(principalNames), "must 
provide principals");
+
+    List<BasicAuthPrincipal> principals = 
Arrays.stream(principalNames.split(",")).map(rawName -> {
+      String name = rawName.trim();
+      Preconditions.checkArgument(StringUtils.isNotBlank(name), "%s is not a 
valid name", name);
+
+      String password = configuration.getProperty(String.format("%s.%s.%s", 
PREFIX, name, PASSWORD));
+      Preconditions.checkArgument(StringUtils.isNotBlank(password), "must 
provide a password for %s", name);
+
+      Set<String> tables = new HashSet<>();
+      String tableNames = configuration.getProperty(String.format("%s.%s.%s", 
PREFIX, name, TABLES));
+      if (StringUtils.isNotBlank(tableNames) && !ALL.equals(tableNames)) {
+        tables = 
Arrays.stream(tableNames.split(",")).map(String::trim).collect(Collectors.toSet());
+      }
+
+      Set<AccessType> permissions = new HashSet<>();
+      String permissionNames = 
configuration.getProperty(String.format("%s.%s.%s", PREFIX, name, PERMISSIONS));
+      if (StringUtils.isNotBlank(permissionNames) && !ALL.equals(tableNames)) {
+        permissions = 
Arrays.stream(permissionNames.split(",")).map(String::trim).map(String::toUpperCase)
+                .map(AccessType::valueOf).collect(Collectors.toSet());
+      }
+
+      return new BasicAuthPrincipal(name, toToken(name, password), tables, 
permissions);
+    }).collect(Collectors.toList());
+
+    _accessControl = new BasicAuthAccessControl(principals);
+  }
+
+  @Override
+  public AccessControl create() {
+    return _accessControl;
+  }
+
+  /**
+   * Access Control using header-based basic http authentication
+   */
+  private static class BasicAuthAccessControl implements AccessControl {
+    private final Map<String, BasicAuthPrincipal> _principals;
+
+    public BasicAuthAccessControl(Collection<BasicAuthPrincipal> principals) {
+      this._principals = 
principals.stream().collect(Collectors.toMap(BasicAuthPrincipal::getToken, p -> 
p));
+    }
+
+    @Override
+    public boolean hasDataAccess(HttpHeaders httpHeaders, String tableName) {
+      return getPrincipal(httpHeaders).filter(p -> 
p.hasTable(tableName)).isPresent();
+    }
+
+    @Override
+    public boolean hasAccess(String tableName, AccessType accessType, 
HttpHeaders httpHeaders, String endpointUrl) {
+      return getPrincipal(httpHeaders).filter(p -> p.hasTable(tableName) && 
p.hasPermission(accessType)).isPresent();
+    }
+
+    @Override
+    public boolean hasAccess(AccessType accessType, HttpHeaders httpHeaders, 
String endpointUrl) {
+      return getPrincipal(httpHeaders).isPresent();
+    }
+
+    private Optional<BasicAuthPrincipal> getPrincipal(HttpHeaders headers) {
+      return 
headers.getRequestHeader(HEADER_AUTHORIZATION).stream().map(BasicAuthAccessControlFactory::normalizeToken)
+              .map(_principals::get).filter(Objects::nonNull).findFirst();
+    }
+  }
+
+  /**
+   * Container object for basic auth principal
+   */
+  private static class BasicAuthPrincipal {
+    private final String _name;
+    private final String _token;
+    private final Set<String> _tables;
+    private final Set<AccessType> _permissions;
+
+    public BasicAuthPrincipal(String name, String token, Set<String> tables, 
Set<AccessType> permissions) {
+      this._name = name;
+      this._token = token;
+      this._tables = tables;
+      this._permissions = permissions;
+    }
+
+    public String getName() {
+      return _name;
+    }
+
+    public String getToken() {
+      return _token;
+    }
+
+    public boolean hasTable(String tableName) {
+      return _tables.isEmpty() || _tables.contains(tableName);
+    }
+
+    public boolean hasPermission(AccessType accessType) {
+      return _permissions.isEmpty() || _permissions.contains(accessType);
+    }
+  }
+
+  private static String toToken(String name, String password) {
+    String identifier = String.format("%s:%s", name, password);
+    return normalizeToken(String.format("Basic %s", 
Base64.getEncoder().encodeToString(identifier.getBytes())));
+  }
+
+  private static String normalizeToken(String token) {
+    if (token == null) {
+      return null;
+    }
+    return token.trim().replace("=", "");
+  }
+}
diff --git 
a/pinot-spi/src/main/java/org/apache/pinot/spi/ingestion/batch/spec/SegmentGenerationJobSpec.java
 
b/pinot-spi/src/main/java/org/apache/pinot/spi/ingestion/batch/spec/SegmentGenerationJobSpec.java
index 3c43db8..6a6ffbd 100644
--- 
a/pinot-spi/src/main/java/org/apache/pinot/spi/ingestion/batch/spec/SegmentGenerationJobSpec.java
+++ 
b/pinot-spi/src/main/java/org/apache/pinot/spi/ingestion/batch/spec/SegmentGenerationJobSpec.java
@@ -121,6 +121,11 @@ public class SegmentGenerationJobSpec implements 
Serializable {
    */
   private TlsSpec _tlsSpec;
 
+  /**
+   * Controller auth token
+   */
+  private String _authToken;
+
   public ExecutionFrameworkSpec getExecutionFrameworkSpec() {
     return _executionFrameworkSpec;
   }
@@ -273,6 +278,14 @@ public class SegmentGenerationJobSpec implements 
Serializable {
   public void setTlsSpec(TlsSpec tlsSpec) {
     _tlsSpec = tlsSpec;
   }
+
+  public String getAuthToken() {
+    return _authToken;
+  }
+
+  public void setAuthToken(String authToken) {
+    _authToken = authToken;
+  }
 }
 
 
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/BootstrapTableTool.java 
b/pinot-tools/src/main/java/org/apache/pinot/tools/BootstrapTableTool.java
index d3eb44f..2e86199 100644
--- a/pinot-tools/src/main/java/org/apache/pinot/tools/BootstrapTableTool.java
+++ b/pinot-tools/src/main/java/org/apache/pinot/tools/BootstrapTableTool.java
@@ -55,20 +55,11 @@ public class BootstrapTableTool {
   private final String _controllerProtocol;
   private final String _controllerHost;
   private final int _controllerPort;
+  private final String _token;
   private final String _tableDir;
   private final MinionClient _minionClient;
 
-  public BootstrapTableTool(String controllerHost, int controllerPort, String 
tableDir) {
-    Preconditions.checkNotNull(controllerHost);
-    Preconditions.checkNotNull(tableDir);
-    _controllerProtocol = CommonConstants.HTTP_PROTOCOL;
-    _controllerHost = controllerHost;
-    _controllerPort = controllerPort;
-    _tableDir = tableDir;
-    _minionClient = new MinionClient(controllerHost, 
String.valueOf(controllerPort));
-  }
-
-  public BootstrapTableTool(String controllerProtocol, String controllerHost, 
int controllerPort, String tableDir) {
+  public BootstrapTableTool(String controllerProtocol, String controllerHost, 
int controllerPort, String tableDir, String token) {
     Preconditions.checkNotNull(controllerProtocol);
     Preconditions.checkNotNull(controllerHost);
     Preconditions.checkNotNull(tableDir);
@@ -77,6 +68,7 @@ public class BootstrapTableTool {
     _controllerPort = controllerPort;
     _tableDir = tableDir;
     _minionClient = new MinionClient(controllerHost, 
String.valueOf(controllerPort));
+    _token = token;
   }
 
   public boolean execute()
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/AbstractBaseAdminCommand.java
 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/AbstractBaseAdminCommand.java
index 9ab2f1a..30d4c28 100644
--- 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/AbstractBaseAdminCommand.java
+++ 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/AbstractBaseAdminCommand.java
@@ -29,9 +29,12 @@ import java.io.OutputStreamWriter;
 import java.net.HttpURLConnection;
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
-import java.util.Map;
+import java.util.*;
 
 import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.Header;
+import org.apache.http.message.BasicHeader;
 import org.apache.pinot.tools.AbstractBaseCommand;
 import org.apache.pinot.tools.utils.PinotConfigUtils;
 
@@ -72,11 +75,18 @@ public class AbstractBaseAdminCommand extends 
AbstractBaseCommand {
 
   public static String sendRequest(String requestMethod, String urlString, 
String payload)
       throws IOException {
+    return sendRequest(requestMethod, urlString, payload, 
Collections.emptyList());
+  }
+
+  public static String sendRequest(String requestMethod, String urlString, 
String payload, List<Header> headers)
+      throws IOException {
     final URL url = new URL(urlString);
     final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
 
     conn.setDoOutput(true);
     conn.setRequestMethod(requestMethod);
+    headers.stream().flatMap(header -> Arrays.stream(header.getElements()))
+            .forEach(elem -> conn.setRequestProperty(elem.getName(), 
elem.getValue()));
     if (payload != null) {
       final BufferedWriter writer = new BufferedWriter(new 
OutputStreamWriter(conn.getOutputStream(),
           StandardCharsets.UTF_8));
@@ -112,4 +122,17 @@ public class AbstractBaseAdminCommand extends 
AbstractBaseCommand {
       throws ConfigurationException {
     return PinotConfigUtils.readConfigFromFile(configFileName);
   }
+
+  static List<Header> makeBasicAuth(String user, String password) {
+    if (StringUtils.isBlank(user)) {
+      return Collections.emptyList();
+    }
+
+    if (StringUtils.isBlank(password)) {
+      password = "";
+    }
+
+    String token = "Basic " + Base64.getEncoder().encodeToString((user + ":" + 
password).getBytes());
+    return Collections.singletonList(new BasicHeader("Authorization", token));
+  }
 }
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/AddSchemaCommand.java
 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/AddSchemaCommand.java
index 8178bfc..2bb0a99 100644
--- 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/AddSchemaCommand.java
+++ 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/AddSchemaCommand.java
@@ -22,6 +22,9 @@ import java.io.File;
 import java.io.FileNotFoundException;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collections;
+
 import org.apache.pinot.common.utils.CommonConstants;
 import org.apache.pinot.controller.ControllerConf;
 import org.apache.pinot.spi.data.Schema;
@@ -51,6 +54,12 @@ public class AddSchemaCommand extends 
AbstractBaseAdminCommand implements Comman
   @Option(name = "-exec", required = false, metaVar = "<boolean>", usage = 
"Execute the command.")
   private boolean _exec;
 
+  @Option(name = "-user", required = false, metaVar = "<String>", usage = 
"Username for basic auth.")
+  private String _user;
+
+  @Option(name = "-password", required = false, metaVar = "<String>", usage = 
"Password for basic auth.")
+  private String _password;
+
   @Option(name = "-help", required = false, help = true, aliases = {"-h", 
"--h", "--help"}, usage = "Print this message.")
   private boolean _help = false;
 
@@ -73,7 +82,8 @@ public class AddSchemaCommand extends 
AbstractBaseAdminCommand implements Comman
   public String toString() {
     String retString =
         ("AddSchema -controllerProtocol " + _controllerProtocol + " 
-controllerHost " + _controllerHost
-            + " -controllerPort " + _controllerPort + " -schemaFile " + 
_schemaFile);
+            + " -controllerPort " + _controllerPort + " -schemaFile " + 
_schemaFile + " -user " + _user + " -password "
+                + "[hidden]");
 
     return ((_exec) ? (retString + " -exec") : retString);
   }
@@ -103,6 +113,14 @@ public class AddSchemaCommand extends 
AbstractBaseAdminCommand implements Comman
     return this;
   }
 
+  public void setUser(String user) {
+    this._user = user;
+  }
+
+  public void setPassword(String password) {
+    this._password = password;
+  }
+
   public AddSchemaCommand setExecute(boolean exec) {
     _exec = exec;
     return this;
@@ -131,7 +149,7 @@ public class AddSchemaCommand extends 
AbstractBaseAdminCommand implements Comman
     try (FileUploadDownloadClient fileUploadDownloadClient = new 
FileUploadDownloadClient()) {
       fileUploadDownloadClient.addSchema(
           FileUploadDownloadClient.getUploadSchemaURI(_controllerProtocol, 
_controllerHost, Integer.parseInt(_controllerPort)),
-          schema.getSchemaName(), schemaFile);
+          schema.getSchemaName(), schemaFile, makeBasicAuth(_user, _password), 
Collections.emptyList());
     } catch (Exception e) {
       LOGGER.error("Got Exception to upload Pinot Schema: " + 
schema.getSchemaName(), e);
       return false;
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/AddTableCommand.java
 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/AddTableCommand.java
index 038883f..78123e5 100644
--- 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/AddTableCommand.java
+++ 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/AddTableCommand.java
@@ -21,6 +21,8 @@ package org.apache.pinot.tools.admin.command;
 import com.fasterxml.jackson.databind.JsonNode;
 import java.io.File;
 import java.io.IOException;
+import java.util.Collections;
+
 import org.apache.pinot.common.utils.CommonConstants;
 import org.apache.pinot.common.utils.FileUploadDownloadClient;
 import org.apache.pinot.common.utils.NetUtil;
@@ -58,6 +60,12 @@ public class AddTableCommand extends 
AbstractBaseAdminCommand implements Command
   @Option(name = "-exec", required = false, metaVar = "<boolean>", usage = 
"Execute the command.")
   private boolean _exec;
 
+  @Option(name = "-user", required = false, metaVar = "<String>", usage = 
"Username for basic auth.")
+  private String _user;
+
+  @Option(name = "-password", required = false, metaVar = "<String>", usage = 
"Password for basic auth.")
+  private String _password;
+
   @Option(name = "-help", required = false, help = true, aliases = {"-h", 
"--h", "--help"}, usage = "Print this message.")
   private boolean _help = false;
 
@@ -82,7 +90,8 @@ public class AddTableCommand extends AbstractBaseAdminCommand 
implements Command
   public String toString() {
     String retString =
         ("AddTable -tableConfigFile " + _tableConfigFile + " -schemaFile " + 
_schemaFile + " -controllerProtocol "
-            + _controllerProtocol + " -controllerHost " + _controllerHost + " 
-controllerPort " + _controllerPort);
+            + _controllerProtocol + " -controllerHost " + _controllerHost + " 
-controllerPort " + _controllerPort
+                + " -user " + _user + " -password " + "[hidden]");
     return ((_exec) ? (retString + " -exec") : retString);
   }
 
@@ -115,6 +124,16 @@ public class AddTableCommand extends 
AbstractBaseAdminCommand implements Command
     return this;
   }
 
+  public AddTableCommand setUser(String user) {
+    _user = user;
+    return this;
+  }
+
+  public AddTableCommand setPassword(String password) {
+    _password = password;
+    return this;
+  }
+
   public AddTableCommand setExecute(boolean exec) {
     _exec = exec;
     return this;
@@ -134,7 +153,7 @@ public class AddTableCommand extends 
AbstractBaseAdminCommand implements Command
     try (FileUploadDownloadClient fileUploadDownloadClient = new 
FileUploadDownloadClient()) {
       fileUploadDownloadClient.addSchema(
           FileUploadDownloadClient.getUploadSchemaURI(_controllerProtocol, 
_controllerHost, Integer.parseInt(_controllerPort)),
-          schema.getSchemaName(), schemaFile);
+          schema.getSchemaName(), schemaFile, makeBasicAuth(_user, _password), 
Collections.emptyList());
     } catch (Exception e) {
       LOGGER.error("Got Exception to upload Pinot Schema: " + 
schema.getSchemaName(), e);
       throw e;
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/AddTenantCommand.java
 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/AddTenantCommand.java
index dc38614..3365314 100644
--- 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/AddTenantCommand.java
+++ 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/AddTenantCommand.java
@@ -28,6 +28,8 @@ import org.kohsuke.args4j.Option;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Collections;
+
 
 public class AddTenantCommand extends AbstractBaseAdminCommand implements 
Command {
   private static final Logger LOGGER = 
LoggerFactory.getLogger(AddTenantCommand.class);
@@ -59,6 +61,12 @@ public class AddTenantCommand extends 
AbstractBaseAdminCommand implements Comman
   @Option(name = "-exec", required = false, metaVar = "<boolean>", usage = 
"Execute the command.")
   private boolean _exec;
 
+  @Option(name = "-user", required = false, metaVar = "<String>", usage = 
"Username for basic auth.")
+  private String _user;
+
+  @Option(name = "-password", required = false, metaVar = "<String>", usage = 
"Password for basic auth.")
+  private String _password;
+
   @Option(name = "-help", required = false, help = true, aliases = {"-h", 
"--h", "--help"}, usage = "Print this message.")
   private boolean _help = false;
 
@@ -94,6 +102,16 @@ public class AddTenantCommand extends 
AbstractBaseAdminCommand implements Comman
     return this;
   }
 
+  public AddTenantCommand setUser(String user) {
+    _user = user;
+    return this;
+  }
+
+  public AddTenantCommand setPassword(String password) {
+    _password = password;
+    return this;
+  }
+
   public AddTenantCommand setExecute(boolean exec) {
     _exec = exec;
     return this;
@@ -118,8 +136,8 @@ public class AddTenantCommand extends 
AbstractBaseAdminCommand implements Comman
     LOGGER.info("Executing command: " + toString());
     Tenant tenant = new Tenant(_role, _name, _instanceCount, 
_offlineInstanceCount, _realtimeInstanceCount);
     String res = AbstractBaseAdminCommand
-        
.sendPostRequest(ControllerRequestURLBuilder.baseUrl(_controllerAddress).forTenantCreate(),
-            tenant.toJsonString());
+        .sendRequest("POST", 
ControllerRequestURLBuilder.baseUrl(_controllerAddress).forTenantCreate(),
+            tenant.toJsonString(), makeBasicAuth(_user, _password));
 
     LOGGER.info(res);
     System.out.print(res);
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/BootstrapTableCommand.java
 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/BootstrapTableCommand.java
index 627755d..6f7d017 100644
--- 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/BootstrapTableCommand.java
+++ 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/BootstrapTableCommand.java
@@ -76,6 +76,12 @@ public class BootstrapTableCommand extends 
AbstractBaseAdminCommand implements C
   @Option(name = "-dir", required = false, aliases = {"-d", "-directory"}, 
metaVar = "<String>", usage = "The directory contains all the configs and data 
to bootstrap a table")
   private String _dir;
 
+  @Option(name = "-user", required = false, metaVar = "<String>", usage = 
"Username for basic auth.")
+  private String _user;
+
+  @Option(name = "-password", required = false, metaVar = "<String>", usage = 
"Password for basic auth.")
+  private String _password;
+
   @Option(name = "-help", required = false, help = true, aliases = {"-h", 
"--h", "--help"}, usage = "Print this message.")
   private boolean _help = false;
 
@@ -116,6 +122,7 @@ public class BootstrapTableCommand extends 
AbstractBaseAdminCommand implements C
     if (_controllerHost == null) {
       _controllerHost = NetUtil.getHostAddress();
     }
-    return new BootstrapTableTool(_controllerProtocol, _controllerHost, 
Integer.parseInt(_controllerPort), _dir).execute();
+    String token = ""; // TODO
+    return new BootstrapTableTool(_controllerProtocol, _controllerHost, 
Integer.parseInt(_controllerPort), _dir, token).execute();
   }
 }
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/ChangeTableState.java
 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/ChangeTableState.java
index c7cbe70..d240e77 100644
--- 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/ChangeTableState.java
+++ 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/ChangeTableState.java
@@ -50,6 +50,12 @@ public class ChangeTableState extends 
AbstractBaseAdminCommand implements Comman
   @Option(name = "-state", required = true, metaVar = "<String>", usage = 
"Change Table State(enable|disable|drop)")
   private String _state;
 
+  @Option(name = "-user", required = false, metaVar = "<String>", usage = 
"Username for basic auth.")
+  private String _user;
+
+  @Option(name = "-password", required = false, metaVar = "<String>", usage = 
"Password for basic auth.")
+  private String _password;
+
   @Option(name = "-help", required = false, help = true, aliases = {"-h", 
"--h", "--help"}, usage = "Print this message.")
   private boolean _help = false;
 
@@ -70,6 +76,7 @@ public class ChangeTableState extends 
AbstractBaseAdminCommand implements Comman
         URI_TABLES_PATH + _tableName, "state=" + stateValue, null);
 
     GetMethod httpGet = new GetMethod(uri.toString());
+    httpGet.setRequestHeader("Authorization", null); // TODO
     int status = httpClient.executeMethod(httpGet);
     if (status != 200) {
       throw new RuntimeException("Failed to change table state, error: " + 
httpGet.getResponseBodyAsString());
@@ -94,7 +101,8 @@ public class ChangeTableState extends 
AbstractBaseAdminCommand implements Comman
   @Override
   public String toString() {
     return ("ChangeTableState -controllerProtocol " + _controllerProtocol + " 
-controllerHost " + _controllerHost
-        + " -controllerPort " + _controllerPort + " -tableName" + _tableName + 
" -state" + _state);
+        + " -controllerPort " + _controllerPort + " -tableName" + _tableName + 
" -state" + _state + " -user " + _user
+        + " -password " + "[hidden]");
   }
 
   @Override
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/ImportDataCommand.java
 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/ImportDataCommand.java
index 10b2aaf..49884e4 100644
--- 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/ImportDataCommand.java
+++ 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/ImportDataCommand.java
@@ -30,6 +30,7 @@ import java.util.List;
 import java.util.Map;
 import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.pinot.controller.helix.ControllerRequestURLBuilder;
 import org.apache.pinot.spi.data.readers.FileFormat;
 import org.apache.pinot.spi.filesystem.PinotFSFactory;
@@ -74,6 +75,12 @@ public class ImportDataCommand extends 
AbstractBaseAdminCommand implements Comma
   @Option(name = "-controllerURI", metaVar = "<string>", usage = "Pinot 
Controller URI.")
   private String _controllerURI = "http://localhost:9000";;
 
+  @Option(name = "-user", required = false, metaVar = "<String>", usage = 
"Username for basic auth.")
+  private String _user;
+
+  @Option(name = "-password", required = false, metaVar = "<String>", usage = 
"Password for basic auth.")
+  private String _password;
+
   @Option(name = "-tempDir", metaVar = "<string>", usage = "Temporary 
directory used to hold data during segment creation.")
   private String _tempDir = new File(FileUtils.getTempDirectory(), 
getClass().getSimpleName()).getAbsolutePath();
 
@@ -121,6 +128,16 @@ public class ImportDataCommand extends 
AbstractBaseAdminCommand implements Comma
     return this;
   }
 
+  public ImportDataCommand setUser(String user) {
+    _user = user;
+    return this;
+  }
+
+  public ImportDataCommand setPassword(String password) {
+    _password = password;
+    return this;
+  }
+
   public List<String> getAdditionalConfigs() {
     return _additionalConfigs;
   }
@@ -153,8 +170,8 @@ public class ImportDataCommand extends 
AbstractBaseAdminCommand implements Comma
   @Override
   public String toString() {
     String results = String
-        .format("InsertData -dataFilePath %s -format %s -table %s 
-controllerURI %s -tempDir %s", _dataFilePath,
-            _format, _table, _controllerURI, _tempDir);
+        .format("InsertData -dataFilePath %s -format %s -table %s 
-controllerURI %s -user %s -password %s -tempDir %s",
+            _dataFilePath, _format, _table, _controllerURI, _user, "[hidden]", 
_tempDir);
     if (_additionalConfigs != null) {
       results += " -additionalConfigs " + 
Arrays.toString(_additionalConfigs.toArray());
     }
@@ -227,6 +244,11 @@ public class ImportDataCommand extends 
AbstractBaseAdminCommand implements Comma
     spec.setOverwriteOutput(true);
     spec.setJobType("SegmentCreationAndTarPush");
 
+    if (!StringUtils.isBlank(_user)) {
+      String token = ""; // TODO
+      spec.setAuthToken(token);
+    }
+
     // set ExecutionFrameworkSpec
     ExecutionFrameworkSpec executionFrameworkSpec = new 
ExecutionFrameworkSpec();
     executionFrameworkSpec.setName("standalone");
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/OperateClusterConfigCommand.java
 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/OperateClusterConfigCommand.java
index f265d95..97b04c6 100644
--- 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/OperateClusterConfigCommand.java
+++ 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/OperateClusterConfigCommand.java
@@ -46,6 +46,12 @@ public class OperateClusterConfigCommand extends 
AbstractBaseAdminCommand implem
   @Option(name = "-controllerProtocol", required = false, metaVar = 
"<String>", usage = "protocol for controller.")
   private String _controllerProtocol = CommonConstants.HTTP_PROTOCOL;
 
+  @Option(name = "-user", required = false, metaVar = "<String>", usage = 
"Username for basic auth.")
+  private String _user;
+
+  @Option(name = "-password", required = false, metaVar = "<String>", usage = 
"Password for basic auth.")
+  private String _password;
+
   @Option(name = "-config", metaVar = "<string>", usage = "Cluster config to 
operate.")
   private String _config;
 
@@ -100,6 +106,16 @@ public class OperateClusterConfigCommand extends 
AbstractBaseAdminCommand implem
     return this;
   }
 
+  public OperateClusterConfigCommand setUser(String user) {
+    _user = user;
+    return this;
+  }
+
+  public OperateClusterConfigCommand setPassword(String password) {
+    _password = password;
+    return this;
+  }
+
   public OperateClusterConfigCommand setConfig(String config) {
     _config = config;
     return this;
@@ -129,8 +145,9 @@ public class OperateClusterConfigCommand extends 
AbstractBaseAdminCommand implem
               "Bad config: " + _config + ". Please follow the pattern of 
[Config Key]=[Config Value]");
         }
         String request = 
JsonUtils.objectToString(Collections.singletonMap(splits[0], splits[1]));
-        return sendPostRequest(clusterConfigUrl, request);
+        return sendRequest("POST", clusterConfigUrl, request, 
makeBasicAuth(_user, _password));
       case "GET":
+        // TODO
         String response = IOUtils.toString(new URI(clusterConfigUrl), 
StandardCharsets.UTF_8);
         JsonNode jsonNode = JsonUtils.stringToJsonNode(response);
         Iterator<String> fieldNamesIterator = jsonNode.fieldNames();
@@ -142,7 +159,8 @@ public class OperateClusterConfigCommand extends 
AbstractBaseAdminCommand implem
         }
         return results;
       case "DELETE":
-        return sendDeleteRequest(String.format("%s/%s", clusterConfigUrl, 
_config), null);
+        return sendRequest("DELETE", String.format("%s/%s", clusterConfigUrl, 
_config), null,
+            makeBasicAuth(_user, _password));
       default:
         throw new UnsupportedOperationException("Unsupported operation: " + 
_operation);
     }
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/PostQueryCommand.java
 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/PostQueryCommand.java
index 511d7e7..4afb686 100644
--- 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/PostQueryCommand.java
+++ 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/PostQueryCommand.java
@@ -47,6 +47,12 @@ public class PostQueryCommand extends 
AbstractBaseAdminCommand implements Comman
   @Option(name = "-query", required = true, metaVar = "<string>", usage = 
"Query string to perform.")
   private String _query;
 
+  @Option(name = "-user", required = false, metaVar = "<String>", usage = 
"Username for basic auth.")
+  private String _user;
+
+  @Option(name = "-password", required = false, metaVar = "<String>", usage = 
"Password for basic auth.")
+  private String _password;
+
   @Option(name = "-help", required = false, help = true, aliases = {"-h", 
"--h", "--help"}, usage = "Print this message.")
   private boolean _help = false;
 
@@ -91,6 +97,16 @@ public class PostQueryCommand extends 
AbstractBaseAdminCommand implements Comman
     return this;
   }
 
+  public PostQueryCommand setUser(String user) {
+    _user = user;
+    return this;
+  }
+
+  public PostQueryCommand setPassword(String password) {
+    _password = password;
+    return this;
+  }
+
   public PostQueryCommand setQueryType(String queryType) {
     _queryType = queryType;
     return this;
@@ -117,7 +133,7 @@ public class PostQueryCommand extends 
AbstractBaseAdminCommand implements Comman
       request = JsonUtils.objectToString(Collections.singletonMap(Request.PQL, 
_query));
     }
 
-    return sendPostRequest(urlString, request);
+    return sendRequest("POST", urlString, request, makeBasicAuth(_user, 
_password));
   }
 
   @Override
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/QuickstartRunner.java
 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/QuickstartRunner.java
index 4598d8a..3630602 100644
--- 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/QuickstartRunner.java
+++ 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/QuickstartRunner.java
@@ -203,8 +203,8 @@ public class QuickstartRunner {
   public void bootstrapTable()
       throws Exception {
     for (QuickstartTableRequest request : _tableRequests) {
-      if (!new BootstrapTableTool(InetAddress.getLocalHost().getHostName(), 
_controllerPorts.get(0), request.getBootstrapTableDir())
-          .execute()) {
+      if (!new BootstrapTableTool("http", 
InetAddress.getLocalHost().getHostName(), _controllerPorts.get(0),
+          request.getBootstrapTableDir(), null).execute()) {
         throw new RuntimeException("Failed to bootstrap table with request - " 
+ request);
       }
     }
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/UploadSegmentCommand.java
 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/UploadSegmentCommand.java
index a9e2267..d393e57 100644
--- 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/UploadSegmentCommand.java
+++ 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/UploadSegmentCommand.java
@@ -21,7 +21,9 @@ package org.apache.pinot.tools.admin.command;
 import com.google.common.base.Preconditions;
 import java.io.File;
 import java.net.URI;
+import java.util.Collections;
 import org.apache.commons.io.FileUtils;
+import org.apache.http.message.BasicNameValuePair;
 import org.apache.pinot.common.utils.CommonConstants;
 import org.apache.pinot.common.utils.FileUploadDownloadClient;
 import org.apache.pinot.common.utils.NetUtil;
@@ -50,6 +52,12 @@ public class UploadSegmentCommand extends 
AbstractBaseAdminCommand implements Co
   @Option(name = "-controllerProtocol", required = false, metaVar = 
"<String>", usage = "protocol for controller.")
   private String _controllerProtocol = CommonConstants.HTTP_PROTOCOL;
 
+  @Option(name = "-user", required = false, metaVar = "<String>", usage = 
"Username for basic auth.")
+  private String _user;
+
+  @Option(name = "-password", required = false, metaVar = "<String>", usage = 
"Password for basic auth.")
+  private String _password;
+
   @Option(name = "-segmentDir", required = true, metaVar = "<string>", usage = 
"Path to segment directory.")
   private String _segmentDir = null;
 
@@ -101,6 +109,16 @@ public class UploadSegmentCommand extends 
AbstractBaseAdminCommand implements Co
     return this;
   }
 
+  public UploadSegmentCommand setUser(String user) {
+    _user = user;
+    return this;
+  }
+
+  public UploadSegmentCommand setPassword(String password) {
+    _password = password;
+    return this;
+  }
+
   public UploadSegmentCommand setSegmentDir(String segmentDir) {
     _segmentDir = segmentDir;
     return this;
@@ -140,7 +158,10 @@ public class UploadSegmentCommand extends 
AbstractBaseAdminCommand implements Co
 
         LOGGER.info("Uploading segment tar file: {}", segmentTarFile);
         fileUploadDownloadClient
-            .uploadSegment(uploadSegmentHttpURI, segmentTarFile.getName(), 
segmentTarFile, _tableName);
+            .uploadSegment(uploadSegmentHttpURI, segmentTarFile.getName(), 
segmentTarFile,
+                makeBasicAuth(_user, _password), Collections.singletonList(new 
BasicNameValuePair(
+                    FileUploadDownloadClient.QueryParameters.TABLE_NAME, 
_tableName)),
+                FileUploadDownloadClient.DEFAULT_SOCKET_TIMEOUT_MS);
       }
     } finally {
       // Delete the temporary working directory.
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/utils/PinotConfigUtils.java 
b/pinot-tools/src/main/java/org/apache/pinot/tools/utils/PinotConfigUtils.java
index b636b90..0354fd9 100644
--- 
a/pinot-tools/src/main/java/org/apache/pinot/tools/utils/PinotConfigUtils.java
+++ 
b/pinot-tools/src/main/java/org/apache/pinot/tools/utils/PinotConfigUtils.java
@@ -70,6 +70,12 @@ public class PinotConfigUtils {
     
properties.put(ControllerPeriodicTasksConf.REALTIME_SEGMENT_VALIDATION_FREQUENCY_IN_SECONDS,
 3600);
     
properties.put(ControllerPeriodicTasksConf.BROKER_RESOURCE_VALIDATION_FREQUENCY_IN_SECONDS,
 3600);
     properties.put(ControllerConf.CONTROLLER_MODE, controllerMode.toString());
+    properties.put("controller.admin.access.control.factory.class", 
"org.apache.pinot.controller.api.access.BasicAuthAccessControlFactory");
+    properties.put("controller.admin.access.control.principals", "admin, 
user");
+    
properties.put("controller.admin.access.control.principals.admin.password", 
"verysecret");
+    properties.put("controller.admin.access.control.principals.user.password", 
"secret");
+    properties.put("controller.admin.access.control.principals.user.tables", 
"baseballStats");
+    
properties.put("controller.admin.access.control.principals.user.permissions", 
"read");
 
     return properties;
   }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org
For additional commands, e-mail: commits-h...@pinot.apache.org

Reply via email to