[Erp5-report] r40315 kazuhiko - in /erp5/trunk/products/ERP5Security: ./ tests/ www/
nobody at svn.erp5.org
nobody at svn.erp5.org
Wed Nov 17 09:24:59 CET 2010
Author: kazuhiko
Date: Wed Nov 17 09:24:58 2010
New Revision: 40315
URL: http://svn.erp5.org?rev=40315&view=rev
Log:
initial implementation of ERP5 External Auth Plugin, that extract the user_id from the HTTP request header.
Added:
erp5/trunk/products/ERP5Security/ERP5ExternalAuthPlugin.py
erp5/trunk/products/ERP5Security/www/ERP5Security_addERP5ExternalAuthPlugin.zpt
erp5/trunk/products/ERP5Security/www/ERP5Security_editERP5ExternalAuthPlugin.zpt
Modified:
erp5/trunk/products/ERP5Security/__init__.py
erp5/trunk/products/ERP5Security/tests/testERP5Security.py
Added: erp5/trunk/products/ERP5Security/ERP5ExternalAuthPlugin.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Security/ERP5ExternalAuthPlugin.py?rev=40315&view=auto
==============================================================================
--- erp5/trunk/products/ERP5Security/ERP5ExternalAuthPlugin.py (added)
+++ erp5/trunk/products/ERP5Security/ERP5ExternalAuthPlugin.py [utf8] Wed Nov 17 09:24:58 2010
@@ -0,0 +1,214 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved.
+# Francois-Xavier Algrain <fxalgrain at tiolive.com>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+##############################################################################
+
+from DateTime import DateTime
+from zLOG import LOG, PROBLEM
+from Products.ERP5Type.Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from AccessControl.SecurityManagement import getSecurityManager,\
+ newSecurityManager,\
+ setSecurityManager
+
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+
+from Products.PluggableAuthService.interfaces import plugins
+from Products.PluggableAuthService.utils import classImplements
+from Products.PluggableAuthService.permissions import ManageUsers
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+from Products.PluggableAuthService.plugins.CookieAuthHelper import CookieAuthHelper
+
+from Products.ERP5Type.Cache import CachingMethod
+from Products.ERP5Security.ERP5UserManager import ERP5UserManager,\
+ SUPER_USER, _AuthenticationFailure
+
+#Form for new plugin in ZMI
+manage_addERP5ExternalAuthPluginForm = PageTemplateFile(
+ 'www/ERP5Security_addERP5ExternalAuthPlugin', globals(),
+ __name__='manage_addERP5ExternalAuthPluginForm')
+
+def addERP5ExternalAuthPlugin(dispatcher, id, title=None, user_id_key='',
+ REQUEST=None):
+ """ Add a ERP5ExternalAuthPlugin to a Pluggable Auth Service. """
+
+ plugin = ERP5ExternalAuthPlugin( id, title, user_id_key)
+ dispatcher._setObject(plugin.getId(), plugin)
+
+ if REQUEST is not None:
+ REQUEST['RESPONSE'].redirect(
+ '%s/manage_workspace'
+ '?manage_tabs_message='
+ 'ERP5ExternalAuthPlugin+added.'
+ % dispatcher.absolute_url())
+
+class ERP5ExternalAuthPlugin(ERP5UserManager, CookieAuthHelper):
+ """
+ External authentification PAS plugin which extracts the user id from HTTP
+ request header, like REMOTE_USER, openAMid, etc.
+ """
+
+ meta_type = "ERP5 External Auth Plugin"
+ security = ClassSecurityInfo()
+ user_id_key = ''
+
+ manage_options = (({'label': 'Edit',
+ 'action': 'manage_editERP5ExternalAuthPluginForm',},
+ )
+ + BasePlugin.manage_options[:]
+ )
+
+ def __init__(self, id, title=None, user_id_key=''):
+ #Register value
+ self._setId(id)
+ self.title = title
+ self.user_id_key = user_id_key
+
+ ####################################
+ #ILoginPasswordHostExtractionPlugin#
+ ####################################
+ security.declarePrivate('extractCredentials')
+ def extractCredentials(self, request):
+ """ Extract credentials from the request header. """
+ creds = {}
+ user_id = request.getHeader(self.user_id_key, literal=True)
+ if user_id is not None:
+ creds['login'] = user_id
+
+ #Complete credential with some informations
+ if creds:
+ creds['remote_host'] = request.get('REMOTE_HOST', '')
+ try:
+ creds['remote_address'] = request.getClientAddr()
+ except AttributeError:
+ creds['remote_address'] = request.get('REMOTE_ADDR', '')
+
+ return creds
+
+ ################################
+ # IAuthenticationPlugin #
+ ################################
+ security.declarePrivate('authenticateCredentials')
+ def authenticateCredentials( self, credentials ):
+ """Authentificate with credentials"""
+ login = credentials.get('login', None)
+ # Forbidden the usage of the super user.
+ if login == SUPER_USER:
+ return None
+
+ #Function to allow cache
+ def _authenticateCredentials(login):
+ if not login:
+ return None
+
+ #Search the user by his login
+ user_list = self.getUserByLogin(login)
+ if len(user_list) != 1:
+ raise _AuthenticationFailure()
+ user = user_list[0]
+
+ #We need to be super_user
+ sm = getSecurityManager()
+ if sm.getUser().getId() != SUPER_USER:
+ newSecurityManager(self, self.getUser(SUPER_USER))
+ try:
+ # get assignment list
+ assignment_list = [x for x in user.objectValues(portal_type="Assignment") \
+ if x.getValidationState() == "open"]
+ valid_assignment_list = []
+ # check dates if exist
+ login_date = DateTime()
+ for assignment in assignment_list:
+ if assignment.getStartDate() is not None and \
+ assignment.getStartDate() > login_date:
+ continue
+ if assignment.getStopDate() is not None and \
+ assignment.getStopDate() < login_date:
+ continue
+ valid_assignment_list.append(assignment)
+
+ # validate
+ if len(valid_assignment_list) > 0:
+ return (login,login)
+ finally:
+ setSecurityManager(sm)
+
+ raise _AuthenticationFailure()
+
+ #Cache Method for best performance
+ _authenticateCredentials = CachingMethod(
+ _authenticateCredentials,
+ id='ERP5ExternalAuthPlugin_authenticateCredentials',
+ cache_factory='erp5_content_short')
+ try:
+ return _authenticateCredentials(login=login)
+ except _AuthenticationFailure:
+ return None
+ except StandardError,e:
+ #Log standard error
+ LOG('ERP5ExternalAuthPlugin.authenticateCredentials', PROBLEM, str(e))
+ return None
+
+ ################################
+ # Properties for ZMI managment #
+ ################################
+
+ #'Edit' option form
+ manage_editERP5ExternalAuthPluginForm = PageTemplateFile(
+ 'www/ERP5Security_editERP5ExternalAuthPlugin',
+ globals(),
+ __name__='manage_editERP5ExternalAuthPluginForm' )
+
+ security.declareProtected( ManageUsers, 'manage_editExternalAuthPlugin' )
+ def manage_editExternalAuthPlugin(self, user_id_key, RESPONSE=None):
+ """Edit the object"""
+ error_message = ''
+
+ #Save user_id_key
+ if user_id_key == '' or user_id_key is None:
+ error_message += 'Invalid key value '
+ else:
+ self.user_id_key = user_id_key
+
+ #Redirect
+ if RESPONSE is not None:
+ if error_message != '':
+ self.REQUEST.form['manage_tabs_message'] = error_message
+ return self.manage_editERP5ExternalAuthPluginForm(RESPONSE)
+ else:
+ message = "Updated"
+ RESPONSE.redirect('%s/manage_editERP5ExternalAuthPluginForm'
+ '?manage_tabs_message=%s'
+ % ( self.absolute_url(), message )
+ )
+
+#List implementation of class
+classImplements(ERP5ExternalAuthPlugin,
+ plugins.IAuthenticationPlugin,
+ plugins.ILoginPasswordHostExtractionPlugin)
+
+InitializeClass(ERP5ExternalAuthPlugin)
Modified: erp5/trunk/products/ERP5Security/__init__.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Security/__init__.py?rev=40315&r1=40314&r2=40315&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Security/__init__.py [utf8] (original)
+++ erp5/trunk/products/ERP5Security/__init__.py [utf8] Wed Nov 17 09:24:58 2010
@@ -26,6 +26,7 @@ import ERP5GroupManager
import ERP5RoleManager
import ERP5UserFactory
import ERP5KeyAuthPlugin
+import ERP5ExternalAuthPlugin
def mergedLocalRoles(object):
"""Returns a merging of object and its ancestors'
@@ -60,6 +61,7 @@ registerMultiPlugin(ERP5GroupManager.ERP
registerMultiPlugin(ERP5RoleManager.ERP5RoleManager.meta_type)
registerMultiPlugin(ERP5UserFactory.ERP5UserFactory.meta_type)
registerMultiPlugin(ERP5KeyAuthPlugin.ERP5KeyAuthPlugin.meta_type)
+registerMultiPlugin(ERP5ExternalAuthPlugin.ERP5ExternalAuthPlugin.meta_type)
def initialize(context):
@@ -108,6 +110,15 @@ def initialize(context):
, icon='www/portal.gif'
)
+ context.registerClass( ERP5ExternalAuthPlugin.ERP5ExternalAuthPlugin
+ , permission=ManageUsers
+ , constructors=(
+ ERP5ExternalAuthPlugin.manage_addERP5ExternalAuthPluginForm,
+ ERP5ExternalAuthPlugin.addERP5ExternalAuthPlugin, )
+ , visibility=None
+ , icon='www/portal.gif'
+ )
+
from AccessControl.SecurityInfo import ModuleSecurityInfo
ModuleSecurityInfo('Products.ERP5Security.ERP5UserManager').declarePublic(
'getUserByLogin')
Modified: erp5/trunk/products/ERP5Security/tests/testERP5Security.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Security/tests/testERP5Security.py?rev=40315&r1=40314&r2=40315&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Security/tests/testERP5Security.py [utf8] (original)
+++ erp5/trunk/products/ERP5Security/tests/testERP5Security.py [utf8] Wed Nov 17 09:24:58 2010
@@ -723,6 +723,50 @@ class TestLocalRoleManagement(ERP5TypeTe
self.assertEqual(response.getStatus(), 200)
self.assertTrue(reference in response.getBody())
+ def testERP5ExternalAuthPlugin(self):
+ """
+ Make sure that we can grant security using a ERP5 External Auth Plugin.
+ """
+ user_id_key = 'openAMid'
+ # add key authentication PAS plugin
+ portal = self.portal
+ uf = portal.acl_users
+ uf.manage_addProduct['ERP5Security'].addERP5ExternalAuthPlugin(
+ id='erp5_external_auth_plugin', \
+ title='ERP5 External Auth Plugin',\
+ user_id_key=user_id_key,)
+
+ erp5_external_auth_plugin = getattr(uf, 'erp5_external_auth_plugin')
+ erp5_external_auth_plugin.manage_activateInterfaces(
+ interfaces=['IExtractionPlugin',
+ 'IAuthenticationPlugin'])
+ self.stepTic()
+
+ reference = 'external_auth_person'
+ loginable_person = self.getPersonModule().newContent(portal_type='Person',
+ reference=reference,
+ password='guest')
+ assignment = loginable_person.newContent(portal_type='Assignment',
+ function='another_subcat')
+ assignment.open()
+ self.stepTic()
+
+ base_url = '%s/view' %portal.absolute_url(relative=1)
+
+ # without key we are Anonymous User so we should be redirected with proper HTML
+ # status code to login_form
+ response = self.publish(base_url)
+ self.assertEqual(response.getStatus(), 302)
+ # TODO we should not have redirect but output 403 or 404, because
+ # login process should be provided by an external application.
+ # self.assertTrue('location' in response.headers.keys())
+ # self.assertTrue(response.headers['location'].endswith('login_form'))
+
+ # view front page we should be logged in if we use authentication key
+ response = self.publish(base_url, env={user_id_key:reference})
+ self.assertEqual(response.getStatus(), 200)
+ self.assertTrue(reference in response.getBody())
+
def _createZodbUser(self, login, role_list=None):
if role_list is None:
role_list = ['Member', 'Assignee', 'Assignor', 'Author', 'Auditor',
Added: erp5/trunk/products/ERP5Security/www/ERP5Security_addERP5ExternalAuthPlugin.zpt
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Security/www/ERP5Security_addERP5ExternalAuthPlugin.zpt?rev=40315&view=auto
==============================================================================
--- erp5/trunk/products/ERP5Security/www/ERP5Security_addERP5ExternalAuthPlugin.zpt (added)
+++ erp5/trunk/products/ERP5Security/www/ERP5Security_addERP5ExternalAuthPlugin.zpt [utf8] Wed Nov 17 09:24:58 2010
@@ -0,0 +1,46 @@
+<h1 tal:replace="structure context/manage_page_header">PAGE HEADER</h1>
+<h2 tal:define="form_title string:Add ERP5 External Authentication PAS"
+ tal:replace="structure context/manage_form_title">FORM TITLE</h2>
+
+<p class="form-help">Please input the configuration</p>
+
+<form action="addERP5ExternalAuthPlugin" method="POST">
+<table cellspacing="0" cellpadding="2" border="0">
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Id
+ </div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="id" size="40" />
+ </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Title
+ </div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="title" size="40" />
+ </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ HTTP request header key where the user_id is stored
+ </div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="user_id_key" size="40" />
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2"> <input type="submit" value="add plugin"/>
+ </td>
+ </tr>
+</table>
+</form>
+
+<h1 tal:replace="structure context/manage_page_footer">PAGE FOOTER</h1>
Added: erp5/trunk/products/ERP5Security/www/ERP5Security_editERP5ExternalAuthPlugin.zpt
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Security/www/ERP5Security_editERP5ExternalAuthPlugin.zpt?rev=40315&view=auto
==============================================================================
--- erp5/trunk/products/ERP5Security/www/ERP5Security_editERP5ExternalAuthPlugin.zpt (added)
+++ erp5/trunk/products/ERP5Security/www/ERP5Security_editERP5ExternalAuthPlugin.zpt [utf8] Wed Nov 17 09:24:58 2010
@@ -0,0 +1,29 @@
+<h1 tal:replace="structure context/manage_page_header">PAGE HEADER</h1>
+<h2 tal:replace="structure here/manage_tabs"> TABS </h2>
+<h2 tal:define="form_title string:Edit ERP5 External Authentification Plugin"
+ tal:replace="structure context/manage_form_title">FORM TITLE</h2>
+
+<p class="form-help">Please input the configuration for the radius host</p>
+
+<form action="manage_editExternalAuthPlugin" method="POST">
+
+<table tal:define="user_id_key request/user_id_key|context/user_id_key|string:;">
+
+<tr>
+ <td>HTTP request header key where the user_id is stored</td>
+ <td>
+ <input type="text" name="user_id_key" value=""
+ tal:attributes="value user_id_key;" />
+ </td>
+</tr>
+<tr>
+ <td colspan="2">
+ <input type="submit" value="save"/>
+ </td>
+</tr>
+
+</table>
+
+</form>
+
+<h1 tal:replace="structure context/manage_page_footer">PAGE FOOTER</h1>
More information about the Erp5-report
mailing list