From e3935374369626ee57a208ecd423af95bcb9e835 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=81ukasz=20Nowak?= <luke@nexedi.com>
Date: Fri, 6 Jul 2012 17:20:15 +0200
Subject: [PATCH] Generalise in order to support more backends.

---
 bt5/erp5_credential_facebook/bt/change_log    |   2 -
 bt5/erp5_credential_facebook/bt/description   |   1 -
 bt5/erp5_credential_facebook/bt/revision      |   1 -
 .../bt/template_path_list                     |   2 -
 .../bt/template_skin_id_list                  |   1 -
 bt5/erp5_credential_facebook/bt/title         |   1 -
 .../extrenal_oauth2_token_cache_factory.xml}  |   2 +-
 .../volatile_cache_plugin.xml                 |   0
 .../portal_skins/erp5_credential_oauth2.xml}  |   2 +-
 .../Base_createOauth2User.xml}                |   2 +-
 bt5/erp5_credential_oauth2/bt/change_log      |   5 +
 .../bt/copyright_list                         |   0
 bt5/erp5_credential_oauth2/bt/description     |   1 +
 .../bt/license                                |   0
 bt5/erp5_credential_oauth2/bt/revision        |   1 +
 .../bt/template_format_version                |   0
 .../bt/template_path_list                     |   2 +
 .../bt/template_skin_id_list                  |   1 +
 bt5/erp5_credential_oauth2/bt/title           |   1 +
 .../bt/version                                |   0
 ... => ERP5ExternalOauth2ExtractionPlugin.py} | 115 +++++++++---------
 product/ERP5Security/__init__.py              |  10 +-
 22 files changed, 76 insertions(+), 74 deletions(-)
 delete mode 100644 bt5/erp5_credential_facebook/bt/change_log
 delete mode 100644 bt5/erp5_credential_facebook/bt/description
 delete mode 100644 bt5/erp5_credential_facebook/bt/revision
 delete mode 100644 bt5/erp5_credential_facebook/bt/template_path_list
 delete mode 100644 bt5/erp5_credential_facebook/bt/template_skin_id_list
 delete mode 100644 bt5/erp5_credential_facebook/bt/title
 rename bt5/{erp5_credential_facebook/PathTemplateItem/portal_caches/facebook_token_cache_factory.xml => erp5_credential_oauth2/PathTemplateItem/portal_caches/extrenal_oauth2_token_cache_factory.xml} (96%)
 rename bt5/{erp5_credential_facebook/PathTemplateItem/portal_caches/facebook_token_cache_factory => erp5_credential_oauth2/PathTemplateItem/portal_caches/extrenal_oauth2_token_cache_factory}/volatile_cache_plugin.xml (100%)
 rename bt5/{erp5_credential_facebook/SkinTemplateItem/portal_skins/erp5_credential_facebook.xml => erp5_credential_oauth2/SkinTemplateItem/portal_skins/erp5_credential_oauth2.xml} (89%)
 rename bt5/{erp5_credential_facebook/SkinTemplateItem/portal_skins/erp5_credential_facebook/Base_createFacebookUser.xml => erp5_credential_oauth2/SkinTemplateItem/portal_skins/erp5_credential_oauth2/Base_createOauth2User.xml} (97%)
 create mode 100644 bt5/erp5_credential_oauth2/bt/change_log
 rename bt5/{erp5_credential_facebook => erp5_credential_oauth2}/bt/copyright_list (100%)
 create mode 100644 bt5/erp5_credential_oauth2/bt/description
 rename bt5/{erp5_credential_facebook => erp5_credential_oauth2}/bt/license (100%)
 create mode 100644 bt5/erp5_credential_oauth2/bt/revision
 rename bt5/{erp5_credential_facebook => erp5_credential_oauth2}/bt/template_format_version (100%)
 create mode 100644 bt5/erp5_credential_oauth2/bt/template_path_list
 create mode 100644 bt5/erp5_credential_oauth2/bt/template_skin_id_list
 create mode 100644 bt5/erp5_credential_oauth2/bt/title
 rename bt5/{erp5_credential_facebook => erp5_credential_oauth2}/bt/version (100%)
 rename product/ERP5Security/{ERP5FacebookExtractionPlugin.py => ERP5ExternalOauth2ExtractionPlugin.py} (82%)

