Solution Permissions Management Service

This document describes the Solution Permissions Management Service (SPMS).

Introduction

The SPMS provides a way for a developer to manage permissions for users and devices in a Murano solution. SPMS presents itself to the developer through a Murano service. While actual users and devices are not managed by the SPMS, the solution developer can use the SPMS to organize users and devices as well as manage the permissions users have over devices.

The SPMS is not meant to manage users. It relies on some other service (e.g., Sphinx User Service, Auth0) to authenticate users. The solution developer would then use the SPMS to check authorization of users for their requested actions.

Glossary

User -- A user the system knows about. Each user in a solution must have a unique user ID.

Node -- A node in the user management tree hierarchy.

Node type -- Node types are optional and can be used for grouping nodes of the same type. This would typically be used for domain specific information (e.g., Distributor, OEM, Customer, etc.). All node types do is give the user the ability to filter on them. Node types can only be used on node immediately below the owning node.

Device -- A device in the system, identified by its device ID. Device IDs must be unique across solutions.

Device group -- A group of devices is defined by either a tag or a node. For device groups based on nodes, a device's location in the hierarchy determines the group. The group consists of all devices at and below the node the group is created on.

Tags -- Tags are a type of device group and can be applied to any device across the system and can be used to filter or control access to a set of devices.

Solution permissions -- Permissions the solution developer can create for solution-specific things.

Role -- A collection of permissions.

Rule -- The combination of a Role, User, and device group (node or tag).

Description

At the core of the SPMS is a tree made up of one or many nodes. At the top of the tree is a single root node that is created when the system is initialized. Underneath the root node are N tiers of additional nodes. There is no limit to the number of child nodes another node can have, but each node can have one, and only one, parent node (with the exception of the root node, which has no parent). These nodes are used to organize device and user hierarchy.

Devices can, and must, live at only one place in the hierarchy. A user can either live outside of the tree, not attached to any nodes (orphaned), or they can live on the tree (can only be on a single node a time).

SPMS Concepts

This section describes some of the concepts the SPMS uses.

Managing Devices and Users

The SPMS does not manage devices or users. What it does is allow solution developers to organize devices and users managed by an external service. Most typically this would be Murano or Auth0. It is up to the solution developer to keep the systems in sync.

SPMS does this by only tracking a user ID from an external service, and devices are tracked by a single device ID. Both device IDs and user IDs must be unique across a solution. If a device or user is added/removed from the external tracking system (e.g., Murano or Auth0), the solution developer needs to add/remove it from the SPMS.

Managing Permissions

Permissions in the SPMS are defined by the solution developer and consist of a verb and an object. SPMS does not predefine any permissions and allows the developer to use any verb and object that fits their application. The solution developer defines the actual verb and object (e.g., verb: view, subject: devices).

When a solution developer retrieves a user's permissions for a device, they will be presented with an array of permissions the user has for the device. This could include many permissions if the user has multiple rules over the device, or it could include no permissions if the user has no rules over the device. Based on the response, the solution developer decides if they should allow their user to perform the specified action.

Device Groups and Tags

These are ways to group devices together:

Hierarchy

The first type is what is defined by where the device is in the hierarchy. Devices do not need to be manually added to be part of the group. They are dynamically updated whenever a device is added to the system. Device groups are identified by a node on the SPMS tree, and the device groups will contain all devices that are at or under the identified node.

For example, say you had a tree that looks like the following:

A device can, and must, live at only one node in the tree at a time. If you use the group defined by node B, it would include all devices that are at B, D, and E. If a device is added or removed to one of the B, D, or E nodes, it would automatically be added or removed from the B group. If new nodes are created underneath B, D, and E, any devices added to the new nodes would also automatically be added to the device group defined by the B node.

Device group B would not have access to any devices under A, C, or F.

Ungrouped Devices

Since devices must live at a node in the group, best practice is to place new devices at the root node. As they are sold/built, users with appropriate permissions will be able to see all the new devices and move them to the appropriate place.

Deleting Nodes in the Hierarchy

The removeNode function will delete the selected node and each of it's child nodes. It will move all devices to the selected node's parent; orphan the users assigned to the node; delete tags, node_types, roles, and rules on the node.

For example removing node B will result in nodes D and E also being removed. All devices on D and E will be moved to B, and then all devices on B will be moved to it's parent A. All uses assocated with B, D, and E will be orphaned. All tags, node-types, roles, and rules with B, D, or E as a parent will be deleted from the solution. This will leave only nodes A and C. These would have all the devices, tags, node-types, roles, and rules assocated with them, but orphaned users could still exist in the solution.

