Commit 97892ff3 authored by Gabriel Mazetto's avatar Gabriel Mazetto

Merge branch 'dblessing-auth-events-usage-ping' into 'master'

Report auth events in manage stage usage ping

See merge request gitlab-org/gitlab!39747
parents 14401fee 9f139538
# frozen_string_literal: true
class AuthenticationEvent < ApplicationRecord
include UsageStatistics
belongs_to :user, optional: true
validates :provider, :user_name, :result, presence: true
......@@ -9,4 +11,11 @@ class AuthenticationEvent < ApplicationRecord
failed: 0,
success: 1
}
scope :for_provider, ->(provider) { where(provider: provider) }
scope :ldap, -> { where('provider LIKE ?', 'ldap%')}
def self.providers
distinct.pluck(:provider)
end
end
---
title: Report auth events in manage stage usage ping
merge_request: 39747
author:
type: added
# frozen_string_literal: true
class AddResultIndexToAuthenticationEvents < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
INDEX_NAME = 'index_authentication_events_on_provider_user_id_created_at'
disable_ddl_transaction!
def up
add_concurrent_index :authentication_events, [:provider, :user_id, :created_at], where: 'result = 1', name: INDEX_NAME
end
def down
remove_concurrent_index_by_name :authentication_events, INDEX_NAME
end
end
aef52404e6ce83d5d4b3de65ad00b665334f5ff2e5b7b6c3c622f79313657f26
\ No newline at end of file
......@@ -19478,6 +19478,8 @@ CREATE UNIQUE INDEX index_atlassian_identities_on_extern_uid ON atlassian_identi
CREATE INDEX index_authentication_events_on_provider ON authentication_events USING btree (provider);
CREATE INDEX index_authentication_events_on_provider_user_id_created_at ON authentication_events USING btree (provider, user_id, created_at) WHERE (result = 1);
CREATE INDEX index_authentication_events_on_user_id ON authentication_events USING btree (user_id);
CREATE INDEX index_award_emoji_on_awardable_type_and_awardable_id ON award_emoji USING btree (awardable_type, awardable_id);
......
......@@ -542,6 +542,7 @@ module Gitlab
groups: distinct_count(::GroupMember.where(time_period), :user_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' },
user_auth_by_provider: distinct_count_user_auth_by_provider(time_period),
projects_imported: {
gitlab_project: projects_imported_count('gitlab_project', time_period),
gitlab: projects_imported_count('gitlab', time_period),
......@@ -813,6 +814,7 @@ module Gitlab
clear_memoization(:approval_merge_request_rule_maximum_id)
clear_memoization(:project_minimum_id)
clear_memoization(:project_maximum_id)
clear_memoization(:auth_providers)
end
# rubocop: disable CodeReuse/ActiveRecord
......@@ -844,6 +846,39 @@ module Gitlab
def projects_imported_count(from, time_period)
distinct_count(::Project.imported_from(from).where(time_period), :creator_id) # rubocop: disable CodeReuse/ActiveRecord
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.success.for_provider(provider).where(time_period), :user_id)
end
if any_ldap_auth_providers?
counts['ldap'] = distinct_count(
::AuthenticationEvent.success.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
......
# 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 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
user_minimum_id user_maximum_id unique_visit_service
deployment_minimum_id deployment_maximum_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|
expect(described_class).to receive(:clear_memoization).with(key)
end
......@@ -167,6 +168,8 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
describe 'usage_activity_by_stage_manage' do
it 'includes accurate usage_activity_by_stage data' do
described_class.clear_memoization(:auth_providers)
stub_config(
omniauth:
{ providers: omniauth_providers }
......@@ -174,21 +177,29 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
for_defined_days_back do
user = create(:user)
user2 = create(:user)
create(:event, author: 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
expect(described_class.usage_activity_by_stage_manage({})).to include(
events: 2,
groups: 2,
users_created: 4,
omniauth_providers: ['google_oauth2']
users_created: 6,
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(
events: 1,
groups: 1,
users_created: 2,
omniauth_providers: ['google_oauth2']
users_created: 3,
omniauth_providers: ['google_oauth2'],
user_auth_by_provider: { 'group_saml' => 1, 'ldap' => 2 }
)
end
......
......@@ -12,4 +12,35 @@ RSpec.describe AuthenticationEvent do
it { is_expected.to validate_presence_of(:user_name) }
it { is_expected.to validate_presence_of(:result) }
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 '.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
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