diff --git a/bt5/erp5_credential_facebook/bt/change_log b/bt5/erp5_credential_facebook/bt/change_log
deleted file mode 100644
index 055bbce55f..0000000000
--- a/bt5/erp5_credential_facebook/bt/change_log
+++ /dev/null
@@ -1,2 +0,0 @@
-2012/07/04 Łukasz Nowak
-* Initial version
\ No newline at end of file
diff --git a/bt5/erp5_credential_facebook/bt/description b/bt5/erp5_credential_facebook/bt/description
deleted file mode 100644
index 039c4845f2..0000000000
--- a/bt5/erp5_credential_facebook/bt/description
+++ /dev/null
@@ -1 +0,0 @@
-Facebook based credential system.
\ No newline at end of file
diff --git a/bt5/erp5_credential_facebook/bt/revision b/bt5/erp5_credential_facebook/bt/revision
deleted file mode 100644
index 56a6051ca2..0000000000
--- a/bt5/erp5_credential_facebook/bt/revision
+++ /dev/null
@@ -1 +0,0 @@
-1
\ No newline at end of file
diff --git a/bt5/erp5_credential_facebook/bt/template_path_list b/bt5/erp5_credential_facebook/bt/template_path_list
deleted file mode 100644
index 6091d5ff7a..0000000000
--- a/bt5/erp5_credential_facebook/bt/template_path_list
+++ /dev/null
@@ -1,2 +0,0 @@
-portal_caches/facebook_token_cache_factory
-portal_caches/facebook_token_cache_factory/volatile_cache_plugin
\ No newline at end of file
diff --git a/bt5/erp5_credential_facebook/bt/template_skin_id_list b/bt5/erp5_credential_facebook/bt/template_skin_id_list
deleted file mode 100644
index 09ca68d954..0000000000
--- a/bt5/erp5_credential_facebook/bt/template_skin_id_list
+++ /dev/null
@@ -1 +0,0 @@
-erp5_credential_facebook
\ No newline at end of file
diff --git a/bt5/erp5_credential_facebook/bt/title b/bt5/erp5_credential_facebook/bt/title
deleted file mode 100644
index 09ca68d954..0000000000
--- a/bt5/erp5_credential_facebook/bt/title
+++ /dev/null
@@ -1 +0,0 @@
-erp5_credential_facebook
\ No newline at end of file
diff --git a/bt5/erp5_credential_facebook/PathTemplateItem/portal_caches/facebook_token_cache_factory.xml b/bt5/erp5_credential_oauth2/PathTemplateItem/portal_caches/extrenal_oauth2_token_cache_factory.xml
similarity index 96%
rename from bt5/erp5_credential_facebook/PathTemplateItem/portal_caches/facebook_token_cache_factory.xml
rename to bt5/erp5_credential_oauth2/PathTemplateItem/portal_caches/extrenal_oauth2_token_cache_factory.xml
index 6a946ca13f..af4aaadb5d 100644
--- a/bt5/erp5_credential_facebook/PathTemplateItem/portal_caches/facebook_token_cache_factory.xml
+++ b/bt5/erp5_credential_oauth2/PathTemplateItem/portal_caches/extrenal_oauth2_token_cache_factory.xml
@@ -36,7 +36,7 @@
         </item>
         <item>
             <key> <string>id</string> </key>
-            <value> <string>facebook_token_cache_factory</string> </value>
+            <value> <string>extrenal_oauth2_token_cache_factory</string> </value>
         </item>
         <item>
             <key> <string>portal_type</string> </key>
