diff --git a/rhodecode/authentication/registry.py b/rhodecode/authentication/registry.py --- a/rhodecode/authentication/registry.py +++ b/rhodecode/authentication/registry.py @@ -18,14 +18,17 @@ # RhodeCode Enterprise Edition, including its added features, Support services, # and proprietary license terms, please see https://rhodecode.com/licenses/ +import time import logging from pyramid.exceptions import ConfigurationError from zope.interface import implementer from rhodecode.authentication.interface import IAuthnPluginRegistry +from rhodecode.model.settings import SettingsModel from rhodecode.lib.utils2 import safe_str -from rhodecode.model.settings import SettingsModel +from rhodecode.lib.statsd_client import StatsdClient +from rhodecode.lib import rc_cache log = logging.getLogger(__name__) @@ -38,7 +41,6 @@ class AuthenticationPluginRegistry(objec def __init__(self, settings): self._plugins = {} - self._plugins_for_auth = None self._fallback_plugin = settings.get(self.fallback_plugin_key, None) def add_authn_plugin(self, config, plugin): @@ -64,44 +66,56 @@ class AuthenticationPluginRegistry(objec if plugin.uid == plugin_uid: return plugin - def invalidate_plugins_for_auth(self): - log.debug('Invalidating cached plugins for authentication') - self._plugins_for_auth = None - - def get_plugins_for_authentication(self): + def get_plugins_for_authentication(self, cache=True): """ Returns a list of plugins which should be consulted when authenticating a user. It only returns plugins which are enabled and active. Additionally it includes the fallback plugin from the INI file, if `rhodecode.auth_plugin_fallback` is set to a plugin ID. """ - if self._plugins_for_auth is not None: - return self._plugins_for_auth + + cache_namespace_uid = 'cache_auth_plugins' + region = rc_cache.get_or_create_region('cache_general', cache_namespace_uid) - plugins = [] + @region.conditional_cache_on_arguments(condition=cache) + def _get_auth_plugins(name, key, fallback_plugin): + plugins = [] - # Add all enabled and active plugins to the list. We iterate over the - # auth_plugins setting from DB because it also represents the ordering. - enabled_plugins = SettingsModel().get_auth_plugins() - raw_settings = SettingsModel().get_all_settings(cache=True) - for plugin_id in enabled_plugins: - plugin = self.get_plugin(plugin_id) - if plugin is not None and plugin.is_active( - plugin_cached_settings=raw_settings): + # Add all enabled and active plugins to the list. We iterate over the + # auth_plugins setting from DB because it also represents the ordering. + enabled_plugins = SettingsModel().get_auth_plugins() + raw_settings = SettingsModel().get_all_settings(cache=False) + for plugin_id in enabled_plugins: + plugin = self.get_plugin(plugin_id) + if plugin is not None and plugin.is_active( + plugin_cached_settings=raw_settings): + + # inject settings into plugin, we can re-use the DB fetched settings here + plugin._settings = plugin._propagate_settings(raw_settings) + plugins.append(plugin) - # inject settings into plugin, we can re-use the DB fetched settings here - plugin._settings = plugin._propagate_settings(raw_settings) - plugins.append(plugin) + # Add the fallback plugin from ini file. + if fallback_plugin: + log.warn( + 'Using fallback authentication plugin from INI file: "%s"', + fallback_plugin) + plugin = self.get_plugin(fallback_plugin) + if plugin is not None and plugin not in plugins: + plugin._settings = plugin._propagate_settings(raw_settings) + plugins.append(plugin) + return plugins - # Add the fallback plugin from ini file. - if self._fallback_plugin: - log.warn( - 'Using fallback authentication plugin from INI file: "%s"', - self._fallback_plugin) - plugin = self.get_plugin(self._fallback_plugin) - if plugin is not None and plugin not in plugins: - plugin._settings = plugin._propagate_settings(raw_settings) - plugins.append(plugin) + start = time.time() + plugins = _get_auth_plugins('rhodecode_auth_plugins', 'v1', self._fallback_plugin) + + compute_time = time.time() - start + log.debug('cached method:%s took %.4fs', _get_auth_plugins.func_name, compute_time) - self._plugins_for_auth = plugins - return self._plugins_for_auth + statsd = StatsdClient.statsd + if statsd: + elapsed_time_ms = round(1000.0 * compute_time) # use ms only + statsd.timing("rhodecode_auth_plugins_timing.histogram", elapsed_time_ms, + use_decimals=False) + + return plugins + diff --git a/rhodecode/model/settings.py b/rhodecode/model/settings.py --- a/rhodecode/model/settings.py +++ b/rhodecode/model/settings.py @@ -218,16 +218,9 @@ class SettingsModel(BaseModel): return region, cache_key def invalidate_settings_cache(self): - from rhodecode.authentication.base import get_authn_registry - region, cache_key = self.get_cache_region() log.debug('Invalidation cache region %s for cache_key: %s', region, cache_key) region.invalidate() - registry = get_current_registry() - if registry: - authn_registry = get_authn_registry(registry) - if authn_registry: - authn_registry.invalidate_plugins_for_auth() def get_all_settings(self, cache=False, from_request=True): # defines if we use GLOBAL, or PER_REPO @@ -260,6 +253,7 @@ class SettingsModel(BaseModel): start = time.time() result = _get_all_settings('rhodecode_settings', cache_key) compute_time = time.time() - start + log.debug('cached method:%s took %.4fs', _get_all_settings.func_name, compute_time) statsd = StatsdClient.statsd if statsd: