You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

101 lines
4.6 KiB

# -*- 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