# HG changeset patch # User Florent Aide <florent.aide@gmail.com> # Date 1433446273 -7200 # Thu Jun 04 21:31:13 2015 +0200 # Branch odoo8 # Node ID 6d2087dae38a0fa73b3b9872272353e2bd5e1951 # Parent aed15c7e0451fcac62e7042c6d2a66e8244ac496 First v8 API batch diff --git a/controllers/main.py b/controllers/main.py --- a/controllers/main.py +++ b/controllers/main.py @@ -124,14 +124,15 @@ state = self.get_state(provider_id) try: - with request.registry.cursor() as cr: - auth_request = provider_osv._get_auth_request( - cr, SUPERUSER_ID, provider_id, state=state - ) + auth_request = provider_osv._get_auth_request( + request.cr, SUPERUSER_ID, provider_id, state + ) except Exception, e: _logger.exception("SAML2: %s" % str(e)) + # TODO: handle case when auth_request comes back as None + # store a RelayState on the request to our IDP so that the IDP # can send us back this info alongside the obtained token params = { diff --git a/model/auth_saml.py b/model/auth_saml.py --- a/model/auth_saml.py +++ b/model/auth_saml.py @@ -1,38 +1,39 @@ -from openerp.osv import fields -from openerp.osv import osv +from openerp import models +from openerp import api +from openerp import fields import lasso import simplejson -from openerp import SUPERUSER_ID -class auth_saml_provider(osv.osv): +class auth_saml_provider(models.Model): """Class defining the configuration values of an Saml2 provider""" _name = 'auth.saml.provider' _description = 'SAML2 provider' _order = 'name' - def _get_lasso_for_provider(self, cr, uid, pid, context=None): + @api.multi + def _get_lasso_for_provider(self): # user is not connected yet... so use SUPERUSER_ID - provider = self.browse(cr, SUPERUSER_ID, pid, context=context) # TODO: we should cache those results somewhere because it is # really costy to always recreate a login variable from buffers server = lasso.Server.newFromBuffers( - provider.sp_metadata, - provider.sp_pkey + self.sp_metadata, + self.sp_pkey ) server.addProviderFromBuffer( lasso.PROVIDER_ROLE_IDP, - provider.idp_metadata + self.idp_metadata ) return lasso.Login(server) - def _get_auth_request(self, cr, uid, pid, state, context=None): + @api.multi + def _get_auth_request(self, state): """build an authentication request and give it back to our client WARNING: this method cannot be used for multiple ids """ - login = self._get_lasso_for_provider(cr, uid, pid, context=context) + login = self._get_lasso_for_provider() # ! -- this is the part that MUST be performed on each call and # cannot be cached @@ -46,25 +47,14 @@ # obtained after the buildAuthnRequestMsg() call return login.msgUrl - _columns = { - # Name of the OAuth2 entity, authentic, xcg... - 'name': fields.char('Provider name'), - 'idp_metadata': fields.text('IDP Configuration'), - 'sp_metadata': fields.text('SP Configuration'), - 'sp_pkey': fields.text( - 'Private key of our service provider (this openerpserver)' - ), - 'enabled': fields.boolean('Enabled'), - 'css_class': fields.char('CSS class'), - 'body': fields.char( - 'Body', - required=True, - ), - 'sequence': fields.integer(), - } - - _defaults = { - 'enabled': False, - 'css_class': 'zocial saml', - 'body': 'Authentic', - } + # Name of the OAuth2 entity, authentic, xcg... + name = fields.Char('Provider name') + idp_metadata = fields.Text('IDP Configuration') + sp_metadata = fields.Text('SP Configuration') + sp_pkey = fields.Text( + 'Private key of our service provider (this openerpserver)' + ) + enabled = fields.Boolean('Enabled', default=False) + sequence = fields.Integer('Sequence') + css_class = fields.Char('CSS Class') + body = fields.Char('Body') diff --git a/model/res_users.py b/model/res_users.py --- a/model/res_users.py +++ b/model/res_users.py @@ -6,37 +6,38 @@ import passlib import openerp -from openerp.osv import osv, fields +from openerp import api +from openerp import models +from openerp import fields from openerp import SUPERUSER_ID +from openerp.addons.base.res.res_users import res_users as baseuser _logger = logging.getLogger(__name__) -class res_users(osv.Model): +class res_users(models.Model): _inherit = 'res.users' - _columns = { - 'saml_provider_id': fields.many2one( - 'auth.saml.provider', - string='SAML Provider', - ), - 'saml_uid': fields.char( - 'SAML User ID', - help="SAML Provider user_id", - ), - } + saml_provider_id = fields.Many2one( + 'auth.saml.provider', + string='SAML Provider', + ) + saml_uid = fields.Char( + 'SAML User ID', + help="SAML Provider user_id", + ) - def _no_password_with_saml(self, cr, uid, ids, context=None): + @api.multi + def _no_password_with_saml(self): """Ensure no Odoo user posesses both an SAML user ID and an Odoo password. """ - if self._allow_saml_uid_and_internal_password(cr, uid, context): + if self._allow_saml_uid_and_internal_password(): # The constraint is a no-op in this case. return True - users = self.browse(cr, uid, ids, context=context) - for user in users: + for user in self: if user.password and user.saml_uid: return False @@ -61,15 +62,16 @@ ), ] - def _auth_saml_validate(self, cr, uid, provider_id, token, context=None): + @api.multi + def _auth_saml_validate(self, provider_id, token): """ return the validation data corresponding to the access token """ - p = self.pool.get('auth.saml.provider') + pobj = self.env['auth.saml.provider'] + p = pobj.browse(provider_id) + # 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_id, context=context - ) + login = p.sudo()._get_lasso_for_provider() try: login.processAuthnResponseMsg(token) @@ -87,19 +89,10 @@ # TODO use a real token validation from LASSO # TODO push into the validation result a real UPN - validation = {'user_id': login.assertion.subject.nameId.content} + return {'user_id': login.assertion.subject.nameId.content} - """ - if p.data_endpoint: - data = self._auth_oauth_rpc(cr, uid, p.data_endpoint, access_token) - validation.update(data) - """ - - return validation - - def _auth_saml_signin( - self, cr, uid, provider, validation, saml_response, context=None - ): + @api.multi + def _auth_saml_signin(self, provider, validation, saml_response): """ retrieve and sign into openerp the user corresponding to provider and validated access token @@ -111,11 +104,10 @@ This method can be overridden to add alternative signin methods. """ - token_osv = self.pool.get('auth_saml.token') + token_osv = self.env['auth_saml.token'] saml_uid = validation['user_id'] user_ids = self.search( - cr, uid, [ ("saml_uid", "=", saml_uid), ('saml_provider_id', '=', provider), @@ -128,59 +120,48 @@ # TODO replace assert by proper raise... asserts do not execute in # production code... assert len(user_ids) == 1 - - # browse the user because we'll need this in the response - user = self.browse(cr, uid, user_ids[0], context=context) - - user_id = user.id + user = user_ids[0] # now find if a token for this user/provider already exists token_ids = token_osv.search( - cr, uid, [ ('saml_provider_id', '=', provider), - ('user_id', '=', user_id), + ('user_id', '=', user.id), ] ) + if token_ids: - token_osv.write( - cr, uid, token_ids, + token_ids.write( {'saml_access_token': saml_response}, - context=context ) else: token_osv.create( - cr, uid, { 'saml_access_token': saml_response, 'saml_provider_id': provider, - 'user_id': user_id, + 'user_id': user.id, }, - context=context ) return user.login - def auth_saml(self, cr, uid, provider, saml_response, context=None): + @api.model + def auth_saml(self, provider, saml_response): - validation = self._auth_saml_validate( - cr, uid, provider, saml_response - ) + validation = self._auth_saml_validate(provider, saml_response) # required check if not validation.get('user_id'): raise openerp.exceptions.AccessDenied() # retrieve and sign in user - login = self._auth_saml_signin( - cr, uid, provider, validation, saml_response, context=context - ) + login = self._auth_saml_signin(provider, validation, saml_response) if not login: raise openerp.exceptions.AccessDenied() # return user credentials - return cr.dbname, login, saml_response + return self.env.cr.dbname, login, saml_response def check_credentials(self, cr, uid, token): """token can be a password if the user has used the normal form... @@ -188,8 +169,14 @@ and the interesting code is inside the except clause """ token_osv = self.pool.get('auth_saml.token') + try: - super(res_users, self).check_credentials(cr, uid, token) + baseuser.check_credentials( + self, + cr, + uid, + token + ) except (openerp.exceptions.AccessDenied, passlib.exc.PasswordSizeError): # since normal auth did not succeed we now try to find if the user