bug 832. Fixing non-authorized configuration for testing
[osm/NBI.git] / osm_nbi / authconn.py
index 4d28bf8..1727590 100644 (file)
@@ -1,5 +1,23 @@
 # -*- coding: utf-8 -*-
 
 # -*- coding: utf-8 -*-
 
+# Copyright 2018 Whitestack, LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact: esousa@whitestack.com or glavado@whitestack.com
+##
+
 """
 Authconn implements an Abstract class for the Auth backend connector
 plugins with the definition of the methods to be implemented.
 """
 Authconn implements an Abstract class for the Auth backend connector
 plugins with the definition of the methods to be implemented.
@@ -9,15 +27,23 @@ __author__ = "Eduardo Sousa <esousa@whitestack.com>"
 __date__ = "$27-jul-2018 23:59:59$"
 
 from http import HTTPStatus
 __date__ = "$27-jul-2018 23:59:59$"
 
 from http import HTTPStatus
+from base_topic import BaseTopic
 
 
 class AuthException(Exception):
     """
 
 
 class AuthException(Exception):
     """
-    Authentication error.
+    Authentication error, because token, user password not recognized
     """
     def __init__(self, message, http_code=HTTPStatus.UNAUTHORIZED):
     """
     def __init__(self, message, http_code=HTTPStatus.UNAUTHORIZED):
+        super(AuthException, self).__init__(message)
         self.http_code = http_code
         self.http_code = http_code
-        Exception.__init__(self, message)
+
+
+class AuthExceptionUnauthorized(AuthException):
+    """
+    Authentication error, because not having rights to make this operation
+    """
+    pass
 
 
 class AuthconnException(Exception):
 
 
 class AuthconnException(Exception):
@@ -25,7 +51,7 @@ class AuthconnException(Exception):
     Common and base class Exception for all authconn exceptions.
     """
     def __init__(self, message, http_code=HTTPStatus.UNAUTHORIZED):
     Common and base class Exception for all authconn exceptions.
     """
     def __init__(self, message, http_code=HTTPStatus.UNAUTHORIZED):
-        Exception.__init__(message)
+        super(AuthconnException, self).__init__(message)
         self.http_code = http_code
 
 
         self.http_code = http_code
 
 
@@ -34,7 +60,7 @@ class AuthconnConnectionException(AuthconnException):
     Connectivity error with Auth backend.
     """
     def __init__(self, message, http_code=HTTPStatus.BAD_GATEWAY):
     Connectivity error with Auth backend.
     """
     def __init__(self, message, http_code=HTTPStatus.BAD_GATEWAY):
-        AuthconnException.__init__(self, message, http_code)
+        super(AuthconnConnectionException, self).__init__(message, http_code)
 
 
 class AuthconnNotSupportedException(AuthconnException):
 
 
 class AuthconnNotSupportedException(AuthconnException):
@@ -42,7 +68,7 @@ class AuthconnNotSupportedException(AuthconnException):
     The request is not supported by the Auth backend.
     """
     def __init__(self, message, http_code=HTTPStatus.NOT_IMPLEMENTED):
     The request is not supported by the Auth backend.
     """
     def __init__(self, message, http_code=HTTPStatus.NOT_IMPLEMENTED):
-        AuthconnException.__init__(self, message, http_code)
+        super(AuthconnNotSupportedException, self).__init__(message, http_code)
 
 
 class AuthconnNotImplementedException(AuthconnException):
 
 
 class AuthconnNotImplementedException(AuthconnException):
@@ -50,7 +76,7 @@ class AuthconnNotImplementedException(AuthconnException):
     The method is not implemented by the Auth backend.
     """
     def __init__(self, message, http_code=HTTPStatus.NOT_IMPLEMENTED):
     The method is not implemented by the Auth backend.
     """
     def __init__(self, message, http_code=HTTPStatus.NOT_IMPLEMENTED):
-        AuthconnException.__init__(self, message, http_code)
+        super(AuthconnNotImplementedException, self).__init__(message, http_code)
 
 
 class AuthconnOperationException(AuthconnException):
 
 
 class AuthconnOperationException(AuthconnException):
@@ -58,7 +84,23 @@ class AuthconnOperationException(AuthconnException):
     The operation executed failed.
     """
     def __init__(self, message, http_code=HTTPStatus.INTERNAL_SERVER_ERROR):
     The operation executed failed.
     """
     def __init__(self, message, http_code=HTTPStatus.INTERNAL_SERVER_ERROR):
-        AuthconnException.__init__(self, message, http_code)
+        super(AuthconnOperationException, self).__init__(message, http_code)
+
+
+class AuthconnNotFoundException(AuthconnException):
+    """
+    The operation executed failed because element not found.
+    """
+    def __init__(self, message, http_code=HTTPStatus.NOT_FOUND):
+        super().__init__(message, http_code)
+
+
+class AuthconnConflictException(AuthconnException):
+    """
+    The operation has conflicts.
+    """
+    def __init__(self, message, http_code=HTTPStatus.CONFLICT):
+        super().__init__(message, http_code)
 
 
 class Authconn:
 
 
 class Authconn:
@@ -67,7 +109,7 @@ class Authconn:
     Each Auth backend connector plugin must be a subclass of
     Authconn class.
     """
     Each Auth backend connector plugin must be a subclass of
     Authconn class.
     """
-    def __init__(self, config):
+    def __init__(self, config, db, token_cache):
         """
         Constructor of the Authconn class.
 
         """
         Constructor of the Authconn class.
 
@@ -78,25 +120,20 @@ class Authconn:
         """
         self.config = config
 
         """
         self.config = config
 
-    def authenticate_with_user_password(self, user, password):
+    def authenticate(self, user, password, project=None, token_info=None):
         """
         """
-        Authenticate a user using username and password.
+        Authenticate a user using username/password or token_info, plus project
+        :param user: user: name, id or None
+        :param password: password or None
+        :param project: name, id, or None. If None first found project will be used to get an scope token
+        :param token_info: previous token_info to obtain authorization
+        :return: the scoped token info or raises an exception. The token is a dictionary with:
+            _id:  token string id,
+            username: username,
+            project_id: scoped_token project_id,
+            project_name: scoped_token project_name,
+            expires: epoch time when it expires,
 
 
-        :param user: username
-        :param password: password
-        :return: an unscoped token that grants access to project list
-        """
-        raise AuthconnNotImplementedException("Should have implemented this")
-
-    def authenticate_with_token(self, token, project=None):
-        """
-        Authenticate a user using a token. Can be used to revalidate the token
-        or to get a scoped token.
-
-        :param token: a valid token.
-        :param project: (optional) project for a scoped token.
-        :return: return a revalidated token, scoped if a project was passed or
-        the previous token was already scoped.
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
@@ -118,108 +155,139 @@ class Authconn:
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
-    def get_project_list(self, token):
+    def create_user(self, user_info):
         """
         """
-        Get all the projects associated with a user.
+        Create a user.
 
 
-        :param token: valid token
-        :return: list of projects
+        :param user_info: full user info.
+        :raises AuthconnOperationException: if user creation failed.
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
-    def get_role_list(self, token):
+    def update_user(self, user_info):
         """
         """
-        Get role list for a scoped project.
+        Change the user name and/or password.
 
 
-        :param token: scoped token.
-        :return: returns the list of roles for the user in that project. If
-        the token is unscoped it returns None.
+        :param user_info:  user info modifications
+        :raises AuthconnNotImplementedException: if function not implemented
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
-    def create_user(self, user, password):
+    def delete_user(self, user_id):
         """
         """
-        Create a user.
+        Delete user.
 
 
-        :param user: username.
-        :param password: password.
-        :raises AuthconnOperationException: if user creation failed.
+        :param user_id: user identifier.
+        :raises AuthconnOperationException: if user deletion failed.
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
-    def change_password(self, user, new_password):
+    def get_user_list(self, filter_q=None):
         """
         """
-        Change the user password.
+        Get user list.
+
+        :param filter_q: dictionary to filter user list by name (username is also admited) and/or _id
+        :return: returns a list of users.
+        """
+
+    def get_user(self, id, fail=True):
+        filt = {BaseTopic.id_field("users", id): id}
+        users = self.get_user_list(filt)
+        if not users:
+            if fail:
+                raise AuthconnNotFoundException("User with {} not found".format(filt), http_code=HTTPStatus.NOT_FOUND)
+            else:
+                return None
+        return users[0]
 
 
-        :param user: username.
-        :param new_password: new password.
-        :raises AuthconnOperationException: if user password change failed.
+    def create_role(self, role_info):
+        """
+        Create a role.
+
+        :param role_info: full role info.
+        :raises AuthconnOperationException: if role creation failed.
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
-    def delete_user(self, user):
+    def delete_role(self, role_id):
         """
         """
-        Delete user.
+        Delete a role.
 
 
-        :param user: username.
+        :param role_id: role identifier.
         :raises AuthconnOperationException: if user deletion failed.
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
         :raises AuthconnOperationException: if user deletion failed.
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
-    def create_role(self, role):
+    def get_role_list(self, filter_q=None):
         """
         """
-        Create a role.
+        Get all the roles.
 
 
-        :param role: role name.
-        :raises AuthconnOperationException: if role creation failed.
+        :param filter_q: dictionary to filter role list by _id and/or name.
+        :return: list of roles
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
-    def delete_role(self, role):
-        """
-        Delete a role.
+    def get_role(self, id, fail=True):
+        filt = {BaseTopic.id_field("roles", id): id}
+        roles = self.get_role_list(filt)
+        if not roles:
+            if fail:
+                raise AuthconnNotFoundException("Role with {} not found".format(filt))
+            else:
+                return None
+        return roles[0]
 
 
-        :param role: role name.
-        :raises AuthconnOperationException: if user deletion failed.
+    def update_role(self, role_info):
+        """
+        Change the information of a role
+        :param role_info: full role info
+        :return: None
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
-    def create_project(self, project):
+    def create_project(self, project_info):
         """
         Create a project.
 
         """
         Create a project.
 
-        :param project: project name.
+        :param project_info: full project info.
+        :return: the internal id of the created project
         :raises AuthconnOperationException: if project creation failed.
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
         :raises AuthconnOperationException: if project creation failed.
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
-    def delete_project(self, project):
+    def delete_project(self, project_id):
         """
         Delete a project.
 
         """
         Delete a project.
 
-        :param project: project name.
+        :param project_id: project identifier.
         :raises AuthconnOperationException: if project deletion failed.
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
         :raises AuthconnOperationException: if project deletion failed.
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
-    def assign_role_to_user(self, user, project, role):
+    def get_project_list(self, filter_q=None):
         """
         """
-        Assigning a role to a user in a project.
+        Get all the projects.
 
 
-        :param user: username.
-        :param project: project name.
-        :param role: role name.
-        :raises AuthconnOperationException: if role assignment failed.
+        :param filter_q: dictionary to filter project list, by "name" and/or "_id"
+        :return: list of projects
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
         """
         raise AuthconnNotImplementedException("Should have implemented this")
 
-    def remove_role_from_user(self, user, project, role):
-        """
-        Remove a role from a user in a project.
-
-        :param user: username.
-        :param project: project name.
-        :param role: role name.
-        :raises AuthconnOperationException: if role assignment revocation failed.
+    def get_project(self, id, fail=True):
+        filt = {BaseTopic.id_field("projects", id): id}
+        projs = self.get_project_list(filt)
+        if not projs:
+            if fail:
+                raise AuthconnNotFoundException("project with {} not found".format(filt))
+            else:
+                return None
+        return projs[0]
+
+    def update_project(self, project_id, project_info):
+        """
+        Change the information of a project
+        :param project_id: project to be changed
+        :param project_info: full project info
+        :return: None
         """
         raise AuthconnNotImplementedException("Should have implemented this")
         """
         raise AuthconnNotImplementedException("Should have implemented this")