From a6bb45d79abef42b8585cfa61aedf32e4326f2c9 Mon Sep 17 00:00:00 2001 From: tierno Date: Fri, 14 Jun 2019 09:45:39 +0000 Subject: [PATCH] bug 739 reload roles info when there is a change at roles Adding 'admin' operation to track query string ADMIN Change-Id: I2af27018643fa5e84dce3c606249d66893178a82 Signed-off-by: tierno --- osm_nbi/auth.py | 24 ++++++++++++++++-------- osm_nbi/authconn_keystone.py | 20 +++++++++++++++++--- osm_nbi/nbi.py | 4 ++++ osm_nbi/resources_to_operations.yml | 6 ++++++ 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/osm_nbi/auth.py b/osm_nbi/auth.py index e9a6b4e..6c44499 100644 --- a/osm_nbi/auth.py +++ b/osm_nbi/auth.py @@ -229,13 +229,14 @@ class Authenticator: def load_operation_to_allowed_roles(self): """ Fills the internal self.operation_to_allowed_roles based on database role content and self.operations + It works in a shadow copy and replace at the end to allow other threads working with the old copy :return: None """ permissions = {oper: [] for oper in self.operations} records = self.db.get_list("roles_operations") - ignore_fields = ["_id", "_admin", "name", "default", "admin"] + ignore_fields = ["_id", "_admin", "name", "default"] for record in records: record_permissions = {oper: record["permissions"].get("default", False) for oper in self.operations} operations_joined = [(oper, value) for oper, value in record["permissions"].items() @@ -253,8 +254,7 @@ class Authenticator: for allowed_op in allowed_operations: permissions[allowed_op].append(record["name"]) - for oper, role_list in permissions.items(): - self.operation_to_allowed_roles[oper] = role_list + self.operation_to_allowed_roles = permissions def authorize(self): token = None @@ -293,11 +293,12 @@ class Authenticator: raise AuthException("Needed a token or Authorization http header", http_code=HTTPStatus.UNAUTHORIZED) try: - self.backend.validate_token(token) - self.check_permissions(self.tokens_cache[token], cherrypy.request.path_info, + token_info = self.backend.validate_token(token) + # TODO add to token info remote host, port + + self.check_permissions(token_info, cherrypy.request.path_info, cherrypy.request.method) - # TODO: check if this can be avoided. Backend may provide enough information - return deepcopy(self.tokens_cache[token]) + return token_info except AuthException: self.del_token(token) raise @@ -412,7 +413,14 @@ class Authenticator: operation = self.resources_to_operations_mapping[key] roles_required = self.operation_to_allowed_roles[operation] - roles_allowed = self.backend.get_user_role_list(session["_id"]) + roles_allowed = [role["name"] for role in session["roles"]] + + # fills session["admin"] if some roles allows it + session["admin"] = False + for role in roles_allowed: + if role in self.operation_to_allowed_roles["admin"]: + session["admin"] = True + break if "anonymous" in roles_required: return diff --git a/osm_nbi/authconn_keystone.py b/osm_nbi/authconn_keystone.py index 23b07e3..9fff792 100644 --- a/osm_nbi/authconn_keystone.py +++ b/osm_nbi/authconn_keystone.py @@ -188,16 +188,30 @@ class AuthconnKeystone(Authconn): Check if the token is valid. :param token: token to validate - :return: dictionary with information associated with the token. If the - token is not valid, returns None. + :return: dictionary with information associated with the token: + "expires": + "_id": token_id, + "project_id": project_id, + "username": , + "roles": list with dict containing {name, id} + If the token is not valid an exception is raised. """ if not token: return try: token_info = self.keystone.tokens.validate(token=token) + ses = { + "_id": token_info["auth_token"], + "project_id": token_info["project"]["id"], + "project_name": token_info["project"]["name"], + "user_id": token_info["user"]["id"], + "username": token_info["user"]["name"], + "roles": token_info["roles"], + "expires": token_info.expires.timestamp() + } - return token_info + return ses 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), diff --git a/osm_nbi/nbi.py b/osm_nbi/nbi.py index 9d22df7..afc65c0 100644 --- a/osm_nbi/nbi.py +++ b/osm_nbi/nbi.py @@ -955,6 +955,10 @@ class Server(object): cherrypy.response.status = HTTPStatus.NO_CONTENT.value else: raise NbiException("Method {} not allowed".format(method), HTTPStatus.METHOD_NOT_ALLOWED) + + # if Role information changes, it is needed to reload the information of roles + if topic == "roles" and method != "GET": + self.authenticator.load_operation_to_allowed_roles() return self._format_out(outdata, session, _format) except Exception as e: if isinstance(e, (NbiException, EngineException, DbException, FsException, MsgException, AuthException, diff --git a/osm_nbi/resources_to_operations.yml b/osm_nbi/resources_to_operations.yml index fa5f1a3..ff659d4 100644 --- a/osm_nbi/resources_to_operations.yml +++ b/osm_nbi/resources_to_operations.yml @@ -358,3 +358,9 @@ resources_to_operations: "GET /nsilcm/v1/netslice_instances//nsi_lcm_op_occs": "slice_instances:id:opps:get" "GET /nsilcm/v1/netslice_instances//nsi_lcm_op_occs/": "slice_instances:id:opps:id:get" + +################################################################################ +############################ Admin #################################### +################################################################################ + + "GET ADMIN": "admin" -- 2.17.1