fix bug 749 750: Returns a proper Location Header for project-create
[osm/NBI.git] / osm_nbi / authconn_keystone.py
index 54442c8..c8d6811 100644 (file)
@@ -23,7 +23,7 @@ AuthconnKeystone implements implements the connector for
 Openstack Keystone and leverages the RBAC model, to bring
 it for OSM.
 """
 Openstack Keystone and leverages the RBAC model, to bring
 it for OSM.
 """
-import time
+
 
 __author__ = "Eduardo Sousa <esousa@whitestack.com>"
 __date__ = "$27-jul-2018 23:59:59$"
 
 __author__ = "Eduardo Sousa <esousa@whitestack.com>"
 __date__ = "$27-jul-2018 23:59:59$"
@@ -32,12 +32,14 @@ from authconn import Authconn, AuthException, AuthconnOperationException
 
 import logging
 import requests
 
 import logging
 import requests
+import time
 from keystoneauth1 import session
 from keystoneauth1.identity import v3
 from keystoneauth1.exceptions.base import ClientException
 from keystoneauth1.exceptions.http import Conflict
 from keystoneclient.v3 import client
 from http import HTTPStatus
 from keystoneauth1 import session
 from keystoneauth1.identity import v3
 from keystoneauth1.exceptions.base import ClientException
 from keystoneauth1.exceptions.http import Conflict
 from keystoneclient.v3 import client
 from http import HTTPStatus
+from validation import is_valid_uuid
 
 
 class AuthconnKeystone(Authconn):
 
 
 class AuthconnKeystone(Authconn):
@@ -95,9 +97,10 @@ class AuthconnKeystone(Authconn):
                 project_domain_name=self.project_domain_name)
 
             return token["auth_token"], project_names
                 project_domain_name=self.project_domain_name)
 
             return token["auth_token"], project_names
-        except ClientException:
-            self.logger.exception("Error during user authentication using keystone. Method: basic")
-            raise AuthException("Error during user authentication using Keystone", http_code=HTTPStatus.UNAUTHORIZED)
+        except ClientException as e:
+            self.logger.exception("Error during user authentication using keystone. Method: basic: {}".format(e))
+            raise AuthException("Error during user authentication using Keystone: {}".format(e),
+                                http_code=HTTPStatus.UNAUTHORIZED)
 
     def authenticate_with_token(self, token, project=None):
         """
 
     def authenticate_with_token(self, token, project=None):
         """
@@ -122,9 +125,10 @@ class AuthconnKeystone(Authconn):
                 project_domain_name=self.project_domain_name)
 
             return new_token["auth_token"], project_names
                 project_domain_name=self.project_domain_name)
 
             return new_token["auth_token"], project_names
-        except ClientException:
-            self.logger.exception("Error during user authentication using keystone. Method: bearer")
-            raise AuthException("Error during user authentication using Keystone", http_code=HTTPStatus.UNAUTHORIZED)
+        except ClientException as e:
+            self.logger.exception("Error during user authentication using keystone. Method: bearer: {}".format(e))
+            raise AuthException("Error during user authentication using Keystone: {}".format(e),
+                                http_code=HTTPStatus.UNAUTHORIZED)
 
     def validate_token(self, token):
         """
 
     def validate_token(self, token):
         """
@@ -141,9 +145,10 @@ class AuthconnKeystone(Authconn):
             token_info = self.keystone.tokens.validate(token=token)
 
             return token_info
             token_info = self.keystone.tokens.validate(token=token)
 
             return token_info
-        except ClientException:
-            self.logger.exception("Error during token validation using keystone")
-            raise AuthException("Error during token validation using Keystone", http_code=HTTPStatus.UNAUTHORIZED)
+        except ClientException as e:
+            self.logger.exception("Error during token validation using keystone: {}".format(e))
+            raise AuthException("Error during token validation using Keystone: {}".format(e),
+                                http_code=HTTPStatus.UNAUTHORIZED)
 
     def revoke_token(self, token):
         """
 
     def revoke_token(self, token):
         """
@@ -156,9 +161,10 @@ class AuthconnKeystone(Authconn):
             self.keystone.tokens.revoke_token(token=token)
 
             return True
             self.keystone.tokens.revoke_token(token=token)
 
             return True
-        except ClientException:
-            self.logger.exception("Error during token revocation using keystone")
-            raise AuthException("Error during token revocation using Keystone", http_code=HTTPStatus.UNAUTHORIZED)
+        except ClientException as e:
+            self.logger.exception("Error during token revocation using keystone: {}".format(e))
+            raise AuthException("Error during token revocation using Keystone: {}".format(e),
+                                http_code=HTTPStatus.UNAUTHORIZED)
 
     def get_user_project_list(self, token):
         """
 
     def get_user_project_list(self, token):
         """
