Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds tests for demo configuration java tool #3807

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
8d29d42
Initial commit to add tests
DarshitChanpura Nov 15, 2023
0ca5c71
Added unit tests for Installer class
DarshitChanpura Nov 28, 2023
1cb00f6
Adds tests for SecuritySettingsConfigurer class and modifies relevant…
DarshitChanpura Nov 30, 2023
053b785
Adds tests for CertificateGenerator class
DarshitChanpura Nov 30, 2023
52a5325
Adds missing license headers
DarshitChanpura Nov 30, 2023
b56965e
Adds integration tests to valid demo config script against a remote c…
DarshitChanpura Nov 30, 2023
7a1ae99
Upddates line end characters to use System.lineSeparator()
DarshitChanpura Nov 30, 2023
dcaa380
Adds a common certificate validity check
DarshitChanpura Nov 30, 2023
0e45884
Fixes 1 of 2 broken windows tests
DarshitChanpura Dec 1, 2023
c77fe79
Fixes codehygiene check
DarshitChanpura Dec 1, 2023
9bb7333
Fixes issue with shell script while using bundled jdk to execute the …
DarshitChanpura Dec 1, 2023
c3416fe
Fixes demo certificate validator tests
DarshitChanpura Dec 1, 2023
4de2cc7
Fixes broken windows tests
DarshitChanpura Dec 3, 2023
3feca2e
Updates settings writer to use snakeyaml
DarshitChanpura Dec 4, 2023
de15846
Rewrite the whole tool to use singleton pattern
DarshitChanpura Dec 4, 2023
1ce63ff
Script no longer generates password if one is not supplied. Instead t…
DarshitChanpura Dec 6, 2023
5c7d3e5
Fixes Installer test to fetch expected version
DarshitChanpura Dec 7, 2023
de18a16
Updates tests to reflect to changes around buildOptions
DarshitChanpura Dec 11, 2023
788ae2f
Adds more comments
DarshitChanpura Dec 12, 2023
93ff488
Updates the way keys are looked up in yaml file
DarshitChanpura Dec 12, 2023
0887922
Updates the tests related to yml fieldName lookup
DarshitChanpura Dec 12, 2023
daa0fae
Refactors references to renamed source method
DarshitChanpura Dec 12, 2023
c9b351c
Removes static variable code smell
DarshitChanpura Dec 13, 2023
ebe3d6d
Renames test classes
DarshitChanpura Dec 13, 2023
bcfb5e6
Refactors certificate generator tests
DarshitChanpura Dec 13, 2023
b865415
Refactors out stream assertions
DarshitChanpura Dec 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ void readOptions(String[] args) {
* Prints the help menu when -h option is passed
*/
void showHelp() {
formatter.printHelp("install_demo_configuration.sh", options, true);
formatter.printHelp("install_demo_configuration" + FILE_EXTENSION, options, true);
System.exit(0);
}

Expand Down Expand Up @@ -438,4 +438,12 @@ void finishScriptExecution() {
System.out.println(e.getMessage());
}
}

