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