Commit b4ca26d7 authored by mc_rocha's avatar mc_rocha

Move arkose settings into database

This MR adds the arkose settings to the Applications settings

Changelog: added
MR: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/84415
parent 0c57267a
...@@ -621,6 +621,8 @@ class ApplicationSetting < ApplicationRecord ...@@ -621,6 +621,8 @@ class ApplicationSetting < ApplicationRecord
attr_encrypted :external_pipeline_validation_service_token, encryption_options_base_32_aes_256_gcm attr_encrypted :external_pipeline_validation_service_token, encryption_options_base_32_aes_256_gcm
attr_encrypted :mailgun_signing_key, encryption_options_base_32_aes_256_gcm.merge(encode: false) attr_encrypted :mailgun_signing_key, encryption_options_base_32_aes_256_gcm.merge(encode: false)
attr_encrypted :database_grafana_api_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false) attr_encrypted :database_grafana_api_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :arkose_labs_public_api_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :arkose_labs_private_api_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
validates :disable_feed_token, validates :disable_feed_token,
inclusion: { in: [true, false], message: _('must be a boolean value') } inclusion: { in: [true, false], message: _('must be a boolean value') }
......
...@@ -1001,14 +1001,6 @@ Settings['prometheus'] ||= Settingslogic.new({}) ...@@ -1001,14 +1001,6 @@ Settings['prometheus'] ||= Settingslogic.new({})
Settings.prometheus['enabled'] ||= false Settings.prometheus['enabled'] ||= false
Settings.prometheus['server_address'] ||= nil Settings.prometheus['server_address'] ||= nil
#
# Arkose settings
#
Settings['arkose'] ||= Settingslogic.new({})
Settings.arkose['public_key'] ||= ENV['ARKOSE_LABS_PUBLIC_KEY']
Settings.arkose['private_key'] ||= ENV['ARKOSE_LABS_PRIVATE_KEY']
Settings.arkose['verify_url'] ||= ENV['ARKOSE_LABS_VERIFY_URL']
# #
# Shutdown settings # Shutdown settings
# #
......
# frozen_string_literal: true
class AddArkoseSettingsToApplicationSettings < Gitlab::Database::Migration[1.0]
# rubocop:disable Migration/AddLimitToTextColumns
# limit is added in 20220405203843_add_text_limit_to_arkose_verify_url_application_settings.rb
def up
add_column :application_settings, :encrypted_arkose_labs_public_api_key, :binary
add_column :application_settings, :encrypted_arkose_labs_public_api_key_iv, :binary
add_column :application_settings, :encrypted_arkose_labs_private_api_key, :binary
add_column :application_settings, :encrypted_arkose_labs_private_api_key_iv, :binary
add_column :application_settings, :arkose_labs_verify_api_url, :text
end
# rubocop:enable Migration/AddLimitToTextColumns
def down
remove_column :application_settings, :encrypted_arkose_labs_public_api_key
remove_column :application_settings, :encrypted_arkose_labs_public_api_key_iv
remove_column :application_settings, :encrypted_arkose_labs_private_api_key
remove_column :application_settings, :encrypted_arkose_labs_private_api_key_iv
remove_column :application_settings, :arkose_labs_verify_api_url
end
end
# frozen_string_literal: true
class AddTextLimitToArkoseVerifyUrlApplicationSettings < Gitlab::Database::Migration[1.0]
disable_ddl_transaction!
def up
add_text_limit :application_settings, :arkose_labs_verify_api_url, 255
end
def down
remove_text_limit :application_settings, :arkose_labs_verify_api_url
end
end
0835eaaf3e355f98783a11098a37b894b581176d98c39cdfd3be44e2447fe232
\ No newline at end of file
ac1892c5f2131e41774cadc8799cb5fb2c7d36fe567850fc1251a23c2d454695
\ No newline at end of file
...@@ -11265,6 +11265,11 @@ CREATE TABLE application_settings ( ...@@ -11265,6 +11265,11 @@ CREATE TABLE application_settings (
database_grafana_api_url text, database_grafana_api_url text,
database_grafana_tag text, database_grafana_tag text,
public_runner_releases_url text DEFAULT 'https://gitlab.com/api/v4/projects/gitlab-org%2Fgitlab-runner/releases'::text NOT NULL, public_runner_releases_url text DEFAULT 'https://gitlab.com/api/v4/projects/gitlab-org%2Fgitlab-runner/releases'::text NOT NULL,
encrypted_arkose_labs_public_api_key bytea,
encrypted_arkose_labs_public_api_key_iv bytea,
encrypted_arkose_labs_private_api_key bytea,
encrypted_arkose_labs_private_api_key_iv bytea,
arkose_labs_verify_api_url text,
delete_inactive_projects boolean DEFAULT false NOT NULL, delete_inactive_projects boolean DEFAULT false NOT NULL,
inactive_projects_delete_after_months integer DEFAULT 2 NOT NULL, inactive_projects_delete_after_months integer DEFAULT 2 NOT NULL,
inactive_projects_min_size_mb integer DEFAULT 0 NOT NULL, inactive_projects_min_size_mb integer DEFAULT 0 NOT NULL,
...@@ -11299,7 +11304,8 @@ CREATE TABLE application_settings ( ...@@ -11299,7 +11304,8 @@ CREATE TABLE application_settings (
CONSTRAINT check_d820146492 CHECK ((char_length(spam_check_endpoint_url) <= 255)), CONSTRAINT check_d820146492 CHECK ((char_length(spam_check_endpoint_url) <= 255)),
CONSTRAINT check_e5024c8801 CHECK ((char_length(elasticsearch_username) <= 255)), CONSTRAINT check_e5024c8801 CHECK ((char_length(elasticsearch_username) <= 255)),
CONSTRAINT check_e5aba18f02 CHECK ((char_length(container_registry_version) <= 255)), CONSTRAINT check_e5aba18f02 CHECK ((char_length(container_registry_version) <= 255)),
CONSTRAINT check_ef6176834f CHECK ((char_length(encrypted_cloud_license_auth_token_iv) <= 255)) CONSTRAINT check_ef6176834f CHECK ((char_length(encrypted_cloud_license_auth_token_iv) <= 255)),
CONSTRAINT check_f6563bc000 CHECK ((char_length(arkose_labs_verify_api_url) <= 255))
); );
COMMENT ON COLUMN application_settings.content_validation_endpoint_url IS 'JiHu-specific column'; COMMENT ON COLUMN application_settings.content_validation_endpoint_url IS 'JiHu-specific column';
...@@ -24,7 +24,7 @@ module EE ...@@ -24,7 +24,7 @@ module EE
redirect_to oauth_geo_auth_url(host: current_node_uri.host, port: current_node_uri.port, state: state) redirect_to oauth_geo_auth_url(host: current_node_uri.host, port: current_node_uri.port, state: state)
else else
if ::Feature.enabled?(:arkose_labs_login_challenge) if ::Feature.enabled?(:arkose_labs_login_challenge)
@arkose_labs_public_key ||= Settings.arkose['public_key'] # rubocop:disable Gitlab/ModuleWithInstanceVariables @arkose_labs_public_key ||= arkose_public_api_key # rubocop:disable Gitlab/ModuleWithInstanceVariables
end end
super super
...@@ -125,5 +125,9 @@ module EE ...@@ -125,5 +125,9 @@ module EE
respond_with_navigational(resource) { render :new } respond_with_navigational(resource) { render :new }
end end
def arkose_public_api_key
::Gitlab::CurrentSettings.arkose_labs_public_api_key || ENV['ARKOSE_LABS_PUBLIC_KEY']
end
end end
end end
...@@ -12,7 +12,7 @@ module Arkose ...@@ -12,7 +12,7 @@ module Arkose
end end
def execute def execute
response = Gitlab::HTTP.perform_request(Net::HTTP::Post, VERIFY_URL, body: body).parsed_response response = Gitlab::HTTP.perform_request(Net::HTTP::Post, arkose_verify_url, body: body).parsed_response
logger.info(build_message(response)) logger.info(build_message(response))
return false if invalid_token(response) return false if invalid_token(response)
...@@ -80,7 +80,7 @@ module Arkose ...@@ -80,7 +80,7 @@ module Arkose
def body def body
{ {
private_key: Settings.arkose['private_key'], private_key: arkose_private_api_key,
session_token: session_token, session_token: session_token,
log_data: user.id log_data: user.id
} }
...@@ -132,5 +132,13 @@ module Arkose ...@@ -132,5 +132,13 @@ module Arkose
telltale_list = response&.dig('session_details', 'telltale_list') || [] telltale_list = response&.dig('session_details', 'telltale_list') || []
telltale_list.include?(ALLOWLIST_TELLTALE) telltale_list.include?(ALLOWLIST_TELLTALE)
end end
def arkose_private_api_key
Gitlab::CurrentSettings.arkose_labs_private_api_key || ENV['ARKOSE_LABS_PRIVATE_KEY']
end
def arkose_verify_url
Gitlab::CurrentSettings.arkose_labs_verify_api_url || VERIFY_URL
end
end end
end end
...@@ -6,8 +6,11 @@ RSpec.describe SessionsController, :geo do ...@@ -6,8 +6,11 @@ RSpec.describe SessionsController, :geo do
include DeviseHelpers include DeviseHelpers
include EE::GeoHelpers include EE::GeoHelpers
let(:arkose_labs_public_api_key) { 'foo' }
before do before do
set_devise_mapping(context: @request) set_devise_mapping(context: @request)
stub_application_setting(arkose_labs_public_api_key: arkose_labs_public_api_key)
end end
describe '#new' do describe '#new' do
......
...@@ -8,108 +8,130 @@ RSpec.describe Arkose::UserVerificationService do ...@@ -8,108 +8,130 @@ RSpec.describe Arkose::UserVerificationService do
let(:service) { Arkose::UserVerificationService.new(session_token: session_token, user: user) } let(:service) { Arkose::UserVerificationService.new(session_token: session_token, user: user) }
let(:response) { instance_double(HTTParty::Response, success?: true, code: 200, parsed_response: arkose_ec_response) } let(:response) { instance_double(HTTParty::Response, success?: true, code: 200, parsed_response: arkose_ec_response) }
let(:arkose_labs_private_api_key) { 'foo' }
let(:arkose_labs_verify_api_url) { 'https://bar' }
subject { service.execute } subject { service.execute }
describe '#execute' do describe '#execute' do
context 'when the user did not solve the challenge' do shared_examples_for 'interacting with Arkose verify API' do
let(:arkose_ec_response) { Gitlab::Json.parse(File.read(Rails.root.join('ee/spec/fixtures/arkose/failed_ec_response.json'))) } context 'when the user did not solve the challenge' do
let(:arkose_ec_response) { Gitlab::Json.parse(File.read(Rails.root.join('ee/spec/fixtures/arkose/failed_ec_response.json'))) }
it 'returns false' do it 'returns false' do
allow(Gitlab::HTTP).to receive(:perform_request).and_return(response) allow(Gitlab::HTTP).to receive(:perform_request).and_return(response)
expect(subject).to be_falsey expect(subject).to be_falsey
end
end end
end
context 'when feature arkose_labs_prevent_login is enabled' do
context 'when the user solved the challenge' do
context 'when the risk score is not high' do
let(:arkose_ec_response) { Gitlab::Json.parse(File.read(Rails.root.join('ee/spec/fixtures/arkose/successfully_solved_ec_response.json'))) }
it 'returns true' do
allow(Gitlab::HTTP).to receive(:perform_request).and_return(response)
expect(subject).to be_truthy
end
it 'adds arkose data to custom attributes' do context 'when feature arkose_labs_prevent_login is enabled' do
allow(Gitlab::HTTP).to receive(:perform_request).and_return(response) context 'when the user solved the challenge' do
subject context 'when the risk score is not high' do
expect(user.custom_attributes.count).to eq(4) let(:arkose_ec_response) { Gitlab::Json.parse(File.read(Rails.root.join('ee/spec/fixtures/arkose/successfully_solved_ec_response.json'))) }
expect(user.custom_attributes.find_by(key: 'arkose_session').value).to eq('22612c147bb418c8.2570749403') it 'returns true' do
expect(user.custom_attributes.find_by(key: 'arkose_risk_band').value).to eq('Low') allow(Gitlab::HTTP).to receive(:perform_request).and_return(response)
expect(user.custom_attributes.find_by(key: 'arkose_global_score').value).to eq('0') expect(subject).to be_truthy
expect(user.custom_attributes.find_by(key: 'arkose_custom_score').value).to eq('0') end
end
it 'logs Arkose verify response' do it 'adds arkose data to custom attributes' do
allow(Gitlab::HTTP).to receive(:perform_request).and_return(response) allow(Gitlab::HTTP).to receive(:perform_request).and_return(response)
allow(Gitlab::AppLogger).to receive(:info) subject
allow(Gitlab::ApplicationContext).to receive(:current).and_return({ 'correlation_id': 'be025cf83013ac4f52ffd2bf712b11a2' }) expect(user.custom_attributes.count).to eq(4)
subject
expect(Gitlab::AppLogger).to have_received(:info).with(correlation_id: 'be025cf83013ac4f52ffd2bf712b11a2',
message: 'Arkose verify response',
response: arkose_ec_response,
username: user.username,
'arkose.session_id': '22612c147bb418c8.2570749403',
'arkose.global_score': '0',
'arkose.global_telltale_list': [],
'arkose.custom_score': '0',
'arkose.custom_telltale_list': [],
'arkose.risk_band': 'Low',
'arkose.risk_category': 'NO-THREAT')
end
context 'when the risk score is high' do expect(user.custom_attributes.find_by(key: 'arkose_session').value).to eq('22612c147bb418c8.2570749403')
let(:arkose_ec_response) { Gitlab::Json.parse(File.read(Rails.root.join('ee/spec/fixtures/arkose/successfully_solved_ec_response_high_risk.json'))) } expect(user.custom_attributes.find_by(key: 'arkose_risk_band').value).to eq('Low')
expect(user.custom_attributes.find_by(key: 'arkose_global_score').value).to eq('0')
expect(user.custom_attributes.find_by(key: 'arkose_custom_score').value).to eq('0')
end
it 'returns false' do it 'logs Arkose verify response' do
allow(Gitlab::HTTP).to receive(:perform_request).and_return(response) allow(Gitlab::HTTP).to receive(:perform_request).and_return(response)
expect(subject).to be_falsey allow(Gitlab::AppLogger).to receive(:info)
allow(Gitlab::ApplicationContext).to receive(:current).and_return({ 'correlation_id': 'be025cf83013ac4f52ffd2bf712b11a2' })
subject
expect(Gitlab::AppLogger).to have_received(:info).with(correlation_id: 'be025cf83013ac4f52ffd2bf712b11a2',
message: 'Arkose verify response',
response: arkose_ec_response,
username: user.username,
'arkose.session_id': '22612c147bb418c8.2570749403',
'arkose.global_score': '0',
'arkose.global_telltale_list': [],
'arkose.custom_score': '0',
'arkose.custom_telltale_list': [],
'arkose.risk_band': 'Low',
'arkose.risk_category': 'NO-THREAT')
end end
context 'when the session is allowlisted' do context 'when the risk score is high' do
before do let(:arkose_ec_response) { Gitlab::Json.parse(File.read(Rails.root.join('ee/spec/fixtures/arkose/successfully_solved_ec_response_high_risk.json'))) }
arkose_ec_response['session_details']['telltale_list'].push(Arkose::UserVerificationService::ALLOWLIST_TELLTALE)
end
it 'returns true' do it 'returns false' do
allow(Gitlab::HTTP).to receive(:perform_request).and_return(response) allow(Gitlab::HTTP).to receive(:perform_request).and_return(response)
expect(subject).to be_truthy expect(subject).to be_falsey
end
context 'when the session is allowlisted' do
before do
arkose_ec_response['session_details']['telltale_list'].push(Arkose::UserVerificationService::ALLOWLIST_TELLTALE)
end
it 'returns true' do
allow(Gitlab::HTTP).to receive(:perform_request).and_return(response)
expect(subject).to be_truthy
end
end end
end end
end end
end end
end
context 'when the response does not include the risk session' do context 'when the response does not include the risk session' do
context 'when the user solved the challenge' do context 'when the user solved the challenge' do
let(:arkose_ec_response) { Gitlab::Json.parse(File.read(Rails.root.join('ee/spec/fixtures/arkose/successfully_solved_ec_response_without_session_risk.json'))) } let(:arkose_ec_response) { Gitlab::Json.parse(File.read(Rails.root.join('ee/spec/fixtures/arkose/successfully_solved_ec_response_without_session_risk.json'))) }
it 'returns true' do it 'returns true' do
allow(Gitlab::HTTP).to receive(:perform_request).and_return(response) allow(Gitlab::HTTP).to receive(:perform_request).and_return(response)
expect(subject).to be_truthy expect(subject).to be_truthy
end
end end
end
context 'when the user did not solve the challenge' do context 'when the user did not solve the challenge' do
let(:arkose_ec_response) { Gitlab::Json.parse(File.read(Rails.root.join('ee/spec/fixtures/arkose/failed_ec_response_without_risk_session.json'))) } let(:arkose_ec_response) { Gitlab::Json.parse(File.read(Rails.root.join('ee/spec/fixtures/arkose/failed_ec_response_without_risk_session.json'))) }
it 'returns false' do it 'returns false' do
allow(Gitlab::HTTP).to receive(:perform_request).and_return(response) allow(Gitlab::HTTP).to receive(:perform_request).and_return(response)
expect(subject).to be_falsey expect(subject).to be_falsey
end
end end
end end
end end
context 'when an error occurs during the Arkose request' do
it 'returns true' do
allow(Gitlab::HTTP).to receive(:perform_request).and_raise(Gitlab::HTTP::BlockedUrlError)
expect(subject).to be_truthy
end
end
end
context 'when Arkose is configured using application settings' do
before do
stub_application_setting(arkose_labs_private_api_key: arkose_labs_private_api_key)
stub_application_setting(arkose_labs_verify_api_url: arkose_labs_verify_api_url)
end
it_behaves_like 'interacting with Arkose verify API'
end end
context 'when an error occurs during the Arkose request' do context 'when Arkose application settings are not present, fallback to environment variables' do
it 'returns true' do before do
allow(Gitlab::HTTP).to receive(:perform_request).and_raise(Gitlab::HTTP::BlockedUrlError) stub_env('ARKOSE_LABS_PRIVATE_KEY': arkose_labs_private_api_key)
expect(subject).to be_truthy stub_env('ARKOSE_LABS_VERIFY_URL': arkose_labs_verify_api_url)
end end
it_behaves_like 'interacting with Arkose verify API'
end end
context 'when feature arkose_labs_prevent_login is disabled' do context 'when feature arkose_labs_prevent_login is disabled' do
......
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