Added seed code for access-management.
[ta/access-management.git] / src / access_management / rest-plugin / users_roles.py
1 # Copyright 2019 Nokia
2
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 import time
16 import access_management.db.amdb as amdb
17 from am_api_base import *
18 from cmframework.apis import cmclient
19
20
21 class UsersRoles(AMApiBase):
22
23     """
24     User add role operations
25
26     .. :quickref: User roles;User add role operations
27
28     .. http:post:: /am/v1/users/roles
29
30     **Start User add role**
31
32     **Example request**:
33
34     .. sourcecode:: http
35
36         POST am/v1/users/roles HTTP/1.1
37         Host: haproxyvip:61200
38         Accept: application/json
39         {
40             "user": <uuid> or <username>
41             "role_name": test_role
42         }
43
44     :> json string user: The user's id or name.
45     :> json string role_name: The user's new role.
46
47     **Example response**:
48
49     .. sourcecode:: http
50
51         HTTP/1.1 200 OK
52         {
53             "code": 0,
54             "description": "Role add to user."
55         }
56
57     :> json int code: the status code
58     :> json string description: the error description, present if code is non zero
59
60     User remove role operations
61
62     .. :quickref: User roles;User remove role operations
63
64     .. http:delete:: /am/v1/users/roles
65
66     **Start User remove role**
67
68     **Example request**:
69
70     .. sourcecode:: http
71
72         DELETE am/v1/users/roles HTTP/1.1
73         Host: haproxyvip:61200
74         Accept: application/json
75         {
76             "user": <uuid> or <username>
77             "role_name": test_role
78         }
79
80     :> json string user: The user's id or name.
81     :> json string role_name: Remove this role from the user.
82
83     **Example response**:
84
85     .. sourcecode:: http
86
87         HTTP/1.1 200 OK
88         {
89             "code": 0,
90             "description": "Role removed from user."
91         }
92
93     :> json int code: the status code
94     :> json string description: the error description, present if code is non zero
95     """
96
97     endpoints = ['users/roles']
98     parser_arguments = ['user',
99                         'role_name']
100
101     def post(self):
102         self.logger.info("Received a user add role request!")
103         args = self.parse_args()
104
105         if args["role_name"] is None:
106             self.logger.error("Role name parameter is missing!")
107             return AMApiBase.embed_data({}, 1, "Role name parameter is missing!")
108
109         state, user_info = self.get_uuid_and_name(args["user"])
110         if state:
111             username, def_project = self.get_user_from_uuid(user_info["id"])
112             state, message = self._add_role(args['role_name'], def_project, user_info)
113
114             if state:
115                 self.logger.info("The {0} role is added to the {1} user!".format(args["role_name"], user_info["name"]))
116                 return AMApiBase.embed_data({}, 0, "Role add to user.")
117             else:
118                 self.logger.error("The {0} role addition to the {1} user failed: {2}".format(args["role_name"], user_info["name"], message))
119                 return AMApiBase.construct_error_response(1, message)
120         else:
121             self.logger.error(user_info)
122             return AMApiBase.embed_data({}, 1, user_info)
123
124     def delete(self):
125         self.logger.info("Received a user remove role request!")
126         args = self.parse_args()
127
128         if args["role_name"] is None:
129             self.logger.error("Role name parameter is missing!")
130             return AMApiBase.embed_data({}, 1, "Role name parameter is missing!")
131
132         state, user_info = self.get_uuid_and_name(args["user"])
133         if state:
134             token_owner = self.get_uuid_from_token()
135             if user_info["id"] == token_owner and args["role_name"] == defaults.INF_ADMIN_ROLE_NAME:
136                 self.logger.error("The {0} user tried to removed own ".format(user_info["name"])+defaults.INF_ADMIN_ROLE_NAME+" role!")
137                 return AMApiBase.embed_data({}, 1, "You cannot remove own "+defaults.INF_ADMIN_ROLE_NAME+" role!")
138
139             username, def_project = self.get_user_from_uuid(user_info["id"])
140             state, message = self._remove_role(args["role_name"], def_project, user_info)
141
142             if state:
143                 self.logger.info("The {0} role removed from the {1} user!".format(args["role_name"], user_info["name"]))
144                 return AMApiBase.embed_data({}, 0, "Role removed from user.")
145             else:
146                 self.logger.error("Removal of {0} role from {1} user failed: {2}".format(args["role_name"], user_info["name"], message))
147                 return AMApiBase.construct_error_response(1, message)
148         else:
149             self.logger.error(user_info)
150             return AMApiBase.embed_data({}, 1, user_info)
151
152     def _remove_role(self, role_name, project, user_info):
153         state_open, message_open = self._open_db()
154         if state_open:
155             need_admin_role = True
156             try:
157                 roles = self.db.get_user_roles(user_info["id"])
158             except NotExist:
159                 return False, 'User {0} does not exist.'.format(user_info["name"])
160             except Exception as ex:
161                 return False, 'Error retrieving roles for user {0}: {1}'.format(user_info["name"], ex)
162             if (role_name == defaults.INF_ADMIN_ROLE_NAME and defaults.OS_ADMIN_ROLE_NAME in roles) or (role_name == defaults.OS_ADMIN_ROLE_NAME and defaults.INF_ADMIN_ROLE_NAME in roles):
163                 need_admin_role = False
164             state, message = self.modify_role_in_keystone(role_name, user_info["id"], "delete", project, need_admin_role)
165             if not state:
166                 return state, message
167
168             try:
169 #            self.db.connect()
170             # remove chroot user only if the role is chroot role
171                 self.logger.debug("Check the chroot role, when removing a role!")
172                 if self.db.is_chroot_role(role_name):
173                     self.logger.debug("This is a chroot role!")
174                     for x in range(3):
175                         self.remove_chroot_linux_role_handling(user_info["name"], "Chroot", "cloud.chroot")
176                         time.sleep(2)
177                         if self.check_chroot_linux_state(user_info["name"], "cloud.chroot", "absent"):
178                             self.db.delete_user_role(user_info["id"], role_name)
179                             return True, "Success"
180
181                     self.logger.error("The {0} user cannot remove {1} role, because the cm framework set_property's function failed.".format(user_info["name"], role_name))
182                     return False, "The chroot user is not removed. Please try again!"
183
184                 if role_name == "linux_user":
185                     self.logger.debug("This is a linux_user role!")
186                     for x in range(3):
187                         self.remove_chroot_linux_role_handling(user_info["name"], "Linux", "cloud.linuxuser")
188                         time.sleep(2)
189                         if self.check_chroot_linux_state(user_info["name"], "cloud.linuxuser", "absent"):
190                             self.db.delete_user_role(user_info["id"], role_name)
191                             return True, "Success"
192
193                     self.logger.error("The {0} user cannot remove {1} role, because the cm framework set_property's function failed.".format(user_info["name"], role_name))
194                     return False, "The linux user is not removed. Please try again!"
195
196                 self.db.delete_user_role(user_info["id"], role_name)
197             except amdb.NotAllowedOperation:
198                 return False, 'Service role cannot be deleted: {0}'.format(user_info["name"])
199             except amdb.NotExist:
200                 return False, 'User {0} has no role {1}.'.format(user_info["name"], role_name)
201             except amdb.AlreadyExist:
202                 return False, 'Role for user already exists in table: {0}:{1}'.format(user_info["name"], role_name)
203             except Exception as ex:
204                 return False, ex
205             finally:
206                 state_close, message_close = self._close_db()
207                 if not state_close:
208                     self._close_db()
209             return True, "Success"
210         else:
211             return False, message_open
212
213     def _add_role(self, role_name, project, user_info):
214         state, message = self.modify_role_in_keystone(role_name, user_info["id"], "put", project)
215         if not state:
216             return state, message
217
218         state, message = self.add_role_db_functions(role_name, user_info)
219         return state, message
220
221     def add_role_db_functions(self, role_name, user_info):
222         state_open, message_open = self._open_db()
223         if state_open:
224             try:
225                 roles = self.db.get_user_roles(user_info["id"])
226                 self.db.add_user_role(user_info["id"], role_name)
227
228                 # create chroot user only if the role is chroot role
229                 self.logger.debug("Check the chroot role, when adding a role!")
230                 if self.db.is_chroot_role(role_name):
231                     self.logger.debug("This is a chroot role!")
232
233                     if "linux_user" in roles:
234                         self.logger.error("The {0} user cannot get {1} chroot role, because this user has a linux_user role".format(user_info["name"], role_name))
235                         self.db.delete_user_role(user_info["id"], role_name)
236                         return False, "The {0} user cannot get {1} chroot role, because this user has a linux_user role".format(user_info["name"], role_name)
237
238                     for x in range(3):
239                         self.add_chroot_linux_role_handling(user_info["id"], "Chroot", "cloud.chroot", role_name)
240                         time.sleep(2)
241                         if self.check_chroot_linux_state(user_info["name"], "cloud.chroot", "present"):
242                             return True, "Success"
243
244                     self.db.delete_user_role(user_info["id"], role_name)
245                     self.logger.error("The {0} user cannot get {1} role, because the cm framework set_property's function failed.".format(user_info["name"], role_name))
246                     return False, "The chroot user is not created. Please try again!"
247
248                 # create linux user only if the role is linux_user role
249                 if role_name == "linux_user":
250                     self.logger.debug("This is a linux_user role!")
251                     have_a_chroot = False
252                     self.logger.debug("role list: {0}".format(roles))
253                     for role in roles:
254                         if self.db.is_chroot_role(role):
255                             have_a_chroot = True
256
257                     if have_a_chroot:
258                         self.logger.error("The {0} user cannot get {1} role, because this user has a chroot role".format(user_info["name"], role_name))
259                         self.db.delete_user_role(user_info["id"], role_name)
260                         return False, "The {0} user cannot get {1} role, because this user has a chroot role".format(user_info["name"], role_name)
261
262                     for x in range(3):
263                         self.add_chroot_linux_role_handling(user_info["id"], "Linux", "cloud.linuxuser", None)
264                         time.sleep(2)
265                         if self.check_chroot_linux_state(user_info["name"], "cloud.linuxuser", "present"):
266                             return True, "Success"
267
268                     self.db.delete_user_role(user_info["id"], role_name)
269                     self.logger.error("The {0} user cannot get {1} role, because the cm framework set_property's function failed.".format(user_info["name"], role_name))
270                     return False, "The linux user is not created. Please try again!"
271
272             except amdb.NotExist:
273                 return False, 'The user {} or role {} not exist.'.format(user_info["name"], role_name)
274             except amdb.AlreadyExist:
275                 return False, 'Role for user already exists in table: {0}:{1}'.format(user_info["name"], role_name)
276             except Exception as ex:
277                 return False, ex
278             finally:
279                 state_close, message_close = self._close_db()
280                 if not state_close:
281                     self._close_db()
282             return True, "Success"
283         else:
284             return False, message_open
285
286     def add_chroot_linux_role_handling(self, user_id, user_type, list_name, group):
287         cmc = cmclient.CMClient()
288         user_list = cmc.get_property(list_name)
289         if user_list is None:
290             cmc.set_property(list_name, json.dumps([]))
291             user_list = cmc.get_property(list_name)
292         user_list = json.loads(user_list)
293         self.logger.debug("{0} user list before the change: {1}".format(user_type, json.dumps(user_list)))
294         add = True
295         self.logger.debug("The {0} user list exists!".format(user_type))
296         username, def_project = self.get_user_from_uuid(user_id)
297         self.logger.debug("Username: {0}".format(username))
298         for element in user_list:
299             if element["name"] == username:
300                 if element["state"] == "present":
301                     self.logger.error("The {0} user has an active {1} chroot role".format(username, element["group"]))
302                     self.db.delete_user_role(user_id, group)
303                     return False, "The {0} users have an active {1} chroot role".format(username, element["group"])
304                 else:
305                     self.logger.debug("The {0} user has an active linux_user role".format(username))
306                     if group is not None:
307                         element["group"] = group
308                     element["state"] = "present"
309                     element["remove"] = "no"
310                     add = False
311         if add:
312             new_user = {"name": username, "password": "", "state": "present", "remove": "no", "lock_state": "-u", "public_key": ""}
313             if group is not None:
314                 new_user["group"]= group
315             user_list.append(new_user)
316         self.logger.debug("{0} user list after the change: {1}".format(user_type, json.dumps(user_list)))
317         cmc.set_property(list_name, json.dumps(user_list))
318
319     def remove_chroot_linux_role_handling(self, username, user_type, list_name):
320         cmc = cmclient.CMClient()
321         user_list = cmc.get_property(list_name)
322         user_list = json.loads(user_list)
323         self.logger.debug("{0} user list before the change: {1}".format(user_type, json.dumps(user_list)))
324         if user_list is not None:
325             self.logger.debug("The {0} user list exists!".format(user_type))
326             for val in user_list:
327                 if val["name"] == username:
328                     val["public_key"] = ""
329                     val["state"] = "absent"
330                     val["remove"] = "yes"
331                     val["password"] = ""
332                     break
333             self.logger.debug("{0} user list after the change: {1}".format(user_type, json.dumps(user_list)))
334             cmc.set_property(list_name, json.dumps(user_list))