Show More
@@ -36,8 +36,7 b' from pylons.i18n.translation import _' | |||
|
36 | 36 | |
|
37 | 37 | from rhodecode.lib.exceptions import DefaultUserException, UserOwnsReposException |
|
38 | 38 | from rhodecode.lib import helpers as h |
|
39 |
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator |
|
|
40 | fill_perms | |
|
39 | from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator | |
|
41 | 40 | from rhodecode.lib.base import BaseController, render |
|
42 | 41 | |
|
43 | 42 | from rhodecode.model.db import User |
@@ -157,14 +156,15 b' class UsersController(BaseController):' | |||
|
157 | 156 | def edit(self, id, format='html'): |
|
158 | 157 | """GET /users/id/edit: Form to edit an existing item""" |
|
159 | 158 | # url('edit_user', id=ID) |
|
160 | c.user = self.sa.query(User).get(id) | |
|
159 | user_model = UserModel() | |
|
160 | c.user = user_model.get(id) | |
|
161 | 161 | if not c.user: |
|
162 | 162 | return redirect(url('users')) |
|
163 | 163 | if c.user.username == 'default': |
|
164 | 164 | h.flash(_("You can't edit this user"), category='warning') |
|
165 | 165 | return redirect(url('users')) |
|
166 | 166 | c.user.permissions = {} |
|
167 | c.granted_permissions = fill_perms(c.user).permissions['global'] | |
|
167 | c.granted_permissions = user_model.fill_perms(c.user).permissions['global'] | |
|
168 | 168 | |
|
169 | 169 | defaults = c.user.get_dict() |
|
170 | 170 |
@@ -36,8 +36,7 b' from pylons.i18n.translation import _' | |||
|
36 | 36 | |
|
37 | 37 | from rhodecode.lib.exceptions import DefaultUserException, UserOwnsReposException |
|
38 | 38 | from rhodecode.lib import helpers as h |
|
39 |
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator |
|
|
40 | fill_perms | |
|
39 | from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator | |
|
41 | 40 | from rhodecode.lib.base import BaseController, render |
|
42 | 41 | |
|
43 | 42 | from rhodecode.model.db import User, UsersGroup |
@@ -49,6 +49,7 b' class JournalController(BaseController):' | |||
|
49 | 49 | @LoginRequired() |
|
50 | 50 | def __before__(self): |
|
51 | 51 | super(JournalController, self).__before__() |
|
52 | c.rhodecode_user = self.rhodecode_user | |
|
52 | 53 | self.title = _('%s public journal %s feed') % (c.rhodecode_name, '%s') |
|
53 | 54 | self.language = 'en-us' |
|
54 | 55 | self.ttl = "5" |
@@ -60,7 +61,7 b' class JournalController(BaseController):' | |||
|
60 | 61 | p = int(request.params.get('page', 1)) |
|
61 | 62 | |
|
62 | 63 | c.following = self.sa.query(UserFollowing)\ |
|
63 |
.filter(UserFollowing.user_id == |
|
|
64 | .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\ | |
|
64 | 65 | .options(joinedload(UserFollowing.follows_repository))\ |
|
65 | 66 | .all() |
|
66 | 67 | |
@@ -126,7 +127,7 b' class JournalController(BaseController):' | |||
|
126 | 127 | if user_id: |
|
127 | 128 | try: |
|
128 | 129 | self.scm_model.toggle_following_user(user_id, |
|
129 |
|
|
|
130 | self.rhodecode_user.user_id) | |
|
130 | 131 | return 'ok' |
|
131 | 132 | except: |
|
132 | 133 | raise HTTPInternalServerError() |
@@ -135,7 +136,7 b' class JournalController(BaseController):' | |||
|
135 | 136 | if repo_id: |
|
136 | 137 | try: |
|
137 | 138 | self.scm_model.toggle_following_repo(repo_id, |
|
138 |
|
|
|
139 | self.rhodecode_user.user_id) | |
|
139 | 140 | return 'ok' |
|
140 | 141 | except: |
|
141 | 142 | raise HTTPInternalServerError() |
@@ -152,7 +153,7 b' class JournalController(BaseController):' | |||
|
152 | 153 | p = int(request.params.get('page', 1)) |
|
153 | 154 | |
|
154 | 155 | c.following = self.sa.query(UserFollowing)\ |
|
155 |
.filter(UserFollowing.user_id == |
|
|
156 | .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\ | |
|
156 | 157 | .options(joinedload(UserFollowing.follows_repository))\ |
|
157 | 158 | .all() |
|
158 | 159 | |
@@ -174,7 +175,7 b' class JournalController(BaseController):' | |||
|
174 | 175 | Produce an atom-1.0 feed via feedgenerator module |
|
175 | 176 | """ |
|
176 | 177 | c.following = self.sa.query(UserFollowing)\ |
|
177 |
.filter(UserFollowing.user_id == |
|
|
178 | .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\ | |
|
178 | 179 | .options(joinedload(UserFollowing.follows_repository))\ |
|
179 | 180 | .all() |
|
180 | 181 | |
@@ -207,7 +208,7 b' class JournalController(BaseController):' | |||
|
207 | 208 | Produce an rss2 feed via feedgenerator module |
|
208 | 209 | """ |
|
209 | 210 | c.following = self.sa.query(UserFollowing)\ |
|
210 |
.filter(UserFollowing.user_id == |
|
|
211 | .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\ | |
|
211 | 212 | .options(joinedload(UserFollowing.follows_repository))\ |
|
212 | 213 | .all() |
|
213 | 214 |
@@ -62,19 +62,17 b' class LoginController(BaseController):' | |||
|
62 | 62 | login_form = LoginForm() |
|
63 | 63 | try: |
|
64 | 64 | c.form_result = login_form.to_python(dict(request.POST)) |
|
65 | #form checks for username/password, now we're authenticated | |
|
65 | 66 | username = c.form_result['username'] |
|
66 |
user = UserModel().get_by_username(username, |
|
|
67 | auth_user = AuthUser() | |
|
68 |
auth_user |
|
|
69 |
auth_user. |
|
|
70 | auth_user.is_admin = user.admin | |
|
71 | auth_user.user_id = user.user_id | |
|
72 | auth_user.name = user.name | |
|
73 | auth_user.lastname = user.lastname | |
|
67 | user = UserModel().get_by_username(username, | |
|
68 | case_insensitive=True) | |
|
69 | auth_user = AuthUser(user.user_id) | |
|
70 | auth_user.set_authenticated() | |
|
74 | 71 | session['rhodecode_user'] = auth_user |
|
75 | 72 | session.save() |
|
76 | log.info('user %s is now authenticated', username) | |
|
77 | 73 | |
|
74 | log.info('user %s is now authenticated and stored in session', | |
|
75 | username) | |
|
78 | 76 | user.update_lastlogin() |
|
79 | 77 | |
|
80 | 78 | if c.came_from: |
@@ -146,7 +144,7 b' class LoginController(BaseController):' | |||
|
146 | 144 | return render('/password_reset.html') |
|
147 | 145 | |
|
148 | 146 | def logout(self): |
|
149 |
session['rhodecode_user'] |
|
|
147 | del session['rhodecode_user'] | |
|
150 | 148 | session.save() |
|
151 | 149 | log.info('Logging out and setting user as Empty') |
|
152 | 150 | redirect(url('home')) |
@@ -42,19 +42,11 b' from rhodecode.lib.auth_ldap import Auth' | |||
|
42 | 42 | |
|
43 | 43 | from rhodecode.model import meta |
|
44 | 44 | from rhodecode.model.user import UserModel |
|
45 |
from rhodecode.model.db import |
|
|
46 | UserToPerm, UsersGroupToPerm, UsersGroupMember | |
|
45 | from rhodecode.model.db import Permission | |
|
47 | 46 | |
|
48 | 47 | |
|
49 | 48 | log = logging.getLogger(__name__) |
|
50 | 49 | |
|
51 | ||
|
52 | PERM_WEIGHTS = {'repository.none':0, | |
|
53 | 'repository.read':1, | |
|
54 | 'repository.write':3, | |
|
55 | 'repository.admin':3} | |
|
56 | ||
|
57 | ||
|
58 | 50 | class PasswordGenerator(object): |
|
59 | 51 | """This is a simple class for generating password from |
|
60 | 52 | different sets of characters |
@@ -185,21 +177,66 b' def authenticate(username, password):' | |||
|
185 | 177 | return False |
|
186 | 178 | |
|
187 | 179 | class AuthUser(object): |
|
188 | """A simple object that handles a mercurial username for authentication | |
|
180 | """ | |
|
181 | A simple object that handles all attributes of user in RhodeCode | |
|
182 | ||
|
183 | It does lookup based on API key,given user, or user present in session | |
|
184 | Then it fills all required information for such user. It also checks if | |
|
185 | anonymous access is enabled and if so, it returns default user as logged | |
|
186 | in | |
|
189 | 187 | """ |
|
190 | 188 | |
|
191 | def __init__(self): | |
|
189 | def __init__(self, user_id=None, api_key=None): | |
|
190 | ||
|
191 | self.user_id = user_id | |
|
192 | self.api_key = api_key | |
|
193 | ||
|
192 | 194 | self.username = 'None' |
|
193 | 195 | self.name = '' |
|
194 | 196 | self.lastname = '' |
|
195 | 197 | self.email = '' |
|
196 | self.user_id = None | |
|
197 | 198 | self.is_authenticated = False |
|
198 |
self. |
|
|
199 | self.admin = False | |
|
199 | 200 | self.permissions = {} |
|
201 | self.propagate_data() | |
|
202 | ||
|
203 | ||
|
204 | def propagate_data(self): | |
|
205 | user_model = UserModel() | |
|
206 | if self.api_key: | |
|
207 | #try go get user by api key | |
|
208 | log.debug('Auth User lookup by API KEY %s', self.api_key) | |
|
209 | user_model.fill_data(self, api_key=self.api_key) | |
|
210 | else: | |
|
211 | log.debug('Auth User lookup by USER ID %s', self.user_id) | |
|
212 | self.anonymous_user = user_model.get_by_username('default', cache=True) | |
|
213 | ||
|
214 | if self.user_id is not None and self.user_id != self.anonymous_user.user_id: | |
|
215 | user_model.fill_data(self, user_id=self.user_id) | |
|
216 | else: | |
|
217 | if self.anonymous_user.active is True: | |
|
218 | user_model.fill_data(self, user_id=self.anonymous_user.user_id) | |
|
219 | #then we set this user is logged in | |
|
220 | self.is_authenticated = True | |
|
221 | else: | |
|
222 | self.is_authenticated = False | |
|
223 | ||
|
224 | log.debug('Auth User is now %s', self) | |
|
225 | user_model.fill_perms(self) | |
|
226 | ||
|
227 | @property | |
|
228 | def is_admin(self): | |
|
229 | return self.admin | |
|
200 | 230 | |
|
201 | 231 | def __repr__(self): |
|
202 |
return "<AuthUser('id:%s:%s')>" % (self.user_id, self.username |
|
|
232 | return "<AuthUser('id:%s:%s|%s')>" % (self.user_id, self.username, | |
|
233 | self.is_authenticated) | |
|
234 | ||
|
235 | def set_authenticated(self, authenticated=True): | |
|
236 | ||
|
237 | if self.user_id != self.anonymous_user.user_id: | |
|
238 | self.is_authenticated = authenticated | |
|
239 | ||
|
203 | 240 | |
|
204 | 241 | def set_available_permissions(config): |
|
205 | 242 | """This function will propagate pylons globals with all available defined |
@@ -221,144 +258,42 b' def set_available_permissions(config):' | |||
|
221 | 258 | |
|
222 | 259 | config['available_permissions'] = [x.permission_name for x in all_perms] |
|
223 | 260 | |
|
224 | def fill_perms(user): | |
|
225 | """Fills user permission attribute with permissions taken from database | |
|
226 | works for permissions given for repositories, and for permissions that | |
|
227 | as part of beeing group member | |
|
228 | ||
|
229 | :param user: user instance to fill his perms | |
|
230 | """ | |
|
231 | ||
|
232 | sa = meta.Session() | |
|
233 | user.permissions['repositories'] = {} | |
|
234 | user.permissions['global'] = set() | |
|
235 | ||
|
236 | #=========================================================================== | |
|
237 | # fetch default permissions | |
|
238 | #=========================================================================== | |
|
239 | default_user = UserModel().get_by_username('default', cache=True) | |
|
240 | ||
|
241 | default_perms = sa.query(RepoToPerm, Repository, Permission)\ | |
|
242 | .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\ | |
|
243 | .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\ | |
|
244 | .filter(RepoToPerm.user == default_user).all() | |
|
245 | ||
|
246 | if user.is_admin: | |
|
247 | #======================================================================= | |
|
248 | # #admin have all default rights set to admin | |
|
249 | #======================================================================= | |
|
250 | user.permissions['global'].add('hg.admin') | |
|
251 | ||
|
252 | for perm in default_perms: | |
|
253 | p = 'repository.admin' | |
|
254 | user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p | |
|
255 | ||
|
256 | else: | |
|
257 | #======================================================================= | |
|
258 | # set default permissions | |
|
259 | #======================================================================= | |
|
260 | ||
|
261 | #default global | |
|
262 | default_global_perms = sa.query(UserToPerm)\ | |
|
263 | .filter(UserToPerm.user == sa.query(User)\ | |
|
264 | .filter(User.username == 'default').one()) | |
|
265 | ||
|
266 | for perm in default_global_perms: | |
|
267 | user.permissions['global'].add(perm.permission.permission_name) | |
|
268 | ||
|
269 | #default for repositories | |
|
270 | for perm in default_perms: | |
|
271 | if perm.Repository.private and not perm.Repository.user_id == user.user_id: | |
|
272 | #disable defaults for private repos, | |
|
273 | p = 'repository.none' | |
|
274 | elif perm.Repository.user_id == user.user_id: | |
|
275 | #set admin if owner | |
|
276 | p = 'repository.admin' | |
|
277 | else: | |
|
278 | p = perm.Permission.permission_name | |
|
279 | ||
|
280 | user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p | |
|
281 | ||
|
282 | #======================================================================= | |
|
283 | # overwrite default with user permissions if any | |
|
284 | #======================================================================= | |
|
285 | user_perms = sa.query(RepoToPerm, Permission, Repository)\ | |
|
286 | .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\ | |
|
287 | .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\ | |
|
288 | .filter(RepoToPerm.user_id == user.user_id).all() | |
|
289 | ||
|
290 | for perm in user_perms: | |
|
291 | if perm.Repository.user_id == user.user_id:#set admin if owner | |
|
292 | p = 'repository.admin' | |
|
293 | else: | |
|
294 | p = perm.Permission.permission_name | |
|
295 | user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p | |
|
296 | ||
|
297 | ||
|
298 | #======================================================================= | |
|
299 | # check if user is part of groups for this repository and fill in | |
|
300 | # (or replace with higher) permissions | |
|
301 | #======================================================================= | |
|
302 | user_perms_from_users_groups = sa.query(UsersGroupToPerm, Permission, Repository,)\ | |
|
303 | .join((Repository, UsersGroupToPerm.repository_id == Repository.repo_id))\ | |
|
304 | .join((Permission, UsersGroupToPerm.permission_id == Permission.permission_id))\ | |
|
305 | .join((UsersGroupMember, UsersGroupToPerm.users_group_id == UsersGroupMember.users_group_id))\ | |
|
306 | .filter(UsersGroupMember.user_id == user.user_id).all() | |
|
307 | ||
|
308 | for perm in user_perms_from_users_groups: | |
|
309 | p = perm.Permission.permission_name | |
|
310 | cur_perm = user.permissions['repositories'][perm.UsersGroupToPerm.repository.repo_name] | |
|
311 | #overwrite permission only if it's greater than permission given from other sources | |
|
312 | if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]: | |
|
313 | user.permissions['repositories'][perm.UsersGroupToPerm.repository.repo_name] = p | |
|
314 | ||
|
315 | meta.Session.remove() | |
|
316 | return user | |
|
317 | ||
|
318 | def get_user(session): | |
|
319 | """Gets user from session, and wraps permissions into user | |
|
320 | ||
|
321 | :param session: | |
|
322 | """ | |
|
323 | user = session.get('rhodecode_user', AuthUser()) | |
|
324 | #if the user is not logged in we check for anonymous access | |
|
325 | #if user is logged and it's a default user check if we still have anonymous | |
|
326 | #access enabled | |
|
327 | if user.user_id is None or user.username == 'default': | |
|
328 | anonymous_user = UserModel().get_by_username('default', cache=True) | |
|
329 | if anonymous_user.active is True: | |
|
330 | #then we set this user is logged in | |
|
331 | user.is_authenticated = True | |
|
332 | user.user_id = anonymous_user.user_id | |
|
333 | else: | |
|
334 | user.is_authenticated = False | |
|
335 | ||
|
336 | if user.is_authenticated: | |
|
337 | user = UserModel().fill_data(user) | |
|
338 | ||
|
339 | user = fill_perms(user) | |
|
340 | session['rhodecode_user'] = user | |
|
341 | session.save() | |
|
342 | return user | |
|
343 | ||
|
344 | 261 | #=============================================================================== |
|
345 | 262 | # CHECK DECORATORS |
|
346 | 263 | #=============================================================================== |
|
347 | 264 | class LoginRequired(object): |
|
348 | """Must be logged in to execute this function else | |
|
349 | redirect to login page""" | |
|
265 | """ | |
|
266 | Must be logged in to execute this function else | |
|
267 | redirect to login page | |
|
268 | ||
|
269 | :param api_access: if enabled this checks only for valid auth token | |
|
270 | and grants access based on valid token | |
|
271 | """ | |
|
272 | ||
|
273 | def __init__(self, api_access=False): | |
|
274 | self.api_access = api_access | |
|
350 | 275 | |
|
351 | 276 | def __call__(self, func): |
|
352 | 277 | return decorator(self.__wrapper, func) |
|
353 | 278 | |
|
354 | 279 | def __wrapper(self, func, *fargs, **fkwargs): |
|
355 | user = session.get('rhodecode_user', AuthUser()) | |
|
356 | log.debug('Checking login required for user:%s', user.username) | |
|
357 | if user.is_authenticated: | |
|
280 | cls = fargs[0] | |
|
281 | user = cls.rhodecode_user | |
|
282 | ||
|
283 | api_access_ok = False | |
|
284 | if self.api_access: | |
|
285 | log.debug('Checking API KEY access for %s', cls) | |
|
286 | if user.api_key == request.GET.get('api_key'): | |
|
287 | api_access_ok = True | |
|
288 | else: | |
|
289 | log.debug("API KEY token not valid") | |
|
290 | ||
|
291 | log.debug('Checking if %s is authenticated @ %s', user.username, cls) | |
|
292 | if user.is_authenticated or api_access_ok: | |
|
358 | 293 | log.debug('user %s is authenticated', user.username) |
|
359 | 294 | return func(*fargs, **fkwargs) |
|
360 | 295 | else: |
|
361 |
log.warn('user %s |
|
|
296 | log.warn('user %s NOT authenticated', user.username) | |
|
362 | 297 | |
|
363 | 298 | p = '' |
|
364 | 299 | if request.environ.get('SCRIPT_NAME') != '/': |
@@ -379,10 +314,12 b' class NotAnonymous(object):' | |||
|
379 | 314 | return decorator(self.__wrapper, func) |
|
380 | 315 | |
|
381 | 316 | def __wrapper(self, func, *fargs, **fkwargs): |
|
382 | user = session.get('rhodecode_user', AuthUser()) | |
|
383 | log.debug('Checking if user is not anonymous') | |
|
317 | cls = fargs[0] | |
|
318 | self.user = cls.rhodecode_user | |
|
384 | 319 | |
|
385 | anonymous = user.username == 'default' | |
|
320 | log.debug('Checking if user is not anonymous @%s', cls) | |
|
321 | ||
|
322 | anonymous = self.user.username == 'default' | |
|
386 | 323 | |
|
387 | 324 | if anonymous: |
|
388 | 325 | p = '' |
@@ -401,7 +338,7 b' class NotAnonymous(object):' | |||
|
401 | 338 | return func(*fargs, **fkwargs) |
|
402 | 339 | |
|
403 | 340 | class PermsDecorator(object): |
|
404 | """Base class for decorators""" | |
|
341 | """Base class for controller decorators""" | |
|
405 | 342 | |
|
406 | 343 | def __init__(self, *required_perms): |
|
407 | 344 | available_perms = config['available_permissions'] |
@@ -416,22 +353,19 b' class PermsDecorator(object):' | |||
|
416 | 353 | |
|
417 | 354 | |
|
418 | 355 | def __wrapper(self, func, *fargs, **fkwargs): |
|
419 | # _wrapper.__name__ = func.__name__ | |
|
420 | # _wrapper.__dict__.update(func.__dict__) | |
|
421 | # _wrapper.__doc__ = func.__doc__ | |
|
422 | self.user = session.get('rhodecode_user', AuthUser()) | |
|
356 | cls = fargs[0] | |
|
357 | self.user = cls.rhodecode_user | |
|
423 | 358 | self.user_perms = self.user.permissions |
|
424 | 359 | log.debug('checking %s permissions %s for %s %s', |
|
425 |
self.__class__.__name__, self.required_perms, |
|
|
360 | self.__class__.__name__, self.required_perms, cls, | |
|
426 | 361 | self.user) |
|
427 | 362 | |
|
428 | 363 | if self.check_permissions(): |
|
429 |
log.debug('Permission granted for %s %s', |
|
|
430 | ||
|
364 | log.debug('Permission granted for %s %s', cls, self.user) | |
|
431 | 365 | return func(*fargs, **fkwargs) |
|
432 | 366 | |
|
433 | 367 | else: |
|
434 |
log.warning('Permission denied for %s %s', |
|
|
368 | log.warning('Permission denied for %s %s', cls, self.user) | |
|
435 | 369 | #redirect with forbidden ret code |
|
436 | 370 | return abort(403) |
|
437 | 371 | |
@@ -516,18 +450,18 b' class PermsFunction(object):' | |||
|
516 | 450 | if not user: |
|
517 | 451 | return False |
|
518 | 452 | self.user_perms = user.permissions |
|
519 |
self.granted_for = user |
|
|
453 | self.granted_for = user | |
|
520 | 454 | log.debug('checking %s %s %s', self.__class__.__name__, |
|
521 | 455 | self.required_perms, user) |
|
522 | 456 | |
|
523 | 457 | if self.check_permissions(): |
|
524 |
log.debug('Permission granted |
|
|
525 |
check_Location |
|
|
458 | log.debug('Permission granted %s @ %s', self.granted_for, | |
|
459 | check_Location or 'unspecified location') | |
|
526 | 460 | return True |
|
527 | 461 | |
|
528 | 462 | else: |
|
529 |
log.warning('Permission denied for %s @ %s |
|
|
530 |
check_Location |
|
|
463 | log.warning('Permission denied for %s @ %s', self.granted_for, | |
|
464 | check_Location or 'unspecified location') | |
|
531 | 465 | return False |
|
532 | 466 | |
|
533 | 467 | def check_permissions(self): |
@@ -595,14 +529,9 b' class HasPermissionAnyMiddleware(object)' | |||
|
595 | 529 | self.required_perms = set(perms) |
|
596 | 530 | |
|
597 | 531 | def __call__(self, user, repo_name): |
|
598 | usr = AuthUser() | |
|
599 | usr.user_id = user.user_id | |
|
600 | usr.username = user.username | |
|
601 | usr.is_admin = user.admin | |
|
602 | ||
|
532 | usr = AuthUser(user.user_id) | |
|
603 | 533 | try: |
|
604 |
self.user_perms = set([ |
|
|
605 | .permissions['repositories'][repo_name]]) | |
|
534 | self.user_perms = set([usr.permissions['repositories'][repo_name]]) | |
|
606 | 535 | except: |
|
607 | 536 | self.user_perms = set() |
|
608 | 537 | self.granted_for = '' |
@@ -6,7 +6,7 b' from pylons import config, tmpl_context ' | |||
|
6 | 6 | from pylons.controllers import WSGIController |
|
7 | 7 | from pylons.templating import render_mako as render |
|
8 | 8 | from rhodecode import __version__ |
|
9 |
from rhodecode.lib import |
|
|
9 | from rhodecode.lib.auth import AuthUser | |
|
10 | 10 | from rhodecode.lib.utils import get_repo_slug |
|
11 | 11 | from rhodecode.model import meta |
|
12 | 12 | from rhodecode.model.scm import ScmModel |
@@ -34,7 +34,14 b' class BaseController(WSGIController):' | |||
|
34 | 34 | # available in environ['pylons.routes_dict'] |
|
35 | 35 | try: |
|
36 | 36 | #putting this here makes sure that we update permissions every time |
|
37 | self.rhodecode_user = c.rhodecode_user = auth.get_user(session) | |
|
37 | api_key = request.GET.get('api_key') | |
|
38 | user_id = getattr(session.get('rhodecode_user'), 'user_id', None) | |
|
39 | self.rhodecode_user = c.rhodecode_user = AuthUser(user_id, api_key) | |
|
40 | self.rhodecode_user.set_authenticated( | |
|
41 | getattr(session.get('rhodecode_user'), | |
|
42 | 'is_authenticated', False)) | |
|
43 | session['rhodecode_user'] = self.rhodecode_user | |
|
44 | session.save() | |
|
38 | 45 | return WSGIController.__call__(self, environ, start_response) |
|
39 | 46 | finally: |
|
40 | 47 | meta.Session.remove() |
@@ -32,8 +32,8 b' from pylons.i18n.translation import _' | |||
|
32 | 32 | |
|
33 | 33 | from rhodecode.model import BaseModel |
|
34 | 34 | from rhodecode.model.caching_query import FromCache |
|
35 | from rhodecode.model.db import User | |
|
36 | ||
|
35 | from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \ | |
|
36 | UserToPerm, UsersGroupToPerm, UsersGroupMember | |
|
37 | 37 | from rhodecode.lib.exceptions import DefaultUserException, UserOwnsReposException |
|
38 | 38 | |
|
39 | 39 | from sqlalchemy.exc import DatabaseError |
@@ -41,6 +41,11 b' from rhodecode.lib import generate_api_k' | |||
|
41 | 41 | |
|
42 | 42 | log = logging.getLogger(__name__) |
|
43 | 43 | |
|
44 | PERM_WEIGHTS = {'repository.none':0, | |
|
45 | 'repository.read':1, | |
|
46 | 'repository.write':3, | |
|
47 | 'repository.admin':3} | |
|
48 | ||
|
44 | 49 | class UserModel(BaseModel): |
|
45 | 50 | |
|
46 | 51 | def get(self, user_id, cache=False): |
@@ -63,6 +68,16 b' class UserModel(BaseModel):' | |||
|
63 | 68 | "get_user_%s" % username)) |
|
64 | 69 | return user.scalar() |
|
65 | 70 | |
|
71 | ||
|
72 | def get_by_api_key(self, api_key, cache=False): | |
|
73 | ||
|
74 | user = self.sa.query(User)\ | |
|
75 | .filter(User.api_key == api_key) | |
|
76 | if cache: | |
|
77 | user = user.options(FromCache("sql_cache_short", | |
|
78 | "get_user_%s" % api_key)) | |
|
79 | return user.scalar() | |
|
80 | ||
|
66 | 81 | def create(self, form_data): |
|
67 | 82 | try: |
|
68 | 83 | new_user = User() |
@@ -204,27 +219,125 b' class UserModel(BaseModel):' | |||
|
204 | 219 | run_task(tasks.reset_user_password, data['email']) |
|
205 | 220 | |
|
206 | 221 | |
|
207 | def fill_data(self, user): | |
|
222 | def fill_data(self, auth_user, user_id=None, api_key=None): | |
|
208 | 223 | """ |
|
209 | Fills user data with those from database and log out user if not | |
|
224 | Fetches auth_user by user_id,or api_key if present. | |
|
225 | Fills auth_user attributes with those taken from database. | |
|
226 | Additionally set's is_authenitated if lookup fails | |
|
210 | 227 | present in database |
|
211 | :param user: | |
|
228 | ||
|
229 | :param auth_user: instance of user to set attributes | |
|
230 | :param user_id: user id to fetch by | |
|
231 | :param api_key: api key to fetch by | |
|
212 | 232 | """ |
|
233 | if not user_id and not not api_key: | |
|
234 | raise Exception('You need to pass user_id or api_key') | |
|
213 | 235 | |
|
214 | if not hasattr(user, 'user_id') or user.user_id is None: | |
|
215 | raise Exception('passed in user has to have the user_id attribute') | |
|
236 | try: | |
|
237 | if api_key: | |
|
238 | dbuser = self.get_by_api_key(api_key) | |
|
239 | else: | |
|
240 | dbuser = self.get(user_id) | |
|
241 | ||
|
242 | log.debug('filling %s data', dbuser) | |
|
243 | for k, v in dbuser.get_dict().items(): | |
|
244 | setattr(auth_user, k, v) | |
|
245 | ||
|
246 | except: | |
|
247 | log.error(traceback.format_exc()) | |
|
248 | auth_user.is_authenticated = False | |
|
249 | ||
|
250 | return auth_user | |
|
216 | 251 | |
|
217 | 252 | |
|
218 | log.debug('filling auth user data') | |
|
219 | try: | |
|
220 | dbuser = self.get(user.user_id) | |
|
221 | user.username = dbuser.username | |
|
222 | user.is_admin = dbuser.admin | |
|
223 | user.name = dbuser.name | |
|
224 | user.lastname = dbuser.lastname | |
|
225 | user.email = dbuser.email | |
|
226 | except: | |
|
227 | log.error(traceback.format_exc()) | |
|
228 | user.is_authenticated = False | |
|
253 | def fill_perms(self, user): | |
|
254 | """Fills user permission attribute with permissions taken from database | |
|
255 | works for permissions given for repositories, and for permissions that | |
|
256 | as part of beeing group member | |
|
257 | ||
|
258 | :param user: user instance to fill his perms | |
|
259 | """ | |
|
260 | ||
|
261 | user.permissions['repositories'] = {} | |
|
262 | user.permissions['global'] = set() | |
|
263 | ||
|
264 | #=========================================================================== | |
|
265 | # fetch default permissions | |
|
266 | #=========================================================================== | |
|
267 | default_user = self.get_by_username('default', cache=True) | |
|
268 | ||
|
269 | default_perms = self.sa.query(RepoToPerm, Repository, Permission)\ | |
|
270 | .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\ | |
|
271 | .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\ | |
|
272 | .filter(RepoToPerm.user == default_user).all() | |
|
273 | ||
|
274 | if user.is_admin: | |
|
275 | #======================================================================= | |
|
276 | # #admin have all default rights set to admin | |
|
277 | #======================================================================= | |
|
278 | user.permissions['global'].add('hg.admin') | |
|
279 | ||
|
280 | for perm in default_perms: | |
|
281 | p = 'repository.admin' | |
|
282 | user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p | |
|
283 | ||
|
284 | else: | |
|
285 | #======================================================================= | |
|
286 | # set default permissions | |
|
287 | #======================================================================= | |
|
288 | ||
|
289 | #default global | |
|
290 | default_global_perms = self.sa.query(UserToPerm)\ | |
|
291 | .filter(UserToPerm.user == self.sa.query(User)\ | |
|
292 | .filter(User.username == 'default').one()) | |
|
293 | ||
|
294 | for perm in default_global_perms: | |
|
295 | user.permissions['global'].add(perm.permission.permission_name) | |
|
296 | ||
|
297 | #default for repositories | |
|
298 | for perm in default_perms: | |
|
299 | if perm.Repository.private and not perm.Repository.user_id == user.user_id: | |
|
300 | #diself.sable defaults for private repos, | |
|
301 | p = 'repository.none' | |
|
302 | elif perm.Repository.user_id == user.user_id: | |
|
303 | #set admin if owner | |
|
304 | p = 'repository.admin' | |
|
305 | else: | |
|
306 | p = perm.Permission.permission_name | |
|
307 | ||
|
308 | user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p | |
|
309 | ||
|
310 | #======================================================================= | |
|
311 | # overwrite default with user permissions if any | |
|
312 | #======================================================================= | |
|
313 | user_perms = self.sa.query(RepoToPerm, Permission, Repository)\ | |
|
314 | .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\ | |
|
315 | .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\ | |
|
316 | .filter(RepoToPerm.user_id == user.user_id).all() | |
|
317 | ||
|
318 | for perm in user_perms: | |
|
319 | if perm.Repository.user_id == user.user_id:#set admin if owner | |
|
320 | p = 'repository.admin' | |
|
321 | else: | |
|
322 | p = perm.Permission.permission_name | |
|
323 | user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p | |
|
324 | ||
|
325 | ||
|
326 | #======================================================================= | |
|
327 | # check if user is part of groups for this repository and fill in | |
|
328 | # (or replace with higher) permissions | |
|
329 | #======================================================================= | |
|
330 | user_perms_from_users_groups = self.sa.query(UsersGroupToPerm, Permission, Repository,)\ | |
|
331 | .join((Repository, UsersGroupToPerm.repository_id == Repository.repo_id))\ | |
|
332 | .join((Permission, UsersGroupToPerm.permission_id == Permission.permission_id))\ | |
|
333 | .join((UsersGroupMember, UsersGroupToPerm.users_group_id == UsersGroupMember.users_group_id))\ | |
|
334 | .filter(UsersGroupMember.user_id == user.user_id).all() | |
|
335 | ||
|
336 | for perm in user_perms_from_users_groups: | |
|
337 | p = perm.Permission.permission_name | |
|
338 | cur_perm = user.permissions['repositories'][perm.UsersGroupToPerm.repository.repo_name] | |
|
339 | #overwrite permission only if it's greater than permission given from other sources | |
|
340 | if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]: | |
|
341 | user.permissions['repositories'][perm.UsersGroupToPerm.repository.repo_name] = p | |
|
229 | 342 | |
|
230 | 343 | return user |
General Comments 0
You need to be logged in to leave comments.
Login now