Added seed code for access-management.
[ta/access-management.git] / src / access_management / rest-plugin / 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 access_management.db.amdb as amdb
16 from am_api_base import *
17
18
19 class Roles(AMApiBase):
20
21     """
22     Role create operations
23
24     .. :quickref: Roles;Role create operations
25
26     .. http:post:: /am/v1/roles
27
28     **Start Role create**
29
30     **Example request**:
31
32     .. sourcecode:: http
33
34         POST am/v1/roles HTTP/1.1
35         Host: haproxyvip:61200
36         Accept: application/json
37         {
38             "role_name": "test_role"
39             "desc": "This is a test role"
40         }
41
42     :> json string role_name: The created role name.
43     :> json string desc: A short description from the created role.
44
45     **Example response**:
46
47     .. sourcecode:: http
48
49         HTTP/1.1 200 OK
50         {
51             "code": 0,
52             "description": "Role created."
53         }
54
55     :> json int code: the status code
56     :> json string description: the error description, present if code is non zero
57
58     Role modify operations
59
60     .. :quickref: Roles;Role modify operations
61
62     .. http:put:: /am/v1/roles
63
64     **Start Role modify**
65
66     **Example request**:
67
68     .. sourcecode:: http
69
70         PUT am/v1/roles HTTP/1.1
71         Host: haproxyvip:61200
72         Accept: application/json
73         {
74             "role_name": "test_role"
75             "desc": "This is a test role"
76         }
77
78     :> json string role_name: The modified role name.
79     :> json string desc: A short description from the modified role.
80
81     **Example response**:
82
83     .. sourcecode:: http
84
85         HTTP/1.1 200 OK
86         {
87             "code": 0,
88             "description": "Role modified."
89         }
90
91     :> json int code: the status code
92     :> json string description: the error description, present if code is non zero
93
94     Role delete operations
95
96     .. :quickref: Roles;Role delete operations
97
98     .. http:delete:: /am/v1/roles
99
100     **Start Role delete**
101
102     **Example request**:
103
104     .. sourcecode:: http
105
106         DELETE am/v1/roles HTTP/1.1
107         Host: haproxyvip:61200
108         Accept: application/json
109         {
110             "role_name": "test_role"
111         }
112
113     :> json string role_name: The deleted role name.
114
115     **Example response**:
116
117     .. sourcecode:: http
118
119         HTTP/1.1 200 OK
120         {
121             "code": 0,
122             "description": "Role deleted."
123         }
124
125     :> json int code: the status code
126     :> json string description: the error description, present if code is non zero
127
128     Role list operations
129
130     .. :quickref: Roles;Role list operations
131
132     .. http:get:: /am/v1/roles
133
134     **Start Role list**
135
136     **Example request**:
137
138     .. sourcecode:: http
139
140         GET am/v1/roles HTTP/1.1
141         Host: haproxyvip:61200
142         Accept: application/json
143
144     **Example response**:
145
146     .. sourcecode:: http
147
148         HTTP/1.1 200 OK
149         {
150             "code": 0,
151             "description": "Role list."
152             "data":
153             {
154                 "alarm_admin":
155                 {
156                     "desc": "Alarm Administrator",
157                     "is_chroot": false,
158                     "is_service": true,
159                     "role_name": "alarm_admin"
160                 },
161                 "alarm_viewer":
162                 {
163                     "desc": "Alarm Viewer",
164                     "is_chroot": false,
165                     "is_service": true,
166                     "role_name": "alarm_viewer"
167                 }
168             }
169         }
170
171     :> json int code: the status code
172     :> json string description: the error description, present if code is non zero
173     :> json object data: a dictionary with the existing roles
174     :> json string role_name: The role name.
175     :> json string desc: The role description.
176     :> json string is_chroot: If this field is true, then this is a chroot user role.
177     :> json string is_service: If this field is true, then this is a service role and we created this role in deploymnet time.
178     """
179
180     endpoints = ['roles']
181     parser_arguments = ['role_name',
182                         'desc']
183
184     def post(self):
185         self.logger.info("Received a role create request!")
186         args = self.parse_args()
187         if args["desc"] is None:
188             args["desc"] = ""
189         state, result = self._role_create(args)
190
191         if state:
192             self.logger.info("The {0} role created!".format(args["role_name"]))
193             return AMApiBase.embed_data({}, 0, result)
194         else:
195             self.logger.error("The {0} role creation failed: {1}".format(args["role_name"], result))
196             return AMApiBase.construct_error_response(1, result)
197
198     def put(self):
199         self.logger.info("Received a role modify request!")
200         args = self.parse_args()
201         if args["desc"] is None:
202             args["desc"] = ""
203         state, result = self._role_modify(args)
204
205         if state:
206             self.logger.info("The {0} role modified!".format(args["role_name"]))
207             return AMApiBase.embed_data({}, 0, result)
208         else:
209             self.logger.error("The {0} role modify failed: {1}".format(args["role_name"], result))
210             return AMApiBase.construct_error_response(1, result)
211
212     def get(self):
213         self.logger.info("Received a role list request!")
214         state, roles = self._role_list()
215
216         if state:
217             self.logger.info("The role list response done!")
218             return AMApiBase.embed_data(roles, 0, "Role list.")
219         else:
220             self.logger.error("Role list creation failed: {0}".format(roles))
221             return AMApiBase.construct_error_response(1, roles)
222
223     def delete(self):
224         self.logger.info("Received a role delete request!")
225         args = self.parse_args()
226
227         state, message = self._role_delete(args)
228
229         if state:
230             self.logger.info("The {0} role deleted!".format(args["role_name"]))
231             return AMApiBase.embed_data({}, 0, message)
232         else:
233             self.logger.error("The {0} role deletion failed: {1}".format(args["role_name"], message))
234             return AMApiBase.construct_error_response(1, message)
235
236     def _role_modify(self, args):
237         state_open, message_open = self._open_db()
238         if state_open:
239             try:
240                 self.db.set_role_param(args["role_name"], args["desc"])
241             except amdb.NotAllowedOperation:
242                 self.logger.error("Modifying service role is not allowed: {0}".format(args["role_name"]))
243                 return False, "Modifying service role is not allowed: {0}".format(args["role_name"])
244             except Exception as ex:
245                 self.logger.error("Internal error: {0}".format(ex))
246                 return False, "Internal error: {0}".format(ex)
247             finally:
248                 state_close, message_close = self._close_db()
249                 if not state_close:
250                     self._close_db()
251             return True, "Role modified."
252         else:
253             return False, message_open
254
255     def _role_create(self, args):
256         state_open, message_open = self._open_db()
257         if state_open:
258             try:
259                 self.db.create_role(args["role_name"], args["desc"])
260                 try:
261                     self.keystone.roles.create(args["role_name"])
262                 except Exception as ex:
263                     self.db.delete_role(args["role_name"])
264                     self.logger.error("Role {} already exists".format(args["role_name"]))
265                     return False, "Role {} already exists".format(args["role_name"])
266             except amdb.AlreadyExist:
267                 self.logger.error("Role already exists in table: {0}".format(args["role_name"]))
268                 return False, "Role already exists in table: {0}".format(args["role_name"])
269             except Exception as ex:
270                 self.logger.error("Internal error: {0}".format(ex))
271                 return False, "Internal error: {0}".format(ex)
272             finally:
273                 state_close, message_close = self._close_db()
274                 if not state_close:
275                     self._close_db()
276         else:
277             return False, message_open
278         return True, "Role created."
279
280     def _role_list(self):
281         state_open, message_open = self._open_db()
282         if state_open:
283             try:
284                 roles = self.db.get_all_roles()
285             except Exception as ex:
286                 self.logger.error("Internal error: {0}".format(ex))
287                 return False, "Internal error: {0}".format(ex)
288             finally:
289                 state_close, message_close = self._close_db()
290                 if not state_close:
291                     self._close_db()
292             return True, roles
293         else:
294             return False, message_open
295
296     def _add_roles_back_to_users(self, role_name):
297         uuid_list = self.db.get_role_users(role_name)
298         for uuid in uuid_list:
299             username, def_project = self.get_user_from_uuid(uuid)
300             state, message = self.modify_role_in_keystone(role_name, uuid, "put", def_project)
301             if not state:
302                 return False, "Role deletion failed, please try again!"
303         return False, "Role deletion failed, try again"
304
305     def _role_delete(self, args):
306         state_open, message_open = self._open_db()
307         if state_open:
308             try:
309                 db_role = self.db.get_role(args["role_name"])
310                 if not db_role._data["is_service"]:
311                     role_id = self.get_role_id(args["role_name"])
312                     if role_id is not None:
313                         try:
314                             self.keystone.roles.delete(role_id)
315                         except Exception as ex:
316                             self.logger.error("Some problem occured: {}".format(ex))
317                             return False, "Some problem occured: {}".format(ex)
318
319                         try:
320                             self.db.delete_role(args["role_name"])
321                         except Exception:
322                             try:
323                                 self.keystone.roles.create(args["role_name"])
324                             except Exception:
325                                 self.logger.error("Error during deleting role: {}".format(args["role_name"]))
326                                 return False, "Error during deleting role: {}".format(args["role_name"])
327                             state, message = self._add_roles_back_to_users(args["role_name"])
328                             return state, message
329                 else:
330                     raise amdb.NotAllowedOperation("")
331             except amdb.NotAllowedOperation:
332                 self.logger.error("Deleting service role is not allowed: {0}".format(args["role_name"]))
333                 return False, "Deleting service role is not allowed: {0}".format(args["role_name"])
334             except Exception as ex:
335                 self.logger.error("Internal error: {0}".format(ex))
336                 return False, "Internal error: {0}".format(ex)
337             finally:
338                 state_close, message_close = self._close_db()
339                 if not state_close:
340                     self._close_db()
341             return True, "Role deleted."
342         else:
343             return False, message_open