Onboarding to generate auth code (#21777)

This commit is contained in:
Paulus Schoutsen 2019-03-08 13:51:42 -08:00 committed by GitHub
parent a0e8543aed
commit 3da0ed9cc7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 44 additions and 2 deletions

View File

@ -127,6 +127,7 @@ import voluptuous as vol
from homeassistant.auth.models import User, Credentials, \ from homeassistant.auth.models import User, Credentials, \
TOKEN_TYPE_LONG_LIVED_ACCESS_TOKEN TOKEN_TYPE_LONG_LIVED_ACCESS_TOKEN
from homeassistant.loader import bind_hass
from homeassistant.components import websocket_api from homeassistant.components import websocket_api
from homeassistant.components.http import KEY_REAL_IP from homeassistant.components.http import KEY_REAL_IP
from homeassistant.components.http.auth import async_sign_path from homeassistant.components.http.auth import async_sign_path
@ -184,10 +185,18 @@ RESULT_TYPE_USER = 'user'
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@bind_hass
def create_auth_code(hass, client_id: str, user: User) -> str:
"""Create an authorization code to fetch tokens."""
return hass.data[DOMAIN](client_id, user)
async def async_setup(hass, config): async def async_setup(hass, config):
"""Component to allow users to login.""" """Component to allow users to login."""
store_result, retrieve_result = _create_auth_code_store() store_result, retrieve_result = _create_auth_code_store()
hass.data[DOMAIN] = store_result
hass.http.register_view(TokenView(retrieve_result)) hass.http.register_view(TokenView(retrieve_result))
hass.http.register_view(LinkUserView(retrieve_result)) hass.http.register_view(LinkUserView(retrieve_result))

View File

@ -4,7 +4,7 @@ from homeassistant.loader import bind_hass
from .const import DOMAIN, STEP_USER, STEPS from .const import DOMAIN, STEP_USER, STEPS
DEPENDENCIES = ['http'] DEPENDENCIES = ['auth', 'http']
STORAGE_KEY = DOMAIN STORAGE_KEY = DOMAIN
STORAGE_VERSION = 1 STORAGE_VERSION = 1

View File

@ -74,6 +74,7 @@ class UserOnboardingView(_BaseOnboardingView):
vol.Required('name'): str, vol.Required('name'): str,
vol.Required('username'): str, vol.Required('username'): str,
vol.Required('password'): str, vol.Required('password'): str,
vol.Required('client_id'): str,
})) }))
async def post(self, request, data): async def post(self, request, data):
"""Return the manifest.json.""" """Return the manifest.json."""
@ -98,8 +99,17 @@ class UserOnboardingView(_BaseOnboardingView):
await hass.components.person.async_create_person( await hass.components.person.async_create_person(
data['name'], user_id=user.id data['name'], user_id=user.id
) )
await self._async_mark_done(hass) await self._async_mark_done(hass)
# Return an authorization code to allow fetching tokens.
auth_code = hass.components.auth.create_auth_code(
data['client_id'], user
)
return self.json({
'auth_code': auth_code
})
@callback @callback
def _async_get_hass_provider(hass): def _async_get_hass_provider(hass):

View File

@ -8,7 +8,7 @@ from homeassistant.setup import async_setup_component
from homeassistant.components import onboarding from homeassistant.components import onboarding
from homeassistant.components.onboarding import views from homeassistant.components.onboarding import views
from tests.common import register_auth_provider from tests.common import CLIENT_ID, register_auth_provider
from . import mock_storage from . import mock_storage
@ -59,6 +59,7 @@ async def test_onboarding_user_already_done(hass, hass_storage,
client = await aiohttp_client(hass.http.app) client = await aiohttp_client(hass.http.app)
resp = await client.post('/api/onboarding/users', json={ resp = await client.post('/api/onboarding/users', json={
'client_id': CLIENT_ID,
'name': 'Test Name', 'name': 'Test Name',
'username': 'test-user', 'username': 'test-user',
'password': 'test-pass', 'password': 'test-pass',
@ -79,12 +80,16 @@ async def test_onboarding_user(hass, hass_storage, aiohttp_client):
client = await aiohttp_client(hass.http.app) client = await aiohttp_client(hass.http.app)
resp = await client.post('/api/onboarding/users', json={ resp = await client.post('/api/onboarding/users', json={
'client_id': CLIENT_ID,
'name': 'Test Name', 'name': 'Test Name',
'username': 'test-user', 'username': 'test-user',
'password': 'test-pass', 'password': 'test-pass',
}) })
assert resp.status == 200 assert resp.status == 200
data = await resp.json()
assert 'auth_code' in data
users = await hass.auth.async_get_users() users = await hass.auth.async_get_users()
assert len(users) == 1 assert len(users) == 1
user = users[0] user = users[0]
@ -93,6 +98,21 @@ async def test_onboarding_user(hass, hass_storage, aiohttp_client):
assert user.credentials[0].data['username'] == 'test-user' assert user.credentials[0].data['username'] == 'test-user'
assert len(hass.data['person'].storage_data) == 1 assert len(hass.data['person'].storage_data) == 1
# Request refresh tokens
resp = await client.post('/auth/token', data={
'client_id': CLIENT_ID,
'grant_type': 'authorization_code',
'code': data['auth_code']
})
assert resp.status == 200
tokens = await resp.json()
assert (
await hass.auth.async_validate_access_token(tokens['access_token'])
is not None
)
async def test_onboarding_user_invalid_name(hass, hass_storage, async def test_onboarding_user_invalid_name(hass, hass_storage,
aiohttp_client): aiohttp_client):
@ -106,6 +126,7 @@ async def test_onboarding_user_invalid_name(hass, hass_storage,
client = await aiohttp_client(hass.http.app) client = await aiohttp_client(hass.http.app)
resp = await client.post('/api/onboarding/users', json={ resp = await client.post('/api/onboarding/users', json={
'client_id': CLIENT_ID,
'username': 'test-user', 'username': 'test-user',
'password': 'test-pass', 'password': 'test-pass',
}) })
@ -124,11 +145,13 @@ async def test_onboarding_user_race(hass, hass_storage, aiohttp_client):
client = await aiohttp_client(hass.http.app) client = await aiohttp_client(hass.http.app)
resp1 = client.post('/api/onboarding/users', json={ resp1 = client.post('/api/onboarding/users', json={
'client_id': CLIENT_ID,
'name': 'Test 1', 'name': 'Test 1',
'username': '1-user', 'username': '1-user',
'password': '1-pass', 'password': '1-pass',
}) })
resp2 = client.post('/api/onboarding/users', json={ resp2 = client.post('/api/onboarding/users', json={
'client_id': CLIENT_ID,
'name': 'Test 2', 'name': 'Test 2',
'username': '2-user', 'username': '2-user',
'password': '2-pass', 'password': '2-pass',