diff --git a/app/controllers/oauth/authorizations_controller.rb b/app/controllers/oauth/authorizations_controller.rb index 08e38811841f541d53c8de0a65b6600acff8cec8..96b2f399cf21040077ce72b7ba91497323eb8c2d 100644 --- a/app/controllers/oauth/authorizations_controller.rb +++ b/app/controllers/oauth/authorizations_controller.rb @@ -12,6 +12,9 @@ class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController before_action :add_gon_variables before_action :verify_confirmed_email!, :verify_admin_allowed! + # rubocop: disable Rails/LexicallyScopedActionFilter -- :create is defined in Doorkeeper::AuthorizationsController + after_action :audit_oauth_authorization, only: [:create] + # rubocop: enable Rails/LexicallyScopedActionFilter layout 'minimal' @@ -37,6 +40,26 @@ def new private + def audit_oauth_authorization + return unless performed? && (response.successful? || response.redirect?) && pre_auth&.client + + application = pre_auth.client.application + + Gitlab::Audit::Auditor.audit( + name: 'user_authorized_oauth_application', + author: current_user, + scope: current_user, + target: application, + message: 'User authorized an OAuth application.', + additional_details: { + application_name: application.name, + application_id: application.id, + scopes: application.scopes.to_a + }, + ip_address: request.remote_ip + ) + end + # Chrome blocks redirections if the form-action CSP directive is present # and the redirect location's scheme isn't allow-listed # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/form-action diff --git a/config/audit_events/types/user_authorized_oauth_application.yml b/config/audit_events/types/user_authorized_oauth_application.yml new file mode 100644 index 0000000000000000000000000000000000000000..63289211e4b06d41f533d3a77180f8a3ae750c88 --- /dev/null +++ b/config/audit_events/types/user_authorized_oauth_application.yml @@ -0,0 +1,10 @@ +--- +name: user_authorized_oauth_application +description: User authorized an OAuth application +introduced_by_issue: https://gitlab.com/gitlab-org/gitlab/-/issues/514152 +introduced_by_mr: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/179187 +feature_category: authorization +milestone: '17.9' +saved_to_database: true +streamed: true +scope: [User] diff --git a/doc/user/compliance/audit_event_types.md b/doc/user/compliance/audit_event_types.md index bd17586b28877019917aa10e65c089cf4daaa714..696d2448a469674fed66b5fd46389737eddc4e61 100644 --- a/doc/user/compliance/audit_event_types.md +++ b/doc/user/compliance/audit_event_types.md @@ -98,6 +98,7 @@ Audit event types belong to the following product categories. | Type name | Event triggered when | Saved to database | Introduced in | Scope | |:----------|:---------------------|:------------------|:--------------|:------| | [`secure_ci_job_token_policies_updated`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/170930) | Permissions are updated for a CI_JOB_TOKEN scope | **{check-circle}** Yes | GitLab [17.6](https://gitlab.com/gitlab-org/gitlab/-/issues/495144) | Project | +| [`user_authorized_oauth_application`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/179187) | User authorized an OAuth application | **{check-circle}** Yes | GitLab [17.9](https://gitlab.com/gitlab-org/gitlab/-/issues/514152) | User | ### Build artifacts diff --git a/spec/controllers/oauth/authorizations_controller_spec.rb b/spec/controllers/oauth/authorizations_controller_spec.rb index 4c16d26ea6c898db731d0c4622c449e3438d695b..80bbdabe71a58e1a462e72cb597fbe8c9eb51bf1 100644 --- a/spec/controllers/oauth/authorizations_controller_spec.rb +++ b/spec/controllers/oauth/authorizations_controller_spec.rb @@ -383,4 +383,80 @@ expect(controller).to be_a(Gitlab::GonHelper) end end + + describe '#audit_oauth_authorization' do + let(:pre_auth) { instance_double(Doorkeeper::OAuth::PreAuthorization) } + let(:client) { instance_double(Doorkeeper::OAuth::Client) } + + before do + allow(controller).to receive(:pre_auth).and_return(pre_auth) + allow(pre_auth).to receive(:client).and_return(client) + allow(client).to receive(:application).and_return(application) + end + + context 'when response is successful' do + before do + allow(controller).to receive(:performed?).and_return(true) + allow(controller).to receive_message_chain(:response, :successful?).and_return(true) + end + + it 'creates an audit event' do + expect(Gitlab::Audit::Auditor).to receive(:audit).with( + name: 'user_authorized_oauth_application', + author: user, + scope: user, + target: application, + message: 'User authorized an OAuth application.', + additional_details: { + application_name: application.name, + application_id: application.id, + scopes: application.scopes.to_a + }, + ip_address: request.remote_ip + ) + + controller.send(:audit_oauth_authorization) + end + end + + context 'when response is a redirect' do + before do + allow(controller).to receive(:performed?).and_return(true) + allow(controller).to receive_message_chain(:response, :successful?).and_return(false) + allow(controller).to receive_message_chain(:response, :redirect?).and_return(true) + end + + it 'creates an audit event' do + expect(Gitlab::Audit::Auditor).to receive(:audit) + + controller.send(:audit_oauth_authorization) + end + end + + context 'when response is not performed' do + before do + allow(controller).to receive(:performed?).and_return(false) + end + + it 'does not create an audit event' do + expect(Gitlab::Audit::Auditor).not_to receive(:audit) + + controller.send(:audit_oauth_authorization) + end + end + + context 'when response is neither successful nor redirect' do + before do + allow(controller).to receive(:performed?).and_return(true) + allow(controller).to receive_message_chain(:response, :successful?).and_return(false) + allow(controller).to receive_message_chain(:response, :redirect?).and_return(false) + end + + it 'does not create an audit event' do + expect(Gitlab::Audit::Auditor).not_to receive(:audit) + + controller.send(:audit_oauth_authorization) + end + end + end end