1
mirror of https://github.com/home-assistant/core synced 2024-09-03 08:14:07 +02:00
ha-core/homeassistant/components/config/auth_provider_homeassistant.py
2022-01-11 18:24:08 +01:00

175 lines
5.4 KiB
Python

"""Offer API to configure the Home Assistant auth provider."""
import voluptuous as vol
from homeassistant.auth.providers import homeassistant as auth_ha
from homeassistant.components import websocket_api
from homeassistant.components.websocket_api import decorators
from homeassistant.exceptions import Unauthorized
async def async_setup(hass):
"""Enable the Home Assistant views."""
websocket_api.async_register_command(hass, websocket_create)
websocket_api.async_register_command(hass, websocket_delete)
websocket_api.async_register_command(hass, websocket_change_password)
websocket_api.async_register_command(hass, websocket_admin_change_password)
return True
@decorators.websocket_command(
{
vol.Required("type"): "config/auth_provider/homeassistant/create",
vol.Required("user_id"): str,
vol.Required("username"): str,
vol.Required("password"): str,
}
)
@websocket_api.require_admin
@websocket_api.async_response
async def websocket_create(hass, connection, msg):
"""Create credentials and attach to a user."""
provider = auth_ha.async_get_provider(hass)
if (user := await hass.auth.async_get_user(msg["user_id"])) is None:
connection.send_error(msg["id"], "not_found", "User not found")
return
if user.system_generated:
connection.send_error(
msg["id"],
"system_generated",
"Cannot add credentials to a system generated user.",
)
return
try:
await provider.async_add_auth(msg["username"], msg["password"])
except auth_ha.InvalidUser:
connection.send_error(msg["id"], "username_exists", "Username already exists")
return
credentials = await provider.async_get_or_create_credentials(
{"username": msg["username"]}
)
await hass.auth.async_link_user(user, credentials)
connection.send_result(msg["id"])
@decorators.websocket_command(
{
vol.Required("type"): "config/auth_provider/homeassistant/delete",
vol.Required("username"): str,
}
)
@websocket_api.require_admin
@websocket_api.async_response
async def websocket_delete(hass, connection, msg):
"""Delete username and related credential."""
provider = auth_ha.async_get_provider(hass)
credentials = await provider.async_get_or_create_credentials(
{"username": msg["username"]}
)
# if not new, an existing credential exists.
# Removing the credential will also remove the auth.
if not credentials.is_new:
await hass.auth.async_remove_credentials(credentials)
connection.send_result(msg["id"])
return
try:
await provider.async_remove_auth(msg["username"])
except auth_ha.InvalidUser:
connection.send_error(
msg["id"], "auth_not_found", "Given username was not found."
)
return
connection.send_result(msg["id"])
@decorators.websocket_command(
{
vol.Required("type"): "config/auth_provider/homeassistant/change_password",
vol.Required("current_password"): str,
vol.Required("new_password"): str,
}
)
@websocket_api.async_response
async def websocket_change_password(hass, connection, msg):
"""Change current user password."""
if (user := connection.user) is None:
connection.send_error(msg["id"], "user_not_found", "User not found")
return
provider = auth_ha.async_get_provider(hass)
username = None
for credential in user.credentials:
if credential.auth_provider_type == provider.type:
username = credential.data["username"]
break
if username is None:
connection.send_error(
msg["id"], "credentials_not_found", "Credentials not found"
)
return
try:
await provider.async_validate_login(username, msg["current_password"])
except auth_ha.InvalidAuth:
connection.send_error(
msg["id"], "invalid_current_password", "Invalid current password"
)
return
await provider.async_change_password(username, msg["new_password"])
connection.send_result(msg["id"])
@decorators.websocket_command(
{
vol.Required(
"type"
): "config/auth_provider/homeassistant/admin_change_password",
vol.Required("user_id"): str,
vol.Required("password"): str,
}
)
@decorators.require_admin
@decorators.async_response
async def websocket_admin_change_password(hass, connection, msg):
"""Change password of any user."""
if not connection.user.is_owner:
raise Unauthorized(context=connection.context(msg))
if (user := await hass.auth.async_get_user(msg["user_id"])) is None:
connection.send_error(msg["id"], "user_not_found", "User not found")
return
provider = auth_ha.async_get_provider(hass)
username = None
for credential in user.credentials:
if credential.auth_provider_type == provider.type:
username = credential.data["username"]
break
if username is None:
connection.send_error(
msg["id"], "credentials_not_found", "Credentials not found"
)
return
try:
await provider.async_change_password(username, msg["password"])
connection.send_result(msg["id"])
except auth_ha.InvalidUser:
connection.send_error(
msg["id"], "credentials_not_found", "Credentials not found"
)
return