Device Tags

Tags allow for non-hierarchical grouping of devices. They are created and can persist without being assigned to any devices and have a node as a parent. Devices are manually tagged, and they may exist anywhere in the hierarchy. Devices can have multiple tags. Tags are identified by a UUID. Tag names are unique for their parent node and have an optional description. Tag names are alphanumeric strings and can include periods(.), dashes(-), underscores(_), and spaces(' '). You can get a group of devices by querying for a tag they share.

For example, say you had the tree from the hierarchy:

A device can, and must, live at only one node in the tree at a time. Tags also must live only at one node in the tree. However, devices anywhere on the tree can be tagged. If you had a tag 1 at node B, it may not be assigned to any devices. If you had a device at node E, you could tag it with tag 1. You could also tag a device at node C with tag 1. If there were two devices at node D, you could tag one, none, or both with tag 1. In this way, any device can be tagged with any tag, regardless of where they fall in the hierarchy.

Rules

At the core or the SPMS, there are roles (collection of arbitrary permissions), users, and device groups (tagged or hierarchical). In order to tie these together, the SPMS uses a term called "rules." A rule is a three-way relationship between a role, user, and group (or tag). For example, if you had an admin role and a user you wanted to have the admin role over everything, you would create a rule that links the user to have admin rights, the root node, and the admin role.

Example Use Case

The following Lua code shows how the user would initialize the system with a simple tree and a few users and devices and grant some permissions to them.

Initialization

Initialize the service with the name of the service (only able to be called once).

rootNode = Spms.init()

Get Root Node if already initialized.

rootNode = Spms.getRootNode()

Example Response:

{
  status: 200, 
  result: {
    "description": "Root node of the solution",
    "id": "d200446f-d5e6-48d0-bf40-7dd2f4abd96g",
    "name": "root",
    "node_type_id": "48f7ce6e-ba57-4c0a-b88c-96e2b0abf4bb"
  }
}

Build Organizational Structure

Create a new nodetype.

input = {
        owning_node_id = rootNode.id, -- node that the type will be created at
        name = "Distributer", -- Only alphanumeric chars are allowed
        description = "A distributer of widgets" 
    }
distributerNodeTypeResponse = Spms.createNodeType(input)

Example Response:

{
  status: 200, 
  result: {
    "description": "A distributer of widgets",
    "id": "13d60038-1fff-4f77-889f-3a298516fc17",
    "name": "Distributer",
    "owning_node": "d200446f-d5e6-48d0-bf40-7dd2f4abd96g"
  }
}

Create a new node of the Distributer type called Midwest Distribution Company.


input = {
  name = "Midwest Distribution Company",
  description = "The distribution company for the midwest area",
  node_type_id = distributerNodeTypeResponse.id, -- optional
  parent_node_id = rootNode.id
}
midwestDistributerNode = Spms.createNode(input)

Create a new node of the Distributer type called Southern Distribution Company.

input = {
  name = "Southern Distribution Company",
  description = "The distribution company for the southern area",
  node_type_id = distributerNodeTypeResponse.id,
  parent_node_id=rootNode.id
}
southernDistributerNode = Spms.createNode(input)

Example Response:

{
  status: 200, 
  result: {
    "description": "The distribution company for the midwest area",
    "id": "2d36dd31-16fd-4149-a0d3-30bec5745bac",
    "name": "Midwest Distribution Company",
    "node_type_id": "422a4dd8-4103-4b30-abb9-6c591f16b649",
    "parent_node_id": "d200446f-d5e6-48d0-bf40-7dd2f4abd96g",
  }
}

Our tree now looks like this: Both Midwest and Southern are nodes of type Distributer. The root node is of the special reserved type ROOT. The root type is created when the solution is initialized and only the root node can, and must, be of this type.

Add Users

You will now attach user 1 to the root node and user 2 to the midwest node. Since the users do not yet exist in the system, the addUserToNode will automatically create them.

input = {
    user_id="1",
    node_id=rootNode.id
}

user1 = Spms.addUserToNode(input)

input = {
    user_id="2",
    node_id=midwestDistributerNode.id
}

user2 = Spms.addUserToNode(input)

Example Response:

{
  status: 200, 
  result: {
    "node_id": "2f757893-e56a-46e0-9576-c39511e4a3c3",
    "user_id": "2"
  }
}

Add Devices

Now you will place a device at each one of the nodes.

input = {
        device_ids = {"1"}, -- if multiple devices you could use {"1","2","3"}
        node_id = rootNode.id -- node to place devices on
    }
