##// END OF EJS Templates
authentication: introduce login restriction option for builtin rhodecode plugin.
marcink -
r3387:8a62bda2 default
parent child Browse files
Show More
@@ -107,6 +107,16 b' class TestLoginController(object):'
107
107
108 response.mustcontain('/%s' % HG_REPO)
108 response.mustcontain('/%s' % HG_REPO)
109
109
110 def test_login_regular_forbidden_when_super_admin_restriction(self):
111 from rhodecode.authentication.plugins.auth_rhodecode import RhodeCodeAuthPlugin
112 with fixture.login_restriction(RhodeCodeAuthPlugin.LOGIN_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
110 def test_login_ok_came_from(self):
120 def test_login_ok_came_from(self):
111 test_came_from = '/_admin/users?branch=stable'
121 test_came_from = '/_admin/users?branch=stable'
112 _url = '{}?came_from={}'.format(route_path('login'), test_came_from)
122 _url = '{}?came_from={}'.format(route_path('login'), test_came_from)
@@ -46,20 +46,10 b' class RhodecodeAuthnResource(AuthnPlugin'
46 pass
46 pass
47
47
48
48
49 class RhodeCodeSettingsSchema(AuthnPluginSettingsSchemaBase):
50
51 superadmin_restriction = colander.SchemaNode(
52 colander.Bool(),
53 default=False,
54 description=_('Only allow super-admins to log-in using this plugin.'),
55 missing=False,
56 title=_('Enabled'),
57 widget='bool',
58 )
59
60
61 class RhodeCodeAuthPlugin(RhodeCodeAuthPluginBase):
49 class RhodeCodeAuthPlugin(RhodeCodeAuthPluginBase):
62 uid = 'rhodecode'
50 uid = 'rhodecode'
51 LOGIN_RESTRICTION_NONE = 'none'
52 LOGIN_RESTRICTION_SUPER_ADMIN = 'super_admin'
63
53
64 def includeme(self, config):
54 def includeme(self, config):
65 config.add_authn_plugin(self)
55 config.add_authn_plugin(self)
@@ -112,12 +102,20 b' class RhodeCodeAuthPlugin(RhodeCodeAuthP'
112 if not userobj:
102 if not userobj:
113 log.debug('userobj was:%s skipping', userobj)
103 log.debug('userobj was:%s skipping', userobj)
114 return None
104 return None
105
115 if userobj.extern_type != self.name:
106 if userobj.extern_type != self.name:
116 log.warning(
107 log.warning(
117 "userobj:%s extern_type mismatch got:`%s` expected:`%s`",
108 "userobj:%s extern_type mismatch got:`%s` expected:`%s`",
118 userobj, userobj.extern_type, self.name)
109 userobj, userobj.extern_type, self.name)
119 return None
110 return None
120
111
112 login_restriction = settings.get('login_restriction', '')
113 if login_restriction == self.LOGIN_RESTRICTION_SUPER_ADMIN and userobj.admin is False:
114 log.info(
115 "userobj:%s is not super-admin and login restriction is set to %s",
116 userobj, login_restriction)
117 return None
118
121 user_attrs = {
119 user_attrs = {
122 "username": userobj.username,
120 "username": userobj.username,
123 "firstname": userobj.firstname,
121 "firstname": userobj.firstname,
@@ -149,8 +147,8 b' class RhodeCodeAuthPlugin(RhodeCodeAuthP'
149 user_attrs['_hash_migrate'] = new_hash
147 user_attrs['_hash_migrate'] = new_hash
150
148
151 if userobj.username == User.DEFAULT_USER and userobj.active:
149 if userobj.username == User.DEFAULT_USER and userobj.active:
152 log.info(
150 log.info('user `%s` authenticated correctly as anonymous user',
153 'user `%s` authenticated correctly as anonymous user', userobj.username)
151 userobj.username)
154 return user_attrs
152 return user_attrs
155
153
156 elif userobj.username == username and password_match:
154 elif userobj.username == username and password_match:
@@ -166,6 +164,23 b' class RhodeCodeAuthPlugin(RhodeCodeAuthP'
166 return None
164 return None
167
165
168
166
167 class RhodeCodeSettingsSchema(AuthnPluginSettingsSchemaBase):
168 login_restriction_choices = [
169 (RhodeCodeAuthPlugin.LOGIN_RESTRICTION_NONE, 'All users'),
170 (RhodeCodeAuthPlugin.LOGIN_RESTRICTION_SUPER_ADMIN, 'Super admins only')
171 ]
172
173 login_restriction = colander.SchemaNode(
174 colander.String(),
175 default=login_restriction_choices[0],
176 description=_('Choose login restrition for users.'),
177 title=_('Login restriction'),
178 validator=colander.OneOf([x[0] for x in login_restriction_choices]),
179 widget='select_with_labels',
180 choices=login_restriction_choices
181 )
182
183
169 def includeme(config):
184 def includeme(config):
170 plugin_id = 'egg:rhodecode-enterprise-ce#{}'.format(RhodeCodeAuthPlugin.uid)
185 plugin_id = 'egg:rhodecode-enterprise-ce#{}'.format(RhodeCodeAuthPlugin.uid)
171 plugin_factory(plugin_id).includeme(config)
186 plugin_factory(plugin_id).includeme(config)
@@ -66,6 +66,8 b''
66 <div class="checkbox">${h.checkbox(node.name, True, checked=defaults.get(node.name))}</div>
66 <div class="checkbox">${h.checkbox(node.name, True, checked=defaults.get(node.name))}</div>
67 %elif node.widget == "select":
67 %elif node.widget == "select":
68 ${h.select(node.name, defaults.get(node.name), node.validator.choices, class_="select2AuthSetting")}
68 ${h.select(node.name, defaults.get(node.name), node.validator.choices, class_="select2AuthSetting")}
69 %elif node.widget == "select_with_labels":
70 ${h.select(node.name, defaults.get(node.name), node.choices, class_="select2AuthSetting")}
69 %elif node.widget == "textarea":
71 %elif node.widget == "textarea":
70 <div class="textarea" style="margin-left: 0px">${h.textarea(node.name, defaults.get(node.name), rows=10)}</div>
72 <div class="textarea" style="margin-left: 0px">${h.textarea(node.name, defaults.get(node.name), rows=10)}</div>
71 %elif node.widget == "readonly":
73 %elif node.widget == "readonly":
@@ -38,6 +38,8 b' from rhodecode.model.repo_group import R'
38 from rhodecode.model.user_group import UserGroupModel
38 from rhodecode.model.user_group import UserGroupModel
39 from rhodecode.model.gist import GistModel
39 from rhodecode.model.gist import GistModel
40 from rhodecode.model.auth_token import AuthTokenModel
40 from rhodecode.model.auth_token import AuthTokenModel
41 from rhodecode.authentication.plugins.auth_rhodecode import \
42 RhodeCodeAuthPlugin
41
43
42 dn = os.path.dirname
44 dn = os.path.dirname
43 FIXTURES = os.path.join(dn(dn(os.path.abspath(__file__))), 'tests', 'fixtures')
45 FIXTURES = os.path.join(dn(dn(os.path.abspath(__file__))), 'tests', 'fixtures')
@@ -120,6 +122,38 b' class Fixture(object):'
120
122
121 return context()
123 return context()
122
124
125 def login_restriction(self, login_restriction):
126 """
127 Context process for changing the builtin rhodecode plugin login restrictions.
128 Use like:
129 fixture = Fixture()
130 with fixture.login_restriction('super_admin'):
131 #tests
132
133 after this block login restriction will be taken off
134 """
135
136 class context(object):
137 def _get_pluing(self):
138 plugin_id = 'egg:rhodecode-enterprise-ce#{}'.format(
139 RhodeCodeAuthPlugin.uid)
140 plugin = RhodeCodeAuthPlugin(plugin_id)
141 return plugin
142
143 def __enter__(self):
144 plugin = self._get_pluing()
145 plugin.create_or_update_setting(
146 'login_restriction', login_restriction)
147 Session().commit()
148
149 def __exit__(self, exc_type, exc_val, exc_tb):
150 plugin = self._get_pluing()
151 plugin.create_or_update_setting(
152 'login_restriction', RhodeCodeAuthPlugin.LOGIN_RESTRICTION_NONE)
153 Session().commit()
154
155 return context()
156
123 def _get_repo_create_params(self, **custom):
157 def _get_repo_create_params(self, **custom):
124 defs = {
158 defs = {
125 'repo_name': None,
159 'repo_name': None,
General Comments 0
You need to be logged in to leave comments. Login now