Add ipban for failed login attempt in new login flow (#15551)

* Add ipban for failed login attempt in new login flow

* Address review comment

* Use decorator to clean up code
This commit is contained in:
Jason Hu 2018-07-24 01:09:52 -07:00 committed by Paulus Schoutsen
parent 45c35ceb2b
commit d7690c5fda
2 changed files with 21 additions and 1 deletions

View File

@ -110,6 +110,8 @@ import aiohttp.web
import voluptuous as vol import voluptuous as vol
from homeassistant import data_entry_flow from homeassistant import data_entry_flow
from homeassistant.components.http.ban import process_wrong_login, \
log_invalid_auth
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.data_entry_flow import ( from homeassistant.helpers.data_entry_flow import (
FlowManagerIndexView, FlowManagerResourceView) FlowManagerIndexView, FlowManagerResourceView)
@ -183,6 +185,7 @@ class LoginFlowIndexView(FlowManagerIndexView):
vol.Required('handler'): vol.Any(str, list), vol.Required('handler'): vol.Any(str, list),
vol.Required('redirect_uri'): str, vol.Required('redirect_uri'): str,
})) }))
@log_invalid_auth
async def post(self, request, data): async def post(self, request, data):
"""Create a new login flow.""" """Create a new login flow."""
if not indieauth.verify_redirect_uri(data['client_id'], if not indieauth.verify_redirect_uri(data['client_id'],
@ -212,6 +215,7 @@ class LoginFlowResourceView(FlowManagerResourceView):
@RequestDataValidator(vol.Schema({ @RequestDataValidator(vol.Schema({
'client_id': str 'client_id': str
}, extra=vol.ALLOW_EXTRA)) }, extra=vol.ALLOW_EXTRA))
@log_invalid_auth
async def post(self, request, flow_id, data): async def post(self, request, flow_id, data):
"""Handle progressing a login flow request.""" """Handle progressing a login flow request."""
client_id = data.pop('client_id') client_id = data.pop('client_id')
@ -227,6 +231,11 @@ class LoginFlowResourceView(FlowManagerResourceView):
return self.json_message('User input malformed', 400) return self.json_message('User input malformed', 400)
if result['type'] != data_entry_flow.RESULT_TYPE_CREATE_ENTRY: if result['type'] != data_entry_flow.RESULT_TYPE_CREATE_ENTRY:
# @log_invalid_auth does not work here since it returns HTTP 200
# need manually log failed login attempts
if result['errors'] is not None and \
result['errors'].get('base') == 'invalid_auth':
await process_wrong_login(request)
return self.json(self._prepare_result_json(result)) return self.json(self._prepare_result_json(result))
result.pop('data') result.pop('data')
@ -247,6 +256,7 @@ class GrantTokenView(HomeAssistantView):
"""Initialize the grant token view.""" """Initialize the grant token view."""
self._retrieve_credentials = retrieve_credentials self._retrieve_credentials = retrieve_credentials
@log_invalid_auth
async def post(self, request): async def post(self, request):
"""Grant a token.""" """Grant a token."""
hass = request.app['hass'] hass = request.app['hass']

View File

@ -1,5 +1,4 @@
"""Ban logic for HTTP component.""" """Ban logic for HTTP component."""
from collections import defaultdict from collections import defaultdict
from datetime import datetime from datetime import datetime
from ipaddress import ip_address from ipaddress import ip_address
@ -71,6 +70,17 @@ async def ban_middleware(request, handler):
raise raise
def log_invalid_auth(func):
"""Decorator to handle invalid auth or failed login attempts."""
async def handle_req(view, request, *args, **kwargs):
"""Try to log failed login attempts if response status >= 400."""
resp = await func(view, request, *args, **kwargs)
if resp.status >= 400:
await process_wrong_login(request)
return resp
return handle_req
async def process_wrong_login(request): async def process_wrong_login(request):
"""Process a wrong login attempt. """Process a wrong login attempt.