1
mirror of https://github.com/home-assistant/core synced 2024-07-18 12:02:20 +02:00

No more opt-out auth (#18854)

* No more opt-out auth

* Fix var
This commit is contained in:
Paulus Schoutsen 2018-12-02 16:32:53 +01:00 committed by Pascal Vizeli
parent ae9e3d83d7
commit d1a621601d
42 changed files with 307 additions and 473 deletions

View File

@ -78,11 +78,6 @@ class AuthManager:
hass, self._async_create_login_flow,
self._async_finish_login_flow)
@property
def active(self) -> bool:
"""Return if any auth providers are registered."""
return bool(self._providers)
@property
def support_legacy(self) -> bool:
"""

View File

@ -14,6 +14,8 @@ from homeassistant.util.yaml import load_yaml, dump
DOMAIN = 'config'
DEPENDENCIES = ['http']
SECTIONS = (
'auth',
'auth_provider_homeassistant',
'automation',
'config_entries',
'core',
@ -58,10 +60,6 @@ async def async_setup(hass, config):
tasks = [setup_panel(panel_name) for panel_name in SECTIONS]
if hass.auth.active:
tasks.append(setup_panel('auth'))
tasks.append(setup_panel('auth_provider_homeassistant'))
for panel_name in ON_DEMAND:
if panel_name in hass.config.components:
tasks.append(setup_panel(panel_name))

View File

@ -238,7 +238,7 @@ async def async_setup(hass, config):
if os.path.isdir(local):
hass.http.register_static_path("/local", local, not is_dev)
index_view = IndexView(repo_path, js_version, hass.auth.active)
index_view = IndexView(repo_path, js_version)
hass.http.register_view(index_view)
hass.http.register_view(AuthorizeView(repo_path, js_version))
@ -364,11 +364,10 @@ class IndexView(HomeAssistantView):
requires_auth = False
extra_urls = ['/states', '/states/{extra}']
def __init__(self, repo_path, js_option, auth_active):
def __init__(self, repo_path, js_option):
"""Initialize the frontend view."""
self.repo_path = repo_path
self.js_option = js_option
self.auth_active = auth_active
self._template_cache = {}
def get_template(self, latest):
@ -415,8 +414,6 @@ class IndexView(HomeAssistantView):
# do not try to auto connect on load
no_auth = '0'
use_oauth = '1' if self.auth_active else '0'
template = await hass.async_add_job(self.get_template, latest)
extra_key = DATA_EXTRA_HTML_URL if latest else DATA_EXTRA_HTML_URL_ES5
@ -425,7 +422,7 @@ class IndexView(HomeAssistantView):
no_auth=no_auth,
theme_color=MANIFEST_JSON['theme_color'],
extra_urls=hass.data[extra_key],
use_oauth=use_oauth
use_oauth='1'
)
return web.Response(text=template.render(**template_params),

View File

@ -213,13 +213,7 @@ async def async_setup(hass, config):
embed_iframe=True,
)
# Temporary. No refresh token tells supervisor to use API password.
if hass.auth.active:
token = refresh_token.token
else:
token = None
await hassio.update_hass_api(config.get('http', {}), token)
await hassio.update_hass_api(config.get('http', {}), refresh_token.token)
if 'homeassistant' in config:
await hassio.update_hass_timezone(config['homeassistant'])

View File

@ -200,14 +200,13 @@ class HomeAssistantHTTP:
if is_ban_enabled:
setup_bans(hass, app, login_threshold)
if hass.auth.active and hass.auth.support_legacy:
if hass.auth.support_legacy:
_LOGGER.warning(
"legacy_api_password support has been enabled. If you don't "
"require it, remove the 'api_password' from your http config.")
setup_auth(app, trusted_networks, hass.auth.active,
support_legacy=hass.auth.support_legacy,
api_password=api_password)
setup_auth(app, trusted_networks,
api_password if hass.auth.support_legacy else None)
setup_cors(app, cors_origins)

View File

@ -41,29 +41,26 @@ def async_sign_path(hass, refresh_token_id, path, expiration):
@callback
def setup_auth(app, trusted_networks, use_auth,
support_legacy=False, api_password=None):
def setup_auth(app, trusted_networks, api_password):
"""Create auth middleware for the app."""
old_auth_warning = set()
legacy_auth = (not use_auth or support_legacy) and api_password
@middleware
async def auth_middleware(request, handler):
"""Authenticate as middleware."""
authenticated = False
if use_auth and (HTTP_HEADER_HA_AUTH in request.headers or
DATA_API_PASSWORD in request.query):
if (HTTP_HEADER_HA_AUTH in request.headers or
DATA_API_PASSWORD in request.query):
if request.path not in old_auth_warning:
_LOGGER.log(
logging.INFO if support_legacy else logging.WARNING,
logging.INFO if api_password else logging.WARNING,
'You need to use a bearer token to access %s from %s',
request.path, request[KEY_REAL_IP])
old_auth_warning.add(request.path)
if (hdrs.AUTHORIZATION in request.headers and
await async_validate_auth_header(
request, api_password if legacy_auth else None)):
await async_validate_auth_header(request, api_password)):
# it included both use_auth and api_password Basic auth
authenticated = True
@ -73,7 +70,7 @@ def setup_auth(app, trusted_networks, use_auth,
await async_validate_signed_request(request)):
authenticated = True
elif (legacy_auth and HTTP_HEADER_HA_AUTH in request.headers and
elif (api_password and HTTP_HEADER_HA_AUTH in request.headers and
hmac.compare_digest(
api_password.encode('utf-8'),
request.headers[HTTP_HEADER_HA_AUTH].encode('utf-8'))):
@ -82,7 +79,7 @@ def setup_auth(app, trusted_networks, use_auth,
request['hass_user'] = await legacy_api_password.async_get_user(
app['hass'])
elif (legacy_auth and DATA_API_PASSWORD in request.query and
elif (api_password and DATA_API_PASSWORD in request.query and
hmac.compare_digest(
api_password.encode('utf-8'),
request.query[DATA_API_PASSWORD].encode('utf-8'))):
@ -98,11 +95,6 @@ def setup_auth(app, trusted_networks, use_auth,
break
authenticated = True
elif not use_auth and api_password is None:
# If neither password nor auth_providers set,
# just always set authenticated=True
authenticated = True
request[KEY_AUTHENTICATED] = authenticated
return await handler(request)

View File

@ -242,7 +242,7 @@ class HTML5PushCallbackView(HomeAssistantView):
# 2b. If decode is unsuccessful, return a 401.
target_check = jwt.decode(token, verify=False)
if target_check[ATTR_TARGET] in self.registrations:
if target_check.get(ATTR_TARGET) in self.registrations:
possible_target = self.registrations[target_check[ATTR_TARGET]]
key = possible_target[ATTR_SUBSCRIPTION][ATTR_KEYS][ATTR_AUTH]
try:

View File

@ -14,10 +14,6 @@ STORAGE_VERSION = 1
@callback
def async_is_onboarded(hass):
"""Return if Home Assistant has been onboarded."""
# Temporarily: if auth not active, always set onboarded=True
if not hass.auth.active:
return True
return hass.data.get(DOMAIN, True)

View File

@ -69,7 +69,7 @@ class AuthPhase:
self._send_message(auth_invalid_message(error_msg))
raise Disconnect
if self._hass.auth.active and 'access_token' in msg:
if 'access_token' in msg:
self._logger.debug("Received access_token")
refresh_token = \
await self._hass.auth.async_validate_access_token(
@ -78,8 +78,7 @@ class AuthPhase:
return await self._async_finish_auth(
refresh_token.user, refresh_token)
elif ((not self._hass.auth.active or self._hass.auth.support_legacy)
and 'api_password' in msg):
elif self._hass.auth.support_legacy and 'api_password' in msg:
self._logger.debug("Received api_password")
if validate_password(self._request, msg['api_password']):
return await self._async_finish_auth(None, None)

View File

@ -21,7 +21,7 @@ NPR_NEWS_MP3_URL = "https://pd.npr.org/anon.npr-mp3/npr/news/newscast.mp3"
@pytest.fixture
def alexa_client(loop, hass, aiohttp_client):
def alexa_client(loop, hass, hass_client):
"""Initialize a Home Assistant server for testing this module."""
@callback
def mock_service(call):
@ -49,7 +49,7 @@ def alexa_client(loop, hass, aiohttp_client):
},
}
}))
return loop.run_until_complete(aiohttp_client(hass.http.app))
return loop.run_until_complete(hass_client())
def _flash_briefing_req(client, briefing_id):

View File

@ -114,8 +114,7 @@ async def test_ws_current_user(hass, hass_ws_client, hass_access_token):
user.credentials.append(credential)
assert len(user.credentials) == 1
with patch('homeassistant.auth.AuthManager.active', return_value=True):
client = await hass_ws_client(hass, hass_access_token)
client = await hass_ws_client(hass, hass_access_token)
await client.send_json({
'id': 5,

View File

@ -5,11 +5,11 @@ from homeassistant.bootstrap import async_setup_component
import homeassistant.util.dt as dt_util
async def test_events_http_api(hass, aiohttp_client):
async def test_events_http_api(hass, hass_client):
"""Test the calendar demo view."""
await async_setup_component(hass, 'calendar',
{'calendar': {'platform': 'demo'}})
client = await aiohttp_client(hass.http.app)
client = await hass_client()
response = await client.get(
'/api/calendars/calendar.calendar_2')
assert response.status == 400
@ -24,11 +24,11 @@ async def test_events_http_api(hass, aiohttp_client):
assert events[0]['title'] == 'Future Event'
async def test_calendars_http_api(hass, aiohttp_client):
async def test_calendars_http_api(hass, hass_client):
"""Test the calendar demo view."""
await async_setup_component(hass, 'calendar',
{'calendar': {'platform': 'demo'}})
client = await aiohttp_client(hass.http.app)
client = await hass_client()
response = await client.get('/api/calendars')
assert response.status == 200
data = await response.json()

View File

@ -7,7 +7,7 @@ from homeassistant.setup import async_setup_component
@asyncio.coroutine
def test_fetching_url(aioclient_mock, hass, aiohttp_client):
def test_fetching_url(aioclient_mock, hass, hass_client):
"""Test that it fetches the given url."""
aioclient_mock.get('http://example.com', text='hello world')
@ -20,7 +20,7 @@ def test_fetching_url(aioclient_mock, hass, aiohttp_client):
'password': 'pass'
}})
client = yield from aiohttp_client(hass.http.app)
client = yield from hass_client()
resp = yield from client.get('/api/camera_proxy/camera.config_test')
@ -34,7 +34,7 @@ def test_fetching_url(aioclient_mock, hass, aiohttp_client):
@asyncio.coroutine
def test_fetching_without_verify_ssl(aioclient_mock, hass, aiohttp_client):
def test_fetching_without_verify_ssl(aioclient_mock, hass, hass_client):
"""Test that it fetches the given url when ssl verify is off."""
aioclient_mock.get('https://example.com', text='hello world')
@ -48,7 +48,7 @@ def test_fetching_without_verify_ssl(aioclient_mock, hass, aiohttp_client):
'verify_ssl': 'false',
}})
client = yield from aiohttp_client(hass.http.app)
client = yield from hass_client()
resp = yield from client.get('/api/camera_proxy/camera.config_test')
@ -56,7 +56,7 @@ def test_fetching_without_verify_ssl(aioclient_mock, hass, aiohttp_client):
@asyncio.coroutine
def test_fetching_url_with_verify_ssl(aioclient_mock, hass, aiohttp_client):
def test_fetching_url_with_verify_ssl(aioclient_mock, hass, hass_client):
"""Test that it fetches the given url when ssl verify is explicitly on."""
aioclient_mock.get('https://example.com', text='hello world')
@ -70,7 +70,7 @@ def test_fetching_url_with_verify_ssl(aioclient_mock, hass, aiohttp_client):
'verify_ssl': 'true',
}})
client = yield from aiohttp_client(hass.http.app)
client = yield from hass_client()
resp = yield from client.get('/api/camera_proxy/camera.config_test')
@ -78,7 +78,7 @@ def test_fetching_url_with_verify_ssl(aioclient_mock, hass, aiohttp_client):
@asyncio.coroutine
def test_limit_refetch(aioclient_mock, hass, aiohttp_client):
def test_limit_refetch(aioclient_mock, hass, hass_client):
"""Test that it fetches the given url."""
aioclient_mock.get('http://example.com/5a', text='hello world')
aioclient_mock.get('http://example.com/10a', text='hello world')
@ -94,7 +94,7 @@ def test_limit_refetch(aioclient_mock, hass, aiohttp_client):
'limit_refetch_to_url_change': True,
}})
client = yield from aiohttp_client(hass.http.app)
client = yield from hass_client()
resp = yield from client.get('/api/camera_proxy/camera.config_test')
@ -139,7 +139,7 @@ def test_limit_refetch(aioclient_mock, hass, aiohttp_client):
@asyncio.coroutine
def test_camera_content_type(aioclient_mock, hass, aiohttp_client):
def test_camera_content_type(aioclient_mock, hass, hass_client):
"""Test generic camera with custom content_type."""
svg_image = '<some image>'
urlsvg = 'https://upload.wikimedia.org/wikipedia/commons/0/02/SVG_logo.svg'
@ -158,7 +158,7 @@ def test_camera_content_type(aioclient_mock, hass, aiohttp_client):
yield from async_setup_component(hass, 'camera', {
'camera': [cam_config_svg, cam_config_normal]})
client = yield from aiohttp_client(hass.http.app)
client = yield from hass_client()
resp_1 = yield from client.get('/api/camera_proxy/camera.config_test_svg')
assert aioclient_mock.call_count == 1

View File

@ -11,7 +11,7 @@ from tests.common import mock_registry
@asyncio.coroutine
def test_loading_file(hass, aiohttp_client):
def test_loading_file(hass, hass_client):
"""Test that it loads image from disk."""
mock_registry(hass)
@ -24,7 +24,7 @@ def test_loading_file(hass, aiohttp_client):
'file_path': 'mock.file',
}})
client = yield from aiohttp_client(hass.http.app)
client = yield from hass_client()
m_open = mock.mock_open(read_data=b'hello')
with mock.patch(
@ -56,7 +56,7 @@ def test_file_not_readable(hass, caplog):
@asyncio.coroutine
def test_camera_content_type(hass, aiohttp_client):
def test_camera_content_type(hass, hass_client):
"""Test local_file camera content_type."""
cam_config_jpg = {
'name': 'test_jpg',
@ -83,7 +83,7 @@ def test_camera_content_type(hass, aiohttp_client):
'camera': [cam_config_jpg, cam_config_png,
cam_config_svg, cam_config_noext]})
client = yield from aiohttp_client(hass.http.app)
client = yield from hass_client()
image = 'hello'
m_open = mock.mock_open(read_data=image.encode())

View File

@ -52,10 +52,10 @@ def setup_api(hass):
@pytest.fixture
def cloud_client(hass, aiohttp_client):
def cloud_client(hass, hass_client):
"""Fixture that can fetch from the cloud client."""
with patch('homeassistant.components.cloud.Cloud.write_user_info'):
yield hass.loop.run_until_complete(aiohttp_client(hass.http.app))
yield hass.loop.run_until_complete(hass_client())
@pytest.fixture

View File

@ -1,6 +1,4 @@
"""Test config entries API."""
from unittest.mock import PropertyMock, patch
import pytest
from homeassistant.auth import models as auth_models
@ -9,14 +7,6 @@ from homeassistant.components.config import auth as auth_config
from tests.common import MockGroup, MockUser, CLIENT_ID
@pytest.fixture(autouse=True)
def auth_active(hass):
"""Mock that auth is active."""
with patch('homeassistant.auth.AuthManager.active',
PropertyMock(return_value=True)):
yield
@pytest.fixture(autouse=True)
def setup_config(hass, aiohttp_client):
"""Fixture that sets up the auth provider homeassistant module."""
@ -37,7 +27,7 @@ async def test_list_requires_owner(hass, hass_ws_client, hass_access_token):
assert result['error']['code'] == 'unauthorized'
async def test_list(hass, hass_ws_client):
async def test_list(hass, hass_ws_client, hass_admin_user):
"""Test get users."""
group = MockGroup().add_to_hass(hass)
@ -80,8 +70,17 @@ async def test_list(hass, hass_ws_client):
result = await client.receive_json()
assert result['success'], result
data = result['result']
assert len(data) == 3
assert len(data) == 4
assert data[0] == {
'id': hass_admin_user.id,
'name': 'Mock User',
'is_owner': False,
'is_active': True,
'system_generated': False,
'group_ids': [group.id for group in hass_admin_user.groups],
'credentials': []
}
assert data[1] == {
'id': owner.id,
'name': 'Test Owner',
'is_owner': True,
@ -90,7 +89,7 @@ async def test_list(hass, hass_ws_client):
'group_ids': [group.id for group in owner.groups],
'credentials': [{'type': 'homeassistant'}]
}
assert data[1] == {
assert data[2] == {
'id': system.id,
'name': 'Test Hass.io',
'is_owner': False,
@ -99,7 +98,7 @@ async def test_list(hass, hass_ws_client):
'group_ids': [],
'credentials': [],
}
assert data[2] == {
assert data[3] == {
'id': inactive.id,
'name': 'Inactive User',
'is_owner': False,

View File

@ -6,12 +6,12 @@ from homeassistant.bootstrap import async_setup_component
from homeassistant.components import config
async def test_get_device_config(hass, aiohttp_client):
async def test_get_device_config(hass, hass_client):
"""Test getting device config."""
with patch.object(config, 'SECTIONS', ['automation']):
await async_setup_component(hass, 'config', {})
client = await aiohttp_client(hass.http.app)
client = await hass_client()
def mock_read(path):
"""Mock reading data."""
@ -34,12 +34,12 @@ async def test_get_device_config(hass, aiohttp_client):
assert result == {'id': 'moon'}
async def test_update_device_config(hass, aiohttp_client):
async def test_update_device_config(hass, hass_client):
"""Test updating device config."""
with patch.object(config, 'SECTIONS', ['automation']):
await async_setup_component(hass, 'config', {})
client = await aiohttp_client(hass.http.app)
client = await hass_client()
orig_data = [
{
@ -83,12 +83,12 @@ async def test_update_device_config(hass, aiohttp_client):
assert written[0] == orig_data
async def test_bad_formatted_automations(hass, aiohttp_client):
async def test_bad_formatted_automations(hass, hass_client):
"""Test that we handle automations without ID."""
with patch.object(config, 'SECTIONS', ['automation']):
await async_setup_component(hass, 'config', {})
client = await aiohttp_client(hass.http.app)
client = await hass_client()
orig_data = [
{

View File

@ -23,11 +23,11 @@ def mock_test_component(hass):
@pytest.fixture
def client(hass, aiohttp_client):
def client(hass, hass_client):
"""Fixture that can interact with the config manager API."""
hass.loop.run_until_complete(async_setup_component(hass, 'http', {}))
hass.loop.run_until_complete(config_entries.async_setup(hass))
yield hass.loop.run_until_complete(aiohttp_client(hass.http.app))
yield hass.loop.run_until_complete(hass_client())
@asyncio.coroutine

View File

@ -8,14 +8,14 @@ from tests.common import mock_coro
@asyncio.coroutine
def test_validate_config_ok(hass, aiohttp_client):
def test_validate_config_ok(hass, hass_client):
"""Test checking config."""
with patch.object(config, 'SECTIONS', ['core']):
yield from async_setup_component(hass, 'config', {})
yield from asyncio.sleep(0.1, loop=hass.loop)
client = yield from aiohttp_client(hass.http.app)
client = yield from hass_client()
with patch(
'homeassistant.components.config.core.async_check_ha_config_file',

View File

@ -9,12 +9,12 @@ from homeassistant.config import DATA_CUSTOMIZE
@asyncio.coroutine
def test_get_entity(hass, aiohttp_client):
def test_get_entity(hass, hass_client):
"""Test getting entity."""
with patch.object(config, 'SECTIONS', ['customize']):
yield from async_setup_component(hass, 'config', {})
client = yield from aiohttp_client(hass.http.app)
client = yield from hass_client()
def mock_read(path):
"""Mock reading data."""
@ -38,12 +38,12 @@ def test_get_entity(hass, aiohttp_client):
@asyncio.coroutine
def test_update_entity(hass, aiohttp_client):
def test_update_entity(hass, hass_client):
"""Test updating entity."""
with patch.object(config, 'SECTIONS', ['customize']):
yield from async_setup_component(hass, 'config', {})
client = yield from aiohttp_client(hass.http.app)
client = yield from hass_client()
orig_data = {
'hello.beer': {
@ -89,12 +89,12 @@ def test_update_entity(hass, aiohttp_client):
@asyncio.coroutine
def test_update_entity_invalid_key(hass, aiohttp_client):
def test_update_entity_invalid_key(hass, hass_client):
"""Test updating entity."""
with patch.object(config, 'SECTIONS', ['customize']):
yield from async_setup_component(hass, 'config', {})
client = yield from aiohttp_client(hass.http.app)
client = yield from hass_client()
resp = yield from client.post(
'/api/config/customize/config/not_entity', data=json.dumps({
@ -105,12 +105,12 @@ def test_update_entity_invalid_key(hass, aiohttp_client):
@asyncio.coroutine
def test_update_entity_invalid_json(hass, aiohttp_client):
def test_update_entity_invalid_json(hass, hass_client):
"""Test updating entity."""
with patch.object(config, 'SECTIONS', ['customize']):
yield from async_setup_component(hass, 'config', {})
client = yield from aiohttp_client(hass.http.app)
client = yield from hass_client()
resp = yield from client.post(
'/api/config/customize/config/hello.beer', data='not json')

View File

@ -11,12 +11,12 @@ VIEW_NAME = 'api:config:group:config'
@asyncio.coroutine
def test_get_device_config(hass, aiohttp_client):
def test_get_device_config(hass, hass_client):
"""Test getting device config."""
with patch.object(config, 'SECTIONS', ['group']):
yield from async_setup_component(hass, 'config', {})
client = yield from aiohttp_client(hass.http.app)
client = yield from hass_client()
def mock_read(path):
"""Mock reading data."""
@ -40,12 +40,12 @@ def test_get_device_config(hass, aiohttp_client):
@asyncio.coroutine
def test_update_device_config(hass, aiohttp_client):
def test_update_device_config(hass, hass_client):
"""Test updating device config."""
with patch.object(config, 'SECTIONS', ['group']):
yield from async_setup_component(hass, 'config', {})
client = yield from aiohttp_client(hass.http.app)
client = yield from hass_client()
orig_data = {
'hello.beer': {
@ -89,12 +89,12 @@ def test_update_device_config(hass, aiohttp_client):
@asyncio.coroutine
def test_update_device_config_invalid_key(hass, aiohttp_client):
def test_update_device_config_invalid_key(hass, hass_client):
"""Test updating device config."""
with patch.object(config, 'SECTIONS', ['group']):
yield from async_setup_component(hass, 'config', {})
client = yield from aiohttp_client(hass.http.app)
client = yield from hass_client()
resp = yield from client.post(
'/api/config/group/config/not a slug', data=json.dumps({
@ -105,12 +105,12 @@ def test_update_device_config_invalid_key(hass, aiohttp_client):
@asyncio.coroutine
def test_update_device_config_invalid_data(hass, aiohttp_client):
def test_update_device_config_invalid_data(hass, hass_client):
"""Test updating device config."""
with patch.object(config, 'SECTIONS', ['group']):
yield from async_setup_component(hass, 'config', {})
client = yield from aiohttp_client(hass.http.app)
client = yield from hass_client()
resp = yield from client.post(
'/api/config/group/config/hello_beer', data=json.dumps({
@ -121,12 +121,12 @@ def test_update_device_config_invalid_data(hass, aiohttp_client):
@asyncio.coroutine
def test_update_device_config_invalid_json(hass, aiohttp_client):
def test_update_device_config_invalid_json(hass, hass_client):
"""Test updating device config."""
with patch.object(config, 'SECTIONS', ['group']):
yield from async_setup_component(hass, 'config', {})
client = yield from aiohttp_client(hass.http.app)
client = yield from hass_client()
resp = yield from client.post(
'/api/config/group/config/hello_beer', data='not json')

View File

@ -34,13 +34,13 @@ def test_setup_check_env_works(hass, loop):
@asyncio.coroutine
def test_get_suites(hass, aiohttp_client):
def test_get_suites(hass, hass_client):
"""Test getting suites."""
with patch.dict(os.environ, {'FORCE_HASSBIAN': '1'}), \
patch.object(config, 'SECTIONS', ['hassbian']):
yield from async_setup_component(hass, 'config', {})
client = yield from aiohttp_client(hass.http.app)
client = yield from hass_client()
resp = yield from client.get('/api/config/hassbian/suites')
assert resp.status == 200
result = yield from resp.json()
@ -53,13 +53,13 @@ def test_get_suites(hass, aiohttp_client):
@asyncio.coroutine
def test_install_suite(hass, aiohttp_client):
def test_install_suite(hass, hass_client):
"""Test getting suites."""
with patch.dict(os.environ, {'FORCE_HASSBIAN': '1'}), \
patch.object(config, 'SECTIONS', ['hassbian']):
yield from async_setup_component(hass, 'config', {})
client = yield from aiohttp_client(hass.http.app)
client = yield from hass_client()
resp = yield from client.post(
'/api/config/hassbian/suites/openzwave/install')
assert resp.status == 200

View File

@ -16,12 +16,12 @@ VIEW_NAME = 'api:config:zwave:device_config'
@pytest.fixture
def client(loop, hass, aiohttp_client):
def client(loop, hass, hass_client):
"""Client to communicate with Z-Wave config views."""
with patch.object(config, 'SECTIONS', ['zwave']):
loop.run_until_complete(async_setup_component(hass, 'config', {}))
return loop.run_until_complete(aiohttp_client(hass.http.app))
return loop.run_until_complete(hass_client())
@asyncio.coroutine

View File

@ -3,14 +3,12 @@ from unittest.mock import patch
import pytest
from homeassistant.auth.const import GROUP_ID_ADMIN, GROUP_ID_READ_ONLY
from homeassistant.auth.providers import legacy_api_password, homeassistant
from homeassistant.setup import async_setup_component
from homeassistant.components.websocket_api.http import URL
from homeassistant.components.websocket_api.auth import (
TYPE_AUTH, TYPE_AUTH_OK, TYPE_AUTH_REQUIRED)
from tests.common import MockUser, CLIENT_ID, mock_coro
from tests.common import mock_coro
@pytest.fixture(autouse=True)
@ -22,35 +20,15 @@ def prevent_io():
@pytest.fixture
def hass_ws_client(aiohttp_client):
def hass_ws_client(aiohttp_client, hass_access_token):
"""Websocket client fixture connected to websocket server."""
async def create_client(hass, access_token=None):
async def create_client(hass, access_token=hass_access_token):
"""Create a websocket client."""
assert await async_setup_component(hass, 'websocket_api')
client = await aiohttp_client(hass.http.app)
patches = []
if access_token is None:
patches.append(patch(
'homeassistant.auth.AuthManager.active', return_value=False))
patches.append(patch(
'homeassistant.auth.AuthManager.support_legacy',
return_value=True))
patches.append(patch(
'homeassistant.components.websocket_api.auth.'
'validate_password', return_value=True))
else:
patches.append(patch(
'homeassistant.auth.AuthManager.active', return_value=True))
patches.append(patch(
'homeassistant.components.http.auth.setup_auth'))
for p in patches:
p.start()
try:
with patch('homeassistant.components.http.auth.setup_auth'):
websocket = await client.ws_connect(URL)
auth_resp = await websocket.receive_json()
assert auth_resp['type'] == TYPE_AUTH_REQUIRED
@ -69,76 +47,8 @@ def hass_ws_client(aiohttp_client):
auth_ok = await websocket.receive_json()
assert auth_ok['type'] == TYPE_AUTH_OK
finally:
for p in patches:
p.stop()
# wrap in client
websocket.client = client
return websocket
return create_client
@pytest.fixture
def hass_access_token(hass, hass_admin_user):
"""Return an access token to access Home Assistant."""
refresh_token = hass.loop.run_until_complete(
hass.auth.async_create_refresh_token(hass_admin_user, CLIENT_ID))
yield hass.auth.async_create_access_token(refresh_token)
@pytest.fixture
def hass_owner_user(hass, local_auth):
"""Return a Home Assistant admin user."""
return MockUser(is_owner=True).add_to_hass(hass)
@pytest.fixture
def hass_admin_user(hass, local_auth):
"""Return a Home Assistant admin user."""
admin_group = hass.loop.run_until_complete(hass.auth.async_get_group(
GROUP_ID_ADMIN))
return MockUser(groups=[admin_group]).add_to_hass(hass)
@pytest.fixture
def hass_read_only_user(hass, local_auth):
"""Return a Home Assistant read only user."""
read_only_group = hass.loop.run_until_complete(hass.auth.async_get_group(
GROUP_ID_READ_ONLY))
return MockUser(groups=[read_only_group]).add_to_hass(hass)
@pytest.fixture
def legacy_auth(hass):
"""Load legacy API password provider."""
prv = legacy_api_password.LegacyApiPasswordAuthProvider(
hass, hass.auth._store, {
'type': 'legacy_api_password'
}
)
hass.auth._providers[(prv.type, prv.id)] = prv
@pytest.fixture
def local_auth(hass):
"""Load local auth provider."""
prv = homeassistant.HassAuthProvider(
hass, hass.auth._store, {
'type': 'homeassistant'
}
)
hass.auth._providers[(prv.type, prv.id)] = prv
@pytest.fixture
def hass_client(hass, aiohttp_client, hass_access_token):
"""Return an authenticated HTTP client."""
async def auth_client():
"""Return an authenticated client."""
return await aiohttp_client(hass.http.app, headers={
'Authorization': "Bearer {}".format(hass_access_token)
})
return auth_client

View File

@ -19,7 +19,7 @@ def _url(data=None):
@pytest.fixture
def locative_client(loop, hass, aiohttp_client):
def locative_client(loop, hass, hass_client):
"""Locative mock client."""
assert loop.run_until_complete(async_setup_component(
hass, device_tracker.DOMAIN, {
@ -29,7 +29,7 @@ def locative_client(loop, hass, aiohttp_client):
}))
with patch('homeassistant.components.device_tracker.update_config'):
yield loop.run_until_complete(aiohttp_client(hass.http.app))
yield loop.run_until_complete(hass_client())
@asyncio.coroutine

View File

@ -13,7 +13,7 @@ from homeassistant.components.device_tracker.meraki import URL
@pytest.fixture
def meraki_client(loop, hass, aiohttp_client):
def meraki_client(loop, hass, hass_client):
"""Meraki mock client."""
assert loop.run_until_complete(async_setup_component(
hass, device_tracker.DOMAIN, {
@ -25,7 +25,7 @@ def meraki_client(loop, hass, aiohttp_client):
}
}))
yield loop.run_until_complete(aiohttp_client(hass.http.app))
yield loop.run_until_complete(hass_client())
@asyncio.coroutine

View File

@ -59,8 +59,16 @@ def mock_http_client_with_urls(hass, aiohttp_client):
return hass.loop.run_until_complete(aiohttp_client(hass.http.app))
@pytest.fixture
def mock_onboarded():
"""Mock that we're onboarded."""
with patch('homeassistant.components.onboarding.async_is_onboarded',
return_value=True):
yield
@asyncio.coroutine
def test_frontend_and_static(mock_http_client):
def test_frontend_and_static(mock_http_client, mock_onboarded):
"""Test if we can get the frontend."""
resp = yield from mock_http_client.get('')
assert resp.status == 200
@ -220,7 +228,7 @@ async def test_missing_themes(hass, hass_ws_client):
@asyncio.coroutine
def test_extra_urls(mock_http_client_with_urls):
def test_extra_urls(mock_http_client_with_urls, mock_onboarded):
"""Test that extra urls are loaded."""
resp = yield from mock_http_client_with_urls.get('/states?latest')
assert resp.status == 200
@ -229,7 +237,7 @@ def test_extra_urls(mock_http_client_with_urls):
@asyncio.coroutine
def test_extra_urls_es5(mock_http_client_with_urls):
def test_extra_urls_es5(mock_http_client_with_urls, mock_onboarded):
"""Test that es5 extra urls are loaded."""
resp = yield from mock_http_client_with_urls.get('/states?es5')
assert resp.status == 200
@ -280,7 +288,7 @@ async def test_get_translations(hass, hass_ws_client):
assert msg['result'] == {'resources': {'lang': 'nl'}}
async def test_auth_load(mock_http_client):
async def test_auth_load(mock_http_client, mock_onboarded):
"""Test auth component loaded by default."""
resp = await mock_http_client.get('/auth/providers')
assert resp.status == 200

