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 |
|
|
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. |
|
|
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.r |
|
|
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 |
General Comments 0
You need to be logged in to leave comments.
Login now