Show More
@@ -36,8 +36,7 b' from pylons.i18n.translation import _' | |||||
36 |
|
36 | |||
37 | from rhodecode.lib.exceptions import DefaultUserException, UserOwnsReposException |
|
37 | from rhodecode.lib.exceptions import DefaultUserException, UserOwnsReposException | |
38 | from rhodecode.lib import helpers as h |
|
38 | from rhodecode.lib import helpers as h | |
39 |
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator |
|
39 | from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator | |
40 | fill_perms |
|
|||
41 | from rhodecode.lib.base import BaseController, render |
|
40 | from rhodecode.lib.base import BaseController, render | |
42 |
|
41 | |||
43 | from rhodecode.model.db import User |
|
42 | from rhodecode.model.db import User | |
@@ -157,14 +156,15 b' class UsersController(BaseController):' | |||||
157 | def edit(self, id, format='html'): |
|
156 | def edit(self, id, format='html'): | |
158 | """GET /users/id/edit: Form to edit an existing item""" |
|
157 | """GET /users/id/edit: Form to edit an existing item""" | |
159 | # url('edit_user', id=ID) |
|
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 | if not c.user: |
|
161 | if not c.user: | |
162 | return redirect(url('users')) |
|
162 | return redirect(url('users')) | |
163 | if c.user.username == 'default': |
|
163 | if c.user.username == 'default': | |
164 | h.flash(_("You can't edit this user"), category='warning') |
|
164 | h.flash(_("You can't edit this user"), category='warning') | |
165 | return redirect(url('users')) |
|
165 | return redirect(url('users')) | |
166 | c.user.permissions = {} |
|
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 | defaults = c.user.get_dict() |
|
169 | defaults = c.user.get_dict() | |
170 |
|
170 |
@@ -36,8 +36,7 b' from pylons.i18n.translation import _' | |||||
36 |
|
36 | |||
37 | from rhodecode.lib.exceptions import DefaultUserException, UserOwnsReposException |
|
37 | from rhodecode.lib.exceptions import DefaultUserException, UserOwnsReposException | |
38 | from rhodecode.lib import helpers as h |
|
38 | from rhodecode.lib import helpers as h | |
39 |
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator |
|
39 | from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator | |
40 | fill_perms |
|
|||
41 | from rhodecode.lib.base import BaseController, render |
|
40 | from rhodecode.lib.base import BaseController, render | |
42 |
|
41 | |||
43 | from rhodecode.model.db import User, UsersGroup |
|
42 | from rhodecode.model.db import User, UsersGroup |
@@ -49,6 +49,7 b' class JournalController(BaseController):' | |||||
49 | @LoginRequired() |
|
49 | @LoginRequired() | |
50 | def __before__(self): |
|
50 | def __before__(self): | |
51 | super(JournalController, self).__before__() |
|
51 | super(JournalController, self).__before__() | |
|
52 | c.rhodecode_user = self.rhodecode_user | |||
52 | self.title = _('%s public journal %s feed') % (c.rhodecode_name, '%s') |
|
53 | self.title = _('%s public journal %s feed') % (c.rhodecode_name, '%s') | |
53 | self.language = 'en-us' |
|
54 | self.language = 'en-us' | |
54 | self.ttl = "5" |
|
55 | self.ttl = "5" | |
@@ -60,7 +61,7 b' class JournalController(BaseController):' | |||||
60 | p = int(request.params.get('page', 1)) |
|
61 | p = int(request.params.get('page', 1)) | |
61 |
|
62 | |||
62 | c.following = self.sa.query(UserFollowing)\ |
|
63 | c.following = self.sa.query(UserFollowing)\ | |
63 |
.filter(UserFollowing.user_id == |
|
64 | .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\ | |
64 | .options(joinedload(UserFollowing.follows_repository))\ |
|
65 | .options(joinedload(UserFollowing.follows_repository))\ | |
65 | .all() |
|
66 | .all() | |
66 |
|
67 | |||
@@ -126,7 +127,7 b' class JournalController(BaseController):' | |||||
126 | if user_id: |
|
127 | if user_id: | |
127 | try: |
|
128 | try: | |
128 | self.scm_model.toggle_following_user(user_id, |
|
129 | self.scm_model.toggle_following_user(user_id, | |
129 |
|
|
130 | self.rhodecode_user.user_id) | |
130 | return 'ok' |
|
131 | return 'ok' | |
131 | except: |
|
132 | except: | |
132 | raise HTTPInternalServerError() |
|
133 | raise HTTPInternalServerError() | |
@@ -135,7 +136,7 b' class JournalController(BaseController):' | |||||
135 | if repo_id: |
|
136 | if repo_id: | |
136 | try: |
|
137 | try: | |
137 | self.scm_model.toggle_following_repo(repo_id, |
|
138 | self.scm_model.toggle_following_repo(repo_id, | |
138 |
|
|
139 | self.rhodecode_user.user_id) | |
139 | return 'ok' |
|
140 | return 'ok' | |
140 | except: |
|
141 | except: | |
141 | raise HTTPInternalServerError() |
|
142 | raise HTTPInternalServerError() | |
@@ -152,7 +153,7 b' class JournalController(BaseController):' | |||||
152 | p = int(request.params.get('page', 1)) |
|
153 | p = int(request.params.get('page', 1)) | |
153 |
|
154 | |||
154 | c.following = self.sa.query(UserFollowing)\ |
|
155 | c.following = self.sa.query(UserFollowing)\ | |
155 |
.filter(UserFollowing.user_id == |
|
156 | .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\ | |
156 | .options(joinedload(UserFollowing.follows_repository))\ |
|
157 | .options(joinedload(UserFollowing.follows_repository))\ | |
157 | .all() |
|
158 | .all() | |
158 |
|
159 | |||
@@ -174,7 +175,7 b' class JournalController(BaseController):' | |||||
174 | Produce an atom-1.0 feed via feedgenerator module |
|
175 | Produce an atom-1.0 feed via feedgenerator module | |
175 | """ |
|
176 | """ | |
176 | c.following = self.sa.query(UserFollowing)\ |
|
177 | c.following = self.sa.query(UserFollowing)\ | |
177 |
.filter(UserFollowing.user_id == |
|
178 | .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\ | |
178 | .options(joinedload(UserFollowing.follows_repository))\ |
|
179 | .options(joinedload(UserFollowing.follows_repository))\ | |
179 | .all() |
|
180 | .all() | |
180 |
|
181 | |||
@@ -207,7 +208,7 b' class JournalController(BaseController):' | |||||
207 | Produce an rss2 feed via feedgenerator module |
|
208 | Produce an rss2 feed via feedgenerator module | |
208 | """ |
|
209 | """ | |
209 | c.following = self.sa.query(UserFollowing)\ |
|
210 | c.following = self.sa.query(UserFollowing)\ | |
210 |
.filter(UserFollowing.user_id == |
|
211 | .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\ | |
211 | .options(joinedload(UserFollowing.follows_repository))\ |
|
212 | .options(joinedload(UserFollowing.follows_repository))\ | |
212 | .all() |
|
213 | .all() | |
213 |
|
214 |
@@ -62,19 +62,17 b' class LoginController(BaseController):' | |||||
62 | login_form = LoginForm() |
|
62 | login_form = LoginForm() | |
63 | try: |
|
63 | try: | |
64 | c.form_result = login_form.to_python(dict(request.POST)) |
|
64 | c.form_result = login_form.to_python(dict(request.POST)) | |
|
65 | #form checks for username/password, now we're authenticated | |||
65 | username = c.form_result['username'] |
|
66 | username = c.form_result['username'] | |
66 |
user = UserModel().get_by_username(username, |
|
67 | user = UserModel().get_by_username(username, | |
67 | auth_user = AuthUser() |
|
68 | case_insensitive=True) | |
68 |
auth_user |
|
69 | auth_user = AuthUser(user.user_id) | |
69 |
auth_user. |
|
70 | auth_user.set_authenticated() | |
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 |
|
|||
74 | session['rhodecode_user'] = auth_user |
|
71 | session['rhodecode_user'] = auth_user | |
75 | session.save() |
|
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 | user.update_lastlogin() |
|
76 | user.update_lastlogin() | |
79 |
|
77 | |||
80 | if c.came_from: |
|
78 | if c.came_from: | |
@@ -146,7 +144,7 b' class LoginController(BaseController):' | |||||
146 | return render('/password_reset.html') |
|
144 | return render('/password_reset.html') | |
147 |
|
145 | |||
148 | def logout(self): |
|
146 | def logout(self): | |
149 |
session['rhodecode_user'] |
|
147 | del session['rhodecode_user'] | |
150 | session.save() |
|
148 | session.save() | |
151 | log.info('Logging out and setting user as Empty') |
|
149 | log.info('Logging out and setting user as Empty') | |
152 | redirect(url('home')) |
|
150 | redirect(url('home')) |
@@ -42,19 +42,11 b' from rhodecode.lib.auth_ldap import Auth' | |||||
42 |
|
42 | |||
43 | from rhodecode.model import meta |
|
43 | from rhodecode.model import meta | |
44 | from rhodecode.model.user import UserModel |
|
44 | from rhodecode.model.user import UserModel | |
45 |
from rhodecode.model.db import |
|
45 | from rhodecode.model.db import Permission | |
46 | UserToPerm, UsersGroupToPerm, UsersGroupMember |
|
|||
47 |
|
46 | |||
48 |
|
47 | |||
49 | log = logging.getLogger(__name__) |
|
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 | class PasswordGenerator(object): |
|
50 | class PasswordGenerator(object): | |
59 | """This is a simple class for generating password from |
|
51 | """This is a simple class for generating password from | |
60 | different sets of characters |
|
52 | different sets of characters | |
@@ -185,21 +177,66 b' def authenticate(username, password):' | |||||
185 | return False |
|
177 | return False | |
186 |
|
178 | |||
187 | class AuthUser(object): |
|
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 | self.username = 'None' |
|
194 | self.username = 'None' | |
193 | self.name = '' |
|
195 | self.name = '' | |
194 | self.lastname = '' |
|
196 | self.lastname = '' | |
195 | self.email = '' |
|
197 | self.email = '' | |
196 | self.user_id = None |
|
|||
197 | self.is_authenticated = False |
|
198 | self.is_authenticated = False | |
198 |
self. |
|
199 | self.admin = False | |
199 | self.permissions = {} |
|
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 | def __repr__(self): |
|
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 | def set_available_permissions(config): |
|
241 | def set_available_permissions(config): | |
205 | """This function will propagate pylons globals with all available defined |
|
242 | """This function will propagate pylons globals with all available defined | |
@@ -221,144 +258,42 b' def set_available_permissions(config):' | |||||
221 |
|
258 | |||
222 | config['available_permissions'] = [x.permission_name for x in all_perms] |
|
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 | # CHECK DECORATORS |
|
262 | # CHECK DECORATORS | |
346 | #=============================================================================== |
|
263 | #=============================================================================== | |
347 | class LoginRequired(object): |
|
264 | class LoginRequired(object): | |
348 | """Must be logged in to execute this function else |
|
265 | """ | |
349 | redirect to login page""" |
|
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 | def __call__(self, func): |
|
276 | def __call__(self, func): | |
352 | return decorator(self.__wrapper, func) |
|
277 | return decorator(self.__wrapper, func) | |
353 |
|
278 | |||
354 | def __wrapper(self, func, *fargs, **fkwargs): |
|
279 | def __wrapper(self, func, *fargs, **fkwargs): | |
355 | user = session.get('rhodecode_user', AuthUser()) |
|
280 | cls = fargs[0] | |
356 | log.debug('Checking login required for user:%s', user.username) |
|
281 | user = cls.rhodecode_user | |
357 | if user.is_authenticated: |
|
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 | log.debug('user %s is authenticated', user.username) |
|
293 | log.debug('user %s is authenticated', user.username) | |
359 | return func(*fargs, **fkwargs) |
|
294 | return func(*fargs, **fkwargs) | |
360 | else: |
|
295 | else: | |
361 |
log.warn('user %s |
|
296 | log.warn('user %s NOT authenticated', user.username) | |
362 |
|
297 | |||
363 | p = '' |
|
298 | p = '' | |
364 | if request.environ.get('SCRIPT_NAME') != '/': |
|
299 | if request.environ.get('SCRIPT_NAME') != '/': | |
@@ -379,10 +314,12 b' class NotAnonymous(object):' | |||||
379 | return decorator(self.__wrapper, func) |
|
314 | return decorator(self.__wrapper, func) | |
380 |
|
315 | |||
381 | def __wrapper(self, func, *fargs, **fkwargs): |
|
316 | def __wrapper(self, func, *fargs, **fkwargs): | |
382 | user = session.get('rhodecode_user', AuthUser()) |
|
317 | cls = fargs[0] | |
383 | log.debug('Checking if user is not anonymous') |
|
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 | if anonymous: |
|
324 | if anonymous: | |
388 | p = '' |
|
325 | p = '' | |
@@ -401,7 +338,7 b' class NotAnonymous(object):' | |||||
401 | return func(*fargs, **fkwargs) |
|
338 | return func(*fargs, **fkwargs) | |
402 |
|
339 | |||
403 | class PermsDecorator(object): |
|
340 | class PermsDecorator(object): | |
404 | """Base class for decorators""" |
|
341 | """Base class for controller decorators""" | |
405 |
|
342 | |||
406 | def __init__(self, *required_perms): |
|
343 | def __init__(self, *required_perms): | |
407 | available_perms = config['available_permissions'] |
|
344 | available_perms = config['available_permissions'] | |
@@ -416,22 +353,19 b' class PermsDecorator(object):' | |||||
416 |
|
353 | |||
417 |
|
354 | |||
418 | def __wrapper(self, func, *fargs, **fkwargs): |
|
355 | def __wrapper(self, func, *fargs, **fkwargs): | |
419 | # _wrapper.__name__ = func.__name__ |
|
356 | cls = fargs[0] | |
420 | # _wrapper.__dict__.update(func.__dict__) |
|
357 | self.user = cls.rhodecode_user | |
421 | # _wrapper.__doc__ = func.__doc__ |
|
|||
422 | self.user = session.get('rhodecode_user', AuthUser()) |
|
|||
423 | self.user_perms = self.user.permissions |
|
358 | self.user_perms = self.user.permissions | |
424 | log.debug('checking %s permissions %s for %s %s', |
|
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 | self.user) |
|
361 | self.user) | |
427 |
|
362 | |||
428 | if self.check_permissions(): |
|
363 | if self.check_permissions(): | |
429 |
log.debug('Permission granted for %s %s', |
|
364 | log.debug('Permission granted for %s %s', cls, self.user) | |
430 |
|
||||
431 | return func(*fargs, **fkwargs) |
|
365 | return func(*fargs, **fkwargs) | |
432 |
|
366 | |||
433 | else: |
|
367 | else: | |
434 |
log.warning('Permission denied for %s %s', |
|
368 | log.warning('Permission denied for %s %s', cls, self.user) | |
435 | #redirect with forbidden ret code |
|
369 | #redirect with forbidden ret code | |
436 | return abort(403) |
|
370 | return abort(403) | |
437 |
|
371 | |||
@@ -516,18 +450,18 b' class PermsFunction(object):' | |||||
516 | if not user: |
|
450 | if not user: | |
517 | return False |
|
451 | return False | |
518 | self.user_perms = user.permissions |
|
452 | self.user_perms = user.permissions | |
519 |
self.granted_for = user |
|
453 | self.granted_for = user | |
520 | log.debug('checking %s %s %s', self.__class__.__name__, |
|
454 | log.debug('checking %s %s %s', self.__class__.__name__, | |
521 | self.required_perms, user) |
|
455 | self.required_perms, user) | |
522 |
|
456 | |||
523 | if self.check_permissions(): |
|
457 | if self.check_permissions(): | |
524 |
log.debug('Permission granted |
|
458 | log.debug('Permission granted %s @ %s', self.granted_for, | |
525 |
check_Location |
|
459 | check_Location or 'unspecified location') | |
526 | return True |
|
460 | return True | |
527 |
|
461 | |||
528 | else: |
|
462 | else: | |
529 |
log.warning('Permission denied for %s @ %s |
|
463 | log.warning('Permission denied for %s @ %s', self.granted_for, | |
530 |
check_Location |
|
464 | check_Location or 'unspecified location') | |
531 | return False |
|
465 | return False | |
532 |
|
466 | |||
533 | def check_permissions(self): |
|
467 | def check_permissions(self): | |
@@ -595,14 +529,9 b' class HasPermissionAnyMiddleware(object)' | |||||
595 | self.required_perms = set(perms) |
|
529 | self.required_perms = set(perms) | |
596 |
|
530 | |||
597 | def __call__(self, user, repo_name): |
|
531 | def __call__(self, user, repo_name): | |
598 | usr = AuthUser() |
|
532 | usr = AuthUser(user.user_id) | |
599 | usr.user_id = user.user_id |
|
|||
600 | usr.username = user.username |
|
|||
601 | usr.is_admin = user.admin |
|
|||
602 |
|
||||
603 | try: |
|
533 | try: | |
604 |
self.user_perms = set([ |
|
534 | self.user_perms = set([usr.permissions['repositories'][repo_name]]) | |
605 | .permissions['repositories'][repo_name]]) |
|
|||
606 | except: |
|
535 | except: | |
607 | self.user_perms = set() |
|
536 | self.user_perms = set() | |
608 | self.granted_for = '' |
|
537 | self.granted_for = '' |
@@ -6,7 +6,7 b' from pylons import config, tmpl_context ' | |||||
6 | from pylons.controllers import WSGIController |
|
6 | from pylons.controllers import WSGIController | |
7 | from pylons.templating import render_mako as render |
|
7 | from pylons.templating import render_mako as render | |
8 | from rhodecode import __version__ |
|
8 | from rhodecode import __version__ | |
9 |
from rhodecode.lib import |
|
9 | from rhodecode.lib.auth import AuthUser | |
10 | from rhodecode.lib.utils import get_repo_slug |
|
10 | from rhodecode.lib.utils import get_repo_slug | |
11 | from rhodecode.model import meta |
|
11 | from rhodecode.model import meta | |
12 | from rhodecode.model.scm import ScmModel |
|
12 | from rhodecode.model.scm import ScmModel | |
@@ -34,7 +34,14 b' class BaseController(WSGIController):' | |||||
34 | # available in environ['pylons.routes_dict'] |
|
34 | # available in environ['pylons.routes_dict'] | |
35 | try: |
|
35 | try: | |
36 | #putting this here makes sure that we update permissions every time |
|
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 | return WSGIController.__call__(self, environ, start_response) |
|
45 | return WSGIController.__call__(self, environ, start_response) | |
39 | finally: |
|
46 | finally: | |
40 | meta.Session.remove() |
|
47 | meta.Session.remove() |
@@ -32,8 +32,8 b' from pylons.i18n.translation import _' | |||||
32 |
|
32 | |||
33 | from rhodecode.model import BaseModel |
|
33 | from rhodecode.model import BaseModel | |
34 | from rhodecode.model.caching_query import FromCache |
|
34 | from rhodecode.model.caching_query import FromCache | |
35 | from rhodecode.model.db import User |
|
35 | from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \ | |
36 |
|
36 | UserToPerm, UsersGroupToPerm, UsersGroupMember | ||
37 | from rhodecode.lib.exceptions import DefaultUserException, UserOwnsReposException |
|
37 | from rhodecode.lib.exceptions import DefaultUserException, UserOwnsReposException | |
38 |
|
38 | |||
39 | from sqlalchemy.exc import DatabaseError |
|
39 | from sqlalchemy.exc import DatabaseError | |
@@ -41,6 +41,11 b' from rhodecode.lib import generate_api_k' | |||||
41 |
|
41 | |||
42 | log = logging.getLogger(__name__) |
|
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 | class UserModel(BaseModel): |
|
49 | class UserModel(BaseModel): | |
45 |
|
50 | |||
46 | def get(self, user_id, cache=False): |
|
51 | def get(self, user_id, cache=False): | |
@@ -63,6 +68,16 b' class UserModel(BaseModel):' | |||||
63 | "get_user_%s" % username)) |
|
68 | "get_user_%s" % username)) | |
64 | return user.scalar() |
|
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 | def create(self, form_data): |
|
81 | def create(self, form_data): | |
67 | try: |
|
82 | try: | |
68 | new_user = User() |
|
83 | new_user = User() | |
@@ -204,27 +219,125 b' class UserModel(BaseModel):' | |||||
204 | run_task(tasks.reset_user_password, data['email']) |
|
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 | present in database |
|
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: |
|
236 | try: | |
215 | raise Exception('passed in user has to have the user_id attribute') |
|
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') |
|
253 | def fill_perms(self, user): | |
219 | try: |
|
254 | """Fills user permission attribute with permissions taken from database | |
220 | dbuser = self.get(user.user_id) |
|
255 | works for permissions given for repositories, and for permissions that | |
221 | user.username = dbuser.username |
|
256 | as part of beeing group member | |
222 | user.is_admin = dbuser.admin |
|
257 | ||
223 | user.name = dbuser.name |
|
258 | :param user: user instance to fill his perms | |
224 | user.lastname = dbuser.lastname |
|
259 | """ | |
225 | user.email = dbuser.email |
|
260 | ||
226 | except: |
|
261 | user.permissions['repositories'] = {} | |
227 | log.error(traceback.format_exc()) |
|
262 | user.permissions['global'] = set() | |
228 | user.is_authenticated = False |
|
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 | return user |
|
343 | return user |
General Comments 0
You need to be logged in to leave comments.
Login now