/**
* FOR TESTS ONLY
* resets the installer state to allow testing with fresh instance for the next test.
*/
static void resetInstance() {
instance = null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/

package org.opensearch.security.sanity.tests;

import org.hamcrest.MatcherAssert;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import org.opensearch.client.Request;
import org.opensearch.client.Response;
import org.opensearch.client.ResponseException;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;

public class InvalidAdminPasswordIT extends SecurityRestTestCase {

static String currentPasswordVariable = System.getProperty("password");

@BeforeClass
public static void setUpAdminAsPasswordVariable() {
System.setProperty("password", "admin");
}

@AfterClass
public static void restorePasswordProperty() {
System.setProperty("password", currentPasswordVariable);
}

@Test
public void testAdminCredentials_adminAsPassword_shouldFail() throws Exception {
try {
client().performRequest(new Request("GET", ""));
} catch (ResponseException e) {
Response res = e.getResponse();
MatcherAssert.assertThat(res.getStatusLine().getStatusCode(), is(equalTo(401)));
MatcherAssert.assertThat(res.getStatusLine().getReasonPhrase(), is(equalTo("Unauthorized")));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@
import org.hamcrest.MatcherAssert;
import org.junit.Test;

import org.opensearch.client.Request;
import org.opensearch.client.Response;

import static org.hamcrest.Matchers.anEmptyMap;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
Expand All @@ -34,6 +38,13 @@ public void testSecurityPluginInstallation() throws Exception {
verifyPluginInstallationOnAllNodes();
}

@Test
public void testAdminCredentials_validAdminPassword_shouldSucceed() throws Exception {
Response response = client().performRequest(new Request("GET", ""));
MatcherAssert.assertThat(response.getStatusLine().getStatusCode(), is(equalTo(200)));
MatcherAssert.assertThat(response.getStatusLine().getReasonPhrase(), is(equalTo("OK")));
DarshitChanpura marked this conversation as resolved.
Show resolved Hide resolved
}

private void verifyPluginInstallationOnAllNodes() throws Exception {

Map<String, Map<String, Object>> nodesInCluster = (Map<String, Map<String, Object>>) getAsMapByAdmin("_nodes").get("nodes");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/

package org.opensearch.security.tools.democonfig;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.Instant;
import java.time.LocalDate;
import java.time.Period;
import java.util.Base64;
import java.util.Date;
import java.util.TimeZone;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import org.opensearch.security.tools.democonfig.util.NoExitSecurityManager;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.is;
import static org.opensearch.security.tools.democonfig.util.DemoConfigHelperUtil.createDirectory;
import static org.opensearch.security.tools.democonfig.util.DemoConfigHelperUtil.deleteDirectoryRecursive;
import static org.junit.Assert.fail;

public class CertificateGeneratorTests {

private static Installer installer;

@Before
public void setUp() {
installer = Installer.getInstance();
installer.buildOptions();
installer.OPENSEARCH_CONF_DIR = System.getProperty("user.dir") + File.separator + "test-conf";
createDirectory(installer.OPENSEARCH_CONF_DIR);
}

@After
public void tearDown() {
deleteDirectoryRecursive(installer.OPENSEARCH_CONF_DIR);
Installer.resetInstance();
}

@Test
public void testCreateDemoCertificates() throws Exception {
CertificateGenerator certificateGenerator = new CertificateGenerator(installer);
Certificates[] certificatesArray = Certificates.values();

certificateGenerator.createDemoCertificates();

// root-ca.pem, esnode.pem, esnode-key.pem, kirk.pem, kirk-key.pem
int expectedNumberOfCertificateFiles = 5;

int certsFound = 0;

for (Certificates cert : certificatesArray) {
String certFilePath = installer.OPENSEARCH_CONF_DIR + File.separator + cert.getFileName();
File certFile = new File(certFilePath);
assertThat(certFile.exists(), is(equalTo(true)));
assertThat(certFile.canRead(), is(equalTo(true)));

if (certFilePath.endsWith("-key.pem")) {
checkPrivateKeyValidity(certFilePath);
} else {
checkCertificateValidity(certFilePath);
}

// increment a count since a valid certificate was found
certsFound++;
}

assertThat(certsFound, equalTo(expectedNumberOfCertificateFiles));
}

@Test
public void testCreateDemoCertificates_invalidPath() {
installer.OPENSEARCH_CONF_DIR = "invalidPath";
CertificateGenerator certificateGenerator = new CertificateGenerator(installer);
try {
System.setSecurityManager(new NoExitSecurityManager());
certificateGenerator.createDemoCertificates();
} catch (SecurityException e) {
assertThat(e.getMessage(), equalTo("System.exit(-1) blocked to allow print statement testing."));
} finally {
System.setSecurityManager(null);
}
}

private static void checkCertificateValidity(String certPath) throws Exception {
try (FileInputStream certInputStream = new FileInputStream(certPath)) {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate certificate = cf.generateCertificate(certInputStream);

if (certificate instanceof X509Certificate) {
X509Certificate x509Certificate = (X509Certificate) certificate;
Date expiryDate = x509Certificate.getNotAfter();
Instant expiry = expiryDate.toInstant();

Period duration = getPeriodBetween(x509Certificate.getNotBefore().toInstant(), expiry);
if (certPath.endsWith("-ca.pem")) {
// root-ca.pem is already expired as the validity is only 30 days from generation
// so we just check interval to be of 30 days
assertThat(duration.getDays(), equalTo(30));
return;
}

// we check that cert is valid for total of ~10 yrs
// we don't check days as leaps years may cause flaky-ness
assertThat(duration.getYears(), equalTo(9));
assertThat(duration.getMonths(), equalTo(11));

x509Certificate.checkValidity();
verifyExpiryAtLeastAYearFromNow(expiry);

assertThat(x509Certificate.getSigAlgName(), is(equalTo("SHA256withRSA")));
}
}
}

private static void verifyExpiryAtLeastAYearFromNow(Instant expiry) {
Period gap = getPeriodBetween(Instant.now(), expiry);
assertThat(gap.getYears(), greaterThanOrEqualTo(1));
}

private static Period getPeriodBetween(Instant start, Instant end) {
LocalDate startDate = LocalDate.ofInstant(start, TimeZone.getTimeZone("EDT").toZoneId());
LocalDate endDate = LocalDate.ofInstant(end, TimeZone.getTimeZone("EDT").toZoneId());

return Period.between(startDate, endDate);
}

private void checkPrivateKeyValidity(String keyPath) {
try {
String pemContent = readPEMFile(keyPath);

String base64Data = pemContent.replaceAll("-----BEGIN PRIVATE KEY-----|-----END PRIVATE KEY-----", "").replaceAll("\\s", "");

byte[] keyBytes = Base64.getDecoder().decode(base64Data);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey key = kf.generatePrivate(new PKCS8EncodedKeySpec(keyBytes));
assertThat(key.getFormat(), is(equalTo("PKCS#8")));
assertThat(key.getAlgorithm(), is(equalTo("RSA")));
DarshitChanpura marked this conversation as resolved.
Show resolved Hide resolved
assertThat(key.isDestroyed(), is(equalTo(false)));
} catch (Exception e) {
fail("Error checking key validity: " + e.getMessage());
}
}

private static String readPEMFile(String pemFilePath) throws Exception {
StringBuilder pemContent = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new FileReader(pemFilePath))) {
String line;
while ((line = reader.readLine()) != null) {
pemContent.append(line).append("\n");
}
}
return pemContent.toString();
}
}
Loading
Loading