Christophe (OpenERP) has proposed merging 
lp:~openerp-dev/openobject-addons/trunk-openid-chs into lp:openobject-addons.

Requested reviews:
  Xavier (Open ERP) (xmo)

For more details, see:
https://code.launchpad.net/~openerp-dev/openobject-addons/trunk-openid-chs/+merge/77702

Add auth_openid (web) module
-- 
https://code.launchpad.net/~openerp-dev/openobject-addons/trunk-openid-chs/+merge/77702
Your team OpenERP R&D Team is subscribed to branch 
lp:~openerp-dev/openobject-addons/trunk-openid-chs.
=== added directory 'auth_openid'
=== added file 'auth_openid/__init__.py'
--- auth_openid/__init__.py	1970-01-01 00:00:00 +0000
+++ auth_openid/__init__.py	2011-09-30 13:34:22 +0000
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2010-2011 OpenERP s.a. (<http://openerp.com>).
+#
+#    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/>.
+#
+##############################################################################
+
+import res_users
+import controllers
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+

=== added file 'auth_openid/__openerp__.py'
--- auth_openid/__openerp__.py	1970-01-01 00:00:00 +0000
+++ auth_openid/__openerp__.py	2011-09-30 13:34:22 +0000
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2010-2011 OpenERP s.a. (<http://openerp.com>).
+#
+#    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': '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:

=== added directory 'auth_openid/controllers'
=== added file 'auth_openid/controllers/__init__.py'
--- auth_openid/controllers/__init__.py	1970-01-01 00:00:00 +0000
+++ auth_openid/controllers/__init__.py	2011-09-30 13:34:22 +0000
@@ -0,0 +1,20 @@
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2011 OpenERP SA (<http://openerp.com>).
+#
+#    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/>.
+#
+##############################################################################
+import main

=== added file 'auth_openid/controllers/main.py'
--- auth_openid/controllers/main.py	1970-01-01 00:00:00 +0000
+++ auth_openid/controllers/main.py	2011-09-30 13:34:22 +0000
@@ -0,0 +1,225 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2010-2011 OpenERP s.a. (<http://openerp.com>).
+#
+#    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/>.
+#
+##############################################################################
+
+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')}
+

=== added file 'auth_openid/res_users.py'
--- auth_openid/res_users.py	1970-01-01 00:00:00 +0000
+++ auth_openid/res_users.py	2011-09-30 13:34:22 +0000
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2010-2011 OpenERP s.a. (<http://openerp.com>).
+#
+#    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 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()
+
+

=== added file 'auth_openid/res_users.xml'
--- auth_openid/res_users.xml	1970-01-01 00:00:00 +0000
+++ auth_openid/res_users.xml	2011-09-30 13:34:22 +0000
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>   
+        <record id="view_users_form" model="ir.ui.view">
+            <field name="name">res.users.form</field>
+            <field name="model">res.users</field>
+            <field name="type">form</field>
+            <field name="inherit_id" ref="base.view_users_form"/>
+            <field name="arch" type="xml">
+                <notebook colspan="4" position="inside">
+                    <page string="OpenID">
+                        <field name="openid_url"/>
+                        <field name="openid_email"/>
+                    </page>
+                </notebook>
+            </field>
+        </record>
+    </data>
+</openerp>
+

=== added directory 'auth_openid/static'
=== added directory 'auth_openid/static/src'
=== added directory 'auth_openid/static/src/css'
=== added file 'auth_openid/static/src/css/openid.css'
--- auth_openid/static/src/css/openid.css	1970-01-01 00:00:00 +0000
+++ auth_openid/static/src/css/openid.css	2011-09-30 13:34:22 +0000
@@ -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;
+}

=== added directory 'auth_openid/static/src/img'
=== added file 'auth_openid/static/src/img/aol.png'
Binary files auth_openid/static/src/img/aol.png	1970-01-01 00:00:00 +0000 and auth_openid/static/src/img/aol.png	2011-09-30 13:34:22 +0000 differ
=== added file 'auth_openid/static/src/img/claimid.png'
Binary files auth_openid/static/src/img/claimid.png	1970-01-01 00:00:00 +0000 and auth_openid/static/src/img/claimid.png	2011-09-30 13:34:22 +0000 differ
=== added file 'auth_openid/static/src/img/google.png'
Binary files auth_openid/static/src/img/google.png	1970-01-01 00:00:00 +0000 and auth_openid/static/src/img/google.png	2011-09-30 13:34:22 +0000 differ
=== added file 'auth_openid/static/src/img/googleapps.gif'
Binary files auth_openid/static/src/img/googleapps.gif	1970-01-01 00:00:00 +0000 and auth_openid/static/src/img/googleapps.gif	2011-09-30 13:34:22 +0000 differ
=== added file 'auth_openid/static/src/img/googlefav.png'
Binary files auth_openid/static/src/img/googlefav.png	1970-01-01 00:00:00 +0000 and auth_openid/static/src/img/googlefav.png	2011-09-30 13:34:22 +0000 differ
=== added file 'auth_openid/static/src/img/launchpad.gif'
Binary files auth_openid/static/src/img/launchpad.gif	1970-01-01 00:00:00 +0000 and auth_openid/static/src/img/launchpad.gif	2011-09-30 13:34:22 +0000 differ
=== added file 'auth_openid/static/src/img/launchpad.png'
Binary files auth_openid/static/src/img/launchpad.png	1970-01-01 00:00:00 +0000 and auth_openid/static/src/img/launchpad.png	2011-09-30 13:34:22 +0000 differ
=== added file 'auth_openid/static/src/img/login-bg.gif'
Binary files auth_openid/static/src/img/login-bg.gif	1970-01-01 00:00:00 +0000 and auth_openid/static/src/img/login-bg.gif	2011-09-30 13:34:22 +0000 differ
=== added file 'auth_openid/static/src/img/marketplace.gif'
Binary files auth_openid/static/src/img/marketplace.gif	1970-01-01 00:00:00 +0000 and auth_openid/static/src/img/marketplace.gif	2011-09-30 13:34:22 +0000 differ
=== added file 'auth_openid/static/src/img/myopenid.png'
Binary files auth_openid/static/src/img/myopenid.png	1970-01-01 00:00:00 +0000 and auth_openid/static/src/img/myopenid.png	2011-09-30 13:34:22 +0000 differ
=== added file 'auth_openid/static/src/img/openid.png'
Binary files auth_openid/static/src/img/openid.png	1970-01-01 00:00:00 +0000 and auth_openid/static/src/img/openid.png	2011-09-30 13:34:22 +0000 differ
=== added file 'auth_openid/static/src/img/openid_16.png'
Binary files auth_openid/static/src/img/openid_16.png	1970-01-01 00:00:00 +0000 and auth_openid/static/src/img/openid_16.png	2011-09-30 13:34:22 +0000 differ
=== added file 'auth_openid/static/src/img/textfield_key.png'
Binary files auth_openid/static/src/img/textfield_key.png	1970-01-01 00:00:00 +0000 and auth_openid/static/src/img/textfield_key.png	2011-09-30 13:34:22 +0000 differ
=== added file 'auth_openid/static/src/img/verisign.png'
Binary files auth_openid/static/src/img/verisign.png	1970-01-01 00:00:00 +0000 and auth_openid/static/src/img/verisign.png	2011-09-30 13:34:22 +0000 differ
=== added file 'auth_openid/static/src/img/yahoo.png'
Binary files auth_openid/static/src/img/yahoo.png	1970-01-01 00:00:00 +0000 and auth_openid/static/src/img/yahoo.png	2011-09-30 13:34:22 +0000 differ
=== added directory 'auth_openid/static/src/js'
=== added file 'auth_openid/static/src/js/auth_openid.js'
--- auth_openid/static/src/js/auth_openid.js	1970-01-01 00:00:00 +0000
+++ auth_openid/static/src/js/auth_openid.js	2011-09-30 13:34:22 +0000
@@ -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 ?
+            }
+
+        });
+    },
+
+
+});
+
+
+};

