changeset 6562:f58ed40c9a72

auth: refactor auth plugin importing The list of authentication plugins, configured in the database, may contain plugins which are no longer available. Therefore directly import the plugin in get_auth_plugins and report the ImportError to the log instead of breaking kallithea completely. Patch modified by Mads Kiilerich.
author domruf <dominikruf@gmail.com>
date Sun, 02 Apr 2017 13:38:08 +0200
parents 7d86b9876ac9
children 42bbccdec0a0
files kallithea/controllers/admin/auth_settings.py kallithea/lib/auth_modules/__init__.py kallithea/lib/base.py kallithea/model/db.py
diffstat 4 files changed, 31 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/kallithea/controllers/admin/auth_settings.py	Sun Apr 02 13:38:08 2017 +0200
+++ b/kallithea/controllers/admin/auth_settings.py	Sun Apr 02 13:38:08 2017 +0200
@@ -59,20 +59,20 @@
             'kallithea.lib.auth_modules.auth_crowd',
             'kallithea.lib.auth_modules.auth_pam'
         ]
-        c.enabled_plugin_names = Setting.get_auth_plugins()
+        self.enabled_plugins = auth_modules.get_auth_plugins()
+        c.enabled_plugin_names = [plugin.__class__.__module__ for plugin in self.enabled_plugins]
 
     def __render(self, defaults, errors):
         c.defaults = {}
         c.plugin_settings = {}
         c.plugin_shortnames = {}
 
-        for module in c.enabled_plugin_names:
-            plugin = auth_modules.loadplugin(module)
-            plugin_name = plugin.name
-            c.plugin_shortnames[module] = plugin_name
+        for plugin in self.enabled_plugins:
+            module = plugin.__class__.__module__
+            c.plugin_shortnames[module] = plugin.name
             c.plugin_settings[module] = plugin.plugin_settings()
             for v in c.plugin_settings[module]:
-                fullname = "auth_%s_%s" % (plugin_name, v["name"])
+                fullname = "auth_%s_%s" % (plugin.name, v["name"])
                 if "default" in v:
                     c.defaults[fullname] = v["default"]
                 # Current values will be the default on the form, if there are any
--- a/kallithea/lib/auth_modules/__init__.py	Sun Apr 02 13:38:08 2017 +0200
+++ b/kallithea/lib/auth_modules/__init__.py	Sun Apr 02 13:38:08 2017 +0200
@@ -296,10 +296,10 @@
         return user_data
 
 
-def importplugin(plugin):
+def loadplugin(plugin):
     """
-    Imports and returns the authentication plugin in the module named by plugin
-    (e.g., plugin='kallithea.lib.auth_modules.auth_internal'). Returns the
+    Imports, instantiates, and returns the authentication plugin in the module named by plugin
+    (e.g., plugin='kallithea.lib.auth_modules.auth_internal'). Returns an instance of the
     KallitheaAuthPluginBase subclass on success, raises exceptions on failure.
 
     raises:
@@ -329,16 +329,8 @@
     if not issubclass(pluginclass, KallitheaAuthPluginBase):
         raise TypeError("Authentication class %s.KallitheaAuthPlugin is not "
                         "a subclass of %s" % (plugin, KallitheaAuthPluginBase))
-    return pluginclass
 
-
-def loadplugin(plugin):
-    """
-    Loads and returns an instantiated authentication plugin.
-
-        see: importplugin
-    """
-    plugin = importplugin(plugin)()
+    plugin = pluginclass()
     if plugin.plugin_settings.im_func != KallitheaAuthPluginBase.plugin_settings.im_func:
         raise TypeError("Authentication class %s.KallitheaAuthPluginBase "
                         "has overridden the plugin_settings method, which is "
@@ -346,6 +338,19 @@
     return plugin
 
 
+def get_auth_plugins():
+    """Return a list of instances of plugins that are available and enabled"""
+    auth_plugins = []
+    for plugin_name in Setting.get_by_name("auth_plugins").app_settings_value:
+        try:
+            plugin = loadplugin(plugin_name)
+        except ImportError as e:
+            log.exception('Failed to load authentication module %s' % (plugin_name))
+        else:
+            auth_plugins.append(plugin)
+    return auth_plugins
+
+
 def authenticate(username, password, environ=None):
     """
     Authentication function used for access control,
@@ -357,14 +362,10 @@
     :returns: None if auth failed, user_data dict if auth is correct
     """
 
-    auth_plugins = Setting.get_auth_plugins()
+    auth_plugins = get_auth_plugins()
     log.debug('Authentication against %s plugins', auth_plugins)
-    for module in auth_plugins:
-        try:
-            plugin = loadplugin(module)
-        except (ImportError, AttributeError, TypeError) as e:
-            log.error('Failed to load authentication module %s : %s' % (module, str(e)))
-            continue
+    for plugin in auth_plugins:
+        module = plugin.__class__.__module__
         log.debug('Trying authentication using ** %s **', module)
         # load plugin settings from Kallithea database
         plugin_name = plugin.name
@@ -424,10 +425,10 @@
     """return list of fields that are managed by the user's auth source, usually some of
     'username', 'firstname', 'lastname', 'email', 'active', 'password'
     """
-    auth_plugins = Setting.get_auth_plugins()
-    for module in auth_plugins:
+    auth_plugins = get_auth_plugins()
+    for plugin in auth_plugins:
+        module = plugin.__class__.__module__
         log.debug('testing %s (%s) with auth plugin %s', user, user.extern_type, module)
-        plugin = loadplugin(module)
         if plugin.name == user.extern_type:
             return plugin.get_managed_fields()
     log.error('no auth plugin %s found for %s', user.extern_type, user)
--- a/kallithea/lib/base.py	Sun Apr 02 13:38:08 2017 +0200
+++ b/kallithea/lib/base.py	Sun Apr 02 13:38:08 2017 +0200
@@ -482,8 +482,8 @@
 
         # Authenticate by auth_container plugin (if enabled)
         if any(
-            auth_modules.importplugin(name).is_container_auth
-            for name in Setting.get_auth_plugins()
+            plugin.is_container_auth
+            for plugin in auth_modules.get_auth_plugins()
         ):
             try:
                 user_info = auth_modules.authenticate('', '', request.environ)
--- a/kallithea/model/db.py	Sun Apr 02 13:38:08 2017 +0200
+++ b/kallithea/model/db.py	Sun Apr 02 13:38:08 2017 +0200
@@ -300,11 +300,6 @@
         return settings
 
     @classmethod
-    def get_auth_plugins(cls, cache=False):
-        auth_plugins = cls.get_by_name("auth_plugins").app_settings_value
-        return auth_plugins
-
-    @classmethod
     def get_auth_settings(cls, cache=False):
         ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('auth_')).all()