CSC/ECE 517 Fall 2023 - E2379. Reimplement authorization helper.rb: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
 
(8 intermediate revisions by 3 users not shown)
Line 63: Line 63:


[[File:Jwt-structure.png]]
[[File:Jwt-structure.png]]
== Methods Details ==
*'''Error Handling:''' The method is wrapped in a begin and rescue block to handle JWT::DecodeError. If an error occurs during the decoding process (e.g., an invalid signature or expired token), the method returns nil.
'''Error Handling'''
rescue JWT::DecodeError
  nil
end
*'''check_user_privileges(user_info, required_privilege):''' The check_user_privileges method is responsible for determining whether a user, based on their role and claims stored in a JSON Web Token (JWT), possesses the required privilege within the context of the application.
'''Pseudo Code'''
function check_user_privileges(user_info, required_privilege):
    Check if User info is null
        return false
    switch statement:
            case 'Administrator':
            return user_info[:role] == 'Administrator' OR user_info[:role] == 'Super-Administrator'
            case 'Student':
            return user_info[:role] == 'Student' OR user_info[:role] == 'Teaching Assistant' OR user_info[:role] == 'Instructor' OR user_info[:role] == 'Administrator' OR user_info[:role] == 'Super-Administrator'   
            Other cases
            default:
            return false
*'''Updating existing methods in the helper wherever session is being used.'''


== New methods created==
== New methods created==
*jwt_verify_and_decode:
*'''jwt_verify_and_decode:'''
Description:
Description:
This method is part of the JWT (JSON Web Token) Authentication Integration in the application. It serves the purpose of verifying and decoding a given JWT token using the JsonWebToken class. JWT tokens are commonly used for authentication and authorization purposes in web applications.
This method is part of the JWT (JSON Web Token) Authentication Integration in the application. It serves the purpose of verifying and decoding a given JWT token using the JsonWebToken class. JWT tokens are commonly used for authentication and authorization purposes in web applications.
Line 112: Line 87:
     end
     end


*check_user_privileges:
*'''user_has_needed_privileges?:'''
Description:
Description:
This method is responsible for checking user privileges based on the claims provided in a JWT (JSON Web Token). Given the user information extracted from the JWT and a required privilege, the method determines if the user possesses the specified privilege. The method primarily validates the user's role against the required privilege.
This method is responsible for checking user privileges based on the claims provided in a JWT (JSON Web Token). Given the user information extracted from the JWT and a required privilege, the method determines if the user possesses the specified privilege. The method primarily validates the user's role against the required privilege.
Line 125: Line 100:


'''Code''':
'''Code''':
     def check_user_privileges(user_info, required_privilege)
     def user_has_needed_privileges?(user_rights, required_privilege)
         return false unless user_info.present? && user_info['role'].present?
         return false unless user_rights.present? && user_rights['role'].present?
      
      
         case required_privilege
         case required_privilege
Line 145: Line 120:


== Existing methods updated==
== Existing methods updated==
*current_user_has_super_admin_privileges:
*'''current_user_has_super_admin_privileges:'''
Determine if the currently logged-in user has the privileges of a Super-Admin. It checks if the user has Super-Administrator privileges based on the JWT token. The method calls check_user_privileges with the appropriate privilege and returns the result.
Determine if the currently logged-in user has the privileges of a Super-Admin. It checks if the user has Super-Administrator privileges based on the JWT token. The method calls check_user_privileges with the appropriate privilege and returns the result.


Line 161: Line 136:




*current_user_has_admin_privileges:
*'''current_user_has_admin_privileges:'''
Determine if the currently logged-in user has the privileges of an Admin (or higher). It checks if the user has Administrator privileges based on the JWT token. The method calls check_user_privileges with the appropriate privilege and returns the result.
Determine if the currently logged-in user has the privileges of an Admin (or higher). It checks if the user has Administrator privileges based on the JWT token. The method calls check_user_privileges with the appropriate privilege and returns the result.


Line 177: Line 152:
  end
  end


*current_user_has_instructor_privileges:
*'''current_user_has_instructor_privileges:'''
Determine if the currently logged-in user has the privileges of an Instructor (or higher). It checks if the user has Instructor privileges based on the JWT token. The method calls check_user_privileges with the appropriate privilege and returns the result.
Determine if the currently logged-in user has the privileges of an Instructor (or higher). It checks if the user has Instructor privileges based on the JWT token. The method calls check_user_privileges with the appropriate privilege and returns the result.


Line 194: Line 169:
  end
  end


*current_user_has_ta_privileges:
*'''current_user_has_ta_privileges:'''
Determine if the currently logged-in user has the privileges of an Instructor (or higher). It checks if the user has Instructor privileges based on the JWT token. The method calls check_user_privileges with the appropriate privilege and returns the result.
Determine if the currently logged-in user has the privileges of an Instructor (or higher). It checks if the user has Instructor privileges based on the JWT token. The method calls check_user_privileges with the appropriate privilege and returns the result.


Line 211: Line 186:




*current_user_has_student_privileges:
*'''current_user_has_student_privileges:'''
Determine if the currently logged-in user has the privileges of a Student (or higher). It checks if the user has Student privileges based on the JWT token. The method calls check_user_privileges with the appropriate privilege and returns the result.
Determine if the currently logged-in user has the privileges of a Student (or higher). It checks if the user has Student privileges based on the JWT token. The method calls check_user_privileges with the appropriate privilege and returns the result.


Line 227: Line 202:




*current_user_is_assignment_participant:
*'''current_user_is_assignment_participant:'''
Determine if the currently logged-in user is participating in an Assignment based on the assignment_id argument. It checks if the user is a participant in a specific assignment based on the JWT token.
Determine if the currently logged-in user is participating in an Assignment based on the assignment_id argument. It checks if the user is a participant in a specific assignment based on the JWT token.


Line 246: Line 221:




*current_user_teaching_staff_of_assignment:
*'''current_user_teaching_staff_of_assignment:'''
Determine if the currently logged-in user is teaching staff of an Assignment based on the assignment_id argument. It checks if the user is an instructor or has TA mapping for a specific assignment based on the JWT token.
Determine if the currently logged-in user is teaching staff of an Assignment based on the assignment_id argument. It checks if the user is an instructor or has TA mapping for a specific assignment based on the JWT token.


Line 271: Line 246:
  end
  end


*current_user_is_a:
*'''current_user_is_a:'''
Determine if the currently logged-in user IS of the given role name. It checks if the user's role in the JWT token matches the provided role name.
Determine if the currently logged-in user IS of the given role name. It checks if the user's role in the JWT token matches the provided role name.


Line 285: Line 260:
  end
  end


*current_user_has_id:
*'''current_user_has_id:'''
Determine if the current user has the passed-in id value. It checks if the user's ID in the JWT token matches the provided ID.
Determine if the current user has the passed-in id value. It checks if the user's ID in the JWT token matches the provided ID.


Line 299: Line 274:
  end
  end


*current_user_created_bookmark_id:
*'''current_user_created_bookmark_id:'''
Determine if the currently logged-in user created the bookmark with the given ID. It checks if the user in the JWT token created the bookmark with the specified ID.
Determine if the currently logged-in user created the bookmark with the given ID. It checks if the user in the JWT token created the bookmark with the specified ID.


Line 319: Line 294:
  end
  end


*given_user_can_submit:
*'''current_user_can_submit:'''
Determine if the given user can submit work. It checks if the user in the JWT token can submit work.
Determine if the given user can submit work. It checks if the user in the JWT token can submit work.


Line 328: Line 303:


'''Updated Code''':
'''Updated Code''':
  def given_user_can_submit?(token, user_id)
  def current_user_can_submit?(token, user_id)
   given_user_can?(token, user_id, 'submit')
   current_user_can?(token, user_id, 'submit')
  end
  end


*given_user_can_review:
*'''current_user_can_review:'''
Determine if the given user can review work. It checks if the user in the JWT token can review work.
Determine if the given user can review work. It checks if the user in the JWT token can review work.


Line 341: Line 316:


''' Updated Code ''':
''' Updated Code ''':
  def given_user_can_review?(token, user_id)
  def current_user_can_review?(token, user_id)
   given_user_can?(token, user_id, 'review')
   current_user_can?(token, user_id, 'review')
  end
  end


*given_user_can_take_quiz:
*'''current_user_can_take_quiz:'''
Determine if the given user can take quizzes. It checks if the user in the JWT token can take quizzes.
Determine if the given user can take quizzes. It checks if the user in the JWT token can take quizzes.


Line 354: Line 329:


'''Updated Code''':
'''Updated Code''':
  def given_user_can_take_quiz?(token, user_id)
  def current_user_can_take_quiz?(token, user_id)
   given_user_can?(token, user_id, 'take_quiz')
   current_user_can?(token, user_id, 'take_quiz')
  end
  end


*given_user_can_read:
*'''current_user_can_read:'''
Determine if the given user can read work. It checks if the user in the JWT token can read work.
Determine if the given user can read work. It checks if the user in the JWT token can read work.


Line 367: Line 342:


''' Updated Code ''':
''' Updated Code ''':
  def given_user_can_read?(token, user_id)
  def current_user_can_read?(token, user_id)
   given_user_can_take_quiz?(token, user_id)
   current_user_can_take_quiz?(token, user_id)
  end
  end


==Test Plan==
==Test Plan==
Line 378: Line 352:
*'''Verify JWT Token Processing:'''
*'''Verify JWT Token Processing:'''
Confirm that JWT tokens are correctly processed, verified, and decoded.
Confirm that JWT tokens are correctly processed, verified, and decoded.
'''Token Encoding:'''
'''Token Encoding:'''
Ensure that a user's information (e.g., user_id, role) is properly encoded into a JWT token during the authentication process.
Ensure that a user's information (e.g., user_id, role) is properly encoded into a JWT token during the authentication process.
'''Token Decoding:'''
'''Token Decoding:'''
Implement a method to decode and verify JWT tokens.
Implement a method to decode and verify JWT tokens.
Confirm that the decoding process is successful and returns the expected user information.
Confirm that the decoding process is successful and returns the expected user information.
'''Token Expiry Handling:'''
'''Token Expiry Handling:'''
Check that the system handles token expiry properly and denies access or requests re-authentication when a token is expired.
Check that the system handles token expiry properly and denies access or requests re-authentication when a token is expired.
'''Token Signature Verification:'''
'''Token Signature Verification:'''
Validate that the system verifies the signature of the JWT token to ensure its authenticity.
Validate that the system verifies the signature of the JWT token to ensure its authenticity.
Line 390: Line 368:
*'''User Privilege Verification:'''
*'''User Privilege Verification:'''
Ensure that user privileges are correctly verified based on JWT claims.
Ensure that user privileges are correctly verified based on JWT claims.
'''Role-Based Access Control (RBAC):'''
'''Role-Based Access Control (RBAC):'''
Integrate RBAC using JWT claims to determine user roles.
Integrate RBAC using JWT claims to determine user roles.
Update methods that check for specific privileges to rely on JWT claims instead of other mechanisms.
Update methods that check for specific privileges to rely on JWT claims instead of other mechanisms.
'''Privilege Validation Methods:'''
'''Privilege Validation Methods:'''
Update existing methods (e.g., current_user_has_admin_privileges?) to utilize information from JWT claims.
Update existing methods (e.g., current_user_has_admin_privileges?) to utilize information from JWT claims.
Line 399: Line 379:
*'''User Identity Verification:'''
*'''User Identity Verification:'''
Confirm that the user's identity is accurately verified based on the JWT token.
Confirm that the user's identity is accurately verified based on the JWT token.
'''User ID Verification:'''
'''User ID Verification:'''
Update methods that validate the user's identity (current_user_has_id?) to use the user_id claim from the JWT token.
Update methods that validate the user's identity (current_user_has_id?) to use the user_id claim from the JWT token.
Ensure that the system checks the user's ID against the one provided in the token.
Ensure that the system checks the user's ID against the one provided in the token.
'''User Role Verification:'''
'''User Role Verification:'''
Implement methods to check if the user has a specific role (current_user_is_a?) based on JWT claims.
Implement methods to check if the user has a specific role (current_user_is_a?) based on JWT claims.
Line 408: Line 390:
*'''Existing Methods Update:'''
*'''Existing Methods Update:'''
Validate that existing methods are successfully updated to use JWT claims.
Validate that existing methods are successfully updated to use JWT claims.
'''Method Refactoring:'''
'''Method Refactoring:'''
Refactor existing authentication and authorization methods to utilize JWT claims for user information.
Refactor existing authentication and authorization methods to utilize JWT claims for user information.
Ensure that methods no longer rely on separate data stores for user roles or privileges.
Ensure that methods no longer rely on separate data stores for user roles or privileges.
'''Unit Testing:'''
'''Unit Testing:'''
Create unit tests for each updated method to ensure that they work correctly with JWT claims.
Create unit tests for each updated method to ensure that they work correctly with JWT claims.
Line 432: Line 416:
Validate the behavior of updated methods with various scenarios.
Validate the behavior of updated methods with various scenarios.


*mgcghcmhv
*'''Generate a JWT token using Postman:'''
[[File:E2379 postman.png|500px|center]]
 
1.Open Postman and create a new request or collection.
 
2.In the request, go to the "Authorization" tab and choose "Bearer Token" as the type.
 
3.Click "Get New Access Token" to open the "Token" modal.
 
4.Configure the token with a name, grant type, token endpoint URL, client ID, secret, scope, etc.
 
5.Click "Request Token" to obtain the token, and enter additional credentials if prompted.
 
6.The generated token is displayed in the "Token" modal and is automatically added to the request's "Authorization" header.
 
7.Use the token to authenticate subsequent requests.
 
8.Configure Postman to handle token expiry and automatic token refresh if needed.
 
9.Save the token configuration for reuse.


*mbcgfjhgf
[[File:E2379 token.png|500px|center]]
[[File:E2379 token.png|500px|center]]


*jtfjgkjhbj
*'''Decode JWT Token:'''
 
The JWT token can be decoded using jwt.io.
 
[[File:E2379 postman.png|500px|center]]
 
*'''Run the rails server and confirm its successful execution:'''
[[File:E2379 RubyOnRails.png|500px|center]]
[[File:E2379 RubyOnRails.png|500px|center]]


* Rspec Test cases file:
* '''Rspec Test cases file:'''
Rspec test cases file is run, and all the tests have passed.
 
[[File:E2379 TestsSuccess.png|500px|center]]
[[File:E2379 TestsSuccess.png|500px|center]]
For more detailed explanation of the project, here is the [https://youtu.be/VJhz1xKAde4 Demo Link].


== Team ==
== Team ==
Line 452: Line 462:
*Sucharitha Nadendla (snadend3)
*Sucharitha Nadendla (snadend3)
*Abhishek Desai (adesai7)
*Abhishek Desai (adesai7)
== Pull Request ==
[https://github.com/expertiza/reimplementation-back-end/pull/67 Pull Request]

Latest revision as of 16:57, 14 December 2023

This wiki page is for the information regarding the changes made for the E2379 OSS assignment for Fall 2023, CSC/ECE 517.

Introduction

Expertiza is an open source project developed on Ruby on Rails. This web application is maintained by the student and faculty at NC State. This application gives complete control to the instructor to maintain the assignments in their class. With multiple functionalities such as adding topics, creating groups, and peer reviews, Expertiza is a well-developed application that can handle all types of assignments. To learn more about the full functionality Expertiza has to offer, visit the Expertiza wiki. The Expertiza currently uses session-based authentication in its AuthorizationHelper module. The reimplementation back end uses JSON Web Token (JWT) based authentication. This requires a redesign of the AuthorizationHelper module to accommodate JWT-based authentication.

About Authorization Helper

The AuthorizationHelper module provides methods to check a user's privileges and roles within the system. It allows you to determine if the current user has specific roles like Super-Admin, Admin, Instructor, TA, or Student. You can also check if the user is a participant in a particular assignment, instructs an assignment, or has TA mappings for an assignment. Additionally, it provides methods to identify if the current user can perform actions like submitting work, reviewing, or taking quizzes. These functions are essential for managing user permissions and access control in the application.

  • Role Verification:

The module allows you to determine if the current user possesses specific roles such as Super-Admin, Admin, Instructor, TA (Teaching Assistant), or Student. This is pivotal for identifying the user's overarching responsibilities and access levels within the system.

  • Assignment-related Checks:

You can use the module to check whether the user is a participant in a particular assignment, holds the role of an instructor for an assignment, or has TA mappings (Teaching Assistant assignments) associated with a specific task. These checks are instrumental in understanding the user's involvement and responsibilities in the context of assignments.

  • Action Permissions:

The AuthorizationHelper module provides methods to determine if the current user is allowed to perform specific actions. For instance, you can check if the user can submit work, conduct reviews, or take quizzes. This functionality ensures that user actions align with their assigned roles and responsibilities.

  • Access Control:

Through the aforementioned checks, the module facilitates robust access control by enabling you to tailor the user experience based on their roles and permissions. This is vital for maintaining system security and ensuring that users can only perform actions for which they are authorized.

Requirements

  • JWT Authentication Integration: Modify the AuthorizationHelper module to integrate JWT-based authentication, allowing users to authenticate and authorize requests using JWT tokens instead of sessions.
  • Token Verification: Implement methods to verify and decode JWT tokens to extract user information and permissions.
  • Privilege Verification: Update the existing methods (e.g., current_user_has_super_admin_privileges?, current_user_is_a?, etc) to use JWT claims to determine a user's privileges. Users will be granted access based on their role and claims within the JWT.
  • User Identity Verification: Implement a method to verify the identity of the current user based on the JWT token. Ensure that the user's role is validated correctly.
  • Methods should be updated to use the user's JWT claims.
  • Error Handling: Implement appropriate error handling to deal with JWT verification failures or unauthorized access attempts.


Methods to be implemented

  • jwt_verify_and_decode(token): This method will verify and decode a JWT token and return the user's information, including role and claims.
  • check_user_privileges(user_info, required_privilege): Given user information from the JWT and a required privilege, this method will determine if the user has the required privilege.
  • Update and adapt the existing methods to use JWT claims for authentication and authorization.

Deliverables

  • A modified and fully functional AuthorizationHelper module with JWT-based authentication.
  • Updated methods to ensure JWT claims are used for authentication and authorization.
  • Appropriate error handling to handle JWT-related issues.
  • Unit tests should cover different scenarios and edge cases to ensure that each function works as expected
  • Comments for every function.

JWT Token

JSON Web Tokens (JWT) are commonly used for implementing authorization in web applications. The AuthorizationHelper module can leverage JWT tokens to determine the privileges and roles of a user. Here's a general overview of how JWT tokens are typically used for authorization:

  • Token Generation:

When a user logs in or authenticates, a JWT token is generated on the server-side. This token typically includes information such as the user's ID, roles, and any other relevant claims.

  • Token Issuance:

The server issues the JWT token to the client after successful authentication. The client then stores this token, usually in a secure manner such as in an HTTP-only cookie or local storage.

  • Token Inclusion in Requests:

For subsequent requests to the server that require authorization, the client includes the JWT token in the request headers. This can be done using the "Authorization" header with a value like "Bearer <token>".

  • Token Verification on the Server:

The server-side AuthorizationHelper module receives the JWT token from the client in the request. It then verifies the token's integrity and authenticity using a secret key known only to the server.

  • Decoding the Token:

Once the token is verified, the server decodes its content. The decoded payload includes information about the user, such as their roles, which the AuthorizationHelper module can use for authorization checks.

  • Authorization Checks:

The AuthorizationHelper module performs checks based on the decoded information from the JWT token. For example, it may check if the user has the required roles or permissions to access certain resources or perform specific actions.

  • Access Granted or Denied:

Based on the results of the authorization checks, the server responds to the client's request by either allowing or denying access to the requested resource.

A JWT contains three parts:

  • Header: Consists of two parts: The signing algorithm that’s being used and the type of token.
  • Payload: The payload contains the claims or the JSON object.
  • Signature: A string that is generated via a cryptographic algorithm that can be used to verify the integrity of the JSON payload.

New methods created

  • jwt_verify_and_decode:

Description: This method is part of the JWT (JSON Web Token) Authentication Integration in the application. It serves the purpose of verifying and decoding a given JWT token using the JsonWebToken class. JWT tokens are commonly used for authentication and authorization purposes in web applications.

Parameters: token (String): The JWT token that needs to be verified and decoded.

Returns: If the provided JWT token is valid, the method decodes the token using the JsonWebToken.decode method. If decoding is successful, the decoded information is converted into a HashWithIndifferentAccess to provide easy access to the user information with indifferent access to symbol and string keys. If the token is invalid or decoding fails (raises JWT::DecodeError), the method returns nil.

Code

   def jwt_verify_and_decode(token)
     begin
       decoded_token = JsonWebToken.decode(token)
       return HashWithIndifferentAccess.new(decoded_token)
     rescue JWT::DecodeError
       return nil
     end
   end
  • user_has_needed_privileges?:

Description: This method is responsible for checking user privileges based on the claims provided in a JWT (JSON Web Token). Given the user information extracted from the JWT and a required privilege, the method determines if the user possesses the specified privilege. The method primarily validates the user's role against the required privilege.

Parameters: user_info (HashWithIndifferentAccess): User information extracted from the JWT, typically containing details like the user's role.

required_privilege (String): The required privilege that the method checks against the user's role. Returns: true if the user possesses the required privilege. false otherwise, including cases where the user information is not present (nil) or lacks a role.

Code:

   def user_has_needed_privileges?(user_rights, required_privilege)
       return false unless user_rights.present? && user_rights['role'].present?
   
       case required_privilege
       when 'Super-Administrator'
       return user_info['role'] == 'Super-Administrator'
       when 'Administrator'
       return user_info['role'] == 'Administrator'
       when 'Instructor'
       return user_info['role'] == 'Instructor'
       when 'Teaching Assistant'
       return user_info['role'] == 'Teaching Assistant'
       when 'Student'
       return user_info['role'] == 'Student'
       else
       return false
       end
   end

Existing methods updated

  • current_user_has_super_admin_privileges:

Determine if the currently logged-in user has the privileges of a Super-Admin. It checks if the user has Super-Administrator privileges based on the JWT token. The method calls check_user_privileges with the appropriate privilege and returns the result.

Old Code:

def current_user_has_super_admin_privileges?
  current_user_has_privileges_of?('Super-Administrator')
end

Updated Code:

def current_user_has_super_admin_privileges?(token)
  user_info = jwt_verify_and_decode(token)
  return check_user_privileges(user_info, 'Super-Administrator') if user_info.present?
  false
end


  • current_user_has_admin_privileges:

Determine if the currently logged-in user has the privileges of an Admin (or higher). It checks if the user has Administrator privileges based on the JWT token. The method calls check_user_privileges with the appropriate privilege and returns the result.

Old Code:

def current_user_has_admin_privileges?
  current_user_has_privileges_of?('Administrator')
end


Updated Code:

def current_user_has_admin_privileges?(token)
  user_info = jwt_verify_and_decode(token)
  return check_user_privileges(user_info, 'Administrator') if user_info.present?
  false
end
  • current_user_has_instructor_privileges:

Determine if the currently logged-in user has the privileges of an Instructor (or higher). It checks if the user has Instructor privileges based on the JWT token. The method calls check_user_privileges with the appropriate privilege and returns the result.

Old Code:

def current_user_has_instructor_privileges?
  current_user_has_privileges_of?('Instructor')
end


Updated Code:

def current_user_has_instructor_privileges?(token)
  user_info = jwt_verify_and_decode(token)
  return check_user_privileges(user_info, 'Instructor') if user_info.present?
  false
end
  • current_user_has_ta_privileges:

Determine if the currently logged-in user has the privileges of an Instructor (or higher). It checks if the user has Instructor privileges based on the JWT token. The method calls check_user_privileges with the appropriate privilege and returns the result.

Old Code:

def current_user_has_ta_privileges?
  current_user_has_privileges_of?('Teaching Assistant')
end


Updated Code:

def current_user_has_ta_privileges?(token)
  user_info = jwt_verify_and_decode(token)
  return check_user_privileges(user_info, 'Teaching Assistant') if user_info.present?
  false
end


  • current_user_has_student_privileges:

Determine if the currently logged-in user has the privileges of a Student (or higher). It checks if the user has Student privileges based on the JWT token. The method calls check_user_privileges with the appropriate privilege and returns the result.

Old Code:

def current_user_has_student_privileges?
  current_user_has_privileges_of?('Student')
end

Updated Code:

def current_user_has_student_privileges?(token)
  user_info = jwt_verify_and_decode(token)
  return check_user_privileges(user_info, 'Student') if user_info.present?
  false
end


  • current_user_is_assignment_participant:

Determine if the currently logged-in user is participating in an Assignment based on the assignment_id argument. It checks if the user is a participant in a specific assignment based on the JWT token.

Old Code:

def current_user_is_assignment_participant?(assignment_id)
  if user_logged_in?
    return AssignmentParticipant.exists?(parent_id: assignment_id, user_id: session[:user].id)
  end
  false
end

Updated Code:

def current_user_is_assignment_participant?(token, assignment_id)
  user_info = jwt_verify_and_decode(token)
  return AssignmentParticipant.exists?(parent_id: assignment_id, user_id: user_info[:id]) if user_info.present?
  false
end


  • current_user_teaching_staff_of_assignment:

Determine if the currently logged-in user is teaching staff of an Assignment based on the assignment_id argument. It checks if the user is an instructor or has TA mapping for a specific assignment based on the JWT token.


Old Code:

def current_user_teaching_staff_of_assignment?(assignment_id)
  assignment = Assignment.find(assignment_id)
  user_logged_in? &&
    (
        current_user_instructs_assignment?(assignment) ||
        current_user_has_ta_mapping_for_assignment?(assignment)
      )
end

Updated Code:

def current_user_teaching_staff_of_assignment?(token, assignment_id)
  assignment = Assignment.find(assignment_id)
  user_info = jwt_verify_and_decode(token)
  user_info.present? &&
    (
      current_user_instructs_assignment?(assignment, user_info) ||
      current_user_has_ta_mapping_for_assignment?(assignment, user_info)
    )
end
  • current_user_is_a:

Determine if the currently logged-in user IS of the given role name. It checks if the user's role in the JWT token matches the provided role name.

Old Code:

def current_user_is_a?(role_name)
  current_user_and_role_exist? && session[:user].role.name == role_name
end

Updated Code:

def current_user_is_a?(token, role_name)
  user_info = jwt_verify_and_decode(token)
  return user_info.present? && user_info[:role] == role_name
end
  • current_user_has_id:

Determine if the current user has the passed-in id value. It checks if the user's ID in the JWT token matches the provided ID.

Old Code:

def current_user_has_id?(id)
  user_logged_in? && session[:user].id.eql?(id.to_i)
end

Updated Code:

def current_user_has_id?(token, id)
  user_info = jwt_verify_and_decode(token)
  return user_info.present? && user_info[:id].to_i == id.to_i
end
  • current_user_created_bookmark_id:

Determine if the currently logged-in user created the bookmark with the given ID. It checks if the user in the JWT token created the bookmark with the specified ID.

Old Code:

def current_user_created_bookmark_id?(bookmark_id)
  user_logged_in? && !bookmark_id.nil? && Bookmark.find(bookmark_id.to_i).user_id == session[:user].id
rescue ActiveRecord::RecordNotFound
  false
end

Updated Code:

def current_user_created_bookmark_id?(token, bookmark_id)
  user_info = jwt_verify_and_decode(token)
  return user_info.present? &&
         !bookmark_id.nil? &&
         Bookmark.find(bookmark_id.to_i).user_id == user_info[:id]
rescue ActiveRecord::RecordNotFound
  false
end
  • current_user_can_submit:

Determine if the given user can submit work. It checks if the user in the JWT token can submit work.

Old Code:

def given_user_can_submit?(user_id)
  given_user_can?(user_id, 'submit')
end

Updated Code:

def current_user_can_submit?(token, user_id)
  current_user_can?(token, user_id, 'submit')
end
  • current_user_can_review:

Determine if the given user can review work. It checks if the user in the JWT token can review work.

Old Code:

def given_user_can_review?(user_id)
  given_user_can?(user_id, 'review')
end

Updated Code :

def current_user_can_review?(token, user_id)
  current_user_can?(token, user_id, 'review')
end
  • current_user_can_take_quiz:

Determine if the given user can take quizzes. It checks if the user in the JWT token can take quizzes.

Old Code:

def given_user_can_take_quiz?(user_id)
  given_user_can?(user_id, 'take_quiz')
end

Updated Code:

def current_user_can_take_quiz?(token, user_id)
  current_user_can?(token, user_id, 'take_quiz')
end
  • current_user_can_read:

Determine if the given user can read work. It checks if the user in the JWT token can read work.

Old Code:

def given_user_can_read?(user_id)
   given_user_can_take_quiz?(user_id)
 end

Updated Code :

def current_user_can_read?(token, user_id)
  current_user_can_take_quiz?(token, user_id)
end

Test Plan

  • JWT Authentication Integration

Objectives:

  • Verify JWT Token Processing:

Confirm that JWT tokens are correctly processed, verified, and decoded.

Token Encoding: Ensure that a user's information (e.g., user_id, role) is properly encoded into a JWT token during the authentication process.

Token Decoding: Implement a method to decode and verify JWT tokens. Confirm that the decoding process is successful and returns the expected user information.

Token Expiry Handling: Check that the system handles token expiry properly and denies access or requests re-authentication when a token is expired.

Token Signature Verification: Validate that the system verifies the signature of the JWT token to ensure its authenticity.

  • User Privilege Verification:

Ensure that user privileges are correctly verified based on JWT claims.

Role-Based Access Control (RBAC): Integrate RBAC using JWT claims to determine user roles. Update methods that check for specific privileges to rely on JWT claims instead of other mechanisms.

Privilege Validation Methods: Update existing methods (e.g., current_user_has_admin_privileges?) to utilize information from JWT claims. Ensure that the system grants or denies access based on the user's role and privileges stored in the JWT token.

  • User Identity Verification:

Confirm that the user's identity is accurately verified based on the JWT token.

User ID Verification: Update methods that validate the user's identity (current_user_has_id?) to use the user_id claim from the JWT token. Ensure that the system checks the user's ID against the one provided in the token.

User Role Verification: Implement methods to check if the user has a specific role (current_user_is_a?) based on JWT claims. Verify that the system accurately identifies the user's role using the JWT token.

  • Existing Methods Update:

Validate that existing methods are successfully updated to use JWT claims.

Method Refactoring: Refactor existing authentication and authorization methods to utilize JWT claims for user information. Ensure that methods no longer rely on separate data stores for user roles or privileges.

Unit Testing: Create unit tests for each updated method to ensure that they work correctly with JWT claims. Verify that the methods return expected results for various scenarios, such as different roles and expired tokens.

Test Cases

  • JWT Token Processing:

Verify that a valid JWT token is successfully processed and decoded. Test with an invalid token to ensure proper error handling.

  • User Privilege Verification:

Check user privileges for various roles (super admin, admin, instructor, TA, student). Verify user privileges for specific actions (submitting work, reviewing, etc.).

  • Error Handling:

Test error handling for JWT verification failures. Attempt unauthorized access and validate appropriate error handling.

  • User Identity Verification:

Verify the correct identification of the current user based on the JWT token. Test with various roles to ensure accurate identification.

  • Existing Methods Update:

Confirm that existing methods are updated to use JWT claims for authentication and authorization. Validate the behavior of updated methods with various scenarios.

  • Generate a JWT token using Postman:

1.Open Postman and create a new request or collection.

2.In the request, go to the "Authorization" tab and choose "Bearer Token" as the type.

3.Click "Get New Access Token" to open the "Token" modal.

4.Configure the token with a name, grant type, token endpoint URL, client ID, secret, scope, etc.

5.Click "Request Token" to obtain the token, and enter additional credentials if prompted.

6.The generated token is displayed in the "Token" modal and is automatically added to the request's "Authorization" header.

7.Use the token to authenticate subsequent requests.

8.Configure Postman to handle token expiry and automatic token refresh if needed.

9.Save the token configuration for reuse.

  • Decode JWT Token:

The JWT token can be decoded using jwt.io.

  • Run the rails server and confirm its successful execution:
  • Rspec Test cases file:

Rspec test cases file is run, and all the tests have passed.

For more detailed explanation of the project, here is the Demo Link.

Team

Mentor

  • Ameya Vaichalikar (agvaicha)

Members

  • Sravya Karanam (skarana)
  • Sucharitha Nadendla (snadend3)
  • Abhishek Desai (adesai7)

Pull Request

Pull Request