[ADD] This module initialize the session by looking for the field HTTP_REMOTE_USER in the HEADER of the HTTP request and trying^Co bind the given value to a user
parent
f83737f6e8
commit
7dd5bc685e
|
@ -0,0 +1,24 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Author: Laurent Mignon
|
||||||
|
# Copyright 2014 'ACSONE SA/NV'
|
||||||
|
#
|
||||||
|
# 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 . import controllers
|
||||||
|
from . import res_config
|
||||||
|
from . import res_users
|
|
@ -0,0 +1,133 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Author: Laurent Mignon
|
||||||
|
# Copyright 2014 'ACSONE SA/NV'
|
||||||
|
#
|
||||||
|
# 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': 'Authenticate via HTTP Remote User',
|
||||||
|
'version': '1.0',
|
||||||
|
'category': 'Tools',
|
||||||
|
'description': """
|
||||||
|
Allow users to be automatically logged in.
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
This module initialize the session by looking for the field HTTP_REMOTE_USER in
|
||||||
|
the HEADER of the HTTP request and trying to bind the given value to a user
|
||||||
|
This module must be loaded at startup; Add the *--load* parameter to the startup
|
||||||
|
command: ::
|
||||||
|
|
||||||
|
--load=web,web_kanban,auth_from_http_remote_user, ...
|
||||||
|
|
||||||
|
If the field is not found or no user matches the given one, it can lets the
|
||||||
|
system redirect to the login page (default) or issue a login error page depending
|
||||||
|
of the configuration.
|
||||||
|
|
||||||
|
How to test the module with Apache [#]_
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
Apache can be used as a reverse proxy providing the authentication and adding the
|
||||||
|
required field in the Http headers.
|
||||||
|
|
||||||
|
Install apache: ::
|
||||||
|
|
||||||
|
$ sudo apt-get install apache2
|
||||||
|
|
||||||
|
|
||||||
|
Define a new vhost to Apache by putting a new file in /etc/apache2/sites-available: ::
|
||||||
|
|
||||||
|
$ sudo vi /etc/apache2/sites-available/MY_VHOST.com
|
||||||
|
|
||||||
|
with the following content: ::
|
||||||
|
|
||||||
|
<VirtualHost *:80>
|
||||||
|
ServerName MY_VHOST.com
|
||||||
|
ProxyRequests Off
|
||||||
|
<Location />
|
||||||
|
AuthType Basic
|
||||||
|
AuthName "Test OpenErp auth_from_http_remote_user"
|
||||||
|
AuthBasicProvider file
|
||||||
|
AuthUserFile /etc/apache2/MY_VHOST.htpasswd
|
||||||
|
Require valid-user
|
||||||
|
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteCond %{LA-U:REMOTE_USER} (.+)
|
||||||
|
RewriteRule . - [E=RU:%1]
|
||||||
|
RequestHeader set Remote-User "%{RU}e" env=RU
|
||||||
|
</Location>
|
||||||
|
|
||||||
|
ProxyPass / http://127.0.0.1:8069/ retry=10
|
||||||
|
ProxyPassReverse / http://127.0.0.1:8069/
|
||||||
|
ProxyPreserveHost On
|
||||||
|
</VirtualHost>
|
||||||
|
|
||||||
|
.. important:: The *RequestHeader* directive is used to add the *Remote-User* field
|
||||||
|
in the http headers. By default an *'Http-'* prefix is added to the field name.
|
||||||
|
In OpenErp, header's fields name are normalized. As result of this normalization,
|
||||||
|
the 'Http-Remote-User' is available as 'HTTP_REMOTE_USER'. If you don't know how
|
||||||
|
your specified field is seen by OpenErp, run your server in debug mode once the
|
||||||
|
module is activated and look for an entry like: ::
|
||||||
|
|
||||||
|
DEBUG openerp1 openerp.addons.auth_from_http_remote_user.controllers.session:
|
||||||
|
Field 'HTTP_MY_REMOTE_USER' not found in http headers
|
||||||
|
{'HTTP_AUTHORIZATION': 'Basic YWRtaW46YWRtaW4=', ..., 'HTTP_REMOTE_USER': 'demo')
|
||||||
|
|
||||||
|
Enable the required apache modules: ::
|
||||||
|
|
||||||
|
$ sudo a2enmod headers
|
||||||
|
$ sudo a2enmod proxy
|
||||||
|
$ sudo a2enmod rewrite
|
||||||
|
$ sudo a2enmod proxy_http
|
||||||
|
|
||||||
|
Enable your new vhost: ::
|
||||||
|
|
||||||
|
$ sudo a2ensite MY_VHOST.com
|
||||||
|
|
||||||
|
Create the *htpassword* file used by the configured basic authentication: ::
|
||||||
|
|
||||||
|
$ sudo htpasswd -cb /etc/apache2/MY_VHOST.htpasswd admin admin
|
||||||
|
$ sudo htpasswd -b /etc/apache2/MY_VHOST.htpasswd demo demo
|
||||||
|
|
||||||
|
For local test, add the *MY_VHOST.com* in your /etc/vhosts file.
|
||||||
|
|
||||||
|
Finally reload the configuration: ::
|
||||||
|
|
||||||
|
$ sudo service apache2 reload
|
||||||
|
|
||||||
|
Open your browser and go to MY_VHOST.com. If everything is well configured, you are prompted
|
||||||
|
for a login and password outside OpenErp and are automatically logged in the system.
|
||||||
|
|
||||||
|
.. [#] Based on a ubuntu 12.04 env
|
||||||
|
|
||||||
|
""",
|
||||||
|
'author': 'Acsone SA/NV',
|
||||||
|
'maintainer': 'ACSONE SA/NV',
|
||||||
|
'website': 'http://www.acsone.eu',
|
||||||
|
'depends': ['web'],
|
||||||
|
"license": "AGPL-3",
|
||||||
|
"js": ['static/src/js/auth_from_http_remote_user.js'],
|
||||||
|
'data': [
|
||||||
|
'res_config_view.xml',
|
||||||
|
'res_config_data.xml'],
|
||||||
|
"demo": [],
|
||||||
|
"test": [],
|
||||||
|
"active": False,
|
||||||
|
"license": "AGPL-3",
|
||||||
|
"installable": True,
|
||||||
|
"auto_install": False,
|
||||||
|
"application": False,
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Author: Laurent Mignon
|
||||||
|
# Copyright 2014 'ACSONE SA/NV'
|
||||||
|
#
|
||||||
|
# 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 . import session
|
|
@ -0,0 +1,129 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Author: Laurent Mignon
|
||||||
|
# Copyright 2014 'ACSONE SA/NV'
|
||||||
|
#
|
||||||
|
# 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 SUPERUSER_ID
|
||||||
|
|
||||||
|
from openerp.addons.web import http
|
||||||
|
from openerp.addons.web.controllers import main
|
||||||
|
from openerp.modules.registry import RegistryManager
|
||||||
|
from .. import utils
|
||||||
|
|
||||||
|
import random
|
||||||
|
import logging
|
||||||
|
import openerp.tools.config as config
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Session(main.Session):
|
||||||
|
_cp_path = "/web/session"
|
||||||
|
|
||||||
|
_REQUIRED_ATTRIBUTES = ['HTTP_REMOTE_USER']
|
||||||
|
_OPTIONAL_ATTRIBUTES = []
|
||||||
|
|
||||||
|
def _get_db(self, db):
|
||||||
|
if db is not None and len(db) > 0:
|
||||||
|
return db
|
||||||
|
db = config['db_name']
|
||||||
|
if db is None or len(db) == 0:
|
||||||
|
_logger.error("No db found for SSO. Specify one in the URL using parameter "
|
||||||
|
"db=? or provide a default one in the configuration")
|
||||||
|
raise http.AuthenticationError()
|
||||||
|
|
||||||
|
def _get_user_id_from_attributes(self, res_users, cr, attrs):
|
||||||
|
login = attrs.get('HTTP_REMOTE_USER', None)
|
||||||
|
user_ids = res_users.search(cr, SUPERUSER_ID, [('login', '=', login), ('active', '=', True)])
|
||||||
|
assert len(user_ids) < 2
|
||||||
|
if user_ids:
|
||||||
|
return user_ids[0]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _get_attributes_form_header(self, req):
|
||||||
|
attrs = {}
|
||||||
|
|
||||||
|
all_attrs = self._REQUIRED_ATTRIBUTES + self._OPTIONAL_ATTRIBUTES
|
||||||
|
|
||||||
|
headers = req.httprequest.headers.environ
|
||||||
|
|
||||||
|
for attr in all_attrs:
|
||||||
|
value = headers.get(attr, None)
|
||||||
|
if value is not None:
|
||||||
|
attrs[attr] = value
|
||||||
|
|
||||||
|
attrs_found = set(attrs.keys())
|
||||||
|
attrs_missing = set(all_attrs) - attrs_found
|
||||||
|
if len(attrs_found) > 0:
|
||||||
|
_logger.debug("Fields '%s' not found in http headers\n %s", attrs_missing, headers)
|
||||||
|
|
||||||
|
missings = set(self._REQUIRED_ATTRIBUTES) - attrs_found
|
||||||
|
if len(missings) > 0:
|
||||||
|
_logger.error("Required fields '%s' not found in http headers\n %s", missings, headers)
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
def _bind_http_remote_user(self, req, db_name):
|
||||||
|
db_name = self._get_db(db_name)
|
||||||
|
try:
|
||||||
|
registry = RegistryManager.get(db_name)
|
||||||
|
with registry.cursor() as cr:
|
||||||
|
modules = registry.get('ir.module.module')
|
||||||
|
installed = modules.search_count(cr, SUPERUSER_ID, ['&',
|
||||||
|
('name', '=', 'auth_from_http_remote_user'),
|
||||||
|
('state', '=', 'installed')]) == 1
|
||||||
|
if not installed:
|
||||||
|
return
|
||||||
|
config = registry.get('auth_from_http_remote_user.config.settings')
|
||||||
|
# get parameters for SSO
|
||||||
|
default_login_page_disabled = config.is_default_login_page_disabled(cr, SUPERUSER_ID, None)
|
||||||
|
|
||||||
|
# get the user
|
||||||
|
res_users = registry.get('res.users')
|
||||||
|
attrs = self._get_attributes_form_header(req)
|
||||||
|
user_id = self._get_user_id_from_attributes(res_users, cr, attrs)
|
||||||
|
|
||||||
|
if user_id is None:
|
||||||
|
if default_login_page_disabled:
|
||||||
|
raise http.AuthenticationError()
|
||||||
|
return
|
||||||
|
|
||||||
|
# generate a specific key for authentication
|
||||||
|
key = randomString(utils.KEY_LENGTH, '0123456789abcdef')
|
||||||
|
res_users.write(cr, SUPERUSER_ID, [user_id], {'sso_key': key})
|
||||||
|
login = res_users.browse(cr, SUPERUSER_ID, user_id).login
|
||||||
|
req.session.bind(db_name, user_id, login, key)
|
||||||
|
except http.AuthenticationError, e:
|
||||||
|
raise e
|
||||||
|
except Exception, e:
|
||||||
|
_logger.error("Error binding Http Remote User session", exc_info=True)
|
||||||
|
raise e
|
||||||
|
|
||||||
|
@http.jsonrequest
|
||||||
|
def get_http_remote_user_session_info(self, req, db):
|
||||||
|
if not req.session._login:
|
||||||
|
self._bind_http_remote_user(req, db)
|
||||||
|
return self.session_info(req)
|
||||||
|
|
||||||
|
randrange = random.SystemRandom().randrange
|
||||||
|
|
||||||
|
|
||||||
|
def randomString(length, chrs):
|
||||||
|
"""Produce a string of length random bytes, chosen from chrs."""
|
||||||
|
n = len(chrs)
|
||||||
|
return ''.join([chrs[randrange(n)] for _ in xrange(length)])
|
|
@ -0,0 +1,60 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Author: Laurent Mignon
|
||||||
|
# Copyright 2014 'ACSONE SA/NV'
|
||||||
|
#
|
||||||
|
# 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.osv import orm, fields
|
||||||
|
from openerp.tools.safe_eval import safe_eval
|
||||||
|
import types
|
||||||
|
|
||||||
|
|
||||||
|
class auth_from_http_remote_user_configuration(orm.TransientModel):
|
||||||
|
_name = 'auth_from_http_remote_user.config.settings'
|
||||||
|
_inherit = 'res.config.settings'
|
||||||
|
|
||||||
|
_columns = {
|
||||||
|
'default_login_page_disabled': fields.boolean("Disable login page",
|
||||||
|
help="""
|
||||||
|
Disable the default login page.
|
||||||
|
If the HTTP_REMOTE_HEADER field is not found or no user matches the given one,
|
||||||
|
the system will display a login error page if the login page is disabled.
|
||||||
|
Otherwise the normal login page will be displayed.
|
||||||
|
"""),
|
||||||
|
}
|
||||||
|
|
||||||
|
def is_default_login_page_disabled(self, cr, uid, fields, context=None):
|
||||||
|
ir_config_obj = self.pool['ir.config_parameter']
|
||||||
|
default_login_page_disabled = ir_config_obj.get_param(cr,
|
||||||
|
uid,
|
||||||
|
'auth_from_http_remote_user.default_login_page_disabled')
|
||||||
|
if isinstance(default_login_page_disabled, types.BooleanType):
|
||||||
|
return default_login_page_disabled
|
||||||
|
return safe_eval(default_login_page_disabled)
|
||||||
|
|
||||||
|
def get_default_default_login_page_disabled(self, cr, uid, fields, context=None):
|
||||||
|
default_login_page_disabled = self.is_default_login_page_disabled(cr, uid, fields, context)
|
||||||
|
return {'default_login_page_disabled': default_login_page_disabled}
|
||||||
|
|
||||||
|
def set_default_default_login_page_disabled(self, cr, uid, ids, context=None):
|
||||||
|
config = self.browse(cr, uid, ids[0], context)
|
||||||
|
ir_config_parameter_obj = self.pool['ir.config_parameter']
|
||||||
|
ir_config_parameter_obj.set_param(cr,
|
||||||
|
uid,
|
||||||
|
'auth_from_http_remote_user.default_login_page_disabled',
|
||||||
|
repr(config.default_login_page_disabled))
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<openerp>
|
||||||
|
<data noupdate="1">
|
||||||
|
<record model="ir.config_parameter" id="auth_from_http_remote_user.default_login_page_disabled">
|
||||||
|
<field name="key">auth_from_http_remote_user.default_login_page_disabled</field>
|
||||||
|
<field name="value">False</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</openerp>
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<openerp>
|
||||||
|
<data>
|
||||||
|
<record model="ir.ui.view" id="help_view_config_settings">
|
||||||
|
<field name="name">Auth HTTP_REMOTE_USER settings</field>
|
||||||
|
<field name="model">auth_from_http_remote_user.config.settings</field>
|
||||||
|
<field name="priority" eval="20" />
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="Configure Auth HTTP_REMOTE_USER" version="7.0"
|
||||||
|
class="oe_form_configuration">
|
||||||
|
<header>
|
||||||
|
<header>
|
||||||
|
<button string="Apply" type="object" name="execute" class="oe_highlight"/>
|
||||||
|
or
|
||||||
|
<button string="Cancel" type="object" name="cancel" class="oe_link"/>
|
||||||
|
</header>
|
||||||
|
</header>
|
||||||
|
<separator string="Auth HTTP_REMOTE_USER" />
|
||||||
|
<group>
|
||||||
|
<field name="default_login_page_disabled" />
|
||||||
|
</group>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.actions.act_window" id="auth_from_http_remote_user_action_config_settings">
|
||||||
|
<field name="name">Configure Auth HTTP_REMOTE_USER</field>
|
||||||
|
<field name="type">ir.actions.act_window</field>
|
||||||
|
<field name="res_model">auth_from_http_remote_user.config.settings</field>
|
||||||
|
<field name="view_mode">form</field>
|
||||||
|
<field name="target">inline</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<menuitem id="base.menu_auth_from_http_remote_user_config" name="Auth HTTP_REMOTE_USER"
|
||||||
|
parent="base.menu_config" sequence="10"
|
||||||
|
action="auth_from_http_remote_user_action_config_settings" />
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</openerp>
|
|
@ -0,0 +1,64 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Author: Laurent Mignon
|
||||||
|
# Copyright 2014 'ACSONE SA/NV'
|
||||||
|
#
|
||||||
|
# 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.modules.registry import RegistryManager
|
||||||
|
from openerp.osv import orm, fields
|
||||||
|
from openerp import SUPERUSER_ID
|
||||||
|
import openerp.exceptions
|
||||||
|
from openerp.addons.auth_from_http_remote_user import utils
|
||||||
|
|
||||||
|
|
||||||
|
class res_users(orm.Model):
|
||||||
|
_inherit = 'res.users'
|
||||||
|
|
||||||
|
_columns = {
|
||||||
|
'sso_key': fields.char('SSO Key', size=utils.KEY_LENGTH,
|
||||||
|
readonly=True),
|
||||||
|
}
|
||||||
|
|
||||||
|
def copy(self, cr, uid, rid, defaults=None, context=None):
|
||||||
|
defaults = defaults or {}
|
||||||
|
defaults['sso_key'] = False
|
||||||
|
return super(res_users, self).copy(cr, uid, rid, defaults, context)
|
||||||
|
|
||||||
|
def check_credentials(self, cr, uid, password):
|
||||||
|
try:
|
||||||
|
return super(res_users, self).check_credentials(cr, uid, password)
|
||||||
|
except openerp.exceptions.AccessDenied:
|
||||||
|
res = self.search(cr, SUPERUSER_ID, [('id', '=', uid), ('sso_key', '=', password)])
|
||||||
|
if not res:
|
||||||
|
raise openerp.exceptions.AccessDenied()
|
||||||
|
|
||||||
|
def check(self, db, uid, passwd):
|
||||||
|
try:
|
||||||
|
return super(res_users, self).check(db, uid, passwd)
|
||||||
|
except openerp.exceptions.AccessDenied:
|
||||||
|
if not passwd:
|
||||||
|
raise
|
||||||
|
with RegistryManager.get(db).cursor() as cr:
|
||||||
|
cr.execute('''SELECT COUNT(1)
|
||||||
|
FROM res_users
|
||||||
|
WHERE id=%s
|
||||||
|
AND sso_key=%s
|
||||||
|
AND active=%s''', (int(uid), passwd, True))
|
||||||
|
if not cr.fetchone()[0]:
|
||||||
|
raise
|
||||||
|
self._uid_cache.setdefault(db, {})[uid] = passwd
|
|
@ -0,0 +1,36 @@
|
||||||
|
openerp.auth_from_http_remote_user = function(instance) {
|
||||||
|
|
||||||
|
instance.web.Session.include({
|
||||||
|
session_load_response : function(response) {
|
||||||
|
//unregister the event since it must be called only if the rpc call
|
||||||
|
//is made by session_reload
|
||||||
|
this.off('response', this.session_load_response);
|
||||||
|
if (response.error && response.error.data.type === "session_invalid") {
|
||||||
|
$("body").html("<h1>Access Denied</h1>");
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("session_load_response called");
|
||||||
|
},
|
||||||
|
|
||||||
|
session_reload : function() {
|
||||||
|
var self = this;
|
||||||
|
// we need to register an handler for 'response' since
|
||||||
|
// by default, the rpc doesn't call callback function
|
||||||
|
// if the response is of error type 'session_invalid'
|
||||||
|
this.on('response', this, this.session_load_response);
|
||||||
|
return this.rpc("/web/session/get_http_remote_user_session_info", {
|
||||||
|
db : $.deparam.querystring().db
|
||||||
|
}).done(function(result) {
|
||||||
|
// If immediately follows a login (triggered by trying to
|
||||||
|
// restore
|
||||||
|
// an invalid session or no session at all), refresh session
|
||||||
|
// data
|
||||||
|
// (should not change, but just in case...)
|
||||||
|
_.extend(self, result);
|
||||||
|
}).fail(function(result){
|
||||||
|
$("body").html("<h1>Server error</h1>");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
|
@ -0,0 +1,28 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Author: Laurent Mignon
|
||||||
|
# Copyright 2014 'ACSONE SA/NV'
|
||||||
|
#
|
||||||
|
# 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 . import test_res_users
|
||||||
|
fast_suite = [
|
||||||
|
]
|
||||||
|
|
||||||
|
checks = [
|
||||||
|
test_res_users,
|
||||||
|
]
|
|
@ -0,0 +1,83 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Author: Laurent Mignon
|
||||||
|
# Copyright 2014 'ACSONE SA/NV'
|
||||||
|
#
|
||||||
|
# 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.tests import common
|
||||||
|
import mock
|
||||||
|
import os
|
||||||
|
from contextlib import contextmanager
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def mock_cursor(cr):
|
||||||
|
with mock.patch('openerp.sql_db.Connection.cursor') as mocked_cursor_call:
|
||||||
|
org_close = cr.close
|
||||||
|
org_autocommit = cr.autocommit
|
||||||
|
try:
|
||||||
|
cr.close = mock.Mock()
|
||||||
|
cr.autocommit = mock.Mock()
|
||||||
|
mocked_cursor_call.return_value = cr
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
cr.close = org_close
|
||||||
|
cr.autocommit = org_autocommit
|
||||||
|
|
||||||
|
|
||||||
|
class test_res_users(common.TransactionCase):
|
||||||
|
|
||||||
|
def test_login(self):
|
||||||
|
res_users_obj = self.registry('res.users')
|
||||||
|
uid = res = res_users_obj.login(common.DB, 'admin', 'admin')
|
||||||
|
self.assertTrue(res, "Basic login must works as expected")
|
||||||
|
token = "123456"
|
||||||
|
res = res_users_obj.login(common.DB, 'admin', token)
|
||||||
|
self.assertFalse(res)
|
||||||
|
# mimic what the new controller do when it find a value in
|
||||||
|
# the http header (HTTP_REMODE_USER)
|
||||||
|
res_users_obj.write(self.cr, self.uid, uid, {'sso_key': token})
|
||||||
|
|
||||||
|
# Here we need to mock the cursor since the login is natively done inside
|
||||||
|
# its own connection
|
||||||
|
with mock_cursor(self.cr):
|
||||||
|
# We can verifies that the given (uid, token) is authorized for the database
|
||||||
|
res_users_obj.check(common.DB, uid, token)
|
||||||
|
|
||||||
|
# we are able to login with the new token
|
||||||
|
res = res_users_obj.login(common.DB, 'admin', token)
|
||||||
|
self.assertTrue(res)
|
||||||
|
|
||||||
|
@unittest.skipIf(os.environ.get('TRAVIS'),
|
||||||
|
'When run by travis, tests runs on a database with all required addons from server-tools and '
|
||||||
|
'their dependencies installed. Even if `auth_from_http_remote_user` does not require the `mail`'
|
||||||
|
'module, The previous installation of the mail module has created the column '
|
||||||
|
'`notification_email_send` as REQUIRED into the table res_partner. BTW, it\'s no more possible '
|
||||||
|
'to copy a res_user without an intefirty error')
|
||||||
|
def test_copy(self):
|
||||||
|
'''Check that the sso_key is not copied on copy
|
||||||
|
'''
|
||||||
|
res_users_obj = self.registry('res.users')
|
||||||
|
vals = {'sso_key': '123'}
|
||||||
|
res_users_obj.write(self.cr, self.uid, self.uid, vals)
|
||||||
|
read_vals = res_users_obj.read(self.cr, self.uid, self.uid, ['sso_key'])
|
||||||
|
self.assertDictContainsSubset(vals, read_vals)
|
||||||
|
copy = res_users_obj.copy(self.cr, self.uid, self.uid)
|
||||||
|
read_vals = res_users_obj.read(self.cr, self.uid, copy, ['sso_key'])
|
||||||
|
self.assertFalse(read_vals.get('sso_key'))
|
|
@ -0,0 +1,22 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Author: Laurent Mignon
|
||||||
|
# Copyright 2014 'ACSONE SA/NV'
|
||||||
|
#
|
||||||
|
# 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/>.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
KEY_LENGTH = 16
|
Loading…
Reference in New Issue