Fix bug 731
[osm/NBI.git] / osm_nbi / auth.py
index 9171c94..d916189 100644 (file)
@@ -55,6 +55,7 @@ class Authenticator:
     Authorization. Initially it should support Openstack Keystone as a
     backend through a plugin model where more backends can be added and a
     RBAC model to manage permissions on operations.
+    This class must be threading safe
     """
 
     periodin_db_pruning = 60 * 30  # for the internal backend only. every 30 minutes expired tokens will be pruned
@@ -155,16 +156,15 @@ class Authenticator:
         # Note: it is faster to rewrite the value than to check if it is already there or not
         if self.config["authentication"]["backend"] == "internal":
             return
-        
+
         operations = []
         with open(self.resources_to_operations_file, "r") as stream:
             resources_to_operations_yaml = yaml.load(stream)
 
         for resource, operation in resources_to_operations_yaml["resources_to_operations"].items():
-            operation_key = operation.replace(".", ":")
-            if operation_key not in operations:
-                operations.append(operation_key)
-            self.resources_to_operations_mapping[resource] = operation_key
+            if operation not in operations:
+                operations.append(operation)
+            self.resources_to_operations_mapping[resource] = operation
 
         records = self.db.get_list("roles_operations")
 
@@ -193,19 +193,18 @@ class Authenticator:
                     if not isinstance(is_allowed, bool):
                         continue
 
-                    if operation == ".":
+                    if operation == ":":
                         root = is_allowed
                         continue
 
-                    if len(operation) != 1 and operation[-1] == ".":
-                        self.logger.warning("Invalid operation {0} terminated in '.'. "
+                    if len(operation) != 1 and operation[-1] == ":":
+                        self.logger.warning("Invalid operation {0} terminated in ':'. "
                                             "Operation will be discarded"
                                             .format(operation))
                         continue
 
-                    operation_key = operation.replace(".", ":")
-                    if operation_key not in role_ops.keys():
-                        role_ops[operation_key] = is_allowed
+                    if operation not in role_ops.keys():
+                        role_ops[operation] = is_allowed
                     else:
                         self.logger.info("In role {0}, the operation {1} with the value {2} was discarded due to "
                                          "repetition.".format(role_with_operations["role"], operation, is_allowed))
@@ -230,7 +229,12 @@ class Authenticator:
 
                 if self.config["authentication"]["backend"] != "internal" and \
                         role_with_operations["role"] != "anonymous":
-                    keystone_id = self.backend.create_role(role_with_operations["role"])
+                    keystone_id = [role for role in self.backend.get_role_list() 
+                                   if role["name"] == role_with_operations["role"]]
+                    if keystone_id:
+                        keystone_id = keystone_id[0]
+                    else:
+                        keystone_id = self.backend.create_role(role_with_operations["role"])
                     operation_to_roles_item["_id"] = keystone_id["_id"]
 
                 self.db.create("roles_operations", operation_to_roles_item)
@@ -480,7 +484,8 @@ class Authenticator:
             now = time()
             session = self.tokens_cache.get(token_id)
             if session and session["expires"] < now:
-                del self.tokens_cache[token_id]
+                # delete token. MUST be done with care, as another thread maybe already delete it. Do not use del
+                self.tokens_cache.pop(token_id, None)
                 session = None
             if session:
                 return session
@@ -501,7 +506,7 @@ class Authenticator:
             if self.config["global"].get("test.user_not_authorized"):
                 return {"id": "fake-token-id-for-test",
                         "project_id": self.config["global"].get("test.project_not_authorized", "admin"),
-                        "username": self.config["global"]["test.user_not_authorized"]}
+                        "username": self.config["global"]["test.user_not_authorized"], "admin": True}
             else:
                 raise