From fd533396f4a6b9c7305d5788c5a61598bcc09ff9 Mon Sep 17 00:00:00 2001 From: momo3404 <85097704+momo3404@users.noreply.github.com> Date: Mon, 10 Aug 2026 12:56:53 -0600 Subject: [PATCH 1/3] Add `authorize_resource_owner` to v2 `base_api_controller` - Function checks if resource owner is active and present before authorization, and returns error if not - Move code assigning resource_owner to this new function for better readability --- app/controllers/api/v2/base_api_controller.rb | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/v2/base_api_controller.rb b/app/controllers/api/v2/base_api_controller.rb index fa4aad2b79..47b3bc0d5a 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 @@ -40,13 +42,20 @@ def me # 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 From d23bc06a6d06868d8edccf7b828466416821ebcb Mon Sep 17 00:00:00 2001 From: momo3404 <85097704+momo3404@users.noreply.github.com> Date: Mon, 10 Aug 2026 12:58:40 -0600 Subject: [PATCH 2/3] Create `base_controller_spec` for V2 API --- spec/requests/api/v2/base_controller_spec.rb | 43 ++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 spec/requests/api/v2/base_controller_spec.rb 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 From d78fe3a07b041c2af5122125a278518f01219bf2 Mon Sep 17 00:00:00 2001 From: momo3404 <85097704+momo3404@users.noreply.github.com> Date: Mon, 10 Aug 2026 14:32:13 -0600 Subject: [PATCH 3/3] Add `render_error` to V2 `base_api_controller` --- app/controllers/api/v2/base_api_controller.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/controllers/api/v2/base_api_controller.rb b/app/controllers/api/v2/base_api_controller.rb index 47b3bc0d5a..9d83bbe5a7 100644 --- a/app/controllers/api/v2/base_api_controller.rb +++ b/app/controllers/api/v2/base_api_controller.rb @@ -37,6 +37,11 @@ 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