Show More
@@ -109,7 +109,17 b' class TestLoginController(object):' | |||||
109 |
|
109 | |||
110 | def test_login_regular_forbidden_when_super_admin_restriction(self): |
|
110 | def test_login_regular_forbidden_when_super_admin_restriction(self): | |
111 | from rhodecode.authentication.plugins.auth_rhodecode import RhodeCodeAuthPlugin |
|
111 | from rhodecode.authentication.plugins.auth_rhodecode import RhodeCodeAuthPlugin | |
112 |
with fixture. |
|
112 | with fixture.auth_restriction(RhodeCodeAuthPlugin.AUTH_RESTRICTION_SUPER_ADMIN): | |
|
113 | response = self.app.post(route_path('login'), | |||
|
114 | {'username': 'test_regular', | |||
|
115 | 'password': 'test12'}) | |||
|
116 | ||||
|
117 | response.mustcontain('invalid user name') | |||
|
118 | response.mustcontain('invalid password') | |||
|
119 | ||||
|
120 | def test_login_regular_forbidden_when_scope_restriction(self): | |||
|
121 | from rhodecode.authentication.plugins.auth_rhodecode import RhodeCodeAuthPlugin | |||
|
122 | with fixture.scope_restriction(RhodeCodeAuthPlugin.AUTH_RESTRICTION_SCOPE_VCS): | |||
113 | response = self.app.post(route_path('login'), |
|
123 | response = self.app.post(route_path('login'), | |
114 | {'username': 'test_regular', |
|
124 | {'username': 'test_regular', | |
115 | 'password': 'test12'}) |
|
125 | 'password': 'test12'}) |
@@ -26,13 +26,13 b' import logging' | |||||
26 |
|
26 | |||
27 | import colander |
|
27 | import colander | |
28 |
|
28 | |||
29 | from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase |
|
|||
30 | from rhodecode.translation import _ |
|
29 | from rhodecode.translation import _ | |
31 |
|
||||
32 | from rhodecode.authentication.base import RhodeCodeAuthPluginBase, hybrid_property |
|
|||
33 | from rhodecode.authentication.routes import AuthnPluginResourceBase |
|
|||
34 | from rhodecode.lib.utils2 import safe_str |
|
30 | from rhodecode.lib.utils2 import safe_str | |
35 | from rhodecode.model.db import User |
|
31 | from rhodecode.model.db import User | |
|
32 | from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase | |||
|
33 | from rhodecode.authentication.base import ( | |||
|
34 | RhodeCodeAuthPluginBase, hybrid_property, HTTP_TYPE, VCS_TYPE) | |||
|
35 | from rhodecode.authentication.routes import AuthnPluginResourceBase | |||
36 |
|
36 | |||
37 | log = logging.getLogger(__name__) |
|
37 | log = logging.getLogger(__name__) | |
38 |
|
38 | |||
@@ -48,8 +48,11 b' class RhodecodeAuthnResource(AuthnPlugin' | |||||
48 |
|
48 | |||
49 | class RhodeCodeAuthPlugin(RhodeCodeAuthPluginBase): |
|
49 | class RhodeCodeAuthPlugin(RhodeCodeAuthPluginBase): | |
50 | uid = 'rhodecode' |
|
50 | uid = 'rhodecode' | |
51 |
|
|
51 | AUTH_RESTRICTION_NONE = 'user_all' | |
52 |
|
|
52 | AUTH_RESTRICTION_SUPER_ADMIN = 'user_super_admin' | |
|
53 | AUTH_RESTRICTION_SCOPE_ALL = 'scope_all' | |||
|
54 | AUTH_RESTRICTION_SCOPE_HTTP = 'scope_http' | |||
|
55 | AUTH_RESTRICTION_SCOPE_VCS = 'scope_vcs' | |||
53 |
|
56 | |||
54 | def includeme(self, config): |
|
57 | def includeme(self, config): | |
55 | config.add_authn_plugin(self) |
|
58 | config.add_authn_plugin(self) | |
@@ -104,16 +107,32 b' class RhodeCodeAuthPlugin(RhodeCodeAuthP' | |||||
104 | return None |
|
107 | return None | |
105 |
|
108 | |||
106 | if userobj.extern_type != self.name: |
|
109 | if userobj.extern_type != self.name: | |
107 | log.warning( |
|
110 | log.warning("userobj:%s extern_type mismatch got:`%s` expected:`%s`", | |
108 | "userobj:%s extern_type mismatch got:`%s` expected:`%s`", |
|
111 | userobj, userobj.extern_type, self.name) | |
109 | userobj, userobj.extern_type, self.name) |
|
112 | return None | |
|
113 | ||||
|
114 | # check scope of auth | |||
|
115 | scope_restriction = settings.get('scope_restriction', '') | |||
|
116 | ||||
|
117 | if scope_restriction == self.AUTH_RESTRICTION_SCOPE_HTTP \ | |||
|
118 | and self.auth_type != HTTP_TYPE: | |||
|
119 | log.warning("userobj:%s tried scope type %s and scope restriction is set to %s", | |||
|
120 | userobj, self.auth_type, scope_restriction) | |||
110 | return None |
|
121 | return None | |
111 |
|
122 | |||
112 | login_restriction = settings.get('login_restriction', '') |
|
123 | if scope_restriction == self.AUTH_RESTRICTION_SCOPE_VCS \ | |
113 | if login_restriction == self.LOGIN_RESTRICTION_SUPER_ADMIN and userobj.admin is False: |
|
124 | and self.auth_type != VCS_TYPE: | |
114 | log.info( |
|
125 | log.warning("userobj:%s tried scope type %s and scope restriction is set to %s", | |
115 | "userobj:%s is not super-admin and login restriction is set to %s", |
|
126 | userobj, self.auth_type, scope_restriction) | |
116 | userobj, login_restriction) |
|
127 | return None | |
|
128 | ||||
|
129 | # check super-admin restriction | |||
|
130 | auth_restriction = settings.get('auth_restriction', '') | |||
|
131 | ||||
|
132 | if auth_restriction == self.AUTH_RESTRICTION_SUPER_ADMIN \ | |||
|
133 | and userobj.admin is False: | |||
|
134 | log.warning("userobj:%s is not super-admin and auth restriction is set to %s", | |||
|
135 | userobj, auth_restriction) | |||
117 | return None |
|
136 | return None | |
118 |
|
137 | |||
119 | user_attrs = { |
|
138 | user_attrs = { | |
@@ -154,30 +173,45 b' class RhodeCodeAuthPlugin(RhodeCodeAuthP' | |||||
154 | elif userobj.username == username and password_match: |
|
173 | elif userobj.username == username and password_match: | |
155 | log.info('user `%s` authenticated correctly', userobj.username) |
|
174 | log.info('user `%s` authenticated correctly', userobj.username) | |
156 | return user_attrs |
|
175 | return user_attrs | |
157 | log.warn("user `%s` used a wrong password when " |
|
176 | log.warning("user `%s` used a wrong password when " | |
158 | "authenticating on this plugin", userobj.username) |
|
177 | "authenticating on this plugin", userobj.username) | |
159 | return None |
|
178 | return None | |
160 | else: |
|
179 | else: | |
161 | log.warning( |
|
180 | log.warning('user `%s` failed to authenticate via %s, reason: account not ' | |
162 | 'user `%s` failed to authenticate via %s, reason: account not ' |
|
181 | 'active.', username, self.name) | |
163 | 'active.', username, self.name) |
|
|||
164 | return None |
|
182 | return None | |
165 |
|
183 | |||
166 |
|
184 | |||
167 | class RhodeCodeSettingsSchema(AuthnPluginSettingsSchemaBase): |
|
185 | class RhodeCodeSettingsSchema(AuthnPluginSettingsSchemaBase): | |
168 | login_restriction_choices = [ |
|
186 | ||
169 | (RhodeCodeAuthPlugin.LOGIN_RESTRICTION_NONE, 'All users'), |
|
187 | auth_restriction_choices = [ | |
170 |
(RhodeCodeAuthPlugin. |
|
188 | (RhodeCodeAuthPlugin.AUTH_RESTRICTION_NONE, 'All users'), | |
|
189 | (RhodeCodeAuthPlugin.AUTH_RESTRICTION_SUPER_ADMIN, 'Super admins only'), | |||
|
190 | ] | |||
|
191 | ||||
|
192 | auth_scope_choices = [ | |||
|
193 | (RhodeCodeAuthPlugin.AUTH_RESTRICTION_SCOPE_ALL, 'HTTP and VCS'), | |||
|
194 | (RhodeCodeAuthPlugin.AUTH_RESTRICTION_SCOPE_HTTP, 'HTTP only'), | |||
171 | ] |
|
195 | ] | |
172 |
|
196 | |||
173 |
|
|
197 | auth_restriction = colander.SchemaNode( | |
174 | colander.String(), |
|
198 | colander.String(), | |
175 |
default= |
|
199 | default=auth_restriction_choices[0], | |
176 |
description=_(' |
|
200 | description=_('Allowed user types for authentication using this plugin.'), | |
177 |
title=_(' |
|
201 | title=_('User restriction'), | |
178 |
validator=colander.OneOf([x[0] for x in |
|
202 | validator=colander.OneOf([x[0] for x in auth_restriction_choices]), | |
179 | widget='select_with_labels', |
|
203 | widget='select_with_labels', | |
180 |
choices= |
|
204 | choices=auth_restriction_choices | |
|
205 | ) | |||
|
206 | scope_restriction = colander.SchemaNode( | |||
|
207 | colander.String(), | |||
|
208 | default=auth_scope_choices[0], | |||
|
209 | description=_('Allowed protocols for authentication using this plugin. ' | |||
|
210 | 'VCS means GIT/HG/SVN. HTTP is web based login.'), | |||
|
211 | title=_('Scope restriction'), | |||
|
212 | validator=colander.OneOf([x[0] for x in auth_scope_choices]), | |||
|
213 | widget='select_with_labels', | |||
|
214 | choices=auth_scope_choices | |||
181 | ) |
|
215 | ) | |
182 |
|
216 | |||
183 |
|
217 |
@@ -23,7 +23,9 b' RhodeCode authentication token plugin fo' | |||||
23 | """ |
|
23 | """ | |
24 |
|
24 | |||
25 | import logging |
|
25 | import logging | |
|
26 | import colander | |||
26 |
|
27 | |||
|
28 | from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase | |||
27 | from rhodecode.translation import _ |
|
29 | from rhodecode.translation import _ | |
28 | from rhodecode.authentication.base import ( |
|
30 | from rhodecode.authentication.base import ( | |
29 | RhodeCodeAuthPluginBase, VCS_TYPE, hybrid_property) |
|
31 | RhodeCodeAuthPluginBase, VCS_TYPE, hybrid_property) | |
@@ -48,6 +50,7 b' class RhodeCodeAuthPlugin(RhodeCodeAuthP' | |||||
48 | Enables usage of authentication tokens for vcs operations. |
|
50 | Enables usage of authentication tokens for vcs operations. | |
49 | """ |
|
51 | """ | |
50 | uid = 'token' |
|
52 | uid = 'token' | |
|
53 | AUTH_RESTRICTION_SCOPE_VCS = 'scope_vcs' | |||
51 |
|
54 | |||
52 | def includeme(self, config): |
|
55 | def includeme(self, config): | |
53 | config.add_authn_plugin(self) |
|
56 | config.add_authn_plugin(self) | |
@@ -67,6 +70,9 b' class RhodeCodeAuthPlugin(RhodeCodeAuthP' | |||||
67 | route_name='auth_home', |
|
70 | route_name='auth_home', | |
68 | context=RhodecodeAuthnResource) |
|
71 | context=RhodecodeAuthnResource) | |
69 |
|
72 | |||
|
73 | def get_settings_schema(self): | |||
|
74 | return RhodeCodeSettingsSchema() | |||
|
75 | ||||
70 | def get_display_name(self): |
|
76 | def get_display_name(self): | |
71 | return _('Rhodecode Token') |
|
77 | return _('Rhodecode Token') | |
72 |
|
78 | |||
@@ -142,16 +148,30 b' class RhodeCodeAuthPlugin(RhodeCodeAuthP' | |||||
142 | 'user `%s` successfully authenticated via %s', |
|
148 | 'user `%s` successfully authenticated via %s', | |
143 | user_attrs['username'], self.name) |
|
149 | user_attrs['username'], self.name) | |
144 | return user_attrs |
|
150 | return user_attrs | |
145 | log.warn( |
|
151 | log.warning('user `%s` failed to authenticate via %s, reason: bad or ' | |
146 | 'user `%s` failed to authenticate via %s, reason: bad or ' |
|
152 | 'inactive token.', username, self.name) | |
147 | 'inactive token.', username, self.name) |
|
|||
148 | else: |
|
153 | else: | |
149 | log.warning( |
|
154 | log.warning('user `%s` failed to authenticate via %s, reason: account not ' | |
150 | 'user `%s` failed to authenticate via %s, reason: account not ' |
|
155 | 'active.', username, self.name) | |
151 | 'active.', username, self.name) |
|
|||
152 | return None |
|
156 | return None | |
153 |
|
157 | |||
154 |
|
158 | |||
155 | def includeme(config): |
|
159 | def includeme(config): | |
156 | plugin_id = 'egg:rhodecode-enterprise-ce#{}'.format(RhodeCodeAuthPlugin.uid) |
|
160 | plugin_id = 'egg:rhodecode-enterprise-ce#{}'.format(RhodeCodeAuthPlugin.uid) | |
157 | plugin_factory(plugin_id).includeme(config) |
|
161 | plugin_factory(plugin_id).includeme(config) | |
|
162 | ||||
|
163 | ||||
|
164 | class RhodeCodeSettingsSchema(AuthnPluginSettingsSchemaBase): | |||
|
165 | auth_scope_choices = [ | |||
|
166 | (RhodeCodeAuthPlugin.AUTH_RESTRICTION_SCOPE_VCS, 'VCS only'), | |||
|
167 | ] | |||
|
168 | ||||
|
169 | scope_restriction = colander.SchemaNode( | |||
|
170 | colander.String(), | |||
|
171 | default=auth_scope_choices[0], | |||
|
172 | description=_('Choose operation scope restriction when authenticating.'), | |||
|
173 | title=_('Scope restriction'), | |||
|
174 | validator=colander.OneOf([x[0] for x in auth_scope_choices]), | |||
|
175 | widget='select_with_labels', | |||
|
176 | choices=auth_scope_choices | |||
|
177 | ) |
@@ -122,15 +122,15 b' class Fixture(object):' | |||||
122 |
|
122 | |||
123 | return context() |
|
123 | return context() | |
124 |
|
124 | |||
125 |
def |
|
125 | def auth_restriction(self, auth_restriction): | |
126 | """ |
|
126 | """ | |
127 |
Context process for changing the builtin rhodecode plugin |
|
127 | Context process for changing the builtin rhodecode plugin auth restrictions. | |
128 | Use like: |
|
128 | Use like: | |
129 | fixture = Fixture() |
|
129 | fixture = Fixture() | |
130 |
with fixture. |
|
130 | with fixture.auth_restriction('super_admin'): | |
131 | #tests |
|
131 | #tests | |
132 |
|
132 | |||
133 |
after this block |
|
133 | after this block auth restriction will be taken off | |
134 | """ |
|
134 | """ | |
135 |
|
135 | |||
136 | class context(object): |
|
136 | class context(object): | |
@@ -143,13 +143,45 b' class Fixture(object):' | |||||
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( | |
146 |
' |
|
146 | 'auth_restriction', auth_restriction) | |
147 | Session().commit() |
|
147 | Session().commit() | |
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 |
' |
|
152 | 'auth_restriction', RhodeCodeAuthPlugin.AUTH_RESTRICTION_NONE) | |
|
153 | Session().commit() | |||
|
154 | ||||
|
155 | return context() | |||
|
156 | ||||
|
157 | def scope_restriction(self, scope_restriction): | |||
|
158 | """ | |||
|
159 | Context process for changing the builtin rhodecode plugin scope restrictions. | |||
|
160 | Use like: | |||
|
161 | fixture = Fixture() | |||
|
162 | with fixture.scope_restriction('scope_http'): | |||
|
163 | #tests | |||
|
164 | ||||
|
165 | after this block scope restriction will be taken off | |||
|
166 | """ | |||
|
167 | ||||
|
168 | class context(object): | |||
|
169 | def _get_pluing(self): | |||
|
170 | plugin_id = 'egg:rhodecode-enterprise-ce#{}'.format( | |||
|
171 | RhodeCodeAuthPlugin.uid) | |||
|
172 | plugin = RhodeCodeAuthPlugin(plugin_id) | |||
|
173 | return plugin | |||
|
174 | ||||
|
175 | def __enter__(self): | |||
|
176 | plugin = self._get_pluing() | |||
|
177 | plugin.create_or_update_setting( | |||
|
178 | 'scope_restriction', scope_restriction) | |||
|
179 | Session().commit() | |||
|
180 | ||||
|
181 | def __exit__(self, exc_type, exc_val, exc_tb): | |||
|
182 | plugin = self._get_pluing() | |||
|
183 | plugin.create_or_update_setting( | |||
|
184 | 'scope_restriction', RhodeCodeAuthPlugin.AUTH_RESTRICTION_SCOPE_ALL) | |||
153 | Session().commit() |
|
185 | Session().commit() | |
154 |
|
186 | |||
155 | return context() |
|
187 | return context() |
General Comments 0
You need to be logged in to leave comments.
Login now