Be able to select mqtt:tls_version for Python < 3.6 (#6442)
* Be able to select tls_version * This test should always assert this value, not only in 3.6 * Disable linting on future property (py36) * Only allow TLS 1.0, 1.1 and 1.2 * Fix line length issue * Fix check config tests * Allow auto as a TLS version
This commit is contained in:
parent
0aa8933df6
commit
5183cb5903
3 changed files with 75 additions and 3 deletions
|
@ -9,6 +9,7 @@ import logging
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
import time
|
import time
|
||||||
|
import ssl
|
||||||
import requests.certs
|
import requests.certs
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
@ -48,6 +49,7 @@ CONF_CERTIFICATE = 'certificate'
|
||||||
CONF_CLIENT_KEY = 'client_key'
|
CONF_CLIENT_KEY = 'client_key'
|
||||||
CONF_CLIENT_CERT = 'client_cert'
|
CONF_CLIENT_CERT = 'client_cert'
|
||||||
CONF_TLS_INSECURE = 'tls_insecure'
|
CONF_TLS_INSECURE = 'tls_insecure'
|
||||||
|
CONF_TLS_VERSION = 'tls_version'
|
||||||
|
|
||||||
CONF_BIRTH_MESSAGE = 'birth_message'
|
CONF_BIRTH_MESSAGE = 'birth_message'
|
||||||
CONF_WILL_MESSAGE = 'will_message'
|
CONF_WILL_MESSAGE = 'will_message'
|
||||||
|
@ -67,6 +69,7 @@ DEFAULT_RETAIN = False
|
||||||
DEFAULT_PROTOCOL = PROTOCOL_311
|
DEFAULT_PROTOCOL = PROTOCOL_311
|
||||||
DEFAULT_DISCOVERY = False
|
DEFAULT_DISCOVERY = False
|
||||||
DEFAULT_DISCOVERY_PREFIX = 'homeassistant'
|
DEFAULT_DISCOVERY_PREFIX = 'homeassistant'
|
||||||
|
DEFAULT_TLS_PROTOCOL = 'auto'
|
||||||
|
|
||||||
ATTR_TOPIC = 'topic'
|
ATTR_TOPIC = 'topic'
|
||||||
ATTR_PAYLOAD = 'payload'
|
ATTR_PAYLOAD = 'payload'
|
||||||
|
@ -122,6 +125,9 @@ CONFIG_SCHEMA = vol.Schema({
|
||||||
vol.Inclusive(CONF_CLIENT_CERT, 'client_key_auth',
|
vol.Inclusive(CONF_CLIENT_CERT, 'client_key_auth',
|
||||||
msg=CLIENT_KEY_AUTH_MSG): cv.isfile,
|
msg=CLIENT_KEY_AUTH_MSG): cv.isfile,
|
||||||
vol.Optional(CONF_TLS_INSECURE): cv.boolean,
|
vol.Optional(CONF_TLS_INSECURE): cv.boolean,
|
||||||
|
vol.Optional(CONF_TLS_VERSION,
|
||||||
|
default=DEFAULT_TLS_PROTOCOL): vol.Any('auto', '1.0',
|
||||||
|
'1.1', '1.2'),
|
||||||
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,
|
||||||
|
@ -318,11 +324,27 @@ def async_setup(hass, config):
|
||||||
will_message = conf.get(CONF_WILL_MESSAGE)
|
will_message = conf.get(CONF_WILL_MESSAGE)
|
||||||
birth_message = conf.get(CONF_BIRTH_MESSAGE)
|
birth_message = conf.get(CONF_BIRTH_MESSAGE)
|
||||||
|
|
||||||
|
# Be able to override versions other than TLSv1.0 under Python3.6
|
||||||
|
conf_tls_version = conf.get(CONF_TLS_VERSION)
|
||||||
|
if conf_tls_version == '1.2':
|
||||||
|
tls_version = ssl.PROTOCOL_TLSv1_2
|
||||||
|
elif conf_tls_version == '1.1':
|
||||||
|
tls_version = ssl.PROTOCOL_TLSv1_1
|
||||||
|
elif conf_tls_version == '1.0':
|
||||||
|
tls_version = ssl.PROTOCOL_TLSv1
|
||||||
|
else:
|
||||||
|
import sys
|
||||||
|
# Python3.6 supports automatic negotiation of highest TLS version
|
||||||
|
if sys.hexversion >= 0x03060000:
|
||||||
|
tls_version = ssl.PROTOCOL_TLS # pylint: disable=no-member
|
||||||
|
else:
|
||||||
|
tls_version = ssl.PROTOCOL_TLSv1
|
||||||
|
|
||||||
try:
|
try:
|
||||||
hass.data[DATA_MQTT] = MQTT(
|
hass.data[DATA_MQTT] = MQTT(
|
||||||
hass, broker, port, client_id, keepalive, username, password,
|
hass, broker, port, client_id, keepalive, username, password,
|
||||||
certificate, client_key, client_cert, tls_insecure, protocol,
|
certificate, client_key, client_cert, tls_insecure, protocol,
|
||||||
will_message, birth_message)
|
will_message, birth_message, tls_version)
|
||||||
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 itself")
|
"Please check your settings and the broker itself")
|
||||||
|
@ -380,7 +402,8 @@ class MQTT(object):
|
||||||
|
|
||||||
def __init__(self, hass, broker, port, client_id, keepalive, username,
|
def __init__(self, hass, broker, port, client_id, keepalive, username,
|
||||||
password, certificate, client_key, client_cert,
|
password, certificate, client_key, client_cert,
|
||||||
tls_insecure, protocol, will_message, birth_message):
|
tls_insecure, protocol, will_message, birth_message,
|
||||||
|
tls_version):
|
||||||
"""Initialize Home Assistant MQTT client."""
|
"""Initialize Home Assistant MQTT client."""
|
||||||
import paho.mqtt.client as mqtt
|
import paho.mqtt.client as mqtt
|
||||||
|
|
||||||
|
@ -409,7 +432,8 @@ class MQTT(object):
|
||||||
|
|
||||||
if certificate is not None:
|
if certificate is not None:
|
||||||
self._mqttc.tls_set(
|
self._mqttc.tls_set(
|
||||||
certificate, certfile=client_cert, keyfile=client_key)
|
certificate, certfile=client_cert,
|
||||||
|
keyfile=client_key, tls_version=tls_version)
|
||||||
|
|
||||||
if tls_insecure is not None:
|
if tls_insecure is not None:
|
||||||
self._mqttc.tls_insecure_set(tls_insecure)
|
self._mqttc.tls_insecure_set(tls_insecure)
|
||||||
|
|
|
@ -4,6 +4,7 @@ from collections import namedtuple, OrderedDict
|
||||||
import unittest
|
import unittest
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
import socket
|
import socket
|
||||||
|
import ssl
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
|
@ -409,6 +410,52 @@ def test_setup_uses_certificate_not_on_mqtts_port(hass):
|
||||||
assert mock_MQTT.mock_calls[0][1][7] != mqttsCertificateBundle
|
assert mock_MQTT.mock_calls[0][1][7] != mqttsCertificateBundle
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_setup_without_tls_config_uses_tlsv1_under_python36(hass):
|
||||||
|
"""Test setup defaults to TLSv1 under python3.6."""
|
||||||
|
test_broker_cfg = {mqtt.DOMAIN: {mqtt.CONF_BROKER: 'test-broker'}}
|
||||||
|
|
||||||
|
with mock.patch('homeassistant.components.mqtt.MQTT') as mock_MQTT:
|
||||||
|
yield from async_setup_component(hass, mqtt.DOMAIN, test_broker_cfg)
|
||||||
|
|
||||||
|
assert mock_MQTT.called
|
||||||
|
|
||||||
|
import sys
|
||||||
|
if sys.hexversion >= 0x03060000:
|
||||||
|
expectedTlsVersion = ssl.PROTOCOL_TLS # pylint: disable=no-member
|
||||||
|
else:
|
||||||
|
expectedTlsVersion = ssl.PROTOCOL_TLSv1
|
||||||
|
|
||||||
|
assert mock_MQTT.mock_calls[0][1][14] == expectedTlsVersion
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_setup_with_tls_config_uses_tls_version1_2(hass):
|
||||||
|
"""Test setup uses specified TLS version."""
|
||||||
|
test_broker_cfg = {mqtt.DOMAIN: {mqtt.CONF_BROKER: 'test-broker',
|
||||||
|
'tls_version': '1.2'}}
|
||||||
|
|
||||||
|
with mock.patch('homeassistant.components.mqtt.MQTT') as mock_MQTT:
|
||||||
|
yield from async_setup_component(hass, mqtt.DOMAIN, test_broker_cfg)
|
||||||
|
|
||||||
|
assert mock_MQTT.called
|
||||||
|
|
||||||
|
assert mock_MQTT.mock_calls[0][1][14] == ssl.PROTOCOL_TLSv1_2
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_setup_with_tls_config_of_v1_under_python36_only_uses_v1(hass):
|
||||||
|
"""Test setup uses TLSv1.0 if explicitly chosen."""
|
||||||
|
test_broker_cfg = {mqtt.DOMAIN: {mqtt.CONF_BROKER: 'test-broker',
|
||||||
|
'tls_version': '1.0'}}
|
||||||
|
|
||||||
|
with mock.patch('homeassistant.components.mqtt.MQTT') as mock_MQTT:
|
||||||
|
yield from async_setup_component(hass, mqtt.DOMAIN, test_broker_cfg)
|
||||||
|
|
||||||
|
assert mock_MQTT.called
|
||||||
|
assert mock_MQTT.mock_calls[0][1][14] == ssl.PROTOCOL_TLSv1
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def test_birth_message(hass):
|
def test_birth_message(hass):
|
||||||
"""Test sending birth message."""
|
"""Test sending birth message."""
|
||||||
|
|
|
@ -108,6 +108,7 @@ class TestCheckConfig(unittest.TestCase):
|
||||||
'protocol': '3.1.1',
|
'protocol': '3.1.1',
|
||||||
'discovery': False,
|
'discovery': False,
|
||||||
'discovery_prefix': 'homeassistant',
|
'discovery_prefix': 'homeassistant',
|
||||||
|
'tls_version': 'auto',
|
||||||
},
|
},
|
||||||
'light': []},
|
'light': []},
|
||||||
res['components']
|
res['components']
|
||||||
|
|
Loading…
Add table
Reference in a new issue