##// END OF EJS Templates
user-api: use simple schema validator to be consistent how we validate between API and web views.
marcink -
r1832:d176880c default
parent child Browse files
Show More
@@ -1,192 +1,206 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import mock
21 import mock
22 import pytest
22 import pytest
23
23
24 from rhodecode.lib.auth import check_password
24 from rhodecode.lib.auth import check_password
25 from rhodecode.model.user import UserModel
25 from rhodecode.model.user import UserModel
26 from rhodecode.tests import (
26 from rhodecode.tests import (
27 TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_EMAIL)
27 TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_EMAIL)
28 from rhodecode.api.tests.utils import (
28 from rhodecode.api.tests.utils import (
29 build_data, api_call, assert_ok, assert_error, jsonify, crash)
29 build_data, api_call, assert_ok, assert_error, jsonify, crash)
30 from rhodecode.tests.fixture import Fixture
30 from rhodecode.tests.fixture import Fixture
31 from rhodecode.model.db import RepoGroup
31 from rhodecode.model.db import RepoGroup
32
32
33
33
34 # TODO: mikhail: remove fixture from here
34 # TODO: mikhail: remove fixture from here
35 fixture = Fixture()
35 fixture = Fixture()
36
36
37
37
38 @pytest.mark.usefixtures("testuser_api", "app")
38 @pytest.mark.usefixtures("testuser_api", "app")
39 class TestCreateUser(object):
39 class TestCreateUser(object):
40 def test_api_create_existing_user(self):
40 def test_api_create_existing_user(self):
41 id_, params = build_data(
41 id_, params = build_data(
42 self.apikey, 'create_user',
42 self.apikey, 'create_user',
43 username=TEST_USER_ADMIN_LOGIN,
43 username=TEST_USER_ADMIN_LOGIN,
44 email='test@foo.com',
44 email='test@foo.com',
45 password='trololo')
45 password='trololo')
46 response = api_call(self.app, params)
46 response = api_call(self.app, params)
47
47
48 expected = "user `%s` already exist" % (TEST_USER_ADMIN_LOGIN,)
48 expected = "user `%s` already exist" % (TEST_USER_ADMIN_LOGIN,)
49 assert_error(id_, expected, given=response.body)
49 assert_error(id_, expected, given=response.body)
50
50
51 def test_api_create_user_with_existing_email(self):
51 def test_api_create_user_with_existing_email(self):
52 id_, params = build_data(
52 id_, params = build_data(
53 self.apikey, 'create_user',
53 self.apikey, 'create_user',
54 username=TEST_USER_ADMIN_LOGIN + 'new',
54 username=TEST_USER_ADMIN_LOGIN + 'new',
55 email=TEST_USER_REGULAR_EMAIL,
55 email=TEST_USER_REGULAR_EMAIL,
56 password='trololo')
56 password='trololo')
57 response = api_call(self.app, params)
57 response = api_call(self.app, params)
58
58
59 expected = "email `%s` already exist" % (TEST_USER_REGULAR_EMAIL,)
59 expected = "email `%s` already exist" % (TEST_USER_REGULAR_EMAIL,)
60 assert_error(id_, expected, given=response.body)
60 assert_error(id_, expected, given=response.body)
61
61
62 def test_api_create_user_with_wrong_username(self):
63 bad_username = '<> HELLO WORLD <>'
64 id_, params = build_data(
65 self.apikey, 'create_user',
66 username=bad_username,
67 email='new@email.com',
68 password='trololo')
69 response = api_call(self.app, params)
70
71 expected = {'username':
72 "Username may only contain alphanumeric characters "
73 "underscores, periods or dashes and must begin with "
74 "alphanumeric character or underscore"}
75 assert_error(id_, expected, given=response.body)
76
62 def test_api_create_user(self):
77 def test_api_create_user(self):
63 username = 'test_new_api_user'
78 username = 'test_new_api_user'
64 email = username + "@foo.com"
79 email = username + "@foo.com"
65
80
66 id_, params = build_data(
81 id_, params = build_data(
67 self.apikey, 'create_user',
82 self.apikey, 'create_user',
68 username=username,
83 username=username,
69 email=email,
84 email=email,
70 password='example')
85 password='example')
71 response = api_call(self.app, params)
86 response = api_call(self.app, params)
72
87
73 usr = UserModel().get_by_username(username)
88 usr = UserModel().get_by_username(username)
74 ret = {
89 ret = {
75 'msg': 'created new user `%s`' % (username,),
90 'msg': 'created new user `%s`' % (username,),
76 'user': jsonify(usr.get_api_data(include_secrets=True)),
91 'user': jsonify(usr.get_api_data(include_secrets=True)),
77 }
92 }
78 try:
93 try:
79 expected = ret
94 expected = ret
80 assert check_password('example', usr.password)
95 assert check_password('example', usr.password)
81 assert_ok(id_, expected, given=response.body)
96 assert_ok(id_, expected, given=response.body)
82 finally:
97 finally:
83 fixture.destroy_user(usr.user_id)
98 fixture.destroy_user(usr.user_id)
84
99
85 def test_api_create_user_without_password(self):
100 def test_api_create_user_without_password(self):
86 username = 'test_new_api_user_passwordless'
101 username = 'test_new_api_user_passwordless'
87 email = username + "@foo.com"
102 email = username + "@foo.com"
88
103
89 id_, params = build_data(
104 id_, params = build_data(
90 self.apikey, 'create_user',
105 self.apikey, 'create_user',
91 username=username,
106 username=username,
92 email=email)
107 email=email)
93 response = api_call(self.app, params)
108 response = api_call(self.app, params)
94
109
95 usr = UserModel().get_by_username(username)
110 usr = UserModel().get_by_username(username)
96 ret = {
111 ret = {
97 'msg': 'created new user `%s`' % (username,),
112 'msg': 'created new user `%s`' % (username,),
98 'user': jsonify(usr.get_api_data(include_secrets=True)),
113 'user': jsonify(usr.get_api_data(include_secrets=True)),
99 }
114 }
100 try:
115 try:
101 expected = ret
116 expected = ret
102 assert_ok(id_, expected, given=response.body)
117 assert_ok(id_, expected, given=response.body)
103 finally:
118 finally:
104 fixture.destroy_user(usr.user_id)
119 fixture.destroy_user(usr.user_id)
105
120
106 def test_api_create_user_with_extern_name(self):
121 def test_api_create_user_with_extern_name(self):
107 username = 'test_new_api_user_passwordless'
122 username = 'test_new_api_user_passwordless'
108 email = username + "@foo.com"
123 email = username + "@foo.com"
109
124
110 id_, params = build_data(
125 id_, params = build_data(
111 self.apikey, 'create_user',
126 self.apikey, 'create_user',
112 username=username,
127 username=username,
113 email=email, extern_name='rhodecode')
128 email=email, extern_name='rhodecode')
114 response = api_call(self.app, params)
129 response = api_call(self.app, params)
115
130
116 usr = UserModel().get_by_username(username)
131 usr = UserModel().get_by_username(username)
117 ret = {
132 ret = {
118 'msg': 'created new user `%s`' % (username,),
133 'msg': 'created new user `%s`' % (username,),
119 'user': jsonify(usr.get_api_data(include_secrets=True)),
134 'user': jsonify(usr.get_api_data(include_secrets=True)),
120 }
135 }
121 try:
136 try:
122 expected = ret
137 expected = ret
123 assert_ok(id_, expected, given=response.body)
138 assert_ok(id_, expected, given=response.body)
124 finally:
139 finally:
125 fixture.destroy_user(usr.user_id)
140 fixture.destroy_user(usr.user_id)
126
141
127 def test_api_create_user_with_password_change(self):
142 def test_api_create_user_with_password_change(self):
128 username = 'test_new_api_user_password_change'
143 username = 'test_new_api_user_password_change'
129 email = username + "@foo.com"
144 email = username + "@foo.com"
130
145
131 id_, params = build_data(
146 id_, params = build_data(
132 self.apikey, 'create_user',
147 self.apikey, 'create_user',
133 username=username,
148 username=username,
134 email=email, extern_name='rhodecode',
149 email=email, extern_name='rhodecode',
135 force_password_change=True)
150 force_password_change=True)
136 response = api_call(self.app, params)
151 response = api_call(self.app, params)
137
152
138 usr = UserModel().get_by_username(username)
153 usr = UserModel().get_by_username(username)
139 ret = {
154 ret = {
140 'msg': 'created new user `%s`' % (username,),
155 'msg': 'created new user `%s`' % (username,),
141 'user': jsonify(usr.get_api_data(include_secrets=True)),
156 'user': jsonify(usr.get_api_data(include_secrets=True)),
142 }
157 }
143 try:
158 try:
144 expected = ret
159 expected = ret
145 assert_ok(id_, expected, given=response.body)
160 assert_ok(id_, expected, given=response.body)
146 finally:
161 finally:
147 fixture.destroy_user(usr.user_id)
162 fixture.destroy_user(usr.user_id)
148
163
149 def test_api_create_user_with_personal_repo_group(self):
164 def test_api_create_user_with_personal_repo_group(self):
150 username = 'test_new_api_user_personal_group'
165 username = 'test_new_api_user_personal_group'
151 email = username + "@foo.com"
166 email = username + "@foo.com"
152
167
153 id_, params = build_data(
168 id_, params = build_data(
154 self.apikey, 'create_user',
169 self.apikey, 'create_user',
155 username=username,
170 username=username,
156 email=email, extern_name='rhodecode',
171 email=email, extern_name='rhodecode',
157 create_personal_repo_group=True)
172 create_personal_repo_group=True)
158 response = api_call(self.app, params)
173 response = api_call(self.app, params)
159
174
160 usr = UserModel().get_by_username(username)
175 usr = UserModel().get_by_username(username)
161 ret = {
176 ret = {
162 'msg': 'created new user `%s`' % (username,),
177 'msg': 'created new user `%s`' % (username,),
163 'user': jsonify(usr.get_api_data(include_secrets=True)),
178 'user': jsonify(usr.get_api_data(include_secrets=True)),
164 }
179 }
165
180
166 personal_group = RepoGroup.get_by_group_name(username)
181 personal_group = RepoGroup.get_by_group_name(username)
167 assert personal_group
182 assert personal_group
168 assert personal_group.personal == True
183 assert personal_group.personal == True
169 assert personal_group.user.username == username
184 assert personal_group.user.username == username
170
185
171 try:
186 try:
172 expected = ret
187 expected = ret
173 assert_ok(id_, expected, given=response.body)
188 assert_ok(id_, expected, given=response.body)
174 finally:
189 finally:
175 fixture.destroy_repo_group(username)
190 fixture.destroy_repo_group(username)
176 fixture.destroy_user(usr.user_id)
191 fixture.destroy_user(usr.user_id)
177
192
178
179 @mock.patch.object(UserModel, 'create_or_update', crash)
193 @mock.patch.object(UserModel, 'create_or_update', crash)
180 def test_api_create_user_when_exception_happened(self):
194 def test_api_create_user_when_exception_happened(self):
181
195
182 username = 'test_new_api_user'
196 username = 'test_new_api_user'
183 email = username + "@foo.com"
197 email = username + "@foo.com"
184
198
185 id_, params = build_data(
199 id_, params = build_data(
186 self.apikey, 'create_user',
200 self.apikey, 'create_user',
187 username=username,
201 username=username,
188 email=email,
202 email=email,
189 password='trololo')
203 password='trololo')
190 response = api_call(self.app, params)
204 response = api_call(self.app, params)
191 expected = 'failed to create user `%s`' % (username,)
205 expected = 'failed to create user `%s`' % (username,)
192 assert_error(id_, expected, given=response.body)
206 assert_error(id_, expected, given=response.body)
@@ -1,529 +1,560 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22
22
23 from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCForbidden
23 from rhodecode.api import (
24 jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError)
24 from rhodecode.api.utils import (
25 from rhodecode.api.utils import (
25 Optional, OAttr, has_superadmin_permission, get_user_or_error, store_update)
26 Optional, OAttr, has_superadmin_permission, get_user_or_error, store_update)
26 from rhodecode.lib import audit_logger
27 from rhodecode.lib import audit_logger
27 from rhodecode.lib.auth import AuthUser, PasswordGenerator
28 from rhodecode.lib.auth import AuthUser, PasswordGenerator
28 from rhodecode.lib.exceptions import DefaultUserException
29 from rhodecode.lib.exceptions import DefaultUserException
29 from rhodecode.lib.utils2 import safe_int, str2bool
30 from rhodecode.lib.utils2 import safe_int, str2bool
30 from rhodecode.model.db import Session, User, Repository
31 from rhodecode.model.db import Session, User, Repository
31 from rhodecode.model.user import UserModel
32 from rhodecode.model.user import UserModel
33 from rhodecode.model import validation_schema
34 from rhodecode.model.validation_schema.schemas import user_schema
32
35
33 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
34
37
35
38
36 @jsonrpc_method()
39 @jsonrpc_method()
37 def get_user(request, apiuser, userid=Optional(OAttr('apiuser'))):
40 def get_user(request, apiuser, userid=Optional(OAttr('apiuser'))):
38 """
41 """
39 Returns the information associated with a username or userid.
42 Returns the information associated with a username or userid.
40
43
41 * If the ``userid`` is not set, this command returns the information
44 * If the ``userid`` is not set, this command returns the information
42 for the ``userid`` calling the method.
45 for the ``userid`` calling the method.
43
46
44 .. note::
47 .. note::
45
48
46 Normal users may only run this command against their ``userid``. For
49 Normal users may only run this command against their ``userid``. For
47 full privileges you must run this command using an |authtoken| with
50 full privileges you must run this command using an |authtoken| with
48 admin rights.
51 admin rights.
49
52
50 :param apiuser: This is filled automatically from the |authtoken|.
53 :param apiuser: This is filled automatically from the |authtoken|.
51 :type apiuser: AuthUser
54 :type apiuser: AuthUser
52 :param userid: Sets the userid for which data will be returned.
55 :param userid: Sets the userid for which data will be returned.
53 :type userid: Optional(str or int)
56 :type userid: Optional(str or int)
54
57
55 Example output:
58 Example output:
56
59
57 .. code-block:: bash
60 .. code-block:: bash
58
61
59 {
62 {
60 "error": null,
63 "error": null,
61 "id": <id>,
64 "id": <id>,
62 "result": {
65 "result": {
63 "active": true,
66 "active": true,
64 "admin": false,
67 "admin": false,
65 "api_keys": [ list of keys ],
68 "api_keys": [ list of keys ],
66 "auth_tokens": [ list of tokens with details ],
69 "auth_tokens": [ list of tokens with details ],
67 "email": "user@example.com",
70 "email": "user@example.com",
68 "emails": [
71 "emails": [
69 "user@example.com"
72 "user@example.com"
70 ],
73 ],
71 "extern_name": "rhodecode",
74 "extern_name": "rhodecode",
72 "extern_type": "rhodecode",
75 "extern_type": "rhodecode",
73 "firstname": "username",
76 "firstname": "username",
74 "ip_addresses": [],
77 "ip_addresses": [],
75 "language": null,
78 "language": null,
76 "last_login": "Timestamp",
79 "last_login": "Timestamp",
77 "last_activity": "Timestamp",
80 "last_activity": "Timestamp",
78 "lastname": "surnae",
81 "lastname": "surnae",
79 "permissions": {
82 "permissions": {
80 "global": [
83 "global": [
81 "hg.inherit_default_perms.true",
84 "hg.inherit_default_perms.true",
82 "usergroup.read",
85 "usergroup.read",
83 "hg.repogroup.create.false",
86 "hg.repogroup.create.false",
84 "hg.create.none",
87 "hg.create.none",
85 "hg.password_reset.enabled",
88 "hg.password_reset.enabled",
86 "hg.extern_activate.manual",
89 "hg.extern_activate.manual",
87 "hg.create.write_on_repogroup.false",
90 "hg.create.write_on_repogroup.false",
88 "hg.usergroup.create.false",
91 "hg.usergroup.create.false",
89 "group.none",
92 "group.none",
90 "repository.none",
93 "repository.none",
91 "hg.register.none",
94 "hg.register.none",
92 "hg.fork.repository"
95 "hg.fork.repository"
93 ],
96 ],
94 "repositories": { "username/example": "repository.write"},
97 "repositories": { "username/example": "repository.write"},
95 "repositories_groups": { "user-group/repo": "group.none" },
98 "repositories_groups": { "user-group/repo": "group.none" },
96 "user_groups": { "user_group_name": "usergroup.read" }
99 "user_groups": { "user_group_name": "usergroup.read" }
97 },
100 },
98 "user_id": 32,
101 "user_id": 32,
99 "username": "username"
102 "username": "username"
100 }
103 }
101 }
104 }
102 """
105 """
103
106
104 if not has_superadmin_permission(apiuser):
107 if not has_superadmin_permission(apiuser):
105 # make sure normal user does not pass someone else userid,
108 # make sure normal user does not pass someone else userid,
106 # he is not allowed to do that
109 # he is not allowed to do that
107 if not isinstance(userid, Optional) and userid != apiuser.user_id:
110 if not isinstance(userid, Optional) and userid != apiuser.user_id:
108 raise JSONRPCError('userid is not the same as your user')
111 raise JSONRPCError('userid is not the same as your user')
109
112
110 userid = Optional.extract(userid, evaluate_locals=locals())
113 userid = Optional.extract(userid, evaluate_locals=locals())
111 userid = getattr(userid, 'user_id', userid)
114 userid = getattr(userid, 'user_id', userid)
112
115
113 user = get_user_or_error(userid)
116 user = get_user_or_error(userid)
114 data = user.get_api_data(include_secrets=True)
117 data = user.get_api_data(include_secrets=True)
115 data['permissions'] = AuthUser(user_id=user.user_id).permissions
118 data['permissions'] = AuthUser(user_id=user.user_id).permissions
116 return data
119 return data
117
120
118
121
119 @jsonrpc_method()
122 @jsonrpc_method()
120 def get_users(request, apiuser):
123 def get_users(request, apiuser):
121 """
124 """
122 Lists all users in the |RCE| user database.
125 Lists all users in the |RCE| user database.
123
126
124 This command can only be run using an |authtoken| with admin rights to
127 This command can only be run using an |authtoken| with admin rights to
125 the specified repository.
128 the specified repository.
126
129
127 This command takes the following options:
130 This command takes the following options:
128
131
129 :param apiuser: This is filled automatically from the |authtoken|.
132 :param apiuser: This is filled automatically from the |authtoken|.
130 :type apiuser: AuthUser
133 :type apiuser: AuthUser
131
134
132 Example output:
135 Example output:
133
136
134 .. code-block:: bash
137 .. code-block:: bash
135
138
136 id : <id_given_in_input>
139 id : <id_given_in_input>
137 result: [<user_object>, ...]
140 result: [<user_object>, ...]
138 error: null
141 error: null
139 """
142 """
140
143
141 if not has_superadmin_permission(apiuser):
144 if not has_superadmin_permission(apiuser):
142 raise JSONRPCForbidden()
145 raise JSONRPCForbidden()
143
146
144 result = []
147 result = []
145 users_list = User.query().order_by(User.username) \
148 users_list = User.query().order_by(User.username) \
146 .filter(User.username != User.DEFAULT_USER) \
149 .filter(User.username != User.DEFAULT_USER) \
147 .all()
150 .all()
148 for user in users_list:
151 for user in users_list:
149 result.append(user.get_api_data(include_secrets=True))
152 result.append(user.get_api_data(include_secrets=True))
150 return result
153 return result
151
154
152
155
153 @jsonrpc_method()
156 @jsonrpc_method()
154 def create_user(request, apiuser, username, email, password=Optional(''),
157 def create_user(request, apiuser, username, email, password=Optional(''),
155 firstname=Optional(''), lastname=Optional(''),
158 firstname=Optional(''), lastname=Optional(''),
156 active=Optional(True), admin=Optional(False),
159 active=Optional(True), admin=Optional(False),
157 extern_name=Optional('rhodecode'),
160 extern_name=Optional('rhodecode'),
158 extern_type=Optional('rhodecode'),
161 extern_type=Optional('rhodecode'),
159 force_password_change=Optional(False),
162 force_password_change=Optional(False),
160 create_personal_repo_group=Optional(None)):
163 create_personal_repo_group=Optional(None)):
161 """
164 """
162 Creates a new user and returns the new user object.
165 Creates a new user and returns the new user object.
163
166
164 This command can only be run using an |authtoken| with admin rights to
167 This command can only be run using an |authtoken| with admin rights to
165 the specified repository.
168 the specified repository.
166
169
167 This command takes the following options:
170 This command takes the following options:
168
171
169 :param apiuser: This is filled automatically from the |authtoken|.
172 :param apiuser: This is filled automatically from the |authtoken|.
170 :type apiuser: AuthUser
173 :type apiuser: AuthUser
171 :param username: Set the new username.
174 :param username: Set the new username.
172 :type username: str or int
175 :type username: str or int
173 :param email: Set the user email address.
176 :param email: Set the user email address.
174 :type email: str
177 :type email: str
175 :param password: Set the new user password.
178 :param password: Set the new user password.
176 :type password: Optional(str)
179 :type password: Optional(str)
177 :param firstname: Set the new user firstname.
180 :param firstname: Set the new user firstname.
178 :type firstname: Optional(str)
181 :type firstname: Optional(str)
179 :param lastname: Set the new user surname.
182 :param lastname: Set the new user surname.
180 :type lastname: Optional(str)
183 :type lastname: Optional(str)
181 :param active: Set the user as active.
184 :param active: Set the user as active.
182 :type active: Optional(``True`` | ``False``)
185 :type active: Optional(``True`` | ``False``)
183 :param admin: Give the new user admin rights.
186 :param admin: Give the new user admin rights.
184 :type admin: Optional(``True`` | ``False``)
187 :type admin: Optional(``True`` | ``False``)
185 :param extern_name: Set the authentication plugin name.
188 :param extern_name: Set the authentication plugin name.
186 Using LDAP this is filled with LDAP UID.
189 Using LDAP this is filled with LDAP UID.
187 :type extern_name: Optional(str)
190 :type extern_name: Optional(str)
188 :param extern_type: Set the new user authentication plugin.
191 :param extern_type: Set the new user authentication plugin.
189 :type extern_type: Optional(str)
192 :type extern_type: Optional(str)
190 :param force_password_change: Force the new user to change password
193 :param force_password_change: Force the new user to change password
191 on next login.
194 on next login.
192 :type force_password_change: Optional(``True`` | ``False``)
195 :type force_password_change: Optional(``True`` | ``False``)
193 :param create_personal_repo_group: Create personal repo group for this user
196 :param create_personal_repo_group: Create personal repo group for this user
194 :type create_personal_repo_group: Optional(``True`` | ``False``)
197 :type create_personal_repo_group: Optional(``True`` | ``False``)
195
198
196 Example output:
199 Example output:
197
200
198 .. code-block:: bash
201 .. code-block:: bash
199
202
200 id : <id_given_in_input>
203 id : <id_given_in_input>
201 result: {
204 result: {
202 "msg" : "created new user `<username>`",
205 "msg" : "created new user `<username>`",
203 "user": <user_obj>
206 "user": <user_obj>
204 }
207 }
205 error: null
208 error: null
206
209
207 Example error output:
210 Example error output:
208
211
209 .. code-block:: bash
212 .. code-block:: bash
210
213
211 id : <id_given_in_input>
214 id : <id_given_in_input>
212 result : null
215 result : null
213 error : {
216 error : {
214 "user `<username>` already exist"
217 "user `<username>` already exist"
215 or
218 or
216 "email `<email>` already exist"
219 "email `<email>` already exist"
217 or
220 or
218 "failed to create user `<username>`"
221 "failed to create user `<username>`"
219 }
222 }
220
223
221 """
224 """
222 if not has_superadmin_permission(apiuser):
225 if not has_superadmin_permission(apiuser):
223 raise JSONRPCForbidden()
226 raise JSONRPCForbidden()
224
227
225 if UserModel().get_by_username(username):
228 if UserModel().get_by_username(username):
226 raise JSONRPCError("user `%s` already exist" % (username,))
229 raise JSONRPCError("user `%s` already exist" % (username,))
227
230
228 if UserModel().get_by_email(email, case_insensitive=True):
231 if UserModel().get_by_email(email, case_insensitive=True):
229 raise JSONRPCError("email `%s` already exist" % (email,))
232 raise JSONRPCError("email `%s` already exist" % (email,))
230
233
231 # generate random password if we actually given the
234 # generate random password if we actually given the
232 # extern_name and it's not rhodecode
235 # extern_name and it's not rhodecode
233 if (not isinstance(extern_name, Optional) and
236 if (not isinstance(extern_name, Optional) and
234 Optional.extract(extern_name) != 'rhodecode'):
237 Optional.extract(extern_name) != 'rhodecode'):
235 # generate temporary password if user is external
238 # generate temporary password if user is external
236 password = PasswordGenerator().gen_password(length=16)
239 password = PasswordGenerator().gen_password(length=16)
237 create_repo_group = Optional.extract(create_personal_repo_group)
240 create_repo_group = Optional.extract(create_personal_repo_group)
238 if isinstance(create_repo_group, basestring):
241 if isinstance(create_repo_group, basestring):
239 create_repo_group = str2bool(create_repo_group)
242 create_repo_group = str2bool(create_repo_group)
240
243
244 username = Optional.extract(username)
245 password = Optional.extract(password)
246 email = Optional.extract(email)
247 first_name = Optional.extract(firstname)
248 last_name = Optional.extract(lastname)
249 active = Optional.extract(active)
250 admin = Optional.extract(admin)
251 extern_type = Optional.extract(extern_type)
252 extern_name = Optional.extract(extern_name)
253
254 schema = user_schema.UserSchema().bind(
255 # user caller
256 user=apiuser)
257 try:
258 schema_data = schema.deserialize(dict(
259 username=username,
260 email=email,
261 password=password,
262 first_name=first_name,
263 last_name=last_name,
264 active=active,
265 admin=admin,
266 extern_type=extern_type,
267 extern_name=extern_name,
268 ))
269 except validation_schema.Invalid as err:
270 raise JSONRPCValidationError(colander_exc=err)
271
241 try:
272 try:
242 user = UserModel().create_or_update(
273 user = UserModel().create_or_update(
243 username=Optional.extract(username),
274 username=schema_data['username'],
244 password=Optional.extract(password),
275 password=schema_data['password'],
245 email=Optional.extract(email),
276 email=schema_data['email'],
246 firstname=Optional.extract(firstname),
277 firstname=schema_data['first_name'],
247 lastname=Optional.extract(lastname),
278 lastname=schema_data['last_name'],
248 active=Optional.extract(active),
279 active=schema_data['active'],
249 admin=Optional.extract(admin),
280 admin=schema_data['admin'],
250 extern_type=Optional.extract(extern_type),
281 extern_type=schema_data['extern_type'],
251 extern_name=Optional.extract(extern_name),
282 extern_name=schema_data['extern_name'],
252 force_password_change=Optional.extract(force_password_change),
283 force_password_change=Optional.extract(force_password_change),
253 create_repo_group=create_repo_group
284 create_repo_group=create_repo_group
254 )
285 )
255 Session().flush()
286 Session().flush()
256 creation_data = user.get_api_data()
287 creation_data = user.get_api_data()
257 audit_logger.store_api(
288 audit_logger.store_api(
258 'user.create', action_data={'data': creation_data},
289 'user.create', action_data={'data': creation_data},
259 user=apiuser)
290 user=apiuser)
260
291
261 Session().commit()
292 Session().commit()
262 return {
293 return {
263 'msg': 'created new user `%s`' % username,
294 'msg': 'created new user `%s`' % username,
264 'user': user.get_api_data(include_secrets=True)
295 'user': user.get_api_data(include_secrets=True)
265 }
296 }
266 except Exception:
297 except Exception:
267 log.exception('Error occurred during creation of user')
298 log.exception('Error occurred during creation of user')
268 raise JSONRPCError('failed to create user `%s`' % (username,))
299 raise JSONRPCError('failed to create user `%s`' % (username,))
269
300
270
301
271 @jsonrpc_method()
302 @jsonrpc_method()
272 def update_user(request, apiuser, userid, username=Optional(None),
303 def update_user(request, apiuser, userid, username=Optional(None),
273 email=Optional(None), password=Optional(None),
304 email=Optional(None), password=Optional(None),
274 firstname=Optional(None), lastname=Optional(None),
305 firstname=Optional(None), lastname=Optional(None),
275 active=Optional(None), admin=Optional(None),
306 active=Optional(None), admin=Optional(None),
276 extern_type=Optional(None), extern_name=Optional(None), ):
307 extern_type=Optional(None), extern_name=Optional(None), ):
277 """
308 """
278 Updates the details for the specified user, if that user exists.
309 Updates the details for the specified user, if that user exists.
279
310
280 This command can only be run using an |authtoken| with admin rights to
311 This command can only be run using an |authtoken| with admin rights to
281 the specified repository.
312 the specified repository.
282
313
283 This command takes the following options:
314 This command takes the following options:
284
315
285 :param apiuser: This is filled automatically from |authtoken|.
316 :param apiuser: This is filled automatically from |authtoken|.
286 :type apiuser: AuthUser
317 :type apiuser: AuthUser
287 :param userid: Set the ``userid`` to update.
318 :param userid: Set the ``userid`` to update.
288 :type userid: str or int
319 :type userid: str or int
289 :param username: Set the new username.
320 :param username: Set the new username.
290 :type username: str or int
321 :type username: str or int
291 :param email: Set the new email.
322 :param email: Set the new email.
292 :type email: str
323 :type email: str
293 :param password: Set the new password.
324 :param password: Set the new password.
294 :type password: Optional(str)
325 :type password: Optional(str)
295 :param firstname: Set the new first name.
326 :param firstname: Set the new first name.
296 :type firstname: Optional(str)
327 :type firstname: Optional(str)
297 :param lastname: Set the new surname.
328 :param lastname: Set the new surname.
298 :type lastname: Optional(str)
329 :type lastname: Optional(str)
299 :param active: Set the new user as active.
330 :param active: Set the new user as active.
300 :type active: Optional(``True`` | ``False``)
331 :type active: Optional(``True`` | ``False``)
301 :param admin: Give the user admin rights.
332 :param admin: Give the user admin rights.
302 :type admin: Optional(``True`` | ``False``)
333 :type admin: Optional(``True`` | ``False``)
303 :param extern_name: Set the authentication plugin user name.
334 :param extern_name: Set the authentication plugin user name.
304 Using LDAP this is filled with LDAP UID.
335 Using LDAP this is filled with LDAP UID.
305 :type extern_name: Optional(str)
336 :type extern_name: Optional(str)
306 :param extern_type: Set the authentication plugin type.
337 :param extern_type: Set the authentication plugin type.
307 :type extern_type: Optional(str)
338 :type extern_type: Optional(str)
308
339
309
340
310 Example output:
341 Example output:
311
342
312 .. code-block:: bash
343 .. code-block:: bash
313
344
314 id : <id_given_in_input>
345 id : <id_given_in_input>
315 result: {
346 result: {
316 "msg" : "updated user ID:<userid> <username>",
347 "msg" : "updated user ID:<userid> <username>",
317 "user": <user_object>,
348 "user": <user_object>,
318 }
349 }
319 error: null
350 error: null
320
351
321 Example error output:
352 Example error output:
322
353
323 .. code-block:: bash
354 .. code-block:: bash
324
355
325 id : <id_given_in_input>
356 id : <id_given_in_input>
326 result : null
357 result : null
327 error : {
358 error : {
328 "failed to update user `<username>`"
359 "failed to update user `<username>`"
329 }
360 }
330
361
331 """
362 """
332 if not has_superadmin_permission(apiuser):
363 if not has_superadmin_permission(apiuser):
333 raise JSONRPCForbidden()
364 raise JSONRPCForbidden()
334
365
335 user = get_user_or_error(userid)
366 user = get_user_or_error(userid)
336 old_data = user.get_api_data()
367 old_data = user.get_api_data()
337 # only non optional arguments will be stored in updates
368 # only non optional arguments will be stored in updates
338 updates = {}
369 updates = {}
339
370
340 try:
371 try:
341
372
342 store_update(updates, username, 'username')
373 store_update(updates, username, 'username')
343 store_update(updates, password, 'password')
374 store_update(updates, password, 'password')
344 store_update(updates, email, 'email')
375 store_update(updates, email, 'email')
345 store_update(updates, firstname, 'name')
376 store_update(updates, firstname, 'name')
346 store_update(updates, lastname, 'lastname')
377 store_update(updates, lastname, 'lastname')
347 store_update(updates, active, 'active')
378 store_update(updates, active, 'active')
348 store_update(updates, admin, 'admin')
379 store_update(updates, admin, 'admin')
349 store_update(updates, extern_name, 'extern_name')
380 store_update(updates, extern_name, 'extern_name')
350 store_update(updates, extern_type, 'extern_type')
381 store_update(updates, extern_type, 'extern_type')
351
382
352 user = UserModel().update_user(user, **updates)
383 user = UserModel().update_user(user, **updates)
353 audit_logger.store_api(
384 audit_logger.store_api(
354 'user.edit', action_data={'old_data': old_data},
385 'user.edit', action_data={'old_data': old_data},
355 user=apiuser)
386 user=apiuser)
356 Session().commit()
387 Session().commit()
357 return {
388 return {
358 'msg': 'updated user ID:%s %s' % (user.user_id, user.username),
389 'msg': 'updated user ID:%s %s' % (user.user_id, user.username),
359 'user': user.get_api_data(include_secrets=True)
390 'user': user.get_api_data(include_secrets=True)
360 }
391 }
361 except DefaultUserException:
392 except DefaultUserException:
362 log.exception("Default user edit exception")
393 log.exception("Default user edit exception")
363 raise JSONRPCError('editing default user is forbidden')
394 raise JSONRPCError('editing default user is forbidden')
364 except Exception:
395 except Exception:
365 log.exception("Error occurred during update of user")
396 log.exception("Error occurred during update of user")
366 raise JSONRPCError('failed to update user `%s`' % (userid,))
397 raise JSONRPCError('failed to update user `%s`' % (userid,))
367
398
368
399
369 @jsonrpc_method()
400 @jsonrpc_method()
370 def delete_user(request, apiuser, userid):
401 def delete_user(request, apiuser, userid):
371 """
402 """
372 Deletes the specified user from the |RCE| user database.
403 Deletes the specified user from the |RCE| user database.
373
404
374 This command can only be run using an |authtoken| with admin rights to
405 This command can only be run using an |authtoken| with admin rights to
375 the specified repository.
406 the specified repository.
376
407
377 .. important::
408 .. important::
378
409
379 Ensure all open pull requests and open code review
410 Ensure all open pull requests and open code review
380 requests to this user are close.
411 requests to this user are close.
381
412
382 Also ensure all repositories, or repository groups owned by this
413 Also ensure all repositories, or repository groups owned by this
383 user are reassigned before deletion.
414 user are reassigned before deletion.
384
415
385 This command takes the following options:
416 This command takes the following options:
386
417
387 :param apiuser: This is filled automatically from the |authtoken|.
418 :param apiuser: This is filled automatically from the |authtoken|.
388 :type apiuser: AuthUser
419 :type apiuser: AuthUser
389 :param userid: Set the user to delete.
420 :param userid: Set the user to delete.
390 :type userid: str or int
421 :type userid: str or int
391
422
392 Example output:
423 Example output:
393
424
394 .. code-block:: bash
425 .. code-block:: bash
395
426
396 id : <id_given_in_input>
427 id : <id_given_in_input>
397 result: {
428 result: {
398 "msg" : "deleted user ID:<userid> <username>",
429 "msg" : "deleted user ID:<userid> <username>",
399 "user": null
430 "user": null
400 }
431 }
401 error: null
432 error: null
402
433
403 Example error output:
434 Example error output:
404
435
405 .. code-block:: bash
436 .. code-block:: bash
406
437
407 id : <id_given_in_input>
438 id : <id_given_in_input>
408 result : null
439 result : null
409 error : {
440 error : {
410 "failed to delete user ID:<userid> <username>"
441 "failed to delete user ID:<userid> <username>"
411 }
442 }
412
443
413 """
444 """
414 if not has_superadmin_permission(apiuser):
445 if not has_superadmin_permission(apiuser):
415 raise JSONRPCForbidden()
446 raise JSONRPCForbidden()
416
447
417 user = get_user_or_error(userid)
448 user = get_user_or_error(userid)
418 old_data = user.get_api_data()
449 old_data = user.get_api_data()
419 try:
450 try:
420 UserModel().delete(userid)
451 UserModel().delete(userid)
421 audit_logger.store_api(
452 audit_logger.store_api(
422 'user.delete', action_data={'old_data': old_data},
453 'user.delete', action_data={'old_data': old_data},
423 user=apiuser)
454 user=apiuser)
424
455
425 Session().commit()
456 Session().commit()
426 return {
457 return {
427 'msg': 'deleted user ID:%s %s' % (user.user_id, user.username),
458 'msg': 'deleted user ID:%s %s' % (user.user_id, user.username),
428 'user': None
459 'user': None
429 }
460 }
430 except Exception:
461 except Exception:
431 log.exception("Error occurred during deleting of user")
462 log.exception("Error occurred during deleting of user")
432 raise JSONRPCError(
463 raise JSONRPCError(
433 'failed to delete user ID:%s %s' % (user.user_id, user.username))
464 'failed to delete user ID:%s %s' % (user.user_id, user.username))
434
465
435
466
436 @jsonrpc_method()
467 @jsonrpc_method()
437 def get_user_locks(request, apiuser, userid=Optional(OAttr('apiuser'))):
468 def get_user_locks(request, apiuser, userid=Optional(OAttr('apiuser'))):
438 """
469 """
439 Displays all repositories locked by the specified user.
470 Displays all repositories locked by the specified user.
440
471
441 * If this command is run by a non-admin user, it returns
472 * If this command is run by a non-admin user, it returns
442 a list of |repos| locked by that user.
473 a list of |repos| locked by that user.
443
474
444 This command takes the following options:
475 This command takes the following options:
445
476
446 :param apiuser: This is filled automatically from the |authtoken|.
477 :param apiuser: This is filled automatically from the |authtoken|.
447 :type apiuser: AuthUser
478 :type apiuser: AuthUser
448 :param userid: Sets the userid whose list of locked |repos| will be
479 :param userid: Sets the userid whose list of locked |repos| will be
449 displayed.
480 displayed.
450 :type userid: Optional(str or int)
481 :type userid: Optional(str or int)
451
482
452 Example output:
483 Example output:
453
484
454 .. code-block:: bash
485 .. code-block:: bash
455
486
456 id : <id_given_in_input>
487 id : <id_given_in_input>
457 result : {
488 result : {
458 [repo_object, repo_object,...]
489 [repo_object, repo_object,...]
459 }
490 }
460 error : null
491 error : null
461 """
492 """
462
493
463 include_secrets = False
494 include_secrets = False
464 if not has_superadmin_permission(apiuser):
495 if not has_superadmin_permission(apiuser):
465 # make sure normal user does not pass someone else userid,
496 # make sure normal user does not pass someone else userid,
466 # he is not allowed to do that
497 # he is not allowed to do that
467 if not isinstance(userid, Optional) and userid != apiuser.user_id:
498 if not isinstance(userid, Optional) and userid != apiuser.user_id:
468 raise JSONRPCError('userid is not the same as your user')
499 raise JSONRPCError('userid is not the same as your user')
469 else:
500 else:
470 include_secrets = True
501 include_secrets = True
471
502
472 userid = Optional.extract(userid, evaluate_locals=locals())
503 userid = Optional.extract(userid, evaluate_locals=locals())
473 userid = getattr(userid, 'user_id', userid)
504 userid = getattr(userid, 'user_id', userid)
474 user = get_user_or_error(userid)
505 user = get_user_or_error(userid)
475
506
476 ret = []
507 ret = []
477
508
478 # show all locks
509 # show all locks
479 for r in Repository.getAll():
510 for r in Repository.getAll():
480 _user_id, _time, _reason = r.locked
511 _user_id, _time, _reason = r.locked
481 if _user_id and _time:
512 if _user_id and _time:
482 _api_data = r.get_api_data(include_secrets=include_secrets)
513 _api_data = r.get_api_data(include_secrets=include_secrets)
483 # if we use user filter just show the locks for this user
514 # if we use user filter just show the locks for this user
484 if safe_int(_user_id) == user.user_id:
515 if safe_int(_user_id) == user.user_id:
485 ret.append(_api_data)
516 ret.append(_api_data)
486
517
487 return ret
518 return ret
488
519
489
520
490 @jsonrpc_method()
521 @jsonrpc_method()
491 def get_user_audit_logs(request, apiuser, userid=Optional(OAttr('apiuser'))):
522 def get_user_audit_logs(request, apiuser, userid=Optional(OAttr('apiuser'))):
492 """
523 """
493 Fetches all action logs made by the specified user.
524 Fetches all action logs made by the specified user.
494
525
495 This command takes the following options:
526 This command takes the following options:
496
527
497 :param apiuser: This is filled automatically from the |authtoken|.
528 :param apiuser: This is filled automatically from the |authtoken|.
498 :type apiuser: AuthUser
529 :type apiuser: AuthUser
499 :param userid: Sets the userid whose list of locked |repos| will be
530 :param userid: Sets the userid whose list of locked |repos| will be
500 displayed.
531 displayed.
501 :type userid: Optional(str or int)
532 :type userid: Optional(str or int)
502
533
503 Example output:
534 Example output:
504
535
505 .. code-block:: bash
536 .. code-block:: bash
506
537
507 id : <id_given_in_input>
538 id : <id_given_in_input>
508 result : {
539 result : {
509 [action, action,...]
540 [action, action,...]
510 }
541 }
511 error : null
542 error : null
512 """
543 """
513
544
514 if not has_superadmin_permission(apiuser):
545 if not has_superadmin_permission(apiuser):
515 # make sure normal user does not pass someone else userid,
546 # make sure normal user does not pass someone else userid,
516 # he is not allowed to do that
547 # he is not allowed to do that
517 if not isinstance(userid, Optional) and userid != apiuser.user_id:
548 if not isinstance(userid, Optional) and userid != apiuser.user_id:
518 raise JSONRPCError('userid is not the same as your user')
549 raise JSONRPCError('userid is not the same as your user')
519
550
520 userid = Optional.extract(userid, evaluate_locals=locals())
551 userid = Optional.extract(userid, evaluate_locals=locals())
521 userid = getattr(userid, 'user_id', userid)
552 userid = getattr(userid, 'user_id', userid)
522 user = get_user_or_error(userid)
553 user = get_user_or_error(userid)
523
554
524 ret = []
555 ret = []
525
556
526 # show all user actions
557 # show all user actions
527 for entry in UserModel().get_user_log(user, filter_term=None):
558 for entry in UserModel().get_user_log(user, filter_term=None):
528 ret.append(entry)
559 ret.append(entry)
529 return ret
560 return ret
@@ -1,818 +1,818 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22
22
23 from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCForbidden, \
23 from rhodecode.api import (
24 JSONRPCValidationError
24 jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError)
25 from rhodecode.api.utils import (
25 from rhodecode.api.utils import (
26 Optional, OAttr, store_update, has_superadmin_permission, get_origin,
26 Optional, OAttr, store_update, has_superadmin_permission, get_origin,
27 get_user_or_error, get_user_group_or_error, get_perm_or_error)
27 get_user_or_error, get_user_group_or_error, get_perm_or_error)
28 from rhodecode.lib import audit_logger
28 from rhodecode.lib import audit_logger
29 from rhodecode.lib.auth import HasUserGroupPermissionAnyApi, HasPermissionAnyApi
29 from rhodecode.lib.auth import HasUserGroupPermissionAnyApi, HasPermissionAnyApi
30 from rhodecode.lib.exceptions import UserGroupAssignedException
30 from rhodecode.lib.exceptions import UserGroupAssignedException
31 from rhodecode.model.db import Session
31 from rhodecode.model.db import Session
32 from rhodecode.model.scm import UserGroupList
32 from rhodecode.model.scm import UserGroupList
33 from rhodecode.model.user_group import UserGroupModel
33 from rhodecode.model.user_group import UserGroupModel
34 from rhodecode.model import validation_schema
34 from rhodecode.model import validation_schema
35 from rhodecode.model.validation_schema.schemas import user_group_schema
35 from rhodecode.model.validation_schema.schemas import user_group_schema
36
36
37 log = logging.getLogger(__name__)
37 log = logging.getLogger(__name__)
38
38
39
39
40 @jsonrpc_method()
40 @jsonrpc_method()
41 def get_user_group(request, apiuser, usergroupid):
41 def get_user_group(request, apiuser, usergroupid):
42 """
42 """
43 Returns the data of an existing user group.
43 Returns the data of an existing user group.
44
44
45 This command can only be run using an |authtoken| with admin rights to
45 This command can only be run using an |authtoken| with admin rights to
46 the specified repository.
46 the specified repository.
47
47
48 :param apiuser: This is filled automatically from the |authtoken|.
48 :param apiuser: This is filled automatically from the |authtoken|.
49 :type apiuser: AuthUser
49 :type apiuser: AuthUser
50 :param usergroupid: Set the user group from which to return data.
50 :param usergroupid: Set the user group from which to return data.
51 :type usergroupid: str or int
51 :type usergroupid: str or int
52
52
53 Example error output:
53 Example error output:
54
54
55 .. code-block:: bash
55 .. code-block:: bash
56
56
57 {
57 {
58 "error": null,
58 "error": null,
59 "id": <id>,
59 "id": <id>,
60 "result": {
60 "result": {
61 "active": true,
61 "active": true,
62 "group_description": "group description",
62 "group_description": "group description",
63 "group_name": "group name",
63 "group_name": "group name",
64 "members": [
64 "members": [
65 {
65 {
66 "name": "owner-name",
66 "name": "owner-name",
67 "origin": "owner",
67 "origin": "owner",
68 "permission": "usergroup.admin",
68 "permission": "usergroup.admin",
69 "type": "user"
69 "type": "user"
70 },
70 },
71 {
71 {
72 {
72 {
73 "name": "user name",
73 "name": "user name",
74 "origin": "permission",
74 "origin": "permission",
75 "permission": "usergroup.admin",
75 "permission": "usergroup.admin",
76 "type": "user"
76 "type": "user"
77 },
77 },
78 {
78 {
79 "name": "user group name",
79 "name": "user group name",
80 "origin": "permission",
80 "origin": "permission",
81 "permission": "usergroup.write",
81 "permission": "usergroup.write",
82 "type": "user_group"
82 "type": "user_group"
83 }
83 }
84 ],
84 ],
85 "owner": "owner name",
85 "owner": "owner name",
86 "users": [],
86 "users": [],
87 "users_group_id": 2
87 "users_group_id": 2
88 }
88 }
89 }
89 }
90
90
91 """
91 """
92
92
93 user_group = get_user_group_or_error(usergroupid)
93 user_group = get_user_group_or_error(usergroupid)
94 if not has_superadmin_permission(apiuser):
94 if not has_superadmin_permission(apiuser):
95 # check if we have at least read permission for this user group !
95 # check if we have at least read permission for this user group !
96 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
96 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
97 if not HasUserGroupPermissionAnyApi(*_perms)(
97 if not HasUserGroupPermissionAnyApi(*_perms)(
98 user=apiuser, user_group_name=user_group.users_group_name):
98 user=apiuser, user_group_name=user_group.users_group_name):
99 raise JSONRPCError('user group `%s` does not exist' % (
99 raise JSONRPCError('user group `%s` does not exist' % (
100 usergroupid,))
100 usergroupid,))
101
101
102 permissions = []
102 permissions = []
103 for _user in user_group.permissions():
103 for _user in user_group.permissions():
104 user_data = {
104 user_data = {
105 'name': _user.username,
105 'name': _user.username,
106 'permission': _user.permission,
106 'permission': _user.permission,
107 'origin': get_origin(_user),
107 'origin': get_origin(_user),
108 'type': "user",
108 'type': "user",
109 }
109 }
110 permissions.append(user_data)
110 permissions.append(user_data)
111
111
112 for _user_group in user_group.permission_user_groups():
112 for _user_group in user_group.permission_user_groups():
113 user_group_data = {
113 user_group_data = {
114 'name': _user_group.users_group_name,
114 'name': _user_group.users_group_name,
115 'permission': _user_group.permission,
115 'permission': _user_group.permission,
116 'origin': get_origin(_user_group),
116 'origin': get_origin(_user_group),
117 'type': "user_group",
117 'type': "user_group",
118 }
118 }
119 permissions.append(user_group_data)
119 permissions.append(user_group_data)
120
120
121 data = user_group.get_api_data()
121 data = user_group.get_api_data()
122 data['members'] = permissions
122 data['members'] = permissions
123
123
124 return data
124 return data
125
125
126
126
127 @jsonrpc_method()
127 @jsonrpc_method()
128 def get_user_groups(request, apiuser):
128 def get_user_groups(request, apiuser):
129 """
129 """
130 Lists all the existing user groups within RhodeCode.
130 Lists all the existing user groups within RhodeCode.
131
131
132 This command can only be run using an |authtoken| with admin rights to
132 This command can only be run using an |authtoken| with admin rights to
133 the specified repository.
133 the specified repository.
134
134
135 This command takes the following options:
135 This command takes the following options:
136
136
137 :param apiuser: This is filled automatically from the |authtoken|.
137 :param apiuser: This is filled automatically from the |authtoken|.
138 :type apiuser: AuthUser
138 :type apiuser: AuthUser
139
139
140 Example error output:
140 Example error output:
141
141
142 .. code-block:: bash
142 .. code-block:: bash
143
143
144 id : <id_given_in_input>
144 id : <id_given_in_input>
145 result : [<user_group_obj>,...]
145 result : [<user_group_obj>,...]
146 error : null
146 error : null
147 """
147 """
148
148
149 include_secrets = has_superadmin_permission(apiuser)
149 include_secrets = has_superadmin_permission(apiuser)
150
150
151 result = []
151 result = []
152 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
152 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
153 extras = {'user': apiuser}
153 extras = {'user': apiuser}
154 for user_group in UserGroupList(UserGroupModel().get_all(),
154 for user_group in UserGroupList(UserGroupModel().get_all(),
155 perm_set=_perms, extra_kwargs=extras):
155 perm_set=_perms, extra_kwargs=extras):
156 result.append(
156 result.append(
157 user_group.get_api_data(include_secrets=include_secrets))
157 user_group.get_api_data(include_secrets=include_secrets))
158 return result
158 return result
159
159
160
160
161 @jsonrpc_method()
161 @jsonrpc_method()
162 def create_user_group(
162 def create_user_group(
163 request, apiuser, group_name, description=Optional(''),
163 request, apiuser, group_name, description=Optional(''),
164 owner=Optional(OAttr('apiuser')), active=Optional(True)):
164 owner=Optional(OAttr('apiuser')), active=Optional(True)):
165 """
165 """
166 Creates a new user group.
166 Creates a new user group.
167
167
168 This command can only be run using an |authtoken| with admin rights to
168 This command can only be run using an |authtoken| with admin rights to
169 the specified repository.
169 the specified repository.
170
170
171 This command takes the following options:
171 This command takes the following options:
172
172
173 :param apiuser: This is filled automatically from the |authtoken|.
173 :param apiuser: This is filled automatically from the |authtoken|.
174 :type apiuser: AuthUser
174 :type apiuser: AuthUser
175 :param group_name: Set the name of the new user group.
175 :param group_name: Set the name of the new user group.
176 :type group_name: str
176 :type group_name: str
177 :param description: Give a description of the new user group.
177 :param description: Give a description of the new user group.
178 :type description: str
178 :type description: str
179 :param owner: Set the owner of the new user group.
179 :param owner: Set the owner of the new user group.
180 If not set, the owner is the |authtoken| user.
180 If not set, the owner is the |authtoken| user.
181 :type owner: Optional(str or int)
181 :type owner: Optional(str or int)
182 :param active: Set this group as active.
182 :param active: Set this group as active.
183 :type active: Optional(``True`` | ``False``)
183 :type active: Optional(``True`` | ``False``)
184
184
185 Example output:
185 Example output:
186
186
187 .. code-block:: bash
187 .. code-block:: bash
188
188
189 id : <id_given_in_input>
189 id : <id_given_in_input>
190 result: {
190 result: {
191 "msg": "created new user group `<groupname>`",
191 "msg": "created new user group `<groupname>`",
192 "user_group": <user_group_object>
192 "user_group": <user_group_object>
193 }
193 }
194 error: null
194 error: null
195
195
196 Example error output:
196 Example error output:
197
197
198 .. code-block:: bash
198 .. code-block:: bash
199
199
200 id : <id_given_in_input>
200 id : <id_given_in_input>
201 result : null
201 result : null
202 error : {
202 error : {
203 "user group `<group name>` already exist"
203 "user group `<group name>` already exist"
204 or
204 or
205 "failed to create group `<group name>`"
205 "failed to create group `<group name>`"
206 }
206 }
207
207
208 """
208 """
209
209
210 if not has_superadmin_permission(apiuser):
210 if not has_superadmin_permission(apiuser):
211 if not HasPermissionAnyApi('hg.usergroup.create.true')(user=apiuser):
211 if not HasPermissionAnyApi('hg.usergroup.create.true')(user=apiuser):
212 raise JSONRPCForbidden()
212 raise JSONRPCForbidden()
213
213
214 if UserGroupModel().get_by_name(group_name):
214 if UserGroupModel().get_by_name(group_name):
215 raise JSONRPCError("user group `%s` already exist" % (group_name,))
215 raise JSONRPCError("user group `%s` already exist" % (group_name,))
216
216
217 if isinstance(owner, Optional):
217 if isinstance(owner, Optional):
218 owner = apiuser.user_id
218 owner = apiuser.user_id
219
219
220 owner = get_user_or_error(owner)
220 owner = get_user_or_error(owner)
221 active = Optional.extract(active)
221 active = Optional.extract(active)
222 description = Optional.extract(description)
222 description = Optional.extract(description)
223
223
224 schema = user_group_schema.UserGroupSchema().bind(
224 schema = user_group_schema.UserGroupSchema().bind(
225 # user caller
225 # user caller
226 user=apiuser)
226 user=apiuser)
227 try:
227 try:
228 schema_data = schema.deserialize(dict(
228 schema_data = schema.deserialize(dict(
229 user_group_name=group_name,
229 user_group_name=group_name,
230 user_group_description=description,
230 user_group_description=description,
231 user_group_owner=owner.username,
231 user_group_owner=owner.username,
232 user_group_active=active,
232 user_group_active=active,
233 ))
233 ))
234 except validation_schema.Invalid as err:
234 except validation_schema.Invalid as err:
235 raise JSONRPCValidationError(colander_exc=err)
235 raise JSONRPCValidationError(colander_exc=err)
236
236
237 try:
237 try:
238 user_group = UserGroupModel().create(
238 user_group = UserGroupModel().create(
239 name=schema_data['user_group_name'],
239 name=schema_data['user_group_name'],
240 description=schema_data['user_group_description'],
240 description=schema_data['user_group_description'],
241 owner=owner,
241 owner=owner,
242 active=schema_data['user_group_active'])
242 active=schema_data['user_group_active'])
243 Session().flush()
243 Session().flush()
244 creation_data = user_group.get_api_data()
244 creation_data = user_group.get_api_data()
245 audit_logger.store_api(
245 audit_logger.store_api(
246 'user_group.create', action_data={'data': creation_data},
246 'user_group.create', action_data={'data': creation_data},
247 user=apiuser)
247 user=apiuser)
248 Session().commit()
248 Session().commit()
249 return {
249 return {
250 'msg': 'created new user group `%s`' % group_name,
250 'msg': 'created new user group `%s`' % group_name,
251 'user_group': creation_data
251 'user_group': creation_data
252 }
252 }
253 except Exception:
253 except Exception:
254 log.exception("Error occurred during creation of user group")
254 log.exception("Error occurred during creation of user group")
255 raise JSONRPCError('failed to create group `%s`' % (group_name,))
255 raise JSONRPCError('failed to create group `%s`' % (group_name,))
256
256
257
257
258 @jsonrpc_method()
258 @jsonrpc_method()
259 def update_user_group(request, apiuser, usergroupid, group_name=Optional(''),
259 def update_user_group(request, apiuser, usergroupid, group_name=Optional(''),
260 description=Optional(''), owner=Optional(None),
260 description=Optional(''), owner=Optional(None),
261 active=Optional(True)):
261 active=Optional(True)):
262 """
262 """
263 Updates the specified `user group` with the details provided.
263 Updates the specified `user group` with the details provided.
264
264
265 This command can only be run using an |authtoken| with admin rights to
265 This command can only be run using an |authtoken| with admin rights to
266 the specified repository.
266 the specified repository.
267
267
268 :param apiuser: This is filled automatically from the |authtoken|.
268 :param apiuser: This is filled automatically from the |authtoken|.
269 :type apiuser: AuthUser
269 :type apiuser: AuthUser
270 :param usergroupid: Set the id of the `user group` to update.
270 :param usergroupid: Set the id of the `user group` to update.
271 :type usergroupid: str or int
271 :type usergroupid: str or int
272 :param group_name: Set the new name the `user group`
272 :param group_name: Set the new name the `user group`
273 :type group_name: str
273 :type group_name: str
274 :param description: Give a description for the `user group`
274 :param description: Give a description for the `user group`
275 :type description: str
275 :type description: str
276 :param owner: Set the owner of the `user group`.
276 :param owner: Set the owner of the `user group`.
277 :type owner: Optional(str or int)
277 :type owner: Optional(str or int)
278 :param active: Set the group as active.
278 :param active: Set the group as active.
279 :type active: Optional(``True`` | ``False``)
279 :type active: Optional(``True`` | ``False``)
280
280
281 Example output:
281 Example output:
282
282
283 .. code-block:: bash
283 .. code-block:: bash
284
284
285 id : <id_given_in_input>
285 id : <id_given_in_input>
286 result : {
286 result : {
287 "msg": 'updated user group ID:<user group id> <user group name>',
287 "msg": 'updated user group ID:<user group id> <user group name>',
288 "user_group": <user_group_object>
288 "user_group": <user_group_object>
289 }
289 }
290 error : null
290 error : null
291
291
292 Example error output:
292 Example error output:
293
293
294 .. code-block:: bash
294 .. code-block:: bash
295
295
296 id : <id_given_in_input>
296 id : <id_given_in_input>
297 result : null
297 result : null
298 error : {
298 error : {
299 "failed to update user group `<user group name>`"
299 "failed to update user group `<user group name>`"
300 }
300 }
301
301
302 """
302 """
303
303
304 user_group = get_user_group_or_error(usergroupid)
304 user_group = get_user_group_or_error(usergroupid)
305 include_secrets = False
305 include_secrets = False
306 if not has_superadmin_permission(apiuser):
306 if not has_superadmin_permission(apiuser):
307 # check if we have admin permission for this user group !
307 # check if we have admin permission for this user group !
308 _perms = ('usergroup.admin',)
308 _perms = ('usergroup.admin',)
309 if not HasUserGroupPermissionAnyApi(*_perms)(
309 if not HasUserGroupPermissionAnyApi(*_perms)(
310 user=apiuser, user_group_name=user_group.users_group_name):
310 user=apiuser, user_group_name=user_group.users_group_name):
311 raise JSONRPCError(
311 raise JSONRPCError(
312 'user group `%s` does not exist' % (usergroupid,))
312 'user group `%s` does not exist' % (usergroupid,))
313 else:
313 else:
314 include_secrets = True
314 include_secrets = True
315
315
316 if not isinstance(owner, Optional):
316 if not isinstance(owner, Optional):
317 owner = get_user_or_error(owner)
317 owner = get_user_or_error(owner)
318
318
319 old_data = user_group.get_api_data()
319 old_data = user_group.get_api_data()
320 updates = {}
320 updates = {}
321 store_update(updates, group_name, 'users_group_name')
321 store_update(updates, group_name, 'users_group_name')
322 store_update(updates, description, 'user_group_description')
322 store_update(updates, description, 'user_group_description')
323 store_update(updates, owner, 'user')
323 store_update(updates, owner, 'user')
324 store_update(updates, active, 'users_group_active')
324 store_update(updates, active, 'users_group_active')
325 try:
325 try:
326 UserGroupModel().update(user_group, updates)
326 UserGroupModel().update(user_group, updates)
327 audit_logger.store_api(
327 audit_logger.store_api(
328 'user_group.edit', action_data={'old_data': old_data},
328 'user_group.edit', action_data={'old_data': old_data},
329 user=apiuser)
329 user=apiuser)
330 Session().commit()
330 Session().commit()
331 return {
331 return {
332 'msg': 'updated user group ID:%s %s' % (
332 'msg': 'updated user group ID:%s %s' % (
333 user_group.users_group_id, user_group.users_group_name),
333 user_group.users_group_id, user_group.users_group_name),
334 'user_group': user_group.get_api_data(
334 'user_group': user_group.get_api_data(
335 include_secrets=include_secrets)
335 include_secrets=include_secrets)
336 }
336 }
337 except Exception:
337 except Exception:
338 log.exception("Error occurred during update of user group")
338 log.exception("Error occurred during update of user group")
339 raise JSONRPCError(
339 raise JSONRPCError(
340 'failed to update user group `%s`' % (usergroupid,))
340 'failed to update user group `%s`' % (usergroupid,))
341
341
342
342
343 @jsonrpc_method()
343 @jsonrpc_method()
344 def delete_user_group(request, apiuser, usergroupid):
344 def delete_user_group(request, apiuser, usergroupid):
345 """
345 """
346 Deletes the specified `user group`.
346 Deletes the specified `user group`.
347
347
348 This command can only be run using an |authtoken| with admin rights to
348 This command can only be run using an |authtoken| with admin rights to
349 the specified repository.
349 the specified repository.
350
350
351 This command takes the following options:
351 This command takes the following options:
352
352
353 :param apiuser: filled automatically from apikey
353 :param apiuser: filled automatically from apikey
354 :type apiuser: AuthUser
354 :type apiuser: AuthUser
355 :param usergroupid:
355 :param usergroupid:
356 :type usergroupid: int
356 :type usergroupid: int
357
357
358 Example output:
358 Example output:
359
359
360 .. code-block:: bash
360 .. code-block:: bash
361
361
362 id : <id_given_in_input>
362 id : <id_given_in_input>
363 result : {
363 result : {
364 "msg": "deleted user group ID:<user_group_id> <user_group_name>"
364 "msg": "deleted user group ID:<user_group_id> <user_group_name>"
365 }
365 }
366 error : null
366 error : null
367
367
368 Example error output:
368 Example error output:
369
369
370 .. code-block:: bash
370 .. code-block:: bash
371
371
372 id : <id_given_in_input>
372 id : <id_given_in_input>
373 result : null
373 result : null
374 error : {
374 error : {
375 "failed to delete user group ID:<user_group_id> <user_group_name>"
375 "failed to delete user group ID:<user_group_id> <user_group_name>"
376 or
376 or
377 "RepoGroup assigned to <repo_groups_list>"
377 "RepoGroup assigned to <repo_groups_list>"
378 }
378 }
379
379
380 """
380 """
381
381
382 user_group = get_user_group_or_error(usergroupid)
382 user_group = get_user_group_or_error(usergroupid)
383 if not has_superadmin_permission(apiuser):
383 if not has_superadmin_permission(apiuser):
384 # check if we have admin permission for this user group !
384 # check if we have admin permission for this user group !
385 _perms = ('usergroup.admin',)
385 _perms = ('usergroup.admin',)
386 if not HasUserGroupPermissionAnyApi(*_perms)(
386 if not HasUserGroupPermissionAnyApi(*_perms)(
387 user=apiuser, user_group_name=user_group.users_group_name):
387 user=apiuser, user_group_name=user_group.users_group_name):
388 raise JSONRPCError(
388 raise JSONRPCError(
389 'user group `%s` does not exist' % (usergroupid,))
389 'user group `%s` does not exist' % (usergroupid,))
390
390
391 old_data = user_group.get_api_data()
391 old_data = user_group.get_api_data()
392 try:
392 try:
393 UserGroupModel().delete(user_group)
393 UserGroupModel().delete(user_group)
394 audit_logger.store_api(
394 audit_logger.store_api(
395 'user_group.delete', action_data={'old_data': old_data},
395 'user_group.delete', action_data={'old_data': old_data},
396 user=apiuser)
396 user=apiuser)
397 Session().commit()
397 Session().commit()
398 return {
398 return {
399 'msg': 'deleted user group ID:%s %s' % (
399 'msg': 'deleted user group ID:%s %s' % (
400 user_group.users_group_id, user_group.users_group_name),
400 user_group.users_group_id, user_group.users_group_name),
401 'user_group': None
401 'user_group': None
402 }
402 }
403 except UserGroupAssignedException as e:
403 except UserGroupAssignedException as e:
404 log.exception("UserGroupAssigned error")
404 log.exception("UserGroupAssigned error")
405 raise JSONRPCError(str(e))
405 raise JSONRPCError(str(e))
406 except Exception:
406 except Exception:
407 log.exception("Error occurred during deletion of user group")
407 log.exception("Error occurred during deletion of user group")
408 raise JSONRPCError(
408 raise JSONRPCError(
409 'failed to delete user group ID:%s %s' %(
409 'failed to delete user group ID:%s %s' %(
410 user_group.users_group_id, user_group.users_group_name))
410 user_group.users_group_id, user_group.users_group_name))
411
411
412
412
413 @jsonrpc_method()
413 @jsonrpc_method()
414 def add_user_to_user_group(request, apiuser, usergroupid, userid):
414 def add_user_to_user_group(request, apiuser, usergroupid, userid):
415 """
415 """
416 Adds a user to a `user group`. If the user already exists in the group
416 Adds a user to a `user group`. If the user already exists in the group
417 this command will return false.
417 this command will return false.
418
418
419 This command can only be run using an |authtoken| with admin rights to
419 This command can only be run using an |authtoken| with admin rights to
420 the specified user group.
420 the specified user group.
421
421
422 This command takes the following options:
422 This command takes the following options:
423
423
424 :param apiuser: This is filled automatically from the |authtoken|.
424 :param apiuser: This is filled automatically from the |authtoken|.
425 :type apiuser: AuthUser
425 :type apiuser: AuthUser
426 :param usergroupid: Set the name of the `user group` to which a
426 :param usergroupid: Set the name of the `user group` to which a
427 user will be added.
427 user will be added.
428 :type usergroupid: int
428 :type usergroupid: int
429 :param userid: Set the `user_id` of the user to add to the group.
429 :param userid: Set the `user_id` of the user to add to the group.
430 :type userid: int
430 :type userid: int
431
431
432 Example output:
432 Example output:
433
433
434 .. code-block:: bash
434 .. code-block:: bash
435
435
436 id : <id_given_in_input>
436 id : <id_given_in_input>
437 result : {
437 result : {
438 "success": True|False # depends on if member is in group
438 "success": True|False # depends on if member is in group
439 "msg": "added member `<username>` to user group `<groupname>` |
439 "msg": "added member `<username>` to user group `<groupname>` |
440 User is already in that group"
440 User is already in that group"
441
441
442 }
442 }
443 error : null
443 error : null
444
444
445 Example error output:
445 Example error output:
446
446
447 .. code-block:: bash
447 .. code-block:: bash
448
448
449 id : <id_given_in_input>
449 id : <id_given_in_input>
450 result : null
450 result : null
451 error : {
451 error : {
452 "failed to add member to user group `<user_group_name>`"
452 "failed to add member to user group `<user_group_name>`"
453 }
453 }
454
454
455 """
455 """
456
456
457 user = get_user_or_error(userid)
457 user = get_user_or_error(userid)
458 user_group = get_user_group_or_error(usergroupid)
458 user_group = get_user_group_or_error(usergroupid)
459 if not has_superadmin_permission(apiuser):
459 if not has_superadmin_permission(apiuser):
460 # check if we have admin permission for this user group !
460 # check if we have admin permission for this user group !
461 _perms = ('usergroup.admin',)
461 _perms = ('usergroup.admin',)
462 if not HasUserGroupPermissionAnyApi(*_perms)(
462 if not HasUserGroupPermissionAnyApi(*_perms)(
463 user=apiuser, user_group_name=user_group.users_group_name):
463 user=apiuser, user_group_name=user_group.users_group_name):
464 raise JSONRPCError('user group `%s` does not exist' % (
464 raise JSONRPCError('user group `%s` does not exist' % (
465 usergroupid,))
465 usergroupid,))
466
466
467 try:
467 try:
468 ugm = UserGroupModel().add_user_to_group(user_group, user)
468 ugm = UserGroupModel().add_user_to_group(user_group, user)
469 success = True if ugm is not True else False
469 success = True if ugm is not True else False
470 msg = 'added member `%s` to user group `%s`' % (
470 msg = 'added member `%s` to user group `%s`' % (
471 user.username, user_group.users_group_name
471 user.username, user_group.users_group_name
472 )
472 )
473 msg = msg if success else 'User is already in that group'
473 msg = msg if success else 'User is already in that group'
474 if success:
474 if success:
475 user_data = user.get_api_data()
475 user_data = user.get_api_data()
476 audit_logger.store_api(
476 audit_logger.store_api(
477 'user_group.edit.member.add', action_data={'user': user_data},
477 'user_group.edit.member.add', action_data={'user': user_data},
478 user=apiuser)
478 user=apiuser)
479
479
480 Session().commit()
480 Session().commit()
481
481
482 return {
482 return {
483 'success': success,
483 'success': success,
484 'msg': msg
484 'msg': msg
485 }
485 }
486 except Exception:
486 except Exception:
487 log.exception("Error occurred during adding a member to user group")
487 log.exception("Error occurred during adding a member to user group")
488 raise JSONRPCError(
488 raise JSONRPCError(
489 'failed to add member to user group `%s`' % (
489 'failed to add member to user group `%s`' % (
490 user_group.users_group_name,
490 user_group.users_group_name,
491 )
491 )
492 )
492 )
493
493
494
494
495 @jsonrpc_method()
495 @jsonrpc_method()
496 def remove_user_from_user_group(request, apiuser, usergroupid, userid):
496 def remove_user_from_user_group(request, apiuser, usergroupid, userid):
497 """
497 """
498 Removes a user from a user group.
498 Removes a user from a user group.
499
499
500 * If the specified user is not in the group, this command will return
500 * If the specified user is not in the group, this command will return
501 `false`.
501 `false`.
502
502
503 This command can only be run using an |authtoken| with admin rights to
503 This command can only be run using an |authtoken| with admin rights to
504 the specified user group.
504 the specified user group.
505
505
506 :param apiuser: This is filled automatically from the |authtoken|.
506 :param apiuser: This is filled automatically from the |authtoken|.
507 :type apiuser: AuthUser
507 :type apiuser: AuthUser
508 :param usergroupid: Sets the user group name.
508 :param usergroupid: Sets the user group name.
509 :type usergroupid: str or int
509 :type usergroupid: str or int
510 :param userid: The user you wish to remove from |RCE|.
510 :param userid: The user you wish to remove from |RCE|.
511 :type userid: str or int
511 :type userid: str or int
512
512
513 Example output:
513 Example output:
514
514
515 .. code-block:: bash
515 .. code-block:: bash
516
516
517 id : <id_given_in_input>
517 id : <id_given_in_input>
518 result: {
518 result: {
519 "success": True|False, # depends on if member is in group
519 "success": True|False, # depends on if member is in group
520 "msg": "removed member <username> from user group <groupname> |
520 "msg": "removed member <username> from user group <groupname> |
521 User wasn't in group"
521 User wasn't in group"
522 }
522 }
523 error: null
523 error: null
524
524
525 """
525 """
526
526
527 user = get_user_or_error(userid)
527 user = get_user_or_error(userid)
528 user_group = get_user_group_or_error(usergroupid)
528 user_group = get_user_group_or_error(usergroupid)
529 if not has_superadmin_permission(apiuser):
529 if not has_superadmin_permission(apiuser):
530 # check if we have admin permission for this user group !
530 # check if we have admin permission for this user group !
531 _perms = ('usergroup.admin',)
531 _perms = ('usergroup.admin',)
532 if not HasUserGroupPermissionAnyApi(*_perms)(
532 if not HasUserGroupPermissionAnyApi(*_perms)(
533 user=apiuser, user_group_name=user_group.users_group_name):
533 user=apiuser, user_group_name=user_group.users_group_name):
534 raise JSONRPCError(
534 raise JSONRPCError(
535 'user group `%s` does not exist' % (usergroupid,))
535 'user group `%s` does not exist' % (usergroupid,))
536
536
537 try:
537 try:
538 success = UserGroupModel().remove_user_from_group(user_group, user)
538 success = UserGroupModel().remove_user_from_group(user_group, user)
539 msg = 'removed member `%s` from user group `%s`' % (
539 msg = 'removed member `%s` from user group `%s`' % (
540 user.username, user_group.users_group_name
540 user.username, user_group.users_group_name
541 )
541 )
542 msg = msg if success else "User wasn't in group"
542 msg = msg if success else "User wasn't in group"
543 if success:
543 if success:
544 user_data = user.get_api_data()
544 user_data = user.get_api_data()
545 audit_logger.store_api(
545 audit_logger.store_api(
546 'user_group.edit.member.delete', action_data={'user': user_data},
546 'user_group.edit.member.delete', action_data={'user': user_data},
547 user=apiuser)
547 user=apiuser)
548
548
549 Session().commit()
549 Session().commit()
550 return {'success': success, 'msg': msg}
550 return {'success': success, 'msg': msg}
551 except Exception:
551 except Exception:
552 log.exception("Error occurred during removing an member from user group")
552 log.exception("Error occurred during removing an member from user group")
553 raise JSONRPCError(
553 raise JSONRPCError(
554 'failed to remove member from user group `%s`' % (
554 'failed to remove member from user group `%s`' % (
555 user_group.users_group_name,
555 user_group.users_group_name,
556 )
556 )
557 )
557 )
558
558
559
559
560 @jsonrpc_method()
560 @jsonrpc_method()
561 def grant_user_permission_to_user_group(
561 def grant_user_permission_to_user_group(
562 request, apiuser, usergroupid, userid, perm):
562 request, apiuser, usergroupid, userid, perm):
563 """
563 """
564 Set permissions for a user in a user group.
564 Set permissions for a user in a user group.
565
565
566 :param apiuser: This is filled automatically from the |authtoken|.
566 :param apiuser: This is filled automatically from the |authtoken|.
567 :type apiuser: AuthUser
567 :type apiuser: AuthUser
568 :param usergroupid: Set the user group to edit permissions on.
568 :param usergroupid: Set the user group to edit permissions on.
569 :type usergroupid: str or int
569 :type usergroupid: str or int
570 :param userid: Set the user from whom you wish to set permissions.
570 :param userid: Set the user from whom you wish to set permissions.
571 :type userid: str
571 :type userid: str
572 :param perm: (usergroup.(none|read|write|admin))
572 :param perm: (usergroup.(none|read|write|admin))
573 :type perm: str
573 :type perm: str
574
574
575 Example output:
575 Example output:
576
576
577 .. code-block:: bash
577 .. code-block:: bash
578
578
579 id : <id_given_in_input>
579 id : <id_given_in_input>
580 result : {
580 result : {
581 "msg": "Granted perm: `<perm_name>` for user: `<username>` in user group: `<user_group_name>`",
581 "msg": "Granted perm: `<perm_name>` for user: `<username>` in user group: `<user_group_name>`",
582 "success": true
582 "success": true
583 }
583 }
584 error : null
584 error : null
585 """
585 """
586
586
587 user_group = get_user_group_or_error(usergroupid)
587 user_group = get_user_group_or_error(usergroupid)
588
588
589 if not has_superadmin_permission(apiuser):
589 if not has_superadmin_permission(apiuser):
590 # check if we have admin permission for this user group !
590 # check if we have admin permission for this user group !
591 _perms = ('usergroup.admin',)
591 _perms = ('usergroup.admin',)
592 if not HasUserGroupPermissionAnyApi(*_perms)(
592 if not HasUserGroupPermissionAnyApi(*_perms)(
593 user=apiuser, user_group_name=user_group.users_group_name):
593 user=apiuser, user_group_name=user_group.users_group_name):
594 raise JSONRPCError(
594 raise JSONRPCError(
595 'user group `%s` does not exist' % (usergroupid,))
595 'user group `%s` does not exist' % (usergroupid,))
596
596
597 user = get_user_or_error(userid)
597 user = get_user_or_error(userid)
598 perm = get_perm_or_error(perm, prefix='usergroup.')
598 perm = get_perm_or_error(perm, prefix='usergroup.')
599
599
600 try:
600 try:
601 UserGroupModel().grant_user_permission(
601 UserGroupModel().grant_user_permission(
602 user_group=user_group, user=user, perm=perm)
602 user_group=user_group, user=user, perm=perm)
603 Session().commit()
603 Session().commit()
604 return {
604 return {
605 'msg':
605 'msg':
606 'Granted perm: `%s` for user: `%s` in user group: `%s`' % (
606 'Granted perm: `%s` for user: `%s` in user group: `%s`' % (
607 perm.permission_name, user.username,
607 perm.permission_name, user.username,
608 user_group.users_group_name
608 user_group.users_group_name
609 ),
609 ),
610 'success': True
610 'success': True
611 }
611 }
612 except Exception:
612 except Exception:
613 log.exception("Error occurred during editing permissions "
613 log.exception("Error occurred during editing permissions "
614 "for user in user group")
614 "for user in user group")
615 raise JSONRPCError(
615 raise JSONRPCError(
616 'failed to edit permission for user: '
616 'failed to edit permission for user: '
617 '`%s` in user group: `%s`' % (
617 '`%s` in user group: `%s`' % (
618 userid, user_group.users_group_name))
618 userid, user_group.users_group_name))
619
619
620
620
621 @jsonrpc_method()
621 @jsonrpc_method()
622 def revoke_user_permission_from_user_group(
622 def revoke_user_permission_from_user_group(
623 request, apiuser, usergroupid, userid):
623 request, apiuser, usergroupid, userid):
624 """
624 """
625 Revoke a users permissions in a user group.
625 Revoke a users permissions in a user group.
626
626
627 :param apiuser: This is filled automatically from the |authtoken|.
627 :param apiuser: This is filled automatically from the |authtoken|.
628 :type apiuser: AuthUser
628 :type apiuser: AuthUser
629 :param usergroupid: Set the user group from which to revoke the user
629 :param usergroupid: Set the user group from which to revoke the user
630 permissions.
630 permissions.
631 :type: usergroupid: str or int
631 :type: usergroupid: str or int
632 :param userid: Set the userid of the user whose permissions will be
632 :param userid: Set the userid of the user whose permissions will be
633 revoked.
633 revoked.
634 :type userid: str
634 :type userid: str
635
635
636 Example output:
636 Example output:
637
637
638 .. code-block:: bash
638 .. code-block:: bash
639
639
640 id : <id_given_in_input>
640 id : <id_given_in_input>
641 result : {
641 result : {
642 "msg": "Revoked perm for user: `<username>` in user group: `<user_group_name>`",
642 "msg": "Revoked perm for user: `<username>` in user group: `<user_group_name>`",
643 "success": true
643 "success": true
644 }
644 }
645 error : null
645 error : null
646 """
646 """
647
647
648 user_group = get_user_group_or_error(usergroupid)
648 user_group = get_user_group_or_error(usergroupid)
649
649
650 if not has_superadmin_permission(apiuser):
650 if not has_superadmin_permission(apiuser):
651 # check if we have admin permission for this user group !
651 # check if we have admin permission for this user group !
652 _perms = ('usergroup.admin',)
652 _perms = ('usergroup.admin',)
653 if not HasUserGroupPermissionAnyApi(*_perms)(
653 if not HasUserGroupPermissionAnyApi(*_perms)(
654 user=apiuser, user_group_name=user_group.users_group_name):
654 user=apiuser, user_group_name=user_group.users_group_name):
655 raise JSONRPCError(
655 raise JSONRPCError(
656 'user group `%s` does not exist' % (usergroupid,))
656 'user group `%s` does not exist' % (usergroupid,))
657
657
658 user = get_user_or_error(userid)
658 user = get_user_or_error(userid)
659
659
660 try:
660 try:
661 UserGroupModel().revoke_user_permission(
661 UserGroupModel().revoke_user_permission(
662 user_group=user_group, user=user)
662 user_group=user_group, user=user)
663 Session().commit()
663 Session().commit()
664 return {
664 return {
665 'msg': 'Revoked perm for user: `%s` in user group: `%s`' % (
665 'msg': 'Revoked perm for user: `%s` in user group: `%s`' % (
666 user.username, user_group.users_group_name
666 user.username, user_group.users_group_name
667 ),
667 ),
668 'success': True
668 'success': True
669 }
669 }
670 except Exception:
670 except Exception:
671 log.exception("Error occurred during editing permissions "
671 log.exception("Error occurred during editing permissions "
672 "for user in user group")
672 "for user in user group")
673 raise JSONRPCError(
673 raise JSONRPCError(
674 'failed to edit permission for user: `%s` in user group: `%s`'
674 'failed to edit permission for user: `%s` in user group: `%s`'
675 % (userid, user_group.users_group_name))
675 % (userid, user_group.users_group_name))
676
676
677
677
678 @jsonrpc_method()
678 @jsonrpc_method()
679 def grant_user_group_permission_to_user_group(
679 def grant_user_group_permission_to_user_group(
680 request, apiuser, usergroupid, sourceusergroupid, perm):
680 request, apiuser, usergroupid, sourceusergroupid, perm):
681 """
681 """
682 Give one user group permissions to another user group.
682 Give one user group permissions to another user group.
683
683
684 :param apiuser: This is filled automatically from the |authtoken|.
684 :param apiuser: This is filled automatically from the |authtoken|.
685 :type apiuser: AuthUser
685 :type apiuser: AuthUser
686 :param usergroupid: Set the user group on which to edit permissions.
686 :param usergroupid: Set the user group on which to edit permissions.
687 :type usergroupid: str or int
687 :type usergroupid: str or int
688 :param sourceusergroupid: Set the source user group to which
688 :param sourceusergroupid: Set the source user group to which
689 access/permissions will be granted.
689 access/permissions will be granted.
690 :type sourceusergroupid: str or int
690 :type sourceusergroupid: str or int
691 :param perm: (usergroup.(none|read|write|admin))
691 :param perm: (usergroup.(none|read|write|admin))
692 :type perm: str
692 :type perm: str
693
693
694 Example output:
694 Example output:
695
695
696 .. code-block:: bash
696 .. code-block:: bash
697
697
698 id : <id_given_in_input>
698 id : <id_given_in_input>
699 result : {
699 result : {
700 "msg": "Granted perm: `<perm_name>` for user group: `<source_user_group_name>` in user group: `<user_group_name>`",
700 "msg": "Granted perm: `<perm_name>` for user group: `<source_user_group_name>` in user group: `<user_group_name>`",
701 "success": true
701 "success": true
702 }
702 }
703 error : null
703 error : null
704 """
704 """
705
705
706 user_group = get_user_group_or_error(sourceusergroupid)
706 user_group = get_user_group_or_error(sourceusergroupid)
707 target_user_group = get_user_group_or_error(usergroupid)
707 target_user_group = get_user_group_or_error(usergroupid)
708 perm = get_perm_or_error(perm, prefix='usergroup.')
708 perm = get_perm_or_error(perm, prefix='usergroup.')
709
709
710 if not has_superadmin_permission(apiuser):
710 if not has_superadmin_permission(apiuser):
711 # check if we have admin permission for this user group !
711 # check if we have admin permission for this user group !
712 _perms = ('usergroup.admin',)
712 _perms = ('usergroup.admin',)
713 if not HasUserGroupPermissionAnyApi(*_perms)(
713 if not HasUserGroupPermissionAnyApi(*_perms)(
714 user=apiuser,
714 user=apiuser,
715 user_group_name=target_user_group.users_group_name):
715 user_group_name=target_user_group.users_group_name):
716 raise JSONRPCError(
716 raise JSONRPCError(
717 'to user group `%s` does not exist' % (usergroupid,))
717 'to user group `%s` does not exist' % (usergroupid,))
718
718
719 # check if we have at least read permission for source user group !
719 # check if we have at least read permission for source user group !
720 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
720 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
721 if not HasUserGroupPermissionAnyApi(*_perms)(
721 if not HasUserGroupPermissionAnyApi(*_perms)(
722 user=apiuser, user_group_name=user_group.users_group_name):
722 user=apiuser, user_group_name=user_group.users_group_name):
723 raise JSONRPCError(
723 raise JSONRPCError(
724 'user group `%s` does not exist' % (sourceusergroupid,))
724 'user group `%s` does not exist' % (sourceusergroupid,))
725
725
726 try:
726 try:
727 UserGroupModel().grant_user_group_permission(
727 UserGroupModel().grant_user_group_permission(
728 target_user_group=target_user_group,
728 target_user_group=target_user_group,
729 user_group=user_group, perm=perm)
729 user_group=user_group, perm=perm)
730 Session().commit()
730 Session().commit()
731
731
732 return {
732 return {
733 'msg': 'Granted perm: `%s` for user group: `%s` '
733 'msg': 'Granted perm: `%s` for user group: `%s` '
734 'in user group: `%s`' % (
734 'in user group: `%s`' % (
735 perm.permission_name, user_group.users_group_name,
735 perm.permission_name, user_group.users_group_name,
736 target_user_group.users_group_name
736 target_user_group.users_group_name
737 ),
737 ),
738 'success': True
738 'success': True
739 }
739 }
740 except Exception:
740 except Exception:
741 log.exception("Error occurred during editing permissions "
741 log.exception("Error occurred during editing permissions "
742 "for user group in user group")
742 "for user group in user group")
743 raise JSONRPCError(
743 raise JSONRPCError(
744 'failed to edit permission for user group: `%s` in '
744 'failed to edit permission for user group: `%s` in '
745 'user group: `%s`' % (
745 'user group: `%s`' % (
746 sourceusergroupid, target_user_group.users_group_name
746 sourceusergroupid, target_user_group.users_group_name
747 )
747 )
748 )
748 )
749
749
750
750
751 @jsonrpc_method()
751 @jsonrpc_method()
752 def revoke_user_group_permission_from_user_group(
752 def revoke_user_group_permission_from_user_group(
753 request, apiuser, usergroupid, sourceusergroupid):
753 request, apiuser, usergroupid, sourceusergroupid):
754 """
754 """
755 Revoke the permissions that one user group has to another.
755 Revoke the permissions that one user group has to another.
756
756
757 :param apiuser: This is filled automatically from the |authtoken|.
757 :param apiuser: This is filled automatically from the |authtoken|.
758 :type apiuser: AuthUser
758 :type apiuser: AuthUser
759 :param usergroupid: Set the user group on which to edit permissions.
759 :param usergroupid: Set the user group on which to edit permissions.
760 :type usergroupid: str or int
760 :type usergroupid: str or int
761 :param sourceusergroupid: Set the user group from which permissions
761 :param sourceusergroupid: Set the user group from which permissions
762 are revoked.
762 are revoked.
763 :type sourceusergroupid: str or int
763 :type sourceusergroupid: str or int
764
764
765 Example output:
765 Example output:
766
766
767 .. code-block:: bash
767 .. code-block:: bash
768
768
769 id : <id_given_in_input>
769 id : <id_given_in_input>
770 result : {
770 result : {
771 "msg": "Revoked perm for user group: `<user_group_name>` in user group: `<target_user_group_name>`",
771 "msg": "Revoked perm for user group: `<user_group_name>` in user group: `<target_user_group_name>`",
772 "success": true
772 "success": true
773 }
773 }
774 error : null
774 error : null
775 """
775 """
776
776
777 user_group = get_user_group_or_error(sourceusergroupid)
777 user_group = get_user_group_or_error(sourceusergroupid)
778 target_user_group = get_user_group_or_error(usergroupid)
778 target_user_group = get_user_group_or_error(usergroupid)
779
779
780 if not has_superadmin_permission(apiuser):
780 if not has_superadmin_permission(apiuser):
781 # check if we have admin permission for this user group !
781 # check if we have admin permission for this user group !
782 _perms = ('usergroup.admin',)
782 _perms = ('usergroup.admin',)
783 if not HasUserGroupPermissionAnyApi(*_perms)(
783 if not HasUserGroupPermissionAnyApi(*_perms)(
784 user=apiuser,
784 user=apiuser,
785 user_group_name=target_user_group.users_group_name):
785 user_group_name=target_user_group.users_group_name):
786 raise JSONRPCError(
786 raise JSONRPCError(
787 'to user group `%s` does not exist' % (usergroupid,))
787 'to user group `%s` does not exist' % (usergroupid,))
788
788
789 # check if we have at least read permission
789 # check if we have at least read permission
790 # for the source user group !
790 # for the source user group !
791 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
791 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
792 if not HasUserGroupPermissionAnyApi(*_perms)(
792 if not HasUserGroupPermissionAnyApi(*_perms)(
793 user=apiuser, user_group_name=user_group.users_group_name):
793 user=apiuser, user_group_name=user_group.users_group_name):
794 raise JSONRPCError(
794 raise JSONRPCError(
795 'user group `%s` does not exist' % (sourceusergroupid,))
795 'user group `%s` does not exist' % (sourceusergroupid,))
796
796
797 try:
797 try:
798 UserGroupModel().revoke_user_group_permission(
798 UserGroupModel().revoke_user_group_permission(
799 target_user_group=target_user_group, user_group=user_group)
799 target_user_group=target_user_group, user_group=user_group)
800 Session().commit()
800 Session().commit()
801
801
802 return {
802 return {
803 'msg': 'Revoked perm for user group: '
803 'msg': 'Revoked perm for user group: '
804 '`%s` in user group: `%s`' % (
804 '`%s` in user group: `%s`' % (
805 user_group.users_group_name,
805 user_group.users_group_name,
806 target_user_group.users_group_name
806 target_user_group.users_group_name
807 ),
807 ),
808 'success': True
808 'success': True
809 }
809 }
810 except Exception:
810 except Exception:
811 log.exception("Error occurred during editing permissions "
811 log.exception("Error occurred during editing permissions "
812 "for user group in user group")
812 "for user group in user group")
813 raise JSONRPCError(
813 raise JSONRPCError(
814 'failed to edit permission for user group: '
814 'failed to edit permission for user group: '
815 '`%s` in user group: `%s`' % (
815 '`%s` in user group: `%s`' % (
816 sourceusergroupid, target_user_group.users_group_name
816 sourceusergroupid, target_user_group.users_group_name
817 )
817 )
818 )
818 )
@@ -1,61 +1,125 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import re
21 import colander
22 import colander
22
23
23 from rhodecode import forms
24 from rhodecode import forms
24 from rhodecode.model.db import User
25 from rhodecode.model.db import User
26 from rhodecode.model.validation_schema import types, validators
25 from rhodecode.translation import _
27 from rhodecode.translation import _
26 from rhodecode.lib.auth import check_password
28 from rhodecode.lib.auth import check_password
27
29
28
30
29 @colander.deferred
31 @colander.deferred
30 def deferred_user_password_validator(node, kw):
32 def deferred_user_password_validator(node, kw):
31 username = kw.get('username')
33 username = kw.get('username')
32 user = User.get_by_username(username)
34 user = User.get_by_username(username)
33
35
34 def _user_password_validator(node, value):
36 def _user_password_validator(node, value):
35 if not check_password(value, user.password):
37 if not check_password(value, user.password):
36 msg = _('Password is incorrect')
38 msg = _('Password is incorrect')
37 raise colander.Invalid(node, msg)
39 raise colander.Invalid(node, msg)
38 return _user_password_validator
40 return _user_password_validator
39
41
40
42
41 class ChangePasswordSchema(colander.Schema):
43 class ChangePasswordSchema(colander.Schema):
42
44
43 current_password = colander.SchemaNode(
45 current_password = colander.SchemaNode(
44 colander.String(),
46 colander.String(),
45 missing=colander.required,
47 missing=colander.required,
46 widget=forms.widget.PasswordWidget(redisplay=True),
48 widget=forms.widget.PasswordWidget(redisplay=True),
47 validator=deferred_user_password_validator)
49 validator=deferred_user_password_validator)
48
50
49 new_password = colander.SchemaNode(
51 new_password = colander.SchemaNode(
50 colander.String(),
52 colander.String(),
51 missing=colander.required,
53 missing=colander.required,
52 widget=forms.widget.CheckedPasswordWidget(redisplay=True),
54 widget=forms.widget.CheckedPasswordWidget(redisplay=True),
53 validator=colander.Length(min=6))
55 validator=colander.Length(min=6))
54
56
55
56 def validator(self, form, values):
57 def validator(self, form, values):
57 if values['current_password'] == values['new_password']:
58 if values['current_password'] == values['new_password']:
58 exc = colander.Invalid(form)
59 exc = colander.Invalid(form)
59 exc['new_password'] = _('New password must be different '
60 exc['new_password'] = _('New password must be different '
60 'to old password')
61 'to old password')
61 raise exc
62 raise exc
63
64
65 @colander.deferred
66 def deferred_username_validator(node, kw):
67
68 def name_validator(node, value):
69 msg = _(
70 u'Username may only contain alphanumeric characters '
71 u'underscores, periods or dashes and must begin with '
72 u'alphanumeric character or underscore')
73
74 if not re.match(r'^[\w]{1}[\w\-\.]{0,254}$', value):
75 raise colander.Invalid(node, msg)
76
77 return name_validator
78
79
80 @colander.deferred
81 def deferred_email_validator(node, kw):
82 # NOTE(marcink): we might provide uniqueness validation later here...
83 return colander.Email()
84
85
86 class UserSchema(colander.Schema):
87 username = colander.SchemaNode(
88 colander.String(),
89 validator=deferred_username_validator)
90
91 email = colander.SchemaNode(
92 colander.String(),
93 validator=deferred_email_validator)
94
95 password = colander.SchemaNode(
96 colander.String(), missing='')
97
98 first_name = colander.SchemaNode(
99 colander.String(), missing='')
100
101 last_name = colander.SchemaNode(
102 colander.String(), missing='')
103
104 active = colander.SchemaNode(
105 types.StringBooleanType(),
106 missing=False)
107
108 admin = colander.SchemaNode(
109 types.StringBooleanType(),
110 missing=False)
111
112 extern_name = colander.SchemaNode(
113 colander.String(), missing='')
114
115 extern_type = colander.SchemaNode(
116 colander.String(), missing='')
117
118 def deserialize(self, cstruct):
119 """
120 Custom deserialize that allows to chain validation, and verify
121 permissions, and as last step uniqueness
122 """
123
124 appstruct = super(UserSchema, self).deserialize(cstruct)
125 return appstruct
General Comments 0
You need to be logged in to leave comments. Login now