David Vidal
8 years ago
committed by
Jairo Llopis
15 changed files with 161 additions and 470 deletions
-
53auth_brute_force/README.rst
-
1auth_brute_force/__init__.py
-
27auth_brute_force/__manifest__.py
-
42auth_brute_force/__openerp__.py
-
3auth_brute_force/controllers/__init__.py
-
104auth_brute_force/controllers/controllers.py
-
76auth_brute_force/controllers/main.py
-
26auth_brute_force/data/ir_config_parameter.xml
-
150auth_brute_force/i18n/auth_brute_force.pot
-
1auth_brute_force/models/__init__.py
-
30auth_brute_force/models/res_authentication_attempt.py
-
38auth_brute_force/models/res_banned_remote.py
-
26auth_brute_force/views/action.xml
-
26auth_brute_force/views/menu.xml
-
26auth_brute_force/views/view.xml
@ -1,3 +1,4 @@ |
|||||
# -*- encoding: utf-8 -*- |
# -*- encoding: utf-8 -*- |
||||
|
|
||||
from . import models |
from . import models |
||||
from . import controllers |
from . import controllers |
@ -0,0 +1,27 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2015 GRAP - Sylvain LE GAL |
||||
|
# Copyright 2017 Tecnativa - David Vidal |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
{ |
||||
|
'name': 'Authentification - Brute-force Attack', |
||||
|
'version': '10.0.1.0.0', |
||||
|
'category': 'Tools', |
||||
|
'summary': "Tracks Authentication Attempts and Prevents Brute-force" |
||||
|
" Attacks module", |
||||
|
'author': "GRAP, " |
||||
|
"Tecnativa, " |
||||
|
"Odoo Community Association (OCA)", |
||||
|
'website': 'http://www.grap.coop', |
||||
|
'license': 'AGPL-3', |
||||
|
'depends': [ |
||||
|
'web', |
||||
|
], |
||||
|
'data': [ |
||||
|
'security/ir_model_access.yml', |
||||
|
'data/ir_config_parameter.xml', |
||||
|
'views/view.xml', |
||||
|
'views/action.xml', |
||||
|
'views/menu.xml', |
||||
|
], |
||||
|
'installable': True, |
||||
|
} |
@ -1,42 +0,0 @@ |
|||||
# -*- encoding: utf-8 -*- |
|
||||
############################################################################## |
|
||||
# |
|
||||
# Tracks Authentication Attempts and Prevents Brute-force Attacks module |
|
||||
# Copyright (C) 2015-Today GRAP (http://www.grap.coop) |
|
||||
# @author Sylvain LE GAL (https://twitter.com/legalsylvain) |
|
||||
# |
|
||||
# This program is free software: you can redistribute it and/or modify |
|
||||
# it under the terms of the GNU Affero General Public License as |
|
||||
# published by the Free Software Foundation, either version 3 of the |
|
||||
# License, or (at your option) any later version. |
|
||||
# |
|
||||
# This program is distributed in the hope that it will be useful, |
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
# GNU Affero General Public License for more details. |
|
||||
# |
|
||||
# You should have received a copy of the GNU Affero General Public License |
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
||||
# |
|
||||
############################################################################## |
|
||||
|
|
||||
{ |
|
||||
'name': 'Authentification - Brute-force Attack', |
|
||||
'version': '8.0.1.0.0', |
|
||||
'category': 'base', |
|
||||
'summary': "Tracks Authentication Attempts and Prevents Brute-force" |
|
||||
" Attacks module", |
|
||||
'author': "GRAP,Odoo Community Association (OCA)", |
|
||||
'website': 'http://www.grap.coop', |
|
||||
'license': 'AGPL-3', |
|
||||
'depends': [ |
|
||||
'web', |
|
||||
], |
|
||||
'data': [ |
|
||||
'security/ir_model_access.yml', |
|
||||
'data/ir_config_parameter.xml', |
|
||||
'views/view.xml', |
|
||||
'views/action.xml', |
|
||||
'views/menu.xml', |
|
||||
], |
|
||||
} |
|
@ -1,2 +1,3 @@ |
|||||
# -*- coding: utf-8 -*- |
# -*- coding: utf-8 -*- |
||||
from . import controllers |
|
||||
|
|
||||
|
from . import main |
@ -1,104 +0,0 @@ |
|||||
# -*- encoding: utf-8 -*- |
|
||||
############################################################################## |
|
||||
# |
|
||||
# Tracks Authentication Attempts and Prevents Brute-force Attacks module |
|
||||
# Copyright (C) 2015-Today GRAP (http://www.grap.coop) |
|
||||
# @author Sylvain LE GAL (https://twitter.com/legalsylvain) |
|
||||
# |
|
||||
# This program is free software: you can redistribute it and/or modify |
|
||||
# it under the terms of the GNU Affero General Public License as |
|
||||
# published by the Free Software Foundation, either version 3 of the |
|
||||
# License, or (at your option) any later version. |
|
||||
# |
|
||||
# This program is distributed in the hope that it will be useful, |
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
# GNU Affero General Public License for more details. |
|
||||
# |
|
||||
# You should have received a copy of the GNU Affero General Public License |
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
||||
# |
|
||||
############################################################################## |
|
||||
|
|
||||
import logging |
|
||||
|
|
||||
from openerp import fields, http, registry, SUPERUSER_ID |
|
||||
from openerp.http import request |
|
||||
from openerp.addons.web.controllers.main import Home, ensure_db |
|
||||
|
|
||||
_logger = logging.getLogger(__name__) |
|
||||
|
|
||||
|
|
||||
class LoginController(Home): |
|
||||
@http.route() |
|
||||
def web_login(self, redirect=None, **kw): |
|
||||
if request.httprequest.method == 'POST': |
|
||||
ensure_db() |
|
||||
remote = request.httprequest.remote_addr |
|
||||
# Get registry and cursor |
|
||||
config_obj = registry(request.session.db)['ir.config_parameter'] |
|
||||
attempt_obj = registry( |
|
||||
request.session.db)['res.authentication.attempt'] |
|
||||
banned_remote_obj = registry( |
|
||||
request.session.db)['res.banned.remote'] |
|
||||
cursor = attempt_obj.pool.cursor() |
|
||||
|
|
||||
# Get Settings |
|
||||
max_attempts_qty = int(config_obj.search_read( |
|
||||
cursor, SUPERUSER_ID, |
|
||||
[('key', '=', 'auth_brute_force.max_attempt_qty')], |
|
||||
['value'])[0]['value']) |
|
||||
|
|
||||
# Test if remote user is banned |
|
||||
banned = banned_remote_obj.search(cursor, SUPERUSER_ID, [ |
|
||||
('remote', '=', remote)]) |
|
||||
if banned: |
|
||||
_logger.warning( |
|
||||
"Authentication tried from remote '%s'. The request has" |
|
||||
" been ignored because the remote has been banned after" |
|
||||
" %d attempts without success. Login tried : '%s'." % ( |
|
||||
remote, max_attempts_qty, request.params['login'])) |
|
||||
request.params['password'] = '' |
|
||||
|
|
||||
else: |
|
||||
# Try to authenticate |
|
||||
result = request.session.authenticate( |
|
||||
request.session.db, request.params['login'], |
|
||||
request.params['password']) |
|
||||
|
|
||||
# Log attempt |
|
||||
cursor.commit() |
|
||||
attempt_obj.create(cursor, SUPERUSER_ID, { |
|
||||
'attempt_date': fields.Datetime.now(), |
|
||||
'login': request.params['login'], |
|
||||
'remote': remote, |
|
||||
'result': banned and 'banned' or ( |
|
||||
result and 'successfull' or 'failed'), |
|
||||
}) |
|
||||
cursor.commit() |
|
||||
if not banned and not result: |
|
||||
# Get last bad attempts quantity |
|
||||
attempts_qty = len(attempt_obj.search_last_failed( |
|
||||
cursor, SUPERUSER_ID, remote)) |
|
||||
|
|
||||
if max_attempts_qty <= attempts_qty: |
|
||||
# We ban the remote |
|
||||
_logger.warning( |
|
||||
"Authentication failed from remote '%s'. " |
|
||||
"The remote has been banned. Login tried : '%s'." % ( |
|
||||
remote, request.params['login'])) |
|
||||
banned_remote_obj.create(cursor, SUPERUSER_ID, { |
|
||||
'remote': remote, |
|
||||
'ban_date': fields.Datetime.now(), |
|
||||
}) |
|
||||
cursor.commit() |
|
||||
|
|
||||
else: |
|
||||
_logger.warning( |
|
||||
"Authentication failed from remote '%s'." |
|
||||
" Login tried : '%s'. Attempt %d / %d." % ( |
|
||||
remote, request.params['login'], attempts_qty, |
|
||||
max_attempts_qty)) |
|
||||
cursor.close() |
|
||||
|
|
||||
return super(LoginController, self).web_login(redirect=redirect, **kw) |
|
@ -0,0 +1,76 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2015 GRAP - Sylvain LE GAL |
||||
|
# Copyright 2017 Tecnativa - David Vidal |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
import logging |
||||
|
|
||||
|
from odoo import fields, http, registry, SUPERUSER_ID |
||||
|
from odoo.api import Environment |
||||
|
from odoo.http import request |
||||
|
from odoo.addons.web.controllers.main import Home, ensure_db |
||||
|
|
||||
|
_logger = logging.getLogger(__name__) |
||||
|
|
||||
|
|
||||
|
class LoginController(Home): |
||||
|
|
||||
|
@http.route() |
||||
|
def web_login(self, redirect=None, **kw): |
||||
|
if request.httprequest.method == 'POST': |
||||
|
ensure_db() |
||||
|
remote = request.httprequest.remote_addr |
||||
|
# Get registry and cursor |
||||
|
with registry(request.session.db).cursor() as cursor: |
||||
|
env = Environment(cursor, SUPERUSER_ID, {}) |
||||
|
config_obj = env['ir.config_parameter'] |
||||
|
attempt_obj = env['res.authentication.attempt'] |
||||
|
banned_remote_obj = env['res.banned.remote'] |
||||
|
# Get Settings |
||||
|
max_attempts_qty = int(config_obj.get_param( |
||||
|
'auth_brute_force.max_attempt_qty')) |
||||
|
# Test if remote user is banned |
||||
|
banned = banned_remote_obj.search([('remote', '=', remote)]) |
||||
|
if banned: |
||||
|
request.params['password'] = '' |
||||
|
_logger.warning( |
||||
|
"Authentication tried from remote '%s'. The request " |
||||
|
"has been ignored because the remote has been banned " |
||||
|
"after %d attempts without success. Login tried : '%s'" |
||||
|
"." % (remote, max_attempts_qty, |
||||
|
request.params['login'])) |
||||
|
else: |
||||
|
# Try to authenticate |
||||
|
result = request.session.authenticate( |
||||
|
request.session.db, request.params['login'], |
||||
|
request.params['password']) |
||||
|
# Log attempt |
||||
|
attempt_obj.create({ |
||||
|
'attempt_date': fields.Datetime.now(), |
||||
|
'login': request.params['login'], |
||||
|
'remote': remote, |
||||
|
'result': banned and 'banned' or ( |
||||
|
result and 'successfull' or 'failed'), |
||||
|
}) |
||||
|
cursor.commit() |
||||
|
if not banned and not result: |
||||
|
# Get last bad attempts quantity |
||||
|
attempts_qty = len(attempt_obj.search_last_failed(remote)) |
||||
|
if max_attempts_qty <= attempts_qty: |
||||
|
# We ban the remote |
||||
|
_logger.warning( |
||||
|
"Authentication failed from remote '%s'. " |
||||
|
"The remote has been banned. Login tried : '%s'" |
||||
|
"." % (remote, request.params['login'])) |
||||
|
banned_remote_obj.sudo().create({ |
||||
|
'remote': remote, |
||||
|
'ban_date': fields.Datetime.now(), |
||||
|
}) |
||||
|
cursor.commit() |
||||
|
else: |
||||
|
_logger.warning( |
||||
|
"Authentication failed from remote '%s'." |
||||
|
" Login tried : '%s'. Attempt %d / %d." % ( |
||||
|
remote, request.params['login'], attempts_qty, |
||||
|
max_attempts_qty)) |
||||
|
return super(LoginController, self).web_login(redirect=redirect, **kw) |
@ -1,150 +0,0 @@ |
|||||
# Translation of Odoo Server. |
|
||||
# This file contains the translation of the following modules: |
|
||||
# * auth_brute_force |
|
||||
# |
|
||||
msgid "" |
|
||||
msgstr "" |
|
||||
"Project-Id-Version: Odoo Server 8.0\n" |
|
||||
"Report-Msgid-Bugs-To: \n" |
|
||||
"POT-Creation-Date: 2015-09-26 00:39+0000\n" |
|
||||
"PO-Revision-Date: 2015-09-26 00:39+0000\n" |
|
||||
"Last-Translator: <>\n" |
|
||||
"Language-Team: \n" |
|
||||
"MIME-Version: 1.0\n" |
|
||||
"Content-Type: text/plain; charset=UTF-8\n" |
|
||||
"Content-Transfer-Encoding: \n" |
|
||||
"Plural-Forms: \n" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: code:addons/auth_brute_force/models/res_banned_remote.py:75 |
|
||||
#, python-format |
|
||||
msgid "%s %s - %s %s (ISP: %s)" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: field:res.banned.remote,active:0 |
|
||||
msgid "Active" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: field:res.authentication.attempt,attempt_date:0 |
|
||||
msgid "Attempt Date" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: model:ir.actions.act_window,name:auth_brute_force.action_res_authentication_attempt |
|
||||
#: model:ir.ui.menu,name:auth_brute_force.menu_res_authentication_attempt |
|
||||
msgid "Authentication Attempts" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: field:res.authentication.attempt,result:0 |
|
||||
msgid "Authentication Result" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: field:res.banned.remote,ban_date:0 |
|
||||
msgid "Ban Date" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: code:addons/auth_brute_force/models/res_authentication_attempt.py:34 |
|
||||
#: view:res.authentication.attempt:auth_brute_force.view_res_authentication_attempt_search |
|
||||
#: selection:res.authentication.attempt,result:0 |
|
||||
#, python-format |
|
||||
msgid "Banned" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: model:ir.actions.act_window,name:auth_brute_force.action_res_banned_remote |
|
||||
#: model:ir.ui.menu,name:auth_brute_force.menu_res_banned_remote |
|
||||
msgid "Banned Remotes" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: field:res.authentication.attempt,create_uid:0 |
|
||||
#: field:res.banned.remote,create_uid:0 |
|
||||
msgid "Created by" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: field:res.authentication.attempt,create_date:0 |
|
||||
#: field:res.banned.remote,create_date:0 |
|
||||
msgid "Created on" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: code:addons/auth_brute_force/models/res_authentication_attempt.py:33 |
|
||||
#: view:res.authentication.attempt:auth_brute_force.view_res_authentication_attempt_search |
|
||||
#: selection:res.authentication.attempt,result:0 |
|
||||
#, python-format |
|
||||
msgid "Failed" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: field:res.authentication.attempt,id:0 |
|
||||
#: field:res.banned.remote,id:0 |
|
||||
msgid "ID" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: field:res.authentication.attempt,write_uid:0 |
|
||||
#: field:res.banned.remote,write_uid:0 |
|
||||
msgid "Last Updated by" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: field:res.authentication.attempt,write_date:0 |
|
||||
#: field:res.banned.remote,write_date:0 |
|
||||
msgid "Last Updated on" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: field:res.banned.remote,name:0 |
|
||||
msgid "Name" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: field:res.banned.remote,description:0 |
|
||||
msgid "Remote Description" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: field:res.authentication.attempt,remote:0 |
|
||||
#: field:res.banned.remote,remote:0 |
|
||||
msgid "Remote ID" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: view:res.authentication.attempt:auth_brute_force.view_res_authentication_attempt_search |
|
||||
msgid "Successful" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: code:addons/auth_brute_force/models/res_authentication_attempt.py:32 |
|
||||
#: selection:res.authentication.attempt,result:0 |
|
||||
#, python-format |
|
||||
msgid "Successfull" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: field:res.authentication.attempt,login:0 |
|
||||
msgid "Tried Login" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: help:res.banned.remote,active:0 |
|
||||
msgid "Uncheck this box to unban the remote" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: code:addons/auth_brute_force/models/res_banned_remote.py:77 |
|
||||
#, python-format |
|
||||
msgid "Unidentified Call from %s" |
|
||||
msgstr "" |
|
||||
|
|
||||
#. module: auth_brute_force |
|
||||
#: view:res.authentication.attempt:auth_brute_force.view_res_authentication_attempt_search |
|
||||
msgid "Without Success" |
|
||||
msgstr "" |
|
||||
|
|
@ -1,3 +1,4 @@ |
|||||
# -*- encoding: utf-8 -*- |
# -*- encoding: utf-8 -*- |
||||
|
|
||||
from . import res_banned_remote |
from . import res_banned_remote |
||||
from . import res_authentication_attempt |
from . import res_authentication_attempt |
Write
Preview
Loading…
Cancel
Save
Reference in new issue