# HG changeset patch # User Florent Aide <florent.aide@gmail.com> # Date 1433382584 -7200 # Thu Jun 04 03:49:44 2015 +0200 # Branch odoo8 # Node ID cd10d1d08dc34e11d2722d692f095c9f6a5155bf # Parent 24a71db8c2652ac8562b55144018d423f6972774 WIP, porting to v8 diff --git a/__openerp__.py b/__openerp__.py --- a/__openerp__.py +++ b/__openerp__.py @@ -31,7 +31,11 @@ 'author': 'XCG Consulting s.a.s.', 'maintainer': 'XCG Consulting s.a.s.', 'website': 'http://www.xcg-consulting.fr', - 'depends': ['base', 'web', 'base_setup'], + 'depends': [ + 'base', + 'base_setup', + 'web', + ], 'data': [ 'data/auth_saml.xml', @@ -49,7 +53,6 @@ 'static/lib/zocial/css/zocial.css', 'static/src/css/auth_saml.css', ], - 'qweb': ['static/src/xml/auth_saml.xml'], 'installable': True, 'auto_install': False, } diff --git a/controllers/main.py b/controllers/main.py --- a/controllers/main.py +++ b/controllers/main.py @@ -5,11 +5,13 @@ import werkzeug.utils import openerp +from openerp import http +from openerp.http import request from openerp import SUPERUSER_ID -import openerp.addons.web.http as oeweb +# import openerp.addons.web.http as oeweb from openerp.addons.web.controllers.main import set_cookie_and_redirect +from openerp.addons.web.controllers.main import ensure_db from openerp.addons.web.controllers.main import login_and_redirect -from openerp.modules.registry import RegistryManager _logger = logging.getLogger(__name__) @@ -40,74 +42,105 @@ # ---------------------------------------------------------- # Controller # ---------------------------------------------------------- -class SAMLController(oeweb.Controller): - _cp_path = '/auth_saml' +class SAMLLogin(openerp.addons.web.controllers.main.Home): + + def list_providers(self): + try: + provider_obj = request.registry.get('auth.saml.provider') + providers = provider_obj.search_read( + request.cr, SUPERUSER_ID, [('enabled', '=', True)] + ) + except Exception, e: + _logger.exception("SAML2: %s" % str(e)) + providers = [] + + return providers + + @http.route() + def web_login(self, *args, **kw): + ensure_db() + if ( + request.httprequest.method == 'GET' and + request.session.uid and + request.params.get('redirect') + ): + + # Redirect if already logged in and redirect param is present + return http.redirect_with_hash(request.params.get('redirect')) + + providers = self.list_providers() - @oeweb.jsonrequest - def get_auth_request(self, req, relaystate): + response = super(SAMLLogin, self).web_login(*args, **kw) + if response.is_qweb: + error = request.params.get('saml_error') + if error == '1': + error = _("Sign up is not allowed on this database.") + elif error == '2': + error = _("Access Denied") + elif error == '3': + error = _( + "You do not have access to this database or your " + "invitation has expired. Please ask for an invitation " + "and be sure to follow the link in your invitation email." + ) + else: + error = None + + response.qcontext['providers'] = providers + + if error: + response.qcontext['error'] = error + + return response + + +class AuthSAMLController(http.Controller): + + @http.route('/auth_saml/get_auth_request', type='http', auth='none') + def get_auth_request(self, pid): """state is the JSONified state object and we need to pass it inside our request as the RelayState argument """ - state = simplejson.loads(relaystate) - dbname = state['d'] - provider_id = state['p'] - context = state.get('c', {}) - - registry = RegistryManager.get(dbname) - provider_osv = registry.get('auth.saml.provider') + provider_id = int(pid) + provider_osv = request.registry.get('auth.saml.provider') auth_request = None try: - with registry.cursor() as cr: + with request.registry.cursor() as cr: auth_request = provider_osv._get_auth_request( - cr, SUPERUSER_ID, provider_id, state, context=context + cr, SUPERUSER_ID, provider_id, pid ) except Exception, e: _logger.exception("SAML2: %s" % str(e)) - return {'auth_request': auth_request} + # store a RelayState on the request to our IDP so that the IDP + # can send us back this info alongside the obtained token + params = { + "RelayState": simplejson.dumps({ + "d": request.session.db, + "p": pid, + }), + } + url = auth_request + "&" + werkzeug.url_encode(params) + print "*"*35 + print url + print "*"*35 + redirect = werkzeug.utils.redirect(url, 303) + redirect.autocorrect_location_header = True + return redirect - @oeweb.jsonrequest - def list_providers(self, req, dbname): - l = [] - try: - registry = RegistryManager.get(dbname) - with registry.cursor() as cr: - providers = registry.get('auth.saml.provider') - if providers: - l = providers.read( - cr, SUPERUSER_ID, providers.search( - cr, SUPERUSER_ID, [('enabled', '=', True)] - ), - [ - "id", - "name", - "enabled", - "css_class", - "body", - "sequence", - ], - ) - else: - l = [] - - except Exception, e: - _logger.exception("SAML2: %s" % str(e)) - - return l - - @oeweb.httprequest + @http.route('/auth_saml/signin', type='http', auth='none') @fragment_to_query_string def signin(self, req, **kw): - """JS client obtained a saml token and passed it back + """client obtained a saml token and passed it back to us... we need to validate it """ saml_response = kw.get('SAMLResponse', None) - if not kw.get('RelayState', None): + if kw.get('RelayState', None) is None: # here we are in front of a client that went through # some routes that "lost" its relaystate... this can happen # if the client visited his IDP and successfully logged in @@ -119,16 +152,17 @@ return redirect state = simplejson.loads(kw['RelayState']) - dbname = state['d'] - provider = state['p'] - context = state.get('c', {}) - registry = RegistryManager.get(dbname) + print "*"*35 + print state + print "*"*35 + # THIS IS FALSE TODO TODO + provider = state - with registry.cursor() as cr: + with request.registry.cursor() as cr: try: - u = registry.get('res.users') + u = request.registry.get('res.users') credentials = u.auth_saml( - cr, SUPERUSER_ID, provider, saml_response, context=context + cr, SUPERUSER_ID, provider, saml_response ) cr.commit() action = state.get('a') @@ -141,10 +175,10 @@ return login_and_redirect(req, *credentials, redirect_url=url) except AttributeError, e: - print e + # print e # auth_signup is not installed _logger.error("auth_signup not installed on database " - "%s: saml sign up cancelled." % (dbname,)) + "saml sign up cancelled.") url = "/#action=login&saml_error=1" except openerp.exceptions.AccessDenied: @@ -164,6 +198,6 @@ _logger.exception("SAML2: %s" % str(e)) url = "/#action=login&saml_error=2" - return set_cookie_and_redirect(req, url) + return set_cookie_and_redirect(url) # vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/model/res_users.py b/model/res_users.py --- a/model/res_users.py +++ b/model/res_users.py @@ -62,7 +62,11 @@ """ return the validation data corresponding to the access token """ p = self.pool.get('auth.saml.provider') - login = p._get_lasso_for_provider(cr, uid, provider, context=context) + # we are not yet logged in, so the userid cannot have access to the + # fields we need yet + login = p._get_lasso_for_provider( + cr, SUPERUSER_ID, provider, context=context + ) try: login.processAuthnResponseMsg(token) diff --git a/static/src/xml/auth_saml.xml b/static/src/xml/auth_saml.xml deleted file mode 100644 --- a/static/src/xml/auth_saml.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<templates id="template" xml:space="preserve"> -<t t-name="auth_saml.Login.button"> - <t t-foreach="widget.saml_providers" t-as="p"> - <a href="#" t-attf-class="oe_saml_provider_login_button #{p.css_class}" t-att-data-index="p_index"><t t-esc="p.body"/></a> - </t> -</t> -</templates> diff --git a/views/auth_saml.xml b/views/auth_saml.xml --- a/views/auth_saml.xml +++ b/views/auth_saml.xml @@ -2,6 +2,24 @@ <openerp> <data> + <!-- login form button, new in Odoo8, Odoo7 automatically adds the button --> + <template id="auth_saml.providers" name="Auth SAML Providers"> + <div t-foreach="providers" t-as="p"> + <a t-att-href="'/auth_saml/get_auth_request?pid=%s'%p['id']" class="btn btn-link"> + <i t-att-class="p['css_class']"/> + <t t-esc="p['body']"/> + </a> + </div> + </template> + + <template id="auth_saml.login" inherit_id="web.login" name="Samlv2 Login buttons"> + <xpath expr="//button[@type='submit']" position="before"> + <div class="pull-right"> + <t t-call="auth_saml.providers"/> + </div> + </xpath> + </template> + <!-- Views for the auth.saml.provider model. --> <record model="ir.ui.view" id="view_saml_provider_list">