Permission system
=================

As the Modelverse runs as a service, and allows users to share models, permissions become required.
We briefly introduce the permission system used in the Modelverse.

As in the Modelverse everything is modelled explicitly, all permisions and meta-information about models is also modelled explicitly in the *core* model.
This model is not readable to any user, but can be queried and altered through the provided set of operations.

Model permissions
-----------------

First and foremost are the permissions on the models.
When creating a new model with *model_add*, the model is by default only readable and writable for the creating user.
All other users have neither read, nor write access unless explicitly granted by the creating user.
Similar to UNIX permissions, we use numeric values to indicate permissions, in the form XYZ.
X indicates the permissions of the owner itself.
Y indicates the permissions of the owning group.
Z indicates the permissions of all other users.

The values can range from 0 to 2.
0 indicates that the model is not readable, nor writable.
1 indicates that the model is readable, but not writable.
2 indicates that the model is both readable and writable.

As such, a model can have permission 210.
This indicates that the owner can read and write the model, the owning group can open the model read-only, and all other users have no access at all to the model.

Models can be queried for their permission information with the *model_list_full* operation::

    >>> model_list_full("models/petrinets/")
    [("my_pn", "user1", "group1", "200"),
     ("my_pn2", "user2", "group1", "210"),
     ("my_pn3", "user2", "group2", "210"),
     ("my_pn4", "user2", "group2", "211"),
     ...
    ]

In this case, user1 can modify my_pn, as he is the owner (permission 2: read/write), read my_pn2, as he is a member of group1 (permission 1: read), and has no access to my_pn3, as he is neither owner, nor in the group (permission 0: none).
All users can read my_pn4, independent of their group (permission 1: read).

Folder permissions
^^^^^^^^^^^^^^^^^^

Similar to models, folders can also have permissions, owners, and an owning group.
In this case, a readable folder is required to perform a *model_list* operation on that folder.
A writable folder is required to create new entries (either models or new folders) in that folder.
Note that this permission system leads to interesting situations, as in the UNIX permission model, where a folder cannot be read, but its contained files can (if their exact name is used).
When a file was already created, overwriting that file does not require any permissions of the folder at all.

Permission management
^^^^^^^^^^^^^^^^^^^^^

To share your models, you basically need to relax their permissions.
The default permissions are such that only the owning user can read/write the model, and no other users have access to it.
To alter the permissions, we have access to several operations.

1. *permission_modify* changes the permissions of a model to the specified string.
   For example, to make my_pn readable for everyone::
   
    >>> permission_modify("models/my_pn", "211")

2. *permission_owner* changes the owner of a model, thereby possibly revoking our own permission, but passing it on to someone else.
   For example, to make user2 the owner of our PetriNet model::

    >>> permission_owner("models/my_pn", "user2")

3. *permission_group* changes the owning group of a model, thereby possibly revoking permissions for several users.
   For example, to make group2 the owning group of our PetriNet model::

    >>> permission_group("models/my_pn", "group2")

Meta-level propagation
^^^^^^^^^^^^^^^^^^^^^^

Due to its meta-modelling nature, Modelverse permissions are more involved than just file-like permissions.
Indeed, a model depends on the language used to create it, such as *PetriNets*.
While in this case we have assumed *PetriNets* to be always readable, this does not necessarily need to be the case.

Creating a new instance of an unreadable metamodel, or language, is of course impossible, and the call to *model_add* will be prevented.
Worse, however, is when the permissions of the metamodel are altered when there already is a model in that language.
In this case, the model will suddenly become unreadable, as it depends on an unreadable metamodel.
Later on, we will see that this does not necessarily make it impossible for the model to be opened, as it only prevents it to be opened with that specific metamodel.
This does, however, require multi-conformance, which is an advanced concepts that is currently out of scope of this tutorial.

Group permissions
-----------------

Groups are merely sets of users.
Users can be added to the group with the *group_join* operation.
To make *user1* join *group1*::

    >>> group_join("group1", "user1")

Similarly, they can be removed from a group, thereby revoking all their permissions that were granted by the group.
To make *user1* leave *group1* again::

    >>> group_kick("group1", "user1")

As groups are key to model permissions, care should be taken who is made a member of a specific group.
Groups are themselves managed by group administrators, who govern the members of a specific group.
Group administrators can create new group administrators as well, who also automatically become a member of the group.
Similarly, group administrators can revoke the permissions of other group administrators::

    >>> group_owner_add("group1", "user1")
    >>> group_owner_delete("group1", "user1")

Note that, when removing group administrator status of a user, the user will still be a member of the group, though no longer an administrator.
As such, the result of the previous two commands will leave *user1* as a group member, even though that might not have been the case before.
A *group_kick* automatically removes group administrator permissions as well.

All users can create new groups, of which they automatically become the group administrator::
    
    >>> group_add("group2)

Similarly, groups can be removed by the group owner.
This not only removes the group, but also kicks all users and thereby revokes all permissions originally given by that group::

    >>> group_delete("group2")

User management
---------------

Users can manage the basics of their accounts.
This includes changing their username.
In this case, only the name is altered, and all permissions remain unaltered.
This is because only the name changes, and not the internal representation of that user.
For example, to change the username of *user1* to *user_1*::

    >>> user_name("user1", "user_1")

Similarly, users can alter their password::

    >>> user_password("user_1", "new_password")

In both cases, all currently active sessions remain active, but future logins need to use the new credentials.

Administrators
--------------

Finally, there is still the notion of an administrator in the Modelverse.
Administrators are basically like the root users on UNIX systems: independent of permissions, they are allowed to perform any operation they want.
As such, they are implicitly owner of each model, administrator of all groups, and have full permissions for user management.
The Modelverse is initialized with one administrator user, but administrators can create (promote) new administrators, or revoke their administrator permissions (demote)::

    >>> admin_promote("user1")
    >>> admin_demote("user1")
