| 
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 | +// Re-write 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