=== added directory 'auth_openid/static/src/xml'
=== added file 'auth_openid/static/src/xml/auth_openid.xml'
--- auth_openid/static/src/xml/auth_openid.xml	1970-01-01 00:00:00 +0000
+++ auth_openid/static/src/xml/auth_openid.xml	2011-09-30 13:34:22 +0000
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vim:fdl=1: -->
+<templates id="template" xml:space="preserve">
+
+    <t t-extend="Login">
+        <t t-jquery=".oe_box2 tr:first td:nth-child(2)" t-operation="append">
+            <ul class="openid_providers">
+                <li><a href="#login,password" title="Password" data-url="" id="btn_password">Password</a></li>
+                <li><a href="#google" title="Google" data-url="https://www.google.com/accounts/o8/id";>Google</a></li>
+                <li><a href="#googleapps" title="Google Apps" data-url="https://www.google.com/accounts/o8/site-xrds?hd={id}";>Google</a></li>
+                <li><a href="#launchpad" title="Launchpad" data-url="https://launchpad.net/~{id}";>Launchpad</a></li>
+                <li><a href="#openid_url" title="OpenID" data-url="{id}">OpenID</a></li>
+            </ul>
+        </t>
+    </t>
+
+    <t t-extend="Login">
+        <t t-jquery=".oe_box2 tr:first" t-operation="after">
+            <tr>
+                <td><label for="googleapps">Google Apps Domain:</label></td>
+                <td><input type="text" name="googleapps" /></td>
+            </tr>
+            <tr>
+                <td><label for="launchpad">Username:</label></td>
+                <td><input type="text" name="launchpad" /></td>
+            </tr>
+            <tr>
+                <td><label for="openid_url">OpenID URL:</label></td>
+                <td><input type="text" name="openid_url" /></td>
+            </tr>
+        </t>
+    </t>
+
+    <t t-extend="Login">
+        <t t-jquery=".oe_box2 tr:has(input[name!='db'])">
+            //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'));
+            });
+        </t>
+    </t>
+
+</templates>

=== added file 'auth_openid/utils.py'
--- auth_openid/utils.py	1970-01-01 00:00:00 +0000
+++ auth_openid/utils.py	2011-09-30 13:34:22 +0000
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+##############################################################################
+#    
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2010-2011 OpenERP s.a. (<http://openerp.com>).
+#
+#    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 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()
+

_______________________________________________
Mailing list: https://launchpad.net/~openerp-dev-gtk
Post to     : [email protected]
Unsubscribe : https://launchpad.net/~openerp-dev-gtk
More help   : https://help.launchpad.net/ListHelp

Reply via email to