|
5 | 5 |
|
6 | 6 |
|
7 | 7 | import org.opensearch.gradle.testclusters.OpenSearchCluster |
8 | | -import org.opensearch.gradle.testclusters.TestClusterConfiguration |
9 | 8 | import org.opensearch.gradle.testclusters.StandaloneRestIntegTestTask |
10 | 9 |
|
| 10 | +import javax.net.ssl.HostnameVerifier |
| 11 | +import javax.net.ssl.HttpsURLConnection |
| 12 | +import javax.net.ssl.SSLContext |
| 13 | +import javax.net.ssl.SSLSession |
| 14 | +import javax.net.ssl.TrustManager |
| 15 | +import javax.net.ssl.X509TrustManager |
11 | 16 | import java.nio.charset.StandardCharsets |
12 | 17 | import java.nio.file.Files |
| 18 | +import java.security.GeneralSecurityException |
| 19 | +import java.security.cert.X509Certificate |
13 | 20 | import java.util.concurrent.Callable |
14 | | -import java.util.concurrent.TimeUnit |
15 | 21 | import java.util.function.Predicate |
16 | | -import org.opensearch.gradle.http.WaitForHttpResource |
| 22 | +import java.util.stream.Collectors |
| 23 | +import java.util.concurrent.TimeUnit |
17 | 24 |
|
18 | 25 |
|
19 | 26 | buildscript { |
@@ -301,7 +308,7 @@ afterEvaluate { |
301 | 308 | node.setting("plugins.security.ssl.http.pemtrustedcas_filepath", "root-ca.pem") |
302 | 309 | node.setting("plugins.security.allow_unsafe_democertificates", "true") |
303 | 310 | node.setting("plugins.security.allow_default_init_securityindex", "true") |
304 | | - node.setting("plugins.security.authcz.admin_dn", "\n - CN=kirk,OU=client,O=client,L=test, C=de") |
| 311 | + node.setting("plugins.security.authcz.admin_dn", "\n - CN=kirk,OU=client,O=client,L=test,C=de") |
305 | 312 | node.setting("plugins.security.audit.type", "internal_elasticsearch") |
306 | 313 | node.setting("plugins.security.enable_snapshot_restore_privilege", "true") |
307 | 314 | node.setting("plugins.security.check_snapshot_restore_write_privileges", "true") |
@@ -405,22 +412,125 @@ testClusters.integTest { |
405 | 412 | setting 'path.repo', repo.absolutePath |
406 | 413 | } |
407 | 414 |
|
| 415 | +// Clone of WaitForHttpResource with updated code to support security plugin use case |
| 416 | +class WaitForClusterYellow { |
| 417 | + |
| 418 | + private URL url |
| 419 | + private String username |
| 420 | + private String password |
| 421 | + Set<Integer> validResponseCodes = Collections.singleton(200) |
| 422 | + |
| 423 | + WaitForClusterYellow(String protocol, String host, int numberOfNodes) throws MalformedURLException { |
| 424 | + this(new URL(protocol + "://" + host + "/_cluster/health?wait_for_nodes=>=" + numberOfNodes + "&wait_for_status=yellow")) |
| 425 | + } |
| 426 | + |
| 427 | + WaitForClusterYellow(URL url) { |
| 428 | + this.url = url |
| 429 | + } |
| 430 | + |
| 431 | + boolean wait(int durationInMs) throws GeneralSecurityException, InterruptedException, IOException { |
| 432 | + final long waitUntil = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(durationInMs) |
| 433 | + final long sleep = 100 |
| 434 | + |
| 435 | + IOException failure = null |
| 436 | + while (true) { |
| 437 | + try { |
| 438 | + checkResource() |
| 439 | + return true |
| 440 | + } catch (IOException e) { |
| 441 | + failure = e |
| 442 | + } |
| 443 | + if (System.nanoTime() < waitUntil) { |
| 444 | + Thread.sleep(sleep) |
| 445 | + } else { |
| 446 | + throw failure |
| 447 | + } |
| 448 | + } |
| 449 | + } |
| 450 | + |
| 451 | + void setUsername(String username) { |
| 452 | + this.username = username |
| 453 | + } |
| 454 | + |
| 455 | + void setPassword(String password) { |
| 456 | + this.password = password |
| 457 | + } |
| 458 | + |
| 459 | + void checkResource() throws IOException { |
| 460 | + final HttpURLConnection connection = buildConnection() |
| 461 | + connection.connect() |
| 462 | + final Integer response = connection.getResponseCode() |
| 463 | + if (validResponseCodes.contains(response)) { |
| 464 | + return |
| 465 | + } else { |
| 466 | + throw new IOException(response + " " + connection.getResponseMessage()) |
| 467 | + } |
| 468 | + } |
| 469 | + |
| 470 | + HttpURLConnection buildConnection() throws IOException { |
| 471 | + final HttpURLConnection connection = (HttpURLConnection) this.@url.openConnection() |
| 472 | + |
| 473 | + if (connection instanceof HttpsURLConnection) { |
| 474 | + TrustManager[] trustAllCerts = [new X509TrustManager() { |
| 475 | + X509Certificate[] getAcceptedIssuers() { |
| 476 | + return null |
| 477 | + } |
| 478 | + |
| 479 | + void checkClientTrusted(X509Certificate[] certs, String authType) { |
| 480 | + } |
| 481 | + |
| 482 | + void checkServerTrusted(X509Certificate[] certs, String authType) { |
| 483 | + } |
| 484 | + } |
| 485 | + ] as TrustManager[] |
| 486 | + SSLContext sc = SSLContext.getInstance("SSL") |
| 487 | + sc.init(null, trustAllCerts, new java.security.SecureRandom()) |
| 488 | + connection.setSSLSocketFactory(sc.getSocketFactory()) |
| 489 | + // Create all-trusting host name verifier |
| 490 | + HostnameVerifier allHostsValid = new HostnameVerifier() { |
| 491 | + boolean verify(String hostname, SSLSession session) { |
| 492 | + return true |
| 493 | + } |
| 494 | + } |
| 495 | + // Install the all-trusting host verifier |
| 496 | + connection.setHostnameVerifier(allHostsValid) |
| 497 | + } |
| 498 | + |
| 499 | + configureBasicAuth(connection) |
| 500 | + connection.setRequestMethod("GET") |
| 501 | + return connection |
| 502 | + } |
| 503 | + |
| 504 | + void configureBasicAuth(HttpURLConnection connection) { |
| 505 | + if (username != null) { |
| 506 | + if (password == null) { |
| 507 | + throw new IllegalStateException("Basic Auth user [" + username + "] has been set, but no password has been configured") |
| 508 | + } |
| 509 | + connection.setRequestProperty( |
| 510 | + "Authorization", |
| 511 | + "Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes(StandardCharsets.UTF_8)) |
| 512 | + ) |
| 513 | + } |
| 514 | + } |
| 515 | + |
| 516 | +} |
| 517 | + |
408 | 518 | def waitForClusterSetup(OpenSearchCluster cluster, Boolean securityEnabled) { |
409 | 519 | cluster.@waitConditions.clear() |
410 | 520 | String unicastUris = cluster.nodes.stream().flatMap { node -> |
411 | 521 | node.getAllTransportPortURI().stream() |
412 | 522 | }.collect(Collectors.joining("\n")) |
413 | 523 | cluster.nodes.forEach {node -> |
414 | 524 | try { |
415 | | - Files.write(node.getConfigDir().resolve("unicast_hosts.txt"), unicastUris.getBytes(StandardCharsets.UTF_8)); |
| 525 | + Files.write(node.getConfigDir().resolve("unicast_hosts.txt"), unicastUris.getBytes(StandardCharsets.UTF_8)) |
416 | 526 | } catch (IOException e) { |
417 | | - throw new java.io.UncheckedIOException("Failed to write configuation files for " + this, e); |
| 527 | + throw new java.io.UncheckedIOException("Failed to write configuation files for " + this, e) |
418 | 528 | } |
419 | 529 | } |
420 | 530 |
|
421 | 531 | Predicate pred = { |
422 | 532 | String protocol = securityEnabled ? "https" : "http" |
423 | | - WaitForHttpResource wait = new WaitForHttpResource(protocol, cluster.getFirstNode().getHttpSocketURI(), cluster.nodes.size()) |
| 533 | + WaitForClusterYellow wait = new WaitForClusterYellow(protocol, cluster.getFirstNode().getHttpSocketURI(), cluster.nodes.size()) |
424 | 534 | wait.setUsername(System.getProperty("user", "admin")) |
425 | 535 | wait.setPassword(System.getProperty("password", "admin")) |
426 | 536 | return wait.wait(500) |
@@ -451,7 +561,7 @@ integTest { |
451 | 561 | } |
452 | 562 | } |
453 | 563 |
|
454 | | - // The -Dcluster.debug option makes the cluster debuggable; this makes the tests debuggable |
| 564 | + // The -Dcluster.debug option makes the cluster debuggable, this makes the tests debuggable |
455 | 565 | if (System.getProperty("test.debug") != null) { |
456 | 566 | jvmArgs '-agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=8000' |
457 | 567 | } |
@@ -490,6 +600,7 @@ task integTestRemote(type: RestIntegTestTask) { |
490 | 600 | systemProperty "https", System.getProperty("https") |
491 | 601 | systemProperty "user", System.getProperty("user") |
492 | 602 | systemProperty "password", System.getProperty("password") |
| 603 | + systemProperty 'buildDir', buildDir.path |
493 | 604 |
|
494 | 605 | if (System.getProperty("tests.rest.bwcsuite") == null) { |
495 | 606 | filter { |
|
0 commit comments