CSC/ECE 517 Spring 2024 - E2421. Reimplement impersonating users (within impersonate controller.rb) - Final Project

From Expertiza_Wiki
Revision as of 20:51, 8 April 2024 by Mbhande2 (talk | contribs) (Created page with "==Expertiza== [http://expertiza.ncsu.edu/ Expertiza] is a [http://rubyonrails.org/ Ruby on Rails] based open source project. Instructors have the ability to add new projects, assignments, etc., as well as edit existing ones. Later on, they can view student submissions and grade them. Students can also use Expertiza to organize into teams to work on different projects and assignments and submit their work. They can also review other students' submissions. ==Project Over...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Expertiza

Expertiza is a Ruby on Rails based open source project. Instructors have the ability to add new projects, assignments, etc., as well as edit existing ones. Later on, they can view student submissions and grade them. Students can also use Expertiza to organize into teams to work on different projects and assignments and submit their work. They can also review other students' submissions.

Project Overview

The goal of this project is to update the backend code for the user impersonation feature in the new version of Expertiza. The existing implementation relies on sessions, which is incompatible with the new implementation that uses JWT (JSON Web Tokens) for authentication and JSON responses. The primary challenge is to migrate the impersonation logic from session-based management to JWT-based authentication while preserving the same functionality. This reimplementation requires planning for the communication between the backend and frontend, which may necessitate modifications to existing files or the creation of new files beyond the impersonate_controller.rb file.

Design Document

Current Status

We have successfully implemented the impersonate_users.controller and the necessary methods to generate a new JWT token with the required user information. The can_impersonate method in the user.rb file has been implemented to determine which roles have the authority to impersonate other users.

We have also thoroughly tested the API and functionality using Postman and created a detailed video showcasing the tests performed.

Issues and Plan of Action

Updated UML Diagram


1. TA-Student Mapping: The current implementation does not have a mapping between Teaching Assistants (TAs) and students, which is preventing TAs from accessing specific courses for the students they are impersonating. Currently, TAs have access to all courses, which needed to be fixed. So, we will work on implementing a mapping between TAs and students to ensure that TAs can only access courses for the students they are assigned to.

2. Refactoring Code: We will work on refactoring some of the code, including changing naming conventions based on the feedback received from the first project.

3. Testing Improvement: We will enhance the testing process by:

  • Incorporating Swagger UI to test the API endpoints.
  • Recording and uploading a video demonstrating the execution of automated test cases.

4. Documentation Update: We will update the wiki page to address the following issues:

  • Update the Role Hierarchy diagram to accurately reflect each role's permissions and get a clear idea of impersonating Hierarchy.
  • Improve the flow between the five sections under Implementation and provide an explanation for the order in which these topics are covered.
  • Include more detailed information about the tests performed, such as the conditions tested for.
  • Replace the illegible code snippets in the screenshots with larger, more readable images or code blocks.

By addressing these issues and implementing the necessary improvements, we will aim to deliver a comprehensive and well-documented implementation of the impersonate_users functionality.

Previous Work

Implementation

UML Diagram

The following UML diagram shows the association between models we will be working on


Hierarchy Diagram

Visualization of the hierarchical structure


Request

  • GET: {BASE_URL}/api/v1/impersonate/:username
  - Response:
   "message": "Successfully Fetched User List!",
   "userList": [
       {
           "id": 4,
           "name": "Mihir",
           "full_name": "Mihir BHanderi",
           "email": "mbhande@example.com",
           "email_on_review": false,
           "email_on_submission": false,
           "email_on_review_of_review": false,
           "role": {
               "id": 4,
               "name": "Teaching Assistant"
           },
           "institution": {
               "id": 1,
               "name": "North Carolina State University"
           },
           "parent": {
               "id": null,
               "name": null
           }
       }
   ],
   "success": true
  • POST: {BASE_URL}/api/v1/impersonate
  - Payload: impersonate_id
  - Response: 
    "message": "Successfully Impersonated Ketul!",
    "token": "eyJhbGciOiJSUzI1NiJ9.eyJpZCI6MywibmFtZSI6IktldHVsIiwiZnVsbF9uYW1lIjoiS2V0dWwgQ2hheXlhIiwicm9sZSI6Ikluc3RydWN0b3IiLCJpbnN0aXR1dGlvbl9pZCI6MSwiaW1wZXJzb25hdGVkIjp0cnVlLCJvcmlnaW5hbF91c2VyIjoiIzxVc2VyOjB4MDAwMDdmMzVmYTc5YjVmOD4iLCJleHAiOjE3MTEzMjc0MTV9.U9wDOT618UCkf25MnCiK8W3ybeZv5BSQDNTEPOMUDABAvDd0HWSj3kIGccITHaoVsIykZFsyUDY3rL_M32zmfEXvxZuEleWSqUZGxbjQRIFP1bR_Q5sPESoBdlxVJ4QG8sUGQtuhOzMyH3z4R4ruhz1JpsQlalVZQHCbdtJOI9B4WKhNJ98Dls1fefnzYwLMnTr6e3ttbGGGK5Bm8zSpPvIWmCVNoueKHNptFcNejbU4Mt9RHWHLsTwdAtuywNLCu7li7RRNXo00D5JOUMxL7eB5AiQRpxah8BF7b0lM_Xh7bB56WvD5JTjoNZu3c3AK_EJksGXiFxwlPzNRc8Q",
   "success": true


Impersonate Controller

The ImpersonateController facilitates user impersonation functionality. It includes methods to fetch a list of users available for impersonation based on a provided username parameter and to impersonate a selected user by generating a new JWT token with the necessary user information. The controller ensures that impersonation requests are handled securely, validating permissions before allowing impersonation to occur.

  • impersonate_controller.rb file
 class Api::V1::ImpersonateController < ApplicationController

  # Fetches users to impersonate whose name match the passed parameter
  def get_users_list
    users = current_user.get_available_users(params[:user_name])
    render json: { message: "Successfully Fetched User List!", userList:users, success:true }, status: :ok
  end

  def check_if_user_impersonateable?
    impersonate_user = User.find_by(id: params[:impersonate_id])
    if impersonate_user
      return current_user.can_impersonate? impersonate_user
    end
    false
  end

  # Impersonates a new user and returns new jwt token
  def impersonate
    unless params[:impersonate_id].present?
      render json: { error: "impersonate_id is required", success:false }, status: :unprocessable_entity
      return
    end

    if check_if_user_impersonateable?
      impersonate_user = User.find_by(id: params[:impersonate_id])

      payload = { id: impersonate_user.id, name: impersonate_user.name, full_name: impersonate_user.full_name, role: impersonate_user.role.name,
                  institution_id: impersonate_user.institution.id, impersonated:true, original_user: current_user }
      impersonate_user_token = JsonWebToken.encode(payload, 24.hours.from_now)

      render json: { message: "Successfully Impersonated #{impersonate_user.name}!", token:impersonate_user_token, success:true }, status: :ok

    else
      render json: { error: "You do not have permission to impersonate this user", success:false }, status: :forbidden
    end
  end
end


User

These methods extend the functionality of the User model. The get_available_users method retrieves users whose full names match a provided parameter. can_impersonate? determines whether the user has the authority to impersonate another user based on their role hierarchy. teaching_assistant_for? checks if the user is a teaching assistant for a given student, and teaching_assistant? determines if the user is a teaching assistant based on their role. Lastly, recursively_parent_of recursively checks for parent-child relationships between user roles.

  • user.rb file
  # Check if the user can impersonate another user
  def can_impersonate?(user)
    return true if role.super_administrator?
    return true if recursively_parent_of(user.role)
    false
  end

  # Check if the user is a teaching assistant for the student's course
  def teaching_assistant_for?(student)
    return false unless teaching_assistant?
    return false unless student.role.name == 'Student'

    # We have to use the Ta object instead of User object
    # because single table inheritance is not currently functioning
    ta = Ta.find(id)
    ta.managed_users.each do |user|
      return true if user.id == student.id
    end
    false
  end

  # Check if the user is a teaching assistant
  def teaching_assistant?
    true if role.ta?
  end

  # Recursively check if parent child relationship exists
  def recursively_parent_of(user_role)
    p = user_role.parent
    return false if p.nil?
    return true if p == self.role
    return false if p.super_administrator?
    recursively_parent_of(p)
  end

Files added / modified

  • reimplementation-back-end/app/models/user.rb
  • reimplementation-back-end/app/controllers/api/v1/impersonate_controller.rb
  • reimplementation-back-end/config/routes.rb

List of Users in Database

ID Email Password Role
1 admin2@example.com password123 Super-Administrator
2 jay@example.com password123 Administration
3 k2l@example.com password123 Instructor
4 mbhande@example.com password123 TA
7 dpatesl@example.com password123 Student

Testing on Postman

Postman was used to manually test the additional method in impersonate_controller.rb, as well as the actions and routes of the corresponding controllers. Before testing any of these methods with Postman, submit a request to /login using the user_name and password fields, which will send an authentication token. This token must be added to Postman's 'Authorization' tab as a 'Bearer token' before any further requests can be made. Postman collection link

  • First of all, fork the expertiza workspace in order to work upon it

  • Fetch User List which can be impersonated (For eg: If Instructor fetches list he can see matched TAs and Students only)

  • Login with provided credentials and copy the token

  • In the Expertiza/Authorization paste the token and save

  • Put the id for the user to be impersonated

  • Success message if the user is impersonable

  • Failure message if the user is not impersonable (Here instructor is trying to impersonate admin)

Here is the video of successfully running the tests [1]

Team

Mentor

  • Chetana Chunduru <cchetan2@ncsu.edu>

Students

  • Devansh Shah <dshah8@ncsu.edu>
  • Jay Patel <jhpatel9@ncsu.edu>
  • Mihir Bhanderi <mbhande2@ncsu.edu>

Pull Request

References