Add support for JSON logging for audit events
This will add audit_json.log that writes one line per audit event. For
example:
{
"severity":"INFO",
"time":"2018-10-17T17:38:22.523Z",
"author_id":3,
"entity_id":2,
"entity_type":"Project",
"change":"visibility",
"from":"Private",
"to":"Public",
"author_name":"John Doe4",
"target_id":2,
"target_type":"Project",
"target_details":"namespace2/project2"
}
2018-10-18 19:50:21 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
require 'spec_helper'
|
|
|
|
|
2020-06-24 06:09:01 +00:00
|
|
|
RSpec.describe AuditEventService do
|
2020-10-27 06:08:27 +00:00
|
|
|
let_it_be(:project) { create(:project) }
|
|
|
|
let_it_be(:user) { create(:user, :with_sign_ins) }
|
|
|
|
let_it_be(:project_member) { create(:project_member, user: user) }
|
2021-06-29 03:07:32 +00:00
|
|
|
|
Add support for JSON logging for audit events
This will add audit_json.log that writes one line per audit event. For
example:
{
"severity":"INFO",
"time":"2018-10-17T17:38:22.523Z",
"author_id":3,
"entity_id":2,
"entity_type":"Project",
"change":"visibility",
"from":"Private",
"to":"Public",
"author_name":"John Doe4",
"target_id":2,
"target_type":"Project",
"target_details":"namespace2/project2"
}
2018-10-18 19:50:21 +00:00
|
|
|
let(:service) { described_class.new(user, project, { action: :destroy }) }
|
|
|
|
let(:logger) { instance_double(Gitlab::AuditJsonLogger) }
|
|
|
|
|
|
|
|
describe '#security_event' do
|
|
|
|
it 'creates an event and logs to a file' do
|
2019-07-03 22:58:05 +00:00
|
|
|
expect(service).to receive(:file_logger).and_return(logger)
|
Add support for JSON logging for audit events
This will add audit_json.log that writes one line per audit event. For
example:
{
"severity":"INFO",
"time":"2018-10-17T17:38:22.523Z",
"author_id":3,
"entity_id":2,
"entity_type":"Project",
"change":"visibility",
"from":"Private",
"to":"Public",
"author_name":"John Doe4",
"target_id":2,
"target_type":"Project",
"target_details":"namespace2/project2"
}
2018-10-18 19:50:21 +00:00
|
|
|
expect(logger).to receive(:info).with(author_id: user.id,
|
2020-07-07 12:09:16 +00:00
|
|
|
author_name: user.name,
|
Add support for JSON logging for audit events
This will add audit_json.log that writes one line per audit event. For
example:
{
"severity":"INFO",
"time":"2018-10-17T17:38:22.523Z",
"author_id":3,
"entity_id":2,
"entity_type":"Project",
"change":"visibility",
"from":"Private",
"to":"Public",
"author_name":"John Doe4",
"target_id":2,
"target_type":"Project",
"target_details":"namespace2/project2"
}
2018-10-18 19:50:21 +00:00
|
|
|
entity_id: project.id,
|
|
|
|
entity_type: "Project",
|
2022-04-08 15:10:26 +00:00
|
|
|
action: :destroy,
|
|
|
|
created_at: anything)
|
Add support for JSON logging for audit events
This will add audit_json.log that writes one line per audit event. For
example:
{
"severity":"INFO",
"time":"2018-10-17T17:38:22.523Z",
"author_id":3,
"entity_id":2,
"entity_type":"Project",
"change":"visibility",
"from":"Private",
"to":"Public",
"author_name":"John Doe4",
"target_id":2,
"target_type":"Project",
"target_details":"namespace2/project2"
}
2018-10-18 19:50:21 +00:00
|
|
|
|
2020-08-21 09:10:08 +00:00
|
|
|
expect { service.security_event }.to change(AuditEvent, :count).by(1)
|
Add support for JSON logging for audit events
This will add audit_json.log that writes one line per audit event. For
example:
{
"severity":"INFO",
"time":"2018-10-17T17:38:22.523Z",
"author_id":3,
"entity_id":2,
"entity_type":"Project",
"change":"visibility",
"from":"Private",
"to":"Public",
"author_name":"John Doe4",
"target_id":2,
"target_type":"Project",
"target_details":"namespace2/project2"
}
2018-10-18 19:50:21 +00:00
|
|
|
end
|
2019-07-03 22:58:05 +00:00
|
|
|
|
|
|
|
it 'formats from and to fields' do
|
|
|
|
service = described_class.new(
|
|
|
|
user, project,
|
|
|
|
{
|
|
|
|
from: true,
|
|
|
|
to: false,
|
|
|
|
action: :create,
|
|
|
|
target_id: 1
|
|
|
|
})
|
|
|
|
expect(service).to receive(:file_logger).and_return(logger)
|
|
|
|
expect(logger).to receive(:info).with(author_id: user.id,
|
2020-07-07 12:09:16 +00:00
|
|
|
author_name: user.name,
|
2019-07-03 22:58:05 +00:00
|
|
|
entity_type: 'Project',
|
|
|
|
entity_id: project.id,
|
|
|
|
from: 'true',
|
|
|
|
to: 'false',
|
|
|
|
action: :create,
|
2022-04-08 15:10:26 +00:00
|
|
|
target_id: 1,
|
|
|
|
created_at: anything)
|
2019-07-03 22:58:05 +00:00
|
|
|
|
2020-08-21 09:10:08 +00:00
|
|
|
expect { service.security_event }.to change(AuditEvent, :count).by(1)
|
2019-07-03 22:58:05 +00:00
|
|
|
|
2020-08-21 09:10:08 +00:00
|
|
|
details = AuditEvent.last.details
|
2019-07-03 22:58:05 +00:00
|
|
|
expect(details[:from]).to be true
|
|
|
|
expect(details[:to]).to be false
|
|
|
|
expect(details[:action]).to eq(:create)
|
|
|
|
expect(details[:target_id]).to eq(1)
|
|
|
|
end
|
2020-09-18 06:09:31 +00:00
|
|
|
|
2022-04-08 15:10:26 +00:00
|
|
|
context 'when defining created_at manually' do
|
|
|
|
let(:service) { described_class.new(user, project, { action: :destroy }, :database, 3.weeks.ago) }
|
|
|
|
|
|
|
|
it 'is overridden successfully' do
|
|
|
|
freeze_time do
|
|
|
|
expect(service).to receive(:file_logger).and_return(logger)
|
|
|
|
expect(logger).to receive(:info).with(author_id: user.id,
|
|
|
|
author_name: user.name,
|
|
|
|
entity_id: project.id,
|
|
|
|
entity_type: "Project",
|
|
|
|
action: :destroy,
|
|
|
|
created_at: 3.weeks.ago)
|
|
|
|
|
|
|
|
expect { service.security_event }.to change(AuditEvent, :count).by(1)
|
|
|
|
expect(AuditEvent.last.created_at).to eq(3.weeks.ago)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-09-18 06:09:31 +00:00
|
|
|
context 'authentication event' do
|
|
|
|
let(:audit_service) { described_class.new(user, user, with: 'standard') }
|
|
|
|
|
|
|
|
it 'creates an authentication event' do
|
2020-09-24 15:09:51 +00:00
|
|
|
expect(AuthenticationEvent).to receive(:new).with(
|
2022-05-02 15:10:10 +00:00
|
|
|
{
|
|
|
|
user: user,
|
|
|
|
user_name: user.name,
|
|
|
|
ip_address: user.current_sign_in_ip,
|
|
|
|
result: AuthenticationEvent.results[:success],
|
|
|
|
provider: 'standard'
|
|
|
|
}
|
2021-12-21 15:14:09 +00:00
|
|
|
).and_call_original
|
2020-09-18 06:09:31 +00:00
|
|
|
|
|
|
|
audit_service.for_authentication.security_event
|
|
|
|
end
|
2020-09-24 15:09:51 +00:00
|
|
|
|
|
|
|
it 'tracks exceptions when the event cannot be created' do
|
2021-12-21 15:14:09 +00:00
|
|
|
allow_next_instance_of(AuditEvent) do |event|
|
|
|
|
allow(event).to receive(:valid?).and_return(false)
|
|
|
|
end
|
2020-09-24 15:09:51 +00:00
|
|
|
|
|
|
|
expect(Gitlab::ErrorTracking).to(
|
2021-12-21 15:14:09 +00:00
|
|
|
receive(:track_and_raise_for_dev_exception)
|
2020-09-24 15:09:51 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
audit_service.for_authentication.security_event
|
|
|
|
end
|
2020-10-27 06:08:27 +00:00
|
|
|
|
|
|
|
context 'with IP address', :request_store do
|
|
|
|
using RSpec::Parameterized::TableSyntax
|
|
|
|
|
2021-06-29 12:08:48 +00:00
|
|
|
where(:from_context, :from_author_sign_in, :output) do
|
|
|
|
'192.168.0.2' | '192.168.0.3' | '192.168.0.2'
|
|
|
|
nil | '192.168.0.3' | '192.168.0.3'
|
2020-10-27 06:08:27 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
with_them do
|
|
|
|
let(:user) { create(:user, current_sign_in_ip: from_author_sign_in) }
|
2021-06-29 12:08:48 +00:00
|
|
|
let(:audit_service) { described_class.new(user, user, with: 'standard') }
|
2020-10-27 06:08:27 +00:00
|
|
|
|
|
|
|
before do
|
|
|
|
allow(Gitlab::RequestContext.instance).to receive(:client_ip).and_return(from_context)
|
|
|
|
end
|
|
|
|
|
|
|
|
specify do
|
2021-12-21 15:14:09 +00:00
|
|
|
expect(AuthenticationEvent).to receive(:new).with(hash_including(ip_address: output)).and_call_original
|
2020-10-27 06:08:27 +00:00
|
|
|
|
|
|
|
audit_service.for_authentication.security_event
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2020-09-18 06:09:31 +00:00
|
|
|
end
|
Add support for JSON logging for audit events
This will add audit_json.log that writes one line per audit event. For
example:
{
"severity":"INFO",
"time":"2018-10-17T17:38:22.523Z",
"author_id":3,
"entity_id":2,
"entity_type":"Project",
"change":"visibility",
"from":"Private",
"to":"Public",
"author_name":"John Doe4",
"target_id":2,
"target_type":"Project",
"target_details":"namespace2/project2"
}
2018-10-18 19:50:21 +00:00
|
|
|
end
|
2019-08-27 21:50:17 +00:00
|
|
|
|
|
|
|
describe '#log_security_event_to_file' do
|
|
|
|
it 'logs security event to file' do
|
|
|
|
expect(service).to receive(:file_logger).and_return(logger)
|
|
|
|
expect(logger).to receive(:info).with(author_id: user.id,
|
2020-07-07 12:09:16 +00:00
|
|
|
author_name: user.name,
|
2019-08-27 21:50:17 +00:00
|
|
|
entity_type: 'Project',
|
|
|
|
entity_id: project.id,
|
2022-04-08 15:10:26 +00:00
|
|
|
action: :destroy,
|
|
|
|
created_at: anything)
|
2019-08-27 21:50:17 +00:00
|
|
|
|
|
|
|
service.log_security_event_to_file
|
|
|
|
end
|
|
|
|
end
|
Add support for JSON logging for audit events
This will add audit_json.log that writes one line per audit event. For
example:
{
"severity":"INFO",
"time":"2018-10-17T17:38:22.523Z",
"author_id":3,
"entity_id":2,
"entity_type":"Project",
"change":"visibility",
"from":"Private",
"to":"Public",
"author_name":"John Doe4",
"target_id":2,
"target_type":"Project",
"target_details":"namespace2/project2"
}
2018-10-18 19:50:21 +00:00
|
|
|
end
|