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