diff --git a/bt5/erp5_base/ExtensionTemplateItem/portal_components/extension.erp5.PersonLoginMigration.py b/bt5/erp5_base/ExtensionTemplateItem/portal_components/extension.erp5.PersonLoginMigration.py index 270e6dbf6f1b7a7dbe4abf454b7dd553bbcaf050..856f7b3506d278ce8aa65951de52dcc3e0fb8f69 100644 --- a/bt5/erp5_base/ExtensionTemplateItem/portal_components/extension.erp5.PersonLoginMigration.py +++ b/bt5/erp5_base/ExtensionTemplateItem/portal_components/extension.erp5.PersonLoginMigration.py @@ -1,21 +1,32 @@ def migrateToERP5Login(self): assert self.getPortalType() == 'Person' + login_portal_type = 'ERP5 Login' reference = self.getReference() if not reference: # no user id and no login is required return - if not self.hasUserId() or self.getUserId() == reference: + if not (self.hasUserId() or self.getUserId() == reference): self.setUserId(reference) - if not self.hasPassword(): - # no login is required, but possibly another Login type object is required if implemented - return - if len(self.objectValues(portal_type=self.getPortalObject().getPortalLoginTypeList())): + + if reference.startswith("go_"): + login_portal_type = "Google Login" + reference = self.getDefaultEmailText() + elif reference.startswith("fb_"): + login_portal_type = "Facebook Login" + reference = reference[len("fb_"):] + else: + if not self.hasPassword(): + # no login is required, but possibly another Login type object is required if implemented + return + if len(self.objectValues(portal_type=login_portal_type)): # already migrated return login = self.newContent( - portal_type='ERP5 Login', + portal_type=login_portal_type, reference=reference, ) - login._setEncodedPassword(self.getPassword()) + if login_portal_type == "ERP5 Login": + login._setEncodedPassword(self.getPassword()) + self._setEncodedPassword(None) + login.validate() - self._setEncodedPassword(None) diff --git a/bt5/erp5_oauth_facebook_login/ExtensionTemplateItem/portal_components/extension.erp5.FacebookLoginUtility.py b/bt5/erp5_oauth_facebook_login/ExtensionTemplateItem/portal_components/extension.erp5.FacebookLoginUtility.py index 0863cdd92b8388647ce12de9e62d15a8e535fbf3..165273cd3159222d7133ee4834492e5be6f3ed0c 100644 --- a/bt5/erp5_oauth_facebook_login/ExtensionTemplateItem/portal_components/extension.erp5.FacebookLoginUtility.py +++ b/bt5/erp5_oauth_facebook_login/ExtensionTemplateItem/portal_components/extension.erp5.FacebookLoginUtility.py @@ -2,6 +2,7 @@ import facebook from ZTUtils import make_query from Products.ERP5Security.ERP5ExternalOauth2ExtractionPlugin import getFacebookUserEntry +from zExceptions import Unauthorized def _getFacebookClientIdAndSecretKey(portal, reference="default"): """Returns facebook client id and secret key. @@ -37,5 +38,21 @@ def getAccessTokenFromCode(self, code, redirect_uri): code=code, redirect_uri=redirect_uri, app_id=client_id, app_secret=secret_key) +def unrestrictedSearchFacebookConnector(self): + return self.getPortalObject().portal_catalog.unrestrictedSearchResults( + portal_type="Facebook Connector", + reference="default", + validation_state="validated", + limit=2) + +def unrestrictedSearchFacebookLogin(self, login, REQUEST=None): + if REQUEST is not None: + raise Unauthorized + + return self.getPortalObject().portal_catalog.unrestrictedSearchResults( + portal_type="Facebook Login", + reference=login, + validation_state="validated", limit=1) + def getUserEntry(token): return getFacebookUserEntry(token) diff --git a/bt5/erp5_oauth_facebook_login/SkinTemplateItem/portal_skins/erp5_oauth_facebook_login/ERP5Site_getFacebookConnector.xml b/bt5/erp5_oauth_facebook_login/SkinTemplateItem/portal_skins/erp5_oauth_facebook_login/ERP5Site_getFacebookConnector.xml new file mode 100644 index 0000000000000000000000000000000000000000..454a17f820e0058bab6b5e87301de6b18e4693fa --- /dev/null +++ b/bt5/erp5_oauth_facebook_login/SkinTemplateItem/portal_skins/erp5_oauth_facebook_login/ERP5Site_getFacebookConnector.xml @@ -0,0 +1,28 @@ + + + + + + + + + + _function + unrestrictedSearchFacebookConnector + + + _module + FacebookLoginUtility + + + id + ERP5Site_getFacebookConnector + + + title + + + + + + diff --git a/bt5/erp5_oauth_facebook_login/SkinTemplateItem/portal_skins/erp5_oauth_facebook_login/ERP5Site_getFacebookLogin.xml b/bt5/erp5_oauth_facebook_login/SkinTemplateItem/portal_skins/erp5_oauth_facebook_login/ERP5Site_getFacebookLogin.xml new file mode 100644 index 0000000000000000000000000000000000000000..ea0d8cf8acb9c5b716cf3a6f6f68c799c8996a3f --- /dev/null +++ b/bt5/erp5_oauth_facebook_login/SkinTemplateItem/portal_skins/erp5_oauth_facebook_login/ERP5Site_getFacebookLogin.xml @@ -0,0 +1,28 @@ + + + + + + + + + + _function + unrestrictedSearchFacebookLogin + + + _module + FacebookLoginUtility + + + id + ERP5Site_getFacebookLogin + + + title + + + + + + diff --git a/bt5/erp5_oauth_facebook_login/SkinTemplateItem/portal_skins/erp5_oauth_facebook_login/ERP5Site_getPersonFromFacebookLogin.py b/bt5/erp5_oauth_facebook_login/SkinTemplateItem/portal_skins/erp5_oauth_facebook_login/ERP5Site_getPersonFromFacebookLogin.py new file mode 100644 index 0000000000000000000000000000000000000000..8d8132b800bed224ee27abf3f5b3e1716f309add --- /dev/null +++ b/bt5/erp5_oauth_facebook_login/SkinTemplateItem/portal_skins/erp5_oauth_facebook_login/ERP5Site_getPersonFromFacebookLogin.py @@ -0,0 +1,14 @@ +from zExceptions import Unauthorized + +if REQUEST is not None: + raise Unauthorized + +login = context.ERP5Site_getFacebookLogin(login) + +if login is None: + return login + +if len(login) > 1: + raise ValueError("Duplicated User") + +return login[0].getParentValue().getRelativeUrl() diff --git a/bt5/erp5_oauth_facebook_login/SkinTemplateItem/portal_skins/erp5_oauth_facebook_login/ERP5Site_getPersonFromFacebookLogin.xml b/bt5/erp5_oauth_facebook_login/SkinTemplateItem/portal_skins/erp5_oauth_facebook_login/ERP5Site_getPersonFromFacebookLogin.xml new file mode 100644 index 0000000000000000000000000000000000000000..6b19fdcf1837a72780b29d1c497471bed94d8e53 --- /dev/null +++ b/bt5/erp5_oauth_facebook_login/SkinTemplateItem/portal_skins/erp5_oauth_facebook_login/ERP5Site_getPersonFromFacebookLogin.xml @@ -0,0 +1,70 @@ + + + + + + + + + + Script_magic + 3 + + + _bind_names + + + + + + + + + + _asgns + + + + name_container + container + + + name_context + context + + + name_m_self + script + + + name_subpath + traverse_subpath + + + + + + + + + + + _params + login, REQUEST=None + + + _proxy_roles + + + Manager + + + + + id + ERP5Site_getPersonFromFacebookLogin + + + + + diff --git a/bt5/erp5_oauth_facebook_login/SkinTemplateItem/portal_skins/erp5_oauth_facebook_login/FacebookConnector_view.xml b/bt5/erp5_oauth_facebook_login/SkinTemplateItem/portal_skins/erp5_oauth_facebook_login/FacebookConnector_view.xml index 9964b5f33aa3499a8498f78b3a913eaf1a4526e5..987d99b16cc8e2b5906b93ff7d1d23e947c5afd4 100644 --- a/bt5/erp5_oauth_facebook_login/SkinTemplateItem/portal_skins/erp5_oauth_facebook_login/FacebookConnector_view.xml +++ b/bt5/erp5_oauth_facebook_login/SkinTemplateItem/portal_skins/erp5_oauth_facebook_login/FacebookConnector_view.xml @@ -115,7 +115,7 @@ title - Faceook Connector + Facebook Connector unicode_mode diff --git a/bt5/erp5_oauth_google_login/ExtensionTemplateItem/portal_components/extension.erp5.GoogleLoginUtility.py b/bt5/erp5_oauth_google_login/ExtensionTemplateItem/portal_components/extension.erp5.GoogleLoginUtility.py index 7b80a0de7b9b6b94772ecce968b47857095d8e93..3574ef493289069acc0cc77ac9494fce1b8bf146 100644 --- a/bt5/erp5_oauth_google_login/ExtensionTemplateItem/portal_components/extension.erp5.GoogleLoginUtility.py +++ b/bt5/erp5_oauth_google_login/ExtensionTemplateItem/portal_components/extension.erp5.GoogleLoginUtility.py @@ -1,6 +1,8 @@ import json import oauth2client.client from Products.ERP5Security.ERP5ExternalOauth2ExtractionPlugin import getGoogleUserEntry +from zExceptions import Unauthorized + SCOPE_LIST = ['https://www.googleapis.com/auth/userinfo.profile', 'https://www.googleapis.com/auth/userinfo.email'] @@ -49,5 +51,21 @@ def getAccessTokenFromCode(self, code, redirect_uri): credential_data = json.loads(credential.to_json()) return credential_data +def unrestrictedSearchGoogleConnector(self): + return self.getPortalObject().portal_catalog.unrestrictedSearchResults( + portal_type="Google Connector", + reference="default", + validation_state="validated", + limit=2) + +def unrestrictedSearchGoogleLogin(self, login, REQUEST=None): + if REQUEST is not None: + raise Unauthorized + + return self.getPortalObject().portal_catalog.unrestrictedSearchResults( + portal_type="Google Login", + reference=login, + validation_state="validated", limit=1) + def getUserEntry(access_token): return getGoogleUserEntry(access_token) \ No newline at end of file diff --git a/bt5/erp5_oauth_google_login/SkinTemplateItem/portal_skins/erp5_oauth_google_login/ERP5Site_getGoogleConnector.xml b/bt5/erp5_oauth_google_login/SkinTemplateItem/portal_skins/erp5_oauth_google_login/ERP5Site_getGoogleConnector.xml new file mode 100644 index 0000000000000000000000000000000000000000..3789ef48c5a82278ff22f685a27e0fa75e9674fe --- /dev/null +++ b/bt5/erp5_oauth_google_login/SkinTemplateItem/portal_skins/erp5_oauth_google_login/ERP5Site_getGoogleConnector.xml @@ -0,0 +1,28 @@ + + + + + + + + + + _function + unrestrictedSearchGoogleConnector + + + _module + GoogleLoginUtility + + + id + ERP5Site_getGoogleConnector + + + title + + + + + + diff --git a/bt5/erp5_oauth_google_login/SkinTemplateItem/portal_skins/erp5_oauth_google_login/ERP5Site_getGoogleLogin.xml b/bt5/erp5_oauth_google_login/SkinTemplateItem/portal_skins/erp5_oauth_google_login/ERP5Site_getGoogleLogin.xml new file mode 100644 index 0000000000000000000000000000000000000000..e0764678839583598996e25849816783a5c3efb6 --- /dev/null +++ b/bt5/erp5_oauth_google_login/SkinTemplateItem/portal_skins/erp5_oauth_google_login/ERP5Site_getGoogleLogin.xml @@ -0,0 +1,28 @@ + + + + + + + + + + _function + unrestrictedSearchGoogleConnector + + + _module + GoogleLoginUtility + + + id + ERP5Site_getGoogleLogin + + + title + + + + + + diff --git a/bt5/erp5_oauth_google_login/SkinTemplateItem/portal_skins/erp5_oauth_google_login/ERP5Site_getPersonFromGoogleLogin.py b/bt5/erp5_oauth_google_login/SkinTemplateItem/portal_skins/erp5_oauth_google_login/ERP5Site_getPersonFromGoogleLogin.py new file mode 100644 index 0000000000000000000000000000000000000000..a157badc1b68409436dc7940af5fd7ee040a105b --- /dev/null +++ b/bt5/erp5_oauth_google_login/SkinTemplateItem/portal_skins/erp5_oauth_google_login/ERP5Site_getPersonFromGoogleLogin.py @@ -0,0 +1,14 @@ +from zExceptions import Unauthorized + +if REQUEST is not None: + raise Unauthorized + +login = context.ERP5Site_getGoogleLogin(login) + +if login is None: + return login + +if len(login) > 1: + raise ValueError("Duplicated User") + +return login[0].getParentValue().getRelativeUrl() diff --git a/bt5/erp5_oauth_google_login/SkinTemplateItem/portal_skins/erp5_oauth_google_login/ERP5Site_getPersonFromGoogleLogin.xml b/bt5/erp5_oauth_google_login/SkinTemplateItem/portal_skins/erp5_oauth_google_login/ERP5Site_getPersonFromGoogleLogin.xml new file mode 100644 index 0000000000000000000000000000000000000000..df4e15559ab0fe69e3c06a09e236d7862a84da02 --- /dev/null +++ b/bt5/erp5_oauth_google_login/SkinTemplateItem/portal_skins/erp5_oauth_google_login/ERP5Site_getPersonFromGoogleLogin.xml @@ -0,0 +1,70 @@ + + + + + + + + + + Script_magic + 3 + + + _bind_names + + + + + + + + + + _asgns + + + + name_container + container + + + name_context + context + + + name_m_self + script + + + name_subpath + traverse_subpath + + + + + + + + + + + _params + login, REQUEST=None + + + _proxy_roles + + + Manager + + + + + id + ERP5Site_getPersonFromGoogleLogin + + + + + diff --git a/product/ERP5Security/ERP5ExternalOauth2ExtractionPlugin.py b/product/ERP5Security/ERP5ExternalOauth2ExtractionPlugin.py index bbc36070430b50af1b156c030b7e9f1b42f9a8e5..5b08f1158eb76e1b46c5f7eda1ca28a871466aa2 100644 --- a/product/ERP5Security/ERP5ExternalOauth2ExtractionPlugin.py +++ b/product/ERP5Security/ERP5ExternalOauth2ExtractionPlugin.py @@ -82,7 +82,7 @@ def getGoogleUserEntry(token): ('last_name', 'family_name'), ('email', 'email'), ('reference', 'email'),): - value = google_entry[k[1]].encode('utf-8') + value = google_entry.get(k[1], '').encode('utf-8') user_entry[k[0]] = value return user_entry diff --git a/product/ERP5Security/ERP5LoginUserManager.py b/product/ERP5Security/ERP5LoginUserManager.py index 2e00d8bdddadecdbbf91ac04aea7771e54881c3b..054507252dd07ac1b12258620be74179af42046d 100644 --- a/product/ERP5Security/ERP5LoginUserManager.py +++ b/product/ERP5Security/ERP5LoginUserManager.py @@ -34,6 +34,7 @@ from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin from Products.PluggableAuthService.utils import classImplements from Products.PluggableAuthService.interfaces.plugins import IAuthenticationPlugin from Products.PluggableAuthService.interfaces.plugins import IUserEnumerationPlugin +from Products.ERP5Type.TransactionalVariable import getTransactionalVariable from DateTime import DateTime from Products import ERP5Security from AccessControl import SpecialUsers @@ -274,6 +275,32 @@ class ERP5LoginUserManager(BasePlugin): } for user in user_list if user['user_id'] ] + + tv = getTransactionalVariable() + person = tv.get("transactional_user", None) + if person is not None: + erp5_login = person.objectValues("ERP5 Login")[0] + if (login is not None and erp5_login.getReference() == None) or \ + (id is not None and person.getUserId() == id[0]): + result.append({ + 'id': person.getUserId(), + # Note: PAS forbids us from returning more than one entry per given id, + # so take any available login. + 'login': erp5_login.getReference(), + 'pluginid': plugin_id, + + # Extra properties, specific to ERP5 + 'path': person.getPath(), + 'uid': person.getUid(), + 'login_list': [ + { + 'reference': erp5_login.getReference(), + 'path': erp5_login.getRelativeUrl(), + 'uid': erp5_login.getPath(), + } + ], + }) + for special_user_name in special_user_name_set: # Note: special users are a bastard design in Zope: they are expected to # have a user name (aka, a login), but no id (aka, they do not exist as