Skip to content
Snippets Groups Projects
Commit 286fe610 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 4cb5e501
No related branches found
No related tags found
No related merge requests found
Showing
with 273 additions and 33 deletions
<script>
import { GlTooltipDirective } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import { __, sprintf } from '~/locale';
import { __ } from '~/locale';
import { getCommitIconMap } from '~/ide/utils';
 
export default {
Loading
Loading
@@ -51,17 +51,7 @@ export default {
tooltipTitle() {
if (!this.showTooltip || !this.file.changed) return undefined;
 
const type = this.file.tempFile ? 'addition' : 'modification';
if (this.file.staged) {
return sprintf(__('Staged %{type}'), {
type,
});
}
return sprintf(__('Unstaged %{type}'), {
type,
});
return this.file.tempFile ? __('Added') : __('Modified');
},
showIcon() {
return (
Loading
Loading
Loading
Loading
@@ -257,7 +257,6 @@
width: 15px;
height: 15px;
display: $svg-display;
fill: $gl-text-color;
top: $svg-top;
}
 
Loading
Loading
Loading
Loading
@@ -358,17 +358,30 @@
}
}
 
.build-page-pod-logs {
.environment-logs-viewer {
.build-trace-container {
position: relative;
}
 
.log-lines,
.gl-infinite-scroll-container {
// makes scrollbar visible by creating contrast
background: $black;
}
.gl-infinite-scroll-legend {
margin: 0;
}
.build-trace {
@include build-trace();
margin: 0;
}
 
.top-bar {
@include build-trace-top-bar($gl-line-height * 5);
position: relative;
top: 0;
 
.dropdown-menu-toggle {
width: 200px;
Loading
Loading
@@ -395,4 +408,9 @@
.build-loader-animation {
@include build-loader-animation;
}
.log-footer {
color: $white-normal;
background-color: $gray-900;
}
}
# frozen_string_literal: true
module Authenticates2FAForAdminMode
extend ActiveSupport::Concern
included do
include AuthenticatesWithTwoFactor
end
def admin_mode_prompt_for_two_factor(user)
return handle_locked_user(user) unless user.can?(:log_in)
session[:otp_user_id] = user.id
setup_u2f_authentication(user)
render 'admin/sessions/two_factor', layout: 'application'
end
def admin_mode_authenticate_with_two_factor
user = current_user
return handle_locked_user(user) unless user.can?(:log_in)
if user_params[:otp_attempt].present? && session[:otp_user_id]
admin_mode_authenticate_with_two_factor_via_otp(user)
elsif user_params[:device_response].present? && session[:otp_user_id]
admin_mode_authenticate_with_two_factor_via_u2f(user)
elsif user && user.valid_password?(user_params[:password])
admin_mode_prompt_for_two_factor(user)
else
invalid_login_redirect
end
end
def admin_mode_authenticate_with_two_factor_via_otp(user)
if valid_otp_attempt?(user)
# Remove any lingering user data from login
session.delete(:otp_user_id)
user.save!
# The admin user has successfully passed 2fa, enable admin mode ignoring password
enable_admin_mode
else
user.increment_failed_attempts!
Gitlab::AppLogger.info("Failed Admin Mode Login: user=#{user.username} ip=#{request.remote_ip} method=OTP")
flash.now[:alert] = _('Invalid two-factor code.')
admin_mode_prompt_for_two_factor(user)
end
end
def admin_mode_authenticate_with_two_factor_via_u2f(user)
if U2fRegistration.authenticate(user, u2f_app_id, user_params[:device_response], session[:challenge])
# Remove any lingering user data from login
session.delete(:otp_user_id)
session.delete(:challenge)
# The admin user has successfully passed 2fa, enable admin mode ignoring password
enable_admin_mode
else
user.increment_failed_attempts!
Gitlab::AppLogger.info("Failed Admin Mode Login: user=#{user.username} ip=#{request.remote_ip} method=U2F")
flash.now[:alert] = _('Authentication via U2F device failed.')
admin_mode_prompt_for_two_factor(user)
end
end
private
def enable_admin_mode
if current_user_mode.enable_admin_mode!(skip_password_validation: true)
redirect_to redirect_path, notice: _('Admin mode enabled')
else
invalid_login_redirect
end
end
def invalid_login_redirect
flash.now[:alert] = _('Invalid login or password')
render :new
end
end
# frozen_string_literal: true
 
class Admin::SessionsController < ApplicationController
include Authenticates2FAForAdminMode
include InternalRedirect
 
before_action :user_is_admin!
Loading
Loading
@@ -15,7 +16,9 @@ class Admin::SessionsController < ApplicationController
end
 
def create
if current_user_mode.enable_admin_mode!(password: params[:password])
if two_factor_enabled_for_user?
admin_mode_authenticate_with_two_factor
elsif current_user_mode.enable_admin_mode!(password: user_params[:password])
redirect_to redirect_path, notice: _('Admin mode enabled')
else
flash.now[:alert] = _('Invalid login or password')
Loading
Loading
@@ -37,6 +40,10 @@ class Admin::SessionsController < ApplicationController
render_404 unless current_user&.admin?
end
 
def two_factor_enabled_for_user?
current_user&.two_factor_enabled?
end
def redirect_path
redirect_to_path = safe_redirect_path(stored_location_for(:redirect)) || safe_redirect_path_for_url(request.referer)
 
Loading
Loading
@@ -51,4 +58,13 @@ class Admin::SessionsController < ApplicationController
def excluded_redirect_paths
[new_admin_session_path, admin_session_path]
end
def user_params
params.fetch(:user, {}).permit(:password, :otp_attempt, :device_response)
end
def valid_otp_attempt?(user)
user.validate_and_consume_otp!(user_params[:otp_attempt]) ||
user.invalidate_otp_backup_code!(user_params[:otp_attempt])
end
end
Loading
Loading
@@ -3,8 +3,6 @@
# == AuthenticatesWithTwoFactor
#
# Controller concern to handle two-factor authentication
#
# Upon inclusion, skips `require_no_authentication` on `:create`.
module AuthenticatesWithTwoFactor
extend ActiveSupport::Concern
 
Loading
Loading
Loading
Loading
@@ -2,6 +2,7 @@
 
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
include AuthenticatesWithTwoFactor
include Authenticates2FAForAdminMode
include Devise::Controllers::Rememberable
include AuthHelper
include InitializesCurrentUserMode
Loading
Loading
@@ -97,7 +98,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
log_audit_event(current_user, with: oauth['provider'])
 
if Feature.enabled?(:user_mode_in_session)
return admin_mode_flow if current_user_mode.admin_mode_requested?
return admin_mode_flow(auth_module::User) if current_user_mode.admin_mode_requested?
end
 
identity_linker ||= auth_module::IdentityLinker.new(current_user, oauth, session)
Loading
Loading
@@ -245,13 +246,19 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
end
end
 
def admin_mode_flow
if omniauth_identity_matches_current_user?
def admin_mode_flow(auth_user_class)
auth_user = build_auth_user(auth_user_class)
return fail_admin_mode_invalid_credentials unless omniauth_identity_matches_current_user?
if current_user.two_factor_enabled? && !auth_user.bypass_two_factor?
admin_mode_prompt_for_two_factor(current_user)
else
# Can only reach here if the omniauth identity matches current user
# and current_user is an admin that requested admin mode
current_user_mode.enable_admin_mode!(skip_password_validation: true)
 
redirect_to stored_location_for(:redirect) || admin_root_path, notice: _('Admin mode enabled')
else
fail_admin_mode_invalid_credentials
end
end
 
Loading
Loading
# frozen_string_literal: true
module Projects
module Import
class JiraController < Projects::ApplicationController
before_action :jira_import_enabled?
before_action :jira_integration_configured?
def show
unless @project.import_state&.in_progress?
jira_client = @project.jira_service.client
@jira_projects = jira_client.Project.all.map { |p| ["#{p.name} (#{p.key})", p.key] }
end
flash[:notice] = _("Import %{status}") % { status: @project.import_state.status } if @project.import_state.present? && !@project.import_state.none?
end
def import
import_state = @project.import_state || @project.create_import_state
schedule_import(jira_import_params) unless import_state.in_progress?
redirect_to project_import_jira_path(@project)
end
private
def jira_import_enabled?
return if Feature.enabled?(:jira_issue_import, @project)
redirect_to project_issues_path(@project)
end
def jira_integration_configured?
return if @project.jira_service
flash[:notice] = _("Configure the Jira integration first on your project's %{strong_start} Settings > Integrations > Jira%{strong_end} page." %
{ strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe })
redirect_to project_issues_path(@project)
end
def schedule_import(params)
import_data = @project.create_or_update_import_data(data: {}).becomes(JiraImportData)
import_data << JiraImportData::JiraProjectDetails.new(
params[:jira_project_key],
Time.now.strftime('%Y-%m-%d %H:%M:%S'),
{ user_id: current_user.id, name: current_user.name }
)
@project.import_type = 'jira'
@project.import_state.schedule if @project.save
end
def jira_import_params
params.permit(:jira_project_key)
end
end
end
end
Loading
Loading
@@ -9,7 +9,7 @@ module Mutations
end
 
def group_resolver
Resolvers::GroupResolver.new(object: nil, context: context)
Resolvers::GroupResolver.new(object: nil, context: context, field: nil)
end
end
end
Loading
Loading
@@ -14,7 +14,7 @@ module Mutations
def issuable_resolver(type, parent, context)
resolver_class = "Resolvers::#{type.to_s.classify.pluralize}Resolver".constantize
 
resolver_class.single.new(object: parent, context: context)
resolver_class.single.new(object: parent, context: context, field: nil)
end
 
def resolve_issuable_parent(parent_path)
Loading
Loading
Loading
Loading
@@ -9,7 +9,7 @@ module Mutations
end
 
def project_resolver
Resolvers::ProjectResolver.new(object: nil, context: context)
Resolvers::ProjectResolver.new(object: nil, context: context, field: nil)
end
end
end
Loading
Loading
@@ -17,7 +17,9 @@ module ReleasesHelper
project_id: @project.id,
illustration_path: illustration,
documentation_path: help_page
}
}.tap do |data|
data[:new_release_path] = new_project_tag_path(@project) if can?(current_user, :create_release, @project)
end
end
 
def data_for_edit_release_page
Loading
Loading
Loading
Loading
@@ -100,7 +100,13 @@ module BulkInsertSafe
def _bulk_insert_item_attributes(items, validate_items)
items.map do |item|
item.validate! if validate_items
attributes = item.attributes
attributes = {}
column_names.each do |name|
value = item.read_attribute(name)
value = item.type_for_attribute(name).serialize(value) # rubocop:disable Cop/ActiveRecordSerialize
attributes[name] = value
end
 
_bulk_insert_reject_primary_key!(attributes, item.class.primary_key)
 
Loading
Loading
# frozen_string_literal: true
class JiraImportData < ProjectImportData
JiraProjectDetails = Struct.new(:key, :scheduled_at, :scheduled_by)
def projects
return [] unless data
projects = data.dig('jira', 'projects').map do |p|
JiraProjectDetails.new(p['key'], p['scheduled_at'], p['scheduled_by'])
end
projects.sort_by { |jp| jp.scheduled_at }
end
def <<(project)
self.data ||= { jira: { projects: [] } }
self.data['jira']['projects'] << project.to_h.deep_stringify_keys!
end
end
= 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' }
= label_tag :user_password, _('Password'), class: 'label-bold'
= password_field_tag 'user[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: 'enter_admin_mode_button' }
%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')
%a.nav-link.active{ href: '#login-pane', data: { toggle: 'tab', qa_selector: 'sign_in_tab' }, role: 'tab' }= tab_title
= form_tag(admin_session_path, { method: :post, class: "edit_user gl-show-field-errors js-2fa-form #{'hidden' if current_user.two_factor_u2f_enabled?}" }) do
.form-group
= label_tag :user_otp_attempt, _('Two-Factor Authentication code')
= text_field_tag 'user[otp_attempt]', nil, class: 'form-control', required: true, autofocus: true, autocomplete: 'off', title: _('This field is required.')
%p.form-text.text-muted.hint
= _("Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes.")
.submit-container.move-submit-down
= submit_tag 'Verify code', class: 'btn btn-success'
#js-authenticate-u2f
%a.btn.btn-block.btn-info#js-login-2fa-device{ href: '#' }= _("Sign in via 2FA code")
%script#js-authenticate-u2f-in-progress{ type: "text/template" }
%p= _("Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now.")
-# haml-lint:disable NoPlainNodes
%script#js-authenticate-u2f-error{ type: "text/template" }
%div
%p <%= error_message %> (#{_("error code:")} <%= error_code %>)
%a.btn.btn-block.btn-warning#js-u2f-try-again= _("Try again?")
%script#js-authenticate-u2f-authenticated{ type: "text/template" }
%div
%p= _("We heard back from your U2F device. You have been authenticated.")
= form_tag(admin_session_path, method: :post, id: 'js-login-u2f-form') do |f|
= hidden_field_tag 'user[device_response]', nil, class: 'form-control', required: true, id: "js-device-response"
Loading
Loading
@@ -2,10 +2,10 @@
- page_title _('Enter Admin Mode')
 
.row.justify-content-center
.col-6.new-session-forms-container
.col-md-5.new-session-forms-container
.login-page
#signin-container
= render 'admin/sessions/tabs_normal'
= render 'admin/sessions/tabs_normal', tab_title: _('Enter Admin Mode')
.tab-content
- if !current_user.require_password_creation_for_web?
.login-box.tab-pane.active{ id: 'login-pane', role: 'tabpanel' }
Loading
Loading
@@ -14,7 +14,7 @@
 
- if omniauth_enabled? && button_based_providers_enabled?
.clearfix
= render 'devise/shared/omniauth_box'
= render 'devise/shared/omniauth_box', hide_remember_me: true
 
-# Show a message if none of the mechanisms above are enabled
- if current_user.require_password_creation_for_web? && !omniauth_enabled?
Loading
Loading
- @hide_breadcrumbs = true
- page_title _('Enter 2FA for Admin Mode')
.row.justify-content-center
.col-md-5.new-session-forms-container
.login-page
#signin-container
= render 'admin/sessions/tabs_normal', tab_title: _('Enter Admin Mode')
.tab-content
.login-box.tab-pane.active{ id: 'login-pane', role: 'tabpanel' }
.login-body
- if current_user.two_factor_otp_enabled?
= render 'admin/sessions/two_factor_otp'
- if current_user.two_factor_u2f_enabled?
= render 'admin/sessions/two_factor_u2f'
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment