Commit 20b7c5d6 authored by Tan Le's avatar Tan Le Committed by Bob Van Landuyt

Record impersonation details on Auditor

Audit events captured on MR approval rule changes do not include
impersonation details. The legacy service (i.e. `AuditEventService`) is
capable of recording impersonation details. We'd like replicate this
behaviour on the new service `Gitlab::Audit::Auditor`.

Changelog: fixed
EE: true
parent 69b0b5bf
...@@ -2,31 +2,33 @@ ...@@ -2,31 +2,33 @@
module AuditEvents module AuditEvents
class BuildService class BuildService
# Handle missing attributes
MissingAttributeError = Class.new(StandardError) MissingAttributeError = Class.new(StandardError)
# @raise [MissingAttributeError] when required attributes are blank
#
# @return [BuildService]
def initialize(author:, scope:, target:, ip_address:, message:) def initialize(author:, scope:, target:, ip_address:, message:)
@author = author raise MissingAttributeError if missing_attribute?(author, scope, target, ip_address, message)
@author = build_author(author)
@scope = scope @scope = scope
@target = target @target = target
@ip_address = ip_address @ip_address = ip_address
@message = message @message = build_message(message)
end end
# Create an instance of AuditEvent # Create an instance of AuditEvent
# #
# @raise [MissingAttributeError] when required attributes are blank
#
# @return [AuditEvent] # @return [AuditEvent]
def execute def execute
raise MissingAttributeError if missing_attribute?
AuditEvent.new(payload) AuditEvent.new(payload)
end end
private private
def missing_attribute? def missing_attribute?(author, scope, target, ip_address, message)
@author.blank? || @scope.blank? || @target.blank? || @message.blank? author.blank? || scope.blank? || target.blank? || message.blank?
end end
def payload def payload
...@@ -34,7 +36,8 @@ module AuditEvents ...@@ -34,7 +36,8 @@ module AuditEvents
base_payload.merge( base_payload.merge(
details: base_details_payload.merge( details: base_details_payload.merge(
ip_address: ip_address, ip_address: ip_address,
entity_path: @scope.full_path entity_path: @scope.full_path,
custom_message: @message
), ),
ip_address: ip_address ip_address: ip_address
) )
...@@ -63,6 +66,18 @@ module AuditEvents ...@@ -63,6 +66,18 @@ module AuditEvents
} }
end end
def build_author(author)
author.impersonated? ? ::Gitlab::Audit::ImpersonatedAuthor.new(author) : author
end
def build_message(message)
if License.feature_available?(:admin_audit_log) && @author.impersonated?
"#{message} (by #{@author.impersonated_by})"
else
message
end
end
def ip_address def ip_address
@ip_address.presence || @author.current_sign_in_ip @ip_address.presence || @author.current_sign_in_ip
end end
......
...@@ -23,6 +23,10 @@ module Gitlab ...@@ -23,6 +23,10 @@ module Gitlab
impersonator.name impersonator.name
end end
def impersonated?
true
end
private private
def impersonator def impersonator
......
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe AuditEvents::BuildService do RSpec.describe AuditEvents::BuildService do
let(:author) { build(:author, current_sign_in_ip: '127.0.0.1') } let(:author) { build_stubbed(:author, current_sign_in_ip: '127.0.0.1') }
let(:scope) { build(:group) } let(:scope) { build_stubbed(:group) }
let(:target) { build(:project) } let(:target) { build_stubbed(:project) }
let(:ip_address) { '192.168.8.8' } let(:ip_address) { '192.168.8.8' }
let(:message) { 'Added an interesting field from project Gotham' } let(:message) { 'Added an interesting field from project Gotham' }
...@@ -58,6 +58,29 @@ RSpec.describe AuditEvents::BuildService do ...@@ -58,6 +58,29 @@ RSpec.describe AuditEvents::BuildService do
expect(event.ip_address).to eq(author.current_sign_in_ip) expect(event.ip_address).to eq(author.current_sign_in_ip)
end end
end end
context 'when author is impersonated' do
let(:impersonator) { build_stubbed(:user, name: 'Agent Donald', current_sign_in_ip: '8.8.8.8') }
let(:author) { build_stubbed(:author, impersonator: impersonator) }
it 'sets author to impersonated user', :aggregate_failures do
expect(event.author_id).to eq(author.id)
expect(event.author_name).to eq(author.name)
end
it 'includes impersonator name in message' do
expect(event.details[:custom_message])
.to eq('Added an interesting field from project Gotham (by Agent Donald)')
end
context 'when IP address is not provided' do
let(:ip_address) { nil }
it 'uses impersonator current_sign_in_ip' do
expect(event.ip_address).to eq(impersonator.current_sign_in_ip)
end
end
end
end end
context 'when not licensed' do context 'when not licensed' do
...@@ -86,31 +109,41 @@ RSpec.describe AuditEvents::BuildService do ...@@ -86,31 +109,41 @@ RSpec.describe AuditEvents::BuildService do
expect(event.created_at).to eq(DateTime.current) expect(event.created_at).to eq(DateTime.current)
end end
end end
context 'when author is impersonated' do
let(:impersonator) { build_stubbed(:user, name: 'Agent Donald', current_sign_in_ip: '8.8.8.8') }
let(:author) { build_stubbed(:author, impersonator: impersonator) }
it 'does not includes impersonator name in message' do
expect(event.details[:custom_message])
.to eq('Added an interesting field from project Gotham')
end
end
end end
context 'when attributes are missing' do context 'when attributes are missing' do
context 'when author is missing' do context 'when author is missing' do
let(:author) { nil } let(:author) { nil }
it { expect { event }.to raise_error(described_class::MissingAttributeError) } it { expect { service }.to raise_error(described_class::MissingAttributeError) }
end end
context 'when scope is missing' do context 'when scope is missing' do
let(:scope) { nil } let(:scope) { nil }
it { expect { event }.to raise_error(described_class::MissingAttributeError) } it { expect { service }.to raise_error(described_class::MissingAttributeError) }
end end
context 'when target is missing' do context 'when target is missing' do
let(:target) { nil } let(:target) { nil }
it { expect { event }.to raise_error(described_class::MissingAttributeError) } it { expect { service }.to raise_error(described_class::MissingAttributeError) }
end end
context 'when message is missing' do context 'when message is missing' do
let(:message) { nil } let(:message) { nil }
it { expect { event }.to raise_error(described_class::MissingAttributeError) } it { expect { service }.to raise_error(described_class::MissingAttributeError) }
end end
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment