Skip to content
Snippets Groups Projects
application_controller.rb 8.99 KiB
Newer Older
  • Learn to ignore specific revisions
  • Jared Szechy's avatar
    Jared Szechy committed
    require 'fogbugz'
    
    class ApplicationController < ActionController::Base
    
      include Gitlab::CurrentSettings
    
      include Gitlab::GonHelper
    
      include GitlabRoutingHelper
      include PageLayoutHelper
    
      include SentryHelper
    
      include WorkhorseHelper
    
      before_action :authenticate_user_from_private_token!
    
      before_action :authenticate_user!
    
    tduehr's avatar
    tduehr committed
      before_action :validate_user_service_ticket!
    
      before_action :check_password_expiration
    
      before_action :check_2fa_requirement
    
      before_action :ldap_security_check
    
      before_action :sentry_context
    
      before_action :default_headers
      before_action :add_gon_variables
      before_action :configure_permitted_parameters, if: :devise_controller?
      before_action :require_email, unless: :devise_controller?
    
      protect_from_forgery with: :exception
    
      helper_method :can?, :current_application_settings
    
      helper_method :import_sources_enabled?, :github_import_enabled?, :gitea_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :google_code_import_enabled?, :fogbugz_import_enabled?, :git_import_enabled?, :gitlab_project_import_enabled?
    
    gitlabhq's avatar
    gitlabhq committed
    
    
      rescue_from Encoding::CompatibilityError do |exception|
    
    Riyad Preukschas's avatar
    Riyad Preukschas committed
        log_exception(exception)
    
        render "errors/encoding", layout: "errors", status: 500
    
      rescue_from ActiveRecord::RecordNotFound do |exception|
    
    Riyad Preukschas's avatar
    Riyad Preukschas committed
        log_exception(exception)
    
        render_404
    
    gitlabhq's avatar
    gitlabhq committed
      end
    
    
      rescue_from Gitlab::Access::AccessDeniedError do |exception|
        render_403
      end
    
    
      def redirect_back_or_default(default: root_path, options: {})
        redirect_to request.referer.present? ? :back : default, options
      end
    
    
      def route_not_found
        if current_user
          not_found
        else
          redirect_to new_user_session_path
        end
      end
    
    
    Nihad Abbasov's avatar
    Nihad Abbasov committed
      protected
    
    gitlabhq's avatar
    gitlabhq committed
    
    
      # This filter handles both private tokens and personal access tokens
      def authenticate_user_from_private_token!
        token_string = params[:private_token].presence || request.headers['PRIVATE-TOKEN'].presence
        user = User.find_by_authentication_token(token_string) || User.find_by_personal_access_token(token_string)
    
    
        if user
          # Notice we are passing store false, so the user is not
          # actually stored in the session and a token is needed
          # for every request. If you want the token to work as a
          # sign in token, you can simply remove store: false.
          sign_in user, store: false
        end
      end
    
    
      def authenticate_user!(*args)
    
        if redirect_to_home_page_url?
    
    Douwe Maan's avatar
    Douwe Maan committed
          return redirect_to current_application_settings.home_page_url
    
    Riyad Preukschas's avatar
    Riyad Preukschas committed
      def log_exception(exception)
        application_trace = ActionDispatch::ExceptionWrapper.new(env, exception).application_trace
        application_trace.map!{ |t| "  #{t}\n" }
        logger.error "\n#{exception.class.name} (#{exception.message}):\n#{application_trace.join}"
      end
    
    
      def after_sign_in_path_for(resource)
    
        stored_location_for(:redirect) || stored_location_for(resource) || root_path
    
    randx's avatar
    randx committed
      end
    
    
      def after_sign_out_path_for(resource)
    
        current_application_settings.after_sign_out_path.presence || new_user_session_path
    
    gitlabhq's avatar
    gitlabhq committed
      def can?(object, action, subject)
    
        Ability.allowed?(object, action, subject)
    
    gitlabhq's avatar
    gitlabhq committed
      end
    
    
    gitlabhq's avatar
    gitlabhq committed
      def access_denied!
    
        render "errors/access_denied", layout: "errors", status: 404
    
        render "errors/git_not_found.html", layout: "errors", status: 404
    
    gitlabhq's avatar
    gitlabhq committed
      end
    
    
      def render_403
        head :forbidden
    
    gitlabhq's avatar
    gitlabhq committed
      end
    
    gitlabhq's avatar
    gitlabhq committed
    
    
      def render_404
    
        respond_to do |format|
    
    Sean McGivern's avatar
    Sean McGivern committed
          format.html do
    
            render file: Rails.root.join("public", "404"), layout: false, status: "404"
          end
    
    Sean McGivern's avatar
    Sean McGivern committed
          format.any { head :not_found }
    
      def no_cache_headers
        response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
        response.headers["Pragma"] = "no-cache"
        response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
      end
    
      def default_headers
        headers['X-Frame-Options'] = 'DENY'
        headers['X-XSS-Protection'] = '1; mode=block'
    
        headers['X-UA-Compatible'] = 'IE=edge'
    
        headers['X-Content-Type-Options'] = 'nosniff'
    
        # Enabling HSTS for non-standard ports would send clients to the wrong port
    
    Douwe Maan's avatar
    Douwe Maan committed
        if Gitlab.config.gitlab.https && Gitlab.config.gitlab.port == 443
    
          headers['Strict-Transport-Security'] = 'max-age=31536000'
        end
    
    tduehr's avatar
    tduehr committed
      def validate_user_service_ticket!
        return unless signed_in? && session[:service_tickets]
    
        valid = session[:service_tickets].all? do |provider, ticket|
          Gitlab::OAuth::Session.valid?(provider, ticket)
        end
    
        unless valid
          session[:service_tickets] = nil
          sign_out current_user
          redirect_to new_user_session_path
        end
      end
    
    
        if current_user && current_user.password_expires_at && current_user.password_expires_at < Time.now && !current_user.ldap_user?
    
    Douwe Maan's avatar
    Douwe Maan committed
          return redirect_to new_profile_password_path
    
      def check_2fa_requirement
    
        if two_factor_authentication_required? && current_user && !current_user.two_factor_enabled? && !skip_two_factor?
          redirect_to profile_two_factor_auth_path
    
        if current_user && current_user.requires_ldap_check?
    
    Jacob Vosmaer's avatar
    Jacob Vosmaer committed
          return unless current_user.try_obtain_ldap_lease
    
          unless Gitlab::LDAP::Access.allowed?(current_user)
            sign_out current_user
            flash[:alert] = "Access denied for your LDAP account."
            redirect_to new_user_session_path
    
        # Split using comma to maintain backward compatibility Ex/ "filter1,filter2"
        filters = cookies['event_filter'].split(',')[0] if cookies['event_filter'].present?
    
        @event_filter ||= EventFilter.new(filters)
      end
    
      def gitlab_ldap_access(&block)
    
        Gitlab::LDAP::Access.open { |access| yield(access) }
    
      # JSON for infinite scroll via Pager object
    
      def pager_json(partial, count, locals = {})
    
        html = render_to_string(
          partial,
    
          layout: false,
          formats: [:html]
        )
    
        render json: {
          html: html,
          count: count
        }
      end
    
    Josh Frye's avatar
    Josh Frye committed
      def view_to_html_string(partial, locals = {})
    
        render_to_string(
    
    Josh Frye's avatar
    Josh Frye committed
          partial,
    
          locals: locals,
    
          layout: false,
          formats: [:html]
        )
      end
    
    
      def configure_permitted_parameters
    
        devise_parameter_sanitizer.permit(:sign_in, keys: [:username, :email, :password, :login, :remember_me, :otp_attempt])
    
    
      def hexdigest(string)
        Digest::SHA1.hexdigest string
      end
    
    
      def require_email
    
        if current_user && current_user.temp_oauth_email? && session[:impersonator_id].nil?
    
    Douwe Maan's avatar
    Douwe Maan committed
          return redirect_to profile_path, notice: 'Please complete your profile with email address'
    
      def import_sources_enabled?
        !current_application_settings.import_sources.empty?
      end
    
    
      def github_import_enabled?
    
        current_application_settings.import_sources.include?('github')
      end
    
    
      def gitea_import_enabled?
        current_application_settings.import_sources.include?('gitea')
    
      def github_import_configured?
    
        Gitlab::OAuth::Provider.enabled?(:github)
    
      end
    
      def gitlab_import_enabled?
    
        request.host != 'gitlab.com' && current_application_settings.import_sources.include?('gitlab')
      end
    
      def gitlab_import_configured?
    
        Gitlab::OAuth::Provider.enabled?(:gitlab)
    
      end
    
      def bitbucket_import_enabled?
    
        current_application_settings.import_sources.include?('bitbucket')
      end
    
      def bitbucket_import_configured?
    
        Gitlab::OAuth::Provider.enabled?(:bitbucket)
    
    
      def google_code_import_enabled?
        current_application_settings.import_sources.include?('google_code')
      end
    
    
    Jared Szechy's avatar
    Jared Szechy committed
      def fogbugz_import_enabled?
        current_application_settings.import_sources.include?('fogbugz')
      end
    
    
      def git_import_enabled?
        current_application_settings.import_sources.include?('git')
      end
    
      def gitlab_project_import_enabled?
        current_application_settings.import_sources.include?('gitlab_project')
      end
    
    
      def two_factor_authentication_required?
        current_application_settings.require_two_factor_authentication
      end
    
    
      def two_factor_grace_period
        current_application_settings.two_factor_grace_period
      end
    
    
      def two_factor_grace_period_expired?
        date = current_user.otp_grace_period_started_at
    
        date && (date + two_factor_grace_period.hours) < Time.current
      end
    
      def skip_two_factor?
        session[:skip_tfa] && session[:skip_tfa] > Time.current
      end
    
    
      def redirect_to_home_page_url?
        # If user is not signed-in and tries to access root_path - redirect him to landing page
        # Don't redirect to the default URL to prevent endless redirections
        return false unless current_application_settings.home_page_url.present?
    
        home_page_url = current_application_settings.home_page_url.chomp('/')
        root_urls = [Gitlab.config.gitlab['url'].chomp('/'), root_url.chomp('/')]
    
        return false if root_urls.include?(home_page_url)
    
        current_user.nil? && root_path == request.path
      end
    
      # U2F (universal 2nd factor) devices need a unique identifier for the application
      # to perform authentication.
      # https://developers.yubico.com/U2F/App_ID.html
      def u2f_app_id
        request.base_url
      end
    
    gitlabhq's avatar
    gitlabhq committed
    end