User management (#15420)
* User management * Lint * Fix dict * Reuse data instance * OrderedDict all the way
This commit is contained in:
parent
84858f5c19
commit
70fe463ef0
21 changed files with 982 additions and 116 deletions
|
@ -7,6 +7,8 @@ import hmac
|
|||
import voluptuous as vol
|
||||
|
||||
from homeassistant import data_entry_flow
|
||||
from homeassistant.const import CONF_ID
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
|
||||
from homeassistant.auth.util import generate_secret
|
||||
|
@ -16,8 +18,17 @@ from . import AuthProvider, AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS
|
|||
STORAGE_VERSION = 1
|
||||
STORAGE_KEY = 'auth_provider.homeassistant'
|
||||
|
||||
CONFIG_SCHEMA = AUTH_PROVIDER_SCHEMA.extend({
|
||||
}, extra=vol.PREVENT_EXTRA)
|
||||
|
||||
def _disallow_id(conf):
|
||||
"""Disallow ID in config."""
|
||||
if CONF_ID in conf:
|
||||
raise vol.Invalid(
|
||||
'ID is not allowed for the homeassistant auth provider.')
|
||||
|
||||
return conf
|
||||
|
||||
|
||||
CONFIG_SCHEMA = vol.All(AUTH_PROVIDER_SCHEMA, _disallow_id)
|
||||
|
||||
|
||||
class InvalidAuth(HomeAssistantError):
|
||||
|
@ -88,8 +99,8 @@ class Data:
|
|||
hashed = base64.b64encode(hashed).decode()
|
||||
return hashed
|
||||
|
||||
def add_user(self, username, password):
|
||||
"""Add a user."""
|
||||
def add_auth(self, username, password):
|
||||
"""Add a new authenticated user/pass."""
|
||||
if any(user['username'] == username for user in self.users):
|
||||
raise InvalidUser
|
||||
|
||||
|
@ -98,8 +109,22 @@ class Data:
|
|||
'password': self.hash_password(password, True),
|
||||
})
|
||||
|
||||
@callback
|
||||
def async_remove_auth(self, username):
|
||||
"""Remove authentication."""
|
||||
index = None
|
||||
for i, user in enumerate(self.users):
|
||||
if user['username'] == username:
|
||||
index = i
|
||||
break
|
||||
|
||||
if index is None:
|
||||
raise InvalidUser
|
||||
|
||||
self.users.pop(index)
|
||||
|
||||
def change_password(self, username, new_password):
|
||||
"""Update the password of a user.
|
||||
"""Update the password.
|
||||
|
||||
Raises InvalidUser if user cannot be found.
|
||||
"""
|
||||
|
@ -121,16 +146,24 @@ class HassAuthProvider(AuthProvider):
|
|||
|
||||
DEFAULT_TITLE = 'Home Assistant Local'
|
||||
|
||||
data = None
|
||||
|
||||
async def async_initialize(self):
|
||||
"""Initialize the auth provider."""
|
||||
self.data = Data(self.hass)
|
||||
await self.data.async_load()
|
||||
|
||||
async def async_credential_flow(self):
|
||||
"""Return a flow to login."""
|
||||
return LoginFlow(self)
|
||||
|
||||
async def async_validate_login(self, username, password):
|
||||
"""Helper to validate a username and password."""
|
||||
data = Data(self.hass)
|
||||
await data.async_load()
|
||||
if self.data is None:
|
||||
await self.async_initialize()
|
||||
|
||||
await self.hass.async_add_executor_job(
|
||||
data.validate_login, username, password)
|
||||
self.data.validate_login, username, password)
|
||||
|
||||
async def async_get_or_create_credentials(self, flow_result):
|
||||
"""Get credentials based on the flow result."""
|
||||
|
@ -145,6 +178,24 @@ class HassAuthProvider(AuthProvider):
|
|||
'username': username
|
||||
})
|
||||
|
||||
async def async_user_meta_for_credentials(self, credentials):
|
||||
"""Get extra info for this credential."""
|
||||
return {
|
||||
'name': credentials.data['username']
|
||||
}
|
||||
|
||||
async def async_will_remove_credentials(self, credentials):
|
||||
"""When credentials get removed, also remove the auth."""
|
||||
if self.data is None:
|
||||
await self.async_initialize()
|
||||
|
||||
try:
|
||||
self.data.async_remove_auth(credentials.data['username'])
|
||||
await self.data.async_save()
|
||||
except InvalidUser:
|
||||
# Can happen if somehow we didn't clean up a credential
|
||||
pass
|
||||
|
||||
|
||||
class LoginFlow(data_entry_flow.FlowHandler):
|
||||
"""Handler for the login flow."""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue