Ejemplo n.º 1
0
async def test_login_as_existing_user(mock_hass):
    """Test login as existing user."""
    manager = await auth.auth_manager_from_config(mock_hass, [{
        'type': 'insecure_example',
        'users': [{
            'username': '******',
            'password': '******',
            'name': 'Test Name'
        }]
    }], [])
    mock_hass.auth = manager
    ensure_auth_manager_loaded(manager)

    # Add a fake user that we're not going to log in with
    user = MockUser(
        id='mock-user2',
        is_owner=False,
        is_active=False,
        name='Not user',
    ).add_to_auth_manager(manager)
    user.credentials.append(auth_models.Credentials(
        id='mock-id2',
        auth_provider_type='insecure_example',
        auth_provider_id=None,
        data={'username': '******'},
        is_new=False,
    ))

    # Add fake user with credentials for example auth provider.
    user = MockUser(
        id='mock-user',
        is_owner=False,
        is_active=False,
        name='Paulus',
    ).add_to_auth_manager(manager)
    user.credentials.append(auth_models.Credentials(
        id='mock-id',
        auth_provider_type='insecure_example',
        auth_provider_id=None,
        data={'username': '******'},
        is_new=False,
    ))

    step = await manager.login_flow.async_init(('insecure_example', None))
    assert step['type'] == data_entry_flow.RESULT_TYPE_FORM

    step = await manager.login_flow.async_configure(step['flow_id'], {
        'username': '******',
        'password': '******',
    })
    assert step['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY

    user = step['result']
    assert user is not None
    assert user.id == 'mock-user'
    assert user.is_owner is False
    assert user.is_active is False
    assert user.name == 'Paulus'
Ejemplo n.º 2
0
async def test_new_users_admin(mock_hass):
    """Test newly created users are admin."""
    manager = await auth.auth_manager_from_config(
        mock_hass,
        [
            {
                "type": "insecure_example",
                "users": [
                    {
                        "username": "******",
                        "password": "******",
                        "name": "Test Name",
                    }
                ],
            }
        ],
        [],
    )
    ensure_auth_manager_loaded(manager)

    user = await manager.async_create_user("Hello")
    assert user.is_admin

    user_cred = await manager.async_get_or_create_user(
        auth_models.Credentials(
            id="mock-id",
            auth_provider_type="insecure_example",
            auth_provider_id=None,
            data={"username": "******"},
            is_new=True,
        )
    )
    assert user_cred.is_admin
Ejemplo n.º 3
0
async def test_auth_module_expired_session(mock_hass):
    """Test login as existing user."""
    manager = await auth.auth_manager_from_config(
        mock_hass,
        [
            {
                "type": "insecure_example",
                "users": [
                    {
                        "username": "******",
                        "password": "******",
                        "name": "Test Name",
                    }
                ],
            }
        ],
        [
            {
                "type": "insecure_example",
                "data": [{"user_id": "mock-user", "pin": "test-pin"}],
            }
        ],
    )
    mock_hass.auth = manager
    ensure_auth_manager_loaded(manager)

    # Add fake user with credentials for example auth provider.
    user = MockUser(
        id="mock-user", is_owner=False, is_active=False, name="Paulus"
    ).add_to_auth_manager(manager)
    user.credentials.append(
        auth_models.Credentials(
            id="mock-id",
            auth_provider_type="insecure_example",
            auth_provider_id=None,
            data={"username": "******"},
            is_new=False,
        )
    )

    step = await manager.login_flow.async_init(("insecure_example", None))
    assert step["type"] == data_entry_flow.RESULT_TYPE_FORM

    step = await manager.login_flow.async_configure(
        step["flow_id"], {"username": "******", "password": "******"}
    )

    assert step["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert step["step_id"] == "mfa"

    with patch(
        "homeassistant.util.dt.utcnow",
        return_value=dt_util.utcnow() + MFA_SESSION_EXPIRATION,
    ):
        step = await manager.login_flow.async_configure(
            step["flow_id"], {"pin": "test-pin"}
        )
        # login flow abort due session timeout
        assert step["type"] == data_entry_flow.RESULT_TYPE_ABORT
        assert step["reason"] == "login_expired"
Ejemplo n.º 4
0
async def test_new_users_admin(mock_hass):
    """Test newly created users are admin."""
    manager = await auth.auth_manager_from_config(mock_hass, [{
        'type':
        'insecure_example',
        'users': [{
            'username': '******',
            'password': '******',
            'name': 'Test Name'
        }]
    }], [])
    ensure_auth_manager_loaded(manager)

    user = await manager.async_create_user('Hello')
    assert user.is_admin

    user_cred = await manager.async_get_or_create_user(
        auth_models.Credentials(
            id='mock-id',
            auth_provider_type='insecure_example',
            auth_provider_id=None,
            data={'username': '******'},
            is_new=True,
        ))
    assert user_cred.is_admin
Ejemplo n.º 5
0
async def test_new_users(mock_hass):
    """Test newly created users."""
    manager = await auth.auth_manager_from_config(
        mock_hass,
        [{
            "type":
            "insecure_example",
            "users": [
                {
                    "username": "******",
                    "password": "******",
                    "name": "Test Name",
                },
                {
                    "username": "******",
                    "password": "******",
                    "name": "Test Name",
                },
                {
                    "username": "******",
                    "password": "******",
                    "name": "Test Name",
                },
            ],
        }],
        [],
    )
    ensure_auth_manager_loaded(manager)

    user = await manager.async_create_user("Hello")
    # first user in the system is owner and admin
    assert user.is_owner
    assert user.is_admin
    assert not user.local_only
    assert user.groups == []

    user = await manager.async_create_user("Hello 2")
    assert not user.is_admin
    assert user.groups == []

    user = await manager.async_create_user("Hello 3",
                                           group_ids=["system-admin"],
                                           local_only=True)
    assert user.is_admin
    assert user.groups[0].id == "system-admin"
    assert user.local_only

    user_cred = await manager.async_get_or_create_user(
        auth_models.Credentials(
            id="mock-id",
            auth_provider_type="insecure_example",
            auth_provider_id=None,
            data={"username": "******"},
            is_new=True,
        ))
    assert user_cred.is_admin
Ejemplo n.º 6
0
async def test_auth_module_expired_session(mock_hass):
    """Test login as existing user."""
    manager = await auth.auth_manager_from_config(mock_hass, [{
        'type':
        'insecure_example',
        'users': [{
            'username': '******',
            'password': '******',
            'name': 'Test Name'
        }],
    }], [{
        'type': 'insecure_example',
        'data': [{
            'user_id': 'mock-user',
            'pin': 'test-pin'
        }]
    }])
    mock_hass.auth = manager
    ensure_auth_manager_loaded(manager)

    # Add fake user with credentials for example auth provider.
    user = MockUser(
        id='mock-user',
        is_owner=False,
        is_active=False,
        name='Paulus',
    ).add_to_auth_manager(manager)
    user.credentials.append(
        auth_models.Credentials(
            id='mock-id',
            auth_provider_type='insecure_example',
            auth_provider_id=None,
            data={'username': '******'},
            is_new=False,
        ))

    step = await manager.login_flow.async_init(('insecure_example', None))
    assert step['type'] == data_entry_flow.RESULT_TYPE_FORM

    step = await manager.login_flow.async_configure(step['flow_id'], {
        'username': '******',
        'password': '******',
    })

    assert step['type'] == data_entry_flow.RESULT_TYPE_FORM
    assert step['step_id'] == 'mfa'

    with patch('homeassistant.util.dt.utcnow',
               return_value=dt_util.utcnow() + SESSION_EXPIRATION):
        step = await manager.login_flow.async_configure(
            step['flow_id'], {
                'pin': 'test-pin',
            })
        # login flow abort due session timeout
        assert step['type'] == data_entry_flow.RESULT_TYPE_ABORT
        assert step['reason'] == 'login_expired'
Ejemplo n.º 7
0
async def test_async_remove_user(hass):
    """Test removing a user."""
    events = []

    @callback
    def user_removed(event):
        events.append(event)

    hass.bus.async_listen("user_removed", user_removed)

    manager = await auth.auth_manager_from_config(
        hass,
        [
            {
                "type": "insecure_example",
                "users": [
                    {
                        "username": "******",
                        "password": "******",
                        "name": "Test Name",
                    }
                ],
            }
        ],
        [],
    )
    hass.auth = manager
    ensure_auth_manager_loaded(manager)

    # Add fake user with credentials for example auth provider.
    user = MockUser(
        id="mock-user", is_owner=False, is_active=False, name="Paulus"
    ).add_to_auth_manager(manager)
    user.credentials.append(
        auth_models.Credentials(
            id="mock-id",
            auth_provider_type="insecure_example",
            auth_provider_id=None,
            data={"username": "******"},
            is_new=False,
        )
    )
    assert len(user.credentials) == 1

    await hass.auth.async_remove_user(user)

    assert len(await manager.async_get_users()) == 0
    assert len(user.credentials) == 0

    await hass.async_block_till_done()
    assert len(events) == 1
    assert events[0].data["user_id"] == user.id
Ejemplo n.º 8
0
async def test_not_raise_exception_when_service_not_exist(hass):
    """Test login flow will not raise exception when notify service error."""
    hass.auth = await auth_manager_from_config(
        hass, [{
            'type': 'insecure_example',
            'users': [{
                'username': '******',
                'password': '******'
            }],
        }], [{
            'type': 'notify',
        }])
    user = MockUser(
        id='mock-user',
        is_owner=False,
        is_active=False,
        name='Paulus',
    ).add_to_auth_manager(hass.auth)
    await hass.auth.async_link_user(
        user,
        auth_models.Credentials(
            id='mock-id',
            auth_provider_type='insecure_example',
            auth_provider_id=None,
            data={'username': '******'},
            is_new=False,
        ))

    await hass.auth.async_enable_user_mfa(user, 'notify', {
        'notify_service': 'invalid-notify',
    })

    provider = hass.auth.auth_providers[0]

    result = await hass.auth.login_flow.async_init(
        (provider.type, provider.id))
    assert result['type'] == data_entry_flow.RESULT_TYPE_FORM

    with patch('pyotp.HOTP.at', return_value=MOCK_CODE):
        result = await hass.auth.login_flow.async_configure(
            result['flow_id'], {
                'username': '******',
                'password': '******',
            })
        assert result['type'] == data_entry_flow.RESULT_TYPE_FORM
        assert result['step_id'] == 'mfa'
        assert result['data_schema'].schema.get('code') == str

    # wait service call finished
    await hass.async_block_till_done()
Ejemplo n.º 9
0
async def test_match_existing_credentials(store, provider):
    """See if we match existing users."""
    existing = auth_models.Credentials(
        id=uuid.uuid4(),
        auth_provider_type="insecure_example",
        auth_provider_id=None,
        data={"username": "******"},
        is_new=False,
    )
    provider.async_credentials = Mock(return_value=mock_coro([existing]))
    credentials = await provider.async_get_or_create_credentials(
        {"username": "******", "password": "******"}
    )
    assert credentials is existing
Ejemplo n.º 10
0
async def test_not_raise_exception_when_service_not_exist(hass):
    """Test login flow will not raise exception when notify service error."""
    hass.auth = await auth_manager_from_config(
        hass,
        [{
            "type": "insecure_example",
            "users": [{
                "username": "******",
                "password": "******"
            }],
        }],
        [{
            "type": "notify"
        }],
    )
    user = MockUser(id="mock-user",
                    is_owner=False,
                    is_active=False,
                    name="Paulus").add_to_auth_manager(hass.auth)
    await hass.auth.async_link_user(
        user,
        auth_models.Credentials(
            id="mock-id",
            auth_provider_type="insecure_example",
            auth_provider_id=None,
            data={"username": "******"},
            is_new=False,
        ),
    )

    await hass.auth.async_enable_user_mfa(user, "notify",
                                          {"notify_service": "invalid-notify"})

    provider = hass.auth.auth_providers[0]

    result = await hass.auth.login_flow.async_init(
        (provider.type, provider.id))
    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM

    with patch("pyotp.HOTP.at", return_value=MOCK_CODE):
        result = await hass.auth.login_flow.async_configure(
            result["flow_id"], {
                "username": "******",
                "password": "******"
            })
        assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
        assert result["reason"] == "unknown_error"

    # wait service call finished
    await hass.async_block_till_done()
Ejemplo n.º 11
0
async def test_async_remove_user(hass):
    """Test removing a user."""
    events = []

    @callback
    def user_removed(event):
        events.append(event)

    hass.bus.async_listen('user_removed', user_removed)

    manager = await auth.auth_manager_from_config(hass, [{
        'type':
        'insecure_example',
        'users': [{
            'username': '******',
            'password': '******',
            'name': 'Test Name'
        }]
    }], [])
    hass.auth = manager
    ensure_auth_manager_loaded(manager)

    # Add fake user with credentials for example auth provider.
    user = MockUser(
        id='mock-user',
        is_owner=False,
        is_active=False,
        name='Paulus',
    ).add_to_auth_manager(manager)
    user.credentials.append(
        auth_models.Credentials(
            id='mock-id',
            auth_provider_type='insecure_example',
            auth_provider_id=None,
            data={'username': '******'},
            is_new=False,
        ))
    assert len(user.credentials) == 1

    await hass.auth.async_remove_user(user)

    assert len(await manager.async_get_users()) == 0
    assert len(user.credentials) == 0

    await hass.async_block_till_done()
    assert len(events) == 1
    assert events[0].data['user_id'] == user.id
async def test_match_existing_credentials(store, provider):
    """See if we match existing users."""
    existing = auth_models.Credentials(
        id=uuid.uuid4(),
        auth_provider_type="command_line",
        auth_provider_id=None,
        data={"username": "******"},
        is_new=False,
    )
    provider.async_credentials = AsyncMock(return_value=[existing])
    credentials = await provider.async_get_or_create_credentials({
        "username":
        "******",
        "password":
        "******"
    })
    assert credentials is existing
Ejemplo n.º 13
0
async def test_refresh_token_provider_validation(mock_hass):
    """Test that creating access token from refresh token checks with provider."""
    manager = await auth.auth_manager_from_config(
        mock_hass,
        [
            {
                "type": "insecure_example",
                "users": [{"username": "******", "password": "******"}],
            }
        ],
        [],
    )

    credential = auth_models.Credentials(
        id="mock-credential-id",
        auth_provider_type="insecure_example",
        auth_provider_id=None,
        data={"username": "******"},
        is_new=False,
    )

    user = MockUser().add_to_auth_manager(manager)
    user.credentials.append(credential)
    refresh_token = await manager.async_create_refresh_token(
        user, CLIENT_ID, credential=credential
    )
    ip = "127.0.0.1"

    assert manager.async_create_access_token(refresh_token, ip) is not None

    with patch(
        "homeassistant.auth.providers.insecure_example.ExampleAuthProvider.async_validate_refresh_token",
        side_effect=InvalidAuthError("Invalid access"),
    ) as call:
        with pytest.raises(InvalidAuthError):
            manager.async_create_access_token(refresh_token, ip)

    call.assert_called_with(refresh_token, ip)
Ejemplo n.º 14
0
async def test_login_flow_validates_mfa(hass):
    """Test login flow with mfa enabled."""
    hass.auth = await auth_manager_from_config(
        hass,
        [{
            "type": "insecure_example",
            "users": [{
                "username": "******",
                "password": "******"
            }],
        }],
        [{
            "type": "notify"
        }],
    )
    user = MockUser(id="mock-user",
                    is_owner=False,
                    is_active=False,
                    name="Paulus").add_to_auth_manager(hass.auth)
    await hass.auth.async_link_user(
        user,
        auth_models.Credentials(
            id="mock-id",
            auth_provider_type="insecure_example",
            auth_provider_id=None,
            data={"username": "******"},
            is_new=False,
        ),
    )

    notify_calls = async_mock_service(hass, "notify", "test-notify",
                                      NOTIFY_SERVICE_SCHEMA)

    await hass.auth.async_enable_user_mfa(user, "notify",
                                          {"notify_service": "test-notify"})

    provider = hass.auth.auth_providers[0]

    result = await hass.auth.login_flow.async_init(
        (provider.type, provider.id))
    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM

    result = await hass.auth.login_flow.async_configure(
        result["flow_id"], {
            "username": "******",
            "password": "******"
        })
    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["errors"]["base"] == "invalid_auth"

    result = await hass.auth.login_flow.async_configure(
        result["flow_id"], {
            "username": "******",
            "password": "******"
        })
    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["errors"]["base"] == "invalid_auth"

    with patch("pyotp.HOTP.at", return_value=MOCK_CODE):
        result = await hass.auth.login_flow.async_configure(
            result["flow_id"], {
                "username": "******",
                "password": "******"
            })
        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "mfa"
        assert result["data_schema"].schema.get("code") == str

    # wait service call finished
    await hass.async_block_till_done()

    assert len(notify_calls) == 1
    notify_call = notify_calls[0]
    assert notify_call.domain == "notify"
    assert notify_call.service == "test-notify"
    message = notify_call.data["message"]
    message.hass = hass
    assert MOCK_CODE in message.async_render()

    with patch("pyotp.HOTP.verify", return_value=False):
        result = await hass.auth.login_flow.async_configure(
            result["flow_id"], {"code": "invalid-code"})
        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "mfa"
        assert result["errors"]["base"] == "invalid_code"

    # wait service call finished
    await hass.async_block_till_done()

    # would not send new code, allow user retry
    assert len(notify_calls) == 1

    # retry twice
    with patch("pyotp.HOTP.verify",
               return_value=False), patch("pyotp.HOTP.at",
                                          return_value=MOCK_CODE_2):
        result = await hass.auth.login_flow.async_configure(
            result["flow_id"], {"code": "invalid-code"})
        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "mfa"
        assert result["errors"]["base"] == "invalid_code"

        # after the 3rd failure, flow abort
        result = await hass.auth.login_flow.async_configure(
            result["flow_id"], {"code": "invalid-code"})
        assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
        assert result["reason"] == "too_many_retry"

    # wait service call finished
    await hass.async_block_till_done()

    # restart login
    result = await hass.auth.login_flow.async_init(
        (provider.type, provider.id))
    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM

    with patch("pyotp.HOTP.at", return_value=MOCK_CODE):
        result = await hass.auth.login_flow.async_configure(
            result["flow_id"], {
                "username": "******",
                "password": "******"
            })
        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "mfa"
        assert result["data_schema"].schema.get("code") == str

    # wait service call finished
    await hass.async_block_till_done()

    assert len(notify_calls) == 2
    notify_call = notify_calls[1]
    assert notify_call.domain == "notify"
    assert notify_call.service == "test-notify"
    message = notify_call.data["message"]
    message.hass = hass
    assert MOCK_CODE in message.async_render()

    with patch("pyotp.HOTP.verify", return_value=True):
        result = await hass.auth.login_flow.async_configure(
            result["flow_id"], {"code": MOCK_CODE})
        assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
        assert result["data"].id == "mock-id"
Ejemplo n.º 15
0
async def test_login_flow_validates_mfa(hass):
    """Test login flow with mfa enabled."""
    hass.auth = await auth_manager_from_config(
        hass, [{
            'type': 'insecure_example',
            'users': [{
                'username': '******',
                'password': '******'
            }],
        }], [{
            'type': 'notify',
        }])
    user = MockUser(
        id='mock-user',
        is_owner=False,
        is_active=False,
        name='Paulus',
    ).add_to_auth_manager(hass.auth)
    await hass.auth.async_link_user(
        user,
        auth_models.Credentials(
            id='mock-id',
            auth_provider_type='insecure_example',
            auth_provider_id=None,
            data={'username': '******'},
            is_new=False,
        ))

    notify_calls = async_mock_service(hass, 'notify', 'test-notify',
                                      NOTIFY_SERVICE_SCHEMA)

    await hass.auth.async_enable_user_mfa(user, 'notify', {
        'notify_service': 'test-notify',
    })

    provider = hass.auth.auth_providers[0]

    result = await hass.auth.login_flow.async_init(
        (provider.type, provider.id))
    assert result['type'] == data_entry_flow.RESULT_TYPE_FORM

    result = await hass.auth.login_flow.async_configure(
        result['flow_id'], {
            'username': '******',
            'password': '******',
        })
    assert result['type'] == data_entry_flow.RESULT_TYPE_FORM
    assert result['errors']['base'] == 'invalid_auth'

    result = await hass.auth.login_flow.async_configure(
        result['flow_id'], {
            'username': '******',
            'password': '******',
        })
    assert result['type'] == data_entry_flow.RESULT_TYPE_FORM
    assert result['errors']['base'] == 'invalid_auth'

    with patch('pyotp.HOTP.at', return_value=MOCK_CODE):
        result = await hass.auth.login_flow.async_configure(
            result['flow_id'], {
                'username': '******',
                'password': '******',
            })
        assert result['type'] == data_entry_flow.RESULT_TYPE_FORM
        assert result['step_id'] == 'mfa'
        assert result['data_schema'].schema.get('code') == str

    # wait service call finished
    await hass.async_block_till_done()

    assert len(notify_calls) == 1
    notify_call = notify_calls[0]
    assert notify_call.domain == 'notify'
    assert notify_call.service == 'test-notify'
    message = notify_call.data['message']
    message.hass = hass
    assert MOCK_CODE in message.async_render()

    with patch('pyotp.HOTP.verify', return_value=False):
        result = await hass.auth.login_flow.async_configure(
            result['flow_id'], {'code': 'invalid-code'})
        assert result['type'] == data_entry_flow.RESULT_TYPE_FORM
        assert result['step_id'] == 'mfa'
        assert result['errors']['base'] == 'invalid_code'

    # wait service call finished
    await hass.async_block_till_done()

    # would not send new code, allow user retry
    assert len(notify_calls) == 1

    # retry twice
    with patch('pyotp.HOTP.verify', return_value=False), \
            patch('pyotp.HOTP.at', return_value=MOCK_CODE_2):
        result = await hass.auth.login_flow.async_configure(
            result['flow_id'], {'code': 'invalid-code'})
        assert result['type'] == data_entry_flow.RESULT_TYPE_FORM
        assert result['step_id'] == 'mfa'
        assert result['errors']['base'] == 'invalid_code'

        # after the 3rd failure, flow abort
        result = await hass.auth.login_flow.async_configure(
            result['flow_id'], {'code': 'invalid-code'})
        assert result['type'] == data_entry_flow.RESULT_TYPE_ABORT
        assert result['reason'] == 'too_many_retry'

    # wait service call finished
    await hass.async_block_till_done()

    # restart login
    result = await hass.auth.login_flow.async_init(
        (provider.type, provider.id))
    assert result['type'] == data_entry_flow.RESULT_TYPE_FORM

    with patch('pyotp.HOTP.at', return_value=MOCK_CODE):
        result = await hass.auth.login_flow.async_configure(
            result['flow_id'], {
                'username': '******',
                'password': '******',
            })
        assert result['type'] == data_entry_flow.RESULT_TYPE_FORM
        assert result['step_id'] == 'mfa'
        assert result['data_schema'].schema.get('code') == str

    # wait service call finished
    await hass.async_block_till_done()

    assert len(notify_calls) == 2
    notify_call = notify_calls[1]
    assert notify_call.domain == 'notify'
    assert notify_call.service == 'test-notify'
    message = notify_call.data['message']
    message.hass = hass
    assert MOCK_CODE in message.async_render()

    with patch('pyotp.HOTP.verify', return_value=True):
        result = await hass.auth.login_flow.async_configure(
            result['flow_id'], {'code': MOCK_CODE})
        assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
        assert result['data'].id == 'mock-user'
Ejemplo n.º 16
0
async def test_login_with_multi_auth_module(mock_hass):
    """Test login as existing user with multiple auth modules."""
    manager = await auth.auth_manager_from_config(
        mock_hass,
        [{
            "type":
            "insecure_example",
            "users": [{
                "username": "******",
                "password": "******",
                "name": "Test Name",
            }],
        }],
        [
            {
                "type": "insecure_example",
                "data": [{
                    "user_id": "mock-user",
                    "pin": "test-pin"
                }],
            },
            {
                "type": "insecure_example",
                "id": "module2",
                "data": [{
                    "user_id": "mock-user",
                    "pin": "test-pin2"
                }],
            },
        ],
    )
    mock_hass.auth = manager
    ensure_auth_manager_loaded(manager)

    # Add fake user with credentials for example auth provider.
    user = MockUser(id="mock-user",
                    is_owner=False,
                    is_active=False,
                    name="Paulus").add_to_auth_manager(manager)
    user.credentials.append(
        auth_models.Credentials(
            id="mock-id",
            auth_provider_type="insecure_example",
            auth_provider_id=None,
            data={"username": "******"},
            is_new=False,
        ))

    step = await manager.login_flow.async_init(("insecure_example", None))
    assert step["type"] == data_entry_flow.RESULT_TYPE_FORM

    step = await manager.login_flow.async_configure(step["flow_id"], {
        "username": "******",
        "password": "******"
    })

    # After auth_provider validated, request select auth module
    assert step["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert step["step_id"] == "select_mfa_module"

    step = await manager.login_flow.async_configure(
        step["flow_id"], {"multi_factor_auth_module": "module2"})

    assert step["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert step["step_id"] == "mfa"

    step = await manager.login_flow.async_configure(step["flow_id"],
                                                    {"pin": "test-pin2"})

    # Finally passed, get credential
    assert step["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    assert step["result"]
    assert step["result"].id == "mock-id"
Ejemplo n.º 17
0
async def test_login_as_existing_user(mock_hass):
    """Test login as existing user."""
    manager = await auth.auth_manager_from_config(
        mock_hass,
        [{
            "type":
            "insecure_example",
            "users": [{
                "username": "******",
                "password": "******",
                "name": "Test Name",
            }],
        }],
        [],
    )
    mock_hass.auth = manager
    ensure_auth_manager_loaded(manager)

    # Add a fake user that we're not going to log in with
    user = MockUser(id="mock-user2",
                    is_owner=False,
                    is_active=False,
                    name="Not user").add_to_auth_manager(manager)
    user.credentials.append(
        auth_models.Credentials(
            id="mock-id2",
            auth_provider_type="insecure_example",
            auth_provider_id=None,
            data={"username": "******"},
            is_new=False,
        ))

    # Add fake user with credentials for example auth provider.
    user = MockUser(id="mock-user",
                    is_owner=False,
                    is_active=False,
                    name="Paulus").add_to_auth_manager(manager)
    user.credentials.append(
        auth_models.Credentials(
            id="mock-id",
            auth_provider_type="insecure_example",
            auth_provider_id=None,
            data={"username": "******"},
            is_new=False,
        ))

    step = await manager.login_flow.async_init(("insecure_example", None))
    assert step["type"] == data_entry_flow.RESULT_TYPE_FORM

    step = await manager.login_flow.async_configure(step["flow_id"], {
        "username": "******",
        "password": "******"
    })
    assert step["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY

    credential = step["result"]
    user = await manager.async_get_user_by_credentials(credential)
    assert user is not None
    assert user.id == "mock-user"
    assert user.is_owner is False
    assert user.is_active is False
    assert user.name == "Paulus"
Ejemplo n.º 18
0
async def test_list(hass, hass_ws_client, hass_admin_user):
    """Test get users."""
    group = MockGroup().add_to_hass(hass)

    owner = MockUser(id="abc",
                     name="Test Owner",
                     is_owner=True,
                     groups=[group]).add_to_hass(hass)

    owner.credentials.append(
        auth_models.Credentials(auth_provider_type="homeassistant",
                                auth_provider_id=None,
                                data={}))

    system = MockUser(id="efg", name="Test Hass.io",
                      system_generated=True).add_to_hass(hass)

    inactive = MockUser(id="hij",
                        name="Inactive User",
                        is_active=False,
                        groups=[group]).add_to_hass(hass)

    refresh_token = await hass.auth.async_create_refresh_token(
        owner, CLIENT_ID)
    access_token = hass.auth.async_create_access_token(refresh_token)

    client = await hass_ws_client(hass, access_token)
    await client.send_json({"id": 5, "type": auth_config.WS_TYPE_LIST})

    result = await client.receive_json()
    assert result["success"], result
    data = result["result"]
    assert len(data) == 4
    assert data[0] == {
        "id": hass_admin_user.id,
        "name": "Mock User",
        "is_owner": False,
        "is_active": True,
        "system_generated": False,
        "group_ids": [group.id for group in hass_admin_user.groups],
        "credentials": [],
    }
    assert data[1] == {
        "id": owner.id,
        "name": "Test Owner",
        "is_owner": True,
        "is_active": True,
        "system_generated": False,
        "group_ids": [group.id for group in owner.groups],
        "credentials": [{
            "type": "homeassistant"
        }],
    }
    assert data[2] == {
        "id": system.id,
        "name": "Test Hass.io",
        "is_owner": False,
        "is_active": True,
        "system_generated": True,
        "group_ids": [],
        "credentials": [],
    }
    assert data[3] == {
        "id": inactive.id,
        "name": "Inactive User",
        "is_owner": False,
        "is_active": False,
        "system_generated": False,
        "group_ids": [group.id for group in inactive.groups],
        "credentials": [],
    }
Ejemplo n.º 19
0
async def test_login_flow_validates_mfa(hass):
    """Test login flow with mfa enabled."""
    hass.auth = await auth_manager_from_config(
        hass, [{
            'type': 'insecure_example',
            'users': [{
                'username': '******',
                'password': '******'
            }],
        }], [{
            'type': 'totp',
        }])
    user = MockUser(
        id='mock-user',
        is_owner=False,
        is_active=False,
        name='Paulus',
    ).add_to_auth_manager(hass.auth)
    await hass.auth.async_link_user(
        user,
        auth_models.Credentials(
            id='mock-id',
            auth_provider_type='insecure_example',
            auth_provider_id=None,
            data={'username': '******'},
            is_new=False,
        ))

    await hass.auth.async_enable_user_mfa(user, 'totp', {})

    provider = hass.auth.auth_providers[0]

    result = await hass.auth.login_flow.async_init(
        (provider.type, provider.id))
    assert result['type'] == data_entry_flow.RESULT_TYPE_FORM

    result = await hass.auth.login_flow.async_configure(
        result['flow_id'], {
            'username': '******',
            'password': '******',
        })
    assert result['type'] == data_entry_flow.RESULT_TYPE_FORM
    assert result['errors']['base'] == 'invalid_auth'

    result = await hass.auth.login_flow.async_configure(
        result['flow_id'], {
            'username': '******',
            'password': '******',
        })
    assert result['type'] == data_entry_flow.RESULT_TYPE_FORM
    assert result['errors']['base'] == 'invalid_auth'

    result = await hass.auth.login_flow.async_configure(
        result['flow_id'], {
            'username': '******',
            'password': '******',
        })
    assert result['type'] == data_entry_flow.RESULT_TYPE_FORM
    assert result['step_id'] == 'mfa'
    assert result['data_schema'].schema.get('code') == str

    with patch('pyotp.TOTP.verify', return_value=False):
        result = await hass.auth.login_flow.async_configure(
            result['flow_id'], {'code': 'invalid-code'})
        assert result['type'] == data_entry_flow.RESULT_TYPE_FORM
        assert result['step_id'] == 'mfa'
        assert result['errors']['base'] == 'invalid_code'

    with patch('pyotp.TOTP.verify', return_value=True):
        result = await hass.auth.login_flow.async_configure(
            result['flow_id'], {'code': MOCK_CODE})
        assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
        assert result['data'].id == 'mock-user'
Ejemplo n.º 20
0
async def test_login_with_multi_auth_module(mock_hass):
    """Test login as existing user with multiple auth modules."""
    manager = await auth.auth_manager_from_config(mock_hass, [{
        'type':
        'insecure_example',
        'users': [{
            'username': '******',
            'password': '******',
            'name': 'Test Name'
        }],
    }], [{
        'type': 'insecure_example',
        'data': [{
            'user_id': 'mock-user',
            'pin': 'test-pin'
        }]
    }, {
        'type': 'insecure_example',
        'id': 'module2',
        'data': [{
            'user_id': 'mock-user',
            'pin': 'test-pin2'
        }]
    }])
    mock_hass.auth = manager
    ensure_auth_manager_loaded(manager)

    # Add fake user with credentials for example auth provider.
    user = MockUser(
        id='mock-user',
        is_owner=False,
        is_active=False,
        name='Paulus',
    ).add_to_auth_manager(manager)
    user.credentials.append(
        auth_models.Credentials(
            id='mock-id',
            auth_provider_type='insecure_example',
            auth_provider_id=None,
            data={'username': '******'},
            is_new=False,
        ))

    step = await manager.login_flow.async_init(('insecure_example', None))
    assert step['type'] == data_entry_flow.RESULT_TYPE_FORM

    step = await manager.login_flow.async_configure(step['flow_id'], {
        'username': '******',
        'password': '******',
    })

    # After auth_provider validated, request select auth module
    assert step['type'] == data_entry_flow.RESULT_TYPE_FORM
    assert step['step_id'] == 'select_mfa_module'

    step = await manager.login_flow.async_configure(
        step['flow_id'], {
            'multi_factor_auth_module': 'module2',
        })

    assert step['type'] == data_entry_flow.RESULT_TYPE_FORM
    assert step['step_id'] == 'mfa'

    step = await manager.login_flow.async_configure(step['flow_id'], {
        'pin': 'test-pin2',
    })

    # Finally passed, get user
    assert step['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    user = step['result']
    assert user is not None
    assert user.id == 'mock-user'
    assert user.is_owner is False
    assert user.is_active is False
    assert user.name == 'Paulus'
Ejemplo n.º 21
0
async def test_login_with_auth_module(mock_hass):
    """Test login as existing user with auth module."""
    manager = await auth.auth_manager_from_config(
        mock_hass,
        [{
            "type":
            "insecure_example",
            "users": [{
                "username": "******",
                "password": "******",
                "name": "Test Name",
            }],
        }],
        [{
            "type": "insecure_example",
            "data": [{
                "user_id": "mock-user",
                "pin": "test-pin"
            }],
        }],
    )
    mock_hass.auth = manager
    ensure_auth_manager_loaded(manager)

    # Add fake user with credentials for example auth provider.
    user = MockUser(id="mock-user",
                    is_owner=False,
                    is_active=False,
                    name="Paulus").add_to_auth_manager(manager)
    user.credentials.append(
        auth_models.Credentials(
            id="mock-id",
            auth_provider_type="insecure_example",
            auth_provider_id=None,
            data={"username": "******"},
            is_new=False,
        ))

    step = await manager.login_flow.async_init(("insecure_example", None))
    assert step["type"] == data_entry_flow.RESULT_TYPE_FORM

    step = await manager.login_flow.async_configure(step["flow_id"], {
        "username": "******",
        "password": "******"
    })

    # After auth_provider validated, request auth module input form
    assert step["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert step["step_id"] == "mfa"

    step = await manager.login_flow.async_configure(step["flow_id"],
                                                    {"pin": "invalid-pin"})

    # Invalid code error
    assert step["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert step["step_id"] == "mfa"
    assert step["errors"] == {"base": "invalid_code"}

    step = await manager.login_flow.async_configure(step["flow_id"],
                                                    {"pin": "test-pin"})

    # Finally passed, get user
    assert step["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    user = step["result"]
    assert user is not None
    assert user.id == "mock-user"
    assert user.is_owner is False
    assert user.is_active is False
    assert user.name == "Paulus"
Ejemplo n.º 22
0
async def test_list(hass, hass_ws_client, hass_admin_user):
    """Test get users."""
    group = MockGroup().add_to_hass(hass)

    owner = MockUser(
        id='abc',
        name='Test Owner',
        is_owner=True,
        groups=[group],
    ).add_to_hass(hass)

    owner.credentials.append(
        auth_models.Credentials(
            auth_provider_type='homeassistant',
            auth_provider_id=None,
            data={},
        ))

    system = MockUser(id='efg', name='Test Hass.io',
                      system_generated=True).add_to_hass(hass)

    inactive = MockUser(
        id='hij',
        name='Inactive User',
        is_active=False,
        groups=[group],
    ).add_to_hass(hass)

    refresh_token = await hass.auth.async_create_refresh_token(
        owner, CLIENT_ID)
    access_token = hass.auth.async_create_access_token(refresh_token)

    client = await hass_ws_client(hass, access_token)
    await client.send_json({
        'id': 5,
        'type': auth_config.WS_TYPE_LIST,
    })

    result = await client.receive_json()
    assert result['success'], result
    data = result['result']
    assert len(data) == 4
    assert data[0] == {
        'id': hass_admin_user.id,
        'name': 'Mock User',
        'is_owner': False,
        'is_active': True,
        'system_generated': False,
        'group_ids': [group.id for group in hass_admin_user.groups],
        'credentials': []
    }
    assert data[1] == {
        'id': owner.id,
        'name': 'Test Owner',
        'is_owner': True,
        'is_active': True,
        'system_generated': False,
        'group_ids': [group.id for group in owner.groups],
        'credentials': [{
            'type': 'homeassistant'
        }]
    }
    assert data[2] == {
        'id': system.id,
        'name': 'Test Hass.io',
        'is_owner': False,
        'is_active': True,
        'system_generated': True,
        'group_ids': [],
        'credentials': [],
    }
    assert data[3] == {
        'id': inactive.id,
        'name': 'Inactive User',
        'is_owner': False,
        'is_active': False,
        'system_generated': False,
        'group_ids': [group.id for group in inactive.groups],
        'credentials': [],
    }
Ejemplo n.º 23
0
async def test_login_flow_validates_mfa(hass):
    """Test login flow with mfa enabled."""
    hass.auth = await auth_manager_from_config(
        hass,
        [{
            "type": "insecure_example",
            "users": [{
                "username": "******",
                "password": "******"
            }],
        }],
        [{
            "type": "totp"
        }],
    )
    user = MockUser(id="mock-user",
                    is_owner=False,
                    is_active=False,
                    name="Paulus").add_to_auth_manager(hass.auth)
    await hass.auth.async_link_user(
        user,
        auth_models.Credentials(
            id="mock-id",
            auth_provider_type="insecure_example",
            auth_provider_id=None,
            data={"username": "******"},
            is_new=False,
        ),
    )

    await hass.auth.async_enable_user_mfa(user, "totp", {})

    provider = hass.auth.auth_providers[0]

    result = await hass.auth.login_flow.async_init(
        (provider.type, provider.id))
    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM

    result = await hass.auth.login_flow.async_configure(
        result["flow_id"], {
            "username": "******",
            "password": "******"
        })
    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["errors"]["base"] == "invalid_auth"

    result = await hass.auth.login_flow.async_configure(
        result["flow_id"], {
            "username": "******",
            "password": "******"
        })
    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["errors"]["base"] == "invalid_auth"

    result = await hass.auth.login_flow.async_configure(
        result["flow_id"], {
            "username": "******",
            "password": "******"
        })
    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "mfa"
    assert result["data_schema"].schema.get("code") == str

    with patch("pyotp.TOTP.verify", return_value=False):
        result = await hass.auth.login_flow.async_configure(
            result["flow_id"], {"code": "invalid-code"})
        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "mfa"
        assert result["errors"]["base"] == "invalid_code"

    with patch("pyotp.TOTP.verify", return_value=True):
        result = await hass.auth.login_flow.async_configure(
            result["flow_id"], {"code": MOCK_CODE})
        assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
        assert result["data"].id == "mock-id"