diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-08-18 13:50:51 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-08-18 13:50:51 +0300 |
commit | db384e6b19af03b4c3c82a5760d83a3fd79f7982 (patch) | |
tree | 34beaef37df5f47ccbcf5729d7583aae093cffa0 /app/controllers/concerns | |
parent | 54fd7b1bad233e3944434da91d257fa7f63c3996 (diff) |
Add latest changes from gitlab-org/gitlab@16-3-stable-eev16.3.0-rc42
Diffstat (limited to 'app/controllers/concerns')
-rw-r--r-- | app/controllers/concerns/authenticates_with_two_factor.rb | 8 | ||||
-rw-r--r-- | app/controllers/concerns/enforces_two_factor_authentication.rb | 2 | ||||
-rw-r--r-- | app/controllers/concerns/google_syndication_csp.rb | 21 | ||||
-rw-r--r-- | app/controllers/concerns/integrations/params.rb | 11 | ||||
-rw-r--r-- | app/controllers/concerns/issuable_actions.rb | 1 | ||||
-rw-r--r-- | app/controllers/concerns/kas_cookie.rb | 15 | ||||
-rw-r--r-- | app/controllers/concerns/notes_actions.rb | 7 | ||||
-rw-r--r-- | app/controllers/concerns/onboarding/status.rb | 11 | ||||
-rw-r--r-- | app/controllers/concerns/product_analytics_tracking.rb | 13 | ||||
-rw-r--r-- | app/controllers/concerns/verifies_with_email.rb | 67 |
10 files changed, 127 insertions, 29 deletions
diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb index 9fd86e6a7e0..41a3ee3e1c8 100644 --- a/app/controllers/concerns/authenticates_with_two_factor.rb +++ b/app/controllers/concerns/authenticates_with_two_factor.rb @@ -52,6 +52,14 @@ module AuthenticatesWithTwoFactor elsif user && user.valid_password?(user_params[:password]) prompt_for_two_factor(user) end + rescue ActiveRecord::RecordInvalid => e + # We expect User to always be valid. + # Otherwise, raise internal server error instead of unprocessable entity to improve observability/alerting + if e.record.is_a?(User) + raise e.message + else + raise e + end end private diff --git a/app/controllers/concerns/enforces_two_factor_authentication.rb b/app/controllers/concerns/enforces_two_factor_authentication.rb index 8068913eea2..539feb3cf1c 100644 --- a/app/controllers/concerns/enforces_two_factor_authentication.rb +++ b/app/controllers/concerns/enforces_two_factor_authentication.rb @@ -77,7 +77,7 @@ module EnforcesTwoFactorAuthentication end def two_factor_verifier - @two_factor_verifier ||= Gitlab::Auth::TwoFactorAuthVerifier.new(current_user) # rubocop:disable Gitlab/ModuleWithInstanceVariables + @two_factor_verifier ||= Gitlab::Auth::TwoFactorAuthVerifier.new(current_user, request) # rubocop:disable Gitlab/ModuleWithInstanceVariables end def mfa_help_page_url diff --git a/app/controllers/concerns/google_syndication_csp.rb b/app/controllers/concerns/google_syndication_csp.rb new file mode 100644 index 00000000000..c55debe448b --- /dev/null +++ b/app/controllers/concerns/google_syndication_csp.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module GoogleSyndicationCSP + extend ActiveSupport::Concern + + ALLOWED_SRC = ['*.google.com/pagead/landing', 'pagead2.googlesyndication.com/pagead/landing'].freeze + + included do + content_security_policy do |policy| + next unless helpers.google_tag_manager_enabled? || policy.directives.present? + + connect_src_values = Array.wrap( + policy.directives['connect-src'] || policy.directives['default-src'] + ) + + connect_src_values.concat(ALLOWED_SRC) if helpers.google_tag_manager_enabled? + + policy.connect_src(*connect_src_values.uniq) + end + end +end diff --git a/app/controllers/concerns/integrations/params.rb b/app/controllers/concerns/integrations/params.rb index 53dd06ce638..e344e0dcd8c 100644 --- a/app/controllers/concerns/integrations/params.rb +++ b/app/controllers/concerns/integrations/params.rb @@ -43,6 +43,7 @@ module Integrations :external_wiki_url, :google_iap_service_account_json, :google_iap_audience_client_id, + :google_play_protected_refs, :group_confidential_mention_events, :group_mention_events, :incident_events, @@ -102,10 +103,14 @@ module Integrations param_values = return_value[:integration] if param_values.is_a?(ActionController::Parameters) - if %w[update test].include?(action_name) && integration.chat? && - param_values['webhook'] == BaseChatNotification::SECRET_MASK + if %w[update test].include?(action_name) && integration.chat? + param_values.delete('webhook') if param_values['webhook'] == BaseChatNotification::SECRET_MASK - param_values.delete('webhook') + if integration.try(:mask_configurable_channels?) + integration.event_channel_names.each do |channel| + param_values.delete(channel) if param_values[channel] == BaseChatNotification::SECRET_MASK + end + end end integration.secret_fields.each do |param| diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb index a326fa308ad..1b49cffd408 100644 --- a/app/controllers/concerns/issuable_actions.rb +++ b/app/controllers/concerns/issuable_actions.rb @@ -256,6 +256,7 @@ module IssuableActions :milestone_id, :state_event, :subscription_event, + :confidential, assignee_ids: [], add_label_ids: [], remove_label_ids: [] diff --git a/app/controllers/concerns/kas_cookie.rb b/app/controllers/concerns/kas_cookie.rb index 06a4ee873f8..fafd426da7a 100644 --- a/app/controllers/concerns/kas_cookie.rb +++ b/app/controllers/concerns/kas_cookie.rb @@ -8,11 +8,10 @@ module KasCookie next unless ::Gitlab::Kas::UserAccess.enabled? next unless Settings.gitlab.content_security_policy['enabled'] - kas_url = ::Gitlab::Kas.tunnel_url next if URI(kas_url).host == ::Gitlab.config.gitlab.host # already allowed, no need for exception - kas_url += '/' unless kas_url.end_with?('/') - p.connect_src(*Array.wrap(p.directives['connect-src']), kas_url) + p.connect_src(*Array.wrap(p.directives['connect-src']), kas_ws_url.sub(%r{/?$}, '/')) + p.connect_src(*Array.wrap(p.directives['connect-src']), kas_url.sub(%r{/?$}, '/')) end end @@ -26,4 +25,14 @@ module KasCookie cookies[::Gitlab::Kas::COOKIE_KEY] = cookie_data end + + private + + def kas_url + ::Gitlab::Kas.tunnel_url + end + + def kas_ws_url + ::Gitlab::Kas.tunnel_ws_url + end end diff --git a/app/controllers/concerns/notes_actions.rb b/app/controllers/concerns/notes_actions.rb index 7b2cf131fce..93cf1d15086 100644 --- a/app/controllers/concerns/notes_actions.rb +++ b/app/controllers/concerns/notes_actions.rb @@ -11,6 +11,7 @@ module NotesActions included do before_action :set_polling_interval_header, only: [:index] + before_action :require_last_fetched_at_header!, only: [:index] before_action :require_noteable!, only: [:index, :create] before_action :authorize_admin_note!, only: [:update, :destroy] before_action :note_project, only: [:create] @@ -262,6 +263,12 @@ module NotesActions render_404 unless noteable end + def require_last_fetched_at_header! + return if request.headers['X-Last-Fetched-At'].present? + + render json: { message: 'X-Last-Fetched-At header is required' }, status: :bad_request + end + def last_fetched_at microseconds = request.headers['X-Last-Fetched-At'].to_i diff --git a/app/controllers/concerns/onboarding/status.rb b/app/controllers/concerns/onboarding/status.rb index 986f3f17847..5112ebb3b5d 100644 --- a/app/controllers/concerns/onboarding/status.rb +++ b/app/controllers/concerns/onboarding/status.rb @@ -2,10 +2,17 @@ module Onboarding class Status - def initialize(user) + def self.tracking_label + { free: 'free_registration' } + end + + def initialize(params, session, user) + @params = params + @session = session @user = user end + # overridden in EE def continue_full_onboarding? false end @@ -39,3 +46,5 @@ module Onboarding end end end + +Onboarding::Status.prepend_mod_with('Onboarding::Status') diff --git a/app/controllers/concerns/product_analytics_tracking.rb b/app/controllers/concerns/product_analytics_tracking.rb index 5424354b92c..e148f5d063a 100644 --- a/app/controllers/concerns/product_analytics_tracking.rb +++ b/app/controllers/concerns/product_analytics_tracking.rb @@ -12,6 +12,19 @@ module ProductAnalyticsTracking route_events_to(destinations, name, action, label, &block) end end + + def track_internal_event(*controller_actions, name:, conditions: nil) + custom_conditions = [:trackable_html_request?, *conditions] + + after_action only: controller_actions, if: custom_conditions do + Gitlab::InternalEvents.track_event( + name, + user: current_user, + project: tracking_project_source, + namespace: tracking_namespace_source + ) + end + end end private diff --git a/app/controllers/concerns/verifies_with_email.rb b/app/controllers/concerns/verifies_with_email.rb index 13378800ea9..6affd7bb4cc 100644 --- a/app/controllers/concerns/verifies_with_email.rb +++ b/app/controllers/concerns/verifies_with_email.rb @@ -12,6 +12,7 @@ module VerifiesWithEmail skip_before_action :required_signup_info, only: :successful_verification end + # rubocop:disable Metrics/PerceivedComplexity def verify_with_email return unless user = find_user || find_verification_user @@ -34,18 +35,42 @@ module VerifiesWithEmail # - their account has been locked because of too many failed login attempts, or # - they have logged in before, but never from the current ip address reason = 'sign in from untrusted IP address' unless user.access_locked? - send_verification_instructions(user, reason: reason) + send_verification_instructions(user, reason: reason) unless send_rate_limited?(user) prompt_for_email_verification(user) end end end end + # rubocop:enable Metrics/PerceivedComplexity def resend_verification_code return unless user = find_verification_user - send_verification_instructions(user) - prompt_for_email_verification(user) + if send_rate_limited?(user) + message = format( + s_("IdentityVerification|You've reached the maximum amount of resends. Wait %{interval} and try again."), + interval: rate_limit_interval(:email_verification_code_send) + ) + render json: { status: :failure, message: message } + else + send_verification_instructions(user) + render json: { status: :success } + end + end + + def update_email + return unless user = find_verification_user + + log_verification(user, :email_update_requested) + result = Users::EmailVerification::UpdateEmailService.new(user: user).execute(email: email_params[:email]) + + if result[:status] == :success + send_verification_instructions(user) + else + handle_verification_failure(user, result[:reason], result[:message]) + end + + render json: result end def successful_verification @@ -67,19 +92,7 @@ module VerifiesWithEmail User.find_by_id(session[:verification_user_id]) end - # After successful verification and calling sign_in, devise redirects the - # user to this path. Override it to show the successful verified page. - def after_sign_in_path_for(resource) - if action_name == 'create' && session[:verification_user_id] == resource.id - return users_successful_verification_path - end - - super - end - def send_verification_instructions(user, reason: nil) - return if send_rate_limited?(user) - service = Users::EmailVerification::GenerateTokenService.new(attr: :unlock_token, user: user) raw_token, encrypted_token = service.execute user.unlock_token = encrypted_token @@ -90,7 +103,8 @@ module VerifiesWithEmail def send_verification_instructions_email(user, token) return unless user.can?(:receive_notifications) - Notify.verification_instructions_email(user.email, token: token).deliver_later + email = verification_email(user) + Notify.verification_instructions_email(email, token: token).deliver_later log_verification(user, :instructions_sent) end @@ -101,21 +115,23 @@ module VerifiesWithEmail if result[:status] == :success handle_verification_success(user) + render json: { status: :success, redirect_path: users_successful_verification_path } else handle_verification_failure(user, result[:reason], result[:message]) + render json: result end end def render_sign_in_rate_limited message = format( s_('IdentityVerification|Maximum login attempts exceeded. Wait %{interval} and try again.'), - interval: user_sign_in_interval + interval: rate_limit_interval(:user_sign_in) ) redirect_to new_user_session_path, alert: message end - def user_sign_in_interval - interval_in_seconds = Gitlab::ApplicationRateLimiter.rate_limits[:user_sign_in][:interval] + def rate_limit_interval(rate_limit) + interval_in_seconds = Gitlab::ApplicationRateLimiter.rate_limits[rate_limit][:interval] distance_of_time_in_words(interval_in_seconds) end @@ -126,15 +142,19 @@ module VerifiesWithEmail def handle_verification_failure(user, reason, message) user.errors.add(:base, message) log_verification(user, :failed_attempt, reason) - - prompt_for_email_verification(user) end def handle_verification_success(user) + user.confirm if unconfirmed_verification_email?(user) + user.email_reset_offered_at = Time.current if user.email_reset_offered_at.nil? user.unlock_access! log_verification(user, :successful) sign_in(user) + + log_audit_event(current_user, user, with: authentication_method) + log_user_activity(user) + verify_known_sign_in end def trusted_ip_address?(user) @@ -146,6 +166,7 @@ module VerifiesWithEmail def prompt_for_email_verification(user) session[:verification_user_id] = user.id self.resource = user + add_gon_variables # Necessary to set the sprite_icons path, since we skip the ApplicationController before_filters render 'devise/sessions/email_verification' end @@ -154,6 +175,10 @@ module VerifiesWithEmail params.require(:user).permit(:verification_token) end + def email_params + params.require(:user).permit(:email) + end + def log_verification(user, event, reason = nil) Gitlab::AppLogger.info( message: 'Email Verification', |