Rename is_owner decorator to is_admin (#19266)

* Rename is_owner decorator to is_admin

* Update test_auth.py
This commit is contained in:
Paulus Schoutsen 2018-12-14 10:19:27 +01:00 committed by GitHub
parent a5a896b519
commit 4f98818258
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 42 additions and 61 deletions

View File

@ -39,7 +39,7 @@ async def async_setup(hass):
return True
@websocket_api.require_owner
@websocket_api.require_admin
@websocket_api.async_response
async def websocket_list(hass, connection, msg):
"""Return a list of users."""
@ -49,7 +49,7 @@ async def websocket_list(hass, connection, msg):
websocket_api.result_message(msg['id'], result))
@websocket_api.require_owner
@websocket_api.require_admin
@websocket_api.async_response
async def websocket_delete(hass, connection, msg):
"""Delete a user."""
@ -72,7 +72,7 @@ async def websocket_delete(hass, connection, msg):
websocket_api.result_message(msg['id']))
@websocket_api.require_owner
@websocket_api.require_admin
@websocket_api.async_response
async def websocket_create(hass, connection, msg):
"""Create a user."""

View File

@ -3,7 +3,6 @@ import voluptuous as vol
from homeassistant.auth.providers import homeassistant as auth_ha
from homeassistant.components import websocket_api
from homeassistant.components.websocket_api.decorators import require_owner
WS_TYPE_CREATE = 'config/auth_provider/homeassistant/create'
@ -54,7 +53,7 @@ def _get_provider(hass):
raise RuntimeError('Provider not found')
@require_owner
@websocket_api.require_admin
@websocket_api.async_response
async def websocket_create(hass, connection, msg):
"""Create credentials and attach to a user."""
@ -91,7 +90,7 @@ async def websocket_create(hass, connection, msg):
connection.send_message(websocket_api.result_message(msg['id']))
@require_owner
@websocket_api.require_admin
@websocket_api.async_response
async def websocket_delete(hass, connection, msg):
"""Delete username and related credential."""
@ -123,6 +122,7 @@ async def websocket_delete(hass, connection, msg):
websocket_api.result_message(msg['id']))
@websocket_api.require_admin
@websocket_api.async_response
async def websocket_change_password(hass, connection, msg):
"""Change user password."""

View File

@ -20,7 +20,7 @@ BASE_COMMAND_MESSAGE_SCHEMA = messages.BASE_COMMAND_MESSAGE_SCHEMA
error_message = messages.error_message
result_message = messages.result_message
async_response = decorators.async_response
require_owner = decorators.require_owner
require_admin = decorators.require_admin
ws_require_user = decorators.ws_require_user
# pylint: enable=invalid-name

View File

