5 changed files with 166 additions and 69 deletions
@ -0,0 +1,101 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Bhagyadev KP (odoo@cybrosys.com) |
|||
# |
|||
# This program is free software: you can modify |
|||
# it under the terms of the GNU Affero General Public License (AGPL) 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 <https://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
import odoo |
|||
from odoo.modules.registry import Registry |
|||
from odoo import http |
|||
from odoo.http import request |
|||
from odoo.exceptions import AccessError, AccessDenied |
|||
from odoo.addons.web.controllers.session import Session |
|||
from odoo.tools.translate import _ |
|||
|
|||
def _get_client_ip(req): |
|||
""" |
|||
Extract the client IP address in a proxy-safe way. |
|||
Prefer X-Forwarded-For (first item) if present, otherwise use REMOTE_ADDR. |
|||
""" |
|||
forwarded_for = req.httprequest.environ.get('HTTP_X_FORWARDED_FOR') |
|||
if forwarded_for: |
|||
# X-Forwarded-For can be a comma-separated list: client, proxy1, proxy2... |
|||
ip = forwarded_for.split(',')[0].strip() |
|||
return ip |
|||
return req.httprequest.remote_addr |
|||
|
|||
|
|||
def _check_user_ip(user, ip_address): |
|||
""" |
|||
Check if the user is allowed to login from the given ip_address. |
|||
Raises AccessDenied if not allowed. |
|||
""" |
|||
if user and user.allowed_ip_ids: |
|||
allowed_ips = set(user.allowed_ip_ids.mapped('ip_address')) |
|||
if ip_address not in allowed_ips: |
|||
raise AccessDenied(_("Not allowed to login from this IP address.")) |
|||
|
|||
class Session(Session): |
|||
@http.route('/web/session/authenticate', type='json', auth="none") |
|||
def authenticate(self, db, login, password, base_location=None, **kwargs): |
|||
|
|||
if request.db and request.db != db: |
|||
request.env.cr.close() |
|||
elif request.db: |
|||
request.env.cr.rollback() |
|||
if not http.db_filter([db]): |
|||
raise AccessError("Database not found.") |
|||
credential = {'login': login, 'password': password, 'type': 'password'} |
|||
auth_info = request.session.authenticate(db, credential) |
|||
ip_address = request.httprequest.environ['REMOTE_ADDR'] |
|||
registry = Registry(db) |
|||
with registry.cursor() as cr: |
|||
env = odoo.api.Environment(cr, auth_info['uid'], {}) |
|||
wsgienv = { |
|||
'interactive': True, |
|||
'base_location': request.httprequest.url_root.rstrip('/'), |
|||
'HTTP_HOST': request.httprequest.environ['HTTP_HOST'], |
|||
'REMOTE_ADDR': request.httprequest.environ['REMOTE_ADDR'], |
|||
} |
|||
|
|||
# if 2FA is disabled we finalize immediately |
|||
user = env['res.users'].browse(auth_info['uid']) |
|||
auth_info = registry['res.users'].authenticate(db, credential, wsgienv) |
|||
if user and user.allowed_ip_ids: |
|||
ip_list = set(user.allowed_ip_ids.mapped('ip_address')) |
|||
if ip_address not in ip_list: |
|||
raise AccessError("Not allowed to login from this IP") |
|||
if auth_info['uid'] != request.session.uid: |
|||
# Crapy workaround for unupdatable Odoo Mobile App iOS (Thanks Apple :@) and Android |
|||
# Correct behavior should be to raise AccessError("Renewing an expired session for user that has multi-factor-authentication is not supported. Please use /web/login instead.") |
|||
return {'uid': None} |
|||
|
|||
request.session.db = db |
|||
registry = odoo.modules.registry.Registry(db) |
|||
with registry.cursor() as cr: |
|||
env = odoo.api.Environment(cr, request.session.uid, request.session.context) |
|||
if not request.db: |
|||
# request._save_session would not update the session_token |
|||
# as it lacks an environment, rotating the session myself |
|||
http.root.session_store.rotate(request.session, env) |
|||
request.future_response.set_cookie( |
|||
'session_id', request.session.sid, |
|||
max_age=http.get_session_max_inactivity(env), httponly=True |
|||
) |
|||
return env['ir.http'].session_info() |
|||
Session.authenticate = authenticate |
Loading…
Reference in new issue