[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