Show a reCAPTCHA on signin page if custom header is set
This will only be displayed if `X-GitLab-Show-Login-Captcha` is set as an HTTP header.
This commit is contained in:
parent
6d2a48d52f
commit
9b48d9f43f
5 changed files with 88 additions and 6 deletions
|
@ -3,21 +3,27 @@ class SessionsController < Devise::SessionsController
|
|||
include AuthenticatesWithTwoFactor
|
||||
include Devise::Controllers::Rememberable
|
||||
include Recaptcha::ClientHelper
|
||||
include Recaptcha::Verify
|
||||
|
||||
skip_before_action :check_two_factor_requirement, only: [:destroy]
|
||||
|
||||
prepend_before_action :check_initial_setup, only: [:new]
|
||||
prepend_before_action :authenticate_with_two_factor,
|
||||
if: :two_factor_enabled?, only: [:create]
|
||||
prepend_before_action :check_captcha, only: [:create]
|
||||
prepend_before_action :store_redirect_uri, only: [:new]
|
||||
prepend_before_action :ldap_servers, only: [:new, :create]
|
||||
before_action :auto_sign_in_with_provider, only: [:new]
|
||||
before_action :load_recaptcha
|
||||
|
||||
after_action :log_failed_login, only: [:new], if: :failed_login?
|
||||
|
||||
helper_method :captcha_enabled?
|
||||
|
||||
CAPTCHA_HEADER = 'X-GitLab-Show-Login-Captcha'.freeze
|
||||
|
||||
def new
|
||||
set_minimum_password_length
|
||||
@ldap_servers = Gitlab::Auth::LDAP::Config.available_servers
|
||||
|
||||
super
|
||||
end
|
||||
|
@ -46,6 +52,25 @@ class SessionsController < Devise::SessionsController
|
|||
|
||||
private
|
||||
|
||||
def captcha_enabled?
|
||||
request.headers[CAPTCHA_HEADER] && Gitlab::Recaptcha.enabled?
|
||||
end
|
||||
|
||||
# From https://github.com/plataformatec/devise/wiki/How-To:-Use-Recaptcha-with-Devise#devisepasswordscontroller
|
||||
def check_captcha
|
||||
return unless user_params[:password].present?
|
||||
return unless captcha_enabled?
|
||||
return unless Gitlab::Recaptcha.load_configurations!
|
||||
|
||||
unless verify_recaptcha
|
||||
self.resource = resource_class.new
|
||||
flash[:alert] = 'There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.'
|
||||
flash.delete :recaptcha_error
|
||||
|
||||
respond_with_navigational(resource) { render :new }
|
||||
end
|
||||
end
|
||||
|
||||
def log_failed_login
|
||||
Gitlab::AppLogger.info("Failed Login: username=#{user_params[:login]} ip=#{request.remote_ip}")
|
||||
end
|
||||
|
@ -152,6 +177,10 @@ class SessionsController < Devise::SessionsController
|
|||
Gitlab::Recaptcha.load_configurations!
|
||||
end
|
||||
|
||||
def ldap_servers
|
||||
@ldap_servers ||= Gitlab::Auth::LDAP::Config.available_servers
|
||||
end
|
||||
|
||||
def authentication_method
|
||||
if user_params[:otp_attempt]
|
||||
"two-factor"
|
||||
|
|
|
@ -12,5 +12,9 @@
|
|||
%span Remember me
|
||||
.float-right.forgot-password
|
||||
= link_to "Forgot your password?", new_password_path(:user)
|
||||
%div
|
||||
- if captcha_enabled?
|
||||
= recaptcha_tags
|
||||
|
||||
.submit-container.move-submit-down
|
||||
= f.submit "Sign in", class: "btn btn-save"
|
||||
|
|
|
@ -20,4 +20,21 @@ To use reCAPTCHA, first you must create a site and private key.
|
|||
|
||||
6. Check the `Enable reCAPTCHA` checkbox
|
||||
|
||||
7. Save the configuration.
|
||||
7. Save the configuration.
|
||||
|
||||
## Enabling reCAPTCHA for user logins via passwords
|
||||
|
||||
By default, reCAPTCHA is only enabled for user registrations. To enable it for
|
||||
user logins via passwords, the `X-GitLab-Show-Login-Captcha` HTTP header must
|
||||
be set. For example, in NGINX, this can be done via the `proxy_set_header`
|
||||
configuration variable:
|
||||
|
||||
```
|
||||
proxy_set_header X-GitLab-Show-Login-Captcha 1;
|
||||
```
|
||||
|
||||
In GitLab Omnibus, this can be configured via `/etc/gitlab/gitlab.rb`:
|
||||
|
||||
```ruby
|
||||
nginx['proxy_set_headers'] = { 'X-GitLab-Show-Login-Captcha' => 1 }
|
||||
```
|
||||
|
|
|
@ -53,21 +53,22 @@ describe SessionsController do
|
|||
include UserActivitiesHelpers
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:user_params) { { login: user.username, password: user.password } }
|
||||
|
||||
it 'authenticates user correctly' do
|
||||
post(:create, user: { login: user.username, password: user.password })
|
||||
post(:create, user: user_params)
|
||||
|
||||
expect(subject.current_user). to eq user
|
||||
end
|
||||
|
||||
it 'creates an audit log record' do
|
||||
expect { post(:create, user: { login: user.username, password: user.password }) }.to change { SecurityEvent.count }.by(1)
|
||||
expect { post(:create, user: user_params) }.to change { SecurityEvent.count }.by(1)
|
||||
expect(SecurityEvent.last.details[:with]).to eq('standard')
|
||||
end
|
||||
|
||||
include_examples 'user login request with unique ip limit', 302 do
|
||||
def request
|
||||
post(:create, user: { login: user.username, password: user.password })
|
||||
post(:create, user: user_params)
|
||||
expect(subject.current_user).to eq user
|
||||
subject.sign_out user
|
||||
end
|
||||
|
@ -75,10 +76,40 @@ describe SessionsController do
|
|||
|
||||
it 'updates the user activity' do
|
||||
expect do
|
||||
post(:create, user: { login: user.username, password: user.password })
|
||||
post(:create, user: user_params)
|
||||
end.to change { user_activity(user) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when reCAPTCHA is enabled' do
|
||||
let(:user) { create(:user) }
|
||||
let(:user_params) { { login: user.username, password: user.password } }
|
||||
|
||||
before do
|
||||
stub_application_setting(recaptcha_enabled: true)
|
||||
request.headers[described_class::CAPTCHA_HEADER] = 1
|
||||
end
|
||||
|
||||
it 'displays an error when the reCAPTCHA is not solved' do
|
||||
# Without this, `verify_recaptcha` arbitraily returns true in test env
|
||||
Recaptcha.configuration.skip_verify_env.delete('test')
|
||||
|
||||
post(:create, user: user_params)
|
||||
|
||||
expect(response).to render_template(:new)
|
||||
expect(flash[:alert]).to include 'There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.'
|
||||
expect(subject.current_user).to be_nil
|
||||
end
|
||||
|
||||
it 'successfully logs in a user when reCAPTCHA is solved' do
|
||||
# Avoid test ordering issue and ensure `verify_recaptcha` returns true
|
||||
Recaptcha.configuration.skip_verify_env << 'test'
|
||||
|
||||
post(:create, user: user_params)
|
||||
|
||||
expect(subject.current_user).to eq user
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when using two-factor authentication via OTP' do
|
||||
|
|
|
@ -6,6 +6,7 @@ describe 'devise/shared/_signin_box' do
|
|||
stub_devise
|
||||
assign(:ldap_servers, [])
|
||||
allow(view).to receive(:current_application_settings).and_return(Gitlab::CurrentSettings.current_application_settings)
|
||||
allow(view).to receive(:captcha_enabled?).and_return(false)
|
||||
end
|
||||
|
||||
it 'is shown when Crowd is enabled' do
|
||||
|
|
Loading…
Reference in a new issue