Fix for ProxmoxVE compoenent failing authentication with realms containg upper case letters. (#176742)

This commit is contained in:
Chris Mason
2026-07-24 07:07:26 +00:00
committed by Franck Nijhof
parent db02b3bd21
commit da0a65be87
5 changed files with 149 additions and 79 deletions
@@ -193,9 +193,9 @@ async def async_migrate_entry(hass: HomeAssistant, entry: ProxmoxConfigEntry) ->
if "@" in data.get(CONF_USERNAME, ""):
username, realm = data[CONF_USERNAME].split("@", 1)
data[CONF_USERNAME] = username
data[CONF_REALM] = realm.lower()
data[CONF_REALM] = realm
realm = data[CONF_REALM].lower()
realm = data[CONF_REALM]
# If the realm is one of the base providers,
# set the provider to match the realm.
+1 -1
View File
@@ -16,7 +16,7 @@ def sanitize_config_entry(input_data: Mapping[str, Any]) -> dict[str, Any]:
realm = provider.lower()
if provider == AUTH_OTHER:
realm = data[CONF_REALM].lower()
realm = data[CONF_REALM]
data[CONF_REALM] = realm
data[CONF_USERNAME] = f"{username}@{realm}"
+4 -4
View File
@@ -64,8 +64,8 @@ MOCK_TEST_TOKEN_CONFIG = {
MOCK_TEST_OTHER_CONFIG = {
**MOCK_TEST_CONFIG,
CONF_AUTH_METHOD: "other",
CONF_REALM: "test_realm",
CONF_USERNAME: "test_user@test_realm",
CONF_REALM: "Test_Realm",
CONF_USERNAME: "test_user@Test_Realm",
}
MOCK_TEST_TOKEN_OTHER_CONFIG = {
@@ -74,8 +74,8 @@ MOCK_TEST_TOKEN_OTHER_CONFIG = {
CONF_TOKEN_ID: "test_token_id",
CONF_TOKEN_SECRET: "test_token_secret",
CONF_AUTH_METHOD: "other",
CONF_REALM: "test_realm",
CONF_USERNAME: "test_user@test_realm",
CONF_REALM: "Test_Realm",
CONF_USERNAME: "test_user@Test_Realm",
}
@@ -75,7 +75,7 @@ MOCK_USER_STEP_OTHER = {
MOCK_USER_AUTH_STEP_OTHER = {
**MOCK_USER_AUTH_STEP_PASSWORD,
CONF_REALM: "test_realm",
CONF_REALM: "Test_Realm",
}
# Other authentication method with realm and token
@@ -86,7 +86,7 @@ MOCK_USER_STEP_OTHER_TOKEN = {
MOCK_USER_AUTH_STEP_OTHER_TOKEN = {
**MOCK_USER_AUTH_STEP_TOKEN,
CONF_REALM: "test_realm",
CONF_REALM: "Test_Realm",
}
MOCK_USER_SETUP = {CONF_NODES: ["pve1"]}
@@ -724,7 +724,7 @@ async def test_full_flow_reauth_token_other(
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_REALM: "test_realm",
CONF_REALM: "Test_Realm",
CONF_TOKEN_ID: "test_token_id",
CONF_TOKEN_SECRET: "new_token_secret",
},
+139 -69
View File
@@ -9,6 +9,7 @@ import requests
from requests.exceptions import ConnectTimeout, SSLError
from homeassistant.components.proxmoxve.const import (
AUTH_OTHER,
AUTH_PAM,
CONF_AUTH_METHOD,
CONF_CONTAINERS,
@@ -165,25 +166,56 @@ async def test_setup_exceptions(
assert mock_config_entry.state is expected_state
@pytest.mark.parametrize(
("mock_config_entry", "expected_auth_method", "expected_realm"),
[
(
MockConfigEntry(
domain=DOMAIN,
version=1,
unique_id="1",
data={
CONF_HOST: "http://test_host",
CONF_PORT: 8006,
CONF_REALM: "pam",
CONF_USERNAME: "test_user@pam",
CONF_PASSWORD: "test_password",
CONF_VERIFY_SSL: True,
},
),
AUTH_PAM,
"pam",
),
(
MockConfigEntry(
domain=DOMAIN,
version=1,
unique_id="1",
data={
CONF_HOST: "http://test_host",
CONF_PORT: 8006,
CONF_REALM: "Test_Realm",
CONF_USERNAME: "test_user@Test_Realm",
CONF_PASSWORD: "test_password",
CONF_VERIFY_SSL: True,
},
),
AUTH_OTHER,
"Test_Realm",
),
],
)
async def test_migration_v1_to_v3(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
device_registry: dr.DeviceRegistry,
mock_config_entry: MockConfigEntry,
expected_auth_method: str,
expected_realm: str,
) -> None:
"""Test migration from version 1."""
entry = MockConfigEntry(
domain=DOMAIN,
version=1,
unique_id="1",
data={
CONF_HOST: "http://test_host",
CONF_PORT: 8006,
CONF_REALM: "pam",
CONF_USERNAME: "test_user@pam",
CONF_PASSWORD: "test_password",
CONF_VERIFY_SSL: True,
},
)
"""Test migration from version 1 to 3."""
entry = mock_config_entry
entry.add_to_hass(hass)
assert entry.version == 1
@@ -227,6 +259,8 @@ async def test_migration_v1_to_v3(
await hass.async_block_till_done()
assert entry.version == 3
assert entry.data[CONF_AUTH_METHOD] == expected_auth_method
assert entry.data[CONF_REALM] == expected_realm
vm_entity_after = entity_registry.async_get(vm_entity.entity_id)
container_entity_after = entity_registry.async_get(container_entity.entity_id)
@@ -235,6 +269,97 @@ async def test_migration_v1_to_v3(
assert container_entity_after.unique_id == f"{entry.entry_id}_200_status"
@pytest.mark.parametrize(
("mock_config_entry", "expected_auth_method", "expected_realm"),
[
(
MockConfigEntry(
domain=DOMAIN,
version=2,
unique_id="1",
data={
CONF_HOST: "http://test_host",
CONF_PORT: 8006,
CONF_REALM: "pam",
CONF_USERNAME: "test_user@pam",
CONF_PASSWORD: "test_password",
CONF_VERIFY_SSL: True,
},
),
AUTH_PAM,
"pam",
),
(
MockConfigEntry(
domain=DOMAIN,
version=2,
unique_id="1",
data={
CONF_HOST: "http://test_host",
CONF_PORT: 8006,
CONF_REALM: "Test_Realm",
CONF_USERNAME: "test_user@Test_Realm",
CONF_PASSWORD: "test_password",
CONF_VERIFY_SSL: True,
},
),
AUTH_OTHER,
"Test_Realm",
),
(
MockConfigEntry(
domain=DOMAIN,
version=2,
unique_id="1",
data={
CONF_HOST: "http://test_host",
CONF_PORT: 8006,
CONF_USERNAME: "test_user@pam",
CONF_PASSWORD: "test_password",
CONF_VERIFY_SSL: True,
},
),
AUTH_PAM,
"pam",
),
(
MockConfigEntry(
domain=DOMAIN,
version=2,
unique_id="1",
data={
CONF_HOST: "http://test_host",
CONF_PORT: 8006,
CONF_USERNAME: "test_user@Test_Realm",
CONF_PASSWORD: "test_password",
CONF_VERIFY_SSL: True,
},
),
AUTH_OTHER,
"Test_Realm",
),
],
)
async def test_migration_v2_to_v3(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
expected_auth_method: str,
expected_realm: str,
) -> None:
"""Test migration from version 2 to 3."""
entry = mock_config_entry
entry.add_to_hass(hass)
assert entry.version == 2
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert entry.version == 3
assert entry.data[CONF_AUTH_METHOD] == expected_auth_method
assert entry.data[CONF_REALM] == expected_realm
async def test_offline_node(
hass: HomeAssistant,
mock_proxmox_client: MagicMock,
@@ -253,61 +378,6 @@ async def test_offline_node(
assert state.state == STATE_OFF
async def test_migration_v2_to_v3(
hass: HomeAssistant,
) -> None:
"""Test migration from version 2 to 3."""
entry = MockConfigEntry(
domain=DOMAIN,
version=2,
unique_id="1",
data={
CONF_HOST: "http://test_host",
CONF_PORT: 8006,
CONF_REALM: "pam",
CONF_USERNAME: "test_user@pam",
CONF_PASSWORD: "test_password",
CONF_VERIFY_SSL: True,
},
)
entry.add_to_hass(hass)
assert entry.version == 2
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert entry.version == 3
assert entry.data[CONF_AUTH_METHOD] == AUTH_PAM
assert entry.data[CONF_REALM] == AUTH_PAM
async def test_migration_v2_to_v3_without_realm(
hass: HomeAssistant,
) -> None:
"""Test migration from version 2 to 3."""
entry = MockConfigEntry(
domain=DOMAIN,
version=2,
unique_id="1",
data={
CONF_HOST: "http://test_host",
CONF_PORT: 8006,
CONF_USERNAME: "test_user@pam",
CONF_PASSWORD: "test_password",
CONF_VERIFY_SSL: True,
},
)
entry.add_to_hass(hass)
assert entry.version == 2
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert entry.version == 3
assert entry.data[CONF_AUTH_METHOD] == AUTH_PAM
assert entry.data[CONF_REALM] == AUTH_PAM
async def test_new_vm_creates_entity(
hass: HomeAssistant,
mock_proxmox_client: MagicMock,