Fix reporting on bad login (#6201)

This commit is contained in:
Paulus Schoutsen 2017-02-24 16:33:58 -08:00 committed by GitHub
parent df5866dd95
commit d6818c7015
5 changed files with 28 additions and 23 deletions

View file

@ -19,7 +19,6 @@ from aiohttp.web_exceptions import HTTPUnauthorized, HTTPMovedPermanently
import homeassistant.helpers.config_validation as cv
import homeassistant.remote as rem
import homeassistant.util as hass_util
from homeassistant.components import persistent_notification
from homeassistant.const import (
SERVER_PORT, CONTENT_TYPE_JSON, ALLOWED_CORS_HEADERS,
EVENT_HOMEASSISTANT_STOP, EVENT_HOMEASSISTANT_START)
@ -27,7 +26,7 @@ from homeassistant.core import is_callback
from homeassistant.util.logging import HideSensitiveDataFilter
from .auth import auth_middleware
from .ban import ban_middleware, process_wrong_login
from .ban import ban_middleware
from .const import (
KEY_USE_X_FORWARDED_FOR, KEY_TRUSTED_NETWORKS,
KEY_BANS_ENABLED, KEY_LOGIN_THRESHOLD,
@ -51,8 +50,6 @@ CONF_TRUSTED_NETWORKS = 'trusted_networks'
CONF_LOGIN_ATTEMPTS_THRESHOLD = 'login_attempts_threshold'
CONF_IP_BAN_ENABLED = 'ip_ban_enabled'
NOTIFICATION_ID_LOGIN = 'http-login'
# TLS configuation follows the best-practice guidelines specified here:
# https://wiki.mozilla.org/Security/Server_Side_TLS
# Intermediate guidelines are followed.
@ -409,13 +406,6 @@ def request_handler_factory(view, handler):
authenticated = request.get(KEY_AUTHENTICATED, False)
if view.requires_auth and not authenticated:
yield from process_wrong_login(request)
_LOGGER.warning('Login attempt or request with an invalid '
'password from %s', remote_addr)
persistent_notification.async_create(
request.app['hass'],
'Invalid password used from {}'.format(remote_addr),
'Login attempt failed', NOTIFICATION_ID_LOGIN)
raise HTTPUnauthorized()
_LOGGER.info('Serving %s to %s (auth: %s)',

View file

@ -5,7 +5,7 @@ from datetime import datetime
from ipaddress import ip_address
import logging
from aiohttp.web_exceptions import HTTPForbidden
from aiohttp.web_exceptions import HTTPForbidden, HTTPUnauthorized
import voluptuous as vol
from homeassistant.components import persistent_notification
@ -19,6 +19,7 @@ from .const import (
from .util import get_real_ip
NOTIFICATION_ID_BAN = 'ip-ban'
NOTIFICATION_ID_LOGIN = 'http-login'
IP_BANS_FILE = 'ip_bans.yaml'
ATTR_BANNED_AT = "banned_at"
@ -52,7 +53,11 @@ def ban_middleware(app, handler):
if is_banned:
raise HTTPForbidden()
return handler(request)
try:
return (yield from handler(request))
except HTTPUnauthorized:
yield from process_wrong_login(request)
raise
return ban_middleware_handler
@ -60,6 +65,15 @@ def ban_middleware(app, handler):
@asyncio.coroutine
def process_wrong_login(request):
"""Process a wrong login attempt."""
remote_addr = get_real_ip(request)
msg = ('Login attempt or request with invalid authentication '
'from {}'.format(remote_addr))
_LOGGER.warning(msg)
persistent_notification.async_create(
request.app['hass'], msg, 'Login attempt failed',
NOTIFICATION_ID_LOGIN)
if (not request.app[KEY_BANS_ENABLED] or
request.app[KEY_LOGIN_THRESHOLD] < 1):
return
@ -67,8 +81,6 @@ def process_wrong_login(request):
if KEY_FAILED_LOGIN_ATTEMPTS not in request.app:
request.app[KEY_FAILED_LOGIN_ATTEMPTS] = defaultdict(int)
remote_addr = get_real_ip(request)
request.app[KEY_FAILED_LOGIN_ATTEMPTS][remote_addr] += 1
if (request.app[KEY_FAILED_LOGIN_ATTEMPTS][remote_addr] >

View file

@ -18,6 +18,7 @@ from homeassistant.helpers import config_validation as cv
from homeassistant.components.http import HomeAssistantView
from homeassistant.components.http.auth import validate_password
from homeassistant.components.http.const import KEY_AUTHENTICATED
from homeassistant.components.http.ban import process_wrong_login
DOMAIN = 'websocket_api'
@ -256,9 +257,9 @@ class ActiveConnection:
else:
self.debug('Invalid password')
self.send_message(auth_invalid_message('Invalid password'))
return wsock
if not authenticated:
yield from process_wrong_login(self.request)
return wsock
self.send_message(auth_ok_message())

View file

@ -97,7 +97,6 @@ class TestHttp:
with patch('homeassistant.components.http.'
'ban.get_real_ip',
return_value=ip_address("200.201.202.204")):
print("GETTING API")
return requests.get(
_url(const.URL_API),
headers={const.HTTP_HEADER_HA_AUTH: 'Wrong password'})

View file

@ -9,7 +9,7 @@ import pytest
from homeassistant.core import callback
from homeassistant.components import websocket_api as wapi, frontend
from tests.common import mock_http_component_app
from tests.common import mock_http_component_app, mock_coro
API_PASSWORD = 'test1234'
@ -66,13 +66,16 @@ def test_auth_via_msg(no_auth_websocket_client):
@asyncio.coroutine
def test_auth_via_msg_incorrect_pass(no_auth_websocket_client):
"""Test authenticating."""
no_auth_websocket_client.send_json({
'type': wapi.TYPE_AUTH,
'api_password': API_PASSWORD + 'wrong'
})
with patch('homeassistant.components.websocket_api.process_wrong_login',
return_value=mock_coro()) as mock_process_wrong_login:
no_auth_websocket_client.send_json({
'type': wapi.TYPE_AUTH,
'api_password': API_PASSWORD + 'wrong'
})
msg = yield from no_auth_websocket_client.receive_json()
msg = yield from no_auth_websocket_client.receive_json()
assert mock_process_wrong_login.called
assert msg['type'] == wapi.TYPE_AUTH_INVALID
assert msg['message'] == 'Invalid password'