feat: add audit trail for sign_in and sign_out (#7158)
* feat: add audit_trail for sign_in event * chore: ignore unrelated User model columns for auditing * chore: fix prepend call for webhook/automation rule * chore: add spec for sign_in event * chore: refactor sign_in auditlog method to enterprise namespace * feat: add sign_out audit trail * feat: review comments
This commit is contained in:
@@ -784,8 +784,8 @@ GEM
|
|||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
arm64-darwin-20
|
arm64-darwin-20
|
||||||
arm64-darwin-22
|
|
||||||
arm64-darwin-21
|
arm64-darwin-21
|
||||||
|
arm64-darwin-22
|
||||||
ruby
|
ruby
|
||||||
x86_64-darwin-18
|
x86_64-darwin-18
|
||||||
x86_64-darwin-20
|
x86_64-darwin-20
|
||||||
|
|||||||
@@ -37,3 +37,5 @@ class DeviseOverrides::SessionsController < DeviseTokenAuth::SessionsController
|
|||||||
@resource = user if user&.valid_sso_auth_token?(params[:sso_auth_token])
|
@resource = user if user&.valid_sso_auth_token?(params[:sso_auth_token])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
DeviseOverrides::SessionsController.prepend_mod_with('DeviseOverrides::SessionsController')
|
||||||
|
|||||||
@@ -77,4 +77,4 @@ class AutomationRule < ApplicationRecord
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
AutomationRule.include_mod_with('Audit::Inbox')
|
AutomationRule.include_mod_with('Audit::AutomationRule')
|
||||||
|
|||||||
@@ -166,3 +166,5 @@ class User < ApplicationRecord
|
|||||||
macros.personal.destroy_all
|
macros.personal.destroy_all
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
User.include_mod_with('Audit::User')
|
||||||
|
|||||||
@@ -38,4 +38,4 @@ class Webhook < ApplicationRecord
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Webhook.include_mod_with('Audit::Inbox')
|
Webhook.include_mod_with('Audit::Webhook')
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
module Enterprise::DeviseOverrides::SessionsController
|
||||||
|
def render_create_success
|
||||||
|
create_audit_event('sign_in')
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
create_audit_event('sign_out')
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_audit_event(action)
|
||||||
|
return unless @resource
|
||||||
|
|
||||||
|
associated_type = 'Account'
|
||||||
|
@resource.accounts.each do |account|
|
||||||
|
@resource.audits.create(
|
||||||
|
action: action,
|
||||||
|
user_id: @resource.id,
|
||||||
|
associated_id: account.id,
|
||||||
|
associated_type: associated_type
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
13
enterprise/app/models/enterprise/audit/user.rb
Normal file
13
enterprise/app/models/enterprise/audit/user.rb
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
module Enterprise::Audit::User
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
audited only: [
|
||||||
|
:availability,
|
||||||
|
:display_name,
|
||||||
|
:email,
|
||||||
|
:name
|
||||||
|
]
|
||||||
|
audited associated_with: :account
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe 'Enterprise Audit API', type: :request do
|
||||||
|
let!(:account) { create(:account) }
|
||||||
|
let!(:user) { create(:user, password: 'Password1!', account: account) }
|
||||||
|
|
||||||
|
describe 'POST /sign_in' do
|
||||||
|
it 'creates a sign_in audit event wwith valid credentials' do
|
||||||
|
params = { email: user.email, password: 'Password1!' }
|
||||||
|
|
||||||
|
expect do
|
||||||
|
post new_user_session_url,
|
||||||
|
params: params,
|
||||||
|
as: :json
|
||||||
|
end.to change(Enterprise::AuditLog, :count).by(1)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
expect(response.body).to include(user.email)
|
||||||
|
|
||||||
|
# Check if the sign_in event is created
|
||||||
|
user.reload
|
||||||
|
expect(user.audits.last.action).to eq('sign_in')
|
||||||
|
expect(user.audits.last.associated_id).to eq(account.id)
|
||||||
|
expect(user.audits.last.associated_type).to eq('Account')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'will not create a sign_in audit event with invalid credentials' do
|
||||||
|
params = { email: user.email, password: 'invalid' }
|
||||||
|
expect do
|
||||||
|
post new_user_session_url,
|
||||||
|
params: params,
|
||||||
|
as: :json
|
||||||
|
end.not_to change(Enterprise::AuditLog, :count)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'DELETE /sign_out' do
|
||||||
|
context 'when it is an authenticated user' do
|
||||||
|
it 'signs out the user and creates an audit event' do
|
||||||
|
expect do
|
||||||
|
delete '/auth/sign_out', headers: user.create_new_auth_token
|
||||||
|
end.to change(Enterprise::AuditLog, :count).by(1)
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
|
||||||
|
user.reload
|
||||||
|
|
||||||
|
expect(user.audits.last.action).to eq('sign_out')
|
||||||
|
expect(user.audits.last.associated_id).to eq(account.id)
|
||||||
|
expect(user.audits.last.associated_type).to eq('Account')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user