Commit bbd0f245 authored by Julien Muchembled's avatar Julien Muchembled

Reimplement ERP5Site_getAuthenticatedMemberPersonValue without using acl_users.erp5_users

Because some sites don't have an 'erp5_users' plugin in acl_users, and what
ERP5Site_getAuthenticatedMemberPersonValue does is not specific to 'erp5_users'.

This is done by moving code outside ERP5UserManager class so that it can be
reused. Changes to ERP5UserManager.getUserLogin method are:
- use a transactional cache instead of erp5_content_short:
  - a transactional cache is enough because authenticateCredentials already
    caches its result in erp5_content_short
  - no need to care about empty result from the catalog, which was done using
    _AuthenticationFailure (instead, we simply return an empty list)
  - cache person objects instead of their path
- no need to use SUPER_USER since we use unrestrictedSearchResults

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@37065 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent b9407de5
...@@ -57,11 +57,10 @@ ...@@ -57,11 +57,10 @@
"""\n """\n
owner_id_list = [i[0] for i in context.get_local_roles() if \'Owner\' in i[1]]\n owner_id_list = [i[0] for i in context.get_local_roles() if \'Owner\' in i[1]]\n
if owner_id_list:\n if owner_id_list:\n
found_user_list = context.acl_users.erp5_users.getUserByLogin(owner_id_list[0])\n from Products.ERP5Security.ERP5UserManager import getUserByLogin\n
found_user_list = getUserByLogin(context.getPortalObject(), tuple(owner_id_list))\n
if found_user_list:\n if found_user_list:\n
return found_user_list[0].getTitle()\n return found_user_list[0].getTitle()\n
\n
return owner\n
</string> </value> </string> </value>
</item> </item>
<item> <item>
...@@ -106,8 +105,10 @@ return owner\n ...@@ -106,8 +105,10 @@ return owner\n
<string>i</string> <string>i</string>
<string>_getitem_</string> <string>_getitem_</string>
<string>owner_id_list</string> <string>owner_id_list</string>
<string>Products.ERP5Security.ERP5UserManager</string>
<string>getUserByLogin</string>
<string>tuple</string>
<string>found_user_list</string> <string>found_user_list</string>
<string>owner</string>
</tuple> </tuple>
</value> </value>
</item> </item>
......
...@@ -56,15 +56,14 @@ ...@@ -56,15 +56,14 @@
<value> <string>"""Find and returns Person object for current logged in user.\n <value> <string>"""Find and returns Person object for current logged in user.\n
Returns None if no corresponding person, for example when not using ERP5Security.ERP5UserManager.\n Returns None if no corresponding person, for example when not using ERP5Security.ERP5UserManager.\n
"""\n """\n
portal = context.getPortalObject()\n
if user_name is None:\n if user_name is None:\n
user_name = context.portal_membership.getAuthenticatedMember()\n user_name = portal.portal_membership.getAuthenticatedMember()\n
\n \n
found_user_list = context.acl_users.erp5_users.getUserByLogin(str(user_name))\n from Products.ERP5Security.ERP5UserManager import getUserByLogin\n
found_users = len(found_user_list)\n found_user_list = getUserByLogin(portal, str(user_name))\n
if found_users != 1:\n if len(found_user_list) == 1:\n
return None\n return found_user_list[0]\n
\n
return found_user_list[0]\n
</string> </value> </string> </value>
</item> </item>
<item> <item>
...@@ -110,13 +109,15 @@ return found_user_list[0]\n ...@@ -110,13 +109,15 @@ return found_user_list[0]\n
<value> <value>
<tuple> <tuple>
<string>user_name</string> <string>user_name</string>
<string>None</string>
<string>_getattr_</string> <string>_getattr_</string>
<string>context</string> <string>context</string>
<string>portal</string>
<string>None</string>
<string>Products.ERP5Security.ERP5UserManager</string>
<string>getUserByLogin</string>
<string>str</string> <string>str</string>
<string>found_user_list</string> <string>found_user_list</string>
<string>len</string> <string>len</string>
<string>found_users</string>
<string>_getitem_</string> <string>_getitem_</string>
</tuple> </tuple>
</value> </value>
......
803 804
\ No newline at end of file \ No newline at end of file
...@@ -26,7 +26,7 @@ from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin ...@@ -26,7 +26,7 @@ from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
from Products.PluggableAuthService.utils import classImplements from Products.PluggableAuthService.utils import classImplements
from Products.PluggableAuthService.interfaces.plugins import IAuthenticationPlugin from Products.PluggableAuthService.interfaces.plugins import IAuthenticationPlugin
from Products.PluggableAuthService.interfaces.plugins import IUserEnumerationPlugin from Products.PluggableAuthService.interfaces.plugins import IUserEnumerationPlugin
from Products.ERP5Type.Cache import CachingMethod from Products.ERP5Type.Cache import CachingMethod, transactional_cached
from ZODB.POSException import ConflictError from ZODB.POSException import ConflictError
import sys import sys
from DateTime import DateTime from DateTime import DateTime
...@@ -64,6 +64,36 @@ class _AuthenticationFailure(Exception): ...@@ -64,6 +64,36 @@ class _AuthenticationFailure(Exception):
etc...) etc...)
""" """
@transactional_cached(lambda portal, *args: args)
def getUserByLogin(portal, login, exact_match=True):
if isinstance(login, basestring):
login = login,
if exact_match:
reference_key = 'ExactMatch'
else:
reference_key = 'Keyword'
result = portal.portal_catalog.unrestrictedSearchResults(
select_expression='reference',
portal_type="Person",
reference=dict(query=login, key=reference_key))
# XXX: Here, we filter catalog result list ALTHOUGH we did pass
# parameters to unrestrictedSearchResults to restrict result set.
# This is done because the following values can match person with
# reference "foo":
# "foo " because of MySQL (feature, PADSPACE collation):
# mysql> SELECT reference as r FROM catalog
# -> WHERE reference="foo ";
# +-----+
# | r |
# +-----+
# | foo |
# +-----+
# 1 row in set (0.01 sec)
# "bar OR foo" because of ZSQLCatalog tokenizing searched strings
# by default (feature).
return [x.getObject() for x in result if not exact_match
or x['reference'] in login]
class ERP5UserManager(BasePlugin): class ERP5UserManager(BasePlugin):
""" PAS plugin for managing users in ERP5 """ PAS plugin for managing users in ERP5
...@@ -180,81 +210,30 @@ class ERP5UserManager(BasePlugin): ...@@ -180,81 +210,30 @@ class ERP5UserManager(BasePlugin):
return tuple(user_info) return tuple(user_info)
def getUserByLogin(self, login, exact_match=True): def getUserByLogin(self, login, exact_match=True):
# Search the Catalog for login and return a list of person objects # Search the Catalog for login and return a list of person objects
# login can be a string or a list of strings # login can be a string or a list of strings
# (no docstring to prevent publishing) # (no docstring to prevent publishing)
if not login: if not login:
return [] return []
if isinstance(login, list):
portal = self.getPortalObject() login = tuple(login)
elif not isinstance(login, tuple):
def _getUserByLogin(login, exact_match): login = str(login)
# because we aren't logged in, we have to create our own
# SecurityManager to be able to access the Catalog
if isinstance(login, list):
login = tuple(login)
elif not isinstance(login, tuple):
login = (str(login),)
sm = getSecurityManager()
if sm.getUser().getId() != SUPER_USER:
newSecurityManager(self, self.getUser(SUPER_USER))
try:
try:
if exact_match:
reference_key = 'ExactMatch'
else:
reference_key = 'Keyword'
result = portal.portal_catalog.unrestrictedSearchResults(
select_expression='reference',
portal_type="Person",
reference=dict(query=login,
key=reference_key))
except ConflictError:
raise
except:
LOG('ERP5Security', PROBLEM, 'getUserByLogin failed', error=sys.exc_info())
# Here we must raise an exception to prevent callers from caching
# a result of a degraded situation.
# The kind of exception does not matter as long as it's catched by
# PAS and causes a lookup using another plugin or user folder.
# As PAS does not define explicitely such exception, we must use
# the _SWALLOWABLE_PLUGIN_EXCEPTIONS list.
raise _SWALLOWABLE_PLUGIN_EXCEPTIONS[0]
finally:
setSecurityManager(sm)
# XXX: Here, we filter catalog result list ALTHOUGH we did pass
# parameters to unrestrictedSearchResults to restrict result set.
# This is done because the following values can match person with
# reference "foo":
# "foo " because of MySQL (feature, PADSPACE collation):
# mysql> SELECT reference as r FROM catalog
# -> WHERE reference="foo ";
# +-----+
# | r |
# +-----+
# | foo |
# +-----+
# 1 row in set (0.01 sec)
# "bar OR foo" because of ZSQLCatalog tokenizing searched strings
# by default (feature).
result = [x.path for x in result if (not exact_match)
or x['reference'] in login]
if not result:
raise _AuthenticationFailure()
return result
_getUserByLogin = CachingMethod(_getUserByLogin,
id='ERP5UserManager_getUserByLogin',
cache_factory='erp5_content_short')
try: try:
return [portal.unrestrictedTraverse(x) for x in return getUserByLogin(self.getPortalObject(), login, exact_match)
_getUserByLogin(login, exact_match)] except ConflictError:
except _AuthenticationFailure: raise
return [] except:
LOG('ERP5Security', PROBLEM, 'getUserByLogin failed', error=sys.exc_info())
# Here we must raise an exception to prevent callers from caching
# a result of a degraded situation.
# The kind of exception does not matter as long as it's catched by
# PAS and causes a lookup using another plugin or user folder.
# As PAS does not define explicitely such exception, we must use
# the _SWALLOWABLE_PLUGIN_EXCEPTIONS list.
raise _SWALLOWABLE_PLUGIN_EXCEPTIONS[0]
classImplements( ERP5UserManager classImplements( ERP5UserManager
, IAuthenticationPlugin , IAuthenticationPlugin
......
...@@ -108,3 +108,6 @@ def initialize(context): ...@@ -108,3 +108,6 @@ def initialize(context):
, icon='www/portal.gif' , icon='www/portal.gif'
) )
from AccessControl.SecurityInfo import ModuleSecurityInfo
ModuleSecurityInfo('Products.ERP5Security.ERP5UserManager').declarePublic(
'getUserByLogin')
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment