##// END OF EJS Templates
auth: always consider the repo group owner an admin when computing it's permissions...
Mads Kiilerich -
r8770:e27ff6a9 stable
parent child Browse files
Show More
@@ -1,723 +1,726 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 kallithea.lib.auth
15 kallithea.lib.auth
16 ~~~~~~~~~~~~~~~~~~
16 ~~~~~~~~~~~~~~~~~~
17
17
18 authentication and permission libraries
18 authentication and permission libraries
19
19
20 This file was forked by the Kallithea project in July 2014.
20 This file was forked by the Kallithea project in July 2014.
21 Original author and date, and relevant copyright and licensing information is below:
21 Original author and date, and relevant copyright and licensing information is below:
22 :created_on: Apr 4, 2010
22 :created_on: Apr 4, 2010
23 :author: marcink
23 :author: marcink
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 :license: GPLv3, see LICENSE.md for more details.
25 :license: GPLv3, see LICENSE.md for more details.
26 """
26 """
27 import itertools
27 import itertools
28 import logging
28 import logging
29
29
30 import ipaddr
30 import ipaddr
31 from decorator import decorator
31 from decorator import decorator
32 from sqlalchemy.orm import joinedload
32 from sqlalchemy.orm import joinedload
33 from sqlalchemy.orm.exc import ObjectDeletedError
33 from sqlalchemy.orm.exc import ObjectDeletedError
34 from tg import request
34 from tg import request
35 from tg.i18n import ugettext as _
35 from tg.i18n import ugettext as _
36 from webob.exc import HTTPForbidden, HTTPFound
36 from webob.exc import HTTPForbidden, HTTPFound
37
37
38 import kallithea
38 import kallithea
39 from kallithea.lib import webutils
39 from kallithea.lib import webutils
40 from kallithea.lib.utils import get_repo_group_slug, get_repo_slug, get_user_group_slug
40 from kallithea.lib.utils import get_repo_group_slug, get_repo_slug, get_user_group_slug
41 from kallithea.lib.vcs.utils.lazy import LazyProperty
41 from kallithea.lib.vcs.utils.lazy import LazyProperty
42 from kallithea.lib.webutils import url
42 from kallithea.lib.webutils import url
43 from kallithea.model import db, meta
43 from kallithea.model import db, meta
44 from kallithea.model.user import UserModel
44 from kallithea.model.user import UserModel
45
45
46
46
47 log = logging.getLogger(__name__)
47 log = logging.getLogger(__name__)
48
48
49
49
50 PERM_WEIGHTS = db.Permission.PERM_WEIGHTS
50 PERM_WEIGHTS = db.Permission.PERM_WEIGHTS
51
51
52 def bump_permission(permissions, key, new_perm):
52 def bump_permission(permissions, key, new_perm):
53 """Add a new permission for key to permissions.
53 """Add a new permission for key to permissions.
54 Assuming the permissions are comparable, set the new permission if it
54 Assuming the permissions are comparable, set the new permission if it
55 has higher weight, else drop it and keep the old permission.
55 has higher weight, else drop it and keep the old permission.
56 """
56 """
57 cur_perm = permissions[key]
57 cur_perm = permissions[key]
58 new_perm_val = PERM_WEIGHTS[new_perm]
58 new_perm_val = PERM_WEIGHTS[new_perm]
59 cur_perm_val = PERM_WEIGHTS[cur_perm]
59 cur_perm_val = PERM_WEIGHTS[cur_perm]
60 if new_perm_val > cur_perm_val:
60 if new_perm_val > cur_perm_val:
61 permissions[key] = new_perm
61 permissions[key] = new_perm
62
62
63 class AuthUser(object):
63 class AuthUser(object):
64 """
64 """
65 Represents a Kallithea user, including various authentication and
65 Represents a Kallithea user, including various authentication and
66 authorization information. Typically used to store the current user,
66 authorization information. Typically used to store the current user,
67 but is also used as a generic user information data structure in
67 but is also used as a generic user information data structure in
68 parts of the code, e.g. user management.
68 parts of the code, e.g. user management.
69
69
70 Constructed from a database `User` object, a user ID or cookie dict,
70 Constructed from a database `User` object, a user ID or cookie dict,
71 it looks up the user (if needed) and copies all attributes to itself,
71 it looks up the user (if needed) and copies all attributes to itself,
72 adding various non-persistent data. If lookup fails but anonymous
72 adding various non-persistent data. If lookup fails but anonymous
73 access to Kallithea is enabled, the default user is loaded instead.
73 access to Kallithea is enabled, the default user is loaded instead.
74
74
75 `AuthUser` does not by itself authenticate users. It's up to other parts of
75 `AuthUser` does not by itself authenticate users. It's up to other parts of
76 the code to check e.g. if a supplied password is correct, and if so, trust
76 the code to check e.g. if a supplied password is correct, and if so, trust
77 the AuthUser object as an authenticated user.
77 the AuthUser object as an authenticated user.
78
78
79 However, `AuthUser` does refuse to load a user that is not `active`.
79 However, `AuthUser` does refuse to load a user that is not `active`.
80
80
81 Note that Kallithea distinguishes between the default user (an actual
81 Note that Kallithea distinguishes between the default user (an actual
82 user in the database with username "default") and "no user" (no actual
82 user in the database with username "default") and "no user" (no actual
83 User object, AuthUser filled with blank values and username "None").
83 User object, AuthUser filled with blank values and username "None").
84
84
85 If the default user is active, that will always be used instead of
85 If the default user is active, that will always be used instead of
86 "no user". On the other hand, if the default user is disabled (and
86 "no user". On the other hand, if the default user is disabled (and
87 there is no login information), we instead get "no user"; this should
87 there is no login information), we instead get "no user"; this should
88 only happen on the login page (as all other requests are redirected).
88 only happen on the login page (as all other requests are redirected).
89
89
90 `is_default_user` specifically checks if the AuthUser is the user named
90 `is_default_user` specifically checks if the AuthUser is the user named
91 "default". Use `is_anonymous` to check for both "default" and "no user".
91 "default". Use `is_anonymous` to check for both "default" and "no user".
92 """
92 """
93
93
94 @classmethod
94 @classmethod
95 def make(cls, dbuser=None, is_external_auth=False, ip_addr=None):
95 def make(cls, dbuser=None, is_external_auth=False, ip_addr=None):
96 """Create an AuthUser to be authenticated ... or return None if user for some reason can't be authenticated.
96 """Create an AuthUser to be authenticated ... or return None if user for some reason can't be authenticated.
97 Checks that a non-None dbuser is provided, is active, and that the IP address is ok.
97 Checks that a non-None dbuser is provided, is active, and that the IP address is ok.
98 """
98 """
99 assert ip_addr is not None
99 assert ip_addr is not None
100 if dbuser is None:
100 if dbuser is None:
101 log.info('No db user for authentication')
101 log.info('No db user for authentication')
102 return None
102 return None
103 if not dbuser.active:
103 if not dbuser.active:
104 log.info('Db user %s not active', dbuser.username)
104 log.info('Db user %s not active', dbuser.username)
105 return None
105 return None
106 allowed_ips = AuthUser.get_allowed_ips(dbuser.user_id)
106 allowed_ips = AuthUser.get_allowed_ips(dbuser.user_id)
107 if not check_ip_access(source_ip=ip_addr, allowed_ips=allowed_ips):
107 if not check_ip_access(source_ip=ip_addr, allowed_ips=allowed_ips):
108 log.info('Access for %s from %s forbidden - not in %s', dbuser.username, ip_addr, allowed_ips)
108 log.info('Access for %s from %s forbidden - not in %s', dbuser.username, ip_addr, allowed_ips)
109 return None
109 return None
110 return cls(dbuser=dbuser, is_external_auth=is_external_auth)
110 return cls(dbuser=dbuser, is_external_auth=is_external_auth)
111
111
112 def __init__(self, user_id=None, dbuser=None, is_external_auth=False):
112 def __init__(self, user_id=None, dbuser=None, is_external_auth=False):
113 self.is_external_auth = is_external_auth # container auth - don't show logout option
113 self.is_external_auth = is_external_auth # container auth - don't show logout option
114
114
115 # These attributes will be overridden below if the requested user is
115 # These attributes will be overridden below if the requested user is
116 # found or anonymous access (using the default user) is enabled.
116 # found or anonymous access (using the default user) is enabled.
117 self.user_id = None
117 self.user_id = None
118 self.username = None
118 self.username = None
119 self.api_key = None
119 self.api_key = None
120 self.name = ''
120 self.name = ''
121 self.lastname = ''
121 self.lastname = ''
122 self.email = ''
122 self.email = ''
123 self.admin = False
123 self.admin = False
124
124
125 # Look up database user, if necessary.
125 # Look up database user, if necessary.
126 if user_id is not None:
126 if user_id is not None:
127 assert dbuser is None
127 assert dbuser is None
128 log.debug('Auth User lookup by USER ID %s', user_id)
128 log.debug('Auth User lookup by USER ID %s', user_id)
129 dbuser = UserModel().get(user_id)
129 dbuser = UserModel().get(user_id)
130 assert dbuser is not None
130 assert dbuser is not None
131 else:
131 else:
132 assert dbuser is not None
132 assert dbuser is not None
133 log.debug('Auth User lookup by database user %s', dbuser)
133 log.debug('Auth User lookup by database user %s', dbuser)
134
134
135 log.debug('filling %s data', dbuser)
135 log.debug('filling %s data', dbuser)
136 self.is_anonymous = dbuser.is_default_user
136 self.is_anonymous = dbuser.is_default_user
137 if dbuser.is_default_user and not dbuser.active:
137 if dbuser.is_default_user and not dbuser.active:
138 self.username = 'None'
138 self.username = 'None'
139 self.is_default_user = False
139 self.is_default_user = False
140 else:
140 else:
141 # copy non-confidential database fields from a `db.User` to this `AuthUser`.
141 # copy non-confidential database fields from a `db.User` to this `AuthUser`.
142 for k, v in dbuser.get_dict().items():
142 for k, v in dbuser.get_dict().items():
143 assert k not in ['api_keys', 'permissions']
143 assert k not in ['api_keys', 'permissions']
144 setattr(self, k, v)
144 setattr(self, k, v)
145 self.is_default_user = dbuser.is_default_user
145 self.is_default_user = dbuser.is_default_user
146 log.debug('Auth User is now %s', self)
146 log.debug('Auth User is now %s', self)
147
147
148 @LazyProperty
148 @LazyProperty
149 def global_permissions(self):
149 def global_permissions(self):
150 log.debug('Getting global permissions for %s', self)
150 log.debug('Getting global permissions for %s', self)
151
151
152 if self.is_admin:
152 if self.is_admin:
153 return set(['hg.admin'])
153 return set(['hg.admin'])
154
154
155 global_permissions = set()
155 global_permissions = set()
156
156
157 # default global permissions from the default user
157 # default global permissions from the default user
158 default_global_perms = db.UserToPerm.query() \
158 default_global_perms = db.UserToPerm.query() \
159 .filter(db.UserToPerm.user_id == kallithea.DEFAULT_USER_ID) \
159 .filter(db.UserToPerm.user_id == kallithea.DEFAULT_USER_ID) \
160 .options(joinedload(db.UserToPerm.permission))
160 .options(joinedload(db.UserToPerm.permission))
161 for perm in default_global_perms:
161 for perm in default_global_perms:
162 global_permissions.add(perm.permission.permission_name)
162 global_permissions.add(perm.permission.permission_name)
163
163
164 # user group global permissions
164 # user group global permissions
165 user_perms_from_users_groups = meta.Session().query(db.UserGroupToPerm) \
165 user_perms_from_users_groups = meta.Session().query(db.UserGroupToPerm) \
166 .options(joinedload(db.UserGroupToPerm.permission)) \
166 .options(joinedload(db.UserGroupToPerm.permission)) \
167 .join((db.UserGroupMember, db.UserGroupToPerm.users_group_id ==
167 .join((db.UserGroupMember, db.UserGroupToPerm.users_group_id ==
168 db.UserGroupMember.users_group_id)) \
168 db.UserGroupMember.users_group_id)) \
169 .filter(db.UserGroupMember.user_id == self.user_id) \
169 .filter(db.UserGroupMember.user_id == self.user_id) \
170 .join((db.UserGroup, db.UserGroupMember.users_group_id ==
170 .join((db.UserGroup, db.UserGroupMember.users_group_id ==
171 db.UserGroup.users_group_id)) \
171 db.UserGroup.users_group_id)) \
172 .filter(db.UserGroup.users_group_active == True) \
172 .filter(db.UserGroup.users_group_active == True) \
173 .order_by(db.UserGroupToPerm.users_group_id) \
173 .order_by(db.UserGroupToPerm.users_group_id) \
174 .all()
174 .all()
175 # need to group here by groups since user can be in more than
175 # need to group here by groups since user can be in more than
176 # one group
176 # one group
177 _grouped = [[x, list(y)] for x, y in
177 _grouped = [[x, list(y)] for x, y in
178 itertools.groupby(user_perms_from_users_groups,
178 itertools.groupby(user_perms_from_users_groups,
179 lambda x:x.users_group)]
179 lambda x:x.users_group)]
180 for gr, perms in _grouped:
180 for gr, perms in _grouped:
181 for perm in perms:
181 for perm in perms:
182 global_permissions.add(perm.permission.permission_name)
182 global_permissions.add(perm.permission.permission_name)
183
183
184 # user specific global permissions
184 # user specific global permissions
185 user_perms = meta.Session().query(db.UserToPerm) \
185 user_perms = meta.Session().query(db.UserToPerm) \
186 .options(joinedload(db.UserToPerm.permission)) \
186 .options(joinedload(db.UserToPerm.permission)) \
187 .filter(db.UserToPerm.user_id == self.user_id).all()
187 .filter(db.UserToPerm.user_id == self.user_id).all()
188 for perm in user_perms:
188 for perm in user_perms:
189 global_permissions.add(perm.permission.permission_name)
189 global_permissions.add(perm.permission.permission_name)
190
190
191 # for each kind of global permissions, only keep the one with heighest weight
191 # for each kind of global permissions, only keep the one with heighest weight
192 kind_max_perm = {}
192 kind_max_perm = {}
193 for perm in sorted(global_permissions, key=lambda n: PERM_WEIGHTS.get(n, -1)):
193 for perm in sorted(global_permissions, key=lambda n: PERM_WEIGHTS.get(n, -1)):
194 kind = perm.rsplit('.', 1)[0]
194 kind = perm.rsplit('.', 1)[0]
195 kind_max_perm[kind] = perm
195 kind_max_perm[kind] = perm
196 return set(kind_max_perm.values())
196 return set(kind_max_perm.values())
197
197
198 @LazyProperty
198 @LazyProperty
199 def repository_permissions(self):
199 def repository_permissions(self):
200 log.debug('Getting repository permissions for %s', self)
200 log.debug('Getting repository permissions for %s', self)
201 repository_permissions = {}
201 repository_permissions = {}
202 default_repo_perms = db.Permission.get_default_perms(kallithea.DEFAULT_USER_ID)
202 default_repo_perms = db.Permission.get_default_perms(kallithea.DEFAULT_USER_ID)
203
203
204 if self.is_admin:
204 if self.is_admin:
205 for perm in default_repo_perms:
205 for perm in default_repo_perms:
206 r_k = perm.repository.repo_name
206 r_k = perm.repository.repo_name
207 p = 'repository.admin'
207 p = 'repository.admin'
208 repository_permissions[r_k] = p
208 repository_permissions[r_k] = p
209
209
210 else:
210 else:
211 # defaults for repositories from default user
211 # defaults for repositories from default user
212 for perm in default_repo_perms:
212 for perm in default_repo_perms:
213 r_k = perm.repository.repo_name
213 r_k = perm.repository.repo_name
214 if perm.repository.owner_id == self.user_id:
214 if perm.repository.owner_id == self.user_id:
215 p = 'repository.admin'
215 p = 'repository.admin'
216 elif perm.repository.private:
216 elif perm.repository.private:
217 p = 'repository.none'
217 p = 'repository.none'
218 else:
218 else:
219 p = perm.permission.permission_name
219 p = perm.permission.permission_name
220 repository_permissions[r_k] = p
220 repository_permissions[r_k] = p
221
221
222 # user group repository permissions
222 # user group repository permissions
223 user_repo_perms_from_users_groups = \
223 user_repo_perms_from_users_groups = \
224 meta.Session().query(db.UserGroupRepoToPerm) \
224 meta.Session().query(db.UserGroupRepoToPerm) \
225 .join((db.UserGroup, db.UserGroupRepoToPerm.users_group_id ==
225 .join((db.UserGroup, db.UserGroupRepoToPerm.users_group_id ==
226 db.UserGroup.users_group_id)) \
226 db.UserGroup.users_group_id)) \
227 .filter(db.UserGroup.users_group_active == True) \
227 .filter(db.UserGroup.users_group_active == True) \
228 .join((db.UserGroupMember, db.UserGroupRepoToPerm.users_group_id ==
228 .join((db.UserGroupMember, db.UserGroupRepoToPerm.users_group_id ==
229 db.UserGroupMember.users_group_id)) \
229 db.UserGroupMember.users_group_id)) \
230 .filter(db.UserGroupMember.user_id == self.user_id) \
230 .filter(db.UserGroupMember.user_id == self.user_id) \
231 .options(joinedload(db.UserGroupRepoToPerm.repository)) \
231 .options(joinedload(db.UserGroupRepoToPerm.repository)) \
232 .options(joinedload(db.UserGroupRepoToPerm.permission)) \
232 .options(joinedload(db.UserGroupRepoToPerm.permission)) \
233 .all()
233 .all()
234 for perm in user_repo_perms_from_users_groups:
234 for perm in user_repo_perms_from_users_groups:
235 bump_permission(repository_permissions,
235 bump_permission(repository_permissions,
236 perm.repository.repo_name,
236 perm.repository.repo_name,
237 perm.permission.permission_name)
237 perm.permission.permission_name)
238
238
239 # user permissions for repositories
239 # user permissions for repositories
240 user_repo_perms = db.Permission.get_default_perms(self.user_id)
240 user_repo_perms = db.Permission.get_default_perms(self.user_id)
241 for perm in user_repo_perms:
241 for perm in user_repo_perms:
242 bump_permission(repository_permissions,
242 bump_permission(repository_permissions,
243 perm.repository.repo_name,
243 perm.repository.repo_name,
244 perm.permission.permission_name)
244 perm.permission.permission_name)
245
245
246 return repository_permissions
246 return repository_permissions
247
247
248 @LazyProperty
248 @LazyProperty
249 def repository_group_permissions(self):
249 def repository_group_permissions(self):
250 log.debug('Getting repository group permissions for %s', self)
250 log.debug('Getting repository group permissions for %s', self)
251 repository_group_permissions = {}
251 repository_group_permissions = {}
252 default_repo_groups_perms = db.Permission.get_default_group_perms(kallithea.DEFAULT_USER_ID)
252 default_repo_groups_perms = db.Permission.get_default_group_perms(kallithea.DEFAULT_USER_ID)
253
253
254 if self.is_admin:
254 if self.is_admin:
255 for perm in default_repo_groups_perms:
255 for perm in default_repo_groups_perms:
256 rg_k = perm.group.group_name
256 rg_k = perm.group.group_name
257 p = 'group.admin'
257 p = 'group.admin'
258 repository_group_permissions[rg_k] = p
258 repository_group_permissions[rg_k] = p
259
259
260 else:
260 else:
261 # defaults for repository groups taken from default user permission
261 # defaults for repository groups taken from default user permission
262 # on given group
262 # on given group
263 for perm in default_repo_groups_perms:
263 for perm in default_repo_groups_perms:
264 rg_k = perm.group.group_name
264 rg_k = perm.group.group_name
265 p = perm.permission.permission_name
265 if perm.group.owner_id == self.user_id:
266 p = 'group.admin'
267 else:
268 p = perm.permission.permission_name
266 repository_group_permissions[rg_k] = p
269 repository_group_permissions[rg_k] = p
267
270
268 # user group for repo groups permissions
271 # user group for repo groups permissions
269 user_repo_group_perms_from_users_groups = \
272 user_repo_group_perms_from_users_groups = \
270 meta.Session().query(db.UserGroupRepoGroupToPerm) \
273 meta.Session().query(db.UserGroupRepoGroupToPerm) \
271 .join((db.UserGroup, db.UserGroupRepoGroupToPerm.users_group_id ==
274 .join((db.UserGroup, db.UserGroupRepoGroupToPerm.users_group_id ==
272 db.UserGroup.users_group_id)) \
275 db.UserGroup.users_group_id)) \
273 .filter(db.UserGroup.users_group_active == True) \
276 .filter(db.UserGroup.users_group_active == True) \
274 .join((db.UserGroupMember, db.UserGroupRepoGroupToPerm.users_group_id
277 .join((db.UserGroupMember, db.UserGroupRepoGroupToPerm.users_group_id
275 == db.UserGroupMember.users_group_id)) \
278 == db.UserGroupMember.users_group_id)) \
276 .filter(db.UserGroupMember.user_id == self.user_id) \
279 .filter(db.UserGroupMember.user_id == self.user_id) \
277 .options(joinedload(db.UserGroupRepoGroupToPerm.permission)) \
280 .options(joinedload(db.UserGroupRepoGroupToPerm.permission)) \
278 .all()
281 .all()
279 for perm in user_repo_group_perms_from_users_groups:
282 for perm in user_repo_group_perms_from_users_groups:
280 bump_permission(repository_group_permissions,
283 bump_permission(repository_group_permissions,
281 perm.group.group_name,
284 perm.group.group_name,
282 perm.permission.permission_name)
285 perm.permission.permission_name)
283
286
284 # user explicit permissions for repository groups
287 # user explicit permissions for repository groups
285 user_repo_groups_perms = db.Permission.get_default_group_perms(self.user_id)
288 user_repo_groups_perms = db.Permission.get_default_group_perms(self.user_id)
286 for perm in user_repo_groups_perms:
289 for perm in user_repo_groups_perms:
287 bump_permission(repository_group_permissions,
290 bump_permission(repository_group_permissions,
288 perm.group.group_name,
291 perm.group.group_name,
289 perm.permission.permission_name)
292 perm.permission.permission_name)
290
293
291 return repository_group_permissions
294 return repository_group_permissions
292
295
293 @LazyProperty
296 @LazyProperty
294 def user_group_permissions(self):
297 def user_group_permissions(self):
295 log.debug('Getting user group permissions for %s', self)
298 log.debug('Getting user group permissions for %s', self)
296 user_group_permissions = {}
299 user_group_permissions = {}
297 default_user_group_perms = db.Permission.get_default_user_group_perms(kallithea.DEFAULT_USER_ID)
300 default_user_group_perms = db.Permission.get_default_user_group_perms(kallithea.DEFAULT_USER_ID)
298
301
299 if self.is_admin:
302 if self.is_admin:
300 for perm in default_user_group_perms:
303 for perm in default_user_group_perms:
301 u_k = perm.user_group.users_group_name
304 u_k = perm.user_group.users_group_name
302 p = 'usergroup.admin'
305 p = 'usergroup.admin'
303 user_group_permissions[u_k] = p
306 user_group_permissions[u_k] = p
304
307
305 else:
308 else:
306 # defaults for user groups taken from default user permission
309 # defaults for user groups taken from default user permission
307 # on given user group
310 # on given user group
308 for perm in default_user_group_perms:
311 for perm in default_user_group_perms:
309 u_k = perm.user_group.users_group_name
312 u_k = perm.user_group.users_group_name
310 p = perm.permission.permission_name
313 p = perm.permission.permission_name
311 user_group_permissions[u_k] = p
314 user_group_permissions[u_k] = p
312
315
313 # user group for user group permissions
316 # user group for user group permissions
314 user_group_user_groups_perms = \
317 user_group_user_groups_perms = \
315 meta.Session().query(db.UserGroupUserGroupToPerm) \
318 meta.Session().query(db.UserGroupUserGroupToPerm) \
316 .join((db.UserGroup, db.UserGroupUserGroupToPerm.target_user_group_id
319 .join((db.UserGroup, db.UserGroupUserGroupToPerm.target_user_group_id
317 == db.UserGroup.users_group_id)) \
320 == db.UserGroup.users_group_id)) \
318 .join((db.UserGroupMember, db.UserGroupUserGroupToPerm.user_group_id
321 .join((db.UserGroupMember, db.UserGroupUserGroupToPerm.user_group_id
319 == db.UserGroupMember.users_group_id)) \
322 == db.UserGroupMember.users_group_id)) \
320 .filter(db.UserGroupMember.user_id == self.user_id) \
323 .filter(db.UserGroupMember.user_id == self.user_id) \
321 .join((db.UserGroup, db.UserGroupMember.users_group_id ==
324 .join((db.UserGroup, db.UserGroupMember.users_group_id ==
322 db.UserGroup.users_group_id), aliased=True, from_joinpoint=True) \
325 db.UserGroup.users_group_id), aliased=True, from_joinpoint=True) \
323 .filter(db.UserGroup.users_group_active == True) \
326 .filter(db.UserGroup.users_group_active == True) \
324 .options(joinedload(db.UserGroupUserGroupToPerm.permission)) \
327 .options(joinedload(db.UserGroupUserGroupToPerm.permission)) \
325 .all()
328 .all()
326 for perm in user_group_user_groups_perms:
329 for perm in user_group_user_groups_perms:
327 bump_permission(user_group_permissions,
330 bump_permission(user_group_permissions,
328 perm.target_user_group.users_group_name,
331 perm.target_user_group.users_group_name,
329 perm.permission.permission_name)
332 perm.permission.permission_name)
330
333
331 # user explicit permission for user groups
334 # user explicit permission for user groups
332 user_user_groups_perms = db.Permission.get_default_user_group_perms(self.user_id)
335 user_user_groups_perms = db.Permission.get_default_user_group_perms(self.user_id)
333 for perm in user_user_groups_perms:
336 for perm in user_user_groups_perms:
334 bump_permission(user_group_permissions,
337 bump_permission(user_group_permissions,
335 perm.user_group.users_group_name,
338 perm.user_group.users_group_name,
336 perm.permission.permission_name)
339 perm.permission.permission_name)
337
340
338 return user_group_permissions
341 return user_group_permissions
339
342
340 @LazyProperty
343 @LazyProperty
341 def permissions(self):
344 def permissions(self):
342 """dict with all 4 kind of permissions - mainly for backwards compatibility"""
345 """dict with all 4 kind of permissions - mainly for backwards compatibility"""
343 return {
346 return {
344 'global': self.global_permissions,
347 'global': self.global_permissions,
345 'repositories': self.repository_permissions,
348 'repositories': self.repository_permissions,
346 'repositories_groups': self.repository_group_permissions,
349 'repositories_groups': self.repository_group_permissions,
347 'user_groups': self.user_group_permissions,
350 'user_groups': self.user_group_permissions,
348 }
351 }
349
352
350 def has_repository_permission_level(self, repo_name, level, purpose=None):
353 def has_repository_permission_level(self, repo_name, level, purpose=None):
351 required_perms = {
354 required_perms = {
352 'read': ['repository.read', 'repository.write', 'repository.admin'],
355 'read': ['repository.read', 'repository.write', 'repository.admin'],
353 'write': ['repository.write', 'repository.admin'],
356 'write': ['repository.write', 'repository.admin'],
354 'admin': ['repository.admin'],
357 'admin': ['repository.admin'],
355 }[level]
358 }[level]
356 actual_perm = self.repository_permissions.get(repo_name)
359 actual_perm = self.repository_permissions.get(repo_name)
357 ok = actual_perm in required_perms
360 ok = actual_perm in required_perms
358 log.debug('Checking if user %r can %r repo %r (%s): %s (has %r)',
361 log.debug('Checking if user %r can %r repo %r (%s): %s (has %r)',
359 self.username, level, repo_name, purpose, ok, actual_perm)
362 self.username, level, repo_name, purpose, ok, actual_perm)
360 return ok
363 return ok
361
364
362 def has_repository_group_permission_level(self, repo_group_name, level, purpose=None):
365 def has_repository_group_permission_level(self, repo_group_name, level, purpose=None):
363 required_perms = {
366 required_perms = {
364 'read': ['group.read', 'group.write', 'group.admin'],
367 'read': ['group.read', 'group.write', 'group.admin'],
365 'write': ['group.write', 'group.admin'],
368 'write': ['group.write', 'group.admin'],
366 'admin': ['group.admin'],
369 'admin': ['group.admin'],
367 }[level]
370 }[level]
368 actual_perm = self.repository_group_permissions.get(repo_group_name)
371 actual_perm = self.repository_group_permissions.get(repo_group_name)
369 ok = actual_perm in required_perms
372 ok = actual_perm in required_perms
370 log.debug('Checking if user %r can %r repo group %r (%s): %s (has %r)',
373 log.debug('Checking if user %r can %r repo group %r (%s): %s (has %r)',
371 self.username, level, repo_group_name, purpose, ok, actual_perm)
374 self.username, level, repo_group_name, purpose, ok, actual_perm)
372 return ok
375 return ok
373
376
374 def has_user_group_permission_level(self, user_group_name, level, purpose=None):
377 def has_user_group_permission_level(self, user_group_name, level, purpose=None):
375 required_perms = {
378 required_perms = {
376 'read': ['usergroup.read', 'usergroup.write', 'usergroup.admin'],
379 'read': ['usergroup.read', 'usergroup.write', 'usergroup.admin'],
377 'write': ['usergroup.write', 'usergroup.admin'],
380 'write': ['usergroup.write', 'usergroup.admin'],
378 'admin': ['usergroup.admin'],
381 'admin': ['usergroup.admin'],
379 }[level]
382 }[level]
380 actual_perm = self.user_group_permissions.get(user_group_name)
383 actual_perm = self.user_group_permissions.get(user_group_name)
381 ok = actual_perm in required_perms
384 ok = actual_perm in required_perms
382 log.debug('Checking if user %r can %r user group %r (%s): %s (has %r)',
385 log.debug('Checking if user %r can %r user group %r (%s): %s (has %r)',
383 self.username, level, user_group_name, purpose, ok, actual_perm)
386 self.username, level, user_group_name, purpose, ok, actual_perm)
384 return ok
387 return ok
385
388
386 @property
389 @property
387 def api_keys(self):
390 def api_keys(self):
388 return self._get_api_keys()
391 return self._get_api_keys()
389
392
390 def _get_api_keys(self):
393 def _get_api_keys(self):
391 api_keys = [self.api_key]
394 api_keys = [self.api_key]
392 for api_key in db.UserApiKeys.query() \
395 for api_key in db.UserApiKeys.query() \
393 .filter_by(user_id=self.user_id, is_expired=False):
396 .filter_by(user_id=self.user_id, is_expired=False):
394 api_keys.append(api_key.api_key)
397 api_keys.append(api_key.api_key)
395
398
396 return api_keys
399 return api_keys
397
400
398 @property
401 @property
399 def is_admin(self):
402 def is_admin(self):
400 return self.admin
403 return self.admin
401
404
402 @property
405 @property
403 def repositories_admin(self):
406 def repositories_admin(self):
404 """
407 """
405 Returns list of repositories you're an admin of
408 Returns list of repositories you're an admin of
406 """
409 """
407 return [x[0] for x in self.repository_permissions.items()
410 return [x[0] for x in self.repository_permissions.items()
408 if x[1] == 'repository.admin']
411 if x[1] == 'repository.admin']
409
412
410 @property
413 @property
411 def repository_groups_admin(self):
414 def repository_groups_admin(self):
412 """
415 """
413 Returns list of repository groups you're an admin of
416 Returns list of repository groups you're an admin of
414 """
417 """
415 return [x[0] for x in self.repository_group_permissions.items()
418 return [x[0] for x in self.repository_group_permissions.items()
416 if x[1] == 'group.admin']
419 if x[1] == 'group.admin']
417
420
418 @property
421 @property
419 def user_groups_admin(self):
422 def user_groups_admin(self):
420 """
423 """
421 Returns list of user groups you're an admin of
424 Returns list of user groups you're an admin of
422 """
425 """
423 return [x[0] for x in self.user_group_permissions.items()
426 return [x[0] for x in self.user_group_permissions.items()
424 if x[1] == 'usergroup.admin']
427 if x[1] == 'usergroup.admin']
425
428
426 def __repr__(self):
429 def __repr__(self):
427 return "<%s %s: %r>" % (self.__class__.__name__, self.user_id, self.username)
430 return "<%s %s: %r>" % (self.__class__.__name__, self.user_id, self.username)
428
431
429 def to_cookie(self):
432 def to_cookie(self):
430 """ Serializes this login session to a cookie `dict`. """
433 """ Serializes this login session to a cookie `dict`. """
431 return {
434 return {
432 'user_id': self.user_id,
435 'user_id': self.user_id,
433 'is_external_auth': self.is_external_auth,
436 'is_external_auth': self.is_external_auth,
434 }
437 }
435
438
436 @staticmethod
439 @staticmethod
437 def from_cookie(cookie, ip_addr):
440 def from_cookie(cookie, ip_addr):
438 """
441 """
439 Deserializes an `AuthUser` from a cookie `dict` ... or return None.
442 Deserializes an `AuthUser` from a cookie `dict` ... or return None.
440 """
443 """
441 return AuthUser.make(
444 return AuthUser.make(
442 dbuser=UserModel().get(cookie.get('user_id')),
445 dbuser=UserModel().get(cookie.get('user_id')),
443 is_external_auth=cookie.get('is_external_auth', False),
446 is_external_auth=cookie.get('is_external_auth', False),
444 ip_addr=ip_addr,
447 ip_addr=ip_addr,
445 )
448 )
446
449
447 @classmethod
450 @classmethod
448 def get_allowed_ips(cls, user_id):
451 def get_allowed_ips(cls, user_id):
449 _set = set()
452 _set = set()
450
453
451 default_ips = db.UserIpMap.query().filter(db.UserIpMap.user_id == kallithea.DEFAULT_USER_ID)
454 default_ips = db.UserIpMap.query().filter(db.UserIpMap.user_id == kallithea.DEFAULT_USER_ID)
452 for ip in default_ips:
455 for ip in default_ips:
453 try:
456 try:
454 _set.add(ip.ip_addr)
457 _set.add(ip.ip_addr)
455 except ObjectDeletedError:
458 except ObjectDeletedError:
456 # since we use heavy caching sometimes it happens that we get
459 # since we use heavy caching sometimes it happens that we get
457 # deleted objects here, we just skip them
460 # deleted objects here, we just skip them
458 pass
461 pass
459
462
460 user_ips = db.UserIpMap.query().filter(db.UserIpMap.user_id == user_id)
463 user_ips = db.UserIpMap.query().filter(db.UserIpMap.user_id == user_id)
461 for ip in user_ips:
464 for ip in user_ips:
462 try:
465 try:
463 _set.add(ip.ip_addr)
466 _set.add(ip.ip_addr)
464 except ObjectDeletedError:
467 except ObjectDeletedError:
465 # since we use heavy caching sometimes it happens that we get
468 # since we use heavy caching sometimes it happens that we get
466 # deleted objects here, we just skip them
469 # deleted objects here, we just skip them
467 pass
470 pass
468 return _set or set(['0.0.0.0/0', '::/0'])
471 return _set or set(['0.0.0.0/0', '::/0'])
469
472
470 def get_all_user_repos(self):
473 def get_all_user_repos(self):
471 """
474 """
472 Gets all repositories that user have at least read access
475 Gets all repositories that user have at least read access
473 """
476 """
474 repos = [repo_name
477 repos = [repo_name
475 for repo_name, perm in self.repository_permissions.items()
478 for repo_name, perm in self.repository_permissions.items()
476 if perm in ['repository.read', 'repository.write', 'repository.admin']
479 if perm in ['repository.read', 'repository.write', 'repository.admin']
477 ]
480 ]
478 return db.Repository.query().filter(db.Repository.repo_name.in_(repos))
481 return db.Repository.query().filter(db.Repository.repo_name.in_(repos))
479
482
480
483
481 #==============================================================================
484 #==============================================================================
482 # CHECK DECORATORS
485 # CHECK DECORATORS
483 #==============================================================================
486 #==============================================================================
484
487
485 def _redirect_to_login(message=None):
488 def _redirect_to_login(message=None):
486 """Return an exception that must be raised. It will redirect to the login
489 """Return an exception that must be raised. It will redirect to the login
487 page which will redirect back to the current URL after authentication.
490 page which will redirect back to the current URL after authentication.
488 The optional message will be shown in a flash message."""
491 The optional message will be shown in a flash message."""
489 if message:
492 if message:
490 webutils.flash(message, category='warning')
493 webutils.flash(message, category='warning')
491 p = request.path_qs
494 p = request.path_qs
492 log.debug('Redirecting to login page, origin: %s', p)
495 log.debug('Redirecting to login page, origin: %s', p)
493 return HTTPFound(location=url('login_home', came_from=p))
496 return HTTPFound(location=url('login_home', came_from=p))
494
497
495
498
496 # Use as decorator
499 # Use as decorator
497 class LoginRequired(object):
500 class LoginRequired(object):
498 """Client must be logged in as a valid User, or we'll redirect to the login
501 """Client must be logged in as a valid User, or we'll redirect to the login
499 page.
502 page.
500
503
501 If the "default" user is enabled and allow_default_user is true, that is
504 If the "default" user is enabled and allow_default_user is true, that is
502 considered valid too.
505 considered valid too.
503
506
504 Also checks that IP address is allowed.
507 Also checks that IP address is allowed.
505 """
508 """
506
509
507 def __init__(self, allow_default_user=False):
510 def __init__(self, allow_default_user=False):
508 self.allow_default_user = allow_default_user
511 self.allow_default_user = allow_default_user
509
512
510 def __call__(self, func):
513 def __call__(self, func):
511 return decorator(self.__wrapper, func)
514 return decorator(self.__wrapper, func)
512
515
513 def __wrapper(self, func, *fargs, **fkwargs):
516 def __wrapper(self, func, *fargs, **fkwargs):
514 controller = fargs[0]
517 controller = fargs[0]
515 user = request.authuser
518 user = request.authuser
516 loc = "%s:%s" % (controller.__class__.__name__, func.__name__)
519 loc = "%s:%s" % (controller.__class__.__name__, func.__name__)
517 log.debug('Checking access for user %s @ %s', user, loc)
520 log.debug('Checking access for user %s @ %s', user, loc)
518
521
519 # regular user authentication
522 # regular user authentication
520 if user.is_default_user:
523 if user.is_default_user:
521 if self.allow_default_user:
524 if self.allow_default_user:
522 log.info('default user @ %s', loc)
525 log.info('default user @ %s', loc)
523 return func(*fargs, **fkwargs)
526 return func(*fargs, **fkwargs)
524 log.info('default user is redirected to login @ %s', loc)
527 log.info('default user is redirected to login @ %s', loc)
525 elif user.is_anonymous: # default user is disabled and no proper authentication
528 elif user.is_anonymous: # default user is disabled and no proper authentication
526 log.info('anonymous user is redirected to login @ %s', loc)
529 log.info('anonymous user is redirected to login @ %s', loc)
527 else: # regular authentication
530 else: # regular authentication
528 log.info('user %s authenticated with regular auth @ %s', user, loc)
531 log.info('user %s authenticated with regular auth @ %s', user, loc)
529 return func(*fargs, **fkwargs)
532 return func(*fargs, **fkwargs)
530 raise _redirect_to_login()
533 raise _redirect_to_login()
531
534
532
535
533 # Use as decorator
536 # Use as decorator
534 class NotAnonymous(object):
537 class NotAnonymous(object):
535 """Ensures that client is not logged in as the "default" user, and
538 """Ensures that client is not logged in as the "default" user, and
536 redirects to the login page otherwise. Must be used together with
539 redirects to the login page otherwise. Must be used together with
537 LoginRequired."""
540 LoginRequired."""
538
541
539 def __call__(self, func):
542 def __call__(self, func):
540 return decorator(self.__wrapper, func)
543 return decorator(self.__wrapper, func)
541
544
542 def __wrapper(self, func, *fargs, **fkwargs):
545 def __wrapper(self, func, *fargs, **fkwargs):
543 cls = fargs[0]
546 cls = fargs[0]
544 user = request.authuser
547 user = request.authuser
545
548
546 log.debug('Checking that user %s is not anonymous @%s', user.username, cls)
549 log.debug('Checking that user %s is not anonymous @%s', user.username, cls)
547
550
548 if user.is_default_user:
551 if user.is_default_user:
549 raise _redirect_to_login(_('You need to be a registered user to '
552 raise _redirect_to_login(_('You need to be a registered user to '
550 'perform this action'))
553 'perform this action'))
551 else:
554 else:
552 return func(*fargs, **fkwargs)
555 return func(*fargs, **fkwargs)
553
556
554
557
555 class _PermsDecorator(object):
558 class _PermsDecorator(object):
556 """Base class for controller decorators with multiple permissions"""
559 """Base class for controller decorators with multiple permissions"""
557
560
558 def __init__(self, *required_perms):
561 def __init__(self, *required_perms):
559 self.required_perms = required_perms # usually very short - a list is thus fine
562 self.required_perms = required_perms # usually very short - a list is thus fine
560
563
561 def __call__(self, func):
564 def __call__(self, func):
562 return decorator(self.__wrapper, func)
565 return decorator(self.__wrapper, func)
563
566
564 def __wrapper(self, func, *fargs, **fkwargs):
567 def __wrapper(self, func, *fargs, **fkwargs):
565 cls = fargs[0]
568 cls = fargs[0]
566 user = request.authuser
569 user = request.authuser
567 log.debug('checking %s permissions %s for %s %s',
570 log.debug('checking %s permissions %s for %s %s',
568 self.__class__.__name__, self.required_perms, cls, user)
571 self.__class__.__name__, self.required_perms, cls, user)
569
572
570 if self.check_permissions(user):
573 if self.check_permissions(user):
571 log.debug('Permission granted for %s %s', cls, user)
574 log.debug('Permission granted for %s %s', cls, user)
572 return func(*fargs, **fkwargs)
575 return func(*fargs, **fkwargs)
573
576
574 else:
577 else:
575 log.info('Permission denied for %s %s', cls, user)
578 log.info('Permission denied for %s %s', cls, user)
576 if user.is_default_user:
579 if user.is_default_user:
577 raise _redirect_to_login(_('You need to be signed in to view this page'))
580 raise _redirect_to_login(_('You need to be signed in to view this page'))
578 else:
581 else:
579 raise HTTPForbidden()
582 raise HTTPForbidden()
580
583
581 def check_permissions(self, user):
584 def check_permissions(self, user):
582 raise NotImplementedError()
585 raise NotImplementedError()
583
586
584
587
585 class HasPermissionAnyDecorator(_PermsDecorator):
588 class HasPermissionAnyDecorator(_PermsDecorator):
586 """
589 """
587 Checks the user has any of the given global permissions.
590 Checks the user has any of the given global permissions.
588 """
591 """
589
592
590 def check_permissions(self, user):
593 def check_permissions(self, user):
591 return any(p in user.global_permissions for p in self.required_perms)
594 return any(p in user.global_permissions for p in self.required_perms)
592
595
593
596
594 class _PermDecorator(_PermsDecorator):
597 class _PermDecorator(_PermsDecorator):
595 """Base class for controller decorators with a single permission"""
598 """Base class for controller decorators with a single permission"""
596
599
597 def __init__(self, required_perm):
600 def __init__(self, required_perm):
598 _PermsDecorator.__init__(self, [required_perm])
601 _PermsDecorator.__init__(self, [required_perm])
599 self.required_perm = required_perm
602 self.required_perm = required_perm
600
603
601
604
602 class HasRepoPermissionLevelDecorator(_PermDecorator):
605 class HasRepoPermissionLevelDecorator(_PermDecorator):
603 """
606 """
604 Checks the user has at least the specified permission level for the requested repository.
607 Checks the user has at least the specified permission level for the requested repository.
605 """
608 """
606
609
607 def check_permissions(self, user):
610 def check_permissions(self, user):
608 repo_name = get_repo_slug(request)
611 repo_name = get_repo_slug(request)
609 return user.has_repository_permission_level(repo_name, self.required_perm)
612 return user.has_repository_permission_level(repo_name, self.required_perm)
610
613
611
614
612 class HasRepoGroupPermissionLevelDecorator(_PermDecorator):
615 class HasRepoGroupPermissionLevelDecorator(_PermDecorator):
613 """
616 """
614 Checks the user has any of given permissions for the requested repository group.
617 Checks the user has any of given permissions for the requested repository group.
615 """
618 """
616
619
617 def check_permissions(self, user):
620 def check_permissions(self, user):
618 repo_group_name = get_repo_group_slug(request)
621 repo_group_name = get_repo_group_slug(request)
619 return user.has_repository_group_permission_level(repo_group_name, self.required_perm)
622 return user.has_repository_group_permission_level(repo_group_name, self.required_perm)
620
623
621
624
622 class HasUserGroupPermissionLevelDecorator(_PermDecorator):
625 class HasUserGroupPermissionLevelDecorator(_PermDecorator):
623 """
626 """
624 Checks for access permission for any of given predicates for specific
627 Checks for access permission for any of given predicates for specific
625 user group. In order to fulfill the request any of predicates must be meet
628 user group. In order to fulfill the request any of predicates must be meet
626 """
629 """
627
630
628 def check_permissions(self, user):
631 def check_permissions(self, user):
629 user_group_name = get_user_group_slug(request)
632 user_group_name = get_user_group_slug(request)
630 return user.has_user_group_permission_level(user_group_name, self.required_perm)
633 return user.has_user_group_permission_level(user_group_name, self.required_perm)
631
634
632
635
633 #==============================================================================
636 #==============================================================================
634 # CHECK FUNCTIONS
637 # CHECK FUNCTIONS
635 #==============================================================================
638 #==============================================================================
636
639
637 class _PermsFunction(object):
640 class _PermsFunction(object):
638 """Base function for other check functions with multiple permissions"""
641 """Base function for other check functions with multiple permissions"""
639
642
640 def __init__(self, *required_perms):
643 def __init__(self, *required_perms):
641 self.required_perms = required_perms # usually very short - a list is thus fine
644 self.required_perms = required_perms # usually very short - a list is thus fine
642
645
643 def __bool__(self):
646 def __bool__(self):
644 """ Defend against accidentally forgetting to call the object
647 """ Defend against accidentally forgetting to call the object
645 and instead evaluating it directly in a boolean context,
648 and instead evaluating it directly in a boolean context,
646 which could have security implications.
649 which could have security implications.
647 """
650 """
648 raise AssertionError(self.__class__.__name__ + ' is not a bool and must be called!')
651 raise AssertionError(self.__class__.__name__ + ' is not a bool and must be called!')
649
652
650 def __call__(self, *a, **b):
653 def __call__(self, *a, **b):
651 raise NotImplementedError()
654 raise NotImplementedError()
652
655
653
656
654 class HasPermissionAny(_PermsFunction):
657 class HasPermissionAny(_PermsFunction):
655
658
656 def __call__(self, purpose=None):
659 def __call__(self, purpose=None):
657 ok = any(p in request.authuser.global_permissions for p in self.required_perms)
660 ok = any(p in request.authuser.global_permissions for p in self.required_perms)
658
661
659 log.debug('Check %s for global %s (%s): %s',
662 log.debug('Check %s for global %s (%s): %s',
660 request.authuser.username, self.required_perms, purpose, ok)
663 request.authuser.username, self.required_perms, purpose, ok)
661 return ok
664 return ok
662
665
663
666
664 class _PermFunction(_PermsFunction):
667 class _PermFunction(_PermsFunction):
665 """Base function for other check functions with a single permission"""
668 """Base function for other check functions with a single permission"""
666
669
667 def __init__(self, required_perm):
670 def __init__(self, required_perm):
668 _PermsFunction.__init__(self, [required_perm])
671 _PermsFunction.__init__(self, [required_perm])
669 self.required_perm = required_perm
672 self.required_perm = required_perm
670
673
671
674
672 class HasRepoPermissionLevel(_PermFunction):
675 class HasRepoPermissionLevel(_PermFunction):
673
676
674 def __call__(self, repo_name, purpose=None):
677 def __call__(self, repo_name, purpose=None):
675 return request.authuser.has_repository_permission_level(repo_name, self.required_perm, purpose)
678 return request.authuser.has_repository_permission_level(repo_name, self.required_perm, purpose)
676
679
677
680
678 class HasRepoGroupPermissionLevel(_PermFunction):
681 class HasRepoGroupPermissionLevel(_PermFunction):
679
682
680 def __call__(self, group_name, purpose=None):
683 def __call__(self, group_name, purpose=None):
681 return request.authuser.has_repository_group_permission_level(group_name, self.required_perm, purpose)
684 return request.authuser.has_repository_group_permission_level(group_name, self.required_perm, purpose)
682
685
683
686
684 class HasUserGroupPermissionLevel(_PermFunction):
687 class HasUserGroupPermissionLevel(_PermFunction):
685
688
686 def __call__(self, user_group_name, purpose=None):
689 def __call__(self, user_group_name, purpose=None):
687 return request.authuser.has_user_group_permission_level(user_group_name, self.required_perm, purpose)
690 return request.authuser.has_user_group_permission_level(user_group_name, self.required_perm, purpose)
688
691
689
692
690 #==============================================================================
693 #==============================================================================
691 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
694 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
692 #==============================================================================
695 #==============================================================================
693
696
694 class HasPermissionAnyMiddleware(object):
697 class HasPermissionAnyMiddleware(object):
695 def __init__(self, *perms):
698 def __init__(self, *perms):
696 self.required_perms = set(perms)
699 self.required_perms = set(perms)
697
700
698 def __call__(self, authuser, repo_name, purpose=None):
701 def __call__(self, authuser, repo_name, purpose=None):
699 try:
702 try:
700 ok = authuser.repository_permissions[repo_name] in self.required_perms
703 ok = authuser.repository_permissions[repo_name] in self.required_perms
701 except KeyError:
704 except KeyError:
702 ok = False
705 ok = False
703
706
704 log.debug('Middleware check %s for %s for repo %s (%s): %s', authuser.username, self.required_perms, repo_name, purpose, ok)
707 log.debug('Middleware check %s for %s for repo %s (%s): %s', authuser.username, self.required_perms, repo_name, purpose, ok)
705 return ok
708 return ok
706
709
707
710
708 def check_ip_access(source_ip, allowed_ips=None):
711 def check_ip_access(source_ip, allowed_ips=None):
709 """
712 """
710 Checks if source_ip is a subnet of any of allowed_ips.
713 Checks if source_ip is a subnet of any of allowed_ips.
711
714
712 :param source_ip:
715 :param source_ip:
713 :param allowed_ips: list of allowed ips together with mask
716 :param allowed_ips: list of allowed ips together with mask
714 """
717 """
715 source_ip = source_ip.split('%', 1)[0]
718 source_ip = source_ip.split('%', 1)[0]
716 log.debug('checking if ip:%s is subnet of %s', source_ip, allowed_ips)
719 log.debug('checking if ip:%s is subnet of %s', source_ip, allowed_ips)
717 if isinstance(allowed_ips, (tuple, list, set)):
720 if isinstance(allowed_ips, (tuple, list, set)):
718 for ip in allowed_ips:
721 for ip in allowed_ips:
719 if ipaddr.IPAddress(source_ip) in ipaddr.IPNetwork(ip):
722 if ipaddr.IPAddress(source_ip) in ipaddr.IPNetwork(ip):
720 log.debug('IP %s is network %s',
723 log.debug('IP %s is network %s',
721 ipaddr.IPAddress(source_ip), ipaddr.IPNetwork(ip))
724 ipaddr.IPAddress(source_ip), ipaddr.IPNetwork(ip))
722 return True
725 return True
723 return False
726 return False
General Comments 0
You need to be logged in to leave comments. Login now