diff --git a/bt5/erp5_credential_facebook/PathTemplateItem/portal_caches/facebook_token_cache_factory/volatile_cache_plugin.xml b/bt5/erp5_credential_oauth2/PathTemplateItem/portal_caches/extrenal_oauth2_token_cache_factory/volatile_cache_plugin.xml
similarity index 100%
rename from bt5/erp5_credential_facebook/PathTemplateItem/portal_caches/facebook_token_cache_factory/volatile_cache_plugin.xml
rename to bt5/erp5_credential_oauth2/PathTemplateItem/portal_caches/extrenal_oauth2_token_cache_factory/volatile_cache_plugin.xml
diff --git a/bt5/erp5_credential_facebook/SkinTemplateItem/portal_skins/erp5_credential_facebook.xml b/bt5/erp5_credential_oauth2/SkinTemplateItem/portal_skins/erp5_credential_oauth2.xml
similarity index 89%
rename from bt5/erp5_credential_facebook/SkinTemplateItem/portal_skins/erp5_credential_facebook.xml
rename to bt5/erp5_credential_oauth2/SkinTemplateItem/portal_skins/erp5_credential_oauth2.xml
index dc3f5fcad5..40112a986c 100644
--- a/bt5/erp5_credential_facebook/SkinTemplateItem/portal_skins/erp5_credential_facebook.xml
+++ b/bt5/erp5_credential_oauth2/SkinTemplateItem/portal_skins/erp5_credential_oauth2.xml
@@ -14,7 +14,7 @@
         </item>
         <item>
             <key> <string>id</string> </key>
-            <value> <string>erp5_credential_facebook</string> </value>
+            <value> <string>erp5_credential_oauth2</string> </value>
         </item>
         <item>
             <key> <string>title</string> </key>
diff --git a/bt5/erp5_credential_facebook/SkinTemplateItem/portal_skins/erp5_credential_facebook/Base_createFacebookUser.xml b/bt5/erp5_credential_oauth2/SkinTemplateItem/portal_skins/erp5_credential_oauth2/Base_createOauth2User.xml
similarity index 97%
rename from bt5/erp5_credential_facebook/SkinTemplateItem/portal_skins/erp5_credential_facebook/Base_createFacebookUser.xml
rename to bt5/erp5_credential_oauth2/SkinTemplateItem/portal_skins/erp5_credential_oauth2/Base_createOauth2User.xml
index 8bc75f0afa..9fe00d767a 100644
--- a/bt5/erp5_credential_facebook/SkinTemplateItem/portal_skins/erp5_credential_facebook/Base_createFacebookUser.xml
+++ b/bt5/erp5_credential_oauth2/SkinTemplateItem/portal_skins/erp5_credential_oauth2/Base_createOauth2User.xml
@@ -59,7 +59,7 @@
         </item>
         <item>
             <key> <string>id</string> </key>
-            <value> <string>Base_createFacebookUser</string> </value>
+            <value> <string>Base_createOauth2User</string> </value>
         </item>
       </dictionary>
     </pickle>
diff --git a/bt5/erp5_credential_oauth2/bt/change_log b/bt5/erp5_credential_oauth2/bt/change_log
new file mode 100644
index 0000000000..01e68e86ac
--- /dev/null
+++ b/bt5/erp5_credential_oauth2/bt/change_log
@@ -0,0 +1,5 @@
+2012/07/05 Łukasz Nowak
+* renamed from erp5_credential_facebook
+
+2012/07/04 Łukasz Nowak
+* Initial version
\ No newline at end of file
diff --git a/bt5/erp5_credential_facebook/bt/copyright_list b/bt5/erp5_credential_oauth2/bt/copyright_list
similarity index 100%
rename from bt5/erp5_credential_facebook/bt/copyright_list
rename to bt5/erp5_credential_oauth2/bt/copyright_list
diff --git a/bt5/erp5_credential_oauth2/bt/description b/bt5/erp5_credential_oauth2/bt/description
new file mode 100644
index 0000000000..7308eace8d
--- /dev/null
+++ b/bt5/erp5_credential_oauth2/bt/description
@@ -0,0 +1 @@
+Oauth2 based credential system with user profiles in pluggable form.
\ No newline at end of file
diff --git a/bt5/erp5_credential_facebook/bt/license b/bt5/erp5_credential_oauth2/bt/license
similarity index 100%
rename from bt5/erp5_credential_facebook/bt/license
rename to bt5/erp5_credential_oauth2/bt/license
diff --git a/bt5/erp5_credential_oauth2/bt/revision b/bt5/erp5_credential_oauth2/bt/revision
new file mode 100644
index 0000000000..e440e5c842
--- /dev/null
+++ b/bt5/erp5_credential_oauth2/bt/revision
@@ -0,0 +1 @@
+3
\ No newline at end of file
diff --git a/bt5/erp5_credential_facebook/bt/template_format_version b/bt5/erp5_credential_oauth2/bt/template_format_version
similarity index 100%
rename from bt5/erp5_credential_facebook/bt/template_format_version
rename to bt5/erp5_credential_oauth2/bt/template_format_version
diff --git a/bt5/erp5_credential_oauth2/bt/template_path_list b/bt5/erp5_credential_oauth2/bt/template_path_list
new file mode 100644
index 0000000000..f60e152655
--- /dev/null
+++ b/bt5/erp5_credential_oauth2/bt/template_path_list
@@ -0,0 +1,2 @@
+portal_caches/extrenal_oauth2_token_cache_factory
+portal_caches/extrenal_oauth2_token_cache_factory/volatile_cache_plugin
\ No newline at end of file
diff --git a/bt5/erp5_credential_oauth2/bt/template_skin_id_list b/bt5/erp5_credential_oauth2/bt/template_skin_id_list
new file mode 100644
index 0000000000..e5504332cc
--- /dev/null
+++ b/bt5/erp5_credential_oauth2/bt/template_skin_id_list
@@ -0,0 +1 @@
+erp5_credential_oauth2
\ No newline at end of file
diff --git a/bt5/erp5_credential_oauth2/bt/title b/bt5/erp5_credential_oauth2/bt/title
new file mode 100644
index 0000000000..e5504332cc
--- /dev/null
+++ b/bt5/erp5_credential_oauth2/bt/title
@@ -0,0 +1 @@
+erp5_credential_oauth2
\ No newline at end of file
diff --git a/bt5/erp5_credential_facebook/bt/version b/bt5/erp5_credential_oauth2/bt/version
similarity index 100%
rename from bt5/erp5_credential_facebook/bt/version
rename to bt5/erp5_credential_oauth2/bt/version
diff --git a/product/ERP5Security/ERP5FacebookExtractionPlugin.py b/product/ERP5Security/ERP5ExternalOauth2ExtractionPlugin.py
similarity index 82%
rename from product/ERP5Security/ERP5FacebookExtractionPlugin.py
rename to product/ERP5Security/ERP5ExternalOauth2ExtractionPlugin.py
index 8c4854d8bc..85851a7ee2 100644
--- a/product/ERP5Security/ERP5FacebookExtractionPlugin.py
+++ b/product/ERP5Security/ERP5ExternalOauth2ExtractionPlugin.py
@@ -65,15 +65,9 @@ def addERP5FacebookExtractionPlugin(dispatcher, id, title=None, REQUEST=None):
           'ERP5FacebookExtractionPlugin+added.'
           % dispatcher.absolute_url())
 
-class ERP5FacebookExtractionPlugin(BasePlugin):
-  """
-  Plugin to authenicate as machines.
-  """
+class ERP5ExternalOauth2ExtractionPlugin:
 
-  meta_type = "ERP5 Facebook Extraction Plugin"
-  # cache_fatory_name proposal to begin configurable
-  cache_factory_name = 'facebook_token_cache_factory'
-  reference_prefix = 'fb_'
+  cache_factory_name = 'extrenal_oauth2_token_cache_factory'
   security = ClassSecurityInfo()
 
   def __init__(self, id, title=None):
@@ -100,14 +94,14 @@ class ERP5FacebookExtractionPlugin(BasePlugin):
       raise KeyError
     return cache_factory
 
-  def setFacebookToken(self, key, body):
+  def setToken(self, key, body):
     cache_factory = self._getCacheFactory()
     cache_duration = cache_factory.cache_duration
     for cache_plugin in cache_factory.getCachePluginList():
       cache_plugin.set(key, DEFAULT_CACHE_SCOPE,
                        body, cache_duration=cache_duration)
 
