Mqtt client key auth (#1935)

* Made changes so that the mqtt configuration can accept client keys and certs for auth.

* Need to figure out how the broker_config works, it's failing tests

* Fixed it so all tests passed and ssl feature works for all brokers
which are't embedded

* Bring into line with pep8

* Added config validation which has allowed me to make the code simpler
This commit is contained in:
Tim Harton 2016-05-02 18:21:28 +12:00 committed by Paulus Schoutsen
parent b51561cd9b
commit f6df5bc390

View File

@ -39,6 +39,9 @@ CONF_KEEPALIVE = 'keepalive'
CONF_USERNAME = 'username' CONF_USERNAME = 'username'
CONF_PASSWORD = 'password' CONF_PASSWORD = 'password'
CONF_CERTIFICATE = 'certificate' CONF_CERTIFICATE = 'certificate'
CONF_CLIENT_KEY = 'client_key'
CONF_CLIENT_CERT = 'client_cert'
CONF_TLS_INSECURE = 'tls_insecure'
CONF_PROTOCOL = 'protocol' CONF_PROTOCOL = 'protocol'
CONF_STATE_TOPIC = 'state_topic' CONF_STATE_TOPIC = 'state_topic'
@ -78,6 +81,9 @@ def valid_publish_topic(value):
_VALID_QOS_SCHEMA = vol.All(vol.Coerce(int), vol.In([0, 1, 2])) _VALID_QOS_SCHEMA = vol.All(vol.Coerce(int), vol.In([0, 1, 2]))
_HBMQTT_CONFIG_SCHEMA = vol.Schema(dict) _HBMQTT_CONFIG_SCHEMA = vol.Schema(dict)
CLIENT_KEY_AUTH_MSG = 'client_key and client_cert must both be present in ' \
'the mqtt broker config'
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: vol.Schema({
vol.Optional(CONF_CLIENT_ID): cv.string, vol.Optional(CONF_CLIENT_ID): cv.string,
@ -89,6 +95,11 @@ CONFIG_SCHEMA = vol.Schema({
vol.Optional(CONF_USERNAME): cv.string, vol.Optional(CONF_USERNAME): cv.string,
vol.Optional(CONF_PASSWORD): cv.string, vol.Optional(CONF_PASSWORD): cv.string,
vol.Optional(CONF_CERTIFICATE): cv.isfile, vol.Optional(CONF_CERTIFICATE): cv.isfile,
vol.Inclusive(CONF_CLIENT_KEY, 'client_key_auth',
msg=CLIENT_KEY_AUTH_MSG): cv.isfile,
vol.Inclusive(CONF_CLIENT_CERT, 'client_key_auth',
msg=CLIENT_KEY_AUTH_MSG): cv.isfile,
vol.Optional(CONF_TLS_INSECURE): cv.boolean,
vol.Optional(CONF_PROTOCOL, default=DEFAULT_PROTOCOL): vol.Optional(CONF_PROTOCOL, default=DEFAULT_PROTOCOL):
vol.All(cv.string, vol.In([PROTOCOL_31, PROTOCOL_311])), vol.All(cv.string, vol.In([PROTOCOL_31, PROTOCOL_311])),
vol.Optional(CONF_EMBEDDED): _HBMQTT_CONFIG_SCHEMA, vol.Optional(CONF_EMBEDDED): _HBMQTT_CONFIG_SCHEMA,
@ -192,19 +203,26 @@ def setup(hass, config):
broker_config = _setup_server(hass, config) broker_config = _setup_server(hass, config)
broker_in_conf = True if CONF_BROKER in conf else False
# Only auto config if no server config was passed in # Only auto config if no server config was passed in
if broker_config and CONF_EMBEDDED not in conf: if broker_config and CONF_EMBEDDED not in conf:
broker, port, username, password, certificate, protocol = broker_config broker, port, username, password, certificate, protocol = broker_config
# Embedded broker doesn't have some ssl variables
client_key, client_cert, tls_insecure = None, None, None
elif not broker_config and CONF_BROKER not in conf: elif not broker_config and CONF_BROKER not in conf:
_LOGGER.error('Unable to start broker and auto-configure MQTT.') _LOGGER.error('Unable to start broker and auto-configure MQTT.')
return False return False
if CONF_BROKER in conf: if broker_in_conf:
broker = conf[CONF_BROKER] broker = conf[CONF_BROKER]
port = conf[CONF_PORT] port = conf[CONF_PORT]
username = conf.get(CONF_USERNAME) username = conf.get(CONF_USERNAME)
password = conf.get(CONF_PASSWORD) password = conf.get(CONF_PASSWORD)
certificate = conf.get(CONF_CERTIFICATE) certificate = conf.get(CONF_CERTIFICATE)
client_key = conf.get(CONF_CLIENT_KEY)
client_cert = conf.get(CONF_CLIENT_CERT)
tls_insecure = conf.get(CONF_TLS_INSECURE)
protocol = conf[CONF_PROTOCOL] protocol = conf[CONF_PROTOCOL]
# For cloudmqtt.com, secured connection, auto fill in certificate # For cloudmqtt.com, secured connection, auto fill in certificate
@ -215,8 +233,9 @@ def setup(hass, config):
global MQTT_CLIENT global MQTT_CLIENT
try: try:
MQTT_CLIENT = MQTT(hass, broker, port, client_id, keepalive, username, MQTT_CLIENT = MQTT(hass, broker, port, client_id, keepalive,
password, certificate, protocol) username, password, certificate, client_key,
client_cert, tls_insecure, protocol)
except socket.error: except socket.error:
_LOGGER.exception("Can't connect to the broker. " _LOGGER.exception("Can't connect to the broker. "
"Please check your settings and the broker " "Please check your settings and the broker "
@ -267,7 +286,8 @@ class MQTT(object):
"""Home Assistant MQTT client.""" """Home Assistant MQTT client."""
def __init__(self, hass, broker, port, client_id, keepalive, username, def __init__(self, hass, broker, port, client_id, keepalive, username,
password, certificate, protocol): password, certificate, client_key, client_cert,
tls_insecure, protocol):
"""Initialize Home Assistant MQTT client.""" """Initialize Home Assistant MQTT client."""
import paho.mqtt.client as mqtt import paho.mqtt.client as mqtt
@ -287,8 +307,13 @@ class MQTT(object):
if username is not None: if username is not None:
self._mqttc.username_pw_set(username, password) self._mqttc.username_pw_set(username, password)
if certificate is not None: if certificate is not None:
self._mqttc.tls_set(certificate) self._mqttc.tls_set(certificate, certfile=client_cert,
keyfile=client_key)
if tls_insecure is not None:
self._mqttc.tls_insecure_set(tls_insecure)
self._mqttc.on_subscribe = self._mqtt_on_subscribe self._mqttc.on_subscribe = self._mqtt_on_subscribe
self._mqttc.on_unsubscribe = self._mqtt_on_unsubscribe self._mqttc.on_unsubscribe = self._mqtt_on_unsubscribe