2018-10-01 09:21:00 +00:00
|
|
|
"""Test auth of websocket API."""
|
|
|
|
from unittest.mock import patch
|
|
|
|
|
2019-03-22 18:59:10 +00:00
|
|
|
from homeassistant.components.websocket_api.const import (
|
|
|
|
URL, SIGNAL_WEBSOCKET_CONNECTED, SIGNAL_WEBSOCKET_DISCONNECTED)
|
2018-10-01 14:09:31 +00:00
|
|
|
from homeassistant.components.websocket_api.auth import (
|
|
|
|
TYPE_AUTH, TYPE_AUTH_INVALID, TYPE_AUTH_OK, TYPE_AUTH_REQUIRED)
|
|
|
|
|
2018-10-01 09:21:00 +00:00
|
|
|
from homeassistant.setup import async_setup_component
|
|
|
|
|
|
|
|
from tests.common import mock_coro
|
|
|
|
|
|
|
|
from . import API_PASSWORD
|
|
|
|
|
|
|
|
|
2018-12-02 15:32:53 +00:00
|
|
|
async def test_auth_via_msg(no_auth_websocket_client, legacy_auth):
|
2018-10-01 09:21:00 +00:00
|
|
|
"""Test authenticating."""
|
|
|
|
await no_auth_websocket_client.send_json({
|
2018-10-01 14:09:31 +00:00
|
|
|
'type': TYPE_AUTH,
|
2018-10-01 09:21:00 +00:00
|
|
|
'api_password': API_PASSWORD
|
|
|
|
})
|
|
|
|
|
|
|
|
msg = await no_auth_websocket_client.receive_json()
|
|
|
|
|
2018-10-01 14:09:31 +00:00
|
|
|
assert msg['type'] == TYPE_AUTH_OK
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
|
2019-03-22 18:59:10 +00:00
|
|
|
async def test_auth_events(hass, no_auth_websocket_client, legacy_auth):
|
|
|
|
"""Test authenticating."""
|
|
|
|
connected_evt = []
|
|
|
|
hass.helpers.dispatcher.async_dispatcher_connect(
|
|
|
|
SIGNAL_WEBSOCKET_CONNECTED,
|
|
|
|
lambda: connected_evt.append(1))
|
|
|
|
disconnected_evt = []
|
|
|
|
hass.helpers.dispatcher.async_dispatcher_connect(
|
|
|
|
SIGNAL_WEBSOCKET_DISCONNECTED,
|
|
|
|
lambda: disconnected_evt.append(1))
|
|
|
|
|
|
|
|
await test_auth_via_msg(no_auth_websocket_client, legacy_auth)
|
|
|
|
|
|
|
|
assert len(connected_evt) == 1
|
|
|
|
assert not disconnected_evt
|
|
|
|
|
|
|
|
await no_auth_websocket_client.close()
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert len(disconnected_evt) == 1
|
|
|
|
|
|
|
|
|
2018-10-01 09:21:00 +00:00
|
|
|
async def test_auth_via_msg_incorrect_pass(no_auth_websocket_client):
|
|
|
|
"""Test authenticating."""
|
2018-10-01 14:09:31 +00:00
|
|
|
with patch('homeassistant.components.websocket_api.auth.'
|
|
|
|
'process_wrong_login', return_value=mock_coro()) \
|
|
|
|
as mock_process_wrong_login:
|
2018-10-01 09:21:00 +00:00
|
|
|
await no_auth_websocket_client.send_json({
|
2018-10-01 14:09:31 +00:00
|
|
|
'type': TYPE_AUTH,
|
2018-10-01 09:21:00 +00:00
|
|
|
'api_password': API_PASSWORD + 'wrong'
|
|
|
|
})
|
|
|
|
|
|
|
|
msg = await no_auth_websocket_client.receive_json()
|
|
|
|
|
|
|
|
assert mock_process_wrong_login.called
|
2018-10-01 14:09:31 +00:00
|
|
|
assert msg['type'] == TYPE_AUTH_INVALID
|
2018-10-01 09:21:00 +00:00
|
|
|
assert msg['message'] == 'Invalid access token or password'
|
|
|
|
|
|
|
|
|
2019-03-22 18:59:10 +00:00
|
|
|
async def test_auth_events_incorrect_pass(hass, no_auth_websocket_client):
|
|
|
|
"""Test authenticating."""
|
|
|
|
connected_evt = []
|
|
|
|
hass.helpers.dispatcher.async_dispatcher_connect(
|
|
|
|
SIGNAL_WEBSOCKET_CONNECTED,
|
|
|
|
lambda: connected_evt.append(1))
|
|
|
|
disconnected_evt = []
|
|
|
|
hass.helpers.dispatcher.async_dispatcher_connect(
|
|
|
|
SIGNAL_WEBSOCKET_DISCONNECTED,
|
|
|
|
lambda: disconnected_evt.append(1))
|
|
|
|
|
|
|
|
await test_auth_via_msg_incorrect_pass(no_auth_websocket_client)
|
|
|
|
|
|
|
|
assert not connected_evt
|
|
|
|
assert not disconnected_evt
|
|
|
|
|
|
|
|
await no_auth_websocket_client.close()
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert not connected_evt
|
|
|
|
assert not disconnected_evt
|
|
|
|
|
|
|
|
|
2018-10-01 09:21:00 +00:00
|
|
|
async def test_pre_auth_only_auth_allowed(no_auth_websocket_client):
|
|
|
|
"""Verify that before authentication, only auth messages are allowed."""
|
|
|
|
await no_auth_websocket_client.send_json({
|
2019-03-06 03:31:26 +00:00
|
|
|
'type': 'call_service',
|
2018-10-01 09:21:00 +00:00
|
|
|
'domain': 'domain_test',
|
|
|
|
'service': 'test_service',
|
|
|
|
'service_data': {
|
|
|
|
'hello': 'world'
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
msg = await no_auth_websocket_client.receive_json()
|
|
|
|
|
2018-10-01 14:09:31 +00:00
|
|
|
assert msg['type'] == TYPE_AUTH_INVALID
|
|
|
|
assert msg['message'].startswith('Auth message incorrectly formatted')
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_auth_active_with_token(hass, aiohttp_client, hass_access_token):
|
|
|
|
"""Test authenticating with a token."""
|
|
|
|
assert await async_setup_component(hass, 'websocket_api', {
|
|
|
|
'http': {
|
|
|
|
'api_password': API_PASSWORD
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
client = await aiohttp_client(hass.http.app)
|
|
|
|
|
2018-10-01 14:09:31 +00:00
|
|
|
async with client.ws_connect(URL) as ws:
|
2018-12-02 15:32:53 +00:00
|
|
|
auth_msg = await ws.receive_json()
|
|
|
|
assert auth_msg['type'] == TYPE_AUTH_REQUIRED
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2018-12-02 15:32:53 +00:00
|
|
|
await ws.send_json({
|
|
|
|
'type': TYPE_AUTH,
|
|
|
|
'access_token': hass_access_token
|
|
|
|
})
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2018-12-02 15:32:53 +00:00
|
|
|
auth_msg = await ws.receive_json()
|
|
|
|
assert auth_msg['type'] == TYPE_AUTH_OK
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_auth_active_user_inactive(hass, aiohttp_client,
|
|
|
|
hass_access_token):
|
|
|
|
"""Test authenticating with a token."""
|
|
|
|
refresh_token = await hass.auth.async_validate_access_token(
|
|
|
|
hass_access_token)
|
|
|
|
refresh_token.user.is_active = False
|
|
|
|
assert await async_setup_component(hass, 'websocket_api', {
|
|
|
|
'http': {
|
|
|
|
'api_password': API_PASSWORD
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
client = await aiohttp_client(hass.http.app)
|
|
|
|
|
2018-10-01 14:09:31 +00:00
|
|
|
async with client.ws_connect(URL) as ws:
|
2018-12-02 15:32:53 +00:00
|
|
|
auth_msg = await ws.receive_json()
|
|
|
|
assert auth_msg['type'] == TYPE_AUTH_REQUIRED
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2018-12-02 15:32:53 +00:00
|
|
|
await ws.send_json({
|
|
|
|
'type': TYPE_AUTH,
|
|
|
|
'access_token': hass_access_token
|
|
|
|
})
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2018-12-02 15:32:53 +00:00
|
|
|
auth_msg = await ws.receive_json()
|
|
|
|
assert auth_msg['type'] == TYPE_AUTH_INVALID
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_auth_active_with_password_not_allow(hass, aiohttp_client):
|
|
|
|
"""Test authenticating with a token."""
|
|
|
|
assert await async_setup_component(hass, 'websocket_api', {
|
|
|
|
'http': {
|
|
|
|
'api_password': API_PASSWORD
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
client = await aiohttp_client(hass.http.app)
|
|
|
|
|
2018-10-01 14:09:31 +00:00
|
|
|
async with client.ws_connect(URL) as ws:
|
2018-12-02 15:32:53 +00:00
|
|
|
auth_msg = await ws.receive_json()
|
|
|
|
assert auth_msg['type'] == TYPE_AUTH_REQUIRED
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2018-12-02 15:32:53 +00:00
|
|
|
await ws.send_json({
|
|
|
|
'type': TYPE_AUTH,
|
|
|
|
'api_password': API_PASSWORD
|
|
|
|
})
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2018-12-02 15:32:53 +00:00
|
|
|
auth_msg = await ws.receive_json()
|
|
|
|
assert auth_msg['type'] == TYPE_AUTH_INVALID
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
|
2019-01-09 04:45:24 +00:00
|
|
|
async def test_auth_legacy_support_with_password(hass, aiohttp_client,
|
|
|
|
legacy_auth):
|
2018-10-01 09:21:00 +00:00
|
|
|
"""Test authenticating with a token."""
|
|
|
|
assert await async_setup_component(hass, 'websocket_api', {
|
|
|
|
'http': {
|
|
|
|
'api_password': API_PASSWORD
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
client = await aiohttp_client(hass.http.app)
|
|
|
|
|
2018-10-01 14:09:31 +00:00
|
|
|
async with client.ws_connect(URL) as ws:
|
2018-12-02 15:32:53 +00:00
|
|
|
with patch('homeassistant.auth.AuthManager.support_legacy',
|
2018-10-01 09:21:00 +00:00
|
|
|
return_value=True):
|
|
|
|
auth_msg = await ws.receive_json()
|
2018-10-01 14:09:31 +00:00
|
|
|
assert auth_msg['type'] == TYPE_AUTH_REQUIRED
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
await ws.send_json({
|
2018-10-01 14:09:31 +00:00
|
|
|
'type': TYPE_AUTH,
|
2018-10-01 09:21:00 +00:00
|
|
|
'api_password': API_PASSWORD
|
|
|
|
})
|
|
|
|
|
|
|
|
auth_msg = await ws.receive_json()
|
2018-10-01 14:09:31 +00:00
|
|
|
assert auth_msg['type'] == TYPE_AUTH_OK
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_auth_with_invalid_token(hass, aiohttp_client):
|
|
|
|
"""Test authenticating with a token."""
|
|
|
|
assert await async_setup_component(hass, 'websocket_api', {
|
|
|
|
'http': {
|
|
|
|
'api_password': API_PASSWORD
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
client = await aiohttp_client(hass.http.app)
|
|
|
|
|
2018-10-01 14:09:31 +00:00
|
|
|
async with client.ws_connect(URL) as ws:
|
2018-12-02 15:32:53 +00:00
|
|
|
auth_msg = await ws.receive_json()
|
|
|
|
assert auth_msg['type'] == TYPE_AUTH_REQUIRED
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2018-12-02 15:32:53 +00:00
|
|
|
await ws.send_json({
|
|
|
|
'type': TYPE_AUTH,
|
|
|
|
'access_token': 'incorrect'
|
|
|
|
})
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2018-12-02 15:32:53 +00:00
|
|
|
auth_msg = await ws.receive_json()
|
|
|
|
assert auth_msg['type'] == TYPE_AUTH_INVALID
|