-  def getFacebookToken(self, key):
+  def getToken(self, key):
     cache_factory = self._getCacheFactory()
     for cache_plugin in cache_factory.getCachePluginList():
       cache_entry = cache_plugin.get(key, DEFAULT_CACHE_SCOPE)
@@ -115,55 +109,25 @@ class ERP5FacebookExtractionPlugin(BasePlugin):
         return cache_entry.getValue()
     raise KeyError('Key %r not found' % key)
 
-  def getFacebookEntry(self, token):
-    timeout = socket.getdefaulttimeout()
-    try:
-      # require really fast interaction
-      socket.setdefaulttimeout(5)
-      facebook_entry = facebook.GraphAPI(token).get_object("me")
-    except Exception:
-      facebook_entry = None
-    finally:
-      socket.setdefaulttimeout(timeout)
-
-    user_entry = {}
-    if facebook_entry is not None:
-      # sanitise value
-      try:
-        for k in ('first_name', 'last_name', 'id', 'email'):
-          if k == 'id':
-            user_entry['reference'] = self.reference_prefix + facebook_entry[k].encode(
-              'utf-8')
-          else:
-            user_entry[k] = facebook_entry[k].encode('utf-8')
-      except KeyError:
-        user_entry = None
-    return user_entry
-
   ####################################
   #ILoginPasswordHostExtractionPlugin#
   ####################################
   security.declarePrivate('extractCredentials')
   def extractCredentials(self, request):
-    """ Extract facebook credentials from the request header. """
-    Base_createFacebookUser = getattr(self.getPortalObject(),
-      'Base_createFacebookUser', None)
-    if facebook is None or Base_createFacebookUser is None:
-      # no facebook library available or not configured
-      if facebook is None:
-        LOG('ERP5FacebookExtractionPlugin', INFO,
-          'No facebook module available, disabled authentication.')
-      if Base_createFacebookUser is None:
-        LOG('ERP5FacebookExtractionPlugin', INFO,
-          'No Base_createFacebookUser script available, install '
-            'erp5_credential_facebook, disabled authentication.')
+    """ Extract Oauth2 credentials from the request header. """
+    Base_createOauth2User = getattr(self.getPortalObject(),
+      'Base_createOauth2User', None)
+    if Base_createOauth2User is None:
+      LOG('ERP5ExternalOauth2ExtractionPlugin', INFO,
+          'No Base_createOauth2User script available, install '
+            'erp5_credential_oauth2, disabled authentication.')
       return DumbHTTPExtractor().extractCredentials(request)
 
     creds = {}
     token = None
     if request._auth is not None:
       # 1st - try to fetch from Authorization header
-      if 'facebook' in request._auth.lower():
+      if self.header_string in request._auth.lower():
         l = request._auth.split()
         if len(l) == 2:
           token = l[1]
@@ -172,15 +136,16 @@ class ERP5FacebookExtractionPlugin(BasePlugin):
       # no token
       return DumbHTTPExtractor().extractCredentials(request)
 
+
     # token is available
     user = None
-    facebook_entry = None
+    user_entry = None
     try:
-      user = self.getFacebookToken(token)
+      user = self.getToken(self.prefix + token)
     except KeyError:
-      facebook_entry = self.getFacebookEntry(token)
-      if facebook_entry is not None:
-        user = facebook_entry['reference']
+      user_entry = self.getUserEntry(token)
+      if user_entry is not None:
+        user = user_entry['reference']
 
     if user is None:
       # fallback to default way
@@ -199,18 +164,18 @@ class ERP5FacebookExtractionPlugin(BasePlugin):
           newSecurityManager(self, self.getUser(SUPER_USER))
         try:
           self.REQUEST['USER_CREATION_IN_PROGRESS'] = user
-          if facebook_entry is None:
-            facebook_entry = self.getFacebookEntry(token)
+          if user_entry is None:
+            user_entry = self.getUserEntry(token)
           try:
-            self.Base_createFacebookUser(tag, **facebook_entry)
+            self.Base_createOauth2User(tag, **user_entry)
           except Exception:
