diff --git a/app/api/activity_types_public_api.rb b/app/api/activity_types_public_api.rb index 5d08e11fbf..77ca48fee7 100644 --- a/app/api/activity_types_public_api.rb +++ b/app/api/activity_types_public_api.rb @@ -1,6 +1,11 @@ require 'grape' class ActivityTypesPublicApi < Grape::API + helpers AuthenticationHelpers + + before do + error!({ error: '401 Unauthorized' }, 401) unless authenticated_without_error? + end desc "Get an activity type details" get '/activity_types/:id' do present ActivityType.find(params[:id]), with: Entities::ActivityTypeEntity diff --git a/app/api/api_root.rb b/app/api/api_root.rb index bde5f02365..ba3f3006c1 100644 --- a/app/api/api_root.rb +++ b/app/api/api_root.rb @@ -93,6 +93,7 @@ class ApiRoot < Grape::API AuthenticationHelpers.add_auth_to Admin::OverseerAdminApi AuthenticationHelpers.add_auth_to ActivityTypesAuthenticatedApi + AuthenticationHelpers.add_auth_to ActivityTypesPublicApi AuthenticationHelpers.add_auth_to BreaksApi AuthenticationHelpers.add_auth_to DiscussionCommentApi AuthenticationHelpers.add_auth_to ExtensionCommentsApi @@ -100,6 +101,7 @@ class ApiRoot < Grape::API AuthenticationHelpers.add_auth_to LearningOutcomesApi AuthenticationHelpers.add_auth_to LearningAlignmentApi AuthenticationHelpers.add_auth_to ProjectsApi + AuthenticationHelpers.add_auth_to SettingsApi AuthenticationHelpers.add_auth_to StudentsApi AuthenticationHelpers.add_auth_to Submission::PortfolioApi AuthenticationHelpers.add_auth_to Submission::PortfolioEvidenceApi diff --git a/app/api/campuses_public_api.rb b/app/api/campuses_public_api.rb index 9ec897edc0..2828454cf8 100644 --- a/app/api/campuses_public_api.rb +++ b/app/api/campuses_public_api.rb @@ -1,6 +1,11 @@ require 'grape' class CampusesPublicApi < Grape::API + helpers AuthenticationHelpers + + before do + error!({ error: '401 Unauthorized' }, 401) unless authenticated_without_error? + end desc "Get a campus details" get '/campuses/:id' do campus = Campus.find(params[:id]) diff --git a/app/api/settings_api.rb b/app/api/settings_api.rb index 39be2d292a..82e9216842 100644 --- a/app/api/settings_api.rb +++ b/app/api/settings_api.rb @@ -1,6 +1,11 @@ require 'grape' class SettingsApi < Grape::API + helpers AuthenticationHelpers + + before do + error!({ error: '401 Unauthorized' }, 401) unless authenticated_without_error? + end # # Returns the current auth method # diff --git a/app/api/teaching_periods_public_api.rb b/app/api/teaching_periods_public_api.rb index 9f17860541..442772881c 100644 --- a/app/api/teaching_periods_public_api.rb +++ b/app/api/teaching_periods_public_api.rb @@ -1,6 +1,11 @@ require 'grape' class TeachingPeriodsPublicApi < Grape::API + helpers AuthenticationHelpers + + before do + error!({ error: '401 Unauthorized' }, 401) unless authenticated_without_error? + end desc "Get a teaching period's details" get '/teaching_periods/:id' do teaching_period = TeachingPeriod.find(params[:id]) diff --git a/app/helpers/authentication_helpers.rb b/app/helpers/authentication_helpers.rb index 96128ae0af..fd9d5ca459 100644 --- a/app/helpers/authentication_helpers.rb +++ b/app/helpers/authentication_helpers.rb @@ -48,6 +48,19 @@ def authenticated? end end + # + # Check authentication without raising an error. + # Returns true if authenticated, false otherwise. + # + def authenticated_without_error? + catch(:error) do + return true if authenticated? + end + false + end + + module_function :authenticated_without_error? + # # Get the current user either from warden or from the header # diff --git a/test/api/activity_types_api_test.rb b/test/api/activity_types_api_test.rb index ca05092413..38eb5b788c 100644 --- a/test/api/activity_types_api_test.rb +++ b/test/api/activity_types_api_test.rb @@ -9,7 +9,19 @@ def app Rails.application end + def test_get_all_activity_types_requires_authentication + get '/api/activity_types' + assert_equal 401, last_response.status + end + + def test_get_activity_type_by_id_requires_authentication + activity_type = FactoryBot.create(:activity_type) + get "/api/activity_types/#{activity_type.id}" + assert_equal 401, last_response.status + end + def test_get_all_activity_types + add_auth_header_for(user: User.first) get '/api/activity_types' expected_data = ActivityType.all @@ -23,12 +35,20 @@ def test_get_all_activity_types end end + def test_get_activity_type_by_id + activity_type = FactoryBot.create(:activity_type) + add_auth_header_for(user: User.first) + get "/api/activity_types/#{activity_type.id}" + response_keys = %w(name abbreviation) + assert_json_matches_model(activity_type, last_response_body, response_keys) + end + # POST tests # 1: Admin can create a new activity type def test_admin_can_post_activity_type # Admin user admin = FactoryBot.create(:user, :admin) - + # the number of teaching period before post no_activity_type = ActivityType.count @@ -42,8 +62,8 @@ def test_admin_can_post_activity_type # perform the POST post_json '/api/activity_types', data_to_post - - # check if the request get through + + # check if the request get through assert_equal 201, last_response.status # check if the details posted match as expected @@ -63,7 +83,7 @@ def test_admin_can_post_activity_type def test_convenor_cannot_post_activity_type # Convenor user convenor = FactoryBot.create(:user, :convenor) - + # the number of teaching period before post no_activity_type = ActivityType.count @@ -74,11 +94,11 @@ def test_convenor_cannot_post_activity_type # auth_token and username added to header add_auth_header_for(user: convenor) - + # perform the POST post_json '/api/activity_types', data_to_post - - # check if the request get through + + # check if the request get through assert_equal 403, last_response.status # check if no more activity type is created @@ -89,7 +109,7 @@ def test_convenor_cannot_post_activity_type def test_tutor_cannot_post_activity_type # Tutor user tutor = FactoryBot.create(:user, :tutor) - + # the number of teaching period before post no_activity_type = ActivityType.count @@ -100,11 +120,11 @@ def test_tutor_cannot_post_activity_type # auth_token and username added to header add_auth_header_for(user: tutor) - + # perform the POST post_json '/api/activity_types', data_to_post - - # check if the request get through + + # check if the request get through assert_equal 403, last_response.status # check if no more activity type is created @@ -119,8 +139,8 @@ def test_admin_can_put_activity_types # The activity type to be replaced activity_type = FactoryBot.create(:activity_type) - - # Data to replace + + # Data to replace data_to_put = { activity_type: FactoryBot.build(:activity_type) } @@ -130,7 +150,7 @@ def test_admin_can_put_activity_types # Update activity_type with data_to_put put_json "/api/activity_types/#{activity_type.id}", data_to_put - + #check if the request get through assert_equal 200, last_response.status @@ -139,7 +159,7 @@ def test_admin_can_put_activity_types activity_type_updated = activity_type.reload assert_json_matches_model(activity_type_updated, last_response_body, response_keys) - # check if the details in the replaced teaching period match as data set to replace + # check if the details in the replaced teaching period match as data set to replace assert_equal data_to_put[:activity_type]['name'], activity_type_updated.name assert_equal data_to_put[:activity_type]['abbreviation'], activity_type_updated.abbreviation end @@ -151,8 +171,8 @@ def test_convenor_cannot_put_activity_types # The activity type to be replaced activity_type = FactoryBot.create(:activity_type) - - # Data to replace + + # Data to replace data_to_put = { activity_type: FactoryBot.build(:activity_type) } @@ -162,7 +182,7 @@ def test_convenor_cannot_put_activity_types # Update activity_type with data_to_put put_json "/api/activity_types/#{activity_type.id}", data_to_put - + #check if the request get through assert_equal 403, last_response.status end @@ -174,8 +194,8 @@ def test_tutor_cannot_put_activity_types # The activity type to be replaced activity_type = FactoryBot.create(:activity_type) - - # Data to replace + + # Data to replace data_to_put = { activity_type: FactoryBot.build(:activity_type) } @@ -185,7 +205,7 @@ def test_tutor_cannot_put_activity_types # Update activity_type with data_to_put put_json "/api/activity_types/#{activity_type.id}", data_to_put - + #check if the request get through assert_equal 403, last_response.status end @@ -209,11 +229,11 @@ def test_student_cannot_post_activity_type post_json '/api/activity_types', data_to_post # Check if the post does not get through - assert_equal 403, last_response.status + assert_equal 403, last_response.status # Check if the number of activity type is the same as initially assert_equal ActivityType.count, number_of_activity_type - end + end def test_student_cannot_put_activity_type # A user with student role which does not have premision to put a activity type @@ -223,7 +243,7 @@ def test_student_cannot_put_activity_type activity_type = FactoryBot.create(:activity_type) # Number of Activity type before put new activity type - number_of_activity_type = ActivityType.count + number_of_activity_type = ActivityType.count # Create a dummy activity type data_to_put = { @@ -235,9 +255,9 @@ def test_student_cannot_put_activity_type # Perform PUT, but the student user does not have permissions to put it. put_json "/api/activity_types/#{activity_type.id}", data_to_put - + # Check if the put does not get through - assert_equal 403, last_response.status + assert_equal 403, last_response.status # Check if the number of activity type is the same as initially assert_equal ActivityType.count, number_of_activity_type @@ -246,17 +266,17 @@ def test_student_cannot_put_activity_type def test_delete_activity_type # Create a activity type activity_type = FactoryBot.create(:activity_type) - + #number of activity type before delete number_of_ativity_type = ActivityType.count - + # auth_token and username added to header add_auth_header_for(user: User.first) - + # perform the delete - delete_json "/api/activity_types/#{activity_type.id}" - + delete_json "/api/activity_types/#{activity_type.id}" + # Check if the delete get through assert_equal 200, last_response.status @@ -270,18 +290,18 @@ def test_delete_activity_type def test_student_cannot_delete_activity_type # A user with student role which does not have permision to delete a activity type user = FactoryBot.build(:user, :student) - + # create a activity type to delete activity_type = FactoryBot.create (:activity_type) - + # number of activity type before delete number_of_ativity_type = ActivityType.count - + # auth_token and username added to header add_auth_header_for(user: user) # perform the delete - delete_json "/api/activity_types/#{activity_type.id}" + delete_json "/api/activity_types/#{activity_type.id}" # check if the delete does not get through assert_equal 403, last_response.status diff --git a/test/api/campuses_test.rb b/test/api/campuses_test.rb index 638d490df3..d97dfff686 100644 --- a/test/api/campuses_test.rb +++ b/test/api/campuses_test.rb @@ -9,7 +9,19 @@ def app Rails.application end + def test_get_all_campuses_requires_authentication + get '/api/campuses' + assert_equal 401, last_response.status + end + + def test_get_campus_by_id_requires_authentication + campus = FactoryBot.create(:campus, mode: 'timetable') + get "/api/campuses/#{campus.id}" + assert_equal 401, last_response.status + end + def test_get_all_campuses + add_auth_header_for(user: User.first) get '/api/campuses' expected_data = Campus.all assert_equal expected_data.count, last_response_body.count @@ -22,6 +34,7 @@ def test_get_all_campuses def test_get_campuses_by_id campus = FactoryBot.create(:campus, mode: 'timetable') + add_auth_header_for(user: User.first) get "/api/campuses/#{campus.id}" response_keys = %w(name abbreviation) assert_json_matches_model(campus, last_response_body, response_keys) diff --git a/test/api/settings_test.rb b/test/api/settings_test.rb index 2a922d1c93..d98d950b59 100644 --- a/test/api/settings_test.rb +++ b/test/api/settings_test.rb @@ -10,30 +10,43 @@ def app Rails.application end - # Get config details - def test_get_config_details + # Get config details requires authentication + def test_get_config_details_requires_authentication + get '/api/settings' + assert_equal 401, last_response.status + end + + # Get config details when authenticated + def test_get_config_details + add_auth_header_for(user: User.first) expected_product_name = Doubtfire::Application.config.institution[:product_name] - + # Perform the GET get '/api/settings' - # Set returned details returned_mes = last_response_body['externalName'] # Check if the call succeeds assert_equal 200, last_response.status - # Check returned details match as expected + # Check returned details match as expected assert_equal expected_product_name, returned_mes - end + end - # Get privacy policy details + # Get privacy policy requires authentication + def test_get_privacy_policy_requires_authentication + get '/api/settings/privacy' + assert_equal 401, last_response.status + end + + # Get privacy policy details when authenticated def test_get_privacy_policy_details + add_auth_header_for(user: User.first) expected_privacy = Doubtfire::Application.config.institution[:privacy] expected_plagiarism = Doubtfire::Application.config.institution[:plagiarism] - + # Perform the GET get '/api/settings/privacy' - + # Set two returned details returned_privacy = last_response_body['privacy'] returned_plagiarism = last_response_body['plagiarism'] diff --git a/test/api/teaching_period_api_test.rb b/test/api/teaching_period_api_test.rb index 14d9009292..76e4e65422 100644 --- a/test/api/teaching_period_api_test.rb +++ b/test/api/teaching_period_api_test.rb @@ -11,8 +11,21 @@ def app # GET tests # Get teaching period + def test_get_teaching_periods_requires_authentication + get '/api/teaching_periods' + assert_equal 401, last_response.status + end + + def test_get_teaching_period_details_requires_authentication + expected_tp = FactoryBot.create(:teaching_period) + get "/api/teaching_periods/#{expected_tp.id}" + assert_equal 401, last_response.status + end + def test_get_teaching_periods # The GET we are testing + add_auth_header_for(user: User.first) + # Perform the GET get '/api/teaching_periods' expected_data = TeachingPeriod.all @@ -36,6 +49,7 @@ def test_get_a_teaching_periods_details expected_tp = FactoryBot.create(:teaching_period) # perform the GET + add_auth_header_for(user: User.first) get "/api/teaching_periods/#{expected_tp.id}" actual_tp = last_response_body @@ -112,7 +126,7 @@ def test_put_teaching_period assert_equal data_to_put[:teaching_period]['start_date'].to_date, tp_updated.start_date.to_date assert_equal data_to_put[:teaching_period]['end_date'].to_date, tp_updated.end_date.to_date end - + # Put teaching period using unauthorised account def test_student_cannot_put_teaching_period # A user with student role which does not have permission to put a teaching period @@ -124,7 +138,7 @@ def test_student_cannot_put_teaching_period # Number of teaching period before put new teaching period number_of_tp = TeachingPeriod.count - # Create a dummy teaching period + # Create a dummy teaching period data_to_put = { teaching_period: FactoryBot.build(:teaching_period) }