epugh commented on code in PR #5107:
URL: https://github.com/apache/solr/pull/5107#discussion_r4444379992
##########
solr/core/src/java/org/apache/solr/cli/RunExampleTool.java:
##########
@@ -602,19 +632,343 @@ void initDirs(
+ " is not a directory!");
}
+ private static String[] withCredentials(String[] args, String credentials) {
+ if (credentials == null) return args;
+ List<String> result = new ArrayList<>(Arrays.asList(args));
+ result.add("--credentials");
+ result.add(credentials);
+ return result.toArray(String[]::new);
+ }
+
+ @SuppressWarnings("unchecked")
+ void runSecureExample(StartSolrParams start, int port, boolean noPrompt,
String scriptInputs)
+ throws Exception {
+ for (String file : List.of("solr.xml", "zoo.cfg")) {
+ Path target = solrHomeDir.resolve(file);
+ if (!Files.exists(target))
Files.copy(serverDir.resolve("solr").resolve(file), target);
+ }
+ echo("Welcome to the secure SolrCloud example!");
+ echo(
+ "This example uses demonstration credentials. Change them before using
it outside your local environment.");
+ usingScriptInputs = scriptInputs != null;
+ Scanner input =
+ new Scanner(
+ usingScriptInputs
+ ? new
ByteArrayInputStream(scriptInputs.getBytes(StandardCharsets.UTF_8))
+ : userInput,
+ StandardCharsets.UTF_8);
+ if (usingScriptInputs) input.useDelimiter(",");
+ secureExampleInput = input;
+ secureExampleNoPrompt = noPrompt;
+ secureHttpsVerificationShown = false;
+ Map<String, Object> httpsNodeStatus = null;
+ SecureExampleCredentials accounts = new
SecureExampleCredentials(solrHomeDir);
+ boolean existingAccounts = accounts.exists();
+ if (start.credentials() != null)
accounts.setAdministrator(start.credentials());
+ secureSSL = new SecureExampleSSL(solrHomeDir, runtime);
+ boolean existingHttps = secureSSL.isConfigured();
+ if (!existingHttps) configureSecureExampleSSL(input, start, noPrompt);
+ else echo("Reusing the example's HTTPS configuration.");
+ SecureExampleZk secureZk = new SecureExampleZk(solrHomeDir);
+ boolean changePasswords = false;
+ if (!existingAccounts || !secureZk.isConfigured()) {
+ echo("The solr, index, search, zk-admin, and zk-readonly accounts use
SolrRocks by default.");
+ String choice = noPrompt ? "n" : prompt(input, "Change account
passwords? [y/N]: ", "n");
+ while (!Set.of("y", "n").contains(choice.toLowerCase(Locale.ROOT))) {
+ choice = prompt(input, "Enter y to change passwords or n to use the
defaults [y/N]: ", "n");
+ }
+ changePasswords = choice.equalsIgnoreCase("y");
+ }
+ if (!existingAccounts && changePasswords) {
+ for (String account : List.of("admin", "index", "search")) {
+ String username = "admin".equals(account) ? accounts.adminUsername() :
account;
+ accounts.setPassword(
+ account,
+ promptPassword(input, "Password for " + username + " [SolrRocks]:
", username));
+ }
+ }
+ if (secureZk.isConfigured()) {
+ echo("Reusing the example's ZooKeeper credentials and ACL
configuration.");
+ } else {
+ echo("Protecting ZooKeeper with separate digest accounts and ACLs.");
+ String zkAdminPassword =
+ changePasswords
+ ? promptPassword(input, "Password for zk-admin [SolrRocks]: ",
"zk-admin")
+ : "SolrRocks";
+ String zkReadonlyPassword =
+ changePasswords
+ ? promptPassword(input, "Password for zk-readonly [SolrRocks]:
", "zk-readonly")
+ : "SolrRocks";
+ secureZk.create(zkAdminPassword, zkReadonlyPassword);
+ }
+ if (!existingAccounts || start.credentials() == null) accounts.save();
+ echo("HTTP credentials: " + accounts.file());
+ secureZk.configure(secureSSL.includeFile(), port);
+ echo("ZooKeeper credentials: " + secureZk.credentialsFile());
+ secureSSL.printFiles();
+ secureSSL.configureClientTrust();
+ urlScheme = "https";
+ if (!existingHttps
+ && !Files.isDirectory(solrHomeDir.resolve("zoo_data"))
+ && isPortAvailable(port)) {
+ httpsNodeStatus = startSolr(solrHomeDir, true, start, port, null, 30);
+ confirmSecureHttps((String) httpsNodeStatus.get("baseUrl"));
+ }
+ if (existingAccounts) echo("Reusing the example's HTTP credentials.");
+ String user = accounts.adminUsername();
+ String password = accounts.password("admin");
+ // TODO: Configure users and roles through the security APIs so validation
+ // happens server-side instead of constructing security.json directly.
+ Map<String, Object> config;
+ try (InputStream template =
+ SolrCore.class.getClassLoader().getResourceAsStream("security.json")) {
+ config = (Map<String, Object>) Utils.fromJSON(template.readAllBytes());
+ }
+ Map<String, Object> authentication = (Map<String, Object>)
config.get("authentication");
+ authentication.put("blockUnknown", false);
+ Map<String, Object> credentials = new HashMap<>();
+ credentials.put(user,
Sha256AuthenticationProvider.getSaltedHashedValue(password));
+ authentication.put("credentials", credentials);
+ Map<String, Object> authorization = (Map<String, Object>)
config.get("authorization");
+ Map<String, Object> userRoles = new HashMap<>();
+ userRoles.put(user, List.of("superadmin", "admin"));
+ authorization.put("user-role", userRoles);
+ for (Map<String, Object> permission :
+ (List<Map<String, Object>>) authorization.get("permissions")) {
+ if ("collection-admin-read".equals(permission.get("name"))) {
+ permission.put("role", List.of("admin", "search"));
+ }
+ }
+ Map<String, Object> publicMonitoring = new HashMap<>();
+ publicMonitoring.put("name", "public-monitoring");
+ publicMonitoring.put("collection", null);
+ publicMonitoring.put("path", List.of("/____v2/node/health",
"/____v2/metrics"));
+ publicMonitoring.put("method", "GET");
+ publicMonitoring.put("role", null);
+ List<Map<String, Object>> permissions =
+ (List<Map<String, Object>>) authorization.get("permissions");
+ permissions.add(permissions.size() - 1, publicMonitoring);
+ String indexingCredentials = null;
+ for (String role : List.of("index", "search")) {
+ String pass = accounts.password(role);
+ credentials.put(role,
Sha256AuthenticationProvider.getSaltedHashedValue(pass));
+ userRoles.put(role, "index".equals(role) ? List.of("index", "search") :
List.of("search"));
+ if ("index".equals(role)) indexingCredentials = role + ":" + pass;
+ }
+ StartSolrParams secured =
+ new StartSolrParams(
+ start.example(),
+ start.host(),
+ start.memory(),
+ start.jvmOpts(),
+ start.force(),
+ user + ":" + password,
+ start.extraArgs());
+ runExample(
+ new RunExampleParams(true, null, port, secured),
+ config,
+ httpsNodeStatus,
+ indexingCredentials);
+ if (existingAccounts && start.credentials() != null) accounts.save();
+ echo(
+ "Secure Solr example running at "
+ + urlScheme
+ + "://"
+ + (start.host() == null ? "localhost" : start.host())
+ + ":"
+ + port
+ + "/solr/. Sign in as "
+ + user
+ + "."
+ + (secureSSL != null && secureSSL.isSelfSigned()
+ ? " You will need to accept the self-signed certificate in the
browser."
+ : ""));
+ echo(
+ "Second node running at "
+ + urlScheme
+ + "://"
+ + (start.host() == null ? "localhost" : start.host())
+ + ":"
+ + (port + 1)
+ + "/solr/. Sign in as "
+ + user
+ + ".");
+ echo("HTTP account credentials are saved in " + accounts.file() + ".");
+ if (secureSSL != null) {
+ echo(
+ "ZooKeeper account credentials are saved in "
+ + new SecureExampleZk(solrHomeDir).credentialsFile()
+ + ".");
+ var zkCredentials =
+ VMParamsZkCredentialsInjector.readCredentialsFile(
+ new SecureExampleZk(solrHomeDir).credentialsFile().toString());
+ String zkPassword = zkCredentials.getProperty("zkDigestPassword");
+ echo("List ZooKeeper data with TLS and digest authentication:");
+ echo(
+ "bin/solr zk ls / --zk-tls-ca-file '"
+ + secureSSL.certificate().toString().replace("'", "'\"'\"'")
+ + "' --zk-host localhost:"
+ + (port + 1000)
+ + "/solr --zk-credentials 'zk-admin:"
+ + ("SolrRocks".equals(zkPassword) ? "SolrRocks" : "<password>")
+ + "'");
+ if (!"SolrRocks".equals(zkPassword))
+ echo(
+ "Use the zk-admin password from " + new
SecureExampleZk(solrHomeDir).credentialsFile());
+ }
+ }
+
+ private void confirmSecureHttps(String solrUrl) {
+ secureSSL.printVerificationInstructions(solrUrl);
+ if (!secureExampleNoPrompt) {
+ prompt(secureExampleInput, "Press Enter after curl verifies HTTPS to
continue: ", "");
+ }
+ secureHttpsVerificationShown = true;
+ }
+
+ private void configureSecureExampleSSL(Scanner input, StartSolrParams start,
boolean noPrompt)
+ throws Exception {
+ echo("Generating sample PEM certificate and key files. OpenSSL must be
available on PATH.");
Review Comment:
we could be all java!
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]