From d028d22992917a3f898db127828ffc9e42af7246 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Fri, 30 Sep 2011 15:28:58 +0200 Subject: [PATCH] [ADD] auth_openid module bzr revid: chs@openerp.com-20110930132858-jsxqo21l7pn172av --- addons/auth_openid/__init__.py | 26 ++ addons/auth_openid/__openerp__.py | 48 ++++ addons/auth_openid/controllers/__init__.py | 20 ++ addons/auth_openid/controllers/main.py | 225 ++++++++++++++++++ addons/auth_openid/res_users.py | 94 ++++++++ addons/auth_openid/res_users.xml | 20 ++ addons/auth_openid/static/src/css/openid.css | 64 +++++ addons/auth_openid/static/src/img/aol.png | Bin 0 -> 2843 bytes addons/auth_openid/static/src/img/claimid.png | Bin 0 -> 1315 bytes addons/auth_openid/static/src/img/google.png | Bin 0 -> 2061 bytes .../auth_openid/static/src/img/googleapps.gif | Bin 0 -> 4607 bytes .../auth_openid/static/src/img/googlefav.png | Bin 0 -> 940 bytes .../auth_openid/static/src/img/launchpad.gif | Bin 0 -> 6208 bytes .../auth_openid/static/src/img/launchpad.png | Bin 0 -> 419 bytes .../auth_openid/static/src/img/login-bg.gif | Bin 0 -> 328 bytes .../static/src/img/marketplace.gif | Bin 0 -> 1065 bytes .../auth_openid/static/src/img/myopenid.png | Bin 0 -> 320 bytes addons/auth_openid/static/src/img/openid.png | Bin 0 -> 1120 bytes .../auth_openid/static/src/img/openid_16.png | Bin 0 -> 671 bytes .../static/src/img/textfield_key.png | Bin 0 -> 455 bytes .../auth_openid/static/src/img/verisign.png | Bin 0 -> 520 bytes addons/auth_openid/static/src/img/yahoo.png | Bin 0 -> 2302 bytes .../auth_openid/static/src/js/auth_openid.js | 135 +++++++++++ .../static/src/xml/auth_openid.xml | 45 ++++ addons/auth_openid/utils.py | 46 ++++ 25 files changed, 723 insertions(+) create mode 100644 addons/auth_openid/__init__.py create mode 100644 addons/auth_openid/__openerp__.py create mode 100644 addons/auth_openid/controllers/__init__.py create mode 100644 addons/auth_openid/controllers/main.py create mode 100644 addons/auth_openid/res_users.py create mode 100644 addons/auth_openid/res_users.xml create mode 100644 addons/auth_openid/static/src/css/openid.css create mode 100644 addons/auth_openid/static/src/img/aol.png create mode 100644 addons/auth_openid/static/src/img/claimid.png create mode 100644 addons/auth_openid/static/src/img/google.png create mode 100644 addons/auth_openid/static/src/img/googleapps.gif create mode 100644 addons/auth_openid/static/src/img/googlefav.png create mode 100644 addons/auth_openid/static/src/img/launchpad.gif create mode 100644 addons/auth_openid/static/src/img/launchpad.png create mode 100644 addons/auth_openid/static/src/img/login-bg.gif create mode 100644 addons/auth_openid/static/src/img/marketplace.gif create mode 100644 addons/auth_openid/static/src/img/myopenid.png create mode 100644 addons/auth_openid/static/src/img/openid.png create mode 100644 addons/auth_openid/static/src/img/openid_16.png create mode 100644 addons/auth_openid/static/src/img/textfield_key.png create mode 100644 addons/auth_openid/static/src/img/verisign.png create mode 100644 addons/auth_openid/static/src/img/yahoo.png create mode 100644 addons/auth_openid/static/src/js/auth_openid.js create mode 100644 addons/auth_openid/static/src/xml/auth_openid.xml create mode 100644 addons/auth_openid/utils.py diff --git a/addons/auth_openid/__init__.py b/addons/auth_openid/__init__.py new file mode 100644 index 00000000000..42a28a1b35a --- /dev/null +++ b/addons/auth_openid/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2010-2011 OpenERP s.a. (). +# +# 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 . +# +############################################################################## + +import res_users +import controllers + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + diff --git a/addons/auth_openid/__openerp__.py b/addons/auth_openid/__openerp__.py new file mode 100644 index 00000000000..e974a8a91aa --- /dev/null +++ b/addons/auth_openid/__openerp__.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2010-2011 OpenERP s.a. (). +# +# 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 . +# +############################################################################## + + +{ + 'name': 'OpenID', + 'version': '2.0', + 'category': 'Authentification', + 'description': """Allow users to login through OpenID.""", + 'author': 'OpenERP s.a.', + 'maintainer': 'OpenERP s.a.', + 'website': 'http://www.openerp.com', + 'depends': ['base'], + 'data': [ + 'res_users.xml', + ], + 'js': [ + 'static/src/js/auth_openid.js', + ], + 'css': [ + 'static/src/css/openid.css', + ], + 'external_dependencies': { + 'python' : ['openid'], + }, + 'installable': True, + 'active': False, + 'web_preload': True, +} +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/auth_openid/controllers/__init__.py b/addons/auth_openid/controllers/__init__.py new file mode 100644 index 00000000000..2d3be24431f --- /dev/null +++ b/addons/auth_openid/controllers/__init__.py @@ -0,0 +1,20 @@ +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2011 OpenERP SA (). +# +# 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 . +# +############################################################################## +import main diff --git a/addons/auth_openid/controllers/main.py b/addons/auth_openid/controllers/main.py new file mode 100644 index 00000000000..056fc2b6832 --- /dev/null +++ b/addons/auth_openid/controllers/main.py @@ -0,0 +1,225 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2010-2011 OpenERP s.a. (). +# +# 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 . +# +############################################################################## + +import logging +import os +import sys +import urllib + +import werkzeug.urls +import werkzeug.exceptions + +from openerp.modules.registry import RegistryManager +import web.common.dispatch as openerpweb + +from openid import oidutil +from openid.store import memstore +#from openid.store import filestore +from openid.consumer import consumer +from openid.cryptutil import randomString +from openid.extensions import ax, sreg + +from .. import utils + + + +_logger = logging.getLogger('web.auth_openid') +oidutil.log = logging.getLogger('openid').debug + + +class GoogleAppsAwareConsumer(consumer.GenericConsumer): + def complete(self, message, endpoint, return_to): + if message.getOpenIDNamespace() == consumer.OPENID2_NS: + server_url = message.getArg(consumer.OPENID2_NS, 'op_endpoint', consumer.no_default) + if server_url.startswith('https://www.google.com/a/'): + # update fields + for attr in ['claimed_id', 'identity']: + value = message.getArg(consumer.OPENID2_NS, attr) + value = 'https://www.google.com/accounts/o8/user-xrds?uri=%s' % urllib.quote_plus(value) + message.setArg(consumer.OPENID2_NS, attr, value) + + # now, resign the message + assoc_handle = message.getArg(consumer.OPENID_NS, 'assoc_handle') + assoc = self.store.getAssociation(server_url, assoc_handle) + message.delArg(consumer.OPENID2_NS, 'sig') + message.delArg(consumer.OPENID2_NS, 'signed') + message = assoc.signMessage(message) + + return super(GoogleAppsAwareConsumer, self).complete(message, endpoint, return_to) + + +class OpenIDController(openerpweb.Controller): + _cp_path = '/auth_openid/login' + + _store = memstore.MemoryStore() # TODO use a filestore + + _REQUIRED_ATTRIBUTES = ['email'] + _OPTIONAL_ATTRIBUTES = 'nickname fullname postcode country language timezone'.split() + + + def _add_extensions(self, request): + """Add extensions to the request""" + + sreg_request = sreg.SRegRequest(required=self._REQUIRED_ATTRIBUTES, + optional=self._OPTIONAL_ATTRIBUTES) + request.addExtension(sreg_request) + + ax_request = ax.FetchRequest() + for alias in self._REQUIRED_ATTRIBUTES: + uri = utils.SREG2AX[alias] + ax_request.add(ax.AttrInfo(uri, required=True, alias=alias)) + for alias in self._OPTIONAL_ATTRIBUTES: + uri = utils.SREG2AX[alias] + ax_request.add(ax.AttrInfo(uri, required=False, alias=alias)) + + request.addExtension(ax_request) + + def _get_attributes_from_success_response(self, success_response): + attrs = {} + + all_attrs = self._REQUIRED_ATTRIBUTES + self._OPTIONAL_ATTRIBUTES + + sreg_resp = sreg.SRegResponse.fromSuccessResponse(success_response) + if sreg_resp: + for attr in all_attrs: + value = sreg_resp.get(attr) + if value is not None: + attrs[attr] = value + + ax_resp = ax.FetchResponse.fromSuccessResponse(success_response) + if ax_resp: + for attr in all_attrs: + value = ax_resp.getSingle(utils.SREG2AX[attr]) + if value is not None: + attrs[attr] = value + return attrs + + def _get_realm(self, req): + return req.httprequest.host_url + + @openerpweb.jsonrequest + def verify(self, req, db, url): + redirect_to = werkzeug.urls.Href(req.httprequest.host_url + 'auth_openid/login/process')(session_id=req.session_id) + realm = self._get_realm(req) + + session = dict(dbname=db, openid_url=url) # TODO add origin page ? + oidconsumer = consumer.Consumer(session, self._store) + + try: + request = oidconsumer.begin(url) + except consumer.DiscoveryFailure, exc: + fetch_error_string = 'Error in discovery: %s' % (str(exc[0]),) + return {'error': fetch_error_string, 'title': 'OpenID Error'} + + if request is None: + return {'error': 'No OpenID services found', 'title': 'OpenID Error'} + + req.session.openid_session = session + self._add_extensions(request) + + if request.shouldSendRedirect(): + redirect_url = request.redirectURL(realm, redirect_to) + return {'action': 'redirect', 'value': redirect_url, 'session_id': req.session_id} + else: + form_html = request.htmlMarkup(realm, redirect_to) + return {'action': 'post', 'value': form_html, 'session_id': req.session_id} + + + @openerpweb.httprequest + def process(self, req, **kw): + session = getattr(req.session, 'openid_session', None) + if not session: + return werkzeug.utils.redirect('/') + + oidconsumer = consumer.Consumer(session, self._store, consumer_class=GoogleAppsAwareConsumer) + + query = req.httprequest.args + info = oidconsumer.complete(query, req.httprequest.base_url) + display_identifier = info.getDisplayIdentifier() + + session['status'] = info.status + user_id = None + + if info.status == consumer.SUCCESS: + dbname = session['dbname'] + with utils.cursor(dbname) as cr: + registry = RegistryManager.get(dbname) + Modules = registry.get('ir.module.module') + + installed = Modules.search_count(cr, 1, ['&', ('name', '=', 'auth_openid'), ('state', '=', 'installed')]) == 1 + if installed: + + Users = registry.get('res.users') + + #openid_url = info.endpoint.canonicalID or display_identifier + openid_url = session['openid_url'] + + attrs = self._get_attributes_from_success_response(info) + attrs['openid_url'] = openid_url + session['attributes'] = attrs + openid_email = attrs.get('email', False) + + domain = [] + if openid_email: + domain += ['|', ('openid_email', '=', False)] + domain += [('openid_email', '=', openid_email)] + + domain += [ + ('openid_url', '=', openid_url), + ('active', '=', True), + ] + ids = Users.search(cr, 1, domain) + assert len(ids) < 2 + if ids: + user_id = ids[0] + login = Users.browse(cr, 1, user_id).login + key = randomString(utils.KEY_LENGTH, '0123456789abcdef') + Users.write(cr, 1, [user_id], {'openid_key': key}) + # TODO fill empty fields with the ones from sreg/ax + cr.commit() + + u = req.session.login(dbname, login, key) + + if not user_id: + session['message'] = 'This OpenID identifier is not associated to any active users' + + + elif info.status == consumer.SETUP_NEEDED: + session['message'] = info.setup_url + elif info.status == consumer.FAILURE and display_identifier: + fmt = "Verification of %s failed: %s" + session['message'] = fmt % (display_identifier, info.message) + else: # FAILURE + # Either we don't understand the code or there is no + # openid_url included with the error. Give a generic + # failure message. The library should supply debug + # information in a log. + session['message'] = 'Verification failed.' + + + fragment = '#loginerror' if not user_id else '' + return werkzeug.utils.redirect('/web/webclient/home?debug=1'+fragment) + + @openerpweb.jsonrequest + def status(self, req): + session = getattr(req.session, 'openid_session', {}) + return {'status': session.get('status'), 'message': session.get('message')} + diff --git a/addons/auth_openid/res_users.py b/addons/auth_openid/res_users.py new file mode 100644 index 00000000000..3278184474c --- /dev/null +++ b/addons/auth_openid/res_users.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2010-2011 OpenERP s.a. (). +# +# 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 . +# +############################################################################## +from openerp.osv import osv, fields +import openerp.exceptions +import tools + +import utils + +class res_users(osv.osv): + _inherit = 'res.users' + + # TODO create helper fields for autofill openid_url and openid_email -> http://pad.openerp.com/web-openid + + _columns = { + 'openid_url': fields.char('OpenID URL', size=1024), + 'openid_email': fields.char('OpenID Email', size=256, + help="Used for disambiguation in case of a shared OpenID URL"), + 'openid_key': fields.char('OpenID Key', size=utils.KEY_LENGTH, + readonly=True), + } + + def _check_openid_url_email(self, cr, uid, ids, context=None): + return all(self.search_count(cr, uid, [('active', '=', True), ('openid_url', '=', u.openid_url), ('openid_email', '=', u.openid_email)]) == 1 \ + for u in self.browse(cr, uid, ids, context) if u.active and u.openid_url) + + def _check_openid_url_email_msg(self, cr, uid, ids, context): + return "There is already an active user with this OpenID Email for this OpenID URL" + + _constraints = [ + (_check_openid_url_email, lambda self, *a, **kw: self._check_openid_url_email_msg(*a, **kw), ['active', 'openid_url', 'openid_email']), + ] + + def copy(self, cr, uid, rid, defaults=None, context=None): + reset_fields = 'openid_url openid_email'.split() + reset_values = dict.fromkeys(reset_fields, False) + if defaults is None: + defaults = reset_values + else: + defaults = dict(reset_values, **defaults) + + defaults['openid_key'] = False + return super(res_users, self).copy(cr, uid, rid, defaults, context) + + def login(self, db, login, password): + result = super(res_users, self).login(db, login, password) + if result: + return result + else: + with utils.cursor(db) as cr: + cr.execute('UPDATE res_users SET date=now() WHERE login=%s AND openid_key=%s AND active=%s RETURNING id', + (tools.ustr(login), tools.ustr(password), True)) + res = cr.fetchone() + cr.commit() + return res[0] if res else False + + + 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 utils.cursor(db) as cr: + cr.execute('''SELECT COUNT(1) + FROM res_users + WHERE id=%s + AND openid_key=%s + AND active=%s''', + (int(uid), passwd, True)) + if not cr.fetchone()[0]: + raise + self._uid_cache.setdefault(db, {})[uid] = passwd + +res_users() + + diff --git a/addons/auth_openid/res_users.xml b/addons/auth_openid/res_users.xml new file mode 100644 index 00000000000..e32c2df26c8 --- /dev/null +++ b/addons/auth_openid/res_users.xml @@ -0,0 +1,20 @@ + + + + + res.users.form + res.users + form + + + + + + + + + + + + + diff --git a/addons/auth_openid/static/src/css/openid.css b/addons/auth_openid/static/src/css/openid.css new file mode 100644 index 00000000000..8763ec31685 --- /dev/null +++ b/addons/auth_openid/static/src/css/openid.css @@ -0,0 +1,64 @@ +input[name='openid_url'] { + background: #fff url(../img/login-bg.gif) no-repeat 1px; + padding-left: 20px; +} + +.auth_choice { + position: static; + display: none; +} + +.openerp .login .oe_forms .oe_box2 td input[name="db"], .oe_forms .oe_box2 td select[name="db"] { + width: 50%; + float: left; + margin-top: 15px; +} + +.openerp .login .oe_login_right_pane { + margin-left: 525px; +} +.openerp .login form { + width: 475px; +} + +.openid_providers { + padding: 0; + list-style: none; + float: right; +} + +.openid_providers li { + display: block; + float: left; + margin: 0 1px 3px 2px; +} + +.openid_providers a { + display: block; + width: 24px; + height: 24px; + border: 1px solid #ddd; + background: #fff url(../img/openid_16.png) no-repeat 50%; + text-indent: -9999px; + overflow: hidden; + text-align: left; +} + +.openid_providers a.selected { + border-color: #9A0404; +} + +.openid_providers a[title="Password"] { background-image: url(../img/textfield_key.png); } +.openid_providers a[title="AOL"] { background-image: url(../img/aol.png); } +.openid_providers a[title="ClaimID"] { background-image: url(../img/claimid.png); } +.openid_providers a[title="Google"] { background-image: url(../img/googlefav.png); } +.openid_providers a[title="Google Apps"] { background-image: url(../img/marketplace.gif); } +.openid_providers a[title="MyOpenID"] { background-image: url(../img/myopenid.png); } +.openid_providers a[title="VeriSign"] { background-image: url(../img/verisign.png); } +.openid_providers a[title="Yahoo!"] { background-image: url(../img/yahoo.png); } +.openid_providers a[title="Launchpad"] { background-image: url(../img/launchpad.png); } + + +tr.auth_choice.selected { + display: table-row; +} diff --git a/addons/auth_openid/static/src/img/aol.png b/addons/auth_openid/static/src/img/aol.png new file mode 100644 index 0000000000000000000000000000000000000000..93584e56749a800ddefc9ab96822e3942aea932e GIT binary patch literal 2843 zcmV+$3*_{PP)_h*r1X>cr zT%jn4GPQ!DNb4+eKO7PI-HNh7!G zm1eD6PE${CpJkbRX(pOg%BhJ^M#)fSt)kkfYH{e?R`ugTeZ`zn&JlmAP%Q0ita|hj z#ggESfU{27Etx_fDxOJk?@tv}$Ths@3Hz zwW-AgnaujphcY6F0^pKRD9d=`>XC;&=hz#Ggot@PxC`OktHd z3xb&DibX-NXxYQ<)`RUfhe4@eD2gCRl29w?^N3}B>w&O%z;*`YT==X zVAP*_>x036^m@6HfdAt0HCDA%$AWvoWNs#!;|isjc=nyorxMx1ndXNlJyDj-@fMxpTivd&ZmBV;t;ObpK^ zGaP^MZop+3d*j7U#S)oaHJN4TFq(O4kL!gUPQd%pVBn4?iVoX!tj(a*CpgUQTC>`$ zQ9y~%4_wn#XIyR0k#ynWJ-;uKr5O@UnTlq?z`Yx-c)&w^mU=zWzg(Zr@+F!kJ8Jc> zAMZHOX49)sZ=&KKTB`ME?9bl63;ZW?{JGxQLv6OhosKonXK;9Dqv@qx^(YjecX=p) zan(|-gCc;*=x{t+z_Xg{I$%LglOGQTfQwCa2CZ_j7?Ddw*b_=$yz3VT33$L^I$yjr z80?#h&0P~q7r^0}PzF`7sO6`+-AB6|Mzx%LsL`mgStCE#W_xvC1FN7Rgectk0ly%u z(dXh^hmk$8-Kka5pFIej>77+8mDfb%RvogeVs_C#mn zXng5WIYU&?)nRV}{H!%9T^2QTW6YoWXW#6+Yx38}BSle!3EWtte|}5NQVAgl0&0)u zKhIe;wrV9`J zDXo%mRjIwvY_BJNe>OQC$>J8YbD5lhWM4e@;ebES3wkAUVtegNyXw%J1jk<<3QmU8 zm205t;4{)idj~g&QreQD;CeYl0@BRN3dzs}EK3J4r}W67Dop{YNV2kdA_>|0J~#xv z0BIvIID(9-sLt`~a?VV7%EY9K$Prz(ApOjj=P33Q+zXEcC0>ASpaLwtH4%ebfPLTF zV!=Tm#-R?oUZVgT1}5V@LqS{#NK4L46j9efZz7cBRtgb(8}_B7#}I@{POB93Iuq6@ z8B7Nl@5x98xSb4Vypil=DD4Sl@bh>u<4@!;v``L^6a)lvy)mROqP;Kgak;IU1=vRA zAXMob&oCqk`J0Om-u-L}Z~|KJ6+s8nc{sD9opuzm%c;NhAOeIVXB6V(uDTV>T;$sQ z5Q>N z=?0tTNQdKar@hIhHB0a&{*!aIP`vGleKHh;mxD?rx#HE4&^${(0M8)g?TP5M(J+S4 zp?3S}o8CmO;EQvA=oxdDH;P5h6hi&GkH>l?%-yl@o%@%l) zzRB2yJ|BRF-$OFycvN4dKDNnWH?W_NhOgWY9cZ_`((T$@Z^Fc$FFOCuIV9~mUL49W z6kTr1Vt37#fRI_JdcW^ThkZwb`PnY}J69(QlyGGv{Nq3Oy>@8B{#Gltd4K}shb8#^ zT+0|%%?NHNHBztW*1YBGJkOJwZ8m&#I1mHoFVQxQd^SjAuK(U}_aN5syIY2;ZWUS;pQ#l@6)Knk?PSl!Ic;4oE<9y46 zGQ$9Y%oF~UFOs=28s67p-Pve<{Y1xGAKd$NIFv0GC;0SKEDOR&!%Ps7ZK))p#@!n& zKm1x74kXG_FP2ZkKb)WA;rX%)?13no4rgGnzOmCee@Otfa3D&Il^%)|&1hj!>Z;UO zzcDxf3N1@3u}_l{F;#L3mVqRQN9`C&1=Z}(IjbQ1rIWjy?X`xbO9@ucbI- zS>0A%43W?N7AqXz-)_zP_4?E}B#tYV$C6~i7&+NmqxOi0(bhS;x;{7rDb71kf+)ix4ro@SvxgEl0bmL1R#tTD9S!=T?F_(O>C5dx`LCazkoTVG2iObU!Ctl1 zWkj}ckw_SOB3KEC0c!+7JRY|H%Rge-4#HXi(w$CYeU%FA70VL`>l91@`uwEjTzLbB ttwLIu$}{QVXp=+{WT75sd-<0D0{}&6G!}7L`fUIJ002ovPDHLkV1hj1aaI5T literal 0 HcmV?d00001 diff --git a/addons/auth_openid/static/src/img/claimid.png b/addons/auth_openid/static/src/img/claimid.png new file mode 100644 index 0000000000000000000000000000000000000000..41be7fc8f9e92d92b250ba1c0a3930f8f9cf187e GIT binary patch literal 1315 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

)!QO|U{; zRe{>Ao6tgM>*>$E0DTnCB^c&!olb?fUY-Ms*?@DEU1FOj)ArYD*%RRN2XW7`RG5rf z8Y>{$)_y$~C(ibXd%mn(njyv=_7H!O{P0^jIC`p`4h4D)(GIDp?G^1@GG2eN5NW9< z@ywhrs3SR^o@pDLtJPw_;Y54_p>&4iy+qFxL3_6k@9evXD@{GP*q?)1bOTJk;iN ztKd^7B1Tt36B!)Q<2%Yey(s~09eSi#-T3xwAAa+k4{IOnK>noBXzKBjCqmxL$4@+DeIhM1Ohaid*yRg|li0A&Z0Xw(ej-&*+ z&eSyw;MuJgSWQe+qmk{ne6tUp3JYVvqTwyg5^Cok<%l<@(1v$kO+mwz0h}mq$DI!p z;hmQYkvS?>j)60WSNj{Qcx99E?DjU;+q%Gma^`V=f<=ulFEiu8FDF6c9YTVm3~Frv zzDd(zC9C%8YPyoJekiK0rmGm3RzSNW3*M*|NHqdo_IjZv1p{(s(o;)Y4~7keL@5b) z;)fZSx40kQdwf4$`J)R@ZY;*V^9HbD(9rQNm{$Pad)){AgoM~w z0@*4~IARdx5(1^M$%&a$ECOUd(FBV%&JYHQpP4>blrwNo?=VkEESuLW_X&m2#ojiA zabrwqXmsGfu@<6EH71U?;(Kc+VEx)m?A_laG>O5&KCyUV27df6TAV%P$9Mm^lCpP* zz*dVubUF=EQb!{{Zz5vNMqHuOL6k;|)VmhLymS$o)~`p)g&L@cL;1w(EIxq)hmK9CDs(=*5v9*>1bVul@_OLB+KAz< z4q+3@L2`7DJJVq#ihKCU8r0SkFeFrXQC!-M@neaiNI3U2zaXK~ zNXB$-q@#`ASdUj;tix~Lw!=Wc1);-$Gl=#s4^C2H_~V`f7!y;5Wy|IwJv{@_(+g44 z(T1vRFH)8f$5)?6>B(YvmaN3`WlNA|OGUKN48LhPD$bt6)tX(1riJUXA4kcD_0Xq& z7fY8cApYjPK|yKbq0*3Flc+Z6QP+GC)q78)uYCwnv3g9&n+oHU z88~lmM%iz-pzig}s6StWmY!Z%#*IfT(FkvC-jxi-#BoM!+537G*+GyAszmD$6zzZ4h;0-^yv?A^3+EtuW}-& zrcBFD!l*P060ItjjZVbI#$ZO_EIKhH3rDT(9jH8a4ukZYn3jT=6dN*9Q)nU5MZa=s zxZH$l;#~L~uqI`|WJ$r8(KaL{CBa99{txeUqoS+|V{G(oL)VAOs%C88V#Pn)AB{JE zw?dq1%FmU<;UN2XD{^ylV76G$*xZcLGiT7z)=sg-;+9Ey7@w0v#mJ%zO?)fQk4~TH z=yD-3K8gyR27Y?xLU-_3GwK?gcy!%Fsu?bNS<=Ev#Z0k#e%nV>M6FnKM><;QrNnAA zz!WV?Tv&%ry=d=rQ4!U{94i-DC4ex{+@Lt+dj`C}uNT8^m!ObnqX|*bMhYN?vco7A zh4muE=~L_yds|11ex!Xrlc8 zw}@h6(6PH~S2@yN(Tg(3tIe@6;Jr>2UVX0_i*IektU0TYl$=g+h&b`^L!VwiVpuOZ9-4P!50~{nN1)vEzao~TRcK8?< z^2Kd;%#w@Z_5ESTLYJRLd|%T?lm5$yMrwXW_dGlUv;QC!*d>QB`|dof`N~wJCTZXp z^x$IcC1fTy4_6Z@Y%0|GN5Trx6HvQBquj zLq{&4xlK=JTrGV8Gtn2e1Z2_|xeR(KxtZk)1GEC7%jJM;$RW0{P9H_zz0EKfWbRaS pZpPm)9MCrcQK6R`_1!FO{|999dJo~edT0Ou002ovPDHLkV1mN=;(!1E literal 0 HcmV?d00001 diff --git a/addons/auth_openid/static/src/img/googlefav.png b/addons/auth_openid/static/src/img/googlefav.png new file mode 100644 index 0000000000000000000000000000000000000000..1604ac0baa51d59b5c90b0a5c9f1d2bdb313e7bc GIT binary patch literal 940 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 N002ovPDHLkV1l{GrXK(R literal 0 HcmV?d00001 diff --git a/addons/auth_openid/static/src/img/login-bg.gif b/addons/auth_openid/static/src/img/login-bg.gif new file mode 100644 index 0000000000000000000000000000000000000000..e2d8377db023a3915cc9e8c2f1f5c7462622f0a1 GIT binary patch literal 328 zcmZ?wbhEHb6krfwxXQrr>({UQ_wR4qxN*;(J#*&FS-N!TvSrKGuV4S?%F;i7{_Nbj z^V6qK`}XadJ9qBs)2Dx~3p;V*#MZ4_j~qF&aN)v#|Nb2~aNyvg9 ztXT2$=g%EGcI@80`{m1*Z{NOs{rdIFl`EeF4W-ruOthu2f ztl_Mdp@*QzZPDcui{^-N`o3xq@(UMrZh5FF-w`Y#$*8QNq^Zf+5a!Y$(d{Fk$;RMZ d?jf!z+?DC8mZr!$-G@O{mX$wbm9ry*H2@d`j5z=R literal 0 HcmV?d00001 diff --git a/addons/auth_openid/static/src/img/marketplace.gif b/addons/auth_openid/static/src/img/marketplace.gif new file mode 100644 index 0000000000000000000000000000000000000000..a3e4d2cd6061fb00b59432cfbdfefc8391574f4b GIT binary patch literal 1065 zcmZ?wbhEHb6krfw_|Cw%vf@$k40LFj<#jsv*M+ONLoSOo=;KWX)J2*Rv`+ zu(rpr_9wG3F|aAwvULPK(3FVw)!#UrDOVgEyorx#oAW!2cM zKT|C~sk+=(Gk2qA!!^z6FSVvb>&$#(uq?}{a=+=?Ff;pdi*;d^OYLnpCEITdbe{dm zV||s!=J>#bCBZvVLf5;5@_&%J;9j-1-};QxUl$AgCsA3b*B*oo7}&tE<9Df;r#3K7iEMls>@uwboq+0#+8T9uDrc+)j;{Ww)_oq&71ay zH*egydGF!Pch~PY8Q*>QHm|8|F35Mf4>fxj)o{u{K>+}z;K8`2jqTGo?zhk&)^ulD@AjXl2gqKjgSoY85;s} z52SQ%I?}-}rEWAYBG55nLs0TO6HlQQcV0bn=vm5U$c%0*A>GKy!89oJ^j!lwHwv*ojGP+ z)M8lU$so|EJV}qyahFz6!Q9tE5pVygJ%~8W7ttE{`an$2N7==a3)vp8Sgz98_T zd++oaY6>@BSf1reD_JnXnaS2^t?%@NQu!MP_oqIxYR000>X0ssI2_G&~y0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU$0!c(cRCwC#m_JNYQ542+O9N?RBasHC zVhuwR25n(e6ExAd*}CauqpOLy;3%#vN@T_01e@ThCK#g|f*~PxAgMMffwV~-Y-3}^ z-|cz5eU|>CqEh3@3whjk?|t_>=R4myua4c_UDcw!m{u2Vt4=dVO9+$i)#I4@w5Dcv zI}V|%`IKk()zYNuSaUX?@?lwZvN_eiZvQ^Qx_MYA6mq#-KA%5U_}Wt*+}hf5yWJj- zr@OnmQxO6zlgVVWS>VaYk*@`VFqKNl4G4WcUteDzH^pKxnM?)(fy0iFgYN9?7z~XK zN2E#yNZi5N8VEBVRXU+Oy~=;;?<3^Io12>^ZWu@JEtz`hHG`w0quH{7N~6eRYV5kY zq!z|CJTX9C9M_lo=s})6{z^@qQ<2H)Vir8721ELFea9_?oHZVg15ze{%J28r%QT*P zz23Umu!TG7`9l?ss#}XXdPMTgoE}+SR1?bw4AR)Ohsqx+5htNL6W+*mV@`!5T1&|y z1CP)R4GlFA63IH|dw;fyUjc((Z#}ihi6bxH)7W_N@9P|Z7aY^q>Fet112vUUzJTt- z@}FIt*hB+hO$DQ?tE_=N|I-tG?viXJWM<$+$$4{9)!uRAT_lWJm`ed;3JqMD-2s zAeUxin)9HNCCp@eq~x7P(IzK>JM8db*>#Xq!P%1NwTV=UQoI~DlaoYg>bzDaM&?U` z1kJE;!~!`OvbKf!M!IHWR-79}vX?nd%C{Lwr_;ZL(1>SKtI}2e6?x#$5nHYT9zwob ztWdy;Pbp23Yb{j^@(Oj4R75`#iA4Lgn?x5iQ)4xr=0960B*I`fiIO0xq92$gR>ZCC zdPr@ks&9;dyq*03fPUcnnkl*$+g^+8(OX;=Z|nPpAfJgjMIM8}ps5gmTwh2cmdwYYmiAC84Mf*XGe2$5oU?@wA?*5tas(?C&5B{+|LdfjvK(!RSb3b)ZZ z@Bqf_aMPi^U_T8o%u}iFro+UoGQylvpIMp1Q+ANQ_U48S@oafR$3A{*J17%`tuW&M mH~wKoNImfVxzFVv0t^5s4dYi_crgk90000dbVG7wVRUJ4ZXi@?ZDjy9FETVQ zFgfcmkPxlXU zXtB<+gOG(}tgL~v&u}}Jf*d3QNAgIcm1g#v`M#N5Ydju*dU|^5y}Z0A-e8{R>1;N8 zXx-f0{8CGM3m&aCT5D|wL7>vXKqoOZiS5CjYc14LxW zz!a)oK;b^Oh1E3)is_5w5PTI5;?DKHExzyL`#$eJ zerA7v|J8S}TI0jR14=0#A0Nr*^X%^K;<_#(!Ym9i^Z5o?YrQOxN~QF0I8-8nQi?DP z3Bzz}$G^dMcXy;xDedNRxkIgWuix*#={sh#S*?^h{0$N2aLV)6RV)Ai002ovPDHLk FV1lU+C+q+K literal 0 HcmV?d00001 diff --git a/addons/auth_openid/static/src/img/textfield_key.png b/addons/auth_openid/static/src/img/textfield_key.png new file mode 100644 index 0000000000000000000000000000000000000000..a9d5e4f8cc75240f6e6bbb9e73466a9e3effb610 GIT binary patch literal 455 zcmV;&0XY7NP)4^nI0$7`a(T+P4hBKZ7hk58-_j0w;$<(*=f7ic$nT z*Wgd55in08>183j3?S=MAoDDTLoLSL$!_UDxXqSf-?qdd@H%8(We~hQu&uVIo$6NV z(zMY7wn6r5i617ZGZ)-J($xXssTcN*&WujcIDRIp6J4_PqOvJ}9!p6+yo8LmAGS3~ xN#Qq?aIt$6X#&>gPx#1ZP1_K>z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUy7<5HgbW?9;ba!ELWdKlNX>N2bPDNB8b~7$BHmT?0B>(^cVo5|n zR5(wSl(9<0KoExGBgDc75b^|R?R)@jY?)c2s zUSg?LOECKmP+%7bGTaJhiKvwkEcKY0E=@fqd(JWMVhQIL5PSheJynmPeTGjNV&7e0@ zOt9iCKiBZ3fdGxkVo*#rhebWO$;6%kZt#GCZDBaNiF_5Z;7H$t@y9id0|Y`;71i`@ z8SwCS9Y3Zdx8m#<8AiPUV=~wrCg9hN8Q|VbHWt2AzV4%C$n)4+pLSFh*MdV)>N6Tl z5MO{YJT}nU-qJTzYGKWPqI_DErF5Mmj@`J>OYSyt``ECqr@J4b5}sKcrj3J;!+S3J zOh!}2_qo~U3SgyBWU*j*kh7;FKph<#ds@-_sPJ*Mvi@%7gAc!aN91HpYJ`rF{*NG1 ze|Jg(Hc_0ly>Qp@_UFz>P zJIF&O_wZB5Ko^s2V$>Nsnl!_MBgMDMU@_mC?HlUN<8!H5cOMrRjuH`o512n2tTeu{ zrmQjVO7X*j$HN07@JgqnCKJxH;4WAZ7`rI~6h~sfiEsD(^!uH1K(lgd)Qb2wKtU5v z*L3!tJdj>-ukPrM)1RDAgjtkfc2xwK8{|0+cpw*d@%n>{Pb8)rji&ZSb=v3WcO6ck zrZ{}Icc6!@SeTJ|hrz_&`XGAQdlA4N=ozY3Hn4c)*(QT&Y((!JN0xLY__k=K9T3MF>hntPb@L^R^LN!CC#9!SZ`GH_zmiYk=G`j~H`lb67F0q&K`tP{qckU(!}Q>RLKeu? zNt*P}a&g4?D7!H~^!~zCq106EqlP01rx+aU?3}ETc>24Q+^ML%UuOnSo&^E!;3j$@c%ay|i&VAUcP~D~ zX~qjjvK*y0-gBk*vdg|pIzP+T?SsSX?VWAM7ti){lLbopyN7i;9mYi0?_M!U8Wj-_ zekt#4Qkx(*5(HULa2&EgSBr*N*G% z2M&{kaV@zsq(hX35;R0NsvqY_{Us1b&t_k=?Y%wgBz~@N>#-qy+P?HlCvKcby5O&v zv-ecOMC3q&eM2`+=dJx~OxO~+TGgj4tejS0`smZ11D*<>m< znzOW~wGYxYfcNlmomK)=6E>ekAb4+ApL8yn9Y=@toh|Aaz_&Mc1Adtw>4~@z2S0O{ zIgig`FWLr?w&lRe&o`w(Kz29uXQmeThDdj&YzF?MmAB3naV$8&k$z%#yBlZoa?TY7 zy*hW|0;mY^zkEvsWTr{wu;O0L7k^39>qzhn?3rYUQWsChsaFDLAyo#!C9;f&Q)FK# zg1cQy&E0u?GfJPvin*8WwLR^!a^lTjK9Af^_G~n-z&}C~ok4B0WD-S80B9U4Ka8~> zEt!gZP&;(3 z_zQT`)cfRT75AwJBy*fxyu?tL5|cLyZ3LxvE01hDSyS2wLG-Md!wIOeXTH3A=F_WA z68n!+;;Dia|4CeO<{np>uBP6B=}mjz6j}?|T$Z)9Wq#K0 zzg;U?ofr)O>ML7&+IzK~eX#Q3-70%mTMH{5L>+iLl#=#_PGw;QOo6hh?$mKltV9-2iGkm%>DRXRK})`PL)gmqqoA803(APDvsoh$@}Nh9;DP~nAe;Faz^5O( z0j(I>X0RDw-`Xd%6+9PF^<8^bB}cuZ*tmNY#p&tl+qvWri_bXm>p!5wIsNGs+(aGOwbwu7gUJ1o@eP z*ocK;G4j~W3n%rhKR2dUiMC)g8OgFiA(RqNh$UjrxQ_P)CE zCT(}0gS+jYSRR_WXB~^VKO5(FwQ0^Cy81-fU?NNp^Q(9Q?&^faRGTzEc3#od(!31i zqBS8YclM9BoRrUlt|_}k#wlP-JrUx0&4~jB4y}H~0PC$Cgkp)^w1EvIass6^Z)<=07*qoM6N<$f + + + + + +

+ + + + + + + + + + + + + + + + + + + + + + + //this.addClass('auth_choice'); // XXX for some reason, not all tr tags are HTMLElement's and thus, jQuery decide to not change the class... + this.attr('class', 'auth_choice'); + this.each(function() { + var $i = $(this); + $i.attr('data-provider', $i.find('input').attr('name')); + }); + + + + diff --git a/addons/auth_openid/utils.py b/addons/auth_openid/utils.py new file mode 100644 index 00000000000..2761f3d0e1d --- /dev/null +++ b/addons/auth_openid/utils.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2010-2011 OpenERP s.a. (). +# +# 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 . +# +############################################################################## +from contextlib import contextmanager +from openerp.modules.registry import RegistryManager + +KEY_LENGTH = 16 + +SREG2AX = { # from http://www.axschema.org/types/#sreg + 'nickname': 'http://axschema.org/namePerson/friendly', + 'email': 'http://axschema.org/contact/email', + 'fullname': 'http://axschema.org/namePerson', + 'dob': 'http://axschema.org/birthDate', + 'gender': 'http://axschema.org/person/gender', + 'postcode': 'http://axschema.org/contact/postalCode/home', + 'country': 'http://axschema.org/contact/country/home', + 'language': 'http://axschema.org/pref/language', + 'timezone': 'http://axschema.org/pref/timezone', +} + + +@contextmanager +def cursor(db): + cr = RegistryManager.get(db).db.cursor() + try: + yield cr + finally: + cr.close() +