Fix OAuth reauth in Tesla Fleet (#124744)
* Fix auth failure * Test * Fix test * Only reauth on 401 * Cover 401 and others * Update homeassistant/components/tesla_fleet/strings.json Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com> --------- Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com>
This commit is contained in:
parent
11370979e5
commit
e39b3796f3
5 changed files with 61 additions and 5 deletions
|
@ -3,6 +3,7 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
from typing import Final
|
from typing import Final
|
||||||
|
|
||||||
|
from aiohttp.client_exceptions import ClientResponseError
|
||||||
import jwt
|
import jwt
|
||||||
from tesla_fleet_api import EnergySpecific, TeslaFleetApi, VehicleSpecific
|
from tesla_fleet_api import EnergySpecific, TeslaFleetApi, VehicleSpecific
|
||||||
from tesla_fleet_api.const import Scope
|
from tesla_fleet_api.const import Scope
|
||||||
|
@ -66,7 +67,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: TeslaFleetConfigEntry) -
|
||||||
|
|
||||||
async def _refresh_token() -> str:
|
async def _refresh_token() -> str:
|
||||||
async with refresh_lock:
|
async with refresh_lock:
|
||||||
await oauth_session.async_ensure_token_valid()
|
try:
|
||||||
|
await oauth_session.async_ensure_token_valid()
|
||||||
|
except ClientResponseError as e:
|
||||||
|
if e.status == 401:
|
||||||
|
raise ConfigEntryAuthFailed from e
|
||||||
|
raise ConfigEntryNotReady from e
|
||||||
token: str = oauth_session.token[CONF_ACCESS_TOKEN]
|
token: str = oauth_session.token[CONF_ACCESS_TOKEN]
|
||||||
return token
|
return token
|
||||||
|
|
||||||
|
|
|
@ -83,5 +83,8 @@ class OAuth2FlowHandler(
|
||||||
) -> ConfigFlowResult:
|
) -> ConfigFlowResult:
|
||||||
"""Confirm reauth dialog."""
|
"""Confirm reauth dialog."""
|
||||||
if user_input is None:
|
if user_input is None:
|
||||||
return self.async_show_form(step_id="reauth_confirm")
|
return self.async_show_form(
|
||||||
|
step_id="reauth_confirm",
|
||||||
|
description_placeholders={"name": "Tesla Fleet"},
|
||||||
|
)
|
||||||
return await self.async_step_user()
|
return await self.async_step_user()
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
},
|
},
|
||||||
"reauth_confirm": {
|
"reauth_confirm": {
|
||||||
"title": "[%key:common::config_flow::title::reauth%]",
|
"title": "[%key:common::config_flow::title::reauth%]",
|
||||||
"description": "The Withings integration needs to re-authenticate your account"
|
"description": "The {name} integration needs to re-authenticate your account"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"create_entry": {
|
"create_entry": {
|
||||||
|
|
|
@ -124,7 +124,7 @@ def mock_site_info() -> Generator[AsyncMock]:
|
||||||
yield mock_live_status
|
yield mock_live_status
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture
|
||||||
def mock_find_server() -> Generator[AsyncMock]:
|
def mock_find_server() -> Generator[AsyncMock]:
|
||||||
"""Mock Tesla Fleet find server method."""
|
"""Mock Tesla Fleet find server method."""
|
||||||
with patch(
|
with patch(
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
"""Test the Tesla Fleet init."""
|
"""Test the Tesla Fleet init."""
|
||||||
|
|
||||||
from unittest.mock import AsyncMock
|
from unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
|
from aiohttp import RequestInfo
|
||||||
|
from aiohttp.client_exceptions import ClientResponseError
|
||||||
from freezegun.api import FrozenDateTimeFactory
|
from freezegun.api import FrozenDateTimeFactory
|
||||||
import pytest
|
import pytest
|
||||||
from syrupy.assertion import SnapshotAssertion
|
from syrupy.assertion import SnapshotAssertion
|
||||||
|
@ -16,6 +18,7 @@ from tesla_fleet_api.exceptions import (
|
||||||
VehicleOffline,
|
VehicleOffline,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from homeassistant.components.tesla_fleet.const import AUTHORIZE_URL
|
||||||
from homeassistant.components.tesla_fleet.coordinator import (
|
from homeassistant.components.tesla_fleet.coordinator import (
|
||||||
ENERGY_INTERVAL,
|
ENERGY_INTERVAL,
|
||||||
ENERGY_INTERVAL_SECONDS,
|
ENERGY_INTERVAL_SECONDS,
|
||||||
|
@ -72,6 +75,50 @@ async def test_init_error(
|
||||||
assert normal_config_entry.state is state
|
assert normal_config_entry.state is state
|
||||||
|
|
||||||
|
|
||||||
|
async def test_oauth_refresh_expired(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
normal_config_entry: MockConfigEntry,
|
||||||
|
mock_products: AsyncMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test init with expired Oauth token."""
|
||||||
|
|
||||||
|
# Patch the token refresh to raise an error
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.tesla_fleet.OAuth2Session.async_ensure_token_valid",
|
||||||
|
side_effect=ClientResponseError(
|
||||||
|
RequestInfo(AUTHORIZE_URL, "POST", {}, AUTHORIZE_URL), None, status=401
|
||||||
|
),
|
||||||
|
) as mock_async_ensure_token_valid:
|
||||||
|
# Trigger an unmocked function call
|
||||||
|
mock_products.side_effect = InvalidRegion
|
||||||
|
await setup_platform(hass, normal_config_entry)
|
||||||
|
|
||||||
|
mock_async_ensure_token_valid.assert_called_once()
|
||||||
|
assert normal_config_entry.state is ConfigEntryState.SETUP_ERROR
|
||||||
|
|
||||||
|
|
||||||
|
async def test_oauth_refresh_error(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
normal_config_entry: MockConfigEntry,
|
||||||
|
mock_products: AsyncMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test init with Oauth refresh failure."""
|
||||||
|
|
||||||
|
# Patch the token refresh to raise an error
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.tesla_fleet.OAuth2Session.async_ensure_token_valid",
|
||||||
|
side_effect=ClientResponseError(
|
||||||
|
RequestInfo(AUTHORIZE_URL, "POST", {}, AUTHORIZE_URL), None, status=400
|
||||||
|
),
|
||||||
|
) as mock_async_ensure_token_valid:
|
||||||
|
# Trigger an unmocked function call
|
||||||
|
mock_products.side_effect = InvalidRegion
|
||||||
|
await setup_platform(hass, normal_config_entry)
|
||||||
|
|
||||||
|
mock_async_ensure_token_valid.assert_called_once()
|
||||||
|
assert normal_config_entry.state is ConfigEntryState.SETUP_RETRY
|
||||||
|
|
||||||
|
|
||||||
# Test devices
|
# Test devices
|
||||||
async def test_devices(
|
async def test_devices(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
|
Loading…
Add table
Reference in a new issue