@@ -173,9 +179,10 @@ class AuthconnKeystone(Authconn):
             project_names = [project.name for project in projects]
 
             return project_names
             project_names = [project.name for project in projects]
 
             return project_names
-        except ClientException:
-            self.logger.exception("Error during user project listing using keystone")
-            raise AuthException("Error during user project listing using Keystone", http_code=HTTPStatus.UNAUTHORIZED)
+        except ClientException as e:
+            self.logger.exception("Error during user project listing using keystone: {}".format(e))
+            raise AuthException("Error during user project listing using Keystone: {}".format(e),
+                                http_code=HTTPStatus.UNAUTHORIZED)
 
     def get_user_role_list(self, token):
         """
 
     def get_user_role_list(self, token):
         """
@@ -192,9 +199,10 @@ class AuthconnKeystone(Authconn):
             roles = [role.name for role in roles_info]
 
             return roles
             roles = [role.name for role in roles_info]
 
             return roles
-        except ClientException:
-            self.logger.exception("Error during user role listing using keystone")
-            raise AuthException("Error during user role listing using Keystone", http_code=HTTPStatus.UNAUTHORIZED)
+        except ClientException as e:
+            self.logger.exception("Error during user role listing using keystone: {}".format(e))
+            raise AuthException("Error during user role listing using Keystone: {}".format(e),
+                                http_code=HTTPStatus.UNAUTHORIZED)
 
     def create_user(self, user, password):
         """
 
     def create_user(self, user, password):
         """
@@ -208,9 +216,9 @@ class AuthconnKeystone(Authconn):
         try:
             new_user = self.keystone.users.create(user, password=password, domain=self.user_domain_name)
             return {"username": new_user.name, "_id": new_user.id}
         try:
             new_user = self.keystone.users.create(user, password=password, domain=self.user_domain_name)
             return {"username": new_user.name, "_id": new_user.id}
-        except ClientException:
-            self.logger.exception("Error during user creation using keystone")
-            raise AuthconnOperationException("Error during user creation using Keystone")
+        except ClientException as e:
+            self.logger.exception("Error during user creation using keystone: {}".format(e))
+            raise AuthconnOperationException("Error during user creation using Keystone: {}".format(e))
 
     def change_password(self, user, new_password):
         """
 
     def change_password(self, user, new_password):
         """
@@ -223,9 +231,9 @@ class AuthconnKeystone(Authconn):
         try:
             user_obj = list(filter(lambda x: x.name == user, self.keystone.users.list()))[0]
             self.keystone.users.update(user_obj, password=new_password)
         try:
             user_obj = list(filter(lambda x: x.name == user, self.keystone.users.list()))[0]
             self.keystone.users.update(user_obj, password=new_password)
-        except ClientException:
-            self.logger.exception("Error during user password update using keystone")
-            raise AuthconnOperationException("Error during user password update using Keystone")
+        except ClientException as e:
+            self.logger.exception("Error during user password update using keystone: {}".format(e))
+            raise AuthconnOperationException("Error during user password update using Keystone: {}".format(e))
 
     def delete_user(self, user_id):
         """
 
     def delete_user(self, user_id):
         """
@@ -243,51 +251,62 @@ class AuthconnKeystone(Authconn):
                 raise ClientException("User was not deleted")
 
             return True
                 raise ClientException("User was not deleted")
 
             return True
-        except ClientException:
-            self.logger.exception("Error during user deletion using keystone")
-            raise AuthconnOperationException("Error during user deletion using Keystone")
+        except ClientException as e:
+            self.logger.exception("Error during user deletion using keystone: {}".format(e))
+            raise AuthconnOperationException("Error during user deletion using Keystone: {}".format(e))
 
 
-    def get_user_list(self):
+    def get_user_list(self, filter_q={}):
         """
         Get user list.
 
         """
         Get user list.
 
+        :param filter_q: dictionary to filter user list.
         :return: returns a list of users.
         """
         try:
             users = self.keystone.users.list()
             users = [{
                 "username": user.name,
         :return: returns a list of users.
         """
         try:
             users = self.keystone.users.list()
             users = [{
                 "username": user.name,
-                "_id": user.id
+                "_id": user.id,
+                "id": user.id
             } for user in users if user.name != self.admin_username]
 
             } for user in users if user.name != self.admin_username]
 
