# Authorization and User Management

This section provides details on the authorization roles, user onboarding processes, and access
control mechanisms implemented in the INJECT Exercise Platform.

## Authorization

For authorization processes, the RBAC (Role-based access control) is supplemented with a modified
ACL (access control list).

Three authorization roles (also called groups, not to be mistaken for in-game roles) are present:

**ADMIN(s)**

- have access to all resources and the platform (exercises, definitions, users, etc...)
- role should be assigned only to people that really need it (maintainers, deployers of the
    platform), and the number of people with this role should be kept to a minimum
- can execute every action that a TRAINEE or INSTRUCTOR can

**INSTRUCTOR(s)**

- can access only the exercises and definitions they were assigned to (or which they created and
    were not removed from)
- can add or remove other instructors from exercises or definitions if they have access to these
    resources
- by creating an exercise or uploading an exercise definition, the instructor is automatically
    granted access to it – access to the exercise or definition can be removed by the other
    instructor assigned to it (or by ADMIN)
- of the given exercise can see all teams in the exercise
- can manipulate with the exercises (start, stop, create, or remove)
- can add/remove trainees to/from teams of an exercise
- inherit all trainee permissions
- can be added to the team (to simulate trainees), in such a case, they will only see the data of
    the given team, BUT they will still possess the INSTRUCTOR role and can manipulate the exercise
    (even if they are assigned only to a team)

**TRAINEE(s)**

- can see only the exercises to which they were assigned
- can access only the data of the team to which they are assigned (cannot see the data of other
    teams for the same exercise)
- can use tools in exercise (sending emails, using tools, answering questionnaires, ...)

### Additional notes

Users with the ADMIN role can be added to the access control lists to be shown in exercises (if the
admin acts as an instructor for some reason), but it is not necessary because admins have control
over every resource on the platform, whether they are assigned to it or not.

## User onboarding

### Bulk import using the web interface

Users can be added to the platform via a `.csv` file in the following format:

```
username,group,tags,first_name,last_name
```

**username** (mandatory)

- has to be a valid email address of the user (user will receive credentials via this email)

**group** (optional, implicitly "trainee")

- authorization role of the created user
- values: trainee, instructor, or admin (shorts "t", "i" or "a" can be used as well) case is ignored

Instructors cannot create users with higher privileges. Admin can be created only by admin users.

**tags** (optional)

- you can mark the newly created user by tags to make your work with assigning users to teams or
    exercises more convenient
- format of the field: `tag1|tag2|tag3` (values separated by "|")

**first_name** (optional)

- first name of the created user if you want to identify them later

**last_name** (optional)

- last name of the created user if you want to identify them later

As a separator for the column, you can use either `,` or `;`.