View File

@ -105,7 +105,7 @@ BEACON_EXIT_CAR = {
@pytest.fixture
def geofency_client(loop, hass, aiohttp_client):
def geofency_client(loop, hass, hass_client):
"""Geofency mock client."""
assert loop.run_until_complete(async_setup_component(
hass, DOMAIN, {
@ -116,7 +116,7 @@ def geofency_client(loop, hass, aiohttp_client):
loop.run_until_complete(hass.async_block_till_done())
with patch('homeassistant.components.device_tracker.update_config'):
yield loop.run_until_complete(aiohttp_client(hass.http.app))
yield loop.run_until_complete(hass_client())
@pytest.fixture(autouse=True)

View File

@ -89,8 +89,7 @@ def test_setup_api_push_api_data_server_host(hass, aioclient_mock):
async def test_setup_api_push_api_data_default(hass, aioclient_mock,
hass_storage):
"""Test setup with API push default data."""
with patch.dict(os.environ, MOCK_ENVIRON), \
patch('homeassistant.auth.AuthManager.active', return_value=True):
with patch.dict(os.environ, MOCK_ENVIRON):
result = await async_setup_component(hass, 'hassio', {
'http': {},
'hassio': {}
@ -130,20 +129,6 @@ async def test_setup_adds_admin_group_to_user(hass, aioclient_mock,
'version': 1
}
with patch.dict(os.environ, MOCK_ENVIRON), \
patch('homeassistant.auth.AuthManager.active', return_value=True):
result = await async_setup_component(hass, 'hassio', {
'http': {},
'hassio': {}
})
assert result
assert user.is_admin
async def test_setup_api_push_api_data_no_auth(hass, aioclient_mock,
hass_storage):
"""Test setup with API push default data."""
with patch.dict(os.environ, MOCK_ENVIRON):
result = await async_setup_component(hass, 'hassio', {
'http': {},
@ -151,11 +136,7 @@ async def test_setup_api_push_api_data_no_auth(hass, aioclient_mock,
})
assert result
assert aioclient_mock.call_count == 3
assert not aioclient_mock.mock_calls[1][2]['ssl']
assert aioclient_mock.mock_calls[1][2]['password'] is None
assert aioclient_mock.mock_calls[1][2]['port'] == 8123
assert aioclient_mock.mock_calls[1][2]['refresh_token'] is None
assert user.is_admin
async def test_setup_api_existing_hassio_user(hass, aioclient_mock,
@ -169,8 +150,7 @@ async def test_setup_api_existing_hassio_user(hass, aioclient_mock,
'hassio_user': user.id
}
}
with patch.dict(os.environ, MOCK_ENVIRON), \
patch('homeassistant.auth.AuthManager.active', return_value=True):
with patch.dict(os.environ, MOCK_ENVIRON):
result = await async_setup_component(hass, 'hassio', {
'http': {},
'hassio': {}

View File

@ -75,19 +75,10 @@ async def test_auth_middleware_loaded_by_default(hass):
assert len(mock_setup.mock_calls) == 1
async def test_access_without_password(app, aiohttp_client):
"""Test access without password."""
setup_auth(app, [], False, api_password=None)
client = await aiohttp_client(app)
resp = await client.get('/')
assert resp.status == 200
async def test_access_with_password_in_header(app, aiohttp_client,
legacy_auth, hass):
"""Test access with password in header."""
setup_auth(app, [], False, api_password=API_PASSWORD)
setup_auth(app, [], api_password=API_PASSWORD)
client = await aiohttp_client(app)
user = await legacy_api_password.async_get_user(hass)
@ -107,7 +98,7 @@ async def test_access_with_password_in_header(app, aiohttp_client,
async def test_access_with_password_in_query(app, aiohttp_client, legacy_auth,
hass):
"""Test access with password in URL."""
setup_auth(app, [], False, api_password=API_PASSWORD)
setup_auth(app, [], api_password=API_PASSWORD)
client = await aiohttp_client(app)
user = await legacy_api_password.async_get_user(hass)
@ -131,7 +122,7 @@ async def test_access_with_password_in_query(app, aiohttp_client, legacy_auth,
async def test_basic_auth_works(app, aiohttp_client, hass, legacy_auth):
"""Test access with basic authentication."""
setup_auth(app, [], False, api_password=API_PASSWORD)
setup_auth(app, [], api_password=API_PASSWORD)
client = await aiohttp_client(app)
user = await legacy_api_password.async_get_user(hass)
@ -164,7 +155,7 @@ async def test_basic_auth_works(app, aiohttp_client, hass, legacy_auth):
async def test_access_with_trusted_ip(app2, aiohttp_client, hass_owner_user):
"""Test access with an untrusted ip address."""
setup_auth(app2, TRUSTED_NETWORKS, False, api_password='some-pass')
setup_auth(app2, TRUSTED_NETWORKS, api_password='some-pass')
set_mock_ip = mock_real_ip(app2)
client = await aiohttp_client(app2)
@ -190,7 +181,7 @@ async def test_auth_active_access_with_access_token_in_header(
hass, app, aiohttp_client, hass_access_token):
"""Test access with access token in header."""
token = hass_access_token
setup_auth(app, [], True, api_password=None)
setup_auth(app, [], api_password=None)
client = await aiohttp_client(app)
refresh_token = await hass.auth.async_validate_access_token(
hass_access_token)
@ -238,7 +229,7 @@ async def test_auth_active_access_with_access_token_in_header(
async def test_auth_active_access_with_trusted_ip(app2, aiohttp_client,
hass_owner_user):
"""Test access with an untrusted ip address."""
setup_auth(app2, TRUSTED_NETWORKS, True, api_password=None)
setup_auth(app2, TRUSTED_NETWORKS, None)
set_mock_ip = mock_real_ip(app2)
client = await aiohttp_client(app2)
@ -260,31 +251,10 @@ async def test_auth_active_access_with_trusted_ip(app2, aiohttp_client,
}
async def test_auth_active_blocked_api_password_access(
app, aiohttp_client, legacy_auth):
"""Test access using api_password should be blocked when auth.active."""
setup_auth(app, [], True, api_password=API_PASSWORD)
client = await aiohttp_client(app)
req = await client.get(
'/', headers={HTTP_HEADER_HA_AUTH: API_PASSWORD})
assert req.status == 401
resp = await client.get('/', params={
'api_password': API_PASSWORD
})
assert resp.status == 401
req = await client.get(
'/',
auth=BasicAuth('homeassistant', API_PASSWORD))
assert req.status == 401
async def test_auth_legacy_support_api_password_access(
app, aiohttp_client, legacy_auth, hass):
"""Test access using api_password if auth.support_legacy."""
setup_auth(app, [], True, support_legacy=True, api_password=API_PASSWORD)
setup_auth(app, [], API_PASSWORD)
client = await aiohttp_client(app)
user = await legacy_api_password.async_get_user(hass)
@ -320,7 +290,7 @@ async def test_auth_access_signed_path(
"""Test access with signed url."""
app.router.add_post('/', mock_handler)
app.router.add_get('/another_path', mock_handler)
setup_auth(app, [], True, api_password=None)
setup_auth(app, [], None)
client = await aiohttp_client(app)
refresh_token = await hass.auth.async_validate_access_token(

View File

@ -9,7 +9,7 @@ import homeassistant.components.mailbox as mailbox
@pytest.fixture
def mock_http_client(hass, aiohttp_client):
def mock_http_client(hass, hass_client):
"""Start the Hass HTTP component."""
config = {
mailbox.DOMAIN: {
@ -18,7 +18,7 @@ def mock_http_client(hass, aiohttp_client):
}
hass.loop.run_until_complete(
async_setup_component(hass, mailbox.DOMAIN, config))
return hass.loop.run_until_complete(aiohttp_client(hass.http.app))
return hass.loop.run_until_complete(hass_client())
@asyncio.coroutine

View File

@ -49,7 +49,7 @@ REGISTER_URL = '/api/notify.html5'
PUBLISH_URL = '/api/notify.html5/callback'
async def mock_client(hass, aiohttp_client, registrations=None):
async def mock_client(hass, hass_client, registrations=None):
"""Create a test client for HTML5 views."""
if registrations is None:
registrations = {}
@ -62,7 +62,7 @@ async def mock_client(hass, aiohttp_client, registrations=None):
}
})
return await aiohttp_client(hass.http.app)
return await hass_client()
class TestHtml5Notify:
@ -151,9 +151,9 @@ class TestHtml5Notify:
assert mock_wp.mock_calls[4][2]['gcm_key'] is None
async def test_registering_new_device_view(hass, aiohttp_client):
async def test_registering_new_device_view(hass, hass_client):
"""Test that the HTML view works."""
client = await mock_client(hass, aiohttp_client)
client = await mock_client(hass, hass_client)
with patch('homeassistant.components.notify.html5.save_json') as mock_save:
resp = await client.post(REGISTER_URL, data=json.dumps(SUBSCRIPTION_1))
@ -165,9 +165,9 @@ async def test_registering_new_device_view(hass, aiohttp_client):
}
async def test_registering_new_device_expiration_view(hass, aiohttp_client):
async def test_registering_new_device_expiration_view(hass, hass_client):
"""Test that the HTML view works."""
client = await mock_client(hass, aiohttp_client)
client = await mock_client(hass, hass_client)
with patch('homeassistant.components.notify.html5.save_json') as mock_save:
resp = await client.post(REGISTER_URL, data=json.dumps(SUBSCRIPTION_4))
@ -178,10 +178,10 @@ async def test_registering_new_device_expiration_view(hass, aiohttp_client):
}
async def test_registering_new_device_fails_view(hass, aiohttp_client):
async def test_registering_new_device_fails_view(hass, hass_client):
"""Test subs. are not altered when registering a new device fails."""
registrations = {}
client = await mock_client(hass, aiohttp_client, registrations)
client = await mock_client(hass, hass_client, registrations)
with patch('homeassistant.components.notify.html5.save_json',
side_effect=HomeAssistantError()):
@ -191,10 +191,10 @@ async def test_registering_new_device_fails_view(hass, aiohttp_client):
assert registrations == {}
async def test_registering_existing_device_view(hass, aiohttp_client):
async def test_registering_existing_device_view(hass, hass_client):
"""Test subscription is updated when registering existing device."""
registrations = {}
client = await mock_client(hass, aiohttp_client, registrations)
client = await mock_client(hass, hass_client, registrations)
with patch('homeassistant.components.notify.html5.save_json') as mock_save:
await client.post(REGISTER_URL, data=json.dumps(SUBSCRIPTION_1))
@ -209,10 +209,10 @@ async def test_registering_existing_device_view(hass, aiohttp_client):
}
async def test_registering_existing_device_fails_view(hass, aiohttp_client):
async def test_registering_existing_device_fails_view(hass, hass_client):
"""Test sub. is not updated when registering existing device fails."""
registrations = {}
client = await mock_client(hass, aiohttp_client, registrations)
client = await mock_client(hass, hass_client, registrations)
with patch('homeassistant.components.notify.html5.save_json') as mock_save:
await client.post(REGISTER_URL, data=json.dumps(SUBSCRIPTION_1))
@ -225,9 +225,9 @@ async def test_registering_existing_device_fails_view(hass, aiohttp_client):
}
async def test_registering_new_device_validation(hass, aiohttp_client):
async def test_registering_new_device_validation(hass, hass_client):
"""Test various errors when registering a new device."""
client = await mock_client(hass, aiohttp_client)
client = await mock_client(hass, hass_client)
resp = await client.post(REGISTER_URL, data=json.dumps({
'browser': 'invalid browser',
@ -249,13 +249,13 @@ async def test_registering_new_device_validation(hass, aiohttp_client):
assert resp.status == 400
async def test_unregistering_device_view(hass, aiohttp_client):
async def test_unregistering_device_view(hass, hass_client):
"""Test that the HTML unregister view works."""
registrations = {
'some device': SUBSCRIPTION_1,
'other device': SUBSCRIPTION_2,
}
client = await mock_client(hass, aiohttp_client, registrations)
client = await mock_client(hass, hass_client, registrations)
with patch('homeassistant.components.notify.html5.save_json') as mock_save:
resp = await client.delete(REGISTER_URL, data=json.dumps({
@ -270,10 +270,10 @@ async def test_unregistering_device_view(hass, aiohttp_client):
async def test_unregister_device_view_handle_unknown_subscription(
hass, aiohttp_client):
hass, hass_client):
"""Test that the HTML unregister view handles unknown subscriptions."""
registrations = {}
client = await mock_client(hass, aiohttp_client, registrations)
client = await mock_client(hass, hass_client, registrations)
with patch('homeassistant.components.notify.html5.save_json') as mock_save:
resp = await client.delete(REGISTER_URL, data=json.dumps({
@ -286,13 +286,13 @@ async def test_unregister_device_view_handle_unknown_subscription(
async def test_unregistering_device_view_handles_save_error(
hass, aiohttp_client):
hass, hass_client):
"""Test that the HTML unregister view handles save errors."""
registrations = {
'some device': SUBSCRIPTION_1,
'other device': SUBSCRIPTION_2,
}
client = await mock_client(hass, aiohttp_client, registrations)
client = await mock_client(hass, hass_client, registrations)
with patch('homeassistant.components.notify.html5.save_json',
side_effect=HomeAssistantError()):
@ -307,23 +307,23 @@ async def test_unregistering_device_view_handles_save_error(
}
async def test_callback_view_no_jwt(hass, aiohttp_client):
async def test_callback_view_no_jwt(hass, hass_client):
"""Test that the notification callback view works without JWT."""
client = await mock_client(hass, aiohttp_client)
client = await mock_client(hass, hass_client)
resp = await client.post(PUBLISH_URL, data=json.dumps({
'type': 'push',
'tag': '3bc28d69-0921-41f1-ac6a-7a627ba0aa72'
}))
assert resp.status == 401, resp.response
assert resp.status == 401
async def test_callback_view_with_jwt(hass, aiohttp_client):
async def test_callback_view_with_jwt(hass, hass_client):
"""Test that the notification callback view works with JWT."""
registrations = {
'device': SUBSCRIPTION_1
}
client = await mock_client(hass, aiohttp_client, registrations)
client = await mock_client(hass, hass_client, registrations)
with patch('pywebpush.WebPusher') as mock_wp:
await hass.services.async_call('notify', 'notify', {

View File

@ -38,8 +38,7 @@ async def test_setup_views_if_not_onboarded(hass):
assert len(mock_setup.mock_calls) == 1
assert onboarding.DOMAIN in hass.data
with patch('homeassistant.auth.AuthManager.active', return_value=True):
assert not onboarding.async_is_onboarded(hass)
assert not onboarding.async_is_onboarded(hass)
async def test_is_onboarded():
@ -47,17 +46,13 @@ async def test_is_onboarded():
hass = Mock()
hass.data = {}
with patch('homeassistant.auth.AuthManager.active', return_value=False):
assert onboarding.async_is_onboarded(hass)
assert onboarding.async_is_onboarded(hass)
with patch('homeassistant.auth.AuthManager.active', return_value=True):
assert onboarding.async_is_onboarded(hass)
hass.data[onboarding.DOMAIN] = True
assert onboarding.async_is_onboarded(hass)
hass.data[onboarding.DOMAIN] = True
assert onboarding.async_is_onboarded(hass)
hass.data[onboarding.DOMAIN] = False
assert not onboarding.async_is_onboarded(hass)
hass.data[onboarding.DOMAIN] = False
assert not onboarding.async_is_onboarded(hass)
async def test_having_owner_finishes_user_step(hass, hass_storage):

View File

@ -591,18 +591,18 @@ class TestComponentLogbook(unittest.TestCase):
}, time_fired=event_time_fired)
async def test_logbook_view(hass, aiohttp_client):
async def test_logbook_view(hass, hass_client):
"""Test the logbook view."""
await hass.async_add_job(init_recorder_component, hass)
await async_setup_component(hass, 'logbook', {})
await hass.async_add_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
client = await aiohttp_client(hass.http.app)
client = await hass_client()
response = await client.get(
'/api/logbook/{}'.format(dt_util.utcnow().isoformat()))
assert response.status == 200
async def test_logbook_view_period_entity(hass, aiohttp_client):
async def test_logbook_view_period_entity(hass, hass_client):
"""Test the logbook view with period and entity."""
await hass.async_add_job(init_recorder_component, hass)
await async_setup_component(hass, 'logbook', {})
@ -617,7 +617,7 @@ async def test_logbook_view_period_entity(hass, aiohttp_client):
await hass.async_block_till_done()
await hass.async_add_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
client = await aiohttp_client(hass.http.app)
client = await hass_client()
# Today time 00:00:00
start = dt_util.utcnow().date()

View File

@ -7,14 +7,14 @@ import homeassistant.components.prometheus as prometheus
@pytest.fixture
def prometheus_client(loop, hass, aiohttp_client):
"""Initialize an aiohttp_client with Prometheus component."""
def prometheus_client(loop, hass, hass_client):
"""Initialize an hass_client with Prometheus component."""
assert loop.run_until_complete(async_setup_component(
hass,
prometheus.DOMAIN,
{prometheus.DOMAIN: {}},
))
return loop.run_until_complete(aiohttp_client(hass.http.app))
return loop.run_until_complete(hass_client())
@asyncio.coroutine

View File

@ -8,7 +8,7 @@ from homeassistant.setup import async_setup_component
@pytest.fixture
def mock_http_client(loop, hass, aiohttp_client):
def mock_http_client(loop, hass, hass_client):
"""Set up test fixture."""
config = {
'rss_feed_template': {
@ -21,7 +21,7 @@ def mock_http_client(loop, hass, aiohttp_client):
loop.run_until_complete(async_setup_component(hass,
'rss_feed_template',
config))
return loop.run_until_complete(aiohttp_client(hass.http.app))
return loop.run_until_complete(hass_client())
@asyncio.coroutine

View File

@ -2,7 +2,6 @@
import ctypes
import os
import shutil
import json
from unittest.mock import patch, PropertyMock
import pytest
@ -14,7 +13,7 @@ from homeassistant.components.tts.demo import DemoProvider
from homeassistant.components.media_player import (
SERVICE_PLAY_MEDIA, MEDIA_TYPE_MUSIC, ATTR_MEDIA_CONTENT_ID,
ATTR_MEDIA_CONTENT_TYPE, DOMAIN as DOMAIN_MP)
from homeassistant.setup import setup_component
from homeassistant.setup import setup_component, async_setup_component
from tests.common import (
get_test_home_assistant, get_test_instance_port, assert_setup_component,
@ -584,45 +583,45 @@ class TestTTS:
assert req.status_code == 200
assert req.content == demo_data
def test_setup_component_and_web_get_url(self):
"""Set up the demo platform and receive wrong file from web."""
config = {
tts.DOMAIN: {
'platform': 'demo',
}
async def test_setup_component_and_web_get_url(hass, hass_client):
"""Set up the demo platform and receive file from web."""
config = {
tts.DOMAIN: {
'platform': 'demo',
}
}
with assert_setup_component(1, tts.DOMAIN):
setup_component(self.hass, tts.DOMAIN, config)
await async_setup_component(hass, tts.DOMAIN, config)
self.hass.start()
client = await hass_client()
url = ("{}/api/tts_get_url").format(self.hass.config.api.base_url)
data = {'platform': 'demo',
'message': "I person is on front of your door."}
url = "/api/tts_get_url"
data = {'platform': 'demo',
'message': "I person is on front of your door."}
req = requests.post(url, data=json.dumps(data))
assert req.status_code == 200
response = json.loads(req.text)
assert response.get('url') == (("{}/api/tts_proxy/265944c108cbb00b2a62"
"1be5930513e03a0bb2cd_en_-_demo.mp3")
.format(self.hass.config.api.base_url))
req = await client.post(url, json=data)
assert req.status == 200
response = await req.json()
assert response.get('url') == \
("{}/api/tts_proxy/265944c108cbb00b2a62"
"1be5930513e03a0bb2cd_en_-_demo.mp3".format(hass.config.api.base_url))
def test_setup_component_and_web_get_url_bad_config(self):
"""Set up the demo platform and receive wrong file from web."""
config = {
tts.DOMAIN: {
'platform': 'demo',
}
async def test_setup_component_and_web_get_url_bad_config(hass, hass_client):
"""Set up the demo platform and receive wrong file from web."""
config = {
tts.DOMAIN: {
'platform': 'demo',
}
}
with assert_setup_component(1, tts.DOMAIN):
setup_component(self.hass, tts.DOMAIN, config)
await async_setup_component(hass, tts.DOMAIN, config)
self.hass.start()
client = await hass_client()
url = ("{}/api/tts_get_url").format(self.hass.config.api.base_url)
data = {'message': "I person is on front of your door."}
url = "/api/tts_get_url"
data = {'message': "I person is on front of your door."}
req = requests.post(url, data=data)
assert req.status_code == 400
req = await client.post(url, json=data)
assert req.status == 400

View File

@ -13,7 +13,7 @@ from tests.common import mock_coro
from . import API_PASSWORD
async def test_auth_via_msg(no_auth_websocket_client):
async def test_auth_via_msg(no_auth_websocket_client, legacy_auth):
"""Test authenticating."""
await no_auth_websocket_client.send_json({
'type': TYPE_AUTH,
@ -70,18 +70,16 @@ async def test_auth_active_with_token(hass, aiohttp_client, hass_access_token):
client = await aiohttp_client(hass.http.app)
async with client.ws_connect(URL) as ws:
with patch('homeassistant.auth.AuthManager.active') as auth_active:
auth_active.return_value = True
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_REQUIRED
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_REQUIRED
await ws.send_json({
'type': TYPE_AUTH,
'access_token': hass_access_token
})
await ws.send_json({
'type': TYPE_AUTH,
'access_token': hass_access_token
})
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_OK
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_OK
async def test_auth_active_user_inactive(hass, aiohttp_client,
@ -99,18 +97,16 @@ async def test_auth_active_user_inactive(hass, aiohttp_client,
client = await aiohttp_client(hass.http.app)
async with client.ws_connect(URL) as ws:
with patch('homeassistant.auth.AuthManager.active') as auth_active:
auth_active.return_value = True
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_REQUIRED
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_REQUIRED
await ws.send_json({
'type': TYPE_AUTH,
'access_token': hass_access_token
})
await ws.send_json({
'type': TYPE_AUTH,
'access_token': hass_access_token
})
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_INVALID
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_INVALID
async def test_auth_active_with_password_not_allow(hass, aiohttp_client):
@ -124,18 +120,16 @@ async def test_auth_active_with_password_not_allow(hass, aiohttp_client):
client = await aiohttp_client(hass.http.app)
async with client.ws_connect(URL) as ws:
with patch('homeassistant.auth.AuthManager.active',
return_value=True):
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_REQUIRED
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_REQUIRED
await ws.send_json({
'type': TYPE_AUTH,
'api_password': API_PASSWORD
})
await ws.send_json({
'type': TYPE_AUTH,
'api_password': API_PASSWORD
})
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_INVALID
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_INVALID
async def test_auth_legacy_support_with_password(hass, aiohttp_client):
@ -149,9 +143,7 @@ async def test_auth_legacy_support_with_password(hass, aiohttp_client):
client = await aiohttp_client(hass.http.app)
async with client.ws_connect(URL) as ws:
with patch('homeassistant.auth.AuthManager.active',
return_value=True),\
patch('homeassistant.auth.AuthManager.support_legacy',
with patch('homeassistant.auth.AuthManager.support_legacy',
return_value=True):
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_REQUIRED
@ -176,15 +168,13 @@ async def test_auth_with_invalid_token(hass, aiohttp_client):
client = await aiohttp_client(hass.http.app)
async with client.ws_connect(URL) as ws:
with patch('homeassistant.auth.AuthManager.active') as auth_active:
auth_active.return_value = True
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_REQUIRED
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_REQUIRED
await ws.send_json({
'type': TYPE_AUTH,
'access_token': 'incorrect'
})
await ws.send_json({
'type': TYPE_AUTH,
'access_token': 'incorrect'
})
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_INVALID
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_INVALID

View File

@ -1,6 +1,4 @@
"""Tests for WebSocket API commands."""
from unittest.mock import patch
from async_timeout import timeout
from homeassistant.core import callback
@ -201,18 +199,16 @@ async def test_call_service_context_with_user(hass, aiohttp_client,
client = await aiohttp_client(hass.http.app)
async with client.ws_connect(URL) as ws:
with patch('homeassistant.auth.AuthManager.active') as auth_active:
auth_active.return_value = True
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_REQUIRED
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_REQUIRED
await ws.send_json({
'type': TYPE_AUTH,
'access_token': hass_access_token
})
await ws.send_json({
'type': TYPE_AUTH,
'access_token': hass_access_token
})
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_OK
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_OK
await ws.send_json({
'id': 5,
@ -238,50 +234,6 @@ async def test_call_service_context_with_user(hass, aiohttp_client,
assert call.context.user_id == refresh_token.user.id
async def test_call_service_context_no_user(hass, aiohttp_client):
"""Test that connection without user sets context."""
assert await async_setup_component(hass, 'websocket_api', {
'http': {
'api_password': API_PASSWORD
}
})
calls = async_mock_service(hass, 'domain_test', 'test_service')
client = await aiohttp_client(hass.http.app)
async with client.ws_connect(URL) as ws:
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_REQUIRED
await ws.send_json({
'type': TYPE_AUTH,
'api_password': API_PASSWORD
})
auth_msg = await ws.receive_json()
assert auth_msg['type'] == TYPE_AUTH_OK
await ws.send_json({
'id': 5,
'type': commands.TYPE_CALL_SERVICE,
'domain': 'domain_test',
'service': 'test_service',
'service_data': {
'hello': 'world'
}
})
msg = await ws.receive_json()
assert msg['success']
assert len(calls) == 1
call = calls[0]
assert call.domain == 'domain_test'
assert call.service == 'test_service'
assert call.data == {'hello': 'world'}
assert call.context.user_id is None
async def test_subscribe_requires_admin(websocket_client, hass_admin_user):
"""Test subscribing events without being admin."""
hass_admin_user.groups = []

View File

@ -10,10 +10,12 @@ import requests_mock as _requests_mock
from homeassistant import util
from homeassistant.util import location
from homeassistant.auth.const import GROUP_ID_ADMIN, GROUP_ID_READ_ONLY
from homeassistant.auth.providers import legacy_api_password, homeassistant
from tests.common import (
async_test_home_assistant, INSTANCES, async_mock_mqtt_component, mock_coro,
mock_storage as mock_storage)
mock_storage as mock_storage, MockUser, CLIENT_ID)
from tests.test_util.aiohttp import mock_aiohttp_client
from tests.mock.zwave import MockNetwork, MockOption
@ -133,3 +135,67 @@ def mock_device_tracker_conf():
side_effect=lambda *args: mock_coro(devices)
):
yield devices
@pytest.fixture
def hass_access_token(hass, hass_admin_user):
"""Return an access token to access Home Assistant."""
refresh_token = hass.loop.run_until_complete(
hass.auth.async_create_refresh_token(hass_admin_user, CLIENT_ID))
yield hass.auth.async_create_access_token(refresh_token)
@pytest.fixture
def hass_owner_user(hass, local_auth):
"""Return a Home Assistant admin user."""
return MockUser(is_owner=True).add_to_hass(hass)
@pytest.fixture
def hass_admin_user(hass, local_auth):
"""Return a Home Assistant admin user."""
admin_group = hass.loop.run_until_complete(hass.auth.async_get_group(
GROUP_ID_ADMIN))
return MockUser(groups=[admin_group]).add_to_hass(hass)
@pytest.fixture
def hass_read_only_user(hass, local_auth):
"""Return a Home Assistant read only user."""
read_only_group = hass.loop.run_until_complete(hass.auth.async_get_group(
GROUP_ID_READ_ONLY))
return MockUser(groups=[read_only_group]).add_to_hass(hass)
@pytest.fixture
def legacy_auth(hass):
"""Load legacy API password provider."""
prv = legacy_api_password.LegacyApiPasswordAuthProvider(
hass, hass.auth._store, {
'type': 'legacy_api_password'
}
)
hass.auth._providers[(prv.type, prv.id)] = prv
@pytest.fixture
def local_auth(hass):
"""Load local auth provider."""
prv = homeassistant.HassAuthProvider(
hass, hass.auth._store, {
'type': 'homeassistant'
}
)
hass.auth._providers[(prv.type, prv.id)] = prv
@pytest.fixture
def hass_client(hass, aiohttp_client, hass_access_token):
"""Return an authenticated HTTP client."""
async def auth_client():
"""Return an authenticated client."""
return await aiohttp_client(hass.http.app, headers={
'Authorization': "Bearer {}".format(hass_access_token)
})
return auth_client

View File

@ -14,7 +14,7 @@ from tests.common import get_test_home_assistant
@pytest.fixture
def camera_client(hass, aiohttp_client):
def camera_client(hass, hass_client):
"""Fixture to fetch camera streams."""
assert hass.loop.run_until_complete(async_setup_component(hass, 'camera', {
'camera': {
@ -23,7 +23,7 @@ def camera_client(hass, aiohttp_client):
'mjpeg_url': 'http://example.com/mjpeg_stream',
}}))
yield hass.loop.run_until_complete(aiohttp_client(hass.http.app))
yield hass.loop.run_until_complete(hass_client())
class TestHelpersAiohttpClient(unittest.TestCase):

View File

@ -808,7 +808,6 @@ async def test_auth_provider_config(hass):
assert len(hass.auth.auth_providers) == 2
assert hass.auth.auth_providers[0].type == 'homeassistant'
assert hass.auth.auth_providers[1].type == 'legacy_api_password'
assert hass.auth.active is True
assert len(hass.auth.auth_mfa_modules) == 2
assert hass.auth.auth_mfa_modules[0].id == 'totp'
assert hass.auth.auth_mfa_modules[1].id == 'second'
@ -830,7 +829,6 @@ async def test_auth_provider_config_default(hass):
assert len(hass.auth.auth_providers) == 1
assert hass.auth.auth_providers[0].type == 'homeassistant'
assert hass.auth.active is True
assert len(hass.auth.auth_mfa_modules) == 1
assert hass.auth.auth_mfa_modules[0].id == 'totp'
@ -852,7 +850,6 @@ async def test_auth_provider_config_default_api_password(hass):
assert len(hass.auth.auth_providers) == 2
assert hass.auth.auth_providers[0].type == 'homeassistant'
assert hass.auth.auth_providers[1].type == 'legacy_api_password'
assert hass.auth.active is True
async def test_auth_provider_config_default_trusted_networks(hass):
@ -873,7 +870,6 @@ async def test_auth_provider_config_default_trusted_networks(hass):
assert len(hass.auth.auth_providers) == 2
assert hass.auth.auth_providers[0].type == 'homeassistant'
assert hass.auth.auth_providers[1].type == 'trusted_networks'
assert hass.auth.active is True
async def test_disallowed_auth_provider_config(hass):