+            allowed_fields = ["_id", "id", "username"]
+            for key in filter_q.keys():
+                if key not in allowed_fields:
+                    continue
+
+                users = [user for user in users 
+                         if filter_q[key] == user[key]]
+
             for user in users:
                 projects = self.keystone.projects.list(user=user["_id"])
                 projects = [{
                     "name": project.name,
             for user in users:
                 projects = self.keystone.projects.list(user=user["_id"])
                 projects = [{
                     "name": project.name,
-                    "_id": project.id
+                    "_id": project.id,
+                    "id": project.id
                 } for project in projects]
 
                 for project in projects:
                     roles = self.keystone.roles.list(user=user["_id"], project=project["_id"])
                     roles = [{
                         "name": role.name,
                 } for project in projects]
 
                 for project in projects:
                     roles = self.keystone.roles.list(user=user["_id"], project=project["_id"])
                     roles = [{
                         "name": role.name,
-                        "_id": role.id
+                        "_id": role.id,
+                        "id": role.id
                     } for role in roles]
                     project["roles"] = roles
 
                 user["projects"] = projects
 
             return users
                     } for role in roles]
                     project["roles"] = roles
 
                 user["projects"] = projects
 
             return users
-        except ClientException:
-            self.logger.exception("Error during user listing using keystone")
-            raise AuthconnOperationException("Error during user listing using Keystone")
+        except ClientException as e:
+            self.logger.exception("Error during user listing using keystone: {}".format(e))
+            raise AuthconnOperationException("Error during user listing using Keystone: {}".format(e))
 
     def get_role_list(self):
         """
         Get role list.
 
 
     def get_role_list(self):
         """
         Get role list.
 
-        :return: returns the list of roles for the user in that project. If
-        the token is unscoped it returns None.
+        :return: returns the list of roles.
         """
         try:
             roles_list = self.keystone.roles.list()
         """
         try:
             roles_list = self.keystone.roles.list()
@@ -298,9 +317,10 @@ class AuthconnKeystone(Authconn):
             } for role in roles_list if role.name != "service"]
 
             return roles
             } for role in roles_list if role.name != "service"]
 
             return roles
-        except ClientException:
-            self.logger.exception("Error during user role listing using keystone")
-            raise AuthException("Error during user role listing using Keystone", http_code=HTTPStatus.UNAUTHORIZED)
+        except ClientException as e:
+            self.logger.exception("Error during user role listing using keystone: {}".format(e))
+            raise AuthException("Error during user role listing using Keystone: {}".format(e),
+                                http_code=HTTPStatus.UNAUTHORIZED)
 
     def create_role(self, role):
         """
 
     def create_role(self, role):
         """
@@ -314,9 +334,9 @@ class AuthconnKeystone(Authconn):
             return {"name": result.name, "_id": result.id}
         except Conflict as ex:
             self.logger.info("Duplicate entry: %s", str(ex))
             return {"name": result.name, "_id": result.id}
         except Conflict as ex:
             self.logger.info("Duplicate entry: %s", str(ex))
-        except ClientException:
-            self.logger.exception("Error during role creation using keystone")
-            raise AuthconnOperationException("Error during role creation using Keystone")
+        except ClientException as e:
+            self.logger.exception("Error during role creation using keystone: {}".format(e))
+            raise AuthconnOperationException("Error during role creation using Keystone: {}".format(e))
 
     def delete_role(self, role_id):
         """
 
     def delete_role(self, role_id):
         """
@@ -334,14 +354,15 @@ class AuthconnKeystone(Authconn):
                 raise ClientException("Role was not deleted")
 
             return True
                 raise ClientException("Role was not deleted")
 
             return True
-        except ClientException:
-            self.logger.exception("Error during role deletion using keystone")
-            raise AuthconnOperationException("Error during role deletion using Keystone")
+        except ClientException as e:
+            self.logger.exception("Error during role deletion using keystone: {}".format(e))
+            raise AuthconnOperationException("Error during role deletion using Keystone: {}".format(e))
 
 
-    def get_project_list(self):
+    def get_project_list(self, filter_q={}):
         """
         Get all the projects.
 
         """
         Get all the projects.
 
+        :param filter_q: dictionary to filter project list.
         :return: list of projects
         """
         try:
         :return: list of projects
         """
         try:
@@ -351,24 +372,34 @@ class AuthconnKeystone(Authconn):
                 "_id": project.id
             } for project in projects if project.name != self.admin_project]
 
                 "_id": project.id
             } for project in projects if project.name != self.admin_project]
 
+            allowed_fields = ["_id", "name"]
+            for key in filter_q.keys():
+                if key not in allowed_fields:
+                    continue
+
+                projects = [project for project in projects
+                            if filter_q[key] == project[key]]
+
             return projects
             return projects