An example of such a file can be
[downloaded](https://gitlab.fi.muni.cz/inject/inject-docs/-/raw/main/docs/tech/example_csv.csv?ref_type=heads&inline=false).

The CSV file can be also used for the bulk adding of a new tags.
If the platform detects username (email) that already exists on the platform
it skips the creation and sending of the credentials and only adds new tags for such users.
Meaning that if you modify tags in a CSV that you already used for the account creations
you will achieve bulk adding of a new tags (no other fields will be changes).

This requires access to an SMTP server.

### Through the web interface

It is also possible to create individual user accounts through the API.
This is accessible through the frontend on the `Users` page if you have `INSTRUCTOR` or `ADMIN` role.
Once created, the server sends an invitation email with credentials to the given email address.

Also requires access to an SMTP server.

### Manually using CLI

**Important**: This is the only way to create users without an SMTP server.

Another way of adding users is manually via the console:

- List the running Docker containers to find the **NAME** of the backend container:

    ```
    docker ps
    ```

- Execute a shell session in the backend container. Replace `CONTAINERNAME` with the actual
    container **NAME** of the backend service:

    ```
    docker exec -it CONTAINERNAME python manage.py shell
    ```

- Create a user using the Django shell.
    Replace `email@test.com` and `long_and_secure_password` with your desired user credentials
    (by default a user with a _TRAINEE_ authorization group is created):

    ```python
    from user.models import User
    User().set_email_username("email@test.com").set_password("long_and_secure_password").save()
    ```

    - if you want to create an account with an _INSTRUCTOR_ authorization group:

        ```python
        User(group=User.AuthGroup.INSTRUCTOR).set_email_username("email@test.com").set_password("long_and_secure_password").save()
        ```

    - if you want to create an account with an _ADMIN_ authorization group:

        ```python
        User(group=User.AuthGroup.ADMIN).set_email_username("email@test.com").set_password("long_and_secure_password").save()
        ```

## Assigning users to exercise

There are multiple ways to assign users to an exercise.

### Manual assignment

You can assign users 'manually' by adding one or multiple users to a team or removing them,
utilizing the list of all present users on the platform.
This use case is ideal for situations when the distribution of users into teams is uncertain during preparation,
or for situations when you need to edit semi-automatically created assignments.

### Semi-automatic assignment

You can utilize one of the three options for semi-automatic assignment:

#### **Assign equally**

- The platform automatically assigns selected users to teams while trying to preserve balance
    between teams. Possible cases and their behavior:
    - _Number of users < number of teams_: First _n_ teams will be assigned one user each. The
        remaining teams (number_of_teams - number_of_users) will be left empty.
    - _Number of users = number of teams_: Every team will have exactly one assigned user.
    - _Number of users > number of teams_: Starting with the first user, placing him/her on the first team.
        Then, moving to the second user and placing him/her on the second team, and so on.
        Once a user is assigned to the last team, the algorithm loops back around and assigns the next user to the first team.
        This continues until all users are assigned to a team.
        Example situation – assigning 10 users (user1 to user10) to 3 teams would end up with this distribution:
        - team1: user1, user4, user7, user10
        - team2: user2, user5, user8
        - team3: user3, user6, user9
- If some users are already assigned to the exercise, they will not be reassigned based on the new assignment.
- WARNING: This feature _does not work_ with _role exercise_.

#### **Assign by tags**

- The platform automatically distributes users to teams based on the tags (with chosen prefix) of the selected users.
    Let's illustrate this functionality on the following example:
    - Imagine, we have users (trainees) and their tags in the brackets (these tags were assigned via a CSV file):
        - trainee1 (PowerPlantTTX-team1, HealthCareEX-team3)
        - trainee2 (PowerPlantTTX-team1, HealthCareEX-team2)
        - trainee3 (PowerPlantTTX-team3, HealthCareEX-team3)
        - trainee4 (PowerPlantTTX-team2, HealthCareEX-team1)
    - Now, we want to assign trainees 1-4 to our tabletop exercise about a power plant crisis.
        We knew beforehand how we wanted to distribute them to teams in this exercise and created the appropriate tags.
        We used `PowerPlantTTX` or `PowerPlantTTX-` as our prefix to distinguish between other tags.
    - The platform will now take the selected users and find a tag with a given prefix
        (which must be provided, in our case `PowerPlantTTX`) for each user.
        The users will be assigned by lexicographic ordering of suffix parts.
        In this case:
        - trainee1 and trainee2 will be assigned to the first team
        - trainee4 will be assigned to the second team
        - trainee3 will be assigned to the third team
    - If we used `HealthCareEX` as the wanted prefix for the user assignment, we would end up with:
        - trainee4 in the first team
        - trainee2 in the second team
        - trainee1 and trainee3 in the third
            team
- The following **rules have to be complied with** to make this assignment possible:
    - Prefix parts have to be unique for a given assignment (which can be achieved by making them long
        enough). If we had tags `EXERCISE_t1` and `EX_t1`, and we wanted to use the `EX_t1`, we would
        need to use the prefix `EX`, which would also match with `EXERCISE_t1` and could cause
        incorrect assignment (if we used the prefix `EX_`, we would dodge the match with other tags).
        To simplify, the prefix is checked as a match for the first characters of the tags.
    - Prefix match is case-sensitive.
    - Suffixes can have any values, which can be lexicographically ordered (correct examples where
        `Exercise` or `Exercise-` are the prefix):
        - Exercise-1, Exercise-2, Exercise-3 (those with 1 will be assigned to the first team, those
            with 2 to the second...)
        - Exercise-a, Exercise-b, Exercise-c (those with _a_ will be assigned to first team, those with
            _b_ to second...)
        - Exercise-t1, Exercise-t2, Exercise-t3 (those with _t1_ will be assigned to first team, those
            with _t2_ to second...)
    - If more tags match the prefix than the number of present teams, the operation will fail.
        Either the number of teams has to be increased, users with tags that exceed the number of team
        would need to be removed from selection, or the exceeding tags would need to be removed.
- WARNING: This feature does not work with _role exercise_.

#### **Copy existing assignment**

- The platform copies assignments of users and teams from one selected exercise to another.
- Requires that the exercises match in the number of teams; otherwise, the operation fails.
- Simply transfers assignment, meaning the members of the first team from a selected exercise will
    be members of the first team in another exercise.
