From f4238ca242b246a3fe316ff0bafea8e389849d0b Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 6 Dec 2015 14:05:58 -0800 Subject: [PATCH 1/5] Add SSL support to HA --- homeassistant/components/http.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/http.py b/homeassistant/components/http.py index f76e7e16b11..1201f5b8528 100644 --- a/homeassistant/components/http.py +++ b/homeassistant/components/http.py @@ -6,16 +6,17 @@ This module provides an API and a HTTP interface for debug purposes. For more details about the RESTful API, please refer to the documentation at https://home-assistant.io/developers/api/ """ -import json -import threading -import logging -import time -import gzip -import os from datetime import timedelta -from http.server import SimpleHTTPRequestHandler, HTTPServer +import gzip from http import cookies +from http.server import SimpleHTTPRequestHandler, HTTPServer +import json +import logging +import os from socketserver import ThreadingMixIn +import ssl +import threading +import time from urllib.parse import urlparse, parse_qs import homeassistant.core as ha @@ -36,6 +37,7 @@ CONF_API_PASSWORD = "api_password" CONF_SERVER_HOST = "server_host" CONF_SERVER_PORT = "server_port" CONF_DEVELOPMENT = "development" +CONF_CERTIFICATE = 'certificate' DATA_API_PASSWORD = 'api_password' @@ -57,11 +59,12 @@ def setup(hass, config): server_host = conf.get(CONF_SERVER_HOST, '0.0.0.0') server_port = conf.get(CONF_SERVER_PORT, SERVER_PORT) development = str(conf.get(CONF_DEVELOPMENT, "")) == "1" + certificate = conf.get(CONF_CERTIFICATE) try: server = HomeAssistantHTTPServer( (server_host, server_port), RequestHandler, hass, api_password, - development) + development, certificate) except OSError: # If address already in use _LOGGER.exception("Error setting up HTTP server") @@ -88,7 +91,7 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer): # pylint: disable=too-many-arguments def __init__(self, server_address, request_handler_class, - hass, api_password, development): + hass, api_password, development, certificate): super().__init__(server_address, request_handler_class) self.server_address = server_address @@ -104,6 +107,9 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer): if development: _LOGGER.info("running http in development mode") + if certificate is not None: + self.socket = ssl.wrap_socket(self.socket, certfile=certificate) + def start(self): """ Starts the HTTP server. """ def stop_http(event): From b33e9fe6d9be501f7dc0d812f44887b5a22294c2 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 6 Dec 2015 14:13:35 -0800 Subject: [PATCH 2/5] Update API object to support SSL --- homeassistant/components/http.py | 3 ++- homeassistant/remote.py | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/http.py b/homeassistant/components/http.py index 1201f5b8528..144dbafba3c 100644 --- a/homeassistant/components/http.py +++ b/homeassistant/components/http.py @@ -76,7 +76,8 @@ def setup(hass, config): threading.Thread(target=server.start, daemon=True).start()) hass.http = server - hass.config.api = rem.API(util.get_local_ip(), api_password, server_port) + hass.config.api = rem.API(util.get_local_ip(), api_password, server_port, + certificate is not None) return True diff --git a/homeassistant/remote.py b/homeassistant/remote.py index 72f95ca389a..3b47b60365c 100644 --- a/homeassistant/remote.py +++ b/homeassistant/remote.py @@ -51,11 +51,14 @@ class API(object): """ Object to pass around Home Assistant API location and credentials. """ # pylint: disable=too-few-public-methods - def __init__(self, host, api_password=None, port=None): + def __init__(self, host, api_password=None, port=None, use_ssl=False): self.host = host self.port = port or SERVER_PORT self.api_password = api_password - self.base_url = "http://{}:{}".format(host, self.port) + if use_ssl: + self.base_url = "https://{}:{}".format(host, self.port) + else: + self.base_url = "http://{}:{}".format(host, self.port) self.status = None self._headers = {} From 9d8e077accf0984d37b42672518b4e2e4d3a57d9 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 6 Dec 2015 14:19:25 -0800 Subject: [PATCH 3/5] Add support for keys to HTTP component --- homeassistant/components/http.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/http.py b/homeassistant/components/http.py index 144dbafba3c..aa90ff7df84 100644 --- a/homeassistant/components/http.py +++ b/homeassistant/components/http.py @@ -37,7 +37,8 @@ CONF_API_PASSWORD = "api_password" CONF_SERVER_HOST = "server_host" CONF_SERVER_PORT = "server_port" CONF_DEVELOPMENT = "development" -CONF_CERTIFICATE = 'certificate' +CONF_SSL_CERTIFICATE = 'ssl_certificate' +CONF_SSL_KEY = 'ssl_key' DATA_API_PASSWORD = 'api_password' @@ -59,12 +60,13 @@ def setup(hass, config): server_host = conf.get(CONF_SERVER_HOST, '0.0.0.0') server_port = conf.get(CONF_SERVER_PORT, SERVER_PORT) development = str(conf.get(CONF_DEVELOPMENT, "")) == "1" - certificate = conf.get(CONF_CERTIFICATE) + ssl_certificate = conf.get(CONF_SSL_CERTIFICATE) + ssl_key = conf.get(CONF_SSL_KEY) try: server = HomeAssistantHTTPServer( (server_host, server_port), RequestHandler, hass, api_password, - development, certificate) + development, ssl_certificate, ssl_key) except OSError: # If address already in use _LOGGER.exception("Error setting up HTTP server") @@ -77,7 +79,7 @@ def setup(hass, config): hass.http = server hass.config.api = rem.API(util.get_local_ip(), api_password, server_port, - certificate is not None) + ssl_certificate is not None) return True @@ -92,7 +94,7 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer): # pylint: disable=too-many-arguments def __init__(self, server_address, request_handler_class, - hass, api_password, development, certificate): + hass, api_password, development, ssl_certificate, ssl_key): super().__init__(server_address, request_handler_class) self.server_address = server_address @@ -108,8 +110,11 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer): if development: _LOGGER.info("running http in development mode") - if certificate is not None: - self.socket = ssl.wrap_socket(self.socket, certfile=certificate) + if ssl_certificate is not None: + wrap_kwargs = {'certfile': ssl_certificate} + if ssl_key is not None: + wrap_kwargs['keyfile'] = ssl_key + self.socket = ssl.wrap_socket(self.socket, **wrap_kwargs) def start(self): """ Starts the HTTP server. """ From 832674286b008666f0d14a7c4f35c3940f061c85 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 6 Dec 2015 14:42:08 -0800 Subject: [PATCH 4/5] Update the http log message with correct url --- homeassistant/components/http.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/http.py b/homeassistant/components/http.py index aa90ff7df84..9ae65be1067 100644 --- a/homeassistant/components/http.py +++ b/homeassistant/components/http.py @@ -125,7 +125,7 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer): self.hass.bus.listen_once(ha.EVENT_HOMEASSISTANT_STOP, stop_http) _LOGGER.info( - "Starting web interface at http://%s:%d", *self.server_address) + "Starting web interface at %s", self.hass.config.api.base_url) # 31-1-2015: Refactored frontend/api components out of this component # To prevent stuff from breaking, load the two extracted components From 98467d0d9ff69fedc91eb2423521fa17b55f673d Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 6 Dec 2015 15:13:41 -0800 Subject: [PATCH 5/5] Correct HTTP start log message --- homeassistant/components/http.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/http.py b/homeassistant/components/http.py index 9ae65be1067..4ab0bfee351 100644 --- a/homeassistant/components/http.py +++ b/homeassistant/components/http.py @@ -103,6 +103,7 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer): self.development = development self.paths = [] self.sessions = SessionStore() + self.use_ssl = ssl_certificate is not None # We will lazy init this one if needed self.event_forwarder = None @@ -124,8 +125,11 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer): self.hass.bus.listen_once(ha.EVENT_HOMEASSISTANT_STOP, stop_http) + protocol = 'https' if self.use_ssl else 'http' + _LOGGER.info( - "Starting web interface at %s", self.hass.config.api.base_url) + "Starting web interface at %s://%s:%d", + protocol, self.server_address[0], self.server_address[1]) # 31-1-2015: Refactored frontend/api components out of this component # To prevent stuff from breaking, load the two extracted components