Sylvain LE GAL
9 years ago
committed by
Jairo Llopis
18 changed files with 893 additions and 0 deletions
-
114auth_brute_force/README.rst
-
3auth_brute_force/__init__.py
-
42auth_brute_force/__openerp__.py
-
2auth_brute_force/controllers/__init__.py
-
104auth_brute_force/controllers/controllers.py
-
29auth_brute_force/data/ir_config_parameter.xml
-
150auth_brute_force/i18n/auth_brute_force.pot
-
120auth_brute_force/i18n/fr.po
-
3auth_brute_force/models/__init__.py
-
58auth_brute_force/models/res_authentication_attempt.py
-
71auth_brute_force/models/res_banned_remote.py
-
28auth_brute_force/security/ir_model_access.yml
-
BINauth_brute_force/static/description/icon.png
-
BINauth_brute_force/static/description/screenshot_attempts_list.png
-
BINauth_brute_force/static/description/screenshot_custom_ban.png
-
39auth_brute_force/views/action.xml
-
32auth_brute_force/views/menu.xml
-
98auth_brute_force/views/view.xml
@ -0,0 +1,114 @@ |
|||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg |
|||
:alt: License |
|||
|
|||
=============================================================== |
|||
Tracks Authentication Attempts and Prevents Brute-force Attacks |
|||
=============================================================== |
|||
|
|||
This module registers each request done by users trying to authenticate into |
|||
Odoo. If the authentication fails, a counter is increased for the given remote |
|||
IP. After a defined number of attempts, Odoo will ban the remote IP and |
|||
ignore new requests. |
|||
This module applies security through obscurity |
|||
(https://en.wikipedia.org/wiki/Security_through_obscurity), |
|||
When a user is banned, the request is now considered as an attack. So, the UI |
|||
will **not** indicate to the user that his IP is banned and the regular message |
|||
'Wrong login/password' is displayed. |
|||
|
|||
This module realizes a call to a web API (http://ip-api.com) to try to have |
|||
extra information about remote IP. |
|||
|
|||
Known issue / Roadmap |
|||
--------------------- |
|||
The ID used to identify a remote request is the IP provided in the request |
|||
(key 'REMOTE_ADDR'). |
|||
Depending of server and / or user network configuration, the idenfication |
|||
of the user can be wrong, and mainly in the following cases: |
|||
|
|||
* if the Odoo server is behind an Apache / NGinx proxy without redirection, |
|||
all the request will be have the value '127.0.0.1' for the REMOTE_ADDR key; |
|||
* If some users are behind the same Internet Service Provider, if a user is |
|||
banned, all the other users will be banned too; |
|||
|
|||
Configuration |
|||
------------- |
|||
|
|||
Once installed, you can change the ir.config_parameter value for the key |
|||
'auth_brute_force.max_attempt_qty' (10 by default) that define the max number |
|||
of attempts allowed before the user was banned. |
|||
|
|||
Usage |
|||
----- |
|||
|
|||
Admin user have the possibility to unblock a banned IP. |
|||
|
|||
Logging |
|||
------- |
|||
|
|||
This module generates some WARNING logs, in the three following cases: |
|||
|
|||
* Authentication failed from remote '127.0.0.1'. Login tried : 'admin'. |
|||
Attempt 1 / 10. |
|||
|
|||
* Authentication failed from remote '127.0.0.1'. The remote has been banned. |
|||
Login tried : 'admin'. |
|||
|
|||
* Authentication tried from remote '127.0.0.1'. The request has been ignored |
|||
because the remote has been banned after 10 attempts without success. Login |
|||
tried : 'admin'. |
|||
|
|||
Screenshot |
|||
---------- |
|||
|
|||
**List of Attempts** |
|||
|
|||
.. image:: /auth_brute_force/static/description/screenshot_attempts_list.png |
|||
|
|||
**Detail of a banned IP** |
|||
|
|||
.. image:: /auth_brute_force/static/description/screenshot_custom_ban.png |
|||
|
|||
|
|||
Usage |
|||
===== |
|||
|
|||
* go to ... |
|||
|
|||
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas |
|||
:alt: Try me on Runbot |
|||
:target: https://runbot.odoo-community.org/runbot/149/8.0 |
|||
|
|||
For further information, please visit: |
|||
|
|||
* https://www.odoo.com/forum/help-1 |
|||
|
|||
Bug Tracker |
|||
=========== |
|||
|
|||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/web/issues>`_. |
|||
In case of trouble, please check there if your issue has already been reported. |
|||
If you spotted it first, help us smashing it by providing a detailed and welcomed feedback |
|||
`here <https://github.com/OCA/web/issues/new?body=module:%20auth_brute_force%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. |
|||
|
|||
Credits |
|||
======= |
|||
|
|||
Contributors |
|||
------------ |
|||
|
|||
* Sylvain LE GAL (https://twitter.com/legalsylvain) |
|||
|
|||
Maintainer |
|||
---------- |
|||
|
|||
.. image:: http://odoo-community.org/logo.png |
|||
:alt: Odoo Community Association |
|||
:target: http://odoo-community.org |
|||
|
|||
This module is maintained by the OCA. |
|||
|
|||
OCA, or the Odoo Community Association, is a nonprofit organization whose |
|||
mission is to support the collaborative development of Odoo features and |
|||
promote its widespread use. |
|||
|
|||
To contribute to this module, please visit http://odoo-community.org. |
@ -0,0 +1,3 @@ |
|||
# -*- encoding: utf-8 -*- |
|||
from . import models |
|||
from . import controllers |
@ -0,0 +1,42 @@ |
|||
# -*- 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', |
|||
], |
|||
} |
@ -0,0 +1,2 @@ |
|||
# -*- coding: utf-8 -*- |
|||
from . import controllers |
@ -0,0 +1,104 @@ |
|||
# -*- 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,29 @@ |
|||
<?xml version="1.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/>. --> |
|||
<!-- ********************************************************************** --> |
|||
<openerp> |
|||
<data noupdate="1"> |
|||
|
|||
<record id="max_attempt_qty" model="ir.config_parameter"> |
|||
<field name="key">auth_brute_force.max_attempt_qty</field> |
|||
<field name="value">10</field> |
|||
</record> |
|||
|
|||
</data> |
|||
</openerp> |
@ -0,0 +1,150 @@ |
|||
# 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 "" |
|||
|
@ -0,0 +1,120 @@ |
|||
# 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:34+0000\n" |
|||
"PO-Revision-Date: 2015-09-26 00:34+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 "%s %s - %s %s (FAI : %s)" |
|||
|
|||
#. module: auth_brute_force |
|||
#: field:res.banned.remote,active:0 |
|||
msgid "Active" |
|||
msgstr "Active" |
|||
|
|||
#. module: auth_brute_force |
|||
#: field:res.authentication.attempt,attempt_date:0 |
|||
msgid "Attempt Date" |
|||
msgstr "Date de la tentative" |
|||
|
|||
#. 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 "Tentative d'authentification" |
|||
|
|||
#. module: auth_brute_force |
|||
#: field:res.authentication.attempt,result:0 |
|||
msgid "Authentication Result" |
|||
msgstr "Résultat de l'authentification" |
|||
|
|||
#. module: auth_brute_force |
|||
#: field:res.banned.remote,ban_date:0 |
|||
msgid "Ban Date" |
|||
msgstr "Ban Date" |
|||
|
|||
#. 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 "Banni" |
|||
|
|||
#. 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 "Clients distants bannis" |
|||
|
|||
#. 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 "Echoué" |
|||
|
|||
#. module: auth_brute_force |
|||
#: field:res.banned.remote,name:0 |
|||
msgid "Name" |
|||
msgstr "Nom" |
|||
|
|||
#. module: auth_brute_force |
|||
#: field:res.banned.remote,description:0 |
|||
msgid "Description" |
|||
msgstr "Description" |
|||
|
|||
#. module: auth_brute_force |
|||
#: field:res.authentication.attempt,remote:0 |
|||
#: field:res.banned.remote,remote:0 |
|||
msgid "Remote ID" |
|||
msgstr "ID du client Distant" |
|||
|
|||
#. module: auth_brute_force |
|||
#: view:res.authentication.attempt:auth_brute_force.view_res_authentication_attempt_search |
|||
msgid "Successful" |
|||
msgstr "Réussie" |
|||
|
|||
#. 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 "Réussie" |
|||
|
|||
#. module: auth_brute_force |
|||
#: field:res.authentication.attempt,login:0 |
|||
msgid "Tried Login" |
|||
msgstr "Idenfiant essayé" |
|||
|
|||
#. module: auth_brute_force |
|||
#: help:res.banned.remote,active:0 |
|||
msgid "Uncheck this box to unban the remote" |
|||
msgstr "Décochez cette case afin d'annuler l'exclusion du client distant" |
|||
|
|||
#. module: auth_brute_force |
|||
#: code:addons/auth_brute_force/models/res_banned_remote.py:77 |
|||
#, python-format |
|||
msgid "Unidentified Call from %s" |
|||
msgstr "Appel non identifié depuis %s" |
|||
|
|||
#. module: auth_brute_force |
|||
#: view:res.authentication.attempt:auth_brute_force.view_res_authentication_attempt_search |
|||
msgid "Without Success" |
|||
msgstr "Sans succès" |
|||
|
@ -0,0 +1,3 @@ |
|||
# -*- encoding: utf-8 -*- |
|||
from . import res_banned_remote |
|||
from . import res_authentication_attempt |
@ -0,0 +1,58 @@ |
|||
# -*- 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/>. |
|||
# |
|||
############################################################################## |
|||
|
|||
from openerp import models, fields, api |
|||
from openerp.tools.translate import _ |
|||
|
|||
|
|||
class ResAuthenticationAttempt(models.Model): |
|||
_name = 'res.authentication.attempt' |
|||
_order = 'attempt_date desc' |
|||
|
|||
_ATTEMPT_RESULT = [ |
|||
('successfull', _('Successfull')), |
|||
('failed', _('Failed')), |
|||
('banned', _('Banned')), |
|||
] |
|||
|
|||
# Column Section |
|||
attempt_date = fields.Datetime(string='Attempt Date') |
|||
|
|||
login = fields.Char(string='Tried Login') |
|||
|
|||
remote = fields.Char(string='Remote ID') |
|||
|
|||
result = fields.Selection( |
|||
selection=_ATTEMPT_RESULT, string='Authentication Result') |
|||
|
|||
# Custom Section |
|||
@api.model |
|||
def search_last_failed(self, remote): |
|||
last_ok = self.search( |
|||
[('result', '=', 'successfull'), ('remote', '=', remote)], |
|||
order='attempt_date desc', limit=1) |
|||
if last_ok: |
|||
return self.search([ |
|||
('remote', '=', remote), |
|||
('attempt_date', '>', last_ok.attempt_date)]) |
|||
else: |
|||
return self.search([('remote', '=', remote)]) |
@ -0,0 +1,71 @@ |
|||
# -*- 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 urllib |
|||
import json |
|||
|
|||
from openerp import models, fields, api |
|||
|
|||
|
|||
class ResBannedRemote(models.Model): |
|||
_name = 'res.banned.remote' |
|||
_rec_name = 'remote' |
|||
|
|||
_GEOLOCALISATION_URL = "http://ip-api.com/json/{}" |
|||
|
|||
# Default Section |
|||
def _default_ban_date(self): |
|||
return fields.Datetime.now() |
|||
|
|||
# Column Section |
|||
description = fields.Text( |
|||
string='Description', compute='_compute_description', store=True) |
|||
|
|||
ban_date = fields.Datetime( |
|||
string='Ban Date', required=True, default=_default_ban_date) |
|||
|
|||
remote = fields.Char(string='Remote ID', required=True) |
|||
|
|||
active = fields.Boolean( |
|||
string='Active', help="Uncheck this box to unban the remote", |
|||
default=True) |
|||
|
|||
attempt_ids = fields.Many2many( |
|||
comodel_name='res.authentication.attempt', string='Attempts', |
|||
compute='_compute_attempt_ids') |
|||
|
|||
# Compute Section |
|||
@api.multi |
|||
@api.depends('remote') |
|||
def _compute_description(self): |
|||
for item in self: |
|||
url = self._GEOLOCALISATION_URL.format(item.remote) |
|||
res = json.loads(urllib.urlopen(url).read()) |
|||
item.description = '' |
|||
for k, v in res.iteritems(): |
|||
item.description += '%s : %s\n' % (k, v) |
|||
|
|||
@api.multi |
|||
def _compute_attempt_ids(self): |
|||
for item in self: |
|||
attempt_obj = self.env['res.authentication.attempt'] |
|||
item.attempt_ids = attempt_obj.search_last_failed(item.remote).ids |
@ -0,0 +1,28 @@ |
|||
# -*- encoding: utf-8 -*- |
|||
- !record {model: ir.model.access, id: access_res_authentication_attempt_all}: |
|||
model_id: model_res_authentication_attempt |
|||
name: Authentication Attempt All Users |
|||
perm_read: true |
|||
|
|||
- !record {model: ir.model.access, id: access_res_banned_remote_all}: |
|||
model_id: model_res_banned_remote |
|||
name: Banned Remote All Users |
|||
perm_read: true |
|||
|
|||
- !record {model: ir.model.access, id: access_res_authentication_attempt_manager}: |
|||
group_id: base.group_system |
|||
model_id: model_res_authentication_attempt |
|||
name: Authentication Attempt Manager |
|||
perm_create: true |
|||
perm_read: true |
|||
perm_write: true |
|||
perm_unlink: true |
|||
|
|||
- !record {model: ir.model.access, id: access_res_banned_remote_manager}: |
|||
group_id: base.group_system |
|||
model_id: model_res_banned_remote |
|||
name: Banned Remote Manager |
|||
perm_create: true |
|||
perm_read: true |
|||
perm_write: true |
|||
perm_unlink: true |
After Width: 128 | Height: 128 | Size: 9.2 KiB |
After Width: 915 | Height: 262 | Size: 29 KiB |
After Width: 601 | Height: 331 | Size: 31 KiB |
@ -0,0 +1,39 @@ |
|||
<?xml version="1.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/>. --> |
|||
<!-- ********************************************************************** --> |
|||
<openerp> |
|||
<data> |
|||
|
|||
<record id="action_res_authentication_attempt" model="ir.actions.act_window"> |
|||
<field name="name">Authentication Attempts</field> |
|||
<field name="res_model">res.authentication.attempt</field> |
|||
<field name="view_type">form</field> |
|||
<field name="view_mode">tree,graph</field> |
|||
<field name="context">{"search_default_filter_no_success":1}</field> |
|||
</record> |
|||
|
|||
<record id="action_res_banned_remote" model="ir.actions.act_window"> |
|||
<field name="name">Banned Remotes</field> |
|||
<field name="res_model">res.banned.remote</field> |
|||
<field name="view_type">form</field> |
|||
<field name="view_mode">tree,form</field> |
|||
</record> |
|||
|
|||
</data> |
|||
</openerp> |
@ -0,0 +1,32 @@ |
|||
<?xml version="1.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/>. --> |
|||
<!-- ********************************************************************** --> |
|||
<openerp> |
|||
<data> |
|||
|
|||
<menuitem id="menu_res_authentication_attempt" |
|||
parent="base.menu_users" |
|||
action="action_res_authentication_attempt"/> |
|||
|
|||
<menuitem id="menu_res_banned_remote" |
|||
parent="base.menu_users" |
|||
action="action_res_banned_remote"/> |
|||
|
|||
</data> |
|||
</openerp> |
@ -0,0 +1,98 @@ |
|||
<?xml version="1.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/>. --> |
|||
<!-- ********************************************************************** --> |
|||
<openerp> |
|||
<data> |
|||
|
|||
<!-- Model: res.authentication.attempt --> |
|||
<record id="view_res_authentication_attempt_tree" model="ir.ui.view"> |
|||
<field name="model">res.authentication.attempt</field> |
|||
<field name="arch" type="xml"> |
|||
<tree colors="orange: result == 'failed';red: result == 'banned'"> |
|||
<field name="attempt_date" /> |
|||
<field name="remote" /> |
|||
<field name="login" /> |
|||
<field name="result" /> |
|||
</tree> |
|||
</field> |
|||
</record> |
|||
|
|||
<record id="view_res_authentication_attempt_graph" model="ir.ui.view"> |
|||
<field name="model">res.authentication.attempt</field> |
|||
<field name="arch" type="xml"> |
|||
<graph> |
|||
<field name="attempt_date" /> |
|||
<field name="result" /> |
|||
</graph> |
|||
</field> |
|||
</record> |
|||
|
|||
<record id="view_res_authentication_attempt_search" model="ir.ui.view"> |
|||
<field name="model">res.authentication.attempt</field> |
|||
<field name="arch" type="xml"> |
|||
<search> |
|||
<field name="login"/> |
|||
<filter name="filter_no_success" string="Without Success" domain="[('result','!=', 'successfull')]"/> |
|||
<filter name="filter_banned" string="Banned" domain="[('result','=', 'banned')]"/> |
|||
<filter name="filter_failed" string="Failed" domain="[('result','=', 'failed')]"/> |
|||
<filter name="filter_successful" string="Successful" domain="[('result','=', 'successfull')]"/> |
|||
</search> |
|||
</field> |
|||
</record> |
|||
|
|||
<!-- Model: res.banned.remote --> |
|||
<record id="view_res_banned_remote_tree" model="ir.ui.view"> |
|||
<field name="model">res.banned.remote</field> |
|||
<field name="arch" type="xml"> |
|||
<tree colors="gray: active==False"> |
|||
<field name="remote" /> |
|||
<field name="ban_date" /> |
|||
<field name="active" invisible="1" /> |
|||
</tree> |
|||
</field> |
|||
</record> |
|||
|
|||
<record id="view_res_banned_remote_form" model="ir.ui.view"> |
|||
<field name="model">res.banned.remote</field> |
|||
<field name="arch" type="xml"> |
|||
<form> |
|||
<sheet> |
|||
<group> |
|||
<field name="remote" /> |
|||
<field name="ban_date" /> |
|||
<field name="active" /> |
|||
<field name="description" /> |
|||
<field name="attempt_ids" /> |
|||
</group> |
|||
</sheet> |
|||
</form> |
|||
</field> |
|||
</record> |
|||
|
|||
<record id="view_res_banned_remote_search" model="ir.ui.view"> |
|||
<field name="model">res.banned.remote</field> |
|||
<field name="arch" type="xml"> |
|||
<search> |
|||
<field name="remote"/> |
|||
</search> |
|||
</field> |
|||
</record> |
|||
|
|||
</data> |
|||
</openerp> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue