mirror of
https://github.com/Graylog2/graylog2-server.git
synced 2026-03-13 09:32:21 +08:00
Move certutil code to graylog-server (#15193)
This commit is contained in:
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Graylog, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the Server Side Public License, version 1,
|
||||
* as published by MongoDB, Inc.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* Server Side Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the Server Side Public License
|
||||
* along with this program. If not, see
|
||||
* <http://www.mongodb.com/licensing/server-side-public-license>.
|
||||
*/
|
||||
package org.graylog.datanode.bootstrap.commands.certutil;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.SignatureException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertPathValidatorException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
|
||||
class CertutilCaTest {
|
||||
|
||||
@TempDir
|
||||
static Path tempDir;
|
||||
|
||||
@Test
|
||||
void testCaCertificateGeneration() throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, InvalidAlgorithmParameterException, CertPathValidatorException, SignatureException, InvalidKeyException, NoSuchProviderException {
|
||||
|
||||
final Path certPath = tempDir.resolve("test-ca.p12");
|
||||
|
||||
final TestableConsole input = TestableConsole.empty()
|
||||
.register("Enter CA password", "password");
|
||||
|
||||
final CertutilCa command = new CertutilCa(certPath.toAbsolutePath().toString(), input);
|
||||
command.run();
|
||||
|
||||
KeyStore keyStore = KeyStore.getInstance("PKCS12");
|
||||
keyStore.load(new FileInputStream(certPath.toFile()), "password".toCharArray());
|
||||
|
||||
Assertions.assertThat(keyStore.getKey("root", "password".toCharArray())).isNotNull();
|
||||
Assertions.assertThat(keyStore.getKey("ca", "password".toCharArray())).isNotNull();
|
||||
final Certificate rootCert = keyStore.getCertificate("root");
|
||||
Assertions.assertThat(rootCert).isNotNull();
|
||||
|
||||
final Certificate caCert = keyStore.getCertificate("ca");
|
||||
|
||||
Assertions.assertThatCode(() -> caCert.verify(rootCert.getPublicKey()))
|
||||
.doesNotThrowAnyException();
|
||||
|
||||
|
||||
/*
|
||||
CertPathValidator validator = CertPathValidator.getInstance("PKIX");
|
||||
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
|
||||
final ArrayList<Certificate> objects = new ArrayList<>();
|
||||
objects.add(keyStore.getCertificate("root"));
|
||||
objects.add(keyStore.getCertificate("ca"));
|
||||
CertPath path = cf.generateCertPath(objects);
|
||||
|
||||
PKIXParameters params = new PKIXParameters(keyStore);
|
||||
|
||||
validator.validate(path, params);
|
||||
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Graylog, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the Server Side Public License, version 1,
|
||||
* as published by MongoDB, Inc.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* Server Side Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the Server Side Public License
|
||||
* along with this program. If not, see
|
||||
* <http://www.mongodb.com/licensing/server-side-public-license>.
|
||||
*/
|
||||
package org.graylog.datanode.bootstrap.commands.certutil;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.file.Path;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.Key;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.SignatureException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertPathValidatorException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
class CertutilCertTest {
|
||||
|
||||
@TempDir
|
||||
static Path tempDir;
|
||||
|
||||
@Test
|
||||
void testGenerateNodeCertificate() throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, InvalidAlgorithmParameterException, CertPathValidatorException, SignatureException, InvalidKeyException, NoSuchProviderException {
|
||||
|
||||
final Path caPath = tempDir.resolve("test-ca.p12");
|
||||
final Path nodePath = tempDir.resolve("test-node.p12");
|
||||
|
||||
final TestableConsole inputCa = TestableConsole.empty()
|
||||
.register("Enter CA password", "password");
|
||||
final CertutilCa certutilCa = new CertutilCa(caPath.toAbsolutePath().toString(), inputCa);
|
||||
certutilCa.run();
|
||||
|
||||
// now we have a ROOT + CA keypair in the keystore, let's use it to generate node keypair
|
||||
|
||||
TestableConsole inputCert = TestableConsole.empty()
|
||||
.register("Enter CA password", "password")
|
||||
.register("Enter datanode certificate password", "changeme");
|
||||
|
||||
CertutilCert certutilCert = new CertutilCert(
|
||||
caPath.toAbsolutePath().toString(),
|
||||
nodePath.toAbsolutePath().toString(),
|
||||
inputCert);
|
||||
certutilCert.run();
|
||||
|
||||
KeyStore caKeyStore = KeyStore.getInstance("PKCS12");
|
||||
caKeyStore.load(new FileInputStream(caPath.toFile()), "password".toCharArray());
|
||||
|
||||
KeyStore nodeKeyStore = KeyStore.getInstance("PKCS12");
|
||||
nodeKeyStore.load(new FileInputStream(nodePath.toFile()), "changeme".toCharArray());
|
||||
final Key nodeKey = nodeKeyStore.getKey(CertutilCert.DATANODE_KEY_ALIAS, "changeme".toCharArray());
|
||||
Assertions.assertThat(nodeKey).isNotNull();
|
||||
|
||||
Assertions.assertThatCode(() -> nodeKeyStore.getCertificate(CertutilCert.DATANODE_KEY_ALIAS).verify(caKeyStore.getCertificate("ca").getPublicKey()))
|
||||
.doesNotThrowAnyException();
|
||||
|
||||
final Certificate[] certificateChain = nodeKeyStore.getCertificateChain(CertutilCert.DATANODE_KEY_ALIAS);
|
||||
Assertions.assertThat(certificateChain)
|
||||
.hasSize(3)
|
||||
.extracting(c ->(X509Certificate)c)
|
||||
.extracting(c -> c.getSubjectX500Principal().getName())
|
||||
.contains("CN=root", "CN=ca", "CN=localhost");
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Graylog, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the Server Side Public License, version 1,
|
||||
* as published by MongoDB, Inc.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* Server Side Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the Server Side Public License
|
||||
* along with this program. If not, see
|
||||
* <http://www.mongodb.com/licensing/server-side-public-license>.
|
||||
*/
|
||||
package org.graylog.datanode.bootstrap.commands.certutil;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.bouncycastle.asn1.x509.Extension;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.Key;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.SignatureException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertPathValidatorException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
class CertutilHttpTest {
|
||||
|
||||
@TempDir
|
||||
static Path tempDir;
|
||||
|
||||
@Test
|
||||
void testGenerateNodeCertificate() throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, InvalidAlgorithmParameterException, CertPathValidatorException, SignatureException, InvalidKeyException, NoSuchProviderException {
|
||||
|
||||
final Path caPath = tempDir.resolve("test-ca.p12");
|
||||
final Path nodePath = tempDir.resolve("test-node.p12");
|
||||
|
||||
final TestableConsole inputCa = TestableConsole.empty()
|
||||
.register("Enter CA password", "password");
|
||||
final CertutilCa certutilCa = new CertutilCa(caPath.toAbsolutePath().toString(), inputCa);
|
||||
certutilCa.run();
|
||||
|
||||
// now we have a ROOT + CA keypair in the keystore, let's use it to generate node keypair
|
||||
|
||||
TestableConsole inputHttp = TestableConsole.empty()
|
||||
.register("Do you want to use your own certificate authority? Respond with y/n?", "n")
|
||||
.register("Enter CA password", "password")
|
||||
.register("Enter certificate validity in days", "90")
|
||||
.register("Enter alternative names (addresses) of this node [comma separated]", "example.com")
|
||||
.register("Enter HTTP certificate password", "changeme");
|
||||
|
||||
CertutilHttp certutilCert = new CertutilHttp(
|
||||
caPath.toAbsolutePath().toString(),
|
||||
nodePath.toAbsolutePath().toString(),
|
||||
inputHttp);
|
||||
certutilCert.run();
|
||||
|
||||
KeyStore caKeyStore = KeyStore.getInstance("PKCS12");
|
||||
caKeyStore.load(new FileInputStream(caPath.toFile()), "password".toCharArray());
|
||||
|
||||
KeyStore nodeKeyStore = KeyStore.getInstance("PKCS12");
|
||||
nodeKeyStore.load(new FileInputStream(nodePath.toFile()), "changeme".toCharArray());
|
||||
final Key nodeKey = nodeKeyStore.getKey(CertutilCert.DATANODE_KEY_ALIAS, "changeme".toCharArray());
|
||||
Assertions.assertThat(nodeKey).isNotNull();
|
||||
|
||||
final Certificate nodeCertificate = nodeKeyStore.getCertificate(CertutilCert.DATANODE_KEY_ALIAS);
|
||||
Assertions.assertThatCode(() -> nodeCertificate.verify(caKeyStore.getCertificate("ca").getPublicKey()))
|
||||
.doesNotThrowAnyException();
|
||||
|
||||
final Collection<List<?>> alternativeNames = ((X509Certificate) nodeCertificate).getSubjectAlternativeNames();
|
||||
Assertions.assertThat(alternativeNames)
|
||||
.isNotEmpty()
|
||||
.extracting(item -> (String) item.get(1))
|
||||
.contains("localhost", "example.com");
|
||||
|
||||
final Certificate[] certificateChain = nodeKeyStore.getCertificateChain(CertutilCert.DATANODE_KEY_ALIAS);
|
||||
Assertions.assertThat(certificateChain)
|
||||
.hasSize(3)
|
||||
.extracting(c ->(X509Certificate)c)
|
||||
.extracting(c -> c.getSubjectX500Principal().getName())
|
||||
.contains("CN=root", "CN=ca", "CN=localhost");
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Graylog, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the Server Side Public License, version 1,
|
||||
* as published by MongoDB, Inc.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* Server Side Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the Server Side Public License
|
||||
* along with this program. If not, see
|
||||
* <http://www.mongodb.com/licensing/server-side-public-license>.
|
||||
*/
|
||||
package org.graylog.datanode.bootstrap.commands.certutil;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
public class TestableConsole implements CommandLineConsole {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(TestableConsole.class);
|
||||
|
||||
private final List<Pair<String, String>> providedResponses = new LinkedList<>();
|
||||
private final List<String> output = new LinkedList<>();
|
||||
private boolean silent = false;
|
||||
|
||||
public static TestableConsole empty() {
|
||||
return new TestableConsole();
|
||||
}
|
||||
|
||||
public TestableConsole silent() {
|
||||
this.silent = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TestableConsole register(String question, String response) {
|
||||
this.providedResponses.add(Pair.of(cleanQuestion(question), response));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readLine(String format, Object... args) {
|
||||
final Pair<String, String> response = consumeResponse(format, args);
|
||||
return response.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] readPassword(String format, Object... args) {
|
||||
final Pair<String, String> response = consumeResponse(format, args);
|
||||
return response.getValue().toCharArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printLine(String line) {
|
||||
if (!silent) {
|
||||
LOG.info(line);
|
||||
}
|
||||
this.output.add(line);
|
||||
}
|
||||
|
||||
public List<String> getOutput() {
|
||||
return output;
|
||||
}
|
||||
|
||||
private Pair<String, String> consumeResponse(String format, Object[] args) {
|
||||
final String question = cleanQuestion(String.format(Locale.ROOT, format, args));
|
||||
final Pair<String, String> response = providedResponses.stream().filter(r -> r.getKey().equals(question)).findFirst()
|
||||
.orElseThrow(() -> new ConsoleException("Unexpected input question:" + question));
|
||||
providedResponses.remove(response);
|
||||
return response;
|
||||
}
|
||||
|
||||
private String cleanQuestion(String input) {
|
||||
return Optional.of(input)
|
||||
.map(String::trim)
|
||||
.map(s -> StringUtils.removeEnd(s, ":"))
|
||||
.map(String::trim)
|
||||
.get();
|
||||
}
|
||||
}
|
||||
@@ -24,11 +24,11 @@ import com.github.rholder.retry.WaitStrategies;
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.response.ValidatableResponse;
|
||||
import org.apache.http.NoHttpResponseException;
|
||||
import org.graylog.datanode.bootstrap.commands.certutil.CertutilCa;
|
||||
import org.graylog.datanode.bootstrap.commands.certutil.CertutilCert;
|
||||
import org.graylog.datanode.bootstrap.commands.certutil.CertutilHttp;
|
||||
import org.graylog.datanode.bootstrap.commands.certutil.TestableConsole;
|
||||
import org.graylog.datanode.testinfra.DatanodeContainerizedBackend;
|
||||
import org.graylog.security.certutil.CertutilCa;
|
||||
import org.graylog.security.certutil.CertutilCert;
|
||||
import org.graylog.security.certutil.CertutilHttp;
|
||||
import org.graylog.security.certutil.console.TestableConsole;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
Reference in New Issue
Block a user