Fix onvif reauth when device returns a http 401/403 error (#92690)

pull/92700/head^2
J. Nick Koston 2023-05-06 17:12:24 -05:00 committed by GitHub
parent d66305ddd3
commit d05724a42a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 34 additions and 3 deletions

View File

@ -1,5 +1,6 @@
"""The ONVIF integration."""
import asyncio
from http import HTTPStatus
import logging
from httpx import RequestError
@ -56,7 +57,20 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
except ONVIFError as err:
await device.device.close()
raise ConfigEntryNotReady(
f"Could not setup camera {device.device.host}:{device.device.port}: {err}"
f"Could not setup camera {device.device.host}:{device.device.port}: {stringify_onvif_error(err)}"
) from err
except TransportError as err:
await device.device.close()
stringified_onvif_error = stringify_onvif_error(err)
if err.status_code in (
HTTPStatus.UNAUTHORIZED.value,
HTTPStatus.FORBIDDEN.value,
):
raise ConfigEntryAuthFailed(
f"Auth Failed: {stringified_onvif_error}"
) from err
raise ConfigEntryNotReady(
f"Could not setup camera {device.device.host}:{device.device.port}: {stringified_onvif_error}"
) from err
except asyncio.CancelledError as err:
# After https://github.com/agronholm/anyio/issues/374 is resolved

View File

@ -142,10 +142,14 @@ class OnvifFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
hass.async_create_task(hass.config_entries.async_reload(entry_id))
return self.async_abort(reason="reauth_successful")
username = (user_input or {}).get(CONF_USERNAME) or entry.data[CONF_USERNAME]
return self.async_show_form(
step_id="reauth_confirm",
data_schema=vol.Schema(
{vol.Required(CONF_USERNAME): str, vol.Required(CONF_PASSWORD): str}
{
vol.Required(CONF_USERNAME, default=username): str,
vol.Required(CONF_PASSWORD): str,
}
),
errors=errors,
description_placeholders=description_placeholders,

View File

@ -47,6 +47,7 @@
},
"reauth_confirm": {
"title": "Reauthenticate the ONVIF device",
"description": "Some devices will reject authentication if the time is out of sync by more than 5 seconds. If authentication is unsuccessful, verify the time on the device is correct and try again.",
"data": {
"username": "[%key:common::config_flow::data::username%]",
"password": "[%key:common::config_flow::data::password%]"

View File

@ -5,7 +5,7 @@ from homeassistant import config_entries, data_entry_flow
from homeassistant.components import dhcp
from homeassistant.components.onvif import DOMAIN, config_flow
from homeassistant.config_entries import SOURCE_DHCP
from homeassistant.const import CONF_HOST
from homeassistant.const import CONF_HOST, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from homeassistant.helpers import device_registry as dr
@ -710,6 +710,14 @@ async def test_discovered_by_dhcp_does_not_update_if_no_matching_entry(
assert result["reason"] == "no_devices_found"
def _get_schema_default(schema, key_name):
"""Iterate schema to find a key."""
for schema_key in schema:
if schema_key == key_name:
return schema_key.default()
raise KeyError(f"{key_name} not found in schema")
async def test_form_reauth(hass: HomeAssistant) -> None:
"""Test reauthenticate."""
entry, _, _ = await setup_onvif_integration(hass)
@ -721,6 +729,10 @@ async def test_form_reauth(hass: HomeAssistant) -> None:
)
assert result["type"] == FlowResultType.FORM
assert result["step_id"] == "reauth_confirm"
assert (
_get_schema_default(result["data_schema"].schema, CONF_USERNAME)
== entry.data[CONF_USERNAME]
)
with patch(
"homeassistant.components.onvif.config_flow.get_device"