Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update auth document #52

Merged
merged 9 commits into from
Aug 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions docs/auth_auth_module.md
Original file line number Diff line number Diff line change
@@ -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/<name of module>.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.
30 changes: 24 additions & 6 deletions docs/auth_auth_provider.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/<name of provider>.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/<name of provider>.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 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
```
1 change: 1 addition & 0 deletions website/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
3 changes: 2 additions & 1 deletion website/sidebars.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
"Authentication": [
"auth_index",
"auth_api",
"auth_auth_provider"
"auth_auth_provider",
"auth_auth_module"
],
"Configuration.yaml": [
"configuration_yaml_index"
Expand Down