From db966c03263943dc718f01252ee756be836d129d Mon Sep 17 00:00:00 2001 From: Robin Siep Date: Fri, 11 Sep 2026 17:37:31 +0200 Subject: [PATCH] Fix reauth flow possibly pointing to different UniFi site (#180936) --- homeassistant/components/unifi/config_flow.py | 16 ++++---- homeassistant/components/unifi/strings.json | 3 +- tests/components/unifi/test_config_flow.py | 38 +++++++++++++++++++ 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/unifi/config_flow.py b/homeassistant/components/unifi/config_flow.py index 632d21e0a853..5aa33f6c0a77 100644 --- a/homeassistant/components/unifi/config_flow.py +++ b/homeassistant/components/unifi/config_flow.py @@ -31,7 +31,7 @@ from homeassistant.const import ( CONF_VERIFY_SSL, ) from homeassistant.core import HomeAssistant, callback -from homeassistant.data_entry_flow import SectionConfig, section +from homeassistant.data_entry_flow import AbortFlow, SectionConfig, section from homeassistant.helpers import config_validation as cv from homeassistant.helpers.device_registry import format_mac from homeassistant.helpers.typing import DiscoveryInfoType @@ -113,15 +113,15 @@ class UnifiFlowHandler(ConfigFlow, domain=DOMAIN): errors["base"] = "service_unavailable" else: - if ( - self.source == SOURCE_REAUTH - and ( + if self.source == SOURCE_REAUTH: + if ( (reauth_unique_id := self._get_reauth_entry().unique_id) is not None - ) - and reauth_unique_id in self.sites - ): - return await self.async_step_site({CONF_SITE_ID: reauth_unique_id}) + ) and reauth_unique_id in self.sites: + return await self.async_step_site( + {CONF_SITE_ID: reauth_unique_id} + ) + raise AbortFlow("unknown_site_id") return await self.async_step_site() diff --git a/homeassistant/components/unifi/strings.json b/homeassistant/components/unifi/strings.json index b3bf482edfc5..c44b2d9c5260 100644 --- a/homeassistant/components/unifi/strings.json +++ b/homeassistant/components/unifi/strings.json @@ -4,7 +4,8 @@ "already_configured": "UniFi Network site is already configured", "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", "configuration_updated": "Configuration updated", - "reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]" + "reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]", + "unknown_site_id": "Previously configured UniFi Network site can no longer be found" }, "error": { "faulty_credentials": "[%key:common::config_flow::error::invalid_auth%]", diff --git a/tests/components/unifi/test_config_flow.py b/tests/components/unifi/test_config_flow.py index 1e4632fa137d..3d82f891996a 100644 --- a/tests/components/unifi/test_config_flow.py +++ b/tests/components/unifi/test_config_flow.py @@ -1,5 +1,6 @@ """Test UniFi Network config flow.""" +from collections.abc import Callable import socket from typing import Any from unittest.mock import PropertyMock, patch @@ -386,6 +387,43 @@ async def test_reauth_flow_update_configuration_on_not_loaded_entry( assert config_entry.data[CONF_PASSWORD] == "new_pass" +@pytest.mark.parametrize( + "site_payload", + [ + [ + {"name": "site2", "role": "admin", "desc": "site2 name", "_id": "2"}, + ] + ], +) +async def test_abort_reauth_flow_on_site_id_mismatch( + hass: HomeAssistant, + config_entry: MockConfigEntry, + mock_requests: Callable[[str, str], None], +) -> None: + """Verify reauth flow aborts when original site can no longer be found.""" + mock_requests(config_entry.data[CONF_HOST], config_entry.data[CONF_SITE_ID]) + + result = await config_entry.start_reauth_flow(hass) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "user" + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={ + CONF_HOST: "1.2.3.4", + CONF_USERNAME: "new_name", + CONF_PASSWORD: "new_pass", + CONF_PORT: 1234, + CONF_VERIFY_SSL: True, + }, + ) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "unknown_site_id" + assert config_entry.data[CONF_SITE_ID] == "site_id" + + @pytest.mark.parametrize("client_payload", [CLIENTS]) @pytest.mark.parametrize("device_payload", [DEVICES]) @pytest.mark.parametrize("wlan_payload", [WLANS])