Home Assistant Unofficial Reference 2024.12.1
auth.py
Go to the documentation of this file.
1 """Offer API to configure Home Assistant auth."""
2 
3 from __future__ import annotations
4 
5 from typing import Any
6 
7 import voluptuous as vol
8 
9 from homeassistant.auth.models import User
10 from homeassistant.components import websocket_api
11 from homeassistant.core import HomeAssistant, callback
12 
13 WS_TYPE_LIST = "config/auth/list"
14 SCHEMA_WS_LIST = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend(
15  {vol.Required("type"): WS_TYPE_LIST}
16 )
17 
18 WS_TYPE_DELETE = "config/auth/delete"
19 SCHEMA_WS_DELETE = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend(
20  {vol.Required("type"): WS_TYPE_DELETE, vol.Required("user_id"): str}
21 )
22 
23 
24 @callback
25 def async_setup(hass: HomeAssistant) -> bool:
26  """Enable the Home Assistant views."""
27  websocket_api.async_register_command(
28  hass, WS_TYPE_LIST, websocket_list, SCHEMA_WS_LIST
29  )
30  websocket_api.async_register_command(
31  hass, WS_TYPE_DELETE, websocket_delete, SCHEMA_WS_DELETE
32  )
33  websocket_api.async_register_command(hass, websocket_create)
34  websocket_api.async_register_command(hass, websocket_update)
35  return True
36 
37 
38 @websocket_api.require_admin
39 @websocket_api.async_response
40 async def websocket_list(
41  hass: HomeAssistant,
43  msg: dict[str, Any],
44 ) -> None:
45  """Return a list of users."""
46  result = [_user_info(u) for u in await hass.auth.async_get_users()]
47 
48  connection.send_message(websocket_api.result_message(msg["id"], result))
49 
50 
51 @websocket_api.require_admin
52 @websocket_api.async_response
53 async def websocket_delete(
54  hass: HomeAssistant,
56  msg: dict[str, Any],
57 ) -> None:
58  """Delete a user."""
59  if msg["user_id"] == connection.user.id:
60  connection.send_message(
61  websocket_api.error_message(
62  msg["id"], "no_delete_self", "Unable to delete your own account"
63  )
64  )
65  return
66 
67  if not (user := await hass.auth.async_get_user(msg["user_id"])):
68  connection.send_message(
69  websocket_api.error_message(msg["id"], "not_found", "User not found")
70  )
71  return
72 
73  await hass.auth.async_remove_user(user)
74 
75  connection.send_message(websocket_api.result_message(msg["id"]))
76 
77 
78 @websocket_api.require_admin
79 @websocket_api.websocket_command( { vol.Required("type"): "config/auth/create",
80  vol.Required("name"): str,
81  vol.Optional("group_ids"): [str],
82  vol.Optional("local_only"): bool,
83  }
84 )
85 @websocket_api.async_response
86 async def websocket_create(
87  hass: HomeAssistant,
89  msg: dict[str, Any],
90 ) -> None:
91  """Create a user."""
92  user = await hass.auth.async_create_user(
93  msg["name"], group_ids=msg.get("group_ids"), local_only=msg.get("local_only")
94  )
95 
96  connection.send_message(
97  websocket_api.result_message(msg["id"], {"user": _user_info(user)})
98  )
99 
100 
101 @websocket_api.require_admin
102 @websocket_api.websocket_command( { vol.Required("type"): "config/auth/update",
103  vol.Required("user_id"): str,
104  vol.Optional("name"): str,
105  vol.Optional("is_active"): bool,
106  vol.Optional("group_ids"): [str],
107  vol.Optional("local_only"): bool,
108  }
109 )
110 @websocket_api.async_response
111 async def websocket_update(
112  hass: HomeAssistant,
113  connection: websocket_api.ActiveConnection,
114  msg: dict[str, Any],
115 ) -> None:
116  """Update a user."""
117  if not (user := await hass.auth.async_get_user(msg.pop("user_id"))):
118  connection.send_message(
119  websocket_api.error_message(
120  msg["id"], websocket_api.ERR_NOT_FOUND, "User not found"
121  )
122  )
123  return
124 
125  if user.system_generated:
126  connection.send_message(
127  websocket_api.error_message(
128  msg["id"],
129  "cannot_modify_system_generated",
130  "Unable to update system generated users.",
131  )
132  )
133  return
134 
135  if user.is_owner and msg.get("is_active") is False:
136  connection.send_message(
137  websocket_api.error_message(
138  msg["id"],
139  "cannot_deactivate_owner",
140  "Unable to deactivate owner.",
141  )
142  )
143  return
144 
145  msg.pop("type")
146  msg_id = msg.pop("id")
147 
148  await hass.auth.async_update_user(user, **msg)
149 
150  connection.send_message(
151  websocket_api.result_message(msg_id, {"user": _user_info(user)})
152  )
153 
154 
155 def _user_info(user: User) -> dict[str, Any]:
156  """Format a user."""
157 
158  ha_username = next(
159  (
160  cred.data.get("username")
161  for cred in user.credentials
162  if cred.auth_provider_type == "homeassistant"
163  ),
164  None,
165  )
166 
167  return {
168  "id": user.id,
169  "username": ha_username,
170  "name": user.name,
171  "is_owner": user.is_owner,
172  "is_active": user.is_active,
173  "local_only": user.local_only,
174  "system_generated": user.system_generated,
175  "group_ids": [group.id for group in user.groups],
176  "credentials": [{"type": c.auth_provider_type} for c in user.credentials],
177  }
178 
None websocket_list(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
Definition: auth.py:44
None websocket_create(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
Definition: auth.py:92
bool async_setup(HomeAssistant hass)
Definition: auth.py:25
dict[str, Any] _user_info(User user)
Definition: auth.py:159
None websocket_delete(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
Definition: auth.py:57
None websocket_update(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
Definition: auth.py:119