Spms.putDevicesOnNode(input)

input = {
        device_ids = {"2"},
        node_id = midwestDistributerNode.id
    }
Spms.putDevicesOnNode(input)

input = {
        device_ids = {"3"},
        node_id = southernDistributerNode.id
    }
Spms.putDevicesOnNode(input)

Example Response:

{
  status: 200, 
  result: {
    "devices": [
      {
        "device_id": "3",
        "owning_node": "954cc152-12bd-4154-a1eb-9671fbaba7c1"
      }
    ]
  }
}

Create Tag

Now create a tag tag_group.

input {
    tag_name = "tag_group",
    tag_description = "A tag to group devices with.",
    owning_node_id = southernDistributerNode.id
}
Spms.createTag(input)

Example Response:

{ status: 200,
  result: {
    id: '839f4b35-745f-4bd7-8cb5-455e51d4915c',
    name: 'tag_group',
    description: 'A tag to group devices with.',
    owning_node_id = '617f4b35-745f-4bd7-8cb5-455e51d3804d'
  }
}

Get Tag

Get a tag's info.

input {
    tag_id = '839f4b35-745f-4bd7-8cb5-455e51d4915c'
}
Spms.getTag(input)

Example Response:

{ status: 200,
  result: {
    id: '839f4b35-745f-4bd7-8cb5-455e51d4915c',
    name: 'tag_group',
    description: 'A tag to group devices with.',
    owning_node_id = '617f4b35-745f-4bd7-8cb5-455e51d3804d'
  }
}

Tag Some Devices

Tag a list of devices.

input {
    tag_id = '839f4b35-745f-4bd7-8cb5-455e51d4915c',
    device_ids = ['0000001', '0000002', '0000003']
}
Spms.tagDevices(input)

Example Response:

{ status: 200 }

Untag a Device

Remove tag from devices.

input {
    tag_id = '839f4b35-745f-4bd7-8cb5-455e51d4915c',
    device_ids = ['00000003', '0000004']
}
Spms.tagDevices(input)

Example Response:

{ status: 200 }

Get Devices with tag_group

Get a list of devices with tag_group.

input = {
    tag_id = '839f4b35-745f-4bd7-8cb5-455e51d4915c'
}
Spms.getDevicesWithTag(input)

Example Response:

{ status: 200,
  result: [
    {
      device_id: '0000001',
      owning_node: '617f4b35-745f-4bd7-8cb5-455e51d3804d'
    },
    {
      device_id: '0000002',
      owning_node: '617f4b35-745f-4bd7-8cb5-455e51d3804d'
    }
  ]
}

Add Role and Permissions

Add some permissions to the system.

input = {
        verb = "Full",
        object = "All",
        name = "All Access",
        description = "Provides full access to all things"
    }

fullAccessPermission = Spms.createSolutionPermission(input)

Example Response:

{
  status: 200, 
  result: {
    "description": "Provides full access to all things",
    "id": "41dbe0e9-33d6-4b5a-8882-c7d29ed1e3ce",
    "name": "All Access",
    "object": "All",
    "verb": "Full"
  }
}

Now create a role on the root node with with your newly created permissions widgets.

input = {
        name="Admin",
        owning_node_id = rootNode.id,
        permissions={fullAccessPermission.id}
    }

adminRole = Spms.createRole(input)

Example Response:

{
  status: 200, 
  result: {
    "id": "d670a1b8-ae88-4c59-9c9d-a5e821027c98",
    "name": "Admin",
    "owning_node_id": "d200446f-d5e6-48d0-bf40-7dd2f4abd95e",
  }
}

Assign User a Rule

Now create a rule giving user 1 admin access at the root node. Since no users exist, the new user will automatically be created, but it will not be attached to any node.

input = {
        device_group_id = rootNode.id,
        role_id = adminRole.id,
        user_id = "1"
    }
Spms.createRule(input)

Example Response:

{
  status: 200, 
  result: {
    "device_group_id": "d200446f-d5e6-48d0-bf40-7dd2f4abd95e",
    "id": "ad7247ac-cd80-47d6-a3f8-5180c1f0a6d5",
    "role_id": "67990b19-041b-4764-9a38-d4943d1d5fd2",
    "user_id": "9f563e2e-395d-4e4a-8603-0bfc57c35099"
  }
}

What is shown in the following diagram is what constitutes a rule. The rule links together a Role, User, and Group. At this point, user 1 has full access to all devices in the system.

Get Everything You Just Created

