Fix reporting on bad login (#6201)
This commit is contained in:
parent
df5866dd95
commit
d6818c7015
5 changed files with 28 additions and 23 deletions
|
@ -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)',
|
||||
|
|
|
@ -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] >
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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'})
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue