diff --git a/app/controllers/api/v2/base_api_controller.rb b/app/controllers/api/v2/base_api_controller.rb index fa4aad2b79..9d83bbe5a7 100644 --- a/app/controllers/api/v2/base_api_controller.rb +++ b/app/controllers/api/v2/base_api_controller.rb @@ -8,6 +8,8 @@ class BaseApiController < ApplicationController # rubocop:todo Style/Documentati # call doorkeeper to authorize the request before_action :doorkeeper_authorize!, except: %i[heartbeat] + # Authorize resource owner, check if the user account associated with the token is active + before_action :authorize_resource_owner, except: %i[heartbeat] # get details of server (e.g. DMPonline) and client app before_action :base_response_content @@ -35,18 +37,30 @@ def me ) end + def render_error(errors:, status:, details: nil) + @payload = { errors: errors, details: details } + render '/api/v2/error', status: status + end + private # define instance variable json and associated getter and setter methods attr_accessor :json + def authorize_resource_owner + return unless doorkeeper_token&.resource_owner_id.present? + + @resource_owner = User.find_by(id: doorkeeper_token.resource_owner_id) + + return if @resource_owner.present? && @resource_owner.active? + + render_error(errors: _('User account has been deactivated.'), status: :unauthorized) + end + def base_response_content @application = ApplicationService.application_name @client = doorkeeper_token&.application @caller = @client&.name || request.remote_ip - return unless doorkeeper_token&.resource_owner_id - - @resource_owner = User.find(doorkeeper_token.resource_owner_id) end def log_access diff --git a/spec/requests/api/v2/base_controller_spec.rb b/spec/requests/api/v2/base_controller_spec.rb new file mode 100644 index 0000000000..92f681c080 --- /dev/null +++ b/spec/requests/api/v2/base_controller_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Api::V2::BaseApiController do + include ApiHelper + + describe 'GET /api/v2/me' do + context 'OAuth (authorization_code grant type) — on behalf of a user' do + before do + @user = create(:user) + @client = create(:oauth_application) + token = mock_authorization_code_token(oauth_application: @client, user: @user).plaintext_token + + @headers = { + Accept: 'application/json', + 'Content-Type': 'application/json', + Authorization: "Bearer #{token}" + } + end + + it 'returns 200 OK and user details when user is active' do + get(api_v2_me_path, headers: @headers) + + expect(response).to have_http_status(:ok) + + json = JSON.parse(response.body) + expect(json['email']).to eq(@user.email) + expect(json['firstname']).to eq(@user.firstname) + expect(json['surname']).to eq(@user.surname) + expect(json['organisation']).to eq(@user.org.name) + end + end + + context 'when no authorization token is provided' do + it 'returns 401 Unauthorized' do + get(api_v2_me_path, headers: { Accept: 'application/json' }) + + expect(response).to have_http_status(:unauthorized) + end + end + end +end