-        except ClientException:
-            self.logger.exception("Error during user project listing using keystone")
-            raise AuthException("Error during user project listing using Keystone", http_code=HTTPStatus.UNAUTHORIZED)
+        except ClientException as e:
+            self.logger.exception("Error during user project listing using keystone: {}".format(e))
+            raise AuthException("Error during user project listing using Keystone: {}".format(e),
+                                http_code=HTTPStatus.UNAUTHORIZED)
 
     def create_project(self, project):
         """
         Create a project.
 
         :param project: project name.
 
     def create_project(self, project):
         """
         Create a project.
 
         :param project: project name.
+        :return: the internal id of the created project
         :raises AuthconnOperationException: if project creation failed.
         """
         try:
             result = self.keystone.projects.create(project, self.project_domain_name)
         :raises AuthconnOperationException: if project creation failed.
         """
         try:
             result = self.keystone.projects.create(project, self.project_domain_name)
-            return {"name": result.name, "_id": result.id}
-        except ClientException:
-            self.logger.exception("Error during project creation using keystone")
-            raise AuthconnOperationException("Error during project creation using Keystone")
+            return result.id
+        except ClientException as e:
+            self.logger.exception("Error during project creation using keystone: {}".format(e))
+            raise AuthconnOperationException("Error during project creation using Keystone: {}".format(e))
 
     def delete_project(self, project_id):
         """
 
     def delete_project(self, project_id):
         """
@@ -386,9 +417,22 @@ class AuthconnKeystone(Authconn):
                 raise ClientException("Project was not deleted")
 
             return True
                 raise ClientException("Project was not deleted")
 
             return True
-        except ClientException:
-            self.logger.exception("Error during project deletion using keystone")
-            raise AuthconnOperationException("Error during project deletion using Keystone")
+        except ClientException as e:
+            self.logger.exception("Error during project deletion using keystone: {}".format(e))
+            raise AuthconnOperationException("Error during project deletion using Keystone: {}".format(e))
+
+    def update_project(self, project_id, new_name):
+        """
+        Change the name of a project
+        :param project_id: project to be changed
+        :param new_name: new name
+        :return: None
+        """
+        try:
+            self.keystone.projects.update(project_id, name=new_name)
+        except ClientException as e:
+            self.logger.exception("Error during project update using keystone: {}".format(e))
+            raise AuthconnOperationException("Error during project deletion using Keystone: {}".format(e))
 
     def assign_role_to_user(self, user, project, role):
         """
 
     def assign_role_to_user(self, user, project, role):
         """
@@ -400,14 +444,25 @@ class AuthconnKeystone(Authconn):
         :raises AuthconnOperationException: if role assignment failed.
         """
         try:
         :raises AuthconnOperationException: if role assignment failed.
         """
         try:
-            user_obj = list(filter(lambda x: x.name == user, self.keystone.users.list()))[0]
-            project_obj = list(filter(lambda x: x.name == project, self.keystone.projects.list()))[0]
-            role_obj = list(filter(lambda x: x.name == role, self.keystone.roles.list()))[0]
+            if is_valid_uuid(user):
+                user_obj = self.keystone.users.get(user)
+            else:
+                user_obj = self.keystone.users.list(name=user)[0]
+
+            if is_valid_uuid(project):
+                project_obj = self.keystone.projects.get(project)
+            else:
+                project_obj = self.keystone.projects.list(name=project)[0]
+
+            if is_valid_uuid(role):
+                role_obj = self.keystone.roles.get(role)
+            else:
+                role_obj = self.keystone.roles.list(name=role)[0]
 
             self.keystone.roles.grant(role_obj, user=user_obj, project=project_obj)
 
             self.keystone.roles.grant(role_obj, user=user_obj, project=project_obj)
-        except ClientException:
-            self.logger.exception("Error during user role assignment using keystone")
-            raise AuthconnOperationException("Error during user role assignment using Keystone")
+        except ClientException as e:
+            self.logger.exception("Error during user role assignment using keystone: {}".format(e))
+            raise AuthconnOperationException("Error during user role assignment using Keystone: {}".format(e))
 
     def remove_role_from_user(self, user, project, role):
         """
 
     def remove_role_from_user(self, user, project, role):
         """
@@ -424,6 +479,6 @@ class AuthconnKeystone(Authconn):
             role_obj = list(filter(lambda x: x.name == role, self.keystone.roles.list()))[0]
 
             self.keystone.roles.revoke(role_obj, user=user_obj, project=project_obj)
             role_obj = list(filter(lambda x: x.name == role, self.keystone.roles.list()))[0]
 
             self.keystone.roles.revoke(role_obj, user=user_obj, project=project_obj)
-        except ClientException:
-            self.logger.exception("Error during user role revocation using keystone")
-            raise AuthconnOperationException("Error during user role revocation using Keystone")
+        except ClientException as e:
+            self.logger.exception("Error during user role revocation using keystone: {}".format(e))
+            raise AuthconnOperationException("Error during user role revocation using Keystone: {}".format(e))