@ -3,6 +3,7 @@ from functools import wraps
import logging
from homeassistant.core import callback
from homeassistant.exceptions import Unauthorized
from . import messages
@ -30,21 +31,19 @@ def async_response(func):
return schedule_handler
def require_owner(func):
"""Websocket decorator to require user to be an owner."""
def require_admin(func):
"""Websocket decorator to require user to be an admin."""
@wraps(func)
def with_owner(hass, connection, msg):
"""Check owner and call function."""
def with_admin(hass, connection, msg):
"""Check admin and call function."""
user = connection.user
if user is None or not user.is_owner:
connection.send_message(messages.error_message(
msg['id'], 'unauthorized', 'This command is for owners only.'))
return
if user is None or not user.is_admin:
raise Unauthorized()
func(hass, connection, msg)
return with_owner
return with_admin
def ws_require_user(

View File

@ -13,9 +13,10 @@ def setup_config(hass, aiohttp_client):
hass.loop.run_until_complete(auth_config.async_setup(hass))
async def test_list_requires_owner(hass, hass_ws_client, hass_access_token):
async def test_list_requires_admin(hass, hass_ws_client,
hass_read_only_access_token):
"""Test get users requires auth."""
client = await hass_ws_client(hass, hass_access_token)
client = await hass_ws_client(hass, hass_read_only_access_token)
await client.send_json({
'id': 5,
@ -109,9 +110,10 @@ async def test_list(hass, hass_ws_client, hass_admin_user):
}
async def test_delete_requires_owner(hass, hass_ws_client, hass_access_token):
async def test_delete_requires_admin(hass, hass_ws_client,
hass_read_only_access_token):
"""Test delete command requires an owner."""
client = await hass_ws_client(hass, hass_access_token)
client = await hass_ws_client(hass, hass_read_only_access_token)
await client.send_json({
'id': 5,
@ -139,15 +141,12 @@ async def test_delete_unable_self_account(hass, hass_ws_client,
result = await client.receive_json()
assert not result['success'], result
assert result['error']['code'] == 'unauthorized'
assert result['error']['code'] == 'no_delete_self'
async def test_delete_unknown_user(hass, hass_ws_client, hass_access_token):
"""Test we cannot delete an unknown user."""
client = await hass_ws_client(hass, hass_access_token)
refresh_token = await hass.auth.async_validate_access_token(
hass_access_token)
refresh_token.user.is_owner = True
await client.send_json({
'id': 5,
@ -163,9 +162,6 @@ async def test_delete_unknown_user(hass, hass_ws_client, hass_access_token):
async def test_delete(hass, hass_ws_client, hass_access_token):
"""Test delete command works."""
client = await hass_ws_client(hass, hass_access_token)
refresh_token = await hass.auth.async_validate_access_token(
hass_access_token)
refresh_token.user.is_owner = True
test_user = MockUser(
id='efg',
).add_to_hass(hass)
@ -186,9 +182,6 @@ async def test_delete(hass, hass_ws_client, hass_access_token):
async def test_create(hass, hass_ws_client, hass_access_token):
"""Test create command works."""
client = await hass_ws_client(hass, hass_access_token)
refresh_token = await hass.auth.async_validate_access_token(
hass_access_token)
refresh_token.user.is_owner = True
assert len(await hass.auth.async_get_users()) == 1
@ -210,9 +203,10 @@ async def test_create(hass, hass_ws_client, hass_access_token):
assert not user.system_generated
async def test_create_requires_owner(hass, hass_ws_client, hass_access_token):
async def test_create_requires_admin(hass, hass_ws_client,
hass_read_only_access_token):
"""Test create command requires an owner."""
client = await hass_ws_client(hass, hass_access_token)
client = await hass_ws_client(hass, hass_read_only_access_token)
await client.send_json({
'id': 5,

View File

@ -22,9 +22,6 @@ async def test_create_auth_system_generated_user(hass, hass_access_token,
"""Test we can't add auth to system generated users."""
system_user = MockUser(system_generated=True).add_to_hass(hass)
client = await hass_ws_client(hass, hass_access_token)
refresh_token = await hass.auth.async_validate_access_token(
hass_access_token)
refresh_token.user.is_owner = True
await client.send_json({
'id': 5,
@ -49,9 +46,6 @@ async def test_create_auth_unknown_user(hass_ws_client, hass,
hass_access_token):
"""Test create pointing at unknown user."""
client = await hass_ws_client(hass, hass_access_token)
refresh_token = await hass.auth.async_validate_access_token(
hass_access_token)
refresh_token.user.is_owner = True
await client.send_json({
'id': 5,
@ -67,10 +61,10 @@ async def test_create_auth_unknown_user(hass_ws_client, hass,
assert result['error']['code'] == 'not_found'
async def test_create_auth_requires_owner(hass, hass_ws_client,
hass_access_token):
"""Test create requires owner to call API."""
client = await hass_ws_client(hass, hass_access_token)
async def test_create_auth_requires_admin(hass, hass_ws_client,
hass_read_only_access_token):
"""Test create requires admin to call API."""
client = await hass_ws_client(hass, hass_read_only_access_token)
await client.send_json({
'id': 5,
@ -90,9 +84,6 @@ async def test_create_auth(hass, hass_ws_client, hass_access_token,
"""Test create auth command works."""
client = await hass_ws_client(hass, hass_access_token)
user = MockUser().add_to_hass(hass)
refresh_token = await hass.auth.async_validate_access_token(
hass_access_token)
refresh_token.user.is_owner = True
assert len(user.credentials) == 0
@ -123,9 +114,6 @@ async def test_create_auth_duplicate_username(hass, hass_ws_client,
"""Test we can't create auth with a duplicate username."""
client = await hass_ws_client(hass, hass_access_token)
user = MockUser().add_to_hass(hass)
refresh_token = await hass.auth.async_validate_access_token(
hass_access_token)
refresh_token.user.is_owner = True
hass_storage[prov_ha.STORAGE_KEY] = {
'version': 1,
@ -153,9 +141,6 @@ async def test_delete_removes_just_auth(hass_ws_client, hass, hass_storage,
hass_access_token):
"""Test deleting an auth without being connected to a user."""
client = await hass_ws_client(hass, hass_access_token)
refresh_token = await hass.auth.async_validate_access_token(
hass_access_token)
refresh_token.user.is_owner = True
hass_storage[prov_ha.STORAGE_KEY] = {
'version': 1,
@ -181,9 +166,6 @@ async def test_delete_removes_credential(hass, hass_ws_client,
hass_access_token, hass_storage):
"""Test deleting auth that is connected to a user."""
client = await hass_ws_client(hass, hass_access_token)
refresh_token = await hass.auth.async_validate_access_token(
hass_access_token)
refresh_token.user.is_owner = True
user = MockUser().add_to_hass(hass)
user.credentials.append(
@ -210,9 +192,10 @@ async def test_delete_removes_credential(hass, hass_ws_client,
assert len(hass_storage[prov_ha.STORAGE_KEY]['data']['users']) == 0
async def test_delete_requires_owner(hass, hass_ws_client, hass_access_token):
"""Test delete requires owner."""
client = await hass_ws_client(hass, hass_access_token)
async def test_delete_requires_admin(hass, hass_ws_client,
hass_read_only_access_token):
"""Test delete requires admin."""
client = await hass_ws_client(hass, hass_read_only_access_token)
await client.send_json({
'id': 5,
@ -228,9 +211,6 @@ async def test_delete_requires_owner(hass, hass_ws_client, hass_access_token):
async def test_delete_unknown_auth(hass, hass_ws_client, hass_access_token):
"""Test trying to delete an unknown auth username."""
client = await hass_ws_client(hass, hass_access_token)
refresh_token = await hass.auth.async_validate_access_token(
hass_access_token)
refresh_token.user.is_owner = True
await client.send_json({
'id': 5,

View File

@ -142,7 +142,7 @@ 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)
return hass.auth.async_create_access_token(refresh_token)
@pytest.fixture
@ -167,6 +167,14 @@ def hass_read_only_user(hass, local_auth):
return MockUser(groups=[read_only_group]).add_to_hass(hass)
@pytest.fixture
def hass_read_only_access_token(hass, hass_read_only_user):
"""Return a Home Assistant read only user."""
refresh_token = hass.loop.run_until_complete(
hass.auth.async_create_refresh_token(hass_read_only_user, CLIENT_ID))
return hass.auth.async_create_access_token(refresh_token)
@pytest.fixture
def legacy_auth(hass):
"""Load legacy API password provider."""