mirror of
https://github.com/home-assistant/core.git
synced 2025-08-07 14:45:09 +02:00
Fix bsblan reauthentication (#149926)
This commit is contained in:
committed by
GitHub
parent
b76f47cd9f
commit
88c9d5dbe3
@@ -211,16 +211,16 @@ class BSBLANFlowHandler(ConfigFlow, domain=DOMAIN):
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Use existing host and port, update auth credentials
|
# Combine existing data with the user's new input for validation.
|
||||||
self.host = existing_entry.data[CONF_HOST]
|
# This correctly handles adding, changing, and clearing credentials.
|
||||||
self.port = existing_entry.data[CONF_PORT]
|
config_data = existing_entry.data.copy()
|
||||||
self.passkey = user_input.get(CONF_PASSKEY) or existing_entry.data.get(
|
config_data.update(user_input)
|
||||||
CONF_PASSKEY
|
|
||||||
)
|
self.host = config_data[CONF_HOST]
|
||||||
self.username = user_input.get(CONF_USERNAME) or existing_entry.data.get(
|
self.port = config_data[CONF_PORT]
|
||||||
CONF_USERNAME
|
self.passkey = config_data.get(CONF_PASSKEY)
|
||||||
)
|
self.username = config_data.get(CONF_USERNAME)
|
||||||
self.password = user_input.get(CONF_PASSWORD)
|
self.password = config_data.get(CONF_PASSWORD)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await self._get_bsblan_info(raise_on_progress=False, is_reauth=True)
|
await self._get_bsblan_info(raise_on_progress=False, is_reauth=True)
|
||||||
@@ -267,17 +267,9 @@ class BSBLANFlowHandler(ConfigFlow, domain=DOMAIN):
|
|||||||
errors={"base": "cannot_connect"},
|
errors={"base": "cannot_connect"},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Update the config entry with new auth data
|
# Update only the fields that were provided by the user
|
||||||
data_updates = {}
|
|
||||||
if self.passkey is not None:
|
|
||||||
data_updates[CONF_PASSKEY] = self.passkey
|
|
||||||
if self.username is not None:
|
|
||||||
data_updates[CONF_USERNAME] = self.username
|
|
||||||
if self.password is not None:
|
|
||||||
data_updates[CONF_PASSWORD] = self.password
|
|
||||||
|
|
||||||
return self.async_update_reload_and_abort(
|
return self.async_update_reload_and_abort(
|
||||||
existing_entry, data_updates=data_updates, reason="reauth_successful"
|
existing_entry, data_updates=user_input, reason="reauth_successful"
|
||||||
)
|
)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
|
@@ -866,6 +866,164 @@ async def test_reauth_flow_partial_credentials_update(
|
|||||||
assert mock_config_entry.data[CONF_PORT] == 80
|
assert mock_config_entry.data[CONF_PORT] == 80
|
||||||
|
|
||||||
|
|
||||||
|
async def test_reauth_flow_preserves_non_credential_fields(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_bsblan: MagicMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test reauth flow preserves non-credential fields using data_updates."""
|
||||||
|
# Create a config entry with additional custom fields that should be preserved
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
data={
|
||||||
|
CONF_HOST: "127.0.0.1",
|
||||||
|
CONF_PORT: 80,
|
||||||
|
CONF_PASSKEY: "old_key",
|
||||||
|
CONF_USERNAME: "old_user",
|
||||||
|
CONF_PASSWORD: "old_pass",
|
||||||
|
# Add some custom fields that should be preserved
|
||||||
|
"custom_field": "should_be_preserved",
|
||||||
|
"another_field": 42,
|
||||||
|
},
|
||||||
|
unique_id="00:80:41:19:69:90",
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
# Start reauth flow
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={
|
||||||
|
"source": SOURCE_REAUTH,
|
||||||
|
"entry_id": entry.entry_id,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
# Submit with only new credentials
|
||||||
|
result = await _configure_flow(
|
||||||
|
hass,
|
||||||
|
result["flow_id"],
|
||||||
|
{
|
||||||
|
CONF_PASSKEY: "new_key",
|
||||||
|
CONF_USERNAME: "new_user",
|
||||||
|
CONF_PASSWORD: "new_pass",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
_assert_abort_result(result, "reauth_successful")
|
||||||
|
|
||||||
|
# Verify that only the provided fields were updated, others preserved
|
||||||
|
assert entry.data[CONF_PASSKEY] == "new_key" # Updated
|
||||||
|
assert entry.data[CONF_USERNAME] == "new_user" # Updated
|
||||||
|
assert entry.data[CONF_PASSWORD] == "new_pass" # Updated
|
||||||
|
|
||||||
|
# These fields should remain unchanged (preserved by data_updates)
|
||||||
|
assert entry.data[CONF_HOST] == "127.0.0.1"
|
||||||
|
assert entry.data[CONF_PORT] == 80
|
||||||
|
assert entry.data["custom_field"] == "should_be_preserved"
|
||||||
|
assert entry.data["another_field"] == 42
|
||||||
|
|
||||||
|
|
||||||
|
async def test_reauth_flow_clears_credentials_with_empty_strings(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_bsblan: MagicMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test reauth flow can clear credentials by providing empty strings."""
|
||||||
|
# Create a config entry with existing credentials
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
data={
|
||||||
|
CONF_HOST: "127.0.0.1",
|
||||||
|
CONF_PORT: 80,
|
||||||
|
CONF_PASSKEY: "existing_key",
|
||||||
|
CONF_USERNAME: "existing_user",
|
||||||
|
CONF_PASSWORD: "existing_pass",
|
||||||
|
},
|
||||||
|
unique_id="00:80:41:19:69:90",
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
# Start reauth flow
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={
|
||||||
|
"source": SOURCE_REAUTH,
|
||||||
|
"entry_id": entry.entry_id,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
# Submit with empty strings to clear credentials
|
||||||
|
result = await _configure_flow(
|
||||||
|
hass,
|
||||||
|
result["flow_id"],
|
||||||
|
{
|
||||||
|
CONF_PASSKEY: "", # Clear passkey
|
||||||
|
CONF_USERNAME: "", # Clear username
|
||||||
|
CONF_PASSWORD: "", # Clear password
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
_assert_abort_result(result, "reauth_successful")
|
||||||
|
|
||||||
|
# Verify that credentials were cleared (set to empty strings)
|
||||||
|
assert entry.data[CONF_PASSKEY] == ""
|
||||||
|
assert entry.data[CONF_USERNAME] == ""
|
||||||
|
assert entry.data[CONF_PASSWORD] == ""
|
||||||
|
|
||||||
|
# Host and port should remain unchanged
|
||||||
|
assert entry.data[CONF_HOST] == "127.0.0.1"
|
||||||
|
assert entry.data[CONF_PORT] == 80
|
||||||
|
|
||||||
|
|
||||||
|
async def test_reauth_flow_partial_clear_credentials(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_bsblan: MagicMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test reauth flow can partially clear some credentials while updating others."""
|
||||||
|
# Create a config entry with existing credentials
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
data={
|
||||||
|
CONF_HOST: "127.0.0.1",
|
||||||
|
CONF_PORT: 80,
|
||||||
|
CONF_PASSKEY: "existing_key",
|
||||||
|
CONF_USERNAME: "existing_user",
|
||||||
|
CONF_PASSWORD: "existing_pass",
|
||||||
|
},
|
||||||
|
unique_id="00:80:41:19:69:90",
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
# Start reauth flow
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={
|
||||||
|
"source": SOURCE_REAUTH,
|
||||||
|
"entry_id": entry.entry_id,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
# Submit with mix of clearing and updating credentials
|
||||||
|
result = await _configure_flow(
|
||||||
|
hass,
|
||||||
|
result["flow_id"],
|
||||||
|
{
|
||||||
|
CONF_PASSKEY: "", # Clear passkey
|
||||||
|
CONF_USERNAME: "new_user", # Update username
|
||||||
|
CONF_PASSWORD: "", # Clear password
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
_assert_abort_result(result, "reauth_successful")
|
||||||
|
|
||||||
|
# Verify mixed update: some cleared, some updated, some preserved
|
||||||
|
assert entry.data[CONF_PASSKEY] == "" # Cleared
|
||||||
|
assert entry.data[CONF_USERNAME] == "new_user" # Updated
|
||||||
|
assert entry.data[CONF_PASSWORD] == "" # Cleared
|
||||||
|
|
||||||
|
# Host and port should remain unchanged
|
||||||
|
assert entry.data[CONF_HOST] == "127.0.0.1"
|
||||||
|
assert entry.data[CONF_PORT] == 80
|
||||||
|
|
||||||
|
|
||||||
async def test_zeroconf_discovery_auth_error_during_confirm(
|
async def test_zeroconf_discovery_auth_error_during_confirm(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_bsblan: MagicMock,
|
mock_bsblan: MagicMock,
|
||||||
|
Reference in New Issue
Block a user