diff --git a/app/controllers/passwords_controller.rb b/app/controllers/passwords_controller.rb index f74daff3bd0..a8575e037e4 100644 --- a/app/controllers/passwords_controller.rb +++ b/app/controllers/passwords_controller.rb @@ -23,6 +23,14 @@ class PasswordsController < Devise::PasswordsController end end + def update + super do |resource| + if resource.valid? && resource.require_password? + resource.update_attribute(:password_automatically_set, false) + end + end + end + protected def resource_from_email diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 44eb58e418b..65677a3dd3c 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -4,8 +4,10 @@ class SessionsController < Devise::SessionsController skip_before_action :check_2fa_requirement, only: [:destroy] + prepend_before_action :check_initial_setup, only: [:new] prepend_before_action :authenticate_with_two_factor, only: [:create] prepend_before_action :store_redirect_path, only: [:new] + before_action :auto_sign_in_with_provider, only: [:new] before_action :load_recaptcha @@ -33,6 +35,22 @@ class SessionsController < Devise::SessionsController private + # Handle an "initial setup" state, where there's only one user, it's an admin, + # and they require a password change. + def check_initial_setup + return unless User.count == 1 + + user = User.admins.last + + return unless user && user.require_password? + + token = user.generate_reset_token + user.save + + redirect_to edit_user_password_path(reset_password_token: token), + notice: "Please create a password for your new account." + end + def user_params params.require(:user).permit(:login, :password, :remember_me, :otp_attempt) end diff --git a/db/fixtures/production/001_admin.rb b/db/fixtures/production/001_admin.rb index 308b0528c9b..78746c83225 100644 --- a/db/fixtures/production/001_admin.rb +++ b/db/fixtures/production/001_admin.rb @@ -1,33 +1,38 @@ -if ENV['GITLAB_ROOT_PASSWORD'].blank? - password = '5iveL!fe' - expire_time = Time.now -else - password = ENV['GITLAB_ROOT_PASSWORD'] - expire_time = nil -end - -email = ENV['GITLAB_ROOT_EMAIL'].presence || 'admin@example.com' - -admin = User.create( - email: email, - name: "Administrator", +user_args = { + email: ENV['GITLAB_ROOT_EMAIL'].presence || 'admin@example.com', + name: 'Administrator', username: 'root', - password: password, - password_expires_at: expire_time, - theme_id: Gitlab::Themes::APPLICATION_DEFAULT + admin: true +} -) - -admin.projects_limit = 10000 -admin.admin = true -admin.save! -admin.confirm - -if admin.valid? -puts %Q[ -Administrator account created: - -login.........root -password......#{password} -] +if ENV['GITLAB_ROOT_PASSWORD'].blank? + user_args[:password_automatically_set] = true + user_args[:force_random_password] = true +else + user_args[:password] = ENV['GITLAB_ROOT_PASSWORD'] +end + +user = User.new(user_args) +user.skip_confirmation! + +if user.save + puts "Administrator account created:".green + puts + puts "login: root".green + + if user_args.key?(:password) + puts "password: #{user_args[:password]}".green + else + puts "password: You'll be prompted to create one on your first visit.".green + end + puts +else + puts "Could not create the default administrator account:".red + puts + user.errors.full_messages.map do |message| + puts "--> #{message}".red + end + puts + + exit 1 end diff --git a/spec/features/login_spec.rb b/spec/features/login_spec.rb index dac9205449a..4433ef2d6f1 100644 --- a/spec/features/login_spec.rb +++ b/spec/features/login_spec.rb @@ -1,6 +1,32 @@ require 'spec_helper' feature 'Login', feature: true do + describe 'initial login after setup' do + it 'allows the initial admin to create a password' do + # This behavior is dependent on there only being one user + User.delete_all + + user = create(:admin, password_automatically_set: true) + + visit root_path + expect(current_path).to eq edit_user_password_path + expect(page).to have_content('Please create a password for your new account.') + + fill_in 'user_password', with: 'password' + fill_in 'user_password_confirmation', with: 'password' + click_button 'Change your password' + + expect(current_path).to eq new_user_session_path + expect(page).to have_content(I18n.t('devise.passwords.updated_not_active')) + + fill_in 'user_login', with: user.username + fill_in 'user_password', with: 'password' + click_button 'Sign in' + + expect(current_path).to eq root_path + end + end + describe 'with two-factor authentication' do context 'with valid username/password' do let(:user) { create(:user, :two_factor) }