##// END OF EJS Templates
Authentication: cache plugins for auth and their settings in the auth_registry....
marcink -
r4220:5a873939 stable
parent child Browse files
Show More
@@ -108,7 +108,8 b' class TestLoginController(object):'
108 108
109 109 def test_login_regular_forbidden_when_super_admin_restriction(self):
110 110 from rhodecode.authentication.plugins.auth_rhodecode import RhodeCodeAuthPlugin
111 with fixture.auth_restriction(RhodeCodeAuthPlugin.AUTH_RESTRICTION_SUPER_ADMIN):
111 with fixture.auth_restriction(self.app._pyramid_registry,
112 RhodeCodeAuthPlugin.AUTH_RESTRICTION_SUPER_ADMIN):
112 113 response = self.app.post(route_path('login'),
113 114 {'username': 'test_regular',
114 115 'password': 'test12'})
@@ -118,7 +119,8 b' class TestLoginController(object):'
118 119
119 120 def test_login_regular_forbidden_when_scope_restriction(self):
120 121 from rhodecode.authentication.plugins.auth_rhodecode import RhodeCodeAuthPlugin
121 with fixture.scope_restriction(RhodeCodeAuthPlugin.AUTH_RESTRICTION_SCOPE_VCS):
122 with fixture.scope_restriction(self.app._pyramid_registry,
123 RhodeCodeAuthPlugin.AUTH_RESTRICTION_SCOPE_VCS):
122 124 response = self.app.post(route_path('login'),
123 125 {'username': 'test_regular',
124 126 'password': 'test12'})
@@ -150,6 +150,7 b' class RhodeCodeAuthPluginBase(object):'
150 150
151 151 def __init__(self, plugin_id):
152 152 self._plugin_id = plugin_id
153 self._settings = {}
153 154
154 155 def __str__(self):
155 156 return self.get_id()
@@ -226,17 +227,26 b' class RhodeCodeAuthPluginBase(object):'
226 227 """
227 228 return AuthnPluginSettingsSchemaBase()
228 229
229 def get_settings(self):
230 """
231 Returns the plugin settings as dictionary.
232 """
230 def _propagate_settings(self, raw_settings):
233 231 settings = {}
234 raw_settings = SettingsModel().get_all_settings()
235 232 for node in self.get_settings_schema():
236 233 settings[node.name] = self.get_setting_by_name(
237 234 node.name, plugin_cached_settings=raw_settings)
238 235 return settings
239 236
237 def get_settings(self, use_cache=True):
238 """
239 Returns the plugin settings as dictionary.
240 """
241 if self._settings != {} and use_cache:
242 return self._settings
243
244 raw_settings = SettingsModel().get_all_settings()
245 settings = self._propagate_settings(raw_settings)
246
247 self._settings = settings
248 return self._settings
249
240 250 def get_setting_by_name(self, name, default=None, plugin_cached_settings=None):
241 251 """
242 252 Returns a plugin setting by name.
@@ -667,7 +677,7 b' def loadplugin(plugin_id):'
667 677
668 678 def get_authn_registry(registry=None):
669 679 registry = registry or get_current_registry()
670 authn_registry = registry.getUtility(IAuthnPluginRegistry)
680 authn_registry = registry.queryUtility(IAuthnPluginRegistry)
671 681 return authn_registry
672 682
673 683
@@ -690,6 +700,7 b' def authenticate(username, password, env'
690 700 headers_only = environ and not (username and password)
691 701
692 702 authn_registry = get_authn_registry(registry)
703
693 704 plugins_to_check = authn_registry.get_plugins_for_authentication()
694 705 log.debug('Starting ordered authentication chain using %s plugins',
695 706 [x.name for x in plugins_to_check])
@@ -38,6 +38,7 b' class AuthenticationPluginRegistry(objec'
38 38
39 39 def __init__(self, settings):
40 40 self._plugins = {}
41 self._plugins_for_auth = None
41 42 self._fallback_plugin = settings.get(self.fallback_plugin_key, None)
42 43
43 44 def add_authn_plugin(self, config, plugin):
@@ -63,6 +64,10 b' class AuthenticationPluginRegistry(objec'
63 64 if plugin.uid == plugin_uid:
64 65 return plugin
65 66
67 def invalidate_plugins_for_auth(self):
68 log.debug('Invalidating cached plugins for authentication')
69 self._plugins_for_auth = None
70
66 71 def get_plugins_for_authentication(self):
67 72 """
68 73 Returns a list of plugins which should be consulted when authenticating
@@ -70,6 +75,9 b' class AuthenticationPluginRegistry(objec'
70 75 Additionally it includes the fallback plugin from the INI file, if
71 76 `rhodecode.auth_plugin_fallback` is set to a plugin ID.
72 77 """
78 if self._plugins_for_auth is not None:
79 return self._plugins_for_auth
80
73 81 plugins = []
74 82
75 83 # Add all enabled and active plugins to the list. We iterate over the
@@ -80,6 +88,9 b' class AuthenticationPluginRegistry(objec'
80 88 plugin = self.get_plugin(plugin_id)
81 89 if plugin is not None and plugin.is_active(
82 90 plugin_cached_settings=raw_settings):
91
92 # inject settings into plugin, we can re-use the DB fetched settings here
93 plugin._settings = plugin._propagate_settings(raw_settings)
83 94 plugins.append(plugin)
84 95
85 96 # Add the fallback plugin from ini file.
@@ -89,6 +100,8 b' class AuthenticationPluginRegistry(objec'
89 100 self._fallback_plugin)
90 101 plugin = self.get_plugin(self._fallback_plugin)
91 102 if plugin is not None and plugin not in plugins:
103 plugin._settings = plugin._propagate_settings(raw_settings)
92 104 plugins.append(plugin)
93 105
94 return plugins
106 self._plugins_for_auth = plugins
107 return self._plugins_for_auth
@@ -99,11 +99,12 b' class AuthnPluginViewBase(BaseAppView):'
99 99 for name, value in valid_data.items():
100 100 self.plugin.create_or_update_setting(name, value)
101 101 Session().commit()
102 SettingsModel().invalidate_settings_cache()
102 103
103 104 # Display success message and redirect.
104 105 h.flash(_('Auth settings updated successfully.'), category='success')
105 redirect_to = self.request.resource_path(
106 self.context, route_name='auth_home')
106 redirect_to = self.request.resource_path(self.context, route_name='auth_home')
107
107 108 return HTTPFound(redirect_to)
108 109
109 110
@@ -159,7 +160,7 b' class AuthSettingsView(BaseAppView):'
159 160 'auth_plugins', plugins)
160 161 Session().add(setting)
161 162 Session().commit()
162
163 SettingsModel().invalidate_settings_cache()
163 164 h.flash(_('Auth settings updated successfully.'), category='success')
164 165 except formencode.Invalid as errors:
165 166 e = errors.error_dict or {}
@@ -174,6 +175,6 b' class AuthSettingsView(BaseAppView):'
174 175 h.flash(_('Error occurred during update of auth settings.'),
175 176 category='error')
176 177
177 redirect_to = self.request.resource_path(
178 self.context, route_name='auth_home')
178 redirect_to = self.request.resource_path(self.context, route_name='auth_home')
179
179 180 return HTTPFound(redirect_to)
@@ -211,8 +211,9 b' def vcs_operation_context('
211 211 class BasicAuth(AuthBasicAuthenticator):
212 212
213 213 def __init__(self, realm, authfunc, registry, auth_http_code=None,
214 initial_call_detection=False, acl_repo_name=None):
214 initial_call_detection=False, acl_repo_name=None, rc_realm=''):
215 215 self.realm = realm
216 self.rc_realm = rc_realm
216 217 self.initial_call = initial_call_detection
217 218 self.authfunc = authfunc
218 219 self.registry = registry
@@ -227,7 +228,7 b' class BasicAuth(AuthBasicAuthenticator):'
227 228 return HTTPForbidden
228 229
229 230 def get_rc_realm(self):
230 return safe_str(self.registry.rhodecode_settings.get('rhodecode_realm'))
231 return safe_str(self.rc_realm)
231 232
232 233 def build_authentication(self):
233 234 head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
@@ -133,15 +133,16 b' class SimpleVCS(object):'
133 133 self.config = config
134 134 # re-populated by specialized middleware
135 135 self.repo_vcs_config = base.Config()
136 self.rhodecode_settings = SettingsModel().get_all_settings(cache=True)
137 136
138 registry.rhodecode_settings = self.rhodecode_settings
137 rc_settings = SettingsModel().get_all_settings(cache=True, from_request=False)
138 realm = rc_settings.get('rhodecode_realm') or 'RhodeCode AUTH'
139
139 140 # authenticate this VCS request using authfunc
140 141 auth_ret_code_detection = \
141 142 str2bool(self.config.get('auth_ret_code_detection', False))
142 143 self.authenticate = BasicAuth(
143 144 '', authenticate, registry, config.get('auth_ret_code'),
144 auth_ret_code_detection)
145 auth_ret_code_detection, rc_realm=realm)
145 146 self.ip_addr = '0.0.0.0'
146 147
147 148 @LazyProperty
@@ -25,7 +25,7 b' import re'
25 25 from collections import namedtuple
26 26 from functools import wraps
27 27 import bleach
28 from pyramid.threadlocal import get_current_request
28 from pyramid.threadlocal import get_current_request, get_current_registry
29 29
30 30 from rhodecode.lib import rc_cache
31 31 from rhodecode.lib.utils2 import (
@@ -213,6 +213,8 b' class SettingsModel(BaseModel):'
213 213 CacheKey.set_invalidate(invalidation_namespace)
214 214
215 215 def get_all_settings(self, cache=False, from_request=True):
216 from rhodecode.authentication.base import get_authn_registry
217
216 218 # defines if we use GLOBAL, or PER_REPO
217 219 repo = self._get_repo(self.repo) if self.repo else None
218 220 key = "settings_repo.{}".format(repo.repo_id) if repo else "settings_app"
@@ -253,6 +255,11 b' class SettingsModel(BaseModel):'
253 255 # are anyway very short lived and it's a safest way.
254 256 region = rc_cache.get_or_create_region('sql_cache_short')
255 257 region.invalidate()
258 registry = get_current_registry()
259 if registry:
260 authn_registry = get_authn_registry(registry)
261 if authn_registry:
262 authn_registry.invalidate_plugins_for_auth()
256 263
257 264 result = _get_all_settings('rhodecode_settings', key)
258 265 log.debug('Fetching app settings for key: %s took: %.4fs', key,
@@ -29,6 +29,7 b' import shutil'
29 29
30 30 import configobj
31 31
32 from rhodecode.model.settings import SettingsModel
32 33 from rhodecode.tests import *
33 34 from rhodecode.model.db import Repository, User, RepoGroup, UserGroup, Gist, UserEmailMap
34 35 from rhodecode.model.meta import Session
@@ -122,7 +123,7 b' class Fixture(object):'
122 123
123 124 return context()
124 125
125 def auth_restriction(self, auth_restriction):
126 def auth_restriction(self, registry, auth_restriction):
126 127 """
127 128 Context process for changing the builtin rhodecode plugin auth restrictions.
128 129 Use like:
@@ -135,26 +136,26 b' class Fixture(object):'
135 136
136 137 class context(object):
137 138 def _get_pluing(self):
138 plugin_id = 'egg:rhodecode-enterprise-ce#{}'.format(
139 RhodeCodeAuthPlugin.uid)
139 plugin_id = 'egg:rhodecode-enterprise-ce#{}'.format(RhodeCodeAuthPlugin.uid)
140 140 plugin = RhodeCodeAuthPlugin(plugin_id)
141 141 return plugin
142 142
143 143 def __enter__(self):
144 144 plugin = self._get_pluing()
145 plugin.create_or_update_setting(
146 'auth_restriction', auth_restriction)
145 plugin.create_or_update_setting('auth_restriction', auth_restriction)
147 146 Session().commit()
147 SettingsModel().invalidate_settings_cache()
148 148
149 149 def __exit__(self, exc_type, exc_val, exc_tb):
150 150 plugin = self._get_pluing()
151 151 plugin.create_or_update_setting(
152 152 'auth_restriction', RhodeCodeAuthPlugin.AUTH_RESTRICTION_NONE)
153 153 Session().commit()
154 SettingsModel().invalidate_settings_cache()
154 155
155 156 return context()
156 157
157 def scope_restriction(self, scope_restriction):
158 def scope_restriction(self, registry, scope_restriction):
158 159 """
159 160 Context process for changing the builtin rhodecode plugin scope restrictions.
160 161 Use like:
@@ -167,22 +168,22 b' class Fixture(object):'
167 168
168 169 class context(object):
169 170 def _get_pluing(self):
170 plugin_id = 'egg:rhodecode-enterprise-ce#{}'.format(
171 RhodeCodeAuthPlugin.uid)
171 plugin_id = 'egg:rhodecode-enterprise-ce#{}'.format(RhodeCodeAuthPlugin.uid)
172 172 plugin = RhodeCodeAuthPlugin(plugin_id)
173 173 return plugin
174 174
175 175 def __enter__(self):
176 176 plugin = self._get_pluing()
177 plugin.create_or_update_setting(
178 'scope_restriction', scope_restriction)
177 plugin.create_or_update_setting('scope_restriction', scope_restriction)
179 178 Session().commit()
179 SettingsModel().invalidate_settings_cache()
180 180
181 181 def __exit__(self, exc_type, exc_val, exc_tb):
182 182 plugin = self._get_pluing()
183 183 plugin.create_or_update_setting(
184 184 'scope_restriction', RhodeCodeAuthPlugin.AUTH_RESTRICTION_SCOPE_ALL)
185 185 Session().commit()
186 SettingsModel().invalidate_settings_cache()
186 187
187 188 return context()
188 189
@@ -209,6 +209,8 b' def enable_auth_plugins(request, baseapp'
209 209 Session().add(setting)
210 210 Session().commit()
211 211
212 SettingsModel().invalidate_settings_cache()
213
212 214 def cleanup():
213 215 _enable_plugins(['egg:rhodecode-enterprise-ce#rhodecode'])
214 216
General Comments 0
You need to be logged in to leave comments. Login now