Moved external HttpServer to hal-core and added SSL possibility through LestEncrypt

This commit is contained in:
Ziver Koc 2021-08-05 16:41:10 +02:00
parent 2dc35e212b
commit e8270d4027
6 changed files with 113 additions and 22 deletions

View file

@ -4,4 +4,6 @@
dependencies { dependencies {
implementation 'org.xerial:sqlite-jdbc:3.32.3.2' implementation 'org.xerial:sqlite-jdbc:3.32.3.2'
implementation 'org.shredzone.acme4j:acme4j-client:2.12'
implementation 'org.shredzone.acme4j:acme4j-utils:2.12'
} }

View file

@ -22,6 +22,8 @@ public class HalContext {
// Constants // Constants
public static final String CONFIG_HTTP_PORT = "hal_core.http_port"; public static final String CONFIG_HTTP_PORT = "hal_core.http_port";
public static final String CONFIG_HTTP_EXTERNAL_PORT = "hal_core.http_external_port";
public static final String CONFIG_HTTP_EXTERNAL_DOMAIN = "hal_core.http_external_domain";
public static final String CONFIG_MAP_BACKGROUND_IMAGE = "hal_core.map_bgimage"; public static final String CONFIG_MAP_BACKGROUND_IMAGE = "hal_core.map_bgimage";
public static final String RESOURCE_ROOT; public static final String RESOURCE_ROOT;

View file

@ -4,15 +4,19 @@ package se.hal;
import se.hal.intf.*; import se.hal.intf.*;
import se.hal.page.HalAlertManager; import se.hal.page.HalAlertManager;
import se.hal.struct.PluginConfig; import se.hal.struct.PluginConfig;
import se.hal.util.HalAcmeDataStore;
import zutil.db.DBConnection; import zutil.db.DBConnection;
import zutil.io.file.FileUtil; import zutil.io.file.FileUtil;
import zutil.log.LogUtil; import zutil.log.LogUtil;
import zutil.net.acme.AcmeClient;
import zutil.net.http.HttpPage;
import zutil.net.http.HttpServer; import zutil.net.http.HttpServer;
import zutil.net.http.page.HttpFilePage; import zutil.net.http.page.HttpFilePage;
import zutil.net.http.page.HttpRedirectPage; import zutil.net.http.page.HttpRedirectPage;
import zutil.plugin.PluginData; import zutil.plugin.PluginData;
import zutil.plugin.PluginManager; import zutil.plugin.PluginManager;
import java.security.cert.Certificate;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
@ -22,6 +26,9 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import static se.hal.HalContext.CONFIG_HTTP_EXTERNAL_DOMAIN;
import static se.hal.HalContext.CONFIG_HTTP_EXTERNAL_PORT;
/** /**
* Main class for Hal * Main class for Hal
*/ */
@ -34,7 +41,7 @@ public class HalServer {
private static List<HalDaemon> daemons = new ArrayList<>(); private static List<HalDaemon> daemons = new ArrayList<>();
private static HttpServer http; private static HttpServer http;
private static List<HalWebPage> pages = new ArrayList<>(); private static HttpServer httpExternal;
private static PluginManager pluginManager; private static PluginManager pluginManager;
@ -51,8 +58,9 @@ public class HalServer {
// init variables // init variables
pluginManager = new PluginManager(); pluginManager = new PluginManager();
daemonExecutor = Executors.newScheduledThreadPool(1); // We set only one thread for easier troubleshooting daemonExecutor = Executors.newScheduledThreadPool(1); // We set only one thread for easier troubleshooting for now
http = new HttpServer(HalContext.getIntegerProperty(HalContext.CONFIG_HTTP_PORT)); http = new HttpServer(HalContext.getIntegerProperty(HalContext.CONFIG_HTTP_PORT));
http.start();
// Upgrade database // Upgrade database
HalDatabaseUpgradeManager.initialize(pluginManager); HalDatabaseUpgradeManager.initialize(pluginManager);
@ -65,6 +73,27 @@ public class HalServer {
logger.info("Working directory: " + FileUtil.find(".").getAbsolutePath()); logger.info("Working directory: " + FileUtil.find(".").getAbsolutePath());
// ------------------------------------
// Initialize External HttpServer
// ------------------------------------
if (HalContext.containsProperty(CONFIG_HTTP_EXTERNAL_PORT) &&
HalContext.containsProperty(CONFIG_HTTP_EXTERNAL_DOMAIN)) {
// Start a non secure server to retrieve handle the ACME protocol challenge
HttpServer tmpHttpExternal = new HttpServer(HalContext.getIntegerProperty(CONFIG_HTTP_EXTERNAL_PORT));
tmpHttpExternal.start();
AcmeClient acme = new AcmeClient(new HalAcmeDataStore());
Certificate certificate = acme.fetchCertificate(tmpHttpExternal, HalContext.getStringProperty(CONFIG_HTTP_EXTERNAL_DOMAIN));
tmpHttpExternal.close();
httpExternal = new HttpServer(HalContext.getIntegerProperty(CONFIG_HTTP_EXTERNAL_PORT));
httpExternal.start();
} else {
logger.warning("Missing '" + CONFIG_HTTP_EXTERNAL_PORT + "' and '" + CONFIG_HTTP_EXTERNAL_DOMAIN + "' configuration, will not setup external http server.");
return;
}
// ------------------------------------ // ------------------------------------
// Initialize Plugins // Initialize Plugins
// ------------------------------------ // ------------------------------------
@ -124,7 +153,6 @@ public class HalServer {
registerPage(it.next()); registerPage(it.next());
for (Iterator<HalWebPage> it = pluginManager.getSingletonIterator(HalWebPage.class); it.hasNext(); ) for (Iterator<HalWebPage> it = pluginManager.getSingletonIterator(HalWebPage.class); it.hasNext(); )
registerPage(it.next()); registerPage(it.next());
http.start();
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, "Startup failed.", e); logger.log(Level.SEVERE, "Startup failed.", e);
@ -172,11 +200,45 @@ public class HalServer {
daemon.initiate(daemonExecutor); daemon.initiate(daemonExecutor);
} }
/** /**
* @param page registers the given page with the intranet Hal web server. * Registers the given page with the intranet Hal web server.
*
* @param url is the web path to the page.
* @param page is the page to register with the server.
*/
public static void registerPage(String url, HttpPage page){
http.setPage(url, page);
}
/**
* Registers the given page with the intranet Hal web server.
*
* @param page is the page to register with the server.
*/ */
public static void registerPage(HalWebPage page){ public static void registerPage(HalWebPage page){
pages.add(page); registerPage(page.getId(), page);
http.setPage(page.getId(), page); }
/**
* Registers the given page with the external Hal web server.
* Note: as this page will most likely be accessible trough the internet it needs to be robust and secure.
*
* @param url is the web path to the page.
* @param page is the page to register with the server.
*/
public static void registerExternalPage(String url, HttpPage page){
if (httpExternal != null)
httpExternal.setPage(url, page);
}
/**
* Registers the given page with the external Hal web server.
* Note: as this page will most likely be accessible trough the internet it needs to be robust and secure.
*
* @param page is the page to register with the server.
*/
public static void registerExternalPage(HalWebPage page){
registerExternalPage(page.getId(), page);
} }
} }

View file

@ -0,0 +1,30 @@
package se.hal.util;
import zutil.net.acme.AcmeDataStore;
import java.security.KeyPair;
public class HalAcmeDataStore implements AcmeDataStore {
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";
@Override
public KeyPair loadUserKeyPair() {
return null;
}
@Override
public void storeUserKeyPair(KeyPair keyPair) {
}
@Override
public KeyPair loadDomainKeyPair() {
return null;
}
@Override
public void storeDomainKeyPair(KeyPair keyPair) {
}
}

View file

@ -3,6 +3,8 @@
# ------------------------------------ # ------------------------------------
hal_core.http_port=8080 hal_core.http_port=8080
hal_core.http_external_port=8081
#hal_core.http_external_domain=example.com
# ------------------------------------------------------------------------ # ------------------------------------------------------------------------
# Plugin configurations # Plugin configurations
@ -13,16 +15,15 @@ hal_core.http_port=8080
# ------------------------------------ # ------------------------------------
## Tellstick plugin ## Tellstick plugin
#hal_tellstick.com_port=COM5 #hal_tellstick.com_port=COM5|/dev/serial/by-id/usb-Telldus_TellStick_Duo_A6XNNE6Z-if00-port0
#hal_tellstick.com_port=/dev/serial/by-id/usb-Telldus_TellStick_Duo_A6XNNE6Z-if00-port0
## NetUPS plugin ## NetUPS plugin
#hal_nutups.host= #hal_nutups.host=
#hal_nutups.port= #hal_nutups.port=
## NetScan plugin ## NetScan plugin
# Network scanning should probably be disabled in some networks (default on) # Network scanning should probably be disabled in some networks
#hal_netscan.ipscan=false #hal_netscan.ipscan=true
## Zigbee plugin ## Zigbee plugin
#hal_zigbee.com_port=COM4 #hal_zigbee.com_port=COM4
@ -39,5 +40,4 @@ hal_powerchallenge.sync_port=6666
# ------------------------------------ # ------------------------------------
## Google Assistant ## Google Assistant
hal_assistant.google.port=8081
hal_assistant.google.client_id=https://oauth-redirect.googleusercontent.com/r/optimal-comfort-XXXXX hal_assistant.google.client_id=https://oauth-redirect.googleusercontent.com/r/optimal-comfort-XXXXX

View file

@ -25,9 +25,9 @@
package se.hal.plugin.assistant.google; package se.hal.plugin.assistant.google;
import se.hal.HalContext; import se.hal.HalContext;
import se.hal.HalServer;
import se.hal.intf.HalDaemon; import se.hal.intf.HalDaemon;
import zutil.log.LogUtil; import zutil.log.LogUtil;
import zutil.net.http.HttpServer;
import zutil.net.http.page.oauth.OAuth2AuthorizationPage; import zutil.net.http.page.oauth.OAuth2AuthorizationPage;
import zutil.net.http.page.oauth.OAuth2Registry; import zutil.net.http.page.oauth.OAuth2Registry;
import zutil.net.http.page.oauth.OAuth2TokenPage; import zutil.net.http.page.oauth.OAuth2TokenPage;
@ -43,19 +43,16 @@ public class SmartHomeDaemon implements HalDaemon {
public static final String ENDPOINT_TOKEN = "api/assistant/google/auth/token"; public static final String ENDPOINT_TOKEN = "api/assistant/google/auth/token";
public static final String ENDPOINT_SMARTHOME = "api/assistant/google/smarthome"; public static final String ENDPOINT_SMARTHOME = "api/assistant/google/smarthome";
private static final String CONFIG_PORT = "hal_assistant.google.port";
private static final String CONFIG_CLIENT_ID = "hal_assistant.google.client_id"; private static final String CONFIG_CLIENT_ID = "hal_assistant.google.client_id";
private SmartHomeImpl smartHome; private SmartHomeImpl smartHome;
private OAuth2Registry oAuth2Registry; private OAuth2Registry oAuth2Registry;
private HttpServer httpServer;
@Override @Override
public void initiate(ScheduledExecutorService executor) { public void initiate(ScheduledExecutorService executor) {
if (smartHome == null) { if (smartHome == null) {
if (!HalContext.containsProperty(CONFIG_PORT) || if (!HalContext.containsProperty(CONFIG_CLIENT_ID)) {
!HalContext.containsProperty(CONFIG_CLIENT_ID)) { logger.severe("Missing configuration, aborting initializations.");
logger.severe("Missing configuration, abort initializations.");
return; return;
} }
@ -65,11 +62,9 @@ public class SmartHomeDaemon implements HalDaemon {
oAuth2Registry.addWhitelist(HalContext.getStringProperty(CONFIG_CLIENT_ID)); oAuth2Registry.addWhitelist(HalContext.getStringProperty(CONFIG_CLIENT_ID));
oAuth2Registry.setTokenListener(smartHome); oAuth2Registry.setTokenListener(smartHome);
httpServer = new HttpServer(HalContext.getIntegerProperty(CONFIG_PORT)); HalServer.registerExternalPage(ENDPOINT_AUTH, new OAuth2AuthorizationPage(oAuth2Registry));
httpServer.setPage(ENDPOINT_AUTH, new OAuth2AuthorizationPage(oAuth2Registry)); HalServer.registerExternalPage(ENDPOINT_TOKEN, new OAuth2TokenPage(oAuth2Registry));
httpServer.setPage(ENDPOINT_TOKEN, new OAuth2TokenPage(oAuth2Registry)); HalServer.registerExternalPage(ENDPOINT_SMARTHOME, new SmartHomePage(smartHome));
httpServer.setPage(ENDPOINT_SMARTHOME, new SmartHomePage(smartHome));
httpServer.start();
} }
} }