diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-09-26 12:06:00 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-09-26 12:06:00 +0000 |
commit | 5707f305f4b961e24369fcdaecf0b8ce1c34bad8 (patch) | |
tree | 3b291653b83b3e6c2bffc77c54527fbe6f6373be /app | |
parent | 759cd6c2985088d187ed519f2a881c2c690b34ec (diff) | |
download | gitlab-ce-5707f305f4b961e24369fcdaecf0b8ce1c34bad8.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r-- | app/assets/javascripts/jobs/store/utils.js | 65 | ||||
-rw-r--r-- | app/assets/stylesheets/framework/card.scss | 3 | ||||
-rw-r--r-- | app/controllers/admin/sessions_controller.rb | 33 | ||||
-rw-r--r-- | app/controllers/application_controller.rb | 5 | ||||
-rw-r--r-- | app/controllers/concerns/enforces_admin_authentication.rb | 12 | ||||
-rw-r--r-- | app/controllers/concerns/sessionless_authentication.rb | 10 | ||||
-rw-r--r-- | app/controllers/health_controller.rb | 4 | ||||
-rw-r--r-- | app/helpers/nav_helper.rb | 6 | ||||
-rw-r--r-- | app/policies/base_policy.rb | 8 | ||||
-rw-r--r-- | app/services/projects/container_repository/delete_tags_service.rb | 2 | ||||
-rw-r--r-- | app/views/admin/sessions/_new_base.html.haml | 7 | ||||
-rw-r--r-- | app/views/admin/sessions/_signin_box.html.haml | 11 | ||||
-rw-r--r-- | app/views/admin/sessions/_tabs_normal.html.haml | 3 | ||||
-rw-r--r-- | app/views/admin/sessions/new.html.haml | 15 | ||||
-rw-r--r-- | app/views/layouts/nav/_dashboard.html.haml | 20 |
15 files changed, 187 insertions, 17 deletions
diff --git a/app/assets/javascripts/jobs/store/utils.js b/app/assets/javascripts/jobs/store/utils.js index fd2af0e421b..4a7d870674b 100644 --- a/app/assets/javascripts/jobs/store/utils.js +++ b/app/assets/javascripts/jobs/store/utils.js @@ -24,6 +24,46 @@ export const parseHeaderLine = (line = {}, lineNumber) => ({ }); /** + * Finds the matching header section + * for the section_duration object and adds it to it + * + * { + * isHeader: true, + * line: { + * content: [], + * lineNumber: 0, + * section_duration: "", + * }, + * lines: [] + * } + * + * @param Array data + * @param Object durationLine + */ +export function addDurationToHeader(data, durationLine) { + data.forEach(el => { + if (el.line && el.line.section === durationLine.section) { + el.line.section_duration = durationLine.section_duration; + } + }); +} + +/** + * Check is the current section belongs to a collapsible section + * + * @param Array acc + * @param Object last + * @param Object section + * + * @returns Boolean + */ +export const isCollapsibleSection = (acc = [], last = {}, section = {}) => + acc.length > 0 && + last.isHeader === true && + !section.section_duration && + section.section === last.line.section; + +/** * Parses the job log content into a structure usable by the template * * For collaspible lines (section_header = true): @@ -32,28 +72,35 @@ export const parseHeaderLine = (line = {}, lineNumber) => ({ * - adds a isHeader property to handle template logic * - adds the section_duration * For each line: - * - adds the index as lineNumber + * - adds the index as lineNumber * - * @param {Array} lines - * @returns {Array} + * @param Array lines + * @param Number lineNumberStart + * @param Array accumulator + * @returns Array parsed log lines */ -export const logLinesParser = (lines = [], lineNumberStart) => +export const logLinesParser = (lines = [], lineNumberStart, accumulator = []) => lines.reduce((acc, line, index) => { const lineNumber = lineNumberStart ? lineNumberStart + index : index; const last = acc[acc.length - 1]; + // If the object is an header, we parse it into another structure if (line.section_header) { acc.push(parseHeaderLine(line, lineNumber)); - } else if (acc.length && last.isHeader && !line.section_duration && line.content.length) { + } else if (isCollapsibleSection(acc, last, line)) { + // if the object belongs to a nested section, we append it to the new `lines` array of the + // previously formated header last.lines.push(parseLine(line, lineNumber)); - } else if (acc.length && last.isHeader && line.section_duration) { - last.section_duration = line.section_duration; - } else if (line.content.length) { + } else if (line.section_duration) { + // if the line has section_duration, we look for the correct header to add it + addDurationToHeader(acc, line); + } else { + // otherwise it's a regular line acc.push(parseLine(line, lineNumber)); } return acc; - }, []); + }, accumulator); /** * Finds the repeated offset, removes the old one diff --git a/app/assets/stylesheets/framework/card.scss b/app/assets/stylesheets/framework/card.scss index 1e51d28bba2..9911b926cbb 100644 --- a/app/assets/stylesheets/framework/card.scss +++ b/app/assets/stylesheets/framework/card.scss @@ -1,8 +1,7 @@ .card-header { &:first-child { // intended use case: card with only a header (for example empty related issues) - &.border-0, - &.border-bottom-0 { + &:last-child { @include border-radius($card-inner-border-radius); } } diff --git a/app/controllers/admin/sessions_controller.rb b/app/controllers/admin/sessions_controller.rb new file mode 100644 index 00000000000..1f946e41995 --- /dev/null +++ b/app/controllers/admin/sessions_controller.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +class Admin::SessionsController < ApplicationController + include InternalRedirect + + before_action :user_is_admin! + + def new + # Renders a form in which the admin can enter their password + end + + def create + if current_user_mode.enable_admin_mode!(password: params[:password]) + redirect_location = stored_location_for(:redirect) || admin_root_path + redirect_to safe_redirect_path(redirect_location) + else + flash.now[:alert] = _('Invalid Login or password') + render :new + end + end + + def destroy + current_user_mode.disable_admin_mode! + + redirect_to root_path, status: :found, notice: _('Admin mode disabled') + end + + private + + def user_is_admin! + render_404 unless current_user&.admin? + end +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 9a7859fc687..0d0384ba52f 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -36,6 +36,7 @@ class ApplicationController < ActionController::Base protect_from_forgery with: :exception, prepend: true helper_method :can? + helper_method :current_user_mode helper_method :import_sources_enabled?, :github_import_enabled?, :gitea_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, @@ -533,6 +534,10 @@ class ApplicationController < ActionController::Base yield end end + + def current_user_mode + @current_user_mode ||= Gitlab::Auth::CurrentUserMode.new(current_user) + end end ApplicationController.prepend_if_ee('EE::ApplicationController') diff --git a/app/controllers/concerns/enforces_admin_authentication.rb b/app/controllers/concerns/enforces_admin_authentication.rb index 3ef92730df6..e731211f423 100644 --- a/app/controllers/concerns/enforces_admin_authentication.rb +++ b/app/controllers/concerns/enforces_admin_authentication.rb @@ -14,6 +14,16 @@ module EnforcesAdminAuthentication end def authenticate_admin! - render_404 unless current_user.admin? + return render_404 unless current_user.admin? + return unless Feature.enabled?(:user_mode_in_session) + + unless current_user_mode.admin_mode? + store_location_for(:redirect, request.fullpath) if storable_location? + redirect_to(new_admin_session_path, notice: _('Re-authentication required')) + end + end + + def storable_location? + request.path != new_admin_session_path end end diff --git a/app/controllers/concerns/sessionless_authentication.rb b/app/controllers/concerns/sessionless_authentication.rb index ba06384a37a..f644923443b 100644 --- a/app/controllers/concerns/sessionless_authentication.rb +++ b/app/controllers/concerns/sessionless_authentication.rb @@ -5,6 +5,12 @@ # Controller concern to handle PAT, RSS, and static objects token authentication methods # module SessionlessAuthentication + extend ActiveSupport::Concern + + included do + before_action :enable_admin_mode!, if: :sessionless_user? + end + # This filter handles personal access tokens, atom requests with rss tokens, and static object tokens def authenticate_sessionless_user!(request_format) user = Gitlab::Auth::RequestAuthenticator.new(request).find_sessionless_user(request_format) @@ -25,4 +31,8 @@ module SessionlessAuthentication sign_in(user, store: false, message: :sessionless_sign_in) end end + + def enable_admin_mode! + current_user_mode.enable_admin_mode!(skip_password_validation: true) if Feature.enabled?(:user_mode_in_session) + end end diff --git a/app/controllers/health_controller.rb b/app/controllers/health_controller.rb index dc9a52f8da5..c97057c08cb 100644 --- a/app/controllers/health_controller.rb +++ b/app/controllers/health_controller.rb @@ -20,9 +20,7 @@ class HealthController < ActionController::Base end def liveness - results = CHECKS.map { |check| [check.name, check.liveness] } - - render_check_results(results) + render json: { status: 'ok' }, status: :ok end private diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb index c6e9a20c5b2..2ce45cec878 100644 --- a/app/helpers/nav_helper.rb +++ b/app/helpers/nav_helper.rb @@ -86,6 +86,12 @@ module NavHelper links << :admin_impersonation end + if Feature.enabled?(:user_mode_in_session) + if current_user&.admin? && current_user_mode&.admin_mode? + links << :admin_mode + end + end + links end end diff --git a/app/policies/base_policy.rb b/app/policies/base_policy.rb index 78379516062..2305c55033f 100644 --- a/app/policies/base_policy.rb +++ b/app/policies/base_policy.rb @@ -5,7 +5,13 @@ require_dependency 'declarative_policy' class BasePolicy < DeclarativePolicy::Base desc "User is an instance admin" with_options scope: :user, score: 0 - condition(:admin) { @user&.admin? } + condition(:admin) do + if Feature.enabled?(:user_mode_in_session) + Gitlab::Auth::CurrentUserMode.new(@user).admin_mode? + else + @user&.admin? + end + end desc "User is blocked" with_options scope: :user, score: 0 diff --git a/app/services/projects/container_repository/delete_tags_service.rb b/app/services/projects/container_repository/delete_tags_service.rb index 21dc1621e5c..22656b29c58 100644 --- a/app/services/projects/container_repository/delete_tags_service.rb +++ b/app/services/projects/container_repository/delete_tags_service.rb @@ -32,7 +32,7 @@ module Projects # This is a hack as the registry doesn't support deleting individual # tags. This code effectively pushes a dummy image and assigns the tag to it. # This way when the tag is deleted only the dummy image is affected. - # See https://gitlab.com/gitlab-org/gitlab-ce/issues/21405 for a discussion + # See https://gitlab.com/gitlab-org/gitlab/issues/15737 for a discussion def smart_delete(container_repository, tag_names) # generates the blobs for the dummy image dummy_manifest = container_repository.client.generate_empty_manifest(container_repository.path) diff --git a/app/views/admin/sessions/_new_base.html.haml b/app/views/admin/sessions/_new_base.html.haml new file mode 100644 index 00000000000..55aea0296e7 --- /dev/null +++ b/app/views/admin/sessions/_new_base.html.haml @@ -0,0 +1,7 @@ += form_tag(admin_session_path, method: :post, html: { class: 'new_user gl-show-field-errors', 'aria-live': 'assertive'}) do + .form-group + = label_tag :password, _('Password'), class: 'label-bold' + = password_field_tag :password, nil, class: 'form-control', required: true, title: _('This field is required.'), data: { qa_selector: 'password_field' } + + .submit-container.move-submit-down + = submit_tag _('Enter admin mode'), class: 'btn btn-success', data: { qa_selector: 'sign_in_button' } diff --git a/app/views/admin/sessions/_signin_box.html.haml b/app/views/admin/sessions/_signin_box.html.haml new file mode 100644 index 00000000000..69baa76060e --- /dev/null +++ b/app/views/admin/sessions/_signin_box.html.haml @@ -0,0 +1,11 @@ +- if form_based_providers.any? + + - if password_authentication_enabled_for_web? + .login-box.tab-pane{ id: 'login-pane', role: 'tabpanel' } + .login-body + = render 'admin/sessions/new_base' + +- elsif password_authentication_enabled_for_web? + .login-box.tab-pane.active{ id: 'login-pane', role: 'tabpanel' } + .login-body + = render 'admin/sessions/new_base' diff --git a/app/views/admin/sessions/_tabs_normal.html.haml b/app/views/admin/sessions/_tabs_normal.html.haml new file mode 100644 index 00000000000..f5dedb5ad76 --- /dev/null +++ b/app/views/admin/sessions/_tabs_normal.html.haml @@ -0,0 +1,3 @@ +%ul.nav-links.new-session-tabs.nav-tabs.nav{ role: 'tablist' } + %li.nav-item{ role: 'presentation' } + %a.nav-link.active{ href: '#login-pane', data: { toggle: 'tab', qa_selector: 'sign_in_tab' }, role: 'tab' }= _('Enter admin mode') diff --git a/app/views/admin/sessions/new.html.haml b/app/views/admin/sessions/new.html.haml new file mode 100644 index 00000000000..ee06b4a1741 --- /dev/null +++ b/app/views/admin/sessions/new.html.haml @@ -0,0 +1,15 @@ +- @hide_breadcrumbs = true +- page_title _('Enter admin mode') + +.row.justify-content-center + .col-6.new-session-forms-container + .login-page + #signin-container + = render 'admin/sessions/tabs_normal' + .tab-content + - if password_authentication_enabled_for_web? + = render 'admin/sessions/signin_box' + - else + -# Show a message if none of the mechanisms above are enabled + .prepend-top-default.center + = _('No authentication methods configured.') diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml index 4b83239dfbd..015ba13be05 100644 --- a/app/views/layouts/nav/_dashboard.html.haml +++ b/app/views/layouts/nav/_dashboard.html.haml @@ -68,6 +68,15 @@ = nav_link(controller: 'admin/dashboard') do = link_to admin_root_path, class: 'd-lg-none admin-icon qa-admin-area-link' do = _('Admin Area') + - if Feature.enabled?(:user_mode_in_session) + - if header_link?(:admin_mode) + = nav_link(controller: 'admin/sessions') do + = link_to destroy_admin_session_path, class: 'd-lg-none lock-open-icon' do + = _('Leave admin mode') + - elsif current_user.admin? + = nav_link(controller: 'admin/sessions') do + = link_to new_admin_session_path, class: 'd-lg-none lock-icon' do + = _('Enter admin mode') - if Gitlab::Sherlock.enabled? %li = link_to sherlock_transactions_path, class: 'd-lg-none admin-icon' do @@ -95,6 +104,17 @@ = nav_link(controller: 'admin/dashboard', html_options: { class: "d-none d-lg-block d-xl-block"}) do = link_to admin_root_path, class: 'admin-icon qa-admin-area-link', title: _('Admin Area'), aria: { label: _('Admin Area') }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do = sprite_icon('admin', size: 18) + + - if Feature.enabled?(:user_mode_in_session) + - if header_link?(:admin_mode) + = nav_link(controller: 'admin/sessions', html_options: { class: "d-none d-lg-block d-xl-block"}) do + = link_to destroy_admin_session_path, title: _('Leave admin mode'), aria: { label: _('Leave admin mode') }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do + = sprite_icon('lock-open', size: 18) + - elsif current_user.admin? + = nav_link(controller: 'admin/sessions', html_options: { class: "d-none d-lg-block d-xl-block"}) do + = link_to new_admin_session_path, title: _('Enter admin mode'), aria: { label: _('Enter admin mode') }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do + = sprite_icon('lock', size: 18) + - if Gitlab::Sherlock.enabled? %li = link_to sherlock_transactions_path, class: 'admin-icon d-none d-lg-block d-xl-block', title: _('Sherlock Transactions'), |