From 739d31395c747d07cf1640c07d0796fccee56955 Mon Sep 17 00:00:00 2001 From: Richard Glosner <xglosner@fi.muni.cz> Date: Mon, 10 Feb 2025 10:56:31 +0100 Subject: [PATCH] * run formatter * grammar fix * format and make text clearer * update FE-BE initial communication with login --- docs/tech/architecture/overview.md | 186 ++++++++--------------------- docs/tech/security.md | 84 +++++++------ 2 files changed, 88 insertions(+), 182 deletions(-) diff --git a/docs/tech/architecture/overview.md b/docs/tech/architecture/overview.md index 4c978d2..9ca4452 100644 --- a/docs/tech/architecture/overview.md +++ b/docs/tech/architecture/overview.md @@ -7,7 +7,7 @@ enhancing modularity and scalability within the system. The architecture of the IXP can be visualized as follows: -``` mermaid +```mermaid flowchart LR A(INJECT) --> B(BACKEND) A --> C(FRONTEND) @@ -25,31 +25,32 @@ flowchart LR This diagram illustrates the high-level architecture of the IXP. It is composed out of these parts: -* Frontend: The frontend component serves as the user interface of the IXP, +- Frontend: The frontend component serves as the user interface of the IXP, allowing users to interact with the system. It includes four main parts: - * Trainee View: This view is designed for trainees participating in tabletop exercises. - It provides functionalities tailored to their role, such as accessing exercise scenarios, - submitting responses, and general interaction with the exercise. - * Instructor View: This view is tailored for instructors or facilitators overseeing tabletop exercises. - It offers capabilities for monitoring trainee progress, and providing guidance during the exercise. - * Analytics: The analytics view provides insights and analytics related to the tabletop exercises conducted on the platform. - It includes metrics such as participation rates, completion times, and performance trends. - * Exercise Panel: The exercise panel enables users to view and manage exercises available on the platform, - including creating new exercises, editing existing ones, and organizing exercise-related resources. - -* Backend: The backend component serves as the backbone of the INJECT platform, handling data management, + + - Trainee View: This view is designed for trainees participating in tabletop exercises. + It provides functionalities tailored to their role, such as accessing exercise scenarios, + submitting responses, and general interaction with the exercise. + - Instructor View: This view is tailored for instructors or facilitators overseeing tabletop exercises. + It offers capabilities for monitoring trainee progress, and providing guidance during the exercise. + - Analytics: The analytics view provides insights and analytics related to the tabletop exercises conducted on the platform. + It includes metrics such as participation rates, completion times, and performance trends. + - Exercise Panel: The exercise panel enables users to view and manage exercises available on the platform, + including creating new exercises, editing existing ones, and organizing exercise-related resources. + +- Backend: The backend component serves as the backbone of the INJECT platform, handling data management, authentication, and communication with the frontend. It includes several parts: - * Exercises: This module manages the creation, modification, - and storage of tabletop exercises on the platform. - * Exercise Definitions: The exercise definitions module stores templates and definitions for different types of exercises. - These definitions include details such as injects, emails and tools. - It also checks and ensures that definitions are correctly configured and set up. - For a more in-depth explanation of definitions, please refer to [definitions documentation](definitions/README.md). - * Running Exercise: This module manages the execution and runtime aspects of tabletop exercises, - including tracking the progress of ongoing exercises and managing the flow of injects. - * Authentication: Handles user authentication and authorization, ensuring secure access to the platform's functionalities. + - Exercises: This module manages the creation, modification, + and storage of tabletop exercises on the platform. + - Exercise Definitions: The exercise definitions module stores templates and definitions for different types of exercises. + These definitions include details such as injects, emails and tools. + It also checks and ensures that definitions are correctly configured and set up. + For a more in-depth explanation of definitions, please refer to [definitions documentation](definitions/README.md). + - Running Exercise: This module manages the execution and runtime aspects of tabletop exercises, + including tracking the progress of ongoing exercises and managing the flow of injects. + - Authentication: Handles user authentication and authorization, ensuring secure access to the platform's functionalities. ## Used Technology @@ -58,165 +59,74 @@ It is composed out of these parts: The backend component of the IXP is built using Python and Django, a high-level web development framework. Key components of the backend architecture include: -* Python Backend: The backend of the IXP is implemented using Python. -* Django Framework: Django, the most popular web development framework for Python, +- Python Backend: The backend of the IXP is implemented using Python. +- Django Framework: Django, the most popular web development framework for Python, is used to build the backend application. Django provides robust features for database management, user authentication, and more. -* GraphQL API: The backend exposes a GraphQL API for communication with the frontend. +- GraphQL API: The backend exposes a GraphQL API for communication with the frontend. GraphQL allows efficient data fetching and enables the client to request only the data it needs. -* Django REST Framework: For file transfers and other functionalities not supported by GraphQL, +- Django REST Framework: For file transfers and other functionalities not supported by GraphQL, a REST API is implemented using Django REST Framework. ### Frontend Technology The frontend component of the IXP utilizes modern web technologies including: -* React Frontend: The frontend application of the IXP is developed using React, library for building user interfaces. -* TypeScript: TypeScript is used instead of JavaScript to ensure type safety and improve code quality. -* React Hooks: React hooks play a crucial role in modern React programming, +- React Frontend: The frontend application of the IXP is developed using React, library for building user interfaces. +- TypeScript: TypeScript is used instead of JavaScript to ensure type safety and improve code quality. +- React Hooks: React hooks play a crucial role in modern React programming, providing essential features such as state management and performing side effects. -* Libraries and Tools: Various libraries and tools, including Yarn, Vite, Apollo Client, and Generouted, +- Libraries and Tools: Various libraries and tools, including Yarn, Vite, Apollo Client, and Generouted, are utilized for package management, building, data management, and routing within the frontend application. ## Security overview ### Authentication -Authentication on the INJECT platform is fundamental to ensuring secure access to its features and resources. -Leveraging Django's built-in session system, the platform utilizes cookies as a means to authenticate client requests. +Authentication on the INJECT Exercise Platform is fundamental to ensuring secure access to its features and resources. +Leveraging Django's (modified) built-in session system, the platform uses HTTP header as a means to authenticate client requests. ### Authentication Process Overview The authentication process involves the following steps: + ```mermaid sequenceDiagram Client->>Server: Get backend version - Server->>Client: Responds with backend version and SET_COOKIE + Server->>Client: Respond with backend + Client->>Client: Check version compatibility ``` -1. Client → Server: Get the backend version from the REST API. - (No cookies are set yet.) -2. Client ↠Server: Responds with backend version and `SET_COOKIE` - with `CSRF cookie` needed for POST actions. +1. Client → Server: Gets the backend version from the REST API. -At this stage, the client has obtained the _CSRF cookie_. -Since the client is not yet authenticated, any requests made will include `AnonymousUser`as the requester's identity, -indicating an unauthenticated state. -All subsequent POST requests from the client must include both the _csrf cookie_ and the _X-csrftoken header_. +2. Client ↠Server: Responds with backend version. -The client can now make requests to endpoints that do not require authentication. -For every request, the server checks for a match between the _csrf cookie_ and the _X-csrftoken header_ -to prevent cross-site request forgery. -POST requests that do not contain matching _csrf cookie_ and _X-csrftoken header_ will fail -with response `403 Forbidden`. +3. Client: Checks the compatibility between client and backend versions and display an error in case of incompatible versions. The next crucial step in the process is **login**: -``` mermaid +```mermaid sequenceDiagram - Client->>Server: Sends login request on GraphQL login endpoint - Server->>Client: Server generates new session + Client->>Server: Send login request (username with password) on REST API + Server->>Client: Send session identifier ``` -3. Client → Server: Sends a login request on the GraphQL endpoint (login mutation) containing the username and password. +3. Client → Server: Sends a login request on the REST endpoint containing the username and password. 4. Client ↠Server: If the provided credentials are valid, the server generates a _new session_, -setting the _user_ attribute of the session to the corresponding user that has successfully authenticated. -The server then responds with a `SET_COOKIE` header, containing both the new `sessionid` cookie and a new `csrf` cookie. + setting the _user_ attribute of the session to the corresponding user that has successfully authenticated. + The server then responds with a _sessionid_, containing identifier of users session. -The client is expected to drop the old _csrf cookie_ and replace them with the new one. -Also, every request from now on should contain _X-csrftoken_ value of the _**new** csrf cookie_. +From now on, the client requests are authenticated by the HTTP header that contains the _sessionid_ (session identifier). For further information, refer to the official documentation on: -* [Django Sessions](https://docs.djangoproject.com/en/2.0/topics/http/sessions/) -* [CSRF Protection](https://docs.djangoproject.com/en/2.0/ref/csrf/) +- [Django Sessions](https://docs.djangoproject.com/en/2.0/topics/http/sessions/) ### Basic authentication For the purposes of more convenient development, basic authentication is also supported for the REST API according to the [RFC 2617](https://datatracker.ietf.org/doc/html/rfc2617#section-2) standard. -<!-- -### Authorization - -### Process of Authorization - -Every endpoint resolver (in REST API and GraphQL), which allows access to data that should not be visible to everyone, should be decorated by decorators. -The INJECT authorization schema functions on the combinations of these decorators: - -#### protected - - - takes as an argument permission needed for accessing the endpoint - - Role-based access control -> checks whether the requester is assigned to a group with the required permission - - if request is unauthenticated, it automatically denies access - -```python -@protected(required_permission: str) -def resolver_function(): -  pass -``` -#### extra_protected - - takes `Enum Check` value - ```python - class Check(str, Enum): -  TEAM_ID = "team_id" -  EXERCISE_ID = "exercise_id" -  DEFINITION_ID = "definition_id" -  LOG_ID = "log_id" -  THREAD_ID = "thread_id" -  VISIBLE_ONLY = "visible_only" - ``` - - based on the value of the argument, checks whether the requester has access to a specific resource - - utilizes Access-controll list - - given argument must occur as a key-word argument of the endpoint resolver - - works by extracting the Check keyword value and executing the relevant check function - - if request is unauthenticated, it automatically denies access - -```python -@extra_protected(check: Check) -def resolver_function(argument): -  pass -``` - - example usage: -```python -@extra_protected(Check.TEAM_ID) -def resolver_function(team_id: str): -  pass -``` - -#### input_object_protected - - works on the same principle as **extra_protected** but instead of _Check enum argument, it takes the name of the input object argument. - - internally uses the same check functions as **extra_protected**, but differs in the extraction of the needed value for the check. -```python -@input_object_protected(object_name: str) -def resolver(): -  pass -``` -- example usage: -```python -@input_object_protected("create_exercise_input") -def resolver_function(create_exercise_input: CreateExerciseInput): -  pass -``` - -The best authorization control and functionality are achieved by combining the mentioned decorators. This way, you can set up more granular and specific checks. For example: - -```python -# Accessible only to the trainees assigned to the team with an ID equal to the team_id (inheritably for the instructors of the exercise, where the team with "team_id" belongs to) -@protected(Perms.view_trainee_info) # view_trainee_info is permission for the trainee role -@extra_protected(Checks.TEAM_ID) -def resolver(team_id: str): -  pass - -# Accessible only to the instructors of the exercise, where the thread with "thread_id" was created -@protected(Perms.analytics_view) # analytics_view is the permission of the instructor role -@extra_protected(Check.THREAD_ID) -def resolver(thread_id): -  pass -``` ---> - - <div class="navigation" markdown> [← Installation overview](../installation/overview.md){ .md-button } -</div> \ No newline at end of file +</div> diff --git a/docs/tech/security.md b/docs/tech/security.md index 772659e..1748a60 100644 --- a/docs/tech/security.md +++ b/docs/tech/security.md @@ -123,50 +123,46 @@ There are multiple ways to assign users to an exercise ### Manual assignment -You can assign users 'manually' by adding one or multiple -users to team or remove 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 the preparation or for the situations when you need to edit -semi-automatically created assignments. +You can assign users 'manually' by adding one or multiple users to a team or remove 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 the preparation or for the 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 will automatically assign selected users to teams - while trying to preserve balance between teams. Possible cases and their behavior: +#### **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 rest number (number_of_teams - number_of_users) of teams will be left empty. - + The rest (number_of_teams - number_of_users) of teams will be left empty. - _Number of users = number of teams_: Every team will have assigned exactly one user. - - - _Number of users > number of teams_: Starting with the first user, placing them on the - first team. Then, moving to the second user and placing them on the second team, and so on. + - _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 assign - the next user to the first team again. This continues until all users are assigned to a team.\ + 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 - - WARNING: This feature does not work with _role exercise_. +- If some users are already assigned in the exercise, they will not be reassigned based on the new assigning. +- WARNING: This feature _does not work_ with _role exercise_. + +#### **Assign by tags** -- **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 example: - - Image we have users (trainees) and their tags in the brackets (these tags were assigned - via CSV file): +- 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 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 power plant crisis. - We knew beforehand how we want 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 finds 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: + We knew beforehand how we want 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 second team - trainee3 will be assigned to the third team @@ -174,23 +170,23 @@ You can utilize one of the three options for semi-automatic assignment: - trainee4 in the first team - trainee2 in the second team - trainee1 and trainee3 in the third team - - Following **rules have to be complied** with to make this assignment by tags possible: - - Prefix parts have to be unique (which can be achieved by making them long enough). - If we had tags `EXERCISE_t1` and `EX_t1` and we would want to use the `EX_t1` we would - need to use prefix `EX`, which would also match with `EXERCISE_t1` and could cause - incorrect assignment (if we used prefix `EX_`we would dodge the match with other tag). - 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 first team, those with 2 to 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 there are more tags matching 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 number of teams 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 a selected exercise. - - Requires that the exercises matches in the number of teams, otherwise fails. - - Simply transfers assignment meaning the members of the first team from a selected exercise - will be members of the first team in the current exercise. +- The following **rules have to be complied with** to make this assignment possible: + - Prefix parts have to be unique for given assignment (which can be achieved by making them long enough). + If we had tags `EXERCISE_t1` and `EX_t1` and we would want to use the `EX_t1` we would need to use prefix `EX`, which would also match with `EXERCISE_t1` and could cause incorrect assignment (if we used prefix `EX_`we would dodge the match with other tag). + 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 first team, those with 2 to 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 there are more tags matching 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 number of teams 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 a 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 the another exercise. -- GitLab