1
mirror of https://github.com/home-assistant/core synced 2024-10-04 07:58:43 +02:00

Add ssl_cipher_list option to rest (#91078)

This commit is contained in:
Michael 2023-04-15 23:22:41 +02:00 committed by GitHub
parent 59dc0ea2e0
commit 323d16cc21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 62 additions and 2 deletions

View File

@ -43,7 +43,9 @@ from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from .const import (
CONF_ENCODING,
CONF_SSL_CIPHER_LIST,
COORDINATOR,
DEFAULT_SSL_CIPHER_LIST,
DOMAIN,
PLATFORM_IDX,
REST,
@ -185,6 +187,7 @@ def create_rest_data_from_config(hass: HomeAssistant, config: ConfigType) -> Res
method: str = config[CONF_METHOD]
payload: str | None = config.get(CONF_PAYLOAD)
verify_ssl: bool = config[CONF_VERIFY_SSL]
ssl_cipher_list: str = config.get(CONF_SSL_CIPHER_LIST, DEFAULT_SSL_CIPHER_LIST)
username: str | None = config.get(CONF_USERNAME)
password: str | None = config.get(CONF_PASSWORD)
headers: dict[str, str] | None = config.get(CONF_HEADERS)
@ -218,5 +221,6 @@ def create_rest_data_from_config(hass: HomeAssistant, config: ConfigType) -> Res
params,
payload,
verify_ssl,
ssl_cipher_list,
timeout,
)

View File

@ -1,12 +1,16 @@
"""The rest component constants."""
from homeassistant.util.ssl import SSLCipherList
DOMAIN = "rest"
DEFAULT_METHOD = "GET"
DEFAULT_VERIFY_SSL = True
DEFAULT_SSL_CIPHER_LIST = SSLCipherList.PYTHON_DEFAULT
DEFAULT_FORCE_UPDATE = False
DEFAULT_ENCODING = "UTF-8"
CONF_ENCODING = "encoding"
CONF_SSL_CIPHER_LIST = "ssl_cipher_list"
DEFAULT_BINARY_SENSOR_NAME = "REST Binary Sensor"
DEFAULT_SENSOR_NAME = "REST Sensor"

View File

@ -9,6 +9,7 @@ import httpx
from homeassistant.core import HomeAssistant
from homeassistant.helpers import template
from homeassistant.helpers.httpx_client import create_async_httpx_client
from homeassistant.util.ssl import SSLCipherList
DEFAULT_TIMEOUT = 10
@ -29,6 +30,7 @@ class RestData:
params: dict[str, str] | None,
data: str | None,
verify_ssl: bool,
ssl_cipher_list: str,
timeout: int = DEFAULT_TIMEOUT,
) -> None:
"""Initialize the data object."""
@ -42,6 +44,7 @@ class RestData:
self._request_data = data
self._timeout = timeout
self._verify_ssl = verify_ssl
self._ssl_cipher_list = SSLCipherList(ssl_cipher_list)
self._async_client: httpx.AsyncClient | None = None
self.data: str | None = None
self.last_exception: Exception | None = None
@ -55,7 +58,10 @@ class RestData:
"""Get the latest data from REST service with provided method."""
if not self._async_client:
self._async_client = create_async_httpx_client(
self._hass, verify_ssl=self._verify_ssl, default_encoding=self._encoding
self._hass,
verify_ssl=self._verify_ssl,
default_encoding=self._encoding,
ssl_cipher_list=self._ssl_cipher_list,
)
rendered_headers = template.render_complex(self._headers, parse_result=False)

View File

@ -31,14 +31,17 @@ from homeassistant.helpers.template_entity import (
TEMPLATE_ENTITY_BASE_SCHEMA,
TEMPLATE_SENSOR_BASE_SCHEMA,
)
from homeassistant.util.ssl import SSLCipherList
from .const import (
CONF_ENCODING,
CONF_JSON_ATTRS,
CONF_JSON_ATTRS_PATH,
CONF_SSL_CIPHER_LIST,
DEFAULT_ENCODING,
DEFAULT_FORCE_UPDATE,
DEFAULT_METHOD,
DEFAULT_SSL_CIPHER_LIST,
DEFAULT_VERIFY_SSL,
DOMAIN,
METHODS,
@ -58,6 +61,10 @@ RESOURCE_SCHEMA = {
vol.Optional(CONF_PASSWORD): cv.string,
vol.Optional(CONF_PAYLOAD): cv.string,
vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean,
vol.Optional(
CONF_SSL_CIPHER_LIST,
default=DEFAULT_SSL_CIPHER_LIST,
): vol.In([e.value for e in SSLCipherList]),
vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int,
vol.Optional(CONF_ENCODING, default=DEFAULT_ENCODING): cv.string,
}

View File

@ -2,7 +2,7 @@
import asyncio
from http import HTTPStatus
import ssl
from unittest.mock import MagicMock, patch
from unittest.mock import AsyncMock, MagicMock, patch
import httpx
import pytest
@ -30,6 +30,7 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from homeassistant.setup import async_setup_component
from homeassistant.util.ssl import SSLCipherList
from tests.common import get_fixture_path
@ -157,6 +158,44 @@ async def test_setup_encoding(hass: HomeAssistant) -> None:
assert hass.states.get("sensor.mysensor").state == "tack själv"
@respx.mock
@pytest.mark.parametrize(
("ssl_cipher_list", "ssl_cipher_list_expected"),
(
("python_default", SSLCipherList.PYTHON_DEFAULT),
("intermediate", SSLCipherList.INTERMEDIATE),
("modern", SSLCipherList.MODERN),
),
)
async def test_setup_ssl_ciphers(
hass: HomeAssistant, ssl_cipher_list: str, ssl_cipher_list_expected: SSLCipherList
) -> None:
"""Test setup with minimum configuration."""
with patch(
"homeassistant.components.rest.data.create_async_httpx_client",
return_value=MagicMock(request=AsyncMock(return_value=respx.MockResponse())),
) as httpx:
assert await async_setup_component(
hass,
SENSOR_DOMAIN,
{
SENSOR_DOMAIN: {
"platform": DOMAIN,
"resource": "http://localhost",
"method": "GET",
"ssl_cipher_list": ssl_cipher_list,
}
},
)
await hass.async_block_till_done()
httpx.assert_called_once_with(
hass,
verify_ssl=True,
default_encoding="UTF-8",
ssl_cipher_list=ssl_cipher_list_expected,
)
@respx.mock
async def test_manual_update(hass: HomeAssistant) -> None:
"""Test setup with minimum configuration."""