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 00000000000..93584e56749 Binary files /dev/null and b/addons/auth_openid/static/src/img/aol.png differ 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 00000000000..41be7fc8f9e Binary files /dev/null and b/addons/auth_openid/static/src/img/claimid.png differ diff --git a/addons/auth_openid/static/src/img/google.png b/addons/auth_openid/static/src/img/google.png new file mode 100644 index 00000000000..d8b8b2a7abb Binary files /dev/null and b/addons/auth_openid/static/src/img/google.png differ diff --git a/addons/auth_openid/static/src/img/googleapps.gif b/addons/auth_openid/static/src/img/googleapps.gif new file mode 100644 index 00000000000..f86bc8956d2 Binary files /dev/null and b/addons/auth_openid/static/src/img/googleapps.gif differ 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 00000000000..1604ac0baa5 Binary files /dev/null and b/addons/auth_openid/static/src/img/googlefav.png differ diff --git a/addons/auth_openid/static/src/img/launchpad.gif b/addons/auth_openid/static/src/img/launchpad.gif new file mode 100644 index 00000000000..48e7ba4f5b0 Binary files /dev/null and b/addons/auth_openid/static/src/img/launchpad.gif differ diff --git a/addons/auth_openid/static/src/img/launchpad.png b/addons/auth_openid/static/src/img/launchpad.png new file mode 100644 index 00000000000..7db6e67f8b5 Binary files /dev/null and b/addons/auth_openid/static/src/img/launchpad.png differ 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 00000000000..e2d8377db02 Binary files /dev/null and b/addons/auth_openid/static/src/img/login-bg.gif differ 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 00000000000..a3e4d2cd606 Binary files /dev/null and b/addons/auth_openid/static/src/img/marketplace.gif differ diff --git a/addons/auth_openid/static/src/img/myopenid.png b/addons/auth_openid/static/src/img/myopenid.png new file mode 100644 index 00000000000..d00ca76543b Binary files /dev/null and b/addons/auth_openid/static/src/img/myopenid.png differ diff --git a/addons/auth_openid/static/src/img/openid.png b/addons/auth_openid/static/src/img/openid.png new file mode 100644 index 00000000000..280ee6ce3b7 Binary files /dev/null and b/addons/auth_openid/static/src/img/openid.png differ diff --git a/addons/auth_openid/static/src/img/openid_16.png b/addons/auth_openid/static/src/img/openid_16.png new file mode 100644 index 00000000000..eadf8e8577f Binary files /dev/null and b/addons/auth_openid/static/src/img/openid_16.png differ 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 00000000000..a9d5e4f8cc7 Binary files /dev/null and b/addons/auth_openid/static/src/img/textfield_key.png differ diff --git a/addons/auth_openid/static/src/img/verisign.png b/addons/auth_openid/static/src/img/verisign.png new file mode 100644 index 00000000000..fe890ca7aeb Binary files /dev/null and b/addons/auth_openid/static/src/img/verisign.png differ diff --git a/addons/auth_openid/static/src/img/yahoo.png b/addons/auth_openid/static/src/img/yahoo.png new file mode 100644 index 00000000000..5fbf752d9b5 Binary files /dev/null and b/addons/auth_openid/static/src/img/yahoo.png differ diff --git a/addons/auth_openid/static/src/js/auth_openid.js b/addons/auth_openid/static/src/js/auth_openid.js new file mode 100644 index 00000000000..7399e1fb371 --- /dev/null +++ b/addons/auth_openid/static/src/js/auth_openid.js @@ -0,0 +1,135 @@ + +openerp.auth_openid = function(instance) { + +var QWeb = instance.web.qweb; +QWeb.add_template('/auth_openid/static/src/xml/auth_openid.xml'); + +instance.web.Login = instance.web.Login.extend({ + start: function() { + this._super.apply(this, arguments); + var self = this; + + this.$openid_selected_button = $(); + this.$openid_selected_input = $(); + this.$openid_selected_provider = null; + + + var openIdProvider = null; + if (this.has_local_storage && this.remember_creditentials) { + openIdProvider = localStorage.getItem('openid-provider'); + } + + if (openIdProvider) { + $openid_selected_provider = openIdProvider; + this.do_openid_select('a[href="#' + openIdProvider + '"]', openIdProvider, true); + + if (this.has_local_storage && this.remember_creditentials) { + this.$openid_selected_input.find('input').val(localStorage.getItem('openid-login')); + } + } + else { + this.do_openid_select('a[data-url=""]', 'login,password', true); + } + + this.$element.find('a[data-url]').click(function (event) { + event.preventDefault(); + var selected_oidh = $(this).attr('href').substr(1); + if (selected_oidh != self.$openid_selected_provider) { + self.do_openid_select(this, selected_oidh); + } + }); + + }, + + + do_openid_select: function (button, provider, noautosubmit) { + var self = this; + + self.$openid_selected_button.add(self.$openid_selected_input).removeClass('selected'); + self.$openid_selected_button = self.$element.find(button).addClass('selected'); + + var input = _(provider.split(',')).map(function(p) { return 'tr[data-provider="'+p+'"]'; }).join(','); + self.$openid_selected_input = self.$element.find(input).addClass('selected'); + + self.$openid_selected_input.find('input:first').focus(); + self.$openid_selected_provider = (self.$openid_selected_button.attr('href') || '').substr(1); + + if (self.has_local_storage && self.remember_creditentials) { + localStorage.setItem('openid-provider', self.$openid_selected_provider); + } + + if (!noautosubmit && self.$openid_selected_input.length == 0) { + self.$element.find('form').submit(); + } + + }, + + on_login_invalid: function() { + var self = this; + var fragment = jQuery.deparam.fragment(); + if (fragment.loginerror != undefined) { + this.rpc('/auth_openid/login/status', {}, function(result) { + if (_.contains(['success', 'failure'], result.status) && result.message) { + self.notification.warn('Invalid OpenID Login', result.message); + } + if (result.status === 'setup_needed' && result.message) { + window.location.replace(result.message); + } + }); + } + return this._super(); + }, + + on_submit: function(ev) { + + var dataurl = this.$openid_selected_button.attr('data-url'); + + if(!dataurl) { + // login-password submitted + this._super(ev); + } else { + ev.preventDefault(); + + var id = this.$openid_selected_input.find('input').val(); + if (this.has_local_storage && this.remember_creditentials) { + localStorage.setItem('openid-login', id); + } + + var db = this.$element.find("form [name=db]").val(); + var openid_url = dataurl.replace('{id}', id); + + this.do_openid_login(db, openid_url); + + } + }, + + do_openid_login: function(db, openid_url) { + var self = this; + this.rpc('/auth_openid/login/verify', {'db': db, 'url': openid_url}, function(result) { + if (result.error) { + self.notification.warn(result.title, result.error); + self.on_login_invalid(); + return; + } + if (result.session_id) { + self.session.session_id = result.session_id; + self.session.session_save(); + } + if (result.action === 'post') { + document.open(); + document.write(result.value); + document.close(); + } else if (result.action === 'redirect') { + window.location.replace(result.value); + } else { + // XXX display error ? + } + + }); + }, + + +}); + + +}; diff --git a/addons/auth_openid/static/src/xml/auth_openid.xml b/addons/auth_openid/static/src/xml/auth_openid.xml new file mode 100644 index 00000000000..6fbab72e831 --- /dev/null +++ b/addons/auth_openid/static/src/xml/auth_openid.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + //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() +