Add expiration of unused refresh tokens (#108428)

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
Michael 2024-01-25 00:24:22 +01:00 committed by GitHub
parent 0d22822ed0
commit f5d439799b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 243 additions and 7 deletions

View file

@ -26,6 +26,7 @@ from tests.common import (
CLIENT_ID,
MockUser,
async_capture_events,
async_fire_time_changed,
ensure_auth_manager_loaded,
flush_store,
)
@ -406,6 +407,8 @@ async def test_generating_system_user(hass: HomeAssistant) -> None:
assert not user.local_only
assert token is not None
assert token.client_id is None
assert token.token_type == auth.models.TOKEN_TYPE_SYSTEM
assert token.expire_at is None
await hass.async_block_till_done()
assert len(events) == 1
@ -421,6 +424,8 @@ async def test_generating_system_user(hass: HomeAssistant) -> None:
assert user.local_only
assert token is not None
assert token.client_id is None
assert token.token_type == auth.models.TOKEN_TYPE_SYSTEM
assert token.expire_at is None
await hass.async_block_till_done()
assert len(events) == 2
@ -474,6 +479,8 @@ async def test_refresh_token_with_specific_access_token_expiration(
assert token is not None
assert token.client_id == CLIENT_ID
assert token.access_token_expiration == timedelta(days=100)
assert token.token_type == auth.models.TOKEN_TYPE_NORMAL
assert token.expire_at is not None
async def test_refresh_token_type(hass: HomeAssistant) -> None:
@ -515,6 +522,7 @@ async def test_refresh_token_type_long_lived_access_token(hass: HomeAssistant) -
assert token.client_name == "GPS LOGGER"
assert token.client_icon == "mdi:home"
assert token.token_type == auth_models.TOKEN_TYPE_LONG_LIVED_ACCESS_TOKEN
assert token.expire_at is None
async def test_refresh_token_provider_validation(mock_hass) -> None:
@ -565,9 +573,9 @@ async def test_cannot_deactive_owner(mock_hass) -> None:
await manager.async_deactivate_user(owner)
async def test_remove_refresh_token(mock_hass) -> None:
async def test_remove_refresh_token(hass: HomeAssistant) -> None:
"""Test that we can remove a refresh token."""
manager = await auth.auth_manager_from_config(mock_hass, [], [])
manager = await auth.auth_manager_from_config(hass, [], [])
user = MockUser().add_to_auth_manager(manager)
refresh_token = await manager.async_create_refresh_token(user, CLIENT_ID)
access_token = manager.async_create_access_token(refresh_token)
@ -578,6 +586,70 @@ async def test_remove_refresh_token(mock_hass) -> None:
assert manager.async_validate_access_token(access_token) is None
async def test_remove_expired_refresh_token(hass: HomeAssistant) -> None:
"""Test that expired refresh tokens are deleted."""
manager = await auth.auth_manager_from_config(hass, [], [])
user = MockUser().add_to_auth_manager(manager)
now = dt_util.utcnow()
with freeze_time(now):
refresh_token1 = await manager.async_create_refresh_token(user, CLIENT_ID)
assert (
refresh_token1.expire_at
== now.timestamp() + timedelta(days=90).total_seconds()
)
with freeze_time(now + timedelta(days=30)):
async_fire_time_changed(hass, now + timedelta(days=30))
refresh_token2 = await manager.async_create_refresh_token(user, CLIENT_ID)
assert (
refresh_token2.expire_at
== now.timestamp() + timedelta(days=120).total_seconds()
)
with freeze_time(now + timedelta(days=89, hours=23)):
async_fire_time_changed(hass, now + timedelta(days=89, hours=23))
await hass.async_block_till_done()
assert manager.async_get_refresh_token(refresh_token1.id)
assert manager.async_get_refresh_token(refresh_token2.id)
with freeze_time(now + timedelta(days=90, seconds=5)):
async_fire_time_changed(hass, now + timedelta(days=90, seconds=5))
await hass.async_block_till_done()
assert manager.async_get_refresh_token(refresh_token1.id) is None
assert manager.async_get_refresh_token(refresh_token2.id)
with freeze_time(now + timedelta(days=120, seconds=5)):
async_fire_time_changed(hass, now + timedelta(days=120, seconds=5))
await hass.async_block_till_done()
assert manager.async_get_refresh_token(refresh_token1.id) is None
assert manager.async_get_refresh_token(refresh_token2.id) is None
async def test_update_expire_at_refresh_token(hass: HomeAssistant) -> None:
"""Test that expire at is updated when refresh token is used."""
manager = await auth.auth_manager_from_config(hass, [], [])
user = MockUser().add_to_auth_manager(manager)
now = dt_util.utcnow()
with freeze_time(now):
refresh_token = await manager.async_create_refresh_token(user, CLIENT_ID)
assert (
refresh_token.expire_at
== now.timestamp() + timedelta(days=90).total_seconds()
)
with freeze_time(now + timedelta(days=30)):
async_fire_time_changed(hass, now + timedelta(days=30))
await hass.async_block_till_done()
assert manager.async_create_access_token(refresh_token)
await hass.async_block_till_done()
assert (
refresh_token.expire_at
== now.timestamp()
+ timedelta(days=30).total_seconds()
+ timedelta(days=90).total_seconds()
)
async def test_register_revoke_token_callback(mock_hass) -> None:
"""Test that a registered revoke token callback is called."""
manager = await auth.auth_manager_from_config(mock_hass, [], [])