Skip to content
Snippets Groups Projects
Verified Commit 266cee9c authored by Drew Blessing's avatar Drew Blessing :red_circle: Committed by Drew Blessing
Browse files

Report auth events in manage stage usage ping

Provide aggregate auth event details in usage ping
to help identify how often particular authentication
methods are being used. This will help inform decision
making about improvements and fixes.
parent c0a5f1c6
No related branches found
No related tags found
No related merge requests found
This commit is part of merge request !39747. Comments created here will be created in the context of that merge request.
# frozen_string_literal: true # frozen_string_literal: true
class AuthenticationEvent < ApplicationRecord class AuthenticationEvent < ApplicationRecord
include UsageStatistics
belongs_to :user, optional: true belongs_to :user, optional: true
validates :provider, :user_name, :result, presence: true validates :ip_address, :provider, :user_name, :result, presence: true
enum result: { enum result: {
failed: 0, failed: 0,
success: 1 success: 1
} }
scope :for_provider, ->(provider) { where(provider: provider) }
scope :successful, -> { where(result: :success) }
scope :ldap, -> { where('provider LIKE ?', 'ldap%')}
def self.providers
distinct.pluck(:provider)
end
end end
---
title: Report auth events in manage stage usage ping
merge_request: 39747
author:
type: added
...@@ -525,6 +525,7 @@ def usage_activity_by_stage_manage(time_period) ...@@ -525,6 +525,7 @@ def usage_activity_by_stage_manage(time_period)
groups: distinct_count(::GroupMember.where(time_period), :user_id), groups: distinct_count(::GroupMember.where(time_period), :user_id),
users_created: count(::User.where(time_period), start: user_minimum_id, finish: user_maximum_id), users_created: count(::User.where(time_period), start: user_minimum_id, finish: user_maximum_id),
omniauth_providers: filtered_omniauth_provider_names.reject { |name| name == 'group_saml' }, omniauth_providers: filtered_omniauth_provider_names.reject { |name| name == 'group_saml' },
user_auth_by_provider: distinct_count_user_auth_by_provider(time_period),
projects_imported: { projects_imported: {
gitlab_project: projects_imported_count('gitlab_project', time_period), gitlab_project: projects_imported_count('gitlab_project', time_period),
gitlab: projects_imported_count('gitlab', time_period), gitlab: projects_imported_count('gitlab', time_period),
...@@ -788,6 +789,7 @@ def clear_memoized ...@@ -788,6 +789,7 @@ def clear_memoized
clear_memoization(:approval_merge_request_rule_maximum_id) clear_memoization(:approval_merge_request_rule_maximum_id)
clear_memoization(:project_minimum_id) clear_memoization(:project_minimum_id)
clear_memoization(:project_maximum_id) clear_memoization(:project_maximum_id)
clear_memoization(:auth_providers)
end end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
...@@ -821,6 +823,39 @@ def deployment_count(relation) ...@@ -821,6 +823,39 @@ def deployment_count(relation)
def projects_imported_count(from, time_period) def projects_imported_count(from, time_period)
distinct_count(::Project.imported_from(from).where(time_period), :creator_id) # rubocop: disable CodeReuse/ActiveRecord distinct_count(::Project.imported_from(from).where(time_period), :creator_id) # rubocop: disable CodeReuse/ActiveRecord
end end
# rubocop:disable CodeReuse/ActiveRecord
def distinct_count_user_auth_by_provider(time_period)
counts = auth_providers_except_ldap.each_with_object({}) do |provider, hash|
hash[provider] = distinct_count(
::AuthenticationEvent.successful.for_provider(provider).where(time_period), :user_id)
end
if any_ldap_auth_providers?
counts['ldap'] = distinct_count(
::AuthenticationEvent.successful.ldap.where(time_period), :user_id
)
end
counts
end
# rubocop:enable CodeReuse/ActiveRecord
# rubocop:disable UsageData/LargeTable
def auth_providers
strong_memoize(:auth_providers) do
::AuthenticationEvent.providers
end
end
# rubocop:enable UsageData/LargeTable
def auth_providers_except_ldap
auth_providers.reject { |provider| provider.starts_with?('ldap') }
end
def any_ldap_auth_providers?
auth_providers.any? { |provider| provider.starts_with?('ldap') }
end
end end
end end
end end
......
# frozen_string_literal: true
FactoryBot.define do
factory :authentication_event do
user
provider { :standard }
user_name { 'Jane Doe' }
ip_address { '127.0.0.1' }
result { :failed }
end
end
...@@ -29,7 +29,8 @@ ...@@ -29,7 +29,8 @@
user_minimum_id user_maximum_id unique_visit_service user_minimum_id user_maximum_id unique_visit_service
deployment_minimum_id deployment_maximum_id deployment_minimum_id deployment_maximum_id
approval_merge_request_rule_minimum_id approval_merge_request_rule_minimum_id
approval_merge_request_rule_maximum_id) approval_merge_request_rule_maximum_id
auth_providers)
values.each do |key| values.each do |key|
expect(described_class).to receive(:clear_memoization).with(key) expect(described_class).to receive(:clear_memoization).with(key)
end end
...@@ -169,6 +170,8 @@ ...@@ -169,6 +170,8 @@
describe 'usage_activity_by_stage_manage' do describe 'usage_activity_by_stage_manage' do
it 'includes accurate usage_activity_by_stage data' do it 'includes accurate usage_activity_by_stage data' do
described_class.clear_memoization(:auth_providers)
stub_config( stub_config(
omniauth: omniauth:
{ providers: omniauth_providers } { providers: omniauth_providers }
...@@ -176,21 +179,29 @@ ...@@ -176,21 +179,29 @@
for_defined_days_back do for_defined_days_back do
user = create(:user) user = create(:user)
user2 = create(:user)
create(:event, author: user) create(:event, author: user)
create(:group_member, user: user) create(:group_member, user: user)
create(:authentication_event, user: user, provider: :ldapmain, result: :success)
create(:authentication_event, user: user2, provider: :ldapsecondary, result: :success)
create(:authentication_event, user: user2, provider: :group_saml, result: :success)
create(:authentication_event, user: user2, provider: :group_saml, result: :success)
create(:authentication_event, user: user, provider: :group_saml, result: :failed)
end end
expect(described_class.usage_activity_by_stage_manage({})).to include( expect(described_class.usage_activity_by_stage_manage({})).to include(
events: 2, events: 2,
groups: 2, groups: 2,
users_created: 4, users_created: 6,
omniauth_providers: ['google_oauth2'] omniauth_providers: ['google_oauth2'],
user_auth_by_provider: { 'group_saml' => 2, 'ldap' => 4 }
) )
expect(described_class.usage_activity_by_stage_manage(described_class.last_28_days_time_period)).to include( expect(described_class.usage_activity_by_stage_manage(described_class.last_28_days_time_period)).to include(
events: 1, events: 1,
groups: 1, groups: 1,
users_created: 2, users_created: 3,
omniauth_providers: ['google_oauth2'] omniauth_providers: ['google_oauth2'],
user_auth_by_provider: { 'group_saml' => 1, 'ldap' => 2 }
) )
end end
......
...@@ -10,6 +10,44 @@ ...@@ -10,6 +10,44 @@
describe 'validations' do describe 'validations' do
it { is_expected.to validate_presence_of(:provider) } it { is_expected.to validate_presence_of(:provider) }
it { is_expected.to validate_presence_of(:user_name) } it { is_expected.to validate_presence_of(:user_name) }
it { is_expected.to validate_presence_of(:ip_address) }
it { is_expected.to validate_presence_of(:result) } it { is_expected.to validate_presence_of(:result) }
end end
describe 'scopes' do
let_it_be(:ldap_event) { create(:authentication_event, provider: :ldapmain, result: :failed) }
let_it_be(:google_oauth2) { create(:authentication_event, provider: :google_oauth2, result: :success) }
describe '.for_provider' do
it 'returns events only for the specified provider' do
expect(described_class.for_provider(:ldapmain)).to match_array ldap_event
end
end
describe '.successful' do
it 'returns events only where success is true' do
expect(described_class.successful).to match_array google_oauth2
end
end
describe '.ldap' do
it 'returns all events for an LDAP provider' do
expect(described_class.ldap).to match_array ldap_event
end
end
end
describe '.providers' do
before do
create(:authentication_event, provider: :ldapmain)
create(:authentication_event, provider: :google_oauth2)
create(:authentication_event, provider: :standard)
create(:authentication_event, provider: :standard)
create(:authentication_event, provider: :standard)
end
it 'returns an array of distinct providers' do
expect(described_class.providers).to match_array %w(ldapmain google_oauth2 standard)
end
end
end end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment