class RoleTopicAuth(BaseTopic):
topic = "roles_operations"
- topic_msg = "roles"
+ topic_msg = None # "roles"
schema_new = roles_new_schema
schema_edit = roles_edit_schema
multiproject = False
:param role_definitions: role definition to test
:return: None if ok, raises ValidationError exception on error
"""
- ignore_fields = ["_id", "_admin", "name"]
- for role_def in role_definitions.keys():
+ if not role_definitions.get("permissions"):
+ return
+ ignore_fields = ["admin", "default"]
+ for role_def in role_definitions["permissions"].keys():
if role_def in ignore_fields:
continue
- if role_def == "root":
- if isinstance(role_definitions[role_def], bool):
- continue
- else:
- raise ValidationError("Operation authorization \".\" should be True/False.")
if role_def[-1] == ":":
- raise ValidationError("Operation cannot end with \".\"")
+ raise ValidationError("Operation cannot end with ':'")
role_def_matches = [op for op in operations if op.startswith(role_def)]
if len(role_def_matches) == 0:
- raise ValidationError("No matching operation found.")
-
- if not isinstance(role_definitions[role_def], bool):
- raise ValidationError("Operation authorization {} should be True/False.".format(role_def))
+ raise ValidationError("Invalid permission '{}'".format(role_def))
def _validate_input_new(self, input, force=False):
"""
:param indata: data to be inserted
:return: None or raises EngineException
"""
- role = indata.get("name")
- role_list = list(map(lambda x: x["name"], self.auth.get_role_list()))
-
- if role in role_list:
- raise EngineException("role '{}' exists".format(role), HTTPStatus.CONFLICT)
+ # check name not exists
+ if self.db.get_one(self.topic, {"name": indata.get("name")}, fail_on_empty=False, fail_on_more=False):
+ raise EngineException("role name '{}' exists".format(indata["name"]), HTTPStatus.CONFLICT)
def check_conflict_on_edit(self, session, final_content, edit_content, _id):
"""
:param _id: internal _id
:return: None or raises EngineException
"""
- roles = self.auth.get_role_list()
- system_admin_role = [role for role in roles
- if role["name"] == "system_admin"][0]
+ if "default" not in final_content["permissions"]:
+ final_content["permissions"]["default"] = False
+ if "admin" not in final_content["permissions"]:
+ final_content["permissions"]["admin"] = False
- if _id == system_admin_role["_id"]:
- raise EngineException("You cannot edit system_admin role", http_code=HTTPStatus.FORBIDDEN)
+ # check name not exists
+ if "name" in edit_content:
+ role_name = edit_content["name"]
+ if self.db.get_one(self.topic, {"name": role_name, "_id.ne": _id}, fail_on_empty=False, fail_on_more=False):
+ raise EngineException("role name '{}' exists".format(role_name), HTTPStatus.CONFLICT)
def check_conflict_on_del(self, session, _id, db_content):
"""
content["_admin"]["created"] = now
content["_admin"]["modified"] = now
- if ":" in content.keys():
- content["root"] = content[":"]
- del content[":"]
+ if "permissions" not in content:
+ content["permissions"] = {}
- if "root" not in content.keys():
- content["root"] = False
+ if "default" not in content["permissions"]:
+ content["permissions"]["default"] = False
+ if "admin" not in content["permissions"]:
+ content["permissions"]["admin"] = False
@staticmethod
def format_on_edit(final_content, edit_content):
"""
final_content["_admin"]["modified"] = time()
- ignore_fields = ["_id", "name", "_admin"]
- delete_keys = [key for key in final_content.keys() if key not in ignore_fields]
-
- for key in delete_keys:
- del final_content[key]
-
- # Saving the role definition
- for role_def, value in edit_content.items():
- final_content[role_def] = value
-
- if ":" in final_content.keys():
- final_content["root"] = final_content[":"]
- del final_content[":"]
-
- if "root" not in final_content.keys():
- final_content["root"] = False
-
- @staticmethod
- def format_on_show(content):
- """
- Modifies the content of the role information to separate the role
- metadata from the role definition. Eases the reading process of the
- role definition.
-
- :param definition: role definition to be processed
- """
- content["_id"] = str(content["_id"])
-
- def show(self, session, _id):
- """
- Get complete information on an topic
-
- :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
- :param _id: server internal id
- :return: dictionary, raise exception if not found.
- """
- filter_db = {"_id": _id}
-
- role = self.db.get_one(self.topic, filter_db)
- new_role = dict(role)
- self.format_on_show(new_role)
-
- return new_role
-
- def list(self, session, filter_q=None):
- """
- Get a list of the topic that matches a filter
-
- :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
- :param filter_q: filter of data to be applied
- :return: The list, it can be empty if no one match the filter.
- """
- if not filter_q:
- filter_q = {}
-
- if ":" in filter_q:
- filter_q["root"] = filter_q[":"]
-
- for key in filter_q.keys():
- if key == "name":
- continue
- filter_q[key] = filter_q[key] in ["True", "true"]
+ if "permissions" not in final_content:
+ final_content["permissions"] = {}
- roles = self.db.get_list(self.topic, filter_q)
- new_roles = []
+ if "default" not in final_content["permissions"]:
+ final_content["permissions"]["default"] = False
+ if "admin" not in final_content["permissions"]:
+ final_content["permissions"]["admin"] = False
- for role in roles:
- new_role = dict(role)
- self.format_on_show(new_role)
- new_roles.append(new_role)
+ # @staticmethod
+ # def format_on_show(content):
+ # """
+ # Modifies the content of the role information to separate the role
+ # metadata from the role definition. Eases the reading process of the
+ # role definition.
+ #
+ # :param definition: role definition to be processed
+ # """
+ # content["_id"] = str(content["_id"])
+ #
+ # def show(self, session, _id):
+ # """
+ # Get complete information on an topic
+ #
+ # :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ # :param _id: server internal id
+ # :return: dictionary, raise exception if not found.
+ # """
+ # filter_db = {"_id": _id}
+ #
+ # role = self.db.get_one(self.topic, filter_db)
+ # new_role = dict(role)
+ # self.format_on_show(new_role)
+ #
+ # return new_role
- return new_roles
+ # def list(self, session, filter_q=None):
+ # """
+ # Get a list of the topic that matches a filter
+ #
+ # :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ # :param filter_q: filter of data to be applied
+ # :return: The list, it can be empty if no one match the filter.
+ # """
+ # if not filter_q:
+ # filter_q = {}
+ #
+ # if ":" in filter_q:
+ # filter_q["root"] = filter_q[":"]
+ #
+ # for key in filter_q.keys():
+ # if key == "name":
+ # continue
+ # filter_q[key] = filter_q[key] in ["True", "true"]
+ #
+ # roles = self.db.get_list(self.topic, filter_q)
+ # new_roles = []
+ #
+ # for role in roles:
+ # new_role = dict(role)
+ # self.format_on_show(new_role)
+ # new_roles.append(new_role)
+ #
+ # return new_roles
def new(self, rollback, session, indata=None, kwargs=None, headers=None):
"""
:return: _id: identity of the inserted data.
"""
try:
- content = BaseTopic._remove_envelop(indata)
+ content = self._remove_envelop(indata)
# Override descriptor with query string kwargs
- BaseTopic._update_input_with_kwargs(content, kwargs)
+ self._update_input_with_kwargs(content, kwargs)
content = self._validate_input_new(content, session["force"])
self.check_conflict_on_new(session, content)
self.format_on_new(content, project_id=session["project_id"], make_public=session["public"])
role_name = content["name"]
- role = self.auth.create_role(role_name)
- content["_id"] = role["_id"]
+ role_id = self.auth.create_role(role_name)
+ content["_id"] = role_id
_id = self.db.create(self.topic, content)
rollback.append({"topic": self.topic, "_id": _id})
# self._send_msg("create", content)
:param content:
:return: _id: identity of the inserted data.
"""
- indata = self._remove_envelop(indata)
-
- # Override descriptor with query string kwargs
- if kwargs:
- self._update_input_with_kwargs(indata, kwargs)
- try:
- indata = self._validate_input_edit(indata, force=session["force"])
-
- if not content:
- content = self.show(session, _id)
- self.check_conflict_on_edit(session, content, indata, _id=_id)
- self.format_on_edit(content, indata)
- self.db.replace(self.topic, _id, content)
- return id
- except ValidationError as e:
- raise EngineException(e, HTTPStatus.UNPROCESSABLE_ENTITY)
+ _id = super().edit(session, _id, indata, kwargs, content)
+ if indata.get("name"):
+ self.auth.update_role(_id, name=indata.get("name"))
self.resources_to_operations_mapping = {}
self.operation_to_allowed_roles = {}
self.logger = logging.getLogger("nbi.authenticator")
+ self.operations = []
def start(self, config):
"""
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():
- if operation not in operations:
- operations.append(operation)
+ if operation not in self.operations:
+ self.operations.append(operation)
self.resources_to_operations_mapping[resource] = operation
records = self.db.get_list("roles_operations")
- # Loading permissions to MongoDB. If there are permissions already in MongoDB, do nothing.
- if len(records) == 0:
+ # Loading permissions to MongoDB if there is not any permission.
+ if not records:
with open(self.roles_to_operations_file, "r") as stream:
roles_to_operations_yaml = yaml.load(stream)
- roles = []
- for role_with_operations in roles_to_operations_yaml["roles_to_operations"]:
- # Verifying if role already exists. If it does, send warning to log and ignore it.
- if role_with_operations["role"] not in roles:
- roles.append(role_with_operations["role"])
+ role_names = []
+ for role_with_operations in roles_to_operations_yaml["roles"]:
+ # Verifying if role already exists. If it does, raise exception
+ if role_with_operations["name"] not in role_names:
+ role_names.append(role_with_operations["name"])
else:
- self.logger.warning("Duplicated role with name: {0}. Role definition is ignored."
- .format(role_with_operations["role"]))
- continue
-
- role_ops = {}
- root = None
+ raise AuthException("Duplicated role name '{}' at file '{}''"
+ .format(role_with_operations["name"], self.roles_to_operations_file))
- if not role_with_operations["operations"]:
+ if not role_with_operations["permissions"]:
continue
- for operation, is_allowed in role_with_operations["operations"].items():
+ for permission, is_allowed in role_with_operations["permissions"].items():
if not isinstance(is_allowed, bool):
- continue
+ raise AuthException("Invalid value for permission '{}' at role '{}'; at file '{}'"
+ .format(permission, role_with_operations["name"],
+ self.roles_to_operations_file))
- if operation == ":":
- root = is_allowed
- continue
+ # TODO chek permission is ok
+ if permission[-1] == ":":
+ raise AuthException("Invalid permission '{}' terminated in ':' for role '{}'; at file {}"
+ .format(permission, role_with_operations["name"],
+ self.roles_to_operations_file))
- if len(operation) != 1 and operation[-1] == ":":
- self.logger.warning("Invalid operation {0} terminated in ':'. "
- "Operation will be discarded"
- .format(operation))
- continue
-
- 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))
-
- if not root:
- root = False
- self.logger.info("Root for role {0} not defined. Default value 'False' applied."
- .format(role_with_operations["role"]))
+ if "default" not in role_with_operations["permissions"]:
+ role_with_operations["permissions"]["default"] = False
+ if "admin" not in role_with_operations["permissions"]:
+ role_with_operations["permissions"]["admin"] = False
now = time()
- operation_to_roles_item = {
- "_admin": {
- "created": now,
- "modified": now,
- },
- "name": role_with_operations["role"],
- "root": root
+ role_with_operations["_admin"] = {
+ "created": now,
+ "modified": now,
}
- for operation, value in role_ops.items():
- operation_to_roles_item[operation] = value
-
if self.config["authentication"]["backend"] != "internal" and \
- role_with_operations["role"] != "anonymous":
- 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]
+ role_with_operations["name"] != "anonymous":
+
+ backend_roles = self.backend.get_role_list(filter_q={"name": role_with_operations["name"]})
+
+ if backend_roles:
+ backend_id = backend_roles[0]["_id"]
else:
- keystone_id = self.backend.create_role(role_with_operations["role"])
- operation_to_roles_item["_id"] = keystone_id["_id"]
+ backend_id = self.backend.create_role(role_with_operations["name"])
+ role_with_operations["_id"] = backend_id
- self.db.create("roles_operations", operation_to_roles_item)
+ self.db.create("roles_operations", role_with_operations)
- permissions = {oper: [] for oper in operations}
+ if self.config["authentication"]["backend"] != "internal":
+ self.backend.assign_role_to_user("admin", "admin", "system_admin")
+
+ self.load_operation_to_allowed_roles()
+
+ def load_operation_to_allowed_roles(self):
+ """
+ Fills the internal self.operation_to_allowed_roles based on database role content and self.operations
+ :return: None
+ """
+
+ permissions = {oper: [] for oper in self.operations}
records = self.db.get_list("roles_operations")
- ignore_fields = ["_id", "_admin", "name", "root"]
+ ignore_fields = ["_id", "_admin", "name", "default", "admin"]
for record in records:
- record_permissions = {oper: record["root"] for oper in operations}
- operations_joined = [(oper, value) for oper, value in record.items() if oper not in ignore_fields]
+ record_permissions = {oper: record["permissions"].get("default", False) for oper in self.operations}
+ operations_joined = [(oper, value) for oper, value in record["permissions"].items()
+ if oper not in ignore_fields]
operations_joined.sort(key=lambda x: x[0].count(":"))
for oper in operations_joined:
for oper, role_list in permissions.items():
self.operation_to_allowed_roles[oper] = role_list
- if self.config["authentication"]["backend"] != "internal":
- self.backend.assign_role_to_user("admin", "admin", "system_admin")
-
def authorize(self):
token = None
user_passwd64 = None
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 = self.backend.get_user_role_list(session["_id"])
if "anonymous" in roles_required:
return
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:
"""
Abstract base class for all the Auth backend connector plugins.
"""
raise AuthconnNotImplementedException("Should have implemented this")
- def get_role_list(self):
+ def get_role_list(self, filter_q=None):
"""
Get all the roles.
+ :param filter_q: dictionary to filter role list by _id and/or name.
:return: list of roles
"""
raise AuthconnNotImplementedException("Should have implemented this")
+ def update_role(self, role, new_name):
+ """
+ Change the name of a role
+ :param role: role name or id to be changed
+ :param new_name: new name
+ :return: None
+ """
+ raise AuthconnNotImplementedException("Should have implemented this")
+
def create_project(self, project):
"""
Create a project.
__author__ = "Eduardo Sousa <esousa@whitestack.com>"
__date__ = "$27-jul-2018 23:59:59$"
-from authconn import Authconn, AuthException, AuthconnOperationException, AuthconnNotFoundException
+from authconn import Authconn, AuthException, AuthconnOperationException, AuthconnNotFoundException, \
+ AuthconnConflictException
import logging
import requests
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):
+ def get_role_list(self, filter_q=None):
"""
Get role list.
+ :param filter_q: dictionary to filter role list by _id and/or name.
:return: returns the list of roles.
"""
try:
- roles_list = self.keystone.roles.list()
+ filter_name = None
+ if filter_q:
+ filter_name = filter_q.get("name")
+ roles_list = self.keystone.roles.list(name=filter_name)
roles = [{
"name": role.name,
"_id": role.id
} for role in roles_list if role.name != "service"]
+ if filter_q and filter_q.get("_id"):
+ roles = [role for role in roles if filter_q["_id"] == role["_id"]]
+
return roles
except ClientException as e:
self.logger.exception("Error during user role listing using keystone: {}".format(e))
"""
try:
result = self.keystone.roles.create(role)
- return {"name": result.name, "_id": result.id}
+ return result.id
except Conflict as ex:
- self.logger.info("Duplicate entry: %s", str(ex))
+ raise AuthconnConflictException(str(ex))
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))
:raises AuthconnOperationException: if role deletion failed.
"""
try:
- roles = self.keystone.roles.list()
- role_obj = [role for role in roles if role.id == role_id][0]
- result, detail = self.keystone.roles.delete(role_obj)
+ result, detail = self.keystone.roles.delete(role_id)
if result.status_code != 204:
raise ClientException("error {} {}".format(result.status_code, detail))
self.logger.exception("Error during role deletion using keystone: {}".format(e))
raise AuthconnOperationException("Error during role deletion using Keystone: {}".format(e))
+ def update_role(self, role, new_name):
+ """
+ Change the name of a role
+ :param role: role name or id to be changed
+ :param new_name: new name
+ :return: None
+ """
+ try:
+ if is_valid_uuid(role):
+ role_id = role
+ else:
+ role_obj_list = self.keystone.roles.list(name=role)
+ if not role_obj_list:
+ raise AuthconnNotFoundException("Role '{}' not found".format(role))
+ role_id = role_obj_list[0].id
+ self.keystone.roles.update(role_id, name=new_name)
+ except ClientException as e:
+ # self.logger.exception("Error during role update using keystone: {}".format(e))
+ raise AuthconnOperationException("Error during role updating using Keystone: {}".format(e))
+
def get_project_list(self, filter_q=None):
"""
Get all the projects.
:param _id: If not None, ignore this entry that are going to change
:return: None or raises EngineException
"""
- _filter = self._get_project_filter(session)
+ if not self.multiproject:
+ _filter = {}
+ else:
+ _filter = self._get_project_filter(session)
_filter["name"] = name
if _id:
_filter["_id.neq"] = _id
:param _id: server internal id
:return: dictionary, raise exception if not found.
"""
- filter_db = self._get_project_filter(session)
+ if not self.multiproject:
+ filter_db = {}
+ else:
+ filter_db = self._get_project_filter(session)
# To allow project&user addressing by name AS WELL AS _id
filter_db[BaseTopic.id_field(self.topic, _id)] = _id
return self.db.get_one(self.topic, filter_db)
"""
if not filter_q:
filter_q = {}
-
- filter_q.update(self._get_project_filter(session))
+ if self.multiproject:
+ filter_q.update(self._get_project_filter(session))
# TODO transform data for SOL005 URL requests. Transform filtering
# TODO implement "field-type" query string SOL005
# TODO add admin to filter, validate rights
if not filter_q:
filter_q = {}
- filter_q.update(self._get_project_filter(session))
+ if self.multiproject:
+ filter_q.update(self._get_project_filter(session))
return self.db.del_list(self.topic, filter_q)
def delete_extra(self, session, _id, db_content):
if dry_run:
return None
- filter_q.update(self._get_project_filter(session))
+ if self.multiproject:
+ filter_q.update(self._get_project_filter(session))
if self.multiproject and session["project_id"]:
# remove reference from project_read. If not last delete
self.db.set_one(self.topic, filter_q, update_dict=None,
map_target_version_to_int = {
"1.0": 1000,
- "1.1": 1001
+ "1.1": 1001,
+ "1.2": 1002,
# Add new versions here
}
def upgrade_db(self, current_version, target_version):
if target_version not in self.map_target_version_to_int.keys():
- raise EngineException("Wrong database version '{}'. Expected '{}'"
- ". It cannot be up/down-grade".format(current_version, target_version),
+ raise EngineException("Cannot upgrade to version '{}' with this version of code".format(target_version),
http_code=HTTPStatus.INTERNAL_SERVER_ERROR)
if current_version == target_version:
self.db.set_secret_key(serial)
current_version = "1.0"
- if current_version == "1.0" and target_version_int >= self.map_target_version_to_int["1.1"]:
+ if current_version in ("1.0", "1.1") and target_version_int >= self.map_target_version_to_int["1.2"]:
self.db.del_list("roles_operations")
version_data = {
"_id": "version",
- "version_int": 1001,
- "version": "1.1",
- "date": "2019-05-24",
+ "version_int": 1002,
+ "version": "1.2",
+ "date": "2019-06-11",
"description": "set new format for roles_operations"
}
self.db.set_one("admin", {"_id": "version"}, version_data)
- current_version = "1.1"
+ current_version = "1.2"
# TODO add future migrations here
def init_db(self, target_version='1.0'):
__version__ = "0.1.3"
version_date = "Jan 2019"
-database_version = '1.1'
+database_version = '1.2'
auth_database_version = '1.0'
nbi_server = None # instance of Server class
subscription_thread = None # instance of SubscriptionThread class
##
---
-roles_to_operations:
+roles:
##
-# This file defines the mapping between user roles and operation permission.
+# This file defines the mapping between user roles and operation permissions.
# It uses the following pattern:
#
-# - role: <ROLE_NAME>
-# operations:
+# - name: <ROLE_NAME>
+# permissions:
# "<OPERATION>": true | false
#
# <ROLE_NAME> defines the name of the role. This name will be matched with an
-# existing role in the RBAC system.
+# existing role in the RBAC system (e.g. keystone).
#
# NOTE: The role will only be used if there is an existing match. If there
# isn't a role in the system that can be matched, the operation permissions
# won't yield any result.
#
-# operations: is a list of operation permissions for the role. An operation
+# permissions: is a dictionary of operation permissions for the role. An operation
# permission is defined using the following pattern:
#
# "<OPERATION>": true | false
#
# The operations are defined using an hierarchical tree. For this purpose, an
# <OPERATION> tag can represents the path for the following:
-# - Root
-# - Node
-# - Leaf
+# - default: what action to be taken by default, allow or deny
+# - admin: allow or deny usin querey string ADMIN to act on behalf of other project
+# - colon separated hierarchical tree
#
-# The root <OPERATION> tag is defined using "." and the default value is false.
+# The default and admin <OPERATION> tag is considered false if missing.
# When you use this tag, all the operation permissions will be set to the value
# assigned.
# NOTE 1: The default value is false. So if a value isn't specified, it will
# default to false.
-# NOTE 2: The root <OPERATION> tag can be overridden by using more specific tags
+# NOTE 2: The default <OPERATION> tag can be overridden by using more specific tags
# with a different value.
#
# The node <OPERATION> tag is defined by using an internal node of the tree, i.e.
-# "nsds", "users.id". A node <OPERATION> tag will affect all the nodes and leafs
-# beneath it. It can be used to override a root <OPERATION> tag.
+# "nsds", "users:id". A node <OPERATION> tag will affect all the nodes and leafs
+# beneath it. It can be used to override a default <OPERATION> tag.
# NOTE 1: It can be overridden by using a more specific tag, such as a node which
# is beneath it or a leaf.
#
-# The leaf <OPERATION> tag is defined by using a leaf of the tree, i.e. "users.post",
-# "ns_instances.get", "vim_accounts.id.get". A leaf <OPERATION> tag will override all
+# The leaf <OPERATION> tag is defined by using a leaf of the tree, i.e. "users:post",
+# "ns_instances:get", "vim_accounts:id:get". A leaf <OPERATION> tag will override all
# the values defined by the parent nodes, since it is the more specific tag that can
# exist.
#
# - In order to find which tags are in use, check the resources_to_operations.yml.
# - In order to find which roles are in use, check the RBAC system.
# - Non existing tags will be ignored.
-# - Tags finishing in a dot (excluding the root <OPERATION> tag) will be ignored.
+# - Tags finishing in a colon will be ignored.
# - The anonymous role allows to bypass the role definition for paths that
# shouldn't be verified.
##
- - role: "system_admin"
- operations:
- ":": true
+ - name: "system_admin"
+ permissions:
+ default: true
+ admin: true
- - role: "account_manager"
- operations:
- ":": false
- "tokens": true
- "users": true
- "projects": true
- "roles": true
+ - name: "account_manager"
+ permissions:
+ default: false
+ admin: false
+ tokens: true
+ users: true
+ projects: true
+ roles: true
- - role: "project_admin"
- operations:
- ":": true
- # Users
- "users:post": false
- "users:id:post": false
- "users:id:delete": false
- # Projects
- "projects": false
- # Roles
- "roles": false
+ - name: "project_admin"
+ permissions:
+ default: true
+ # Users
+ users:post: false
+ users:id:post: false
+ users:id:delete: false
+ users:id:put: false
+ # Projects
+ projects: false
+ # Roles
+ roles: false
- - role: "project_user"
- operations:
- ":": true
- # NS Instances
- "ns_instances": false
- "ns_instances:get": true
- # VNF Instances
- "vnf_instances": false
- # Users
- "users": false
- "users:id:get": true
- "users:id:put": true
- "users:id:patch": true
- # Projects
- "projects": false
- # VIMs
- "vims": false
- "vims:get": true
- "vims:id:get": true
- # VIM Accounts
- "vim_accounts": false
- "vim_accounts:get": true
- "vim_accounts:id:get": true
- # SDN Controllers
- "sdn_controllers": false
- "sdn_controllers:get": true
- "sdn_controllers:id:get": true
- # WIMs
- "wims": false
- "wims:get": true
- "wims:id:get": true
- # WIM Accounts
- "wim_accounts": false
- "wim_accounts:get": true
- "wim_accounts:id:get": true
+ - name: "project_user"
+ permissions:
+ default: true
+ # NS Instances
+ ns_instances: false
+ ns_instances:get: true
+ # VNF Instances
+ vnf_instances: false
+ # Users
+ users: false
+ users:id:get: true
+ users:id:put: true
+ users:id:patch: true
+ # Projects
+ projects: false
+ # VIMs
+ vims: false
+ vims:get: true
+ vims:id:get: true
+ # VIM Accounts
+ vim_accounts: false
+ vim_accounts:get: true
+ vim_accounts:id:get: true
+ # SDN Controllers
+ sdn_controllers: false
+ sdn_controllers:get: true
+ sdn_controllers:id:get: true
+ # WIMs
+ wims: false
+ wims:get: true
+ wims:id:get: true
+ # WIM Accounts
+ wim_accounts: false
+ wim_accounts:get: true
+ wim_accounts:id:get: true
- - role: "anonymous"
- operations:
+ - name: "anonymous"
+ permissions:
"type": "object",
"properties": {
"name": shortname_schema,
- "root": bool_schema,
+ "permissions": {
+ "type": "object",
+ "patternProperties": {
+ ".": bool_schema,
+ },
+ # "minProperties": 1,
+ }
},
- "required": ["name", "root"],
- "additionalProperties": True
+ "required": ["name"],
+ "additionalProperties": False
}
roles_edit_schema = {
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Roles edit schema for administrators",
"type": "object",
"properties": {
- "root": bool_schema,
+ "name": shortname_schema,
+ "permissions": {
+ "type": "object",
+ "patternProperties": {
+ ".": {
+ "oneOf": [bool_schema, null_schema]
+ }
+ },
+ # "minProperties": 1,
+ }
},
- "required": ["root"],
- "additionalProperties": True,
+ "additionalProperties": False,
"minProperties": 1
}