Accept known hosts for get_url for OAuth (#39936)

This commit is contained in:
Franck Nijhof 2020-09-11 13:00:00 +02:00 committed by GitHub
parent 5117a16841
commit 101b5b3b35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 85 additions and 0 deletions

View File

@ -75,6 +75,38 @@ def get_url(
except NoURLAvailableError:
pass
# For current request, we accept loopback interfaces (e.g., 127.0.0.1),
# the Supervisor hostname and localhost transparently
request_host = _get_request_host()
if (
require_current_request
and request_host is not None
and hass.config.api is not None
):
scheme = "https" if hass.config.api.use_ssl else "http"
current_url = yarl.URL.build(
scheme=scheme, host=request_host, port=hass.config.api.port
)
known_hostname = None
if hass.components.hassio.is_hassio():
host_info = hass.components.hassio.get_host_info()
known_hostname = f"{host_info['hostname']}.local"
if (
(
(
allow_ip
and is_ip_address(request_host)
and is_loopback(ip_address(request_host))
)
or request_host in ["localhost", known_hostname]
)
and (not require_ssl or current_url.scheme == "https")
and (not require_standard_port or current_url.is_default_port())
):
return normalize_url(str(current_url))
# We have to be honest now, we have no viable option available
raise NoURLAvailableError

View File

@ -15,6 +15,7 @@ from homeassistant.helpers.network import (
)
from tests.async_mock import Mock, patch
from tests.common import mock_component
async def test_get_url_internal(hass: HomeAssistant):
@ -799,3 +800,55 @@ async def test_get_external_url_with_base_url_fallback(hass: HomeAssistant):
assert _get_external_url(hass, allow_ip=False) == "https://example.com"
assert _get_external_url(hass, require_standard_port=True) == "https://example.com"
assert _get_external_url(hass, require_ssl=True) == "https://example.com"
async def test_get_current_request_url_with_known_host(
hass: HomeAssistant, current_request
):
"""Test getting current request URL with known hosts addresses."""
hass.config.api = Mock(
use_ssl=False, port=8123, local_ip="127.0.0.1", deprecated_base_url=None
)
assert hass.config.internal_url is None
with pytest.raises(NoURLAvailableError):
get_url(hass, require_current_request=True)
# Ensure we accept localhost
with patch(
"homeassistant.helpers.network._get_request_host", return_value="localhost"
):
assert get_url(hass, require_current_request=True) == "http://localhost:8123"
with pytest.raises(NoURLAvailableError):
get_url(hass, require_current_request=True, require_ssl=True)
with pytest.raises(NoURLAvailableError):
get_url(hass, require_current_request=True, require_standard_port=True)
# Ensure we accept local loopback ip (e.g., 127.0.0.1)
with patch(
"homeassistant.helpers.network._get_request_host", return_value="127.0.0.8"
):
assert get_url(hass, require_current_request=True) == "http://127.0.0.8:8123"
with pytest.raises(NoURLAvailableError):
get_url(hass, require_current_request=True, allow_ip=False)
# Ensure hostname from Supervisor is accepted transparently
mock_component(hass, "hassio")
hass.components.hassio.is_hassio = Mock(return_value=True)
hass.components.hassio.get_host_info = Mock(
return_value={"hostname": "homeassistant"}
)
with patch(
"homeassistant.helpers.network._get_request_host",
return_value="homeassistant.local",
):
assert (
get_url(hass, require_current_request=True)
== "http://homeassistant.local:8123"
)
with patch(
"homeassistant.helpers.network._get_request_host", return_value="unknown.local"
), pytest.raises(NoURLAvailableError):
get_url(hass, require_current_request=True)