Show More
@@ -1,560 +1,562 b'' | |||
|
1 | 1 | # -*- coding: utf-8 -*- |
|
2 | 2 | |
|
3 | 3 | # Copyright (C) 2011-2017 RhodeCode GmbH |
|
4 | 4 | # |
|
5 | 5 | # This program is free software: you can redistribute it and/or modify |
|
6 | 6 | # it under the terms of the GNU Affero General Public License, version 3 |
|
7 | 7 | # (only), as published by the Free Software Foundation. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU Affero General Public License |
|
15 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
16 | 16 | # |
|
17 | 17 | # This program is dual-licensed. If you wish to learn more about the |
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | 21 | import logging |
|
22 | 22 | |
|
23 | 23 | from rhodecode.api import ( |
|
24 | 24 | jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError) |
|
25 | 25 | from rhodecode.api.utils import ( |
|
26 | 26 | Optional, OAttr, has_superadmin_permission, get_user_or_error, store_update) |
|
27 | 27 | from rhodecode.lib import audit_logger |
|
28 | 28 | from rhodecode.lib.auth import AuthUser, PasswordGenerator |
|
29 | 29 | from rhodecode.lib.exceptions import DefaultUserException |
|
30 | 30 | from rhodecode.lib.utils2 import safe_int, str2bool |
|
31 | 31 | from rhodecode.model.db import Session, User, Repository |
|
32 | 32 | from rhodecode.model.user import UserModel |
|
33 | 33 | from rhodecode.model import validation_schema |
|
34 | 34 | from rhodecode.model.validation_schema.schemas import user_schema |
|
35 | 35 | |
|
36 | 36 | log = logging.getLogger(__name__) |
|
37 | 37 | |
|
38 | 38 | |
|
39 | 39 | @jsonrpc_method() |
|
40 | 40 | def get_user(request, apiuser, userid=Optional(OAttr('apiuser'))): |
|
41 | 41 | """ |
|
42 | 42 | Returns the information associated with a username or userid. |
|
43 | 43 | |
|
44 | 44 | * If the ``userid`` is not set, this command returns the information |
|
45 | 45 | for the ``userid`` calling the method. |
|
46 | 46 | |
|
47 | 47 | .. note:: |
|
48 | 48 | |
|
49 | 49 | Normal users may only run this command against their ``userid``. For |
|
50 | 50 | full privileges you must run this command using an |authtoken| with |
|
51 | 51 | admin rights. |
|
52 | 52 | |
|
53 | 53 | :param apiuser: This is filled automatically from the |authtoken|. |
|
54 | 54 | :type apiuser: AuthUser |
|
55 | 55 | :param userid: Sets the userid for which data will be returned. |
|
56 | 56 | :type userid: Optional(str or int) |
|
57 | 57 | |
|
58 | 58 | Example output: |
|
59 | 59 | |
|
60 | 60 | .. code-block:: bash |
|
61 | 61 | |
|
62 | 62 | { |
|
63 | 63 | "error": null, |
|
64 | 64 | "id": <id>, |
|
65 | 65 | "result": { |
|
66 | 66 | "active": true, |
|
67 | 67 | "admin": false, |
|
68 | 68 | "api_keys": [ list of keys ], |
|
69 | 69 | "auth_tokens": [ list of tokens with details ], |
|
70 | 70 | "email": "user@example.com", |
|
71 | 71 | "emails": [ |
|
72 | 72 | "user@example.com" |
|
73 | 73 | ], |
|
74 | 74 | "extern_name": "rhodecode", |
|
75 | 75 | "extern_type": "rhodecode", |
|
76 | 76 | "firstname": "username", |
|
77 | 77 | "ip_addresses": [], |
|
78 | 78 | "language": null, |
|
79 | 79 | "last_login": "Timestamp", |
|
80 | 80 | "last_activity": "Timestamp", |
|
81 | 81 | "lastname": "surnae", |
|
82 | 82 | "permissions": { |
|
83 | 83 | "global": [ |
|
84 | 84 | "hg.inherit_default_perms.true", |
|
85 | 85 | "usergroup.read", |
|
86 | 86 | "hg.repogroup.create.false", |
|
87 | 87 | "hg.create.none", |
|
88 | 88 | "hg.password_reset.enabled", |
|
89 | 89 | "hg.extern_activate.manual", |
|
90 | 90 | "hg.create.write_on_repogroup.false", |
|
91 | 91 | "hg.usergroup.create.false", |
|
92 | 92 | "group.none", |
|
93 | 93 | "repository.none", |
|
94 | 94 | "hg.register.none", |
|
95 | 95 | "hg.fork.repository" |
|
96 | 96 | ], |
|
97 | 97 | "repositories": { "username/example": "repository.write"}, |
|
98 | 98 | "repositories_groups": { "user-group/repo": "group.none" }, |
|
99 | 99 | "user_groups": { "user_group_name": "usergroup.read" } |
|
100 | 100 | }, |
|
101 | 101 | "user_id": 32, |
|
102 | 102 | "username": "username" |
|
103 | 103 | } |
|
104 | 104 | } |
|
105 | 105 | """ |
|
106 | 106 | |
|
107 | 107 | if not has_superadmin_permission(apiuser): |
|
108 | 108 | # make sure normal user does not pass someone else userid, |
|
109 | 109 | # he is not allowed to do that |
|
110 | 110 | if not isinstance(userid, Optional) and userid != apiuser.user_id: |
|
111 | 111 | raise JSONRPCError('userid is not the same as your user') |
|
112 | 112 | |
|
113 | 113 | userid = Optional.extract(userid, evaluate_locals=locals()) |
|
114 | 114 | userid = getattr(userid, 'user_id', userid) |
|
115 | 115 | |
|
116 | 116 | user = get_user_or_error(userid) |
|
117 | 117 | data = user.get_api_data(include_secrets=True) |
|
118 |
|
|
|
118 | permissions = AuthUser(user_id=user.user_id).permissions | |
|
119 | data['permissions'] = permissions # TODO(marcink): should be deprecated | |
|
120 | data['permissions_summary'] = permissions | |
|
119 | 121 | return data |
|
120 | 122 | |
|
121 | 123 | |
|
122 | 124 | @jsonrpc_method() |
|
123 | 125 | def get_users(request, apiuser): |
|
124 | 126 | """ |
|
125 | 127 | Lists all users in the |RCE| user database. |
|
126 | 128 | |
|
127 | 129 | This command can only be run using an |authtoken| with admin rights to |
|
128 | 130 | the specified repository. |
|
129 | 131 | |
|
130 | 132 | This command takes the following options: |
|
131 | 133 | |
|
132 | 134 | :param apiuser: This is filled automatically from the |authtoken|. |
|
133 | 135 | :type apiuser: AuthUser |
|
134 | 136 | |
|
135 | 137 | Example output: |
|
136 | 138 | |
|
137 | 139 | .. code-block:: bash |
|
138 | 140 | |
|
139 | 141 | id : <id_given_in_input> |
|
140 | 142 | result: [<user_object>, ...] |
|
141 | 143 | error: null |
|
142 | 144 | """ |
|
143 | 145 | |
|
144 | 146 | if not has_superadmin_permission(apiuser): |
|
145 | 147 | raise JSONRPCForbidden() |
|
146 | 148 | |
|
147 | 149 | result = [] |
|
148 | 150 | users_list = User.query().order_by(User.username) \ |
|
149 | 151 | .filter(User.username != User.DEFAULT_USER) \ |
|
150 | 152 | .all() |
|
151 | 153 | for user in users_list: |
|
152 | 154 | result.append(user.get_api_data(include_secrets=True)) |
|
153 | 155 | return result |
|
154 | 156 | |
|
155 | 157 | |
|
156 | 158 | @jsonrpc_method() |
|
157 | 159 | def create_user(request, apiuser, username, email, password=Optional(''), |
|
158 | 160 | firstname=Optional(''), lastname=Optional(''), |
|
159 | 161 | active=Optional(True), admin=Optional(False), |
|
160 | 162 | extern_name=Optional('rhodecode'), |
|
161 | 163 | extern_type=Optional('rhodecode'), |
|
162 | 164 | force_password_change=Optional(False), |
|
163 | 165 | create_personal_repo_group=Optional(None)): |
|
164 | 166 | """ |
|
165 | 167 | Creates a new user and returns the new user object. |
|
166 | 168 | |
|
167 | 169 | This command can only be run using an |authtoken| with admin rights to |
|
168 | 170 | the specified repository. |
|
169 | 171 | |
|
170 | 172 | This command takes the following options: |
|
171 | 173 | |
|
172 | 174 | :param apiuser: This is filled automatically from the |authtoken|. |
|
173 | 175 | :type apiuser: AuthUser |
|
174 | 176 | :param username: Set the new username. |
|
175 | 177 | :type username: str or int |
|
176 | 178 | :param email: Set the user email address. |
|
177 | 179 | :type email: str |
|
178 | 180 | :param password: Set the new user password. |
|
179 | 181 | :type password: Optional(str) |
|
180 | 182 | :param firstname: Set the new user firstname. |
|
181 | 183 | :type firstname: Optional(str) |
|
182 | 184 | :param lastname: Set the new user surname. |
|
183 | 185 | :type lastname: Optional(str) |
|
184 | 186 | :param active: Set the user as active. |
|
185 | 187 | :type active: Optional(``True`` | ``False``) |
|
186 | 188 | :param admin: Give the new user admin rights. |
|
187 | 189 | :type admin: Optional(``True`` | ``False``) |
|
188 | 190 | :param extern_name: Set the authentication plugin name. |
|
189 | 191 | Using LDAP this is filled with LDAP UID. |
|
190 | 192 | :type extern_name: Optional(str) |
|
191 | 193 | :param extern_type: Set the new user authentication plugin. |
|
192 | 194 | :type extern_type: Optional(str) |
|
193 | 195 | :param force_password_change: Force the new user to change password |
|
194 | 196 | on next login. |
|
195 | 197 | :type force_password_change: Optional(``True`` | ``False``) |
|
196 | 198 | :param create_personal_repo_group: Create personal repo group for this user |
|
197 | 199 | :type create_personal_repo_group: Optional(``True`` | ``False``) |
|
198 | 200 | |
|
199 | 201 | Example output: |
|
200 | 202 | |
|
201 | 203 | .. code-block:: bash |
|
202 | 204 | |
|
203 | 205 | id : <id_given_in_input> |
|
204 | 206 | result: { |
|
205 | 207 | "msg" : "created new user `<username>`", |
|
206 | 208 | "user": <user_obj> |
|
207 | 209 | } |
|
208 | 210 | error: null |
|
209 | 211 | |
|
210 | 212 | Example error output: |
|
211 | 213 | |
|
212 | 214 | .. code-block:: bash |
|
213 | 215 | |
|
214 | 216 | id : <id_given_in_input> |
|
215 | 217 | result : null |
|
216 | 218 | error : { |
|
217 | 219 | "user `<username>` already exist" |
|
218 | 220 | or |
|
219 | 221 | "email `<email>` already exist" |
|
220 | 222 | or |
|
221 | 223 | "failed to create user `<username>`" |
|
222 | 224 | } |
|
223 | 225 | |
|
224 | 226 | """ |
|
225 | 227 | if not has_superadmin_permission(apiuser): |
|
226 | 228 | raise JSONRPCForbidden() |
|
227 | 229 | |
|
228 | 230 | if UserModel().get_by_username(username): |
|
229 | 231 | raise JSONRPCError("user `%s` already exist" % (username,)) |
|
230 | 232 | |
|
231 | 233 | if UserModel().get_by_email(email, case_insensitive=True): |
|
232 | 234 | raise JSONRPCError("email `%s` already exist" % (email,)) |
|
233 | 235 | |
|
234 | 236 | # generate random password if we actually given the |
|
235 | 237 | # extern_name and it's not rhodecode |
|
236 | 238 | if (not isinstance(extern_name, Optional) and |
|
237 | 239 | Optional.extract(extern_name) != 'rhodecode'): |
|
238 | 240 | # generate temporary password if user is external |
|
239 | 241 | password = PasswordGenerator().gen_password(length=16) |
|
240 | 242 | create_repo_group = Optional.extract(create_personal_repo_group) |
|
241 | 243 | if isinstance(create_repo_group, basestring): |
|
242 | 244 | create_repo_group = str2bool(create_repo_group) |
|
243 | 245 | |
|
244 | 246 | username = Optional.extract(username) |
|
245 | 247 | password = Optional.extract(password) |
|
246 | 248 | email = Optional.extract(email) |
|
247 | 249 | first_name = Optional.extract(firstname) |
|
248 | 250 | last_name = Optional.extract(lastname) |
|
249 | 251 | active = Optional.extract(active) |
|
250 | 252 | admin = Optional.extract(admin) |
|
251 | 253 | extern_type = Optional.extract(extern_type) |
|
252 | 254 | extern_name = Optional.extract(extern_name) |
|
253 | 255 | |
|
254 | 256 | schema = user_schema.UserSchema().bind( |
|
255 | 257 | # user caller |
|
256 | 258 | user=apiuser) |
|
257 | 259 | try: |
|
258 | 260 | schema_data = schema.deserialize(dict( |
|
259 | 261 | username=username, |
|
260 | 262 | email=email, |
|
261 | 263 | password=password, |
|
262 | 264 | first_name=first_name, |
|
263 | 265 | last_name=last_name, |
|
264 | 266 | active=active, |
|
265 | 267 | admin=admin, |
|
266 | 268 | extern_type=extern_type, |
|
267 | 269 | extern_name=extern_name, |
|
268 | 270 | )) |
|
269 | 271 | except validation_schema.Invalid as err: |
|
270 | 272 | raise JSONRPCValidationError(colander_exc=err) |
|
271 | 273 | |
|
272 | 274 | try: |
|
273 | 275 | user = UserModel().create_or_update( |
|
274 | 276 | username=schema_data['username'], |
|
275 | 277 | password=schema_data['password'], |
|
276 | 278 | email=schema_data['email'], |
|
277 | 279 | firstname=schema_data['first_name'], |
|
278 | 280 | lastname=schema_data['last_name'], |
|
279 | 281 | active=schema_data['active'], |
|
280 | 282 | admin=schema_data['admin'], |
|
281 | 283 | extern_type=schema_data['extern_type'], |
|
282 | 284 | extern_name=schema_data['extern_name'], |
|
283 | 285 | force_password_change=Optional.extract(force_password_change), |
|
284 | 286 | create_repo_group=create_repo_group |
|
285 | 287 | ) |
|
286 | 288 | Session().flush() |
|
287 | 289 | creation_data = user.get_api_data() |
|
288 | 290 | audit_logger.store_api( |
|
289 | 291 | 'user.create', action_data={'data': creation_data}, |
|
290 | 292 | user=apiuser) |
|
291 | 293 | |
|
292 | 294 | Session().commit() |
|
293 | 295 | return { |
|
294 | 296 | 'msg': 'created new user `%s`' % username, |
|
295 | 297 | 'user': user.get_api_data(include_secrets=True) |
|
296 | 298 | } |
|
297 | 299 | except Exception: |
|
298 | 300 | log.exception('Error occurred during creation of user') |
|
299 | 301 | raise JSONRPCError('failed to create user `%s`' % (username,)) |
|
300 | 302 | |
|
301 | 303 | |
|
302 | 304 | @jsonrpc_method() |
|
303 | 305 | def update_user(request, apiuser, userid, username=Optional(None), |
|
304 | 306 | email=Optional(None), password=Optional(None), |
|
305 | 307 | firstname=Optional(None), lastname=Optional(None), |
|
306 | 308 | active=Optional(None), admin=Optional(None), |
|
307 | 309 | extern_type=Optional(None), extern_name=Optional(None), ): |
|
308 | 310 | """ |
|
309 | 311 | Updates the details for the specified user, if that user exists. |
|
310 | 312 | |
|
311 | 313 | This command can only be run using an |authtoken| with admin rights to |
|
312 | 314 | the specified repository. |
|
313 | 315 | |
|
314 | 316 | This command takes the following options: |
|
315 | 317 | |
|
316 | 318 | :param apiuser: This is filled automatically from |authtoken|. |
|
317 | 319 | :type apiuser: AuthUser |
|
318 | 320 | :param userid: Set the ``userid`` to update. |
|
319 | 321 | :type userid: str or int |
|
320 | 322 | :param username: Set the new username. |
|
321 | 323 | :type username: str or int |
|
322 | 324 | :param email: Set the new email. |
|
323 | 325 | :type email: str |
|
324 | 326 | :param password: Set the new password. |
|
325 | 327 | :type password: Optional(str) |
|
326 | 328 | :param firstname: Set the new first name. |
|
327 | 329 | :type firstname: Optional(str) |
|
328 | 330 | :param lastname: Set the new surname. |
|
329 | 331 | :type lastname: Optional(str) |
|
330 | 332 | :param active: Set the new user as active. |
|
331 | 333 | :type active: Optional(``True`` | ``False``) |
|
332 | 334 | :param admin: Give the user admin rights. |
|
333 | 335 | :type admin: Optional(``True`` | ``False``) |
|
334 | 336 | :param extern_name: Set the authentication plugin user name. |
|
335 | 337 | Using LDAP this is filled with LDAP UID. |
|
336 | 338 | :type extern_name: Optional(str) |
|
337 | 339 | :param extern_type: Set the authentication plugin type. |
|
338 | 340 | :type extern_type: Optional(str) |
|
339 | 341 | |
|
340 | 342 | |
|
341 | 343 | Example output: |
|
342 | 344 | |
|
343 | 345 | .. code-block:: bash |
|
344 | 346 | |
|
345 | 347 | id : <id_given_in_input> |
|
346 | 348 | result: { |
|
347 | 349 | "msg" : "updated user ID:<userid> <username>", |
|
348 | 350 | "user": <user_object>, |
|
349 | 351 | } |
|
350 | 352 | error: null |
|
351 | 353 | |
|
352 | 354 | Example error output: |
|
353 | 355 | |
|
354 | 356 | .. code-block:: bash |
|
355 | 357 | |
|
356 | 358 | id : <id_given_in_input> |
|
357 | 359 | result : null |
|
358 | 360 | error : { |
|
359 | 361 | "failed to update user `<username>`" |
|
360 | 362 | } |
|
361 | 363 | |
|
362 | 364 | """ |
|
363 | 365 | if not has_superadmin_permission(apiuser): |
|
364 | 366 | raise JSONRPCForbidden() |
|
365 | 367 | |
|
366 | 368 | user = get_user_or_error(userid) |
|
367 | 369 | old_data = user.get_api_data() |
|
368 | 370 | # only non optional arguments will be stored in updates |
|
369 | 371 | updates = {} |
|
370 | 372 | |
|
371 | 373 | try: |
|
372 | 374 | |
|
373 | 375 | store_update(updates, username, 'username') |
|
374 | 376 | store_update(updates, password, 'password') |
|
375 | 377 | store_update(updates, email, 'email') |
|
376 | 378 | store_update(updates, firstname, 'name') |
|
377 | 379 | store_update(updates, lastname, 'lastname') |
|
378 | 380 | store_update(updates, active, 'active') |
|
379 | 381 | store_update(updates, admin, 'admin') |
|
380 | 382 | store_update(updates, extern_name, 'extern_name') |
|
381 | 383 | store_update(updates, extern_type, 'extern_type') |
|
382 | 384 | |
|
383 | 385 | user = UserModel().update_user(user, **updates) |
|
384 | 386 | audit_logger.store_api( |
|
385 | 387 | 'user.edit', action_data={'old_data': old_data}, |
|
386 | 388 | user=apiuser) |
|
387 | 389 | Session().commit() |
|
388 | 390 | return { |
|
389 | 391 | 'msg': 'updated user ID:%s %s' % (user.user_id, user.username), |
|
390 | 392 | 'user': user.get_api_data(include_secrets=True) |
|
391 | 393 | } |
|
392 | 394 | except DefaultUserException: |
|
393 | 395 | log.exception("Default user edit exception") |
|
394 | 396 | raise JSONRPCError('editing default user is forbidden') |
|
395 | 397 | except Exception: |
|
396 | 398 | log.exception("Error occurred during update of user") |
|
397 | 399 | raise JSONRPCError('failed to update user `%s`' % (userid,)) |
|
398 | 400 | |
|
399 | 401 | |
|
400 | 402 | @jsonrpc_method() |
|
401 | 403 | def delete_user(request, apiuser, userid): |
|
402 | 404 | """ |
|
403 | 405 | Deletes the specified user from the |RCE| user database. |
|
404 | 406 | |
|
405 | 407 | This command can only be run using an |authtoken| with admin rights to |
|
406 | 408 | the specified repository. |
|
407 | 409 | |
|
408 | 410 | .. important:: |
|
409 | 411 | |
|
410 | 412 | Ensure all open pull requests and open code review |
|
411 | 413 | requests to this user are close. |
|
412 | 414 | |
|
413 | 415 | Also ensure all repositories, or repository groups owned by this |
|
414 | 416 | user are reassigned before deletion. |
|
415 | 417 | |
|
416 | 418 | This command takes the following options: |
|
417 | 419 | |
|
418 | 420 | :param apiuser: This is filled automatically from the |authtoken|. |
|
419 | 421 | :type apiuser: AuthUser |
|
420 | 422 | :param userid: Set the user to delete. |
|
421 | 423 | :type userid: str or int |
|
422 | 424 | |
|
423 | 425 | Example output: |
|
424 | 426 | |
|
425 | 427 | .. code-block:: bash |
|
426 | 428 | |
|
427 | 429 | id : <id_given_in_input> |
|
428 | 430 | result: { |
|
429 | 431 | "msg" : "deleted user ID:<userid> <username>", |
|
430 | 432 | "user": null |
|
431 | 433 | } |
|
432 | 434 | error: null |
|
433 | 435 | |
|
434 | 436 | Example error output: |
|
435 | 437 | |
|
436 | 438 | .. code-block:: bash |
|
437 | 439 | |
|
438 | 440 | id : <id_given_in_input> |
|
439 | 441 | result : null |
|
440 | 442 | error : { |
|
441 | 443 | "failed to delete user ID:<userid> <username>" |
|
442 | 444 | } |
|
443 | 445 | |
|
444 | 446 | """ |
|
445 | 447 | if not has_superadmin_permission(apiuser): |
|
446 | 448 | raise JSONRPCForbidden() |
|
447 | 449 | |
|
448 | 450 | user = get_user_or_error(userid) |
|
449 | 451 | old_data = user.get_api_data() |
|
450 | 452 | try: |
|
451 | 453 | UserModel().delete(userid) |
|
452 | 454 | audit_logger.store_api( |
|
453 | 455 | 'user.delete', action_data={'old_data': old_data}, |
|
454 | 456 | user=apiuser) |
|
455 | 457 | |
|
456 | 458 | Session().commit() |
|
457 | 459 | return { |
|
458 | 460 | 'msg': 'deleted user ID:%s %s' % (user.user_id, user.username), |
|
459 | 461 | 'user': None |
|
460 | 462 | } |
|
461 | 463 | except Exception: |
|
462 | 464 | log.exception("Error occurred during deleting of user") |
|
463 | 465 | raise JSONRPCError( |
|
464 | 466 | 'failed to delete user ID:%s %s' % (user.user_id, user.username)) |
|
465 | 467 | |
|
466 | 468 | |
|
467 | 469 | @jsonrpc_method() |
|
468 | 470 | def get_user_locks(request, apiuser, userid=Optional(OAttr('apiuser'))): |
|
469 | 471 | """ |
|
470 | 472 | Displays all repositories locked by the specified user. |
|
471 | 473 | |
|
472 | 474 | * If this command is run by a non-admin user, it returns |
|
473 | 475 | a list of |repos| locked by that user. |
|
474 | 476 | |
|
475 | 477 | This command takes the following options: |
|
476 | 478 | |
|
477 | 479 | :param apiuser: This is filled automatically from the |authtoken|. |
|
478 | 480 | :type apiuser: AuthUser |
|
479 | 481 | :param userid: Sets the userid whose list of locked |repos| will be |
|
480 | 482 | displayed. |
|
481 | 483 | :type userid: Optional(str or int) |
|
482 | 484 | |
|
483 | 485 | Example output: |
|
484 | 486 | |
|
485 | 487 | .. code-block:: bash |
|
486 | 488 | |
|
487 | 489 | id : <id_given_in_input> |
|
488 | 490 | result : { |
|
489 | 491 | [repo_object, repo_object,...] |
|
490 | 492 | } |
|
491 | 493 | error : null |
|
492 | 494 | """ |
|
493 | 495 | |
|
494 | 496 | include_secrets = False |
|
495 | 497 | if not has_superadmin_permission(apiuser): |
|
496 | 498 | # make sure normal user does not pass someone else userid, |
|
497 | 499 | # he is not allowed to do that |
|
498 | 500 | if not isinstance(userid, Optional) and userid != apiuser.user_id: |
|
499 | 501 | raise JSONRPCError('userid is not the same as your user') |
|
500 | 502 | else: |
|
501 | 503 | include_secrets = True |
|
502 | 504 | |
|
503 | 505 | userid = Optional.extract(userid, evaluate_locals=locals()) |
|
504 | 506 | userid = getattr(userid, 'user_id', userid) |
|
505 | 507 | user = get_user_or_error(userid) |
|
506 | 508 | |
|
507 | 509 | ret = [] |
|
508 | 510 | |
|
509 | 511 | # show all locks |
|
510 | 512 | for r in Repository.getAll(): |
|
511 | 513 | _user_id, _time, _reason = r.locked |
|
512 | 514 | if _user_id and _time: |
|
513 | 515 | _api_data = r.get_api_data(include_secrets=include_secrets) |
|
514 | 516 | # if we use user filter just show the locks for this user |
|
515 | 517 | if safe_int(_user_id) == user.user_id: |
|
516 | 518 | ret.append(_api_data) |
|
517 | 519 | |
|
518 | 520 | return ret |
|
519 | 521 | |
|
520 | 522 | |
|
521 | 523 | @jsonrpc_method() |
|
522 | 524 | def get_user_audit_logs(request, apiuser, userid=Optional(OAttr('apiuser'))): |
|
523 | 525 | """ |
|
524 | 526 | Fetches all action logs made by the specified user. |
|
525 | 527 | |
|
526 | 528 | This command takes the following options: |
|
527 | 529 | |
|
528 | 530 | :param apiuser: This is filled automatically from the |authtoken|. |
|
529 | 531 | :type apiuser: AuthUser |
|
530 | 532 | :param userid: Sets the userid whose list of locked |repos| will be |
|
531 | 533 | displayed. |
|
532 | 534 | :type userid: Optional(str or int) |
|
533 | 535 | |
|
534 | 536 | Example output: |
|
535 | 537 | |
|
536 | 538 | .. code-block:: bash |
|
537 | 539 | |
|
538 | 540 | id : <id_given_in_input> |
|
539 | 541 | result : { |
|
540 | 542 | [action, action,...] |
|
541 | 543 | } |
|
542 | 544 | error : null |
|
543 | 545 | """ |
|
544 | 546 | |
|
545 | 547 | if not has_superadmin_permission(apiuser): |
|
546 | 548 | # make sure normal user does not pass someone else userid, |
|
547 | 549 | # he is not allowed to do that |
|
548 | 550 | if not isinstance(userid, Optional) and userid != apiuser.user_id: |
|
549 | 551 | raise JSONRPCError('userid is not the same as your user') |
|
550 | 552 | |
|
551 | 553 | userid = Optional.extract(userid, evaluate_locals=locals()) |
|
552 | 554 | userid = getattr(userid, 'user_id', userid) |
|
553 | 555 | user = get_user_or_error(userid) |
|
554 | 556 | |
|
555 | 557 | ret = [] |
|
556 | 558 | |
|
557 | 559 | # show all user actions |
|
558 | 560 | for entry in UserModel().get_user_log(user, filter_term=None): |
|
559 | 561 | ret.append(entry) |
|
560 | 562 | return ret |
@@ -1,822 +1,823 b'' | |||
|
1 | 1 | # -*- coding: utf-8 -*- |
|
2 | 2 | |
|
3 | 3 | # Copyright (C) 2011-2017 RhodeCode GmbH |
|
4 | 4 | # |
|
5 | 5 | # This program is free software: you can redistribute it and/or modify |
|
6 | 6 | # it under the terms of the GNU Affero General Public License, version 3 |
|
7 | 7 | # (only), as published by the Free Software Foundation. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU Affero General Public License |
|
15 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
16 | 16 | # |
|
17 | 17 | # This program is dual-licensed. If you wish to learn more about the |
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | 21 | import logging |
|
22 | 22 | |
|
23 | 23 | from rhodecode.api import ( |
|
24 | 24 | jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError) |
|
25 | 25 | from rhodecode.api.utils import ( |
|
26 | 26 | Optional, OAttr, store_update, has_superadmin_permission, get_origin, |
|
27 | 27 | get_user_or_error, get_user_group_or_error, get_perm_or_error) |
|
28 | 28 | from rhodecode.lib import audit_logger |
|
29 | 29 | from rhodecode.lib.auth import HasUserGroupPermissionAnyApi, HasPermissionAnyApi |
|
30 | 30 | from rhodecode.lib.exceptions import UserGroupAssignedException |
|
31 | 31 | from rhodecode.model.db import Session |
|
32 | 32 | from rhodecode.model.scm import UserGroupList |
|
33 | 33 | from rhodecode.model.user_group import UserGroupModel |
|
34 | 34 | from rhodecode.model import validation_schema |
|
35 | 35 | from rhodecode.model.validation_schema.schemas import user_group_schema |
|
36 | 36 | |
|
37 | 37 | log = logging.getLogger(__name__) |
|
38 | 38 | |
|
39 | 39 | |
|
40 | 40 | @jsonrpc_method() |
|
41 | 41 | def get_user_group(request, apiuser, usergroupid): |
|
42 | 42 | """ |
|
43 | 43 | Returns the data of an existing user group. |
|
44 | 44 | |
|
45 | 45 | This command can only be run using an |authtoken| with admin rights to |
|
46 | 46 | the specified repository. |
|
47 | 47 | |
|
48 | 48 | :param apiuser: This is filled automatically from the |authtoken|. |
|
49 | 49 | :type apiuser: AuthUser |
|
50 | 50 | :param usergroupid: Set the user group from which to return data. |
|
51 | 51 | :type usergroupid: str or int |
|
52 | 52 | |
|
53 | 53 | Example error output: |
|
54 | 54 | |
|
55 | 55 | .. code-block:: bash |
|
56 | 56 | |
|
57 | 57 | { |
|
58 | 58 | "error": null, |
|
59 | 59 | "id": <id>, |
|
60 | 60 | "result": { |
|
61 | 61 | "active": true, |
|
62 | 62 | "group_description": "group description", |
|
63 | 63 | "group_name": "group name", |
|
64 | 64 | "members": [ |
|
65 | 65 | { |
|
66 | 66 | "name": "owner-name", |
|
67 | 67 | "origin": "owner", |
|
68 | 68 | "permission": "usergroup.admin", |
|
69 | 69 | "type": "user" |
|
70 | 70 | }, |
|
71 | 71 | { |
|
72 | 72 | { |
|
73 | 73 | "name": "user name", |
|
74 | 74 | "origin": "permission", |
|
75 | 75 | "permission": "usergroup.admin", |
|
76 | 76 | "type": "user" |
|
77 | 77 | }, |
|
78 | 78 | { |
|
79 | 79 | "name": "user group name", |
|
80 | 80 | "origin": "permission", |
|
81 | 81 | "permission": "usergroup.write", |
|
82 | 82 | "type": "user_group" |
|
83 | 83 | } |
|
84 | 84 | ], |
|
85 | 85 | "owner": "owner name", |
|
86 | 86 | "users": [], |
|
87 | 87 | "users_group_id": 2 |
|
88 | 88 | } |
|
89 | 89 | } |
|
90 | 90 | |
|
91 | 91 | """ |
|
92 | 92 | |
|
93 | 93 | user_group = get_user_group_or_error(usergroupid) |
|
94 | 94 | if not has_superadmin_permission(apiuser): |
|
95 | 95 | # check if we have at least read permission for this user group ! |
|
96 | 96 | _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',) |
|
97 | 97 | if not HasUserGroupPermissionAnyApi(*_perms)( |
|
98 | 98 | user=apiuser, user_group_name=user_group.users_group_name): |
|
99 | 99 | raise JSONRPCError('user group `%s` does not exist' % ( |
|
100 | 100 | usergroupid,)) |
|
101 | 101 | |
|
102 | 102 | permissions = [] |
|
103 | 103 | for _user in user_group.permissions(): |
|
104 | 104 | user_data = { |
|
105 | 105 | 'name': _user.username, |
|
106 | 106 | 'permission': _user.permission, |
|
107 | 107 | 'origin': get_origin(_user), |
|
108 | 108 | 'type': "user", |
|
109 | 109 | } |
|
110 | 110 | permissions.append(user_data) |
|
111 | 111 | |
|
112 | 112 | for _user_group in user_group.permission_user_groups(): |
|
113 | 113 | user_group_data = { |
|
114 | 114 | 'name': _user_group.users_group_name, |
|
115 | 115 | 'permission': _user_group.permission, |
|
116 | 116 | 'origin': get_origin(_user_group), |
|
117 | 117 | 'type': "user_group", |
|
118 | 118 | } |
|
119 | 119 | permissions.append(user_group_data) |
|
120 | 120 | |
|
121 | 121 | data = user_group.get_api_data() |
|
122 | 122 | data["permissions"] = permissions |
|
123 | ||
|
123 | data["Permissions_summary"] = UserGroupModel().get_perms_summary( | |
|
124 | user_group.users_group_id) | |
|
124 | 125 | return data |
|
125 | 126 | |
|
126 | 127 | |
|
127 | 128 | @jsonrpc_method() |
|
128 | 129 | def get_user_groups(request, apiuser): |
|
129 | 130 | """ |
|
130 | 131 | Lists all the existing user groups within RhodeCode. |
|
131 | 132 | |
|
132 | 133 | This command can only be run using an |authtoken| with admin rights to |
|
133 | 134 | the specified repository. |
|
134 | 135 | |
|
135 | 136 | This command takes the following options: |
|
136 | 137 | |
|
137 | 138 | :param apiuser: This is filled automatically from the |authtoken|. |
|
138 | 139 | :type apiuser: AuthUser |
|
139 | 140 | |
|
140 | 141 | Example error output: |
|
141 | 142 | |
|
142 | 143 | .. code-block:: bash |
|
143 | 144 | |
|
144 | 145 | id : <id_given_in_input> |
|
145 | 146 | result : [<user_group_obj>,...] |
|
146 | 147 | error : null |
|
147 | 148 | """ |
|
148 | 149 | |
|
149 | 150 | include_secrets = has_superadmin_permission(apiuser) |
|
150 | 151 | |
|
151 | 152 | result = [] |
|
152 | 153 | _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',) |
|
153 | 154 | extras = {'user': apiuser} |
|
154 | 155 | for user_group in UserGroupList(UserGroupModel().get_all(), |
|
155 | 156 | perm_set=_perms, extra_kwargs=extras): |
|
156 | 157 | result.append( |
|
157 | 158 | user_group.get_api_data(include_secrets=include_secrets)) |
|
158 | 159 | return result |
|
159 | 160 | |
|
160 | 161 | |
|
161 | 162 | @jsonrpc_method() |
|
162 | 163 | def create_user_group( |
|
163 | 164 | request, apiuser, group_name, description=Optional(''), |
|
164 | 165 | owner=Optional(OAttr('apiuser')), active=Optional(True)): |
|
165 | 166 | """ |
|
166 | 167 | Creates a new user group. |
|
167 | 168 | |
|
168 | 169 | This command can only be run using an |authtoken| with admin rights to |
|
169 | 170 | the specified repository. |
|
170 | 171 | |
|
171 | 172 | This command takes the following options: |
|
172 | 173 | |
|
173 | 174 | :param apiuser: This is filled automatically from the |authtoken|. |
|
174 | 175 | :type apiuser: AuthUser |
|
175 | 176 | :param group_name: Set the name of the new user group. |
|
176 | 177 | :type group_name: str |
|
177 | 178 | :param description: Give a description of the new user group. |
|
178 | 179 | :type description: str |
|
179 | 180 | :param owner: Set the owner of the new user group. |
|
180 | 181 | If not set, the owner is the |authtoken| user. |
|
181 | 182 | :type owner: Optional(str or int) |
|
182 | 183 | :param active: Set this group as active. |
|
183 | 184 | :type active: Optional(``True`` | ``False``) |
|
184 | 185 | |
|
185 | 186 | Example output: |
|
186 | 187 | |
|
187 | 188 | .. code-block:: bash |
|
188 | 189 | |
|
189 | 190 | id : <id_given_in_input> |
|
190 | 191 | result: { |
|
191 | 192 | "msg": "created new user group `<groupname>`", |
|
192 | 193 | "user_group": <user_group_object> |
|
193 | 194 | } |
|
194 | 195 | error: null |
|
195 | 196 | |
|
196 | 197 | Example error output: |
|
197 | 198 | |
|
198 | 199 | .. code-block:: bash |
|
199 | 200 | |
|
200 | 201 | id : <id_given_in_input> |
|
201 | 202 | result : null |
|
202 | 203 | error : { |
|
203 | 204 | "user group `<group name>` already exist" |
|
204 | 205 | or |
|
205 | 206 | "failed to create group `<group name>`" |
|
206 | 207 | } |
|
207 | 208 | |
|
208 | 209 | """ |
|
209 | 210 | |
|
210 | 211 | if not has_superadmin_permission(apiuser): |
|
211 | 212 | if not HasPermissionAnyApi('hg.usergroup.create.true')(user=apiuser): |
|
212 | 213 | raise JSONRPCForbidden() |
|
213 | 214 | |
|
214 | 215 | if UserGroupModel().get_by_name(group_name): |
|
215 | 216 | raise JSONRPCError("user group `%s` already exist" % (group_name,)) |
|
216 | 217 | |
|
217 | 218 | if isinstance(owner, Optional): |
|
218 | 219 | owner = apiuser.user_id |
|
219 | 220 | |
|
220 | 221 | owner = get_user_or_error(owner) |
|
221 | 222 | active = Optional.extract(active) |
|
222 | 223 | description = Optional.extract(description) |
|
223 | 224 | |
|
224 | 225 | schema = user_group_schema.UserGroupSchema().bind( |
|
225 | 226 | # user caller |
|
226 | 227 | user=apiuser) |
|
227 | 228 | try: |
|
228 | 229 | schema_data = schema.deserialize(dict( |
|
229 | 230 | user_group_name=group_name, |
|
230 | 231 | user_group_description=description, |
|
231 | 232 | user_group_owner=owner.username, |
|
232 | 233 | user_group_active=active, |
|
233 | 234 | )) |
|
234 | 235 | except validation_schema.Invalid as err: |
|
235 | 236 | raise JSONRPCValidationError(colander_exc=err) |
|
236 | 237 | |
|
237 | 238 | try: |
|
238 | 239 | user_group = UserGroupModel().create( |
|
239 | 240 | name=schema_data['user_group_name'], |
|
240 | 241 | description=schema_data['user_group_description'], |
|
241 | 242 | owner=owner, |
|
242 | 243 | active=schema_data['user_group_active']) |
|
243 | 244 | Session().flush() |
|
244 | 245 | creation_data = user_group.get_api_data() |
|
245 | 246 | audit_logger.store_api( |
|
246 | 247 | 'user_group.create', action_data={'data': creation_data}, |
|
247 | 248 | user=apiuser) |
|
248 | 249 | Session().commit() |
|
249 | 250 | return { |
|
250 | 251 | 'msg': 'created new user group `%s`' % group_name, |
|
251 | 252 | 'user_group': creation_data |
|
252 | 253 | } |
|
253 | 254 | except Exception: |
|
254 | 255 | log.exception("Error occurred during creation of user group") |
|
255 | 256 | raise JSONRPCError('failed to create group `%s`' % (group_name,)) |
|
256 | 257 | |
|
257 | 258 | |
|
258 | 259 | @jsonrpc_method() |
|
259 | 260 | def update_user_group(request, apiuser, usergroupid, group_name=Optional(''), |
|
260 | 261 | description=Optional(''), owner=Optional(None), |
|
261 | 262 | active=Optional(True)): |
|
262 | 263 | """ |
|
263 | 264 | Updates the specified `user group` with the details provided. |
|
264 | 265 | |
|
265 | 266 | This command can only be run using an |authtoken| with admin rights to |
|
266 | 267 | the specified repository. |
|
267 | 268 | |
|
268 | 269 | :param apiuser: This is filled automatically from the |authtoken|. |
|
269 | 270 | :type apiuser: AuthUser |
|
270 | 271 | :param usergroupid: Set the id of the `user group` to update. |
|
271 | 272 | :type usergroupid: str or int |
|
272 | 273 | :param group_name: Set the new name the `user group` |
|
273 | 274 | :type group_name: str |
|
274 | 275 | :param description: Give a description for the `user group` |
|
275 | 276 | :type description: str |
|
276 | 277 | :param owner: Set the owner of the `user group`. |
|
277 | 278 | :type owner: Optional(str or int) |
|
278 | 279 | :param active: Set the group as active. |
|
279 | 280 | :type active: Optional(``True`` | ``False``) |
|
280 | 281 | |
|
281 | 282 | Example output: |
|
282 | 283 | |
|
283 | 284 | .. code-block:: bash |
|
284 | 285 | |
|
285 | 286 | id : <id_given_in_input> |
|
286 | 287 | result : { |
|
287 | 288 | "msg": 'updated user group ID:<user group id> <user group name>', |
|
288 | 289 | "user_group": <user_group_object> |
|
289 | 290 | } |
|
290 | 291 | error : null |
|
291 | 292 | |
|
292 | 293 | Example error output: |
|
293 | 294 | |
|
294 | 295 | .. code-block:: bash |
|
295 | 296 | |
|
296 | 297 | id : <id_given_in_input> |
|
297 | 298 | result : null |
|
298 | 299 | error : { |
|
299 | 300 | "failed to update user group `<user group name>`" |
|
300 | 301 | } |
|
301 | 302 | |
|
302 | 303 | """ |
|
303 | 304 | |
|
304 | 305 | user_group = get_user_group_or_error(usergroupid) |
|
305 | 306 | include_secrets = False |
|
306 | 307 | if not has_superadmin_permission(apiuser): |
|
307 | 308 | # check if we have admin permission for this user group ! |
|
308 | 309 | _perms = ('usergroup.admin',) |
|
309 | 310 | if not HasUserGroupPermissionAnyApi(*_perms)( |
|
310 | 311 | user=apiuser, user_group_name=user_group.users_group_name): |
|
311 | 312 | raise JSONRPCError( |
|
312 | 313 | 'user group `%s` does not exist' % (usergroupid,)) |
|
313 | 314 | else: |
|
314 | 315 | include_secrets = True |
|
315 | 316 | |
|
316 | 317 | if not isinstance(owner, Optional): |
|
317 | 318 | owner = get_user_or_error(owner) |
|
318 | 319 | |
|
319 | 320 | old_data = user_group.get_api_data() |
|
320 | 321 | updates = {} |
|
321 | 322 | store_update(updates, group_name, 'users_group_name') |
|
322 | 323 | store_update(updates, description, 'user_group_description') |
|
323 | 324 | store_update(updates, owner, 'user') |
|
324 | 325 | store_update(updates, active, 'users_group_active') |
|
325 | 326 | try: |
|
326 | 327 | UserGroupModel().update(user_group, updates) |
|
327 | 328 | audit_logger.store_api( |
|
328 | 329 | 'user_group.edit', action_data={'old_data': old_data}, |
|
329 | 330 | user=apiuser) |
|
330 | 331 | Session().commit() |
|
331 | 332 | return { |
|
332 | 333 | 'msg': 'updated user group ID:%s %s' % ( |
|
333 | 334 | user_group.users_group_id, user_group.users_group_name), |
|
334 | 335 | 'user_group': user_group.get_api_data( |
|
335 | 336 | include_secrets=include_secrets) |
|
336 | 337 | } |
|
337 | 338 | except Exception: |
|
338 | 339 | log.exception("Error occurred during update of user group") |
|
339 | 340 | raise JSONRPCError( |
|
340 | 341 | 'failed to update user group `%s`' % (usergroupid,)) |
|
341 | 342 | |
|
342 | 343 | |
|
343 | 344 | @jsonrpc_method() |
|
344 | 345 | def delete_user_group(request, apiuser, usergroupid): |
|
345 | 346 | """ |
|
346 | 347 | Deletes the specified `user group`. |
|
347 | 348 | |
|
348 | 349 | This command can only be run using an |authtoken| with admin rights to |
|
349 | 350 | the specified repository. |
|
350 | 351 | |
|
351 | 352 | This command takes the following options: |
|
352 | 353 | |
|
353 | 354 | :param apiuser: filled automatically from apikey |
|
354 | 355 | :type apiuser: AuthUser |
|
355 | 356 | :param usergroupid: |
|
356 | 357 | :type usergroupid: int |
|
357 | 358 | |
|
358 | 359 | Example output: |
|
359 | 360 | |
|
360 | 361 | .. code-block:: bash |
|
361 | 362 | |
|
362 | 363 | id : <id_given_in_input> |
|
363 | 364 | result : { |
|
364 | 365 | "msg": "deleted user group ID:<user_group_id> <user_group_name>" |
|
365 | 366 | } |
|
366 | 367 | error : null |
|
367 | 368 | |
|
368 | 369 | Example error output: |
|
369 | 370 | |
|
370 | 371 | .. code-block:: bash |
|
371 | 372 | |
|
372 | 373 | id : <id_given_in_input> |
|
373 | 374 | result : null |
|
374 | 375 | error : { |
|
375 | 376 | "failed to delete user group ID:<user_group_id> <user_group_name>" |
|
376 | 377 | or |
|
377 | 378 | "RepoGroup assigned to <repo_groups_list>" |
|
378 | 379 | } |
|
379 | 380 | |
|
380 | 381 | """ |
|
381 | 382 | |
|
382 | 383 | user_group = get_user_group_or_error(usergroupid) |
|
383 | 384 | if not has_superadmin_permission(apiuser): |
|
384 | 385 | # check if we have admin permission for this user group ! |
|
385 | 386 | _perms = ('usergroup.admin',) |
|
386 | 387 | if not HasUserGroupPermissionAnyApi(*_perms)( |
|
387 | 388 | user=apiuser, user_group_name=user_group.users_group_name): |
|
388 | 389 | raise JSONRPCError( |
|
389 | 390 | 'user group `%s` does not exist' % (usergroupid,)) |
|
390 | 391 | |
|
391 | 392 | old_data = user_group.get_api_data() |
|
392 | 393 | try: |
|
393 | 394 | UserGroupModel().delete(user_group) |
|
394 | 395 | audit_logger.store_api( |
|
395 | 396 | 'user_group.delete', action_data={'old_data': old_data}, |
|
396 | 397 | user=apiuser) |
|
397 | 398 | Session().commit() |
|
398 | 399 | return { |
|
399 | 400 | 'msg': 'deleted user group ID:%s %s' % ( |
|
400 | 401 | user_group.users_group_id, user_group.users_group_name), |
|
401 | 402 | 'user_group': None |
|
402 | 403 | } |
|
403 | 404 | except UserGroupAssignedException as e: |
|
404 | 405 | log.exception("UserGroupAssigned error") |
|
405 | 406 | raise JSONRPCError(str(e)) |
|
406 | 407 | except Exception: |
|
407 | 408 | log.exception("Error occurred during deletion of user group") |
|
408 | 409 | raise JSONRPCError( |
|
409 | 410 | 'failed to delete user group ID:%s %s' %( |
|
410 | 411 | user_group.users_group_id, user_group.users_group_name)) |
|
411 | 412 | |
|
412 | 413 | |
|
413 | 414 | @jsonrpc_method() |
|
414 | 415 | def add_user_to_user_group(request, apiuser, usergroupid, userid): |
|
415 | 416 | """ |
|
416 | 417 | Adds a user to a `user group`. If the user already exists in the group |
|
417 | 418 | this command will return false. |
|
418 | 419 | |
|
419 | 420 | This command can only be run using an |authtoken| with admin rights to |
|
420 | 421 | the specified user group. |
|
421 | 422 | |
|
422 | 423 | This command takes the following options: |
|
423 | 424 | |
|
424 | 425 | :param apiuser: This is filled automatically from the |authtoken|. |
|
425 | 426 | :type apiuser: AuthUser |
|
426 | 427 | :param usergroupid: Set the name of the `user group` to which a |
|
427 | 428 | user will be added. |
|
428 | 429 | :type usergroupid: int |
|
429 | 430 | :param userid: Set the `user_id` of the user to add to the group. |
|
430 | 431 | :type userid: int |
|
431 | 432 | |
|
432 | 433 | Example output: |
|
433 | 434 | |
|
434 | 435 | .. code-block:: bash |
|
435 | 436 | |
|
436 | 437 | id : <id_given_in_input> |
|
437 | 438 | result : { |
|
438 | 439 | "success": True|False # depends on if member is in group |
|
439 | 440 | "msg": "added member `<username>` to user group `<groupname>` | |
|
440 | 441 | User is already in that group" |
|
441 | 442 | |
|
442 | 443 | } |
|
443 | 444 | error : null |
|
444 | 445 | |
|
445 | 446 | Example error output: |
|
446 | 447 | |
|
447 | 448 | .. code-block:: bash |
|
448 | 449 | |
|
449 | 450 | id : <id_given_in_input> |
|
450 | 451 | result : null |
|
451 | 452 | error : { |
|
452 | 453 | "failed to add member to user group `<user_group_name>`" |
|
453 | 454 | } |
|
454 | 455 | |
|
455 | 456 | """ |
|
456 | 457 | |
|
457 | 458 | user = get_user_or_error(userid) |
|
458 | 459 | user_group = get_user_group_or_error(usergroupid) |
|
459 | 460 | if not has_superadmin_permission(apiuser): |
|
460 | 461 | # check if we have admin permission for this user group ! |
|
461 | 462 | _perms = ('usergroup.admin',) |
|
462 | 463 | if not HasUserGroupPermissionAnyApi(*_perms)( |
|
463 | 464 | user=apiuser, user_group_name=user_group.users_group_name): |
|
464 | 465 | raise JSONRPCError('user group `%s` does not exist' % ( |
|
465 | 466 | usergroupid,)) |
|
466 | 467 | |
|
467 | 468 | old_values = user_group.get_api_data() |
|
468 | 469 | try: |
|
469 | 470 | ugm = UserGroupModel().add_user_to_group(user_group, user) |
|
470 | 471 | success = True if ugm is not True else False |
|
471 | 472 | msg = 'added member `%s` to user group `%s`' % ( |
|
472 | 473 | user.username, user_group.users_group_name |
|
473 | 474 | ) |
|
474 | 475 | msg = msg if success else 'User is already in that group' |
|
475 | 476 | if success: |
|
476 | 477 | user_data = user.get_api_data() |
|
477 | 478 | audit_logger.store_api( |
|
478 | 479 | 'user_group.edit.member.add', |
|
479 | 480 | action_data={'user': user_data, 'old_data': old_values}, |
|
480 | 481 | user=apiuser) |
|
481 | 482 | |
|
482 | 483 | Session().commit() |
|
483 | 484 | |
|
484 | 485 | return { |
|
485 | 486 | 'success': success, |
|
486 | 487 | 'msg': msg |
|
487 | 488 | } |
|
488 | 489 | except Exception: |
|
489 | 490 | log.exception("Error occurred during adding a member to user group") |
|
490 | 491 | raise JSONRPCError( |
|
491 | 492 | 'failed to add member to user group `%s`' % ( |
|
492 | 493 | user_group.users_group_name, |
|
493 | 494 | ) |
|
494 | 495 | ) |
|
495 | 496 | |
|
496 | 497 | |
|
497 | 498 | @jsonrpc_method() |
|
498 | 499 | def remove_user_from_user_group(request, apiuser, usergroupid, userid): |
|
499 | 500 | """ |
|
500 | 501 | Removes a user from a user group. |
|
501 | 502 | |
|
502 | 503 | * If the specified user is not in the group, this command will return |
|
503 | 504 | `false`. |
|
504 | 505 | |
|
505 | 506 | This command can only be run using an |authtoken| with admin rights to |
|
506 | 507 | the specified user group. |
|
507 | 508 | |
|
508 | 509 | :param apiuser: This is filled automatically from the |authtoken|. |
|
509 | 510 | :type apiuser: AuthUser |
|
510 | 511 | :param usergroupid: Sets the user group name. |
|
511 | 512 | :type usergroupid: str or int |
|
512 | 513 | :param userid: The user you wish to remove from |RCE|. |
|
513 | 514 | :type userid: str or int |
|
514 | 515 | |
|
515 | 516 | Example output: |
|
516 | 517 | |
|
517 | 518 | .. code-block:: bash |
|
518 | 519 | |
|
519 | 520 | id : <id_given_in_input> |
|
520 | 521 | result: { |
|
521 | 522 | "success": True|False, # depends on if member is in group |
|
522 | 523 | "msg": "removed member <username> from user group <groupname> | |
|
523 | 524 | User wasn't in group" |
|
524 | 525 | } |
|
525 | 526 | error: null |
|
526 | 527 | |
|
527 | 528 | """ |
|
528 | 529 | |
|
529 | 530 | user = get_user_or_error(userid) |
|
530 | 531 | user_group = get_user_group_or_error(usergroupid) |
|
531 | 532 | if not has_superadmin_permission(apiuser): |
|
532 | 533 | # check if we have admin permission for this user group ! |
|
533 | 534 | _perms = ('usergroup.admin',) |
|
534 | 535 | if not HasUserGroupPermissionAnyApi(*_perms)( |
|
535 | 536 | user=apiuser, user_group_name=user_group.users_group_name): |
|
536 | 537 | raise JSONRPCError( |
|
537 | 538 | 'user group `%s` does not exist' % (usergroupid,)) |
|
538 | 539 | |
|
539 | 540 | old_values = user_group.get_api_data() |
|
540 | 541 | try: |
|
541 | 542 | success = UserGroupModel().remove_user_from_group(user_group, user) |
|
542 | 543 | msg = 'removed member `%s` from user group `%s`' % ( |
|
543 | 544 | user.username, user_group.users_group_name |
|
544 | 545 | ) |
|
545 | 546 | msg = msg if success else "User wasn't in group" |
|
546 | 547 | if success: |
|
547 | 548 | user_data = user.get_api_data() |
|
548 | 549 | audit_logger.store_api( |
|
549 | 550 | 'user_group.edit.member.delete', |
|
550 | 551 | action_data={'user': user_data, 'old_data': old_values}, |
|
551 | 552 | user=apiuser) |
|
552 | 553 | |
|
553 | 554 | Session().commit() |
|
554 | 555 | return {'success': success, 'msg': msg} |
|
555 | 556 | except Exception: |
|
556 | 557 | log.exception("Error occurred during removing an member from user group") |
|
557 | 558 | raise JSONRPCError( |
|
558 | 559 | 'failed to remove member from user group `%s`' % ( |
|
559 | 560 | user_group.users_group_name, |
|
560 | 561 | ) |
|
561 | 562 | ) |
|
562 | 563 | |
|
563 | 564 | |
|
564 | 565 | @jsonrpc_method() |
|
565 | 566 | def grant_user_permission_to_user_group( |
|
566 | 567 | request, apiuser, usergroupid, userid, perm): |
|
567 | 568 | """ |
|
568 | 569 | Set permissions for a user in a user group. |
|
569 | 570 | |
|
570 | 571 | :param apiuser: This is filled automatically from the |authtoken|. |
|
571 | 572 | :type apiuser: AuthUser |
|
572 | 573 | :param usergroupid: Set the user group to edit permissions on. |
|
573 | 574 | :type usergroupid: str or int |
|
574 | 575 | :param userid: Set the user from whom you wish to set permissions. |
|
575 | 576 | :type userid: str |
|
576 | 577 | :param perm: (usergroup.(none|read|write|admin)) |
|
577 | 578 | :type perm: str |
|
578 | 579 | |
|
579 | 580 | Example output: |
|
580 | 581 | |
|
581 | 582 | .. code-block:: bash |
|
582 | 583 | |
|
583 | 584 | id : <id_given_in_input> |
|
584 | 585 | result : { |
|
585 | 586 | "msg": "Granted perm: `<perm_name>` for user: `<username>` in user group: `<user_group_name>`", |
|
586 | 587 | "success": true |
|
587 | 588 | } |
|
588 | 589 | error : null |
|
589 | 590 | """ |
|
590 | 591 | |
|
591 | 592 | user_group = get_user_group_or_error(usergroupid) |
|
592 | 593 | |
|
593 | 594 | if not has_superadmin_permission(apiuser): |
|
594 | 595 | # check if we have admin permission for this user group ! |
|
595 | 596 | _perms = ('usergroup.admin',) |
|
596 | 597 | if not HasUserGroupPermissionAnyApi(*_perms)( |
|
597 | 598 | user=apiuser, user_group_name=user_group.users_group_name): |
|
598 | 599 | raise JSONRPCError( |
|
599 | 600 | 'user group `%s` does not exist' % (usergroupid,)) |
|
600 | 601 | |
|
601 | 602 | user = get_user_or_error(userid) |
|
602 | 603 | perm = get_perm_or_error(perm, prefix='usergroup.') |
|
603 | 604 | |
|
604 | 605 | try: |
|
605 | 606 | UserGroupModel().grant_user_permission( |
|
606 | 607 | user_group=user_group, user=user, perm=perm) |
|
607 | 608 | Session().commit() |
|
608 | 609 | return { |
|
609 | 610 | 'msg': |
|
610 | 611 | 'Granted perm: `%s` for user: `%s` in user group: `%s`' % ( |
|
611 | 612 | perm.permission_name, user.username, |
|
612 | 613 | user_group.users_group_name |
|
613 | 614 | ), |
|
614 | 615 | 'success': True |
|
615 | 616 | } |
|
616 | 617 | except Exception: |
|
617 | 618 | log.exception("Error occurred during editing permissions " |
|
618 | 619 | "for user in user group") |
|
619 | 620 | raise JSONRPCError( |
|
620 | 621 | 'failed to edit permission for user: ' |
|
621 | 622 | '`%s` in user group: `%s`' % ( |
|
622 | 623 | userid, user_group.users_group_name)) |
|
623 | 624 | |
|
624 | 625 | |
|
625 | 626 | @jsonrpc_method() |
|
626 | 627 | def revoke_user_permission_from_user_group( |
|
627 | 628 | request, apiuser, usergroupid, userid): |
|
628 | 629 | """ |
|
629 | 630 | Revoke a users permissions in a user group. |
|
630 | 631 | |
|
631 | 632 | :param apiuser: This is filled automatically from the |authtoken|. |
|
632 | 633 | :type apiuser: AuthUser |
|
633 | 634 | :param usergroupid: Set the user group from which to revoke the user |
|
634 | 635 | permissions. |
|
635 | 636 | :type: usergroupid: str or int |
|
636 | 637 | :param userid: Set the userid of the user whose permissions will be |
|
637 | 638 | revoked. |
|
638 | 639 | :type userid: str |
|
639 | 640 | |
|
640 | 641 | Example output: |
|
641 | 642 | |
|
642 | 643 | .. code-block:: bash |
|
643 | 644 | |
|
644 | 645 | id : <id_given_in_input> |
|
645 | 646 | result : { |
|
646 | 647 | "msg": "Revoked perm for user: `<username>` in user group: `<user_group_name>`", |
|
647 | 648 | "success": true |
|
648 | 649 | } |
|
649 | 650 | error : null |
|
650 | 651 | """ |
|
651 | 652 | |
|
652 | 653 | user_group = get_user_group_or_error(usergroupid) |
|
653 | 654 | |
|
654 | 655 | if not has_superadmin_permission(apiuser): |
|
655 | 656 | # check if we have admin permission for this user group ! |
|
656 | 657 | _perms = ('usergroup.admin',) |
|
657 | 658 | if not HasUserGroupPermissionAnyApi(*_perms)( |
|
658 | 659 | user=apiuser, user_group_name=user_group.users_group_name): |
|
659 | 660 | raise JSONRPCError( |
|
660 | 661 | 'user group `%s` does not exist' % (usergroupid,)) |
|
661 | 662 | |
|
662 | 663 | user = get_user_or_error(userid) |
|
663 | 664 | |
|
664 | 665 | try: |
|
665 | 666 | UserGroupModel().revoke_user_permission( |
|
666 | 667 | user_group=user_group, user=user) |
|
667 | 668 | Session().commit() |
|
668 | 669 | return { |
|
669 | 670 | 'msg': 'Revoked perm for user: `%s` in user group: `%s`' % ( |
|
670 | 671 | user.username, user_group.users_group_name |
|
671 | 672 | ), |
|
672 | 673 | 'success': True |
|
673 | 674 | } |
|
674 | 675 | except Exception: |
|
675 | 676 | log.exception("Error occurred during editing permissions " |
|
676 | 677 | "for user in user group") |
|
677 | 678 | raise JSONRPCError( |
|
678 | 679 | 'failed to edit permission for user: `%s` in user group: `%s`' |
|
679 | 680 | % (userid, user_group.users_group_name)) |
|
680 | 681 | |
|
681 | 682 | |
|
682 | 683 | @jsonrpc_method() |
|
683 | 684 | def grant_user_group_permission_to_user_group( |
|
684 | 685 | request, apiuser, usergroupid, sourceusergroupid, perm): |
|
685 | 686 | """ |
|
686 | 687 | Give one user group permissions to another user group. |
|
687 | 688 | |
|
688 | 689 | :param apiuser: This is filled automatically from the |authtoken|. |
|
689 | 690 | :type apiuser: AuthUser |
|
690 | 691 | :param usergroupid: Set the user group on which to edit permissions. |
|
691 | 692 | :type usergroupid: str or int |
|
692 | 693 | :param sourceusergroupid: Set the source user group to which |
|
693 | 694 | access/permissions will be granted. |
|
694 | 695 | :type sourceusergroupid: str or int |
|
695 | 696 | :param perm: (usergroup.(none|read|write|admin)) |
|
696 | 697 | :type perm: str |
|
697 | 698 | |
|
698 | 699 | Example output: |
|
699 | 700 | |
|
700 | 701 | .. code-block:: bash |
|
701 | 702 | |
|
702 | 703 | id : <id_given_in_input> |
|
703 | 704 | result : { |
|
704 | 705 | "msg": "Granted perm: `<perm_name>` for user group: `<source_user_group_name>` in user group: `<user_group_name>`", |
|
705 | 706 | "success": true |
|
706 | 707 | } |
|
707 | 708 | error : null |
|
708 | 709 | """ |
|
709 | 710 | |
|
710 | 711 | user_group = get_user_group_or_error(sourceusergroupid) |
|
711 | 712 | target_user_group = get_user_group_or_error(usergroupid) |
|
712 | 713 | perm = get_perm_or_error(perm, prefix='usergroup.') |
|
713 | 714 | |
|
714 | 715 | if not has_superadmin_permission(apiuser): |
|
715 | 716 | # check if we have admin permission for this user group ! |
|
716 | 717 | _perms = ('usergroup.admin',) |
|
717 | 718 | if not HasUserGroupPermissionAnyApi(*_perms)( |
|
718 | 719 | user=apiuser, |
|
719 | 720 | user_group_name=target_user_group.users_group_name): |
|
720 | 721 | raise JSONRPCError( |
|
721 | 722 | 'to user group `%s` does not exist' % (usergroupid,)) |
|
722 | 723 | |
|
723 | 724 | # check if we have at least read permission for source user group ! |
|
724 | 725 | _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',) |
|
725 | 726 | if not HasUserGroupPermissionAnyApi(*_perms)( |
|
726 | 727 | user=apiuser, user_group_name=user_group.users_group_name): |
|
727 | 728 | raise JSONRPCError( |
|
728 | 729 | 'user group `%s` does not exist' % (sourceusergroupid,)) |
|
729 | 730 | |
|
730 | 731 | try: |
|
731 | 732 | UserGroupModel().grant_user_group_permission( |
|
732 | 733 | target_user_group=target_user_group, |
|
733 | 734 | user_group=user_group, perm=perm) |
|
734 | 735 | Session().commit() |
|
735 | 736 | |
|
736 | 737 | return { |
|
737 | 738 | 'msg': 'Granted perm: `%s` for user group: `%s` ' |
|
738 | 739 | 'in user group: `%s`' % ( |
|
739 | 740 | perm.permission_name, user_group.users_group_name, |
|
740 | 741 | target_user_group.users_group_name |
|
741 | 742 | ), |
|
742 | 743 | 'success': True |
|
743 | 744 | } |
|
744 | 745 | except Exception: |
|
745 | 746 | log.exception("Error occurred during editing permissions " |
|
746 | 747 | "for user group in user group") |
|
747 | 748 | raise JSONRPCError( |
|
748 | 749 | 'failed to edit permission for user group: `%s` in ' |
|
749 | 750 | 'user group: `%s`' % ( |
|
750 | 751 | sourceusergroupid, target_user_group.users_group_name |
|
751 | 752 | ) |
|
752 | 753 | ) |
|
753 | 754 | |
|
754 | 755 | |
|
755 | 756 | @jsonrpc_method() |
|
756 | 757 | def revoke_user_group_permission_from_user_group( |
|
757 | 758 | request, apiuser, usergroupid, sourceusergroupid): |
|
758 | 759 | """ |
|
759 | 760 | Revoke the permissions that one user group has to another. |
|
760 | 761 | |
|
761 | 762 | :param apiuser: This is filled automatically from the |authtoken|. |
|
762 | 763 | :type apiuser: AuthUser |
|
763 | 764 | :param usergroupid: Set the user group on which to edit permissions. |
|
764 | 765 | :type usergroupid: str or int |
|
765 | 766 | :param sourceusergroupid: Set the user group from which permissions |
|
766 | 767 | are revoked. |
|
767 | 768 | :type sourceusergroupid: str or int |
|
768 | 769 | |
|
769 | 770 | Example output: |
|
770 | 771 | |
|
771 | 772 | .. code-block:: bash |
|
772 | 773 | |
|
773 | 774 | id : <id_given_in_input> |
|
774 | 775 | result : { |
|
775 | 776 | "msg": "Revoked perm for user group: `<user_group_name>` in user group: `<target_user_group_name>`", |
|
776 | 777 | "success": true |
|
777 | 778 | } |
|
778 | 779 | error : null |
|
779 | 780 | """ |
|
780 | 781 | |
|
781 | 782 | user_group = get_user_group_or_error(sourceusergroupid) |
|
782 | 783 | target_user_group = get_user_group_or_error(usergroupid) |
|
783 | 784 | |
|
784 | 785 | if not has_superadmin_permission(apiuser): |
|
785 | 786 | # check if we have admin permission for this user group ! |
|
786 | 787 | _perms = ('usergroup.admin',) |
|
787 | 788 | if not HasUserGroupPermissionAnyApi(*_perms)( |
|
788 | 789 | user=apiuser, |
|
789 | 790 | user_group_name=target_user_group.users_group_name): |
|
790 | 791 | raise JSONRPCError( |
|
791 | 792 | 'to user group `%s` does not exist' % (usergroupid,)) |
|
792 | 793 | |
|
793 | 794 | # check if we have at least read permission |
|
794 | 795 | # for the source user group ! |
|
795 | 796 | _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',) |
|
796 | 797 | if not HasUserGroupPermissionAnyApi(*_perms)( |
|
797 | 798 | user=apiuser, user_group_name=user_group.users_group_name): |
|
798 | 799 | raise JSONRPCError( |
|
799 | 800 | 'user group `%s` does not exist' % (sourceusergroupid,)) |
|
800 | 801 | |
|
801 | 802 | try: |
|
802 | 803 | UserGroupModel().revoke_user_group_permission( |
|
803 | 804 | target_user_group=target_user_group, user_group=user_group) |
|
804 | 805 | Session().commit() |
|
805 | 806 | |
|
806 | 807 | return { |
|
807 | 808 | 'msg': 'Revoked perm for user group: ' |
|
808 | 809 | '`%s` in user group: `%s`' % ( |
|
809 | 810 | user_group.users_group_name, |
|
810 | 811 | target_user_group.users_group_name |
|
811 | 812 | ), |
|
812 | 813 | 'success': True |
|
813 | 814 | } |
|
814 | 815 | except Exception: |
|
815 | 816 | log.exception("Error occurred during editing permissions " |
|
816 | 817 | "for user group in user group") |
|
817 | 818 | raise JSONRPCError( |
|
818 | 819 | 'failed to edit permission for user group: ' |
|
819 | 820 | '`%s` in user group: `%s`' % ( |
|
820 | 821 | sourceusergroupid, target_user_group.users_group_name |
|
821 | 822 | ) |
|
822 | 823 | ) |
@@ -1,546 +1,519 b'' | |||
|
1 | 1 | # -*- coding: utf-8 -*- |
|
2 | 2 | |
|
3 | 3 | # Copyright (C) 2016-2017 RhodeCode GmbH |
|
4 | 4 | # |
|
5 | 5 | # This program is free software: you can redistribute it and/or modify |
|
6 | 6 | # it under the terms of the GNU Affero General Public License, version 3 |
|
7 | 7 | # (only), as published by the Free Software Foundation. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU Affero General Public License |
|
15 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
16 | 16 | # |
|
17 | 17 | # This program is dual-licensed. If you wish to learn more about the |
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | 21 | import logging |
|
22 | 22 | |
|
23 | 23 | import peppercorn |
|
24 | 24 | import formencode |
|
25 | 25 | import formencode.htmlfill |
|
26 | 26 | from pyramid.httpexceptions import HTTPFound |
|
27 | 27 | from pyramid.view import view_config |
|
28 | 28 | from pyramid.response import Response |
|
29 | 29 | from pyramid.renderers import render |
|
30 | 30 | |
|
31 | 31 | from rhodecode.lib.exceptions import ( |
|
32 | 32 | RepoGroupAssignmentError, UserGroupAssignedException) |
|
33 | 33 | from rhodecode.model.forms import ( |
|
34 | 34 | UserGroupPermsForm, UserGroupForm, UserIndividualPermissionsForm, |
|
35 | 35 | UserPermissionsForm) |
|
36 | 36 | from rhodecode.model.permission import PermissionModel |
|
37 | 37 | |
|
38 | 38 | from rhodecode.apps._base import UserGroupAppView |
|
39 | 39 | from rhodecode.lib.auth import ( |
|
40 | 40 | LoginRequired, HasUserGroupPermissionAnyDecorator, CSRFRequired) |
|
41 | 41 | from rhodecode.lib import helpers as h, audit_logger |
|
42 | 42 | from rhodecode.lib.utils2 import str2bool |
|
43 |
from rhodecode.model.db import |
|
|
44 | joinedload, User, UserGroupRepoToPerm, UserGroupRepoGroupToPerm) | |
|
43 | from rhodecode.model.db import User | |
|
45 | 44 | from rhodecode.model.meta import Session |
|
46 | 45 | from rhodecode.model.user_group import UserGroupModel |
|
47 | 46 | |
|
48 | 47 | log = logging.getLogger(__name__) |
|
49 | 48 | |
|
50 | 49 | |
|
51 | 50 | class UserGroupsView(UserGroupAppView): |
|
52 | 51 | |
|
53 | 52 | def load_default_context(self): |
|
54 | 53 | c = self._get_local_tmpl_context() |
|
55 | 54 | |
|
56 | 55 | PermissionModel().set_global_permission_choices( |
|
57 | 56 | c, gettext_translator=self.request.translate) |
|
58 | 57 | |
|
59 | ||
|
60 | 58 | return c |
|
61 | 59 | |
|
62 | def _get_perms_summary(self, user_group_id): | |
|
63 | permissions = { | |
|
64 | 'repositories': {}, | |
|
65 | 'repositories_groups': {}, | |
|
66 | } | |
|
67 | ugroup_repo_perms = UserGroupRepoToPerm.query()\ | |
|
68 | .options(joinedload(UserGroupRepoToPerm.permission))\ | |
|
69 | .options(joinedload(UserGroupRepoToPerm.repository))\ | |
|
70 | .filter(UserGroupRepoToPerm.users_group_id == user_group_id)\ | |
|
71 | .all() | |
|
72 | ||
|
73 | for gr in ugroup_repo_perms: | |
|
74 | permissions['repositories'][gr.repository.repo_name] \ | |
|
75 | = gr.permission.permission_name | |
|
76 | ||
|
77 | ugroup_group_perms = UserGroupRepoGroupToPerm.query()\ | |
|
78 | .options(joinedload(UserGroupRepoGroupToPerm.permission))\ | |
|
79 | .options(joinedload(UserGroupRepoGroupToPerm.group))\ | |
|
80 | .filter(UserGroupRepoGroupToPerm.users_group_id == user_group_id)\ | |
|
81 | .all() | |
|
82 | ||
|
83 | for gr in ugroup_group_perms: | |
|
84 | permissions['repositories_groups'][gr.group.group_name] \ | |
|
85 | = gr.permission.permission_name | |
|
86 | return permissions | |
|
87 | ||
|
88 | 60 | @LoginRequired() |
|
89 | 61 | @HasUserGroupPermissionAnyDecorator('usergroup.admin') |
|
90 | 62 | @view_config( |
|
91 | 63 | route_name='user_group_members_data', request_method='GET', |
|
92 | 64 | renderer='json_ext', xhr=True) |
|
93 | 65 | def user_group_members(self): |
|
94 | 66 | """ |
|
95 | 67 | Return members of given user group |
|
96 | 68 | """ |
|
97 | 69 | self.load_default_context() |
|
98 | 70 | user_group = self.db_user_group |
|
99 | 71 | group_members_obj = sorted((x.user for x in user_group.members), |
|
100 | 72 | key=lambda u: u.username.lower()) |
|
101 | 73 | |
|
102 | 74 | group_members = [ |
|
103 | 75 | { |
|
104 | 76 | 'id': user.user_id, |
|
105 | 77 | 'first_name': user.first_name, |
|
106 | 78 | 'last_name': user.last_name, |
|
107 | 79 | 'username': user.username, |
|
108 | 80 | 'icon_link': h.gravatar_url(user.email, 30), |
|
109 | 81 | 'value_display': h.person(user.email), |
|
110 | 82 | 'value': user.username, |
|
111 | 83 | 'value_type': 'user', |
|
112 | 84 | 'active': user.active, |
|
113 | 85 | } |
|
114 | 86 | for user in group_members_obj |
|
115 | 87 | ] |
|
116 | 88 | |
|
117 | 89 | return { |
|
118 | 90 | 'members': group_members |
|
119 | 91 | } |
|
120 | 92 | |
|
121 | 93 | @LoginRequired() |
|
122 | 94 | @HasUserGroupPermissionAnyDecorator('usergroup.admin') |
|
123 | 95 | @view_config( |
|
124 | 96 | route_name='edit_user_group_perms_summary', request_method='GET', |
|
125 | 97 | renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako') |
|
126 | 98 | def user_group_perms_summary(self): |
|
127 | 99 | c = self.load_default_context() |
|
128 | 100 | c.user_group = self.db_user_group |
|
129 | 101 | c.active = 'perms_summary' |
|
130 |
c.permissions = |
|
|
102 | c.permissions = UserGroupModel().get_perms_summary( | |
|
103 | c.user_group.users_group_id) | |
|
131 | 104 | return self._get_template_context(c) |
|
132 | 105 | |
|
133 | 106 | @LoginRequired() |
|
134 | 107 | @HasUserGroupPermissionAnyDecorator('usergroup.admin') |
|
135 | 108 | @view_config( |
|
136 | 109 | route_name='edit_user_group_perms_summary_json', request_method='GET', |
|
137 | 110 | renderer='json_ext') |
|
138 | 111 | def user_group_perms_summary_json(self): |
|
139 | 112 | self.load_default_context() |
|
140 | 113 | user_group = self.db_user_group |
|
141 |
return |
|
|
114 | return UserGroupModel().get_perms_summary(user_group.users_group_id) | |
|
142 | 115 | |
|
143 | 116 | def _revoke_perms_on_yourself(self, form_result): |
|
144 | 117 | _updates = filter(lambda u: self._rhodecode_user.user_id == int(u[0]), |
|
145 | 118 | form_result['perm_updates']) |
|
146 | 119 | _additions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]), |
|
147 | 120 | form_result['perm_additions']) |
|
148 | 121 | _deletions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]), |
|
149 | 122 | form_result['perm_deletions']) |
|
150 | 123 | admin_perm = 'usergroup.admin' |
|
151 | 124 | if _updates and _updates[0][1] != admin_perm or \ |
|
152 | 125 | _additions and _additions[0][1] != admin_perm or \ |
|
153 | 126 | _deletions and _deletions[0][1] != admin_perm: |
|
154 | 127 | return True |
|
155 | 128 | return False |
|
156 | 129 | |
|
157 | 130 | @LoginRequired() |
|
158 | 131 | @HasUserGroupPermissionAnyDecorator('usergroup.admin') |
|
159 | 132 | @CSRFRequired() |
|
160 | 133 | @view_config( |
|
161 | 134 | route_name='user_groups_update', request_method='POST', |
|
162 | 135 | renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako') |
|
163 | 136 | def user_group_update(self): |
|
164 | 137 | _ = self.request.translate |
|
165 | 138 | |
|
166 | 139 | user_group = self.db_user_group |
|
167 | 140 | user_group_id = user_group.users_group_id |
|
168 | 141 | |
|
169 | 142 | c = self.load_default_context() |
|
170 | 143 | c.user_group = user_group |
|
171 | 144 | c.group_members_obj = [x.user for x in c.user_group.members] |
|
172 | 145 | c.group_members_obj.sort(key=lambda u: u.username.lower()) |
|
173 | 146 | c.group_members = [(x.user_id, x.username) for x in c.group_members_obj] |
|
174 | 147 | c.active = 'settings' |
|
175 | 148 | |
|
176 | 149 | users_group_form = UserGroupForm( |
|
177 | 150 | self.request.translate, edit=True, |
|
178 | 151 | old_data=c.user_group.get_dict(), allow_disabled=True)() |
|
179 | 152 | |
|
180 | 153 | old_values = c.user_group.get_api_data() |
|
181 | 154 | user_group_name = self.request.POST.get('users_group_name') |
|
182 | 155 | try: |
|
183 | 156 | form_result = users_group_form.to_python(self.request.POST) |
|
184 | 157 | pstruct = peppercorn.parse(self.request.POST.items()) |
|
185 | 158 | form_result['users_group_members'] = pstruct['user_group_members'] |
|
186 | 159 | |
|
187 | 160 | user_group, added_members, removed_members = \ |
|
188 | 161 | UserGroupModel().update(c.user_group, form_result) |
|
189 | 162 | updated_user_group = form_result['users_group_name'] |
|
190 | 163 | |
|
191 | 164 | for user_id in added_members: |
|
192 | 165 | user = User.get(user_id) |
|
193 | 166 | user_data = user.get_api_data() |
|
194 | 167 | audit_logger.store_web( |
|
195 | 168 | 'user_group.edit.member.add', |
|
196 | 169 | action_data={'user': user_data, 'old_data': old_values}, |
|
197 | 170 | user=self._rhodecode_user) |
|
198 | 171 | |
|
199 | 172 | for user_id in removed_members: |
|
200 | 173 | user = User.get(user_id) |
|
201 | 174 | user_data = user.get_api_data() |
|
202 | 175 | audit_logger.store_web( |
|
203 | 176 | 'user_group.edit.member.delete', |
|
204 | 177 | action_data={'user': user_data, 'old_data': old_values}, |
|
205 | 178 | user=self._rhodecode_user) |
|
206 | 179 | |
|
207 | 180 | audit_logger.store_web( |
|
208 | 181 | 'user_group.edit', action_data={'old_data': old_values}, |
|
209 | 182 | user=self._rhodecode_user) |
|
210 | 183 | |
|
211 | 184 | h.flash(_('Updated user group %s') % updated_user_group, |
|
212 | 185 | category='success') |
|
213 | 186 | Session().commit() |
|
214 | 187 | except formencode.Invalid as errors: |
|
215 | 188 | defaults = errors.value |
|
216 | 189 | e = errors.error_dict or {} |
|
217 | 190 | |
|
218 | 191 | data = render( |
|
219 | 192 | 'rhodecode:templates/admin/user_groups/user_group_edit.mako', |
|
220 | 193 | self._get_template_context(c), self.request) |
|
221 | 194 | html = formencode.htmlfill.render( |
|
222 | 195 | data, |
|
223 | 196 | defaults=defaults, |
|
224 | 197 | errors=e, |
|
225 | 198 | prefix_error=False, |
|
226 | 199 | encoding="UTF-8", |
|
227 | 200 | force_defaults=False |
|
228 | 201 | ) |
|
229 | 202 | return Response(html) |
|
230 | 203 | |
|
231 | 204 | except Exception: |
|
232 | 205 | log.exception("Exception during update of user group") |
|
233 | 206 | h.flash(_('Error occurred during update of user group %s') |
|
234 | 207 | % user_group_name, category='error') |
|
235 | 208 | |
|
236 | 209 | raise HTTPFound( |
|
237 | 210 | h.route_path('edit_user_group', user_group_id=user_group_id)) |
|
238 | 211 | |
|
239 | 212 | @LoginRequired() |
|
240 | 213 | @HasUserGroupPermissionAnyDecorator('usergroup.admin') |
|
241 | 214 | @CSRFRequired() |
|
242 | 215 | @view_config( |
|
243 | 216 | route_name='user_groups_delete', request_method='POST', |
|
244 | 217 | renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako') |
|
245 | 218 | def user_group_delete(self): |
|
246 | 219 | _ = self.request.translate |
|
247 | 220 | user_group = self.db_user_group |
|
248 | 221 | |
|
249 | 222 | self.load_default_context() |
|
250 | 223 | force = str2bool(self.request.POST.get('force')) |
|
251 | 224 | |
|
252 | 225 | old_values = user_group.get_api_data() |
|
253 | 226 | try: |
|
254 | 227 | UserGroupModel().delete(user_group, force=force) |
|
255 | 228 | audit_logger.store_web( |
|
256 | 229 | 'user.delete', action_data={'old_data': old_values}, |
|
257 | 230 | user=self._rhodecode_user) |
|
258 | 231 | Session().commit() |
|
259 | 232 | h.flash(_('Successfully deleted user group'), category='success') |
|
260 | 233 | except UserGroupAssignedException as e: |
|
261 | 234 | h.flash(str(e), category='error') |
|
262 | 235 | except Exception: |
|
263 | 236 | log.exception("Exception during deletion of user group") |
|
264 | 237 | h.flash(_('An error occurred during deletion of user group'), |
|
265 | 238 | category='error') |
|
266 | 239 | raise HTTPFound(h.route_path('user_groups')) |
|
267 | 240 | |
|
268 | 241 | @LoginRequired() |
|
269 | 242 | @HasUserGroupPermissionAnyDecorator('usergroup.admin') |
|
270 | 243 | @view_config( |
|
271 | 244 | route_name='edit_user_group', request_method='GET', |
|
272 | 245 | renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako') |
|
273 | 246 | def user_group_edit(self): |
|
274 | 247 | user_group = self.db_user_group |
|
275 | 248 | |
|
276 | 249 | c = self.load_default_context() |
|
277 | 250 | c.user_group = user_group |
|
278 | 251 | c.group_members_obj = [x.user for x in c.user_group.members] |
|
279 | 252 | c.group_members_obj.sort(key=lambda u: u.username.lower()) |
|
280 | 253 | c.group_members = [(x.user_id, x.username) for x in c.group_members_obj] |
|
281 | 254 | |
|
282 | 255 | c.active = 'settings' |
|
283 | 256 | |
|
284 | 257 | defaults = user_group.get_dict() |
|
285 | 258 | # fill owner |
|
286 | 259 | if user_group.user: |
|
287 | 260 | defaults.update({'user': user_group.user.username}) |
|
288 | 261 | else: |
|
289 | 262 | replacement_user = User.get_first_super_admin().username |
|
290 | 263 | defaults.update({'user': replacement_user}) |
|
291 | 264 | |
|
292 | 265 | data = render( |
|
293 | 266 | 'rhodecode:templates/admin/user_groups/user_group_edit.mako', |
|
294 | 267 | self._get_template_context(c), self.request) |
|
295 | 268 | html = formencode.htmlfill.render( |
|
296 | 269 | data, |
|
297 | 270 | defaults=defaults, |
|
298 | 271 | encoding="UTF-8", |
|
299 | 272 | force_defaults=False |
|
300 | 273 | ) |
|
301 | 274 | return Response(html) |
|
302 | 275 | |
|
303 | 276 | @LoginRequired() |
|
304 | 277 | @HasUserGroupPermissionAnyDecorator('usergroup.admin') |
|
305 | 278 | @view_config( |
|
306 | 279 | route_name='edit_user_group_perms', request_method='GET', |
|
307 | 280 | renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako') |
|
308 | 281 | def user_group_edit_perms(self): |
|
309 | 282 | user_group = self.db_user_group |
|
310 | 283 | c = self.load_default_context() |
|
311 | 284 | c.user_group = user_group |
|
312 | 285 | c.active = 'perms' |
|
313 | 286 | |
|
314 | 287 | defaults = {} |
|
315 | 288 | # fill user group users |
|
316 | 289 | for p in c.user_group.user_user_group_to_perm: |
|
317 | 290 | defaults.update({'u_perm_%s' % p.user.user_id: |
|
318 | 291 | p.permission.permission_name}) |
|
319 | 292 | |
|
320 | 293 | for p in c.user_group.user_group_user_group_to_perm: |
|
321 | 294 | defaults.update({'g_perm_%s' % p.user_group.users_group_id: |
|
322 | 295 | p.permission.permission_name}) |
|
323 | 296 | |
|
324 | 297 | data = render( |
|
325 | 298 | 'rhodecode:templates/admin/user_groups/user_group_edit.mako', |
|
326 | 299 | self._get_template_context(c), self.request) |
|
327 | 300 | html = formencode.htmlfill.render( |
|
328 | 301 | data, |
|
329 | 302 | defaults=defaults, |
|
330 | 303 | encoding="UTF-8", |
|
331 | 304 | force_defaults=False |
|
332 | 305 | ) |
|
333 | 306 | return Response(html) |
|
334 | 307 | |
|
335 | 308 | @LoginRequired() |
|
336 | 309 | @HasUserGroupPermissionAnyDecorator('usergroup.admin') |
|
337 | 310 | @CSRFRequired() |
|
338 | 311 | @view_config( |
|
339 | 312 | route_name='edit_user_group_perms_update', request_method='POST', |
|
340 | 313 | renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako') |
|
341 | 314 | def user_group_update_perms(self): |
|
342 | 315 | """ |
|
343 | 316 | grant permission for given user group |
|
344 | 317 | """ |
|
345 | 318 | _ = self.request.translate |
|
346 | 319 | |
|
347 | 320 | user_group = self.db_user_group |
|
348 | 321 | user_group_id = user_group.users_group_id |
|
349 | 322 | c = self.load_default_context() |
|
350 | 323 | c.user_group = user_group |
|
351 | 324 | form = UserGroupPermsForm(self.request.translate)().to_python(self.request.POST) |
|
352 | 325 | |
|
353 | 326 | if not self._rhodecode_user.is_admin: |
|
354 | 327 | if self._revoke_perms_on_yourself(form): |
|
355 | 328 | msg = _('Cannot change permission for yourself as admin') |
|
356 | 329 | h.flash(msg, category='warning') |
|
357 | 330 | raise HTTPFound( |
|
358 | 331 | h.route_path('edit_user_group_perms', |
|
359 | 332 | user_group_id=user_group_id)) |
|
360 | 333 | |
|
361 | 334 | try: |
|
362 | 335 | changes = UserGroupModel().update_permissions( |
|
363 | 336 | user_group_id, |
|
364 | 337 | form['perm_additions'], form['perm_updates'], |
|
365 | 338 | form['perm_deletions']) |
|
366 | 339 | |
|
367 | 340 | except RepoGroupAssignmentError: |
|
368 | 341 | h.flash(_('Target group cannot be the same'), category='error') |
|
369 | 342 | raise HTTPFound( |
|
370 | 343 | h.route_path('edit_user_group_perms', |
|
371 | 344 | user_group_id=user_group_id)) |
|
372 | 345 | |
|
373 | 346 | action_data = { |
|
374 | 347 | 'added': changes['added'], |
|
375 | 348 | 'updated': changes['updated'], |
|
376 | 349 | 'deleted': changes['deleted'], |
|
377 | 350 | } |
|
378 | 351 | audit_logger.store_web( |
|
379 | 352 | 'user_group.edit.permissions', action_data=action_data, |
|
380 | 353 | user=self._rhodecode_user) |
|
381 | 354 | |
|
382 | 355 | Session().commit() |
|
383 | 356 | h.flash(_('User Group permissions updated'), category='success') |
|
384 | 357 | raise HTTPFound( |
|
385 | 358 | h.route_path('edit_user_group_perms', user_group_id=user_group_id)) |
|
386 | 359 | |
|
387 | 360 | @LoginRequired() |
|
388 | 361 | @HasUserGroupPermissionAnyDecorator('usergroup.admin') |
|
389 | 362 | @view_config( |
|
390 | 363 | route_name='edit_user_group_global_perms', request_method='GET', |
|
391 | 364 | renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako') |
|
392 | 365 | def user_group_global_perms_edit(self): |
|
393 | 366 | user_group = self.db_user_group |
|
394 | 367 | c = self.load_default_context() |
|
395 | 368 | c.user_group = user_group |
|
396 | 369 | c.active = 'global_perms' |
|
397 | 370 | |
|
398 | 371 | c.default_user = User.get_default_user() |
|
399 | 372 | defaults = c.user_group.get_dict() |
|
400 | 373 | defaults.update(c.default_user.get_default_perms(suffix='_inherited')) |
|
401 | 374 | defaults.update(c.user_group.get_default_perms()) |
|
402 | 375 | |
|
403 | 376 | data = render( |
|
404 | 377 | 'rhodecode:templates/admin/user_groups/user_group_edit.mako', |
|
405 | 378 | self._get_template_context(c), self.request) |
|
406 | 379 | html = formencode.htmlfill.render( |
|
407 | 380 | data, |
|
408 | 381 | defaults=defaults, |
|
409 | 382 | encoding="UTF-8", |
|
410 | 383 | force_defaults=False |
|
411 | 384 | ) |
|
412 | 385 | return Response(html) |
|
413 | 386 | |
|
414 | 387 | @LoginRequired() |
|
415 | 388 | @HasUserGroupPermissionAnyDecorator('usergroup.admin') |
|
416 | 389 | @CSRFRequired() |
|
417 | 390 | @view_config( |
|
418 | 391 | route_name='edit_user_group_global_perms_update', request_method='POST', |
|
419 | 392 | renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako') |
|
420 | 393 | def user_group_global_perms_update(self): |
|
421 | 394 | _ = self.request.translate |
|
422 | 395 | user_group = self.db_user_group |
|
423 | 396 | user_group_id = self.db_user_group.users_group_id |
|
424 | 397 | |
|
425 | 398 | c = self.load_default_context() |
|
426 | 399 | c.user_group = user_group |
|
427 | 400 | c.active = 'global_perms' |
|
428 | 401 | |
|
429 | 402 | try: |
|
430 | 403 | # first stage that verifies the checkbox |
|
431 | 404 | _form = UserIndividualPermissionsForm(self.request.translate) |
|
432 | 405 | form_result = _form.to_python(dict(self.request.POST)) |
|
433 | 406 | inherit_perms = form_result['inherit_default_permissions'] |
|
434 | 407 | user_group.inherit_default_permissions = inherit_perms |
|
435 | 408 | Session().add(user_group) |
|
436 | 409 | |
|
437 | 410 | if not inherit_perms: |
|
438 | 411 | # only update the individual ones if we un check the flag |
|
439 | 412 | _form = UserPermissionsForm( |
|
440 | 413 | self.request.translate, |
|
441 | 414 | [x[0] for x in c.repo_create_choices], |
|
442 | 415 | [x[0] for x in c.repo_create_on_write_choices], |
|
443 | 416 | [x[0] for x in c.repo_group_create_choices], |
|
444 | 417 | [x[0] for x in c.user_group_create_choices], |
|
445 | 418 | [x[0] for x in c.fork_choices], |
|
446 | 419 | [x[0] for x in c.inherit_default_permission_choices])() |
|
447 | 420 | |
|
448 | 421 | form_result = _form.to_python(dict(self.request.POST)) |
|
449 | 422 | form_result.update( |
|
450 | 423 | {'perm_user_group_id': user_group.users_group_id}) |
|
451 | 424 | |
|
452 | 425 | PermissionModel().update_user_group_permissions(form_result) |
|
453 | 426 | |
|
454 | 427 | Session().commit() |
|
455 | 428 | h.flash(_('User Group global permissions updated successfully'), |
|
456 | 429 | category='success') |
|
457 | 430 | |
|
458 | 431 | except formencode.Invalid as errors: |
|
459 | 432 | defaults = errors.value |
|
460 | 433 | |
|
461 | 434 | data = render( |
|
462 | 435 | 'rhodecode:templates/admin/user_groups/user_group_edit.mako', |
|
463 | 436 | self._get_template_context(c), self.request) |
|
464 | 437 | html = formencode.htmlfill.render( |
|
465 | 438 | data, |
|
466 | 439 | defaults=defaults, |
|
467 | 440 | errors=errors.error_dict or {}, |
|
468 | 441 | prefix_error=False, |
|
469 | 442 | encoding="UTF-8", |
|
470 | 443 | force_defaults=False |
|
471 | 444 | ) |
|
472 | 445 | return Response(html) |
|
473 | 446 | except Exception: |
|
474 | 447 | log.exception("Exception during permissions saving") |
|
475 | 448 | h.flash(_('An error occurred during permissions saving'), |
|
476 | 449 | category='error') |
|
477 | 450 | |
|
478 | 451 | raise HTTPFound( |
|
479 | 452 | h.route_path('edit_user_group_global_perms', |
|
480 | 453 | user_group_id=user_group_id)) |
|
481 | 454 | |
|
482 | 455 | @LoginRequired() |
|
483 | 456 | @HasUserGroupPermissionAnyDecorator('usergroup.admin') |
|
484 | 457 | @view_config( |
|
485 | 458 | route_name='edit_user_group_advanced', request_method='GET', |
|
486 | 459 | renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako') |
|
487 | 460 | def user_group_edit_advanced(self): |
|
488 | 461 | user_group = self.db_user_group |
|
489 | 462 | |
|
490 | 463 | c = self.load_default_context() |
|
491 | 464 | c.user_group = user_group |
|
492 | 465 | c.active = 'advanced' |
|
493 | 466 | c.group_members_obj = sorted( |
|
494 | 467 | (x.user for x in c.user_group.members), |
|
495 | 468 | key=lambda u: u.username.lower()) |
|
496 | 469 | |
|
497 | 470 | c.group_to_repos = sorted( |
|
498 | 471 | (x.repository for x in c.user_group.users_group_repo_to_perm), |
|
499 | 472 | key=lambda u: u.repo_name.lower()) |
|
500 | 473 | |
|
501 | 474 | c.group_to_repo_groups = sorted( |
|
502 | 475 | (x.group for x in c.user_group.users_group_repo_group_to_perm), |
|
503 | 476 | key=lambda u: u.group_name.lower()) |
|
504 | 477 | |
|
505 | 478 | c.group_to_review_rules = sorted( |
|
506 | 479 | (x.users_group for x in c.user_group.user_group_review_rules), |
|
507 | 480 | key=lambda u: u.users_group_name.lower()) |
|
508 | 481 | |
|
509 | 482 | return self._get_template_context(c) |
|
510 | 483 | |
|
511 | 484 | @LoginRequired() |
|
512 | 485 | @HasUserGroupPermissionAnyDecorator('usergroup.admin') |
|
513 | 486 | @CSRFRequired() |
|
514 | 487 | @view_config( |
|
515 | 488 | route_name='edit_user_group_advanced_sync', request_method='POST', |
|
516 | 489 | renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako') |
|
517 | 490 | def user_group_edit_advanced_set_synchronization(self): |
|
518 | 491 | _ = self.request.translate |
|
519 | 492 | user_group = self.db_user_group |
|
520 | 493 | user_group_id = user_group.users_group_id |
|
521 | 494 | |
|
522 | 495 | existing = user_group.group_data.get('extern_type') |
|
523 | 496 | |
|
524 | 497 | if existing: |
|
525 | 498 | new_state = user_group.group_data |
|
526 | 499 | new_state['extern_type'] = None |
|
527 | 500 | else: |
|
528 | 501 | new_state = user_group.group_data |
|
529 | 502 | new_state['extern_type'] = 'manual' |
|
530 | 503 | new_state['extern_type_set_by'] = self._rhodecode_user.username |
|
531 | 504 | |
|
532 | 505 | try: |
|
533 | 506 | user_group.group_data = new_state |
|
534 | 507 | Session().add(user_group) |
|
535 | 508 | Session().commit() |
|
536 | 509 | |
|
537 | 510 | h.flash(_('User Group synchronization updated successfully'), |
|
538 | 511 | category='success') |
|
539 | 512 | except Exception: |
|
540 | 513 | log.exception("Exception during sync settings saving") |
|
541 | 514 | h.flash(_('An error occurred during synchronization update'), |
|
542 | 515 | category='error') |
|
543 | 516 | |
|
544 | 517 | raise HTTPFound( |
|
545 | 518 | h.route_path('edit_user_group_advanced', |
|
546 | 519 | user_group_id=user_group_id)) |
@@ -1,647 +1,673 b'' | |||
|
1 | 1 | # -*- coding: utf-8 -*- |
|
2 | 2 | |
|
3 | 3 | # Copyright (C) 2011-2017 RhodeCode GmbH |
|
4 | 4 | # |
|
5 | 5 | # This program is free software: you can redistribute it and/or modify |
|
6 | 6 | # it under the terms of the GNU Affero General Public License, version 3 |
|
7 | 7 | # (only), as published by the Free Software Foundation. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU Affero General Public License |
|
15 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
16 | 16 | # |
|
17 | 17 | # This program is dual-licensed. If you wish to learn more about the |
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | 21 | import logging |
|
22 | 22 | import traceback |
|
23 | 23 | |
|
24 | 24 | from rhodecode.lib.utils2 import safe_str, safe_unicode |
|
25 | 25 | from rhodecode.lib.exceptions import ( |
|
26 | 26 | UserGroupAssignedException, RepoGroupAssignmentError) |
|
27 | 27 | from rhodecode.lib.utils2 import ( |
|
28 | 28 | get_current_rhodecode_user, action_logger_generic) |
|
29 | 29 | from rhodecode.model import BaseModel |
|
30 | 30 | from rhodecode.model.scm import UserGroupList |
|
31 | 31 | from rhodecode.model.db import ( |
|
32 | true, func, User, UserGroupMember, UserGroup, | |
|
32 | joinedload, true, func, User, UserGroupMember, UserGroup, | |
|
33 | 33 | UserGroupRepoToPerm, Permission, UserGroupToPerm, UserUserGroupToPerm, |
|
34 | 34 | UserGroupUserGroupToPerm, UserGroupRepoGroupToPerm) |
|
35 | 35 | |
|
36 | 36 | |
|
37 | 37 | log = logging.getLogger(__name__) |
|
38 | 38 | |
|
39 | 39 | |
|
40 | 40 | class UserGroupModel(BaseModel): |
|
41 | 41 | |
|
42 | 42 | cls = UserGroup |
|
43 | 43 | |
|
44 | 44 | def _get_user_group(self, user_group): |
|
45 | 45 | return self._get_instance(UserGroup, user_group, |
|
46 | 46 | callback=UserGroup.get_by_group_name) |
|
47 | 47 | |
|
48 | 48 | def _create_default_perms(self, user_group): |
|
49 | 49 | # create default permission |
|
50 | 50 | default_perm = 'usergroup.read' |
|
51 | 51 | def_user = User.get_default_user() |
|
52 | 52 | for p in def_user.user_perms: |
|
53 | 53 | if p.permission.permission_name.startswith('usergroup.'): |
|
54 | 54 | default_perm = p.permission.permission_name |
|
55 | 55 | break |
|
56 | 56 | |
|
57 | 57 | user_group_to_perm = UserUserGroupToPerm() |
|
58 | 58 | user_group_to_perm.permission = Permission.get_by_key(default_perm) |
|
59 | 59 | |
|
60 | 60 | user_group_to_perm.user_group = user_group |
|
61 | 61 | user_group_to_perm.user_id = def_user.user_id |
|
62 | 62 | return user_group_to_perm |
|
63 | 63 | |
|
64 | 64 | def update_permissions( |
|
65 | 65 | self, user_group, perm_additions=None, perm_updates=None, |
|
66 | 66 | perm_deletions=None, check_perms=True, cur_user=None): |
|
67 | 67 | |
|
68 | 68 | from rhodecode.lib.auth import HasUserGroupPermissionAny |
|
69 | 69 | if not perm_additions: |
|
70 | 70 | perm_additions = [] |
|
71 | 71 | if not perm_updates: |
|
72 | 72 | perm_updates = [] |
|
73 | 73 | if not perm_deletions: |
|
74 | 74 | perm_deletions = [] |
|
75 | 75 | |
|
76 | 76 | req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin') |
|
77 | 77 | |
|
78 | 78 | changes = { |
|
79 | 79 | 'added': [], |
|
80 | 80 | 'updated': [], |
|
81 | 81 | 'deleted': [] |
|
82 | 82 | } |
|
83 | 83 | # update permissions |
|
84 | 84 | for member_id, perm, member_type in perm_updates: |
|
85 | 85 | member_id = int(member_id) |
|
86 | 86 | if member_type == 'user': |
|
87 | 87 | member_name = User.get(member_id).username |
|
88 | 88 | # this updates existing one |
|
89 | 89 | self.grant_user_permission( |
|
90 | 90 | user_group=user_group, user=member_id, perm=perm |
|
91 | 91 | ) |
|
92 | 92 | else: |
|
93 | 93 | # check if we have permissions to alter this usergroup |
|
94 | 94 | member_name = UserGroup.get(member_id).users_group_name |
|
95 | 95 | if not check_perms or HasUserGroupPermissionAny( |
|
96 | 96 | *req_perms)(member_name, user=cur_user): |
|
97 | 97 | self.grant_user_group_permission( |
|
98 | 98 | target_user_group=user_group, user_group=member_id, perm=perm) |
|
99 | 99 | |
|
100 | 100 | changes['updated'].append({'type': member_type, 'id': member_id, |
|
101 | 101 | 'name': member_name, 'new_perm': perm}) |
|
102 | 102 | |
|
103 | 103 | # set new permissions |
|
104 | 104 | for member_id, perm, member_type in perm_additions: |
|
105 | 105 | member_id = int(member_id) |
|
106 | 106 | if member_type == 'user': |
|
107 | 107 | member_name = User.get(member_id).username |
|
108 | 108 | self.grant_user_permission( |
|
109 | 109 | user_group=user_group, user=member_id, perm=perm) |
|
110 | 110 | else: |
|
111 | 111 | # check if we have permissions to alter this usergroup |
|
112 | 112 | member_name = UserGroup.get(member_id).users_group_name |
|
113 | 113 | if not check_perms or HasUserGroupPermissionAny( |
|
114 | 114 | *req_perms)(member_name, user=cur_user): |
|
115 | 115 | self.grant_user_group_permission( |
|
116 | 116 | target_user_group=user_group, user_group=member_id, perm=perm) |
|
117 | 117 | |
|
118 | 118 | changes['added'].append({'type': member_type, 'id': member_id, |
|
119 | 119 | 'name': member_name, 'new_perm': perm}) |
|
120 | 120 | |
|
121 | 121 | # delete permissions |
|
122 | 122 | for member_id, perm, member_type in perm_deletions: |
|
123 | 123 | member_id = int(member_id) |
|
124 | 124 | if member_type == 'user': |
|
125 | 125 | member_name = User.get(member_id).username |
|
126 | 126 | self.revoke_user_permission(user_group=user_group, user=member_id) |
|
127 | 127 | else: |
|
128 | 128 | # check if we have permissions to alter this usergroup |
|
129 | 129 | member_name = UserGroup.get(member_id).users_group_name |
|
130 | 130 | if not check_perms or HasUserGroupPermissionAny( |
|
131 | 131 | *req_perms)(member_name, user=cur_user): |
|
132 | 132 | self.revoke_user_group_permission( |
|
133 | 133 | target_user_group=user_group, user_group=member_id) |
|
134 | 134 | |
|
135 | 135 | changes['deleted'].append({'type': member_type, 'id': member_id, |
|
136 | 136 | 'name': member_name, 'new_perm': perm}) |
|
137 | 137 | return changes |
|
138 | 138 | |
|
139 | 139 | def get(self, user_group_id, cache=False): |
|
140 | 140 | return UserGroup.get(user_group_id) |
|
141 | 141 | |
|
142 | 142 | def get_group(self, user_group): |
|
143 | 143 | return self._get_user_group(user_group) |
|
144 | 144 | |
|
145 | 145 | def get_by_name(self, name, cache=False, case_insensitive=False): |
|
146 | 146 | return UserGroup.get_by_group_name(name, cache, case_insensitive) |
|
147 | 147 | |
|
148 | 148 | def create(self, name, description, owner, active=True, group_data=None): |
|
149 | 149 | try: |
|
150 | 150 | new_user_group = UserGroup() |
|
151 | 151 | new_user_group.user = self._get_user(owner) |
|
152 | 152 | new_user_group.users_group_name = name |
|
153 | 153 | new_user_group.user_group_description = description |
|
154 | 154 | new_user_group.users_group_active = active |
|
155 | 155 | if group_data: |
|
156 | 156 | new_user_group.group_data = group_data |
|
157 | 157 | self.sa.add(new_user_group) |
|
158 | 158 | perm_obj = self._create_default_perms(new_user_group) |
|
159 | 159 | self.sa.add(perm_obj) |
|
160 | 160 | |
|
161 | 161 | self.grant_user_permission(user_group=new_user_group, |
|
162 | 162 | user=owner, perm='usergroup.admin') |
|
163 | 163 | |
|
164 | 164 | return new_user_group |
|
165 | 165 | except Exception: |
|
166 | 166 | log.error(traceback.format_exc()) |
|
167 | 167 | raise |
|
168 | 168 | |
|
169 | 169 | def _get_memberships_for_user_ids(self, user_group, user_id_list): |
|
170 | 170 | members = [] |
|
171 | 171 | for user_id in user_id_list: |
|
172 | 172 | member = self._get_membership(user_group.users_group_id, user_id) |
|
173 | 173 | members.append(member) |
|
174 | 174 | return members |
|
175 | 175 | |
|
176 | 176 | def _get_added_and_removed_user_ids(self, user_group, user_id_list): |
|
177 | 177 | current_members = user_group.members or [] |
|
178 | 178 | current_members_ids = [m.user.user_id for m in current_members] |
|
179 | 179 | |
|
180 | 180 | added_members = [ |
|
181 | 181 | user_id for user_id in user_id_list |
|
182 | 182 | if user_id not in current_members_ids] |
|
183 | 183 | if user_id_list == []: |
|
184 | 184 | # all members were deleted |
|
185 | 185 | deleted_members = current_members_ids |
|
186 | 186 | else: |
|
187 | 187 | deleted_members = [ |
|
188 | 188 | user_id for user_id in current_members_ids |
|
189 | 189 | if user_id not in user_id_list] |
|
190 | 190 | |
|
191 | 191 | return added_members, deleted_members |
|
192 | 192 | |
|
193 | 193 | def _set_users_as_members(self, user_group, user_ids): |
|
194 | 194 | user_group.members = [] |
|
195 | 195 | self.sa.flush() |
|
196 | 196 | members = self._get_memberships_for_user_ids( |
|
197 | 197 | user_group, user_ids) |
|
198 | 198 | user_group.members = members |
|
199 | 199 | self.sa.add(user_group) |
|
200 | 200 | |
|
201 | 201 | def _update_members_from_user_ids(self, user_group, user_ids): |
|
202 | 202 | added, removed = self._get_added_and_removed_user_ids( |
|
203 | 203 | user_group, user_ids) |
|
204 | 204 | self._set_users_as_members(user_group, user_ids) |
|
205 | 205 | self._log_user_changes('added to', user_group, added) |
|
206 | 206 | self._log_user_changes('removed from', user_group, removed) |
|
207 | 207 | return added, removed |
|
208 | 208 | |
|
209 | 209 | def _clean_members_data(self, members_data): |
|
210 | 210 | if not members_data: |
|
211 | 211 | members_data = [] |
|
212 | 212 | |
|
213 | 213 | members = [] |
|
214 | 214 | for user in members_data: |
|
215 | 215 | uid = int(user['member_user_id']) |
|
216 | 216 | if uid not in members and user['type'] in ['new', 'existing']: |
|
217 | 217 | members.append(uid) |
|
218 | 218 | return members |
|
219 | 219 | |
|
220 | 220 | def update(self, user_group, form_data): |
|
221 | 221 | user_group = self._get_user_group(user_group) |
|
222 | 222 | if 'users_group_name' in form_data: |
|
223 | 223 | user_group.users_group_name = form_data['users_group_name'] |
|
224 | 224 | if 'users_group_active' in form_data: |
|
225 | 225 | user_group.users_group_active = form_data['users_group_active'] |
|
226 | 226 | if 'user_group_description' in form_data: |
|
227 | 227 | user_group.user_group_description = form_data[ |
|
228 | 228 | 'user_group_description'] |
|
229 | 229 | |
|
230 | 230 | # handle owner change |
|
231 | 231 | if 'user' in form_data: |
|
232 | 232 | owner = form_data['user'] |
|
233 | 233 | if isinstance(owner, basestring): |
|
234 | 234 | owner = User.get_by_username(form_data['user']) |
|
235 | 235 | |
|
236 | 236 | if not isinstance(owner, User): |
|
237 | 237 | raise ValueError( |
|
238 | 238 | 'invalid owner for user group: %s' % form_data['user']) |
|
239 | 239 | |
|
240 | 240 | user_group.user = owner |
|
241 | 241 | |
|
242 | 242 | added_user_ids = [] |
|
243 | 243 | removed_user_ids = [] |
|
244 | 244 | if 'users_group_members' in form_data: |
|
245 | 245 | members_id_list = self._clean_members_data( |
|
246 | 246 | form_data['users_group_members']) |
|
247 | 247 | added_user_ids, removed_user_ids = \ |
|
248 | 248 | self._update_members_from_user_ids(user_group, members_id_list) |
|
249 | 249 | |
|
250 | 250 | self.sa.add(user_group) |
|
251 | 251 | return user_group, added_user_ids, removed_user_ids |
|
252 | 252 | |
|
253 | 253 | def delete(self, user_group, force=False): |
|
254 | 254 | """ |
|
255 | 255 | Deletes repository group, unless force flag is used |
|
256 | 256 | raises exception if there are members in that group, else deletes |
|
257 | 257 | group and users |
|
258 | 258 | |
|
259 | 259 | :param user_group: |
|
260 | 260 | :param force: |
|
261 | 261 | """ |
|
262 | 262 | user_group = self._get_user_group(user_group) |
|
263 | 263 | if not user_group: |
|
264 | 264 | return |
|
265 | 265 | |
|
266 | 266 | try: |
|
267 | 267 | # check if this group is not assigned to repo |
|
268 | 268 | assigned_to_repo = [x.repository for x in UserGroupRepoToPerm.query()\ |
|
269 | 269 | .filter(UserGroupRepoToPerm.users_group == user_group).all()] |
|
270 | 270 | # check if this group is not assigned to repo |
|
271 | 271 | assigned_to_repo_group = [x.group for x in UserGroupRepoGroupToPerm.query()\ |
|
272 | 272 | .filter(UserGroupRepoGroupToPerm.users_group == user_group).all()] |
|
273 | 273 | |
|
274 | 274 | if (assigned_to_repo or assigned_to_repo_group) and not force: |
|
275 | 275 | assigned = ','.join(map(safe_str, |
|
276 | 276 | assigned_to_repo+assigned_to_repo_group)) |
|
277 | 277 | |
|
278 | 278 | raise UserGroupAssignedException( |
|
279 | 279 | 'UserGroup assigned to %s' % (assigned,)) |
|
280 | 280 | self.sa.delete(user_group) |
|
281 | 281 | except Exception: |
|
282 | 282 | log.error(traceback.format_exc()) |
|
283 | 283 | raise |
|
284 | 284 | |
|
285 | 285 | def _log_user_changes(self, action, user_group, user_or_users): |
|
286 | 286 | users = user_or_users |
|
287 | 287 | if not isinstance(users, (list, tuple)): |
|
288 | 288 | users = [users] |
|
289 | 289 | |
|
290 | 290 | group_name = user_group.users_group_name |
|
291 | 291 | |
|
292 | 292 | for user_or_user_id in users: |
|
293 | 293 | user = self._get_user(user_or_user_id) |
|
294 | 294 | log_text = 'User {user} {action} {group}'.format( |
|
295 | 295 | action=action, user=user.username, group=group_name) |
|
296 | 296 | action_logger_generic(log_text) |
|
297 | 297 | |
|
298 | 298 | def _find_user_in_group(self, user, user_group): |
|
299 | 299 | user_group_member = None |
|
300 | 300 | for m in user_group.members: |
|
301 | 301 | if m.user_id == user.user_id: |
|
302 | 302 | # Found this user's membership row |
|
303 | 303 | user_group_member = m |
|
304 | 304 | break |
|
305 | 305 | |
|
306 | 306 | return user_group_member |
|
307 | 307 | |
|
308 | 308 | def _get_membership(self, user_group_id, user_id): |
|
309 | 309 | user_group_member = UserGroupMember(user_group_id, user_id) |
|
310 | 310 | return user_group_member |
|
311 | 311 | |
|
312 | 312 | def add_user_to_group(self, user_group, user): |
|
313 | 313 | user_group = self._get_user_group(user_group) |
|
314 | 314 | user = self._get_user(user) |
|
315 | 315 | user_member = self._find_user_in_group(user, user_group) |
|
316 | 316 | if user_member: |
|
317 | 317 | # user already in the group, skip |
|
318 | 318 | return True |
|
319 | 319 | |
|
320 | 320 | member = self._get_membership( |
|
321 | 321 | user_group.users_group_id, user.user_id) |
|
322 | 322 | user_group.members.append(member) |
|
323 | 323 | |
|
324 | 324 | try: |
|
325 | 325 | self.sa.add(member) |
|
326 | 326 | except Exception: |
|
327 | 327 | # what could go wrong here? |
|
328 | 328 | log.error(traceback.format_exc()) |
|
329 | 329 | raise |
|
330 | 330 | |
|
331 | 331 | self._log_user_changes('added to', user_group, user) |
|
332 | 332 | return member |
|
333 | 333 | |
|
334 | 334 | def remove_user_from_group(self, user_group, user): |
|
335 | 335 | user_group = self._get_user_group(user_group) |
|
336 | 336 | user = self._get_user(user) |
|
337 | 337 | user_group_member = self._find_user_in_group(user, user_group) |
|
338 | 338 | |
|
339 | 339 | if not user_group_member: |
|
340 | 340 | # User isn't in that group |
|
341 | 341 | return False |
|
342 | 342 | |
|
343 | 343 | try: |
|
344 | 344 | self.sa.delete(user_group_member) |
|
345 | 345 | except Exception: |
|
346 | 346 | log.error(traceback.format_exc()) |
|
347 | 347 | raise |
|
348 | 348 | |
|
349 | 349 | self._log_user_changes('removed from', user_group, user) |
|
350 | 350 | return True |
|
351 | 351 | |
|
352 | 352 | def has_perm(self, user_group, perm): |
|
353 | 353 | user_group = self._get_user_group(user_group) |
|
354 | 354 | perm = self._get_perm(perm) |
|
355 | 355 | |
|
356 | 356 | return UserGroupToPerm.query()\ |
|
357 | 357 | .filter(UserGroupToPerm.users_group == user_group)\ |
|
358 | 358 | .filter(UserGroupToPerm.permission == perm).scalar() is not None |
|
359 | 359 | |
|
360 | 360 | def grant_perm(self, user_group, perm): |
|
361 | 361 | user_group = self._get_user_group(user_group) |
|
362 | 362 | perm = self._get_perm(perm) |
|
363 | 363 | |
|
364 | 364 | # if this permission is already granted skip it |
|
365 | 365 | _perm = UserGroupToPerm.query()\ |
|
366 | 366 | .filter(UserGroupToPerm.users_group == user_group)\ |
|
367 | 367 | .filter(UserGroupToPerm.permission == perm)\ |
|
368 | 368 | .scalar() |
|
369 | 369 | if _perm: |
|
370 | 370 | return |
|
371 | 371 | |
|
372 | 372 | new = UserGroupToPerm() |
|
373 | 373 | new.users_group = user_group |
|
374 | 374 | new.permission = perm |
|
375 | 375 | self.sa.add(new) |
|
376 | 376 | return new |
|
377 | 377 | |
|
378 | 378 | def revoke_perm(self, user_group, perm): |
|
379 | 379 | user_group = self._get_user_group(user_group) |
|
380 | 380 | perm = self._get_perm(perm) |
|
381 | 381 | |
|
382 | 382 | obj = UserGroupToPerm.query()\ |
|
383 | 383 | .filter(UserGroupToPerm.users_group == user_group)\ |
|
384 | 384 | .filter(UserGroupToPerm.permission == perm).scalar() |
|
385 | 385 | if obj: |
|
386 | 386 | self.sa.delete(obj) |
|
387 | 387 | |
|
388 | 388 | def grant_user_permission(self, user_group, user, perm): |
|
389 | 389 | """ |
|
390 | 390 | Grant permission for user on given user group, or update |
|
391 | 391 | existing one if found |
|
392 | 392 | |
|
393 | 393 | :param user_group: Instance of UserGroup, users_group_id, |
|
394 | 394 | or users_group_name |
|
395 | 395 | :param user: Instance of User, user_id or username |
|
396 | 396 | :param perm: Instance of Permission, or permission_name |
|
397 | 397 | """ |
|
398 | 398 | |
|
399 | 399 | user_group = self._get_user_group(user_group) |
|
400 | 400 | user = self._get_user(user) |
|
401 | 401 | permission = self._get_perm(perm) |
|
402 | 402 | |
|
403 | 403 | # check if we have that permission already |
|
404 | 404 | obj = self.sa.query(UserUserGroupToPerm)\ |
|
405 | 405 | .filter(UserUserGroupToPerm.user == user)\ |
|
406 | 406 | .filter(UserUserGroupToPerm.user_group == user_group)\ |
|
407 | 407 | .scalar() |
|
408 | 408 | if obj is None: |
|
409 | 409 | # create new ! |
|
410 | 410 | obj = UserUserGroupToPerm() |
|
411 | 411 | obj.user_group = user_group |
|
412 | 412 | obj.user = user |
|
413 | 413 | obj.permission = permission |
|
414 | 414 | self.sa.add(obj) |
|
415 | 415 | log.debug('Granted perm %s to %s on %s', perm, user, user_group) |
|
416 | 416 | action_logger_generic( |
|
417 | 417 | 'granted permission: {} to user: {} on usergroup: {}'.format( |
|
418 | 418 | perm, user, user_group), namespace='security.usergroup') |
|
419 | 419 | |
|
420 | 420 | return obj |
|
421 | 421 | |
|
422 | 422 | def revoke_user_permission(self, user_group, user): |
|
423 | 423 | """ |
|
424 | 424 | Revoke permission for user on given user group |
|
425 | 425 | |
|
426 | 426 | :param user_group: Instance of UserGroup, users_group_id, |
|
427 | 427 | or users_group name |
|
428 | 428 | :param user: Instance of User, user_id or username |
|
429 | 429 | """ |
|
430 | 430 | |
|
431 | 431 | user_group = self._get_user_group(user_group) |
|
432 | 432 | user = self._get_user(user) |
|
433 | 433 | |
|
434 | 434 | obj = self.sa.query(UserUserGroupToPerm)\ |
|
435 | 435 | .filter(UserUserGroupToPerm.user == user)\ |
|
436 | 436 | .filter(UserUserGroupToPerm.user_group == user_group)\ |
|
437 | 437 | .scalar() |
|
438 | 438 | if obj: |
|
439 | 439 | self.sa.delete(obj) |
|
440 | 440 | log.debug('Revoked perm on %s on %s', user_group, user) |
|
441 | 441 | action_logger_generic( |
|
442 | 442 | 'revoked permission from user: {} on usergroup: {}'.format( |
|
443 | 443 | user, user_group), namespace='security.usergroup') |
|
444 | 444 | |
|
445 | 445 | def grant_user_group_permission(self, target_user_group, user_group, perm): |
|
446 | 446 | """ |
|
447 | 447 | Grant user group permission for given target_user_group |
|
448 | 448 | |
|
449 | 449 | :param target_user_group: |
|
450 | 450 | :param user_group: |
|
451 | 451 | :param perm: |
|
452 | 452 | """ |
|
453 | 453 | target_user_group = self._get_user_group(target_user_group) |
|
454 | 454 | user_group = self._get_user_group(user_group) |
|
455 | 455 | permission = self._get_perm(perm) |
|
456 | 456 | # forbid assigning same user group to itself |
|
457 | 457 | if target_user_group == user_group: |
|
458 | 458 | raise RepoGroupAssignmentError('target repo:%s cannot be ' |
|
459 | 459 | 'assigned to itself' % target_user_group) |
|
460 | 460 | |
|
461 | 461 | # check if we have that permission already |
|
462 | 462 | obj = self.sa.query(UserGroupUserGroupToPerm)\ |
|
463 | 463 | .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group)\ |
|
464 | 464 | .filter(UserGroupUserGroupToPerm.user_group == user_group)\ |
|
465 | 465 | .scalar() |
|
466 | 466 | if obj is None: |
|
467 | 467 | # create new ! |
|
468 | 468 | obj = UserGroupUserGroupToPerm() |
|
469 | 469 | obj.user_group = user_group |
|
470 | 470 | obj.target_user_group = target_user_group |
|
471 | 471 | obj.permission = permission |
|
472 | 472 | self.sa.add(obj) |
|
473 | 473 | log.debug( |
|
474 | 474 | 'Granted perm %s to %s on %s', perm, target_user_group, user_group) |
|
475 | 475 | action_logger_generic( |
|
476 | 476 | 'granted permission: {} to usergroup: {} on usergroup: {}'.format( |
|
477 | 477 | perm, user_group, target_user_group), |
|
478 | 478 | namespace='security.usergroup') |
|
479 | 479 | |
|
480 | 480 | return obj |
|
481 | 481 | |
|
482 | 482 | def revoke_user_group_permission(self, target_user_group, user_group): |
|
483 | 483 | """ |
|
484 | 484 | Revoke user group permission for given target_user_group |
|
485 | 485 | |
|
486 | 486 | :param target_user_group: |
|
487 | 487 | :param user_group: |
|
488 | 488 | """ |
|
489 | 489 | target_user_group = self._get_user_group(target_user_group) |
|
490 | 490 | user_group = self._get_user_group(user_group) |
|
491 | 491 | |
|
492 | 492 | obj = self.sa.query(UserGroupUserGroupToPerm)\ |
|
493 | 493 | .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group)\ |
|
494 | 494 | .filter(UserGroupUserGroupToPerm.user_group == user_group)\ |
|
495 | 495 | .scalar() |
|
496 | 496 | if obj: |
|
497 | 497 | self.sa.delete(obj) |
|
498 | 498 | log.debug( |
|
499 | 499 | 'Revoked perm on %s on %s', target_user_group, user_group) |
|
500 | 500 | action_logger_generic( |
|
501 | 501 | 'revoked permission from usergroup: {} on usergroup: {}'.format( |
|
502 | 502 | user_group, target_user_group), |
|
503 | 503 | namespace='security.repogroup') |
|
504 | 504 | |
|
505 | def get_perms_summary(self, user_group_id): | |
|
506 | permissions = { | |
|
507 | 'repositories': {}, | |
|
508 | 'repositories_groups': {}, | |
|
509 | } | |
|
510 | ugroup_repo_perms = UserGroupRepoToPerm.query()\ | |
|
511 | .options(joinedload(UserGroupRepoToPerm.permission))\ | |
|
512 | .options(joinedload(UserGroupRepoToPerm.repository))\ | |
|
513 | .filter(UserGroupRepoToPerm.users_group_id == user_group_id)\ | |
|
514 | .all() | |
|
515 | ||
|
516 | for gr in ugroup_repo_perms: | |
|
517 | permissions['repositories'][gr.repository.repo_name] \ | |
|
518 | = gr.permission.permission_name | |
|
519 | ||
|
520 | ugroup_group_perms = UserGroupRepoGroupToPerm.query()\ | |
|
521 | .options(joinedload(UserGroupRepoGroupToPerm.permission))\ | |
|
522 | .options(joinedload(UserGroupRepoGroupToPerm.group))\ | |
|
523 | .filter(UserGroupRepoGroupToPerm.users_group_id == user_group_id)\ | |
|
524 | .all() | |
|
525 | ||
|
526 | for gr in ugroup_group_perms: | |
|
527 | permissions['repositories_groups'][gr.group.group_name] \ | |
|
528 | = gr.permission.permission_name | |
|
529 | return permissions | |
|
530 | ||
|
505 | 531 | def enforce_groups(self, user, groups, extern_type=None): |
|
506 | 532 | user = self._get_user(user) |
|
507 | 533 | current_groups = user.group_member |
|
508 | 534 | |
|
509 | 535 | # find the external created groups, i.e automatically created |
|
510 | 536 | log.debug('Enforcing user group set `%s` on user %s', groups, user) |
|
511 | 537 | # calculate from what groups user should be removed |
|
512 | 538 | # external_groups that are not in groups |
|
513 | 539 | for gr in [x.users_group for x in current_groups]: |
|
514 | 540 | managed = gr.group_data.get('extern_type') |
|
515 | 541 | if managed: |
|
516 | 542 | if gr.users_group_name not in groups: |
|
517 | 543 | log.debug('Removing user %s from user group %s. ' |
|
518 | 544 | 'Group sync managed by: %s', user, gr, managed) |
|
519 | 545 | self.remove_user_from_group(gr, user) |
|
520 | 546 | else: |
|
521 | 547 | log.debug('Skipping removal from group %s since it is ' |
|
522 | 548 | 'not set to be automatically synchronized' % gr) |
|
523 | 549 | |
|
524 | 550 | # now we calculate in which groups user should be == groups params |
|
525 | 551 | owner = User.get_first_super_admin().username |
|
526 | 552 | for gr in set(groups): |
|
527 | 553 | existing_group = UserGroup.get_by_group_name(gr) |
|
528 | 554 | if not existing_group: |
|
529 | 555 | desc = 'Automatically created from plugin:%s' % extern_type |
|
530 | 556 | # we use first admin account to set the owner of the group |
|
531 | 557 | existing_group = UserGroupModel().create( |
|
532 | 558 | gr, desc, owner, group_data={'extern_type': extern_type}) |
|
533 | 559 | |
|
534 | 560 | # we can only add users to groups which have set sync flag via |
|
535 | 561 | # extern_type attribute. |
|
536 | 562 | # This is either set and created via plugins, or manually |
|
537 | 563 | managed = existing_group.group_data.get('extern_type') |
|
538 | 564 | if managed: |
|
539 | 565 | log.debug('Adding user %s to user group %s', user, gr) |
|
540 | 566 | UserGroupModel().add_user_to_group(existing_group, user) |
|
541 | 567 | else: |
|
542 | 568 | log.debug('Skipping addition to group %s since it is ' |
|
543 | 569 | 'not set to be automatically synchronized' % gr) |
|
544 | 570 | |
|
545 | 571 | def change_groups(self, user, groups): |
|
546 | 572 | """ |
|
547 | 573 | This method changes user group assignment |
|
548 | 574 | :param user: User |
|
549 | 575 | :param groups: array of UserGroupModel |
|
550 | 576 | """ |
|
551 | 577 | user = self._get_user(user) |
|
552 | 578 | log.debug('Changing user(%s) assignment to groups(%s)', user, groups) |
|
553 | 579 | current_groups = user.group_member |
|
554 | 580 | current_groups = [x.users_group for x in current_groups] |
|
555 | 581 | |
|
556 | 582 | # calculate from what groups user should be removed/add |
|
557 | 583 | groups = set(groups) |
|
558 | 584 | current_groups = set(current_groups) |
|
559 | 585 | |
|
560 | 586 | groups_to_remove = current_groups - groups |
|
561 | 587 | groups_to_add = groups - current_groups |
|
562 | 588 | |
|
563 | 589 | removed_from_groups = [] |
|
564 | 590 | added_to_groups = [] |
|
565 | 591 | for gr in groups_to_remove: |
|
566 | 592 | log.debug('Removing user %s from user group %s', |
|
567 | 593 | user.username, gr.users_group_name) |
|
568 | 594 | removed_from_groups.append(gr.users_group_id) |
|
569 | 595 | self.remove_user_from_group(gr.users_group_name, user.username) |
|
570 | 596 | for gr in groups_to_add: |
|
571 | 597 | log.debug('Adding user %s to user group %s', |
|
572 | 598 | user.username, gr.users_group_name) |
|
573 | 599 | added_to_groups.append(gr.users_group_id) |
|
574 | 600 | UserGroupModel().add_user_to_group( |
|
575 | 601 | gr.users_group_name, user.username) |
|
576 | 602 | |
|
577 | 603 | return added_to_groups, removed_from_groups |
|
578 | 604 | |
|
579 | 605 | def _serialize_user_group(self, user_group): |
|
580 | 606 | import rhodecode.lib.helpers as h |
|
581 | 607 | return { |
|
582 | 608 | 'id': user_group.users_group_id, |
|
583 | 609 | # TODO: marcink figure out a way to generate the url for the |
|
584 | 610 | # icon |
|
585 | 611 | 'icon_link': '', |
|
586 | 612 | 'value_display': 'Group: %s (%d members)' % ( |
|
587 | 613 | user_group.users_group_name, len(user_group.members),), |
|
588 | 614 | 'value': user_group.users_group_name, |
|
589 | 615 | 'description': user_group.user_group_description, |
|
590 | 616 | 'owner': user_group.user.username, |
|
591 | 617 | |
|
592 | 618 | 'owner_icon': h.gravatar_url(user_group.user.email, 30), |
|
593 | 619 | 'value_display_owner': h.person(user_group.user.email), |
|
594 | 620 | |
|
595 | 621 | 'value_type': 'user_group', |
|
596 | 622 | 'active': user_group.users_group_active, |
|
597 | 623 | } |
|
598 | 624 | |
|
599 | 625 | def get_user_groups(self, name_contains=None, limit=20, only_active=True, |
|
600 | 626 | expand_groups=False): |
|
601 | 627 | query = self.sa.query(UserGroup) |
|
602 | 628 | if only_active: |
|
603 | 629 | query = query.filter(UserGroup.users_group_active == true()) |
|
604 | 630 | |
|
605 | 631 | if name_contains: |
|
606 | 632 | ilike_expression = u'%{}%'.format(safe_unicode(name_contains)) |
|
607 | 633 | query = query.filter( |
|
608 | 634 | UserGroup.users_group_name.ilike(ilike_expression))\ |
|
609 | 635 | .order_by(func.length(UserGroup.users_group_name))\ |
|
610 | 636 | .order_by(UserGroup.users_group_name) |
|
611 | 637 | |
|
612 | 638 | query = query.limit(limit) |
|
613 | 639 | user_groups = query.all() |
|
614 | 640 | perm_set = ['usergroup.read', 'usergroup.write', 'usergroup.admin'] |
|
615 | 641 | user_groups = UserGroupList(user_groups, perm_set=perm_set) |
|
616 | 642 | |
|
617 | 643 | # store same serialize method to extract data from User |
|
618 | 644 | from rhodecode.model.user import UserModel |
|
619 | 645 | serialize_user = UserModel()._serialize_user |
|
620 | 646 | |
|
621 | 647 | _groups = [] |
|
622 | 648 | for group in user_groups: |
|
623 | 649 | entry = self._serialize_user_group(group) |
|
624 | 650 | if expand_groups: |
|
625 | 651 | expanded_members = [] |
|
626 | 652 | for member in group.members: |
|
627 | 653 | expanded_members.append(serialize_user(member.user)) |
|
628 | 654 | entry['members'] = expanded_members |
|
629 | 655 | _groups.append(entry) |
|
630 | 656 | return _groups |
|
631 | 657 | |
|
632 | 658 | @staticmethod |
|
633 | 659 | def get_user_groups_as_dict(user_group): |
|
634 | 660 | import rhodecode.lib.helpers as h |
|
635 | 661 | |
|
636 | 662 | data = { |
|
637 | 663 | 'users_group_id': user_group.users_group_id, |
|
638 | 664 | 'group_name': user_group.users_group_name, |
|
639 | 665 | 'group_description': user_group.user_group_description, |
|
640 | 666 | 'active': user_group.users_group_active, |
|
641 | 667 | "owner": user_group.user.username, |
|
642 | 668 | 'owner_icon': h.gravatar_url(user_group.user.email, 30), |
|
643 | 669 | "owner_data": { |
|
644 | 670 | 'owner': user_group.user.username, |
|
645 | 671 | 'owner_icon': h.gravatar_url(user_group.user.email, 30)} |
|
646 | 672 | } |
|
647 | 673 | return data |
General Comments 0
You need to be logged in to leave comments.
Login now