Check cloud trusted proxies (#24395)

pull/24403/head
Paulus Schoutsen 2019-06-07 23:08:55 -07:00 committed by GitHub
parent 7887d6d6e4
commit f77514c6f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 83 additions and 5 deletions

View File

@ -38,3 +38,7 @@ DISPATCHER_REMOTE_UPDATE = 'cloud_remote_update'
class InvalidTrustedNetworks(Exception):
"""Raised when invalid trusted networks config."""
class InvalidTrustedProxies(Exception):
"""Raised when invalid trusted proxies config."""

View File

@ -18,7 +18,8 @@ from homeassistant.components.google_assistant import helpers as google_helpers
from .const import (
DOMAIN, REQUEST_TIMEOUT, PREF_ENABLE_ALEXA, PREF_ENABLE_GOOGLE,
PREF_GOOGLE_SECURE_DEVICES_PIN, InvalidTrustedNetworks)
PREF_GOOGLE_SECURE_DEVICES_PIN, InvalidTrustedNetworks,
InvalidTrustedProxies)
_LOGGER = logging.getLogger(__name__)
@ -52,7 +53,10 @@ SCHEMA_WS_HOOK_DELETE = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({
_CLOUD_ERRORS = {
InvalidTrustedNetworks:
(500, 'Remote UI not compatible with 127.0.0.1/::1'
' as a trusted network.')
' as a trusted network.'),
InvalidTrustedProxies:
(500, 'Remote UI not compatible with 127.0.0.1/::1'
' as trusted proxies.'),
}

View File

@ -6,7 +6,7 @@ from .const import (
PREF_GOOGLE_SECURE_DEVICES_PIN, PREF_CLOUDHOOKS, PREF_CLOUD_USER,
PREF_GOOGLE_ENTITY_CONFIGS, PREF_OVERRIDE_NAME, PREF_DISABLE_2FA,
PREF_ALIASES, PREF_SHOULD_EXPOSE,
InvalidTrustedNetworks)
InvalidTrustedNetworks, InvalidTrustedProxies)
STORAGE_KEY = DOMAIN
STORAGE_VERSION = 1
@ -59,6 +59,9 @@ class CloudPreferences:
if remote_enabled is True and self._has_local_trusted_network:
raise InvalidTrustedNetworks
if remote_enabled is True and self._has_local_trusted_proxies:
raise InvalidTrustedProxies
await self._store.async_save(self._prefs)
async def async_update_google_entity_config(
@ -112,7 +115,7 @@ class CloudPreferences:
if not enabled:
return False
if self._has_local_trusted_network:
if self._has_local_trusted_network or self._has_local_trusted_proxies:
return False
return True
@ -162,3 +165,18 @@ class CloudPreferences:
return True
return False
@property
def _has_local_trusted_proxies(self) -> bool:
"""Return if we allow localhost to be a proxy and use its data."""
if not hasattr(self._hass, 'http'):
return False
local4 = ip_address('127.0.0.1')
local6 = ip_address('::1')
if any(local4 in nwk or local6 in nwk
for nwk in self._hass.http.trusted_proxies):
return True
return False

View File

@ -228,6 +228,7 @@ class HomeAssistantHTTP:
self.ssl_key = ssl_key
self.server_host = server_host
self.server_port = server_port
self.trusted_proxies = trusted_proxies
self.is_ban_enabled = is_ban_enabled
self.ssl_profile = ssl_profile
self._handler = None

View File

@ -1,6 +1,7 @@
"""Tests for the HTTP API for the cloud component."""
import asyncio
from unittest.mock import patch, MagicMock
from ipaddress import ip_network
import pytest
from jose import jwt
@ -672,7 +673,7 @@ async def test_enabling_remote_trusted_networks_local6(
async def test_enabling_remote_trusted_networks_other(
hass, hass_ws_client, setup_api, mock_cloud_login):
"""Test we cannot enable remote UI when trusted networks active."""
"""Test we can enable remote UI when trusted networks active."""
hass.auth._providers[('trusted_networks', None)] = \
tn_auth.TrustedNetworksAuthProvider(
hass, None, tn_auth.CONFIG_SCHEMA({
@ -749,3 +750,53 @@ async def test_update_google_entity(
'aliases': ['lefty', 'righty'],
'disable_2fa': False,
}
async def test_enabling_remote_trusted_proxies_local4(
hass, hass_ws_client, setup_api, mock_cloud_login):
"""Test we cannot enable remote UI when trusted networks active."""
hass.http.trusted_proxies.append(ip_network('127.0.0.1'))
client = await hass_ws_client(hass)
with patch(
'hass_nabucasa.remote.RemoteUI.connect',
side_effect=AssertionError
) as mock_connect:
await client.send_json({
'id': 5,
'type': 'cloud/remote/connect',
})
response = await client.receive_json()
assert not response['success']
assert response['error']['code'] == 500
assert response['error']['message'] == \
'Remote UI not compatible with 127.0.0.1/::1 as trusted proxies.'
assert len(mock_connect.mock_calls) == 0
async def test_enabling_remote_trusted_proxies_local6(
hass, hass_ws_client, setup_api, mock_cloud_login):
"""Test we cannot enable remote UI when trusted networks active."""
hass.http.trusted_proxies.append(ip_network('::1'))
client = await hass_ws_client(hass)
with patch(
'hass_nabucasa.remote.RemoteUI.connect',
side_effect=AssertionError
) as mock_connect:
await client.send_json({
'id': 5,
'type': 'cloud/remote/connect',
})
response = await client.receive_json()
assert not response['success']
assert response['error']['code'] == 500
assert response['error']['message'] == \
'Remote UI not compatible with 127.0.0.1/::1 as trusted proxies.'
assert len(mock_connect.mock_calls) == 0