From b77c3f83e17614cc136df62e4ae4ac534d62b844 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Wed, 22 Aug 2018 08:19:32 -0700 Subject: [PATCH] Update auth document (#52) * Update auth_auth_provider.md * Update auth_auth_provider.md * Create auth_auth_module.md * Update en.json * Update sidebars.json * Update auth_auth_module.md * Update auth_auth_provider.md * Update auth_auth_module.md * Update auth_auth_module.md --- docs/auth_auth_module.md | 55 ++++++++++++++++++++++++++++++++++++++ docs/auth_auth_provider.md | 28 +++++++++++++++---- website/i18n/en.json | 1 + website/sidebars.json | 3 ++- 4 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 docs/auth_auth_module.md diff --git a/docs/auth_auth_module.md b/docs/auth_auth_module.md new file mode 100644 index 00000000..4a9a2256 --- /dev/null +++ b/docs/auth_auth_module.md @@ -0,0 +1,55 @@ +--- +title: "Multi-factor Authentication Modules" +--- + +Multi-factor Authentication Modules are used in conjunction with [Authentication Provider](auth_auth_provider.html) to provide a fully configurable authentication framework. Each MFA module may provide one multi-factor authentication function. User can enable mulitple mfa module, but can only select one module in login process. + +## Defining an mfa auth module + +> We currently only support built-in mfa auth modules. Support for custom auth modules might arrive in the future. + +Multi-facor Auth modules are defined in `homeassistant/auth/mfa_modules/.py`. The auth module will need to provide an implementation of the `MultiFactorAuthModule` class. + +For an example of a fully implemented auth module, please see [insecure_example.py](https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/auth/mfa_modules/insecure_example.py). + +Multi-factor Auth modules shall extend the following methods of `MultiFactorAuthModule` class. + +| method | Required | Description +| ------ | -------- | ----------- +| `@property def input_schema(self)` | Yes | Return a schema defined the user input form. +| `@property def setup_schema(self)` | No | Return a schema defined the setup input form. +| `async def async_setup_user(self, user_id, setup_data)` | Yes | Set up user for use this auth module. +| `async def async_depose_user(self, user_id)` | Yes | Remove user information from this auth module. +| `async def async_is_user_setup(self, user_id)` | Yes | Return whether user is set up. +| `async def async_validation(self, user_id, user_input)` | Yes | Given a user_id and user input, return valiidation result. + +## Workflow + +To use a MFA auth module, user has to be created first, then call `AuthManager.async_enable_user_mfa` to setup. + +> TODO: draw a diagram + +User == select auth provider ==> LoginFlow.init == input/validate username/password ==> LoginFlow.finish ==> if user enabled mfa ==> LoginFlow.select_mfa_module ==> LoginFlow.mfa == input/validate MFA code ==> LoginFlow.finish ==> Done + +## Configuration example + +```yaml +# configuration.xml +homeassistant: + auth_providers: + - type: homeassistant + - type: legacy_api_password + auth_mfa_modules: + - type: totp + - type: insecure_example + users: [{'user_id': 'a_32_bytes_length_user_id', 'pin': '123456'}] +auth: +``` + +In this example, user will first select from `homeassistant` or `legacy_api_password` auth provider. For `homeassistant` auth provider, user will first input username/password, if that user enabled both `totp` and `insecure_example`, then user need select one auth module, then input Google Authenticator code or input pin code base on the selection. + +> insecure_example is only for demo purpose, please do not use it in production. + +## Validation session + +Not like auth provider, auth module use session to manage the validation. After auth provider validated, mfa module will create a validation session, include an experiation time and user_id from auth provider validate result. Mutli-factor auth moudle will not only verify the user input, and also verify the session is not experied. The validatoin session data storges in login flow instance. diff --git a/docs/auth_auth_provider.md b/docs/auth_auth_provider.md index 31d2d76c..0bff728e 100644 --- a/docs/auth_auth_provider.md +++ b/docs/auth_auth_provider.md @@ -10,15 +10,33 @@ Once an authentication provider has confirmed the identity of a user, it will pa > We currently only support built-in auth providers. Support for custom auth providers might arrive in the future. -Auth providers are defined in `homeassistant/auth_providers/.py`. The auth provider module will need to provide an implementation of the `AuthProvider` class and contain a credential flow. This flow is what asks user for information and validates it. +Auth providers are defined in `homeassistant/auth/providers/.py`. The auth provider module will need to provide an implementation of the `AuthProvider` class and `LoginFlow` class, it is what asks user for information and validates it base on `data_entry_flow`. For an example of a fully implemented auth provider, please see [insecure_example.py](https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/auth/providers/insecure_example.py). -Auth providers can extend the following methods. +Auth providers shall extend the following methods of `AuthProvider` class. | method | Required | Description | ------ | -------- | ----------- -| async def async_credential_flow(self) | Yes | Return an instance of the credential flow for a user to identify itself. -| async def async_get_or_create_credentials(self, flow_result) | Yes | Given the result of a credential flow, return a credentials object. This can either be an existing one or a new one. -| async def async_initialize(self) | No | Callback callled once before interacting with the auth provider for the first time. +| async def async_login_flow(self) | Yes | Return an instance of the login flow for a user to identify itself. +| async def async_get_or_create_credentials(self, flow_result) | Yes | Given the result of a login flow, return a credentials object. This can either be an existing one or a new one. | async def async_user_meta_for_credentials(credentials) | No | Callback called Home Assistant is going to create a user from a Credentials object. Can be used to populate extra fields for the user. + +Auth providers shall extend the following methods of `LoginFlow` class. + +| method | Required | Description +| ------ | -------- | ----------- +| async def async_step_init(self, user_input=None) | Yes | Handle the login form, see more detail in below. + +## async_step_init of LoginFlow + +> We may change this inteface in near future. + +`LoginFlow` extends `data_entry_flow.FlowHandler`. The first step of data entry flow is hard coded as `init`, so each flow has to implement `async_step_init` method. The pattern of `async_step_init` likes following pseudo-code: + +```python +async def async_step_init(self, user_input=None): + return self.async_show_form(step_id='init', data_schema='some schema to construct ui form') if user_input is None + return self.async_show_form(step_id='init', errors) if user_input is invalid + return await self.async_finish(username) if user_input is valid +``` diff --git a/website/i18n/en.json b/website/i18n/en.json index f15260b8..e6674e74 100644 --- a/website/i18n/en.json +++ b/website/i18n/en.json @@ -18,6 +18,7 @@ "asyncio_working_with_async": "Working with Async", "auth_api": "Authentication API", "API": "API", + "auth_auth_module": "Authentication Modules", "auth_auth_provider": "Authentication Providers", "auth_index": "Authentication", "config_entries_config_flow_handler": "Config Flow Handlers", diff --git a/website/sidebars.json b/website/sidebars.json index 9a00cb78..b723be7f 100644 --- a/website/sidebars.json +++ b/website/sidebars.json @@ -25,7 +25,8 @@ "Authentication": [ "auth_index", "auth_api", - "auth_auth_provider" + "auth_auth_provider", + "auth_auth_module" ], "Configuration.yaml": [ "configuration_yaml_index"