From 00de69cbbd6dfb08066e12cb1ea35c6bf7758494 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Sat, 7 Jul 2018 12:47:52 -0700 Subject: [PATCH 1/9] Update auth_auth_provider.md --- docs/auth_auth_provider.md | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/docs/auth_auth_provider.md b/docs/auth_auth_provider.md index c10f2a6b961..e354da03c92 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 self.async_finish(username) if user_input is valid +``` From 86937fca0e5b5f9f0716effffc459e3ba27a102e Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Sat, 7 Jul 2018 13:00:38 -0700 Subject: [PATCH 2/9] Update auth_auth_provider.md --- docs/auth_auth_provider.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/auth_auth_provider.md b/docs/auth_auth_provider.md index e354da03c92..749fcf8478d 100644 --- a/docs/auth_auth_provider.md +++ b/docs/auth_auth_provider.md @@ -38,5 +38,5 @@ Auth providers shall extend the following methods of `LoginFlow` class. 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 self.async_finish(username) if user_input is valid + return await self.async_finish(username) if user_input is valid ``` From cef008b7f19fce1b303749f5f5ae6b641ba6a7eb Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Sat, 7 Jul 2018 14:57:33 -0700 Subject: [PATCH 3/9] Create auth_auth_module.md --- docs/auth_auth_module.md | 55 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) 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 00000000000..f1eb34e6cc0 --- /dev/null +++ b/docs/auth_auth_module.md @@ -0,0 +1,55 @@ +--- +title: "Authentication Modules" +--- + +Authentication Modules are used in conjunction with [Authentication Provider](auth_auth_provider.html) to provide a fully configurable authentication framework. Each auth module may provide one 2FA authentication function, auth provider can work with one or many auth modules. + +## Defining an auth module + +> We currently only support built-in auth modules. Support for custom auth modules might arrive in the future. + +Auth modules are defined in `homeassistant/auth_providers/modules/.py`. The auth module will need to provide an implementation of the `AuthModule` 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_providers/modules/insecure_example.py). + +Auth modules shall extend the following methods of `AuthModule` class. + +| method | Required | Description +| ------ | -------- | ----------- +| @property def input_schema(self)| Yes | Return a schema defined the user input form. +| async def async_validation_flow(self, session_data, user_input) | Yes | Given a validation session data and user input, return valid username or raise InvalidAuth exception. +| async def async_initialize(self)| No | Optional intialization callback. + +## Workflow + +> TODO: draw a diagram + +User == select auth provider ==> LoginFlow.init == input/validate username/password ==> LoginFlow.finish == if auth module configed ==> LoginFlow.auth_module step == input/validate 2FA code ==> if no more auth module ==> AuthProvider.get_or_create_credentials + +## Configuration example + +```yaml +# configuration.xml +homeassistant: + auth_providers: + - type: homeassistant + modules: + - type: totp + - type: legacy_api_password + modules: + - type: insecure_example + users: [{'username': 'homeassistant', 'pin': '123456'}] + - type: totp +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, then input Google Authenticator code for the username. For 'legacy_api_password` auth provider, user will first input api password, then verify the pin, then input Google Authenticator code for 'homeassistant' user. + +> 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, auth module will create a validation session, include an experiation time and username from auth provider validate result. Auth moudle will not only verify the user input, and also verify the session is not experied. The validatoin session data will be storaged in memory only. + +Session related functions fully implementated in `AuthModule` class. + From 9f254008b4735281dd7ab6f9902d9569b07f612d Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Sat, 7 Jul 2018 15:02:57 -0700 Subject: [PATCH 4/9] Update en.json --- website/i18n/en.json | 1 + 1 file changed, 1 insertion(+) diff --git a/website/i18n/en.json b/website/i18n/en.json index 432e3f983d2..bc8a899f441 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", From 9aa53ef700e6d13084bc97cfc4bffebc7b967ed0 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Sat, 7 Jul 2018 15:03:30 -0700 Subject: [PATCH 5/9] Update sidebars.json --- website/sidebars.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/sidebars.json b/website/sidebars.json index c23f382b412..58df938c12b 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" From 9b66ac60a87fdbe48c5e3e61a28bba9274d3b09a Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Wed, 11 Jul 2018 18:29:29 -0700 Subject: [PATCH 6/9] Update auth_auth_module.md --- docs/auth_auth_module.md | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/docs/auth_auth_module.md b/docs/auth_auth_module.md index f1eb34e6cc0..b5216a73044 100644 --- a/docs/auth_auth_module.md +++ b/docs/auth_auth_module.md @@ -1,30 +1,31 @@ --- -title: "Authentication Modules" +title: "Multi-factor Authentication Modules" --- -Authentication Modules are used in conjunction with [Authentication Provider](auth_auth_provider.html) to provide a fully configurable authentication framework. Each auth module may provide one 2FA authentication function, auth provider can work with one or many auth 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 auth module +## Defining an mfa auth module -> We currently only support built-in auth modules. Support for custom auth modules might arrive in the future. +> We currently only support built-in mfa auth modules. Support for custom auth modules might arrive in the future. -Auth modules are defined in `homeassistant/auth_providers/modules/.py`. The auth module will need to provide an implementation of the `AuthModule` class. +Multi-facor Auth modules are defined in `homeassistant/auth/modules/.py`. The auth module will need to provide an implementation of the `AuthModule` 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_providers/modules/insecure_example.py). +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/modules/insecure_example.py). Auth modules shall extend the following methods of `AuthModule` class. | method | Required | Description | ------ | -------- | ----------- -| @property def input_schema(self)| Yes | Return a schema defined the user input form. -| async def async_validation_flow(self, session_data, user_input) | Yes | Given a validation session data and user input, return valid username or raise InvalidAuth exception. -| async def async_initialize(self)| No | Optional intialization callback. +| `@property def input_schema(self)` | Yes | Return a schema defined the user input form. +| `async def async_setup_user(self, user_id, **kwargs)` | Yes | Setup user for use this auth module +| `async def async_validation_flow(self, user_id, user_input)` | Yes | Given a user_id and user input, return valid user_id or raise InvalidAuth exception. +| `async def async_initialize(self)` | No | Optional intialization callback. ## Workflow > TODO: draw a diagram -User == select auth provider ==> LoginFlow.init == input/validate username/password ==> LoginFlow.finish == if auth module configed ==> LoginFlow.auth_module step == input/validate 2FA code ==> if no more auth module ==> AuthProvider.get_or_create_credentials +User == select auth provider ==> LoginFlow.init == input/validate username/password ==> LoginFlow.select_mfa_module ==> LoginFlow.mfa == input/validate MFA code ==> LoginFlow.finish ==> AuthProvider.get_or_create_credentials ## Configuration example @@ -33,23 +34,18 @@ User == select auth provider ==> LoginFlow.init == input/validate username/passw homeassistant: auth_providers: - type: homeassistant - modules: - - type: totp - type: legacy_api_password - modules: - - type: insecure_example - users: [{'username': 'homeassistant', 'pin': '123456'}] - - type: totp + 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, then input Google Authenticator code for the username. For 'legacy_api_password` auth provider, user will first input api password, then verify the pin, then input Google Authenticator code for 'homeassistant' user. +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, auth module will create a validation session, include an experiation time and username from auth provider validate result. Auth moudle will not only verify the user input, and also verify the session is not experied. The validatoin session data will be storaged in memory only. - -Session related functions fully implementated in `AuthModule` class. - +Not like auth provider, auth module use session to manage the validation. After auth provider validated, auth module will create a validation session, include an experiation time and user_id from auth provider validate result. 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. From 419a56d4ed15f477ff67fbb380e51daca6f6e0f9 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Wed, 11 Jul 2018 18:32:44 -0700 Subject: [PATCH 7/9] Update auth_auth_provider.md --- docs/auth_auth_provider.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/auth_auth_provider.md b/docs/auth_auth_provider.md index 749fcf8478d..0bff728e97a 100644 --- a/docs/auth_auth_provider.md +++ b/docs/auth_auth_provider.md @@ -10,9 +10,9 @@ 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 `LoginFlow` class, it is what asks user for information and validates it base on `data_entry_flow`. +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). +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 shall extend the following methods of `AuthProvider` class. From f0478367f8fa6dd08b4f8b453a4544ee904d7bfa Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Thu, 12 Jul 2018 16:50:42 -0700 Subject: [PATCH 8/9] Update auth_auth_module.md --- docs/auth_auth_module.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/auth_auth_module.md b/docs/auth_auth_module.md index b5216a73044..e5ec9b03e2a 100644 --- a/docs/auth_auth_module.md +++ b/docs/auth_auth_module.md @@ -8,21 +8,24 @@ Multi-factor Authentication Modules are used in conjunction with [Authentication > 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/modules/.py`. The auth module will need to provide an implementation of the `AuthModule` class. +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/modules/insecure_example.py). +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). -Auth modules shall extend the following methods of `AuthModule` class. +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. | `async def async_setup_user(self, user_id, **kwargs)` | Yes | Setup 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_validation_flow(self, user_id, user_input)` | Yes | Given a user_id and user input, return valid user_id or raise InvalidAuth exception. | `async def async_initialize(self)` | No | Optional intialization callback. ## 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.select_mfa_module ==> LoginFlow.mfa == input/validate MFA code ==> LoginFlow.finish ==> AuthProvider.get_or_create_credentials @@ -48,4 +51,4 @@ In this example, user will first select from `homeassistant` or `legacy_api_pass ## Validation session -Not like auth provider, auth module use session to manage the validation. After auth provider validated, auth module will create a validation session, include an experiation time and user_id from auth provider validate result. 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. +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. From 6b69a2781d3e0922d092a3abea0765ef10501003 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Wed, 22 Aug 2018 05:17:49 -0700 Subject: [PATCH 9/9] Update auth_auth_module.md --- docs/auth_auth_module.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/auth_auth_module.md b/docs/auth_auth_module.md index e5ec9b03e2a..4a9a2256a8e 100644 --- a/docs/auth_auth_module.md +++ b/docs/auth_auth_module.md @@ -17,10 +17,11 @@ Multi-factor Auth modules shall extend the following methods of `MultiFactorAuth | method | Required | Description | ------ | -------- | ----------- | `@property def input_schema(self)` | Yes | Return a schema defined the user input form. -| `async def async_setup_user(self, user_id, **kwargs)` | Yes | Setup 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_validation_flow(self, user_id, user_input)` | Yes | Given a user_id and user input, return valid user_id or raise InvalidAuth exception. -| `async def async_initialize(self)` | No | Optional intialization callback. +| `@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 @@ -28,7 +29,7 @@ To use a MFA auth module, user has to be created first, then call `AuthManager.a > TODO: draw a diagram -User == select auth provider ==> LoginFlow.init == input/validate username/password ==> LoginFlow.select_mfa_module ==> LoginFlow.mfa == input/validate MFA code ==> LoginFlow.finish ==> AuthProvider.get_or_create_credentials +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