-            LOG('ERP5FacebookExtractionPlugin', ERROR,
+            LOG('ERP5ExternalOauth2ExtractionPlugin', ERROR,
               'Issue while calling creation script:', error=True)
             raise
         finally:
           setSecurityManager(sm)
     try:
-      self.setFacebookToken(token, user)
+      self.setToken(self.prefix + token, user)
     except KeyError:
       # allow to work w/o cache
       pass
@@ -222,6 +187,40 @@ class ERP5FacebookExtractionPlugin(BasePlugin):
       creds['remote_address'] = request.get('REMOTE_ADDR', '')
     return creds
 
+class ERP5FacebookExtractionPlugin(ERP5ExternalOauth2ExtractionPlugin, BasePlugin):
+  """
+  Plugin to authenicate as machines.
+  """
+
+  meta_type = "ERP5 Facebook Extraction Plugin"
+  prefix = 'fb_'
+  header_string = 'facebook'
+
+  def getUserEntry(self, token):
+    timeout = socket.getdefaulttimeout()
+    try:
+      # require really fast interaction
+      socket.setdefaulttimeout(5)
+      facebook_entry = facebook.GraphAPI(token).get_object("me")
+    except Exception:
+      facebook_entry = None
+    finally:
+      socket.setdefaulttimeout(timeout)
+
+    user_entry = {}
+    if facebook_entry is not None:
+      # sanitise value
+      try:
+        for k in ('first_name', 'last_name', 'id', 'email'):
+          if k == 'id':
+            user_entry['reference'] = self.prefix + facebook_entry[k].encode(
+              'utf-8')
+          else:
+            user_entry[k] = facebook_entry[k].encode('utf-8')
+      except KeyError:
+        user_entry = None
+    return user_entry
+
   manage_editERP5FacebookExtractionPluginForm = PageTemplateFile(
       'www/ERP5Security_editERP5FacebookExtractionPlugin',
       globals(),
diff --git a/product/ERP5Security/__init__.py b/product/ERP5Security/__init__.py
index efde32ddf0..63544adfd3 100644
--- a/product/ERP5Security/__init__.py
+++ b/product/ERP5Security/__init__.py
@@ -28,7 +28,7 @@ import ERP5UserFactory
 import ERP5KeyAuthPlugin
 import ERP5ExternalAuthenticationPlugin
 import ERP5BearerExtractionPlugin
-import ERP5FacebookExtractionPlugin
+import ERP5ExternalOauth2ExtractionPlugin
 
 def mergedLocalRoles(object):
   """Returns a merging of object and its ancestors'
@@ -65,7 +65,7 @@ registerMultiPlugin(ERP5UserFactory.ERP5UserFactory.meta_type)
 registerMultiPlugin(ERP5KeyAuthPlugin.ERP5KeyAuthPlugin.meta_type)
 registerMultiPlugin(ERP5ExternalAuthenticationPlugin.ERP5ExternalAuthenticationPlugin.meta_type)
 registerMultiPlugin(ERP5BearerExtractionPlugin.ERP5BearerExtractionPlugin.meta_type)
-registerMultiPlugin(ERP5FacebookExtractionPlugin.ERP5FacebookExtractionPlugin.meta_type)
+registerMultiPlugin(ERP5ExternalOauth2ExtractionPlugin.ERP5FacebookExtractionPlugin.meta_type)
 
 def initialize(context):
 
@@ -132,11 +132,11 @@ def initialize(context):
                          , icon='www/portal.gif'
                          )
 
-    context.registerClass( ERP5FacebookExtractionPlugin.ERP5FacebookExtractionPlugin
+    context.registerClass( ERP5ExternalOauth2ExtractionPlugin.ERP5FacebookExtractionPlugin
                          , permission=ManageUsers
                          , constructors=(
-                            ERP5FacebookExtractionPlugin.manage_addERP5FacebookExtractionPluginForm,
-                            ERP5FacebookExtractionPlugin.addERP5FacebookExtractionPlugin, )
+                            ERP5ExternalOauth2ExtractionPlugin.manage_addERP5FacebookExtractionPluginForm,
+                            ERP5ExternalOauth2ExtractionPlugin.addERP5FacebookExtractionPlugin, )
                          , visibility=None
                          , icon='www/portal.gif'
                          )
-- 
2.30.9