Use existing certificate instead of doing the process all the time

This commit is contained in:
Ziver Koc 2021-08-22 01:42:28 +02:00
parent d9ce3af5aa
commit c197606204
2 changed files with 92 additions and 31 deletions

View file

@ -20,6 +20,8 @@ import zutil.plugin.PluginData;
import zutil.plugin.PluginManager;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
@ -80,37 +82,46 @@ public class HalServer {
// Initialize External HttpServer
// ------------------------------------
if (HalContext.containsProperty(CONFIG_HTTP_EXTERNAL_PORT) &&
HalContext.containsProperty(CONFIG_HTTP_EXTERNAL_DOMAIN)) {
AcmeClient acme;
HttpServer tmpHttpServer = null;
if (HalContext.containsProperty(CONFIG_HTTP_EXTERNAL_DOMAIN) && HalContext.containsProperty(CONFIG_HTTP_EXTERNAL_PORT)) {
String externalServerUrl = "https://" + HalContext.getStringProperty(HalContext.CONFIG_HTTP_EXTERNAL_DOMAIN) +
":" + HalContext.getStringProperty(HalContext.CONFIG_HTTP_EXTERNAL_PORT);
if ("dns".equals(HalContext.getStringProperty(HalContext.CONFIG_HTTP_EXTERNAL_ACME_TYPE, ""))) {
acme = new AcmeClient(new HalAcmeDataStore(), new AcmeManualDnsChallengeFactory(), AcmeClient.ACME_SERVER_LETSENCRYPT_STAGING);
} else if ("http".equals(HalContext.getStringProperty(HalContext.CONFIG_HTTP_EXTERNAL_ACME_TYPE, "http"))) {
tmpHttpServer = new HttpServer(80);
tmpHttpServer.start();
HalAcmeDataStore acmeDataStore = new HalAcmeDataStore();
X509Certificate certificate = acmeDataStore.getCertificate();
acme = new AcmeClient(new HalAcmeDataStore(), new AcmeHttpChallengeFactory(tmpHttpServer), AcmeClient.ACME_SERVER_LETSENCRYPT_STAGING);
} else {
throw new IllegalArgumentException("Unknown config value for " + HalContext.CONFIG_HTTP_EXTERNAL_ACME_TYPE + ": " +
HalContext.getStringProperty(HalContext.CONFIG_HTTP_EXTERNAL_ACME_TYPE));
if (!AcmeClient.isCertificateValid(certificate)) {
// Prepare ACME Client
AcmeClient acme;
HttpServer tmpHttpServer = null;
if ("dns".equals(HalContext.getStringProperty(HalContext.CONFIG_HTTP_EXTERNAL_ACME_TYPE, ""))) {
acme = new AcmeClient(acmeDataStore, new AcmeManualDnsChallengeFactory(), AcmeClient.ACME_SERVER_LETSENCRYPT_STAGING);
} else if ("http".equals(HalContext.getStringProperty(HalContext.CONFIG_HTTP_EXTERNAL_ACME_TYPE, "http"))) {
tmpHttpServer = new HttpServer(80);
tmpHttpServer.start();
acme = new AcmeClient(acmeDataStore, new AcmeHttpChallengeFactory(tmpHttpServer), AcmeClient.ACME_SERVER_LETSENCRYPT_STAGING);
} else {
throw new IllegalArgumentException("Unknown config value for " + externalServerUrl);
}
// Request certificate and start the external webserver
acme.addDomain(HalContext.getStringProperty(CONFIG_HTTP_EXTERNAL_DOMAIN));
acme.prepareRequest();
certificate = acme.requestCertificate();
acmeDataStore.storeCertificate(certificate);
// Cleanup
if (tmpHttpServer != null) {
tmpHttpServer.close();
}
}
acme.addDomain(HalContext.getStringProperty(CONFIG_HTTP_EXTERNAL_DOMAIN));
acme.prepareRequest();
Certificate certificate = acme.requestCertificate();
httpExternal = new HttpServer(HalContext.getIntegerProperty(CONFIG_HTTP_EXTERNAL_PORT), certificate);
httpExternal.start();
// Cleanup
if ("http".equals(HalContext.getStringProperty(HalContext.CONFIG_HTTP_EXTERNAL_ACME_TYPE, "http"))) {
tmpHttpServer.close();
}
logger.info("External https server up and running at: https://" + HalContext.getStringProperty(CONFIG_HTTP_EXTERNAL_DOMAIN) + ":" + HalContext.containsProperty(CONFIG_HTTP_EXTERNAL_PORT));
logger.info("External https server up and running at: " + externalServerUrl);
} else {
logger.warning("Missing '" + CONFIG_HTTP_EXTERNAL_PORT + "' and '" + CONFIG_HTTP_EXTERNAL_DOMAIN + "' configuration, will not setup external http server.");
return;

View file

@ -1,30 +1,53 @@
package se.hal.util;
import org.shredzone.acme4j.toolbox.AcmeUtils;
import org.shredzone.acme4j.util.KeyPairUtils;
import se.hal.HalContext;
import zutil.io.StringInputStream;
import zutil.log.LogUtil;
import zutil.net.acme.AcmeDataStore;
import zutil.parser.Base64Decoder;
import zutil.parser.Base64Encoder;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyPair;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.logging.Level;
import java.util.logging.Logger;
public class HalAcmeDataStore implements AcmeDataStore {
private static final Logger logger = LogUtil.getLogger();
private static final String CONFIG_HTTP_EXTERNAL_USER_KEY = "hal_core.http_external_user_key";
private static final String CONFIG_HTTP_EXTERNAL_DOMAIN_KEY = "hal_core.http_external_domain_key";
private static final String CONFIG_HTTP_EXTERNAL_ACCOUNT_LOCATION = "hal_core.http_external_account_location";
private static final String CONFIG_HTTP_EXTERNAL_ACCOUNT_KEY = "hal_core.http_external_account_key";
private static final String CONFIG_HTTP_EXTERNAL_DOMAIN_KEY = "hal_core.http_external_domain_key";
private static final String CONFIG_HTTP_EXTERNAL_CERTIFICATE = "hal_core.http_external_certificate";
@Override
public KeyPair loadUserKeyPair() {
return loadKeyPair(CONFIG_HTTP_EXTERNAL_USER_KEY);
public URL getAccountLocation() {
try {
if (HalContext.containsProperty(CONFIG_HTTP_EXTERNAL_ACCOUNT_LOCATION))
return new URL(HalContext.getStringProperty(CONFIG_HTTP_EXTERNAL_ACCOUNT_LOCATION));
} catch (MalformedURLException e) {
logger.log(Level.SEVERE, "Unable to create account URL.", e);
}
return null;
}
@Override
public KeyPair loadDomainKeyPair() {
public KeyPair getAccountKeyPair() {
return loadKeyPair(CONFIG_HTTP_EXTERNAL_ACCOUNT_KEY);
}
@Override
public KeyPair getDomainKeyPair() {
return loadKeyPair(CONFIG_HTTP_EXTERNAL_DOMAIN_KEY);
}
@ -43,8 +66,9 @@ public class HalAcmeDataStore implements AcmeDataStore {
@Override
public void storeUserKeyPair(KeyPair keyPair) {
storeKeyPair(keyPair, CONFIG_HTTP_EXTERNAL_USER_KEY);
public void storeAccountKeyPair(URL accountLocation, KeyPair accountKeyPair) {
HalContext.setProperty(CONFIG_HTTP_EXTERNAL_ACCOUNT_LOCATION, accountLocation.toString());
storeKeyPair(accountKeyPair, CONFIG_HTTP_EXTERNAL_ACCOUNT_KEY);
}
@Override
@ -63,4 +87,30 @@ public class HalAcmeDataStore implements AcmeDataStore {
logger.log(Level.SEVERE, "Was unable to store KeyPair to DB.", e);
}
}
@Override
public X509Certificate getCertificate() {
if (HalContext.containsProperty(CONFIG_HTTP_EXTERNAL_CERTIFICATE)) {
try {
CertificateFactory factory = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate) factory.generateCertificate(
new StringInputStream(HalContext.getStringProperty(CONFIG_HTTP_EXTERNAL_CERTIFICATE)));
return certificate;
} catch (CertificateException e) {
logger.log(Level.SEVERE, "Was unable to read certificate from DB.", e);
}
}
return null;
}
@Override
public void storeCertificate(X509Certificate certificate) {
try (StringWriter out = new StringWriter()) {
AcmeUtils.writeToPem(certificate.getEncoded(), AcmeUtils.PemLabel.CERTIFICATE, out);
HalContext.setProperty(CONFIG_HTTP_EXTERNAL_CERTIFICATE, out.toString());
} catch (IOException | CertificateEncodingException e) {
logger.log(Level.SEVERE, "Was unable to store certificate to DB.", e);
}
}
}