Now you can pass in a node_id and get everything connected to and below it on the tree.

input = {
        node_id = rootNode.id
    }
tree = Spms.tree(input)

Example Response:

{status: 200, result: {
  "applied_roles": [
    {
      "created": "2017-03-06T15:30:41.345Z",
      "id": "686bf7d7-a8e0-41a6-99e2-25ffdc91f004",
      "node_id": "27826249-30fa-41b3-8cd8-8f6b4202165c",
      "role_id": "0ddc55cb-2fb1-4265-a349-4ad455ca4024",
      "updated": "2017-03-06T15:30:41.345Z",
      "user_id": "6711c56b-1415-4f9c-a96b-377f363d2f88"
    }
  ],
  "children": [
    {
      "applied_roles": [],
      "children": [],
      "created": "2017-03-06T15:30:41.205Z",
      "description": "The distribution company for the midwest",
      "devices": [
        {
          "created": "2017-03-06T15:30:41.273Z",
          "device_id": "2",
          "id": "36649850-8433-4986-94b3-5b15b273671b",
          "node_id": "ad5614c1-55af-48f4-a8c9-f3f094a68abb",
          "updated": "2017-03-06T15:30:41.273Z"
        }
      ],
      "id": "ad5614c1-55af-48f4-a8c9-f3f094a68abb",
      "name": "Midwest Distribution Company",
      "node_type_id": "ec8038df-8aef-4119-ace8-c095f2a3d505",
      "parent_id": "27826249-30fa-41b3-8cd8-8f6b4202165c",
      "roles": [],
      "updated": "2017-03-06T15:30:41.205Z",
      "users": [
        {
          "created": "2017-03-06T15:30:41.241Z",
          "id": "dcd5389c-02d4-43fa-bcde-e3dd98620ef2",
          "node_id": "ad5614c1-55af-48f4-a8c9-f3f094a68abb",
          "updated": "2017-03-06T15:30:41.241Z",
          "user_id": "2"
        }
      ]
    },
    {
      "applied_roles": [],
      "children": [],
      "created": "2017-03-06T15:30:41.219Z",
      "description": "The distribution company for the south",
      "devices": [
        {
          "created": "2017-03-06T15:30:41.287Z",
          "device_id": "3",
          "id": "98146af8-ec28-4ead-aceb-4e22fb43b5f1",
          "node_id": "42228087-dc97-4888-add2-363274553014",
          "updated": "2017-03-06T15:30:41.287Z"
        }
      ],
      "id": "42228087-dc97-4888-add2-363274553014",
      "name": "Southern Distribution Company",
      "node_type_id": "ec8038df-8aef-4119-ace8-c095f2a3d505",
      "parent_id": "27826249-30fa-41b3-8cd8-8f6b4202165c",
      "roles": [],
      "updated": "2017-03-06T15:30:41.219Z",
      "users": []
    }
  ],
  "created": "2017-03-06T15:30:41.155Z",
  "description": "Root node of the solution",
  "devices": [
    {
      "created": "2017-03-06T15:30:41.257Z",
      "device_id": "1",
      "id": "fc0d73a5-b078-4a20-b790-6b3a49e2a207",
      "node_id": "27826249-30fa-41b3-8cd8-8f6b4202165c",
      "updated": "2017-03-06T15:30:41.257Z"
    }
  ],
  "id": "27826249-30fa-41b3-8cd8-8f6b4202165c",
  "name": "root",
  "node_type_id": "9e81ee8d-6d1c-41a6-9d95-e87de982deae",
  "roles": [
    {
      "created": "2017-03-06T15:30:41.331Z",
      "id": "0ddc55cb-2fb1-4265-a349-4ad455ca4024",
      "name": "Admin",
      "owning_node_id": "27826249-30fa-41b3-8cd8-8f6b4202165c",
      "updated": "2017-03-06T15:30:41.331Z"
    }
  ],
  "updated": "2017-03-06T15:30:41.163Z",
  "users": [
    {
      "created": "2017-03-06T15:30:41.229Z",
      "id": "6711c56b-1415-4f9c-a96b-377f363d2f88",
      "node_id": "27826249-30fa-41b3-8cd8-8f6b4202165c",
      "updated": "2017-03-06T15:30:41.229Z",
      "user_id": "1"
    }
  ]
}
}

Available Permission Types

There will initially be one permission type. In the future, when more structured types are discovered, the system has been designed to make permissions extensible.

Solution Specific

The solution-specific permissions allow a developer to set a verb and an object for arbitrary things in their solution.