core/tests/auth/test_init.py

294 lines
9.4 KiB
Python
Raw Normal View History

"""Tests for the Home Assistant auth module."""
from datetime import timedelta
from unittest.mock import Mock, patch
import pytest
from homeassistant import auth, data_entry_flow
2018-07-13 09:43:08 +00:00
from homeassistant.auth import (
models as auth_models, auth_store, const as auth_const)
from homeassistant.util import dt as dt_util
from tests.common import (
MockUser, ensure_auth_manager_loaded, flush_store, CLIENT_ID)
@pytest.fixture
def mock_hass(loop):
"""Hass mock with minimum amount of data set to make it work with auth."""
hass = Mock()
hass.config.skip_pip = True
return hass
async def test_auth_manager_from_config_validates_config_and_id(mock_hass):
"""Test get auth providers."""
manager = await auth.auth_manager_from_config(mock_hass, [{
'name': 'Test Name',
'type': 'insecure_example',
'users': [],
}, {
'name': 'Invalid config because no users',
'type': 'insecure_example',
'id': 'invalid_config',
}, {
'name': 'Test Name 2',
'type': 'insecure_example',
'id': 'another',
'users': [],
}, {
'name': 'Wrong because duplicate ID',
'type': 'insecure_example',
'id': 'another',
'users': [],
}])
providers = [{
'name': provider.name,
'id': provider.id,
'type': provider.type,
} for provider in manager.auth_providers]
assert providers == [{
'name': 'Test Name',
'type': 'insecure_example',
'id': None,
}, {
'name': 'Test Name 2',
'type': 'insecure_example',
'id': 'another',
}]
async def test_create_new_user(hass, hass_storage):
"""Test creating new user."""
manager = await auth.auth_manager_from_config(hass, [{
'type': 'insecure_example',
'users': [{
'username': 'test-user',
'password': 'test-pass',
'name': 'Test Name'
}]
}])
step = await manager.login_flow.async_init(('insecure_example', None))
assert step['type'] == data_entry_flow.RESULT_TYPE_FORM
step = await manager.login_flow.async_configure(step['flow_id'], {
'username': 'test-user',
'password': 'test-pass',
})
assert step['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
credentials = step['result']
user = await manager.async_get_or_create_user(credentials)
assert user is not None
assert user.is_owner is True
assert user.name == 'Test Name'
async def test_login_as_existing_user(mock_hass):
"""Test login as existing user."""
manager = await auth.auth_manager_from_config(mock_hass, [{
'type': 'insecure_example',
'users': [{
'username': 'test-user',
'password': 'test-pass',
'name': 'Test Name'
}]
}])
ensure_auth_manager_loaded(manager)
2018-07-10 18:33:03 +00:00
# Add a fake user that we're not going to log in with
user = MockUser(
id='mock-user2',
is_owner=False,
is_active=False,
name='Not user',
).add_to_auth_manager(manager)
2018-07-13 09:43:08 +00:00
user.credentials.append(auth_models.Credentials(
2018-07-10 18:33:03 +00:00
id='mock-id2',
auth_provider_type='insecure_example',
auth_provider_id=None,
data={'username': 'other-user'},
is_new=False,
))
# Add fake user with credentials for example auth provider.
user = MockUser(
id='mock-user',
is_owner=False,
is_active=False,
name='Paulus',
).add_to_auth_manager(manager)
2018-07-13 09:43:08 +00:00
user.credentials.append(auth_models.Credentials(
id='mock-id',
auth_provider_type='insecure_example',
auth_provider_id=None,
data={'username': 'test-user'},
is_new=False,
))
step = await manager.login_flow.async_init(('insecure_example', None))
assert step['type'] == data_entry_flow.RESULT_TYPE_FORM
step = await manager.login_flow.async_configure(step['flow_id'], {
'username': 'test-user',
'password': 'test-pass',
})
assert step['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
credentials = step['result']
user = await manager.async_get_or_create_user(credentials)
assert user is not None
assert user.id == 'mock-user'
assert user.is_owner is False
assert user.is_active is False
assert user.name == 'Paulus'
async def test_linking_user_to_two_auth_providers(hass, hass_storage):
"""Test linking user to two auth providers."""
manager = await auth.auth_manager_from_config(hass, [{
'type': 'insecure_example',
'users': [{
'username': 'test-user',
'password': 'test-pass',
}]
}, {
'type': 'insecure_example',
'id': 'another-provider',
'users': [{
'username': 'another-user',
'password': 'another-password',
}]
}])
step = await manager.login_flow.async_init(('insecure_example', None))
step = await manager.login_flow.async_configure(step['flow_id'], {
'username': 'test-user',
'password': 'test-pass',
})
user = await manager.async_get_or_create_user(step['result'])
assert user is not None
step = await manager.login_flow.async_init(('insecure_example',
'another-provider'))
step = await manager.login_flow.async_configure(step['flow_id'], {
'username': 'another-user',
'password': 'another-password',
})
await manager.async_link_user(user, step['result'])
assert len(user.credentials) == 2
async def test_saving_loading(hass, hass_storage):
"""Test storing and saving data.
Creates one of each type that we store to test we restore correctly.
"""
manager = await auth.auth_manager_from_config(hass, [{
'type': 'insecure_example',
'users': [{
'username': 'test-user',
'password': 'test-pass',
}]
}])
step = await manager.login_flow.async_init(('insecure_example', None))
step = await manager.login_flow.async_configure(step['flow_id'], {
'username': 'test-user',
'password': 'test-pass',
})
user = await manager.async_get_or_create_user(step['result'])
refresh_token = await manager.async_create_refresh_token(user, CLIENT_ID)
manager.async_create_access_token(refresh_token)
await flush_store(manager._store._store)
2018-07-13 09:43:08 +00:00
store2 = auth_store.AuthStore(hass)
users = await store2.async_get_users()
assert len(users) == 1
assert users[0] == user
def test_access_token_expired():
"""Test that the expired property on access tokens work."""
2018-07-13 09:43:08 +00:00
refresh_token = auth_models.RefreshToken(
user=None,
client_id='bla'
)
2018-07-13 09:43:08 +00:00
access_token = auth_models.AccessToken(
refresh_token=refresh_token
)
assert access_token.expired is False
2018-07-13 09:43:08 +00:00
with patch('homeassistant.util.dt.utcnow',
return_value=dt_util.utcnow() +
auth_const.ACCESS_TOKEN_EXPIRATION):
assert access_token.expired is True
2018-07-13 09:43:08 +00:00
almost_exp = \
dt_util.utcnow() + auth_const.ACCESS_TOKEN_EXPIRATION - timedelta(1)
with patch('homeassistant.util.dt.utcnow', return_value=almost_exp):
assert access_token.expired is False
async def test_cannot_retrieve_expired_access_token(hass):
"""Test that we cannot retrieve expired access tokens."""
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)
assert refresh_token.user.id is user.id
assert refresh_token.client_id == CLIENT_ID
access_token = manager.async_create_access_token(refresh_token)
assert manager.async_get_access_token(access_token.token) is access_token
2018-07-13 09:43:08 +00:00
with patch('homeassistant.util.dt.utcnow',
return_value=dt_util.utcnow() +
auth_const.ACCESS_TOKEN_EXPIRATION):
assert manager.async_get_access_token(access_token.token) is None
# Even with unpatched time, it should have been removed from manager
assert manager.async_get_access_token(access_token.token) is None
async def test_generating_system_user(hass):
"""Test that we can add a system user."""
manager = await auth.auth_manager_from_config(hass, [])
user = await manager.async_create_system_user('Hass.io')
token = await manager.async_create_refresh_token(user)
assert user.system_generated
assert token is not None
assert token.client_id is None
async def test_refresh_token_requires_client_for_user(hass):
"""Test that we can add a system user."""
manager = await auth.auth_manager_from_config(hass, [])
user = MockUser().add_to_auth_manager(manager)
assert user.system_generated is False
with pytest.raises(ValueError):
await manager.async_create_refresh_token(user)
token = await manager.async_create_refresh_token(user, CLIENT_ID)
assert token is not None
assert token.client_id == CLIENT_ID
async def test_refresh_token_not_requires_client_for_system_user(hass):
"""Test that we can add a system user."""
manager = await auth.auth_manager_from_config(hass, [])
user = await manager.async_create_system_user('Hass.io')
assert user.system_generated is True
with pytest.raises(ValueError):
await manager.async_create_refresh_token(user, CLIENT_ID)
token = await manager.async_create_refresh_token(user)
assert token is not None
assert token.client_id is None