2013-09-17 20:37:36 +00:00
|
|
|
require 'spec_helper'
|
|
|
|
|
|
|
|
describe ApplicationController do
|
2016-11-14 14:55:31 +00:00
|
|
|
let(:user) { create(:user) }
|
|
|
|
|
2013-09-17 20:37:36 +00:00
|
|
|
describe '#check_password_expiration' do
|
2017-05-01 15:13:33 +00:00
|
|
|
let(:controller) { described_class.new }
|
2013-09-17 20:37:36 +00:00
|
|
|
|
2017-09-13 11:18:15 +00:00
|
|
|
before do
|
|
|
|
allow(controller).to receive(:session).and_return({})
|
|
|
|
end
|
|
|
|
|
2016-07-25 18:16:19 +00:00
|
|
|
it 'redirects if the user is over their password expiry' do
|
2013-09-17 20:37:36 +00:00
|
|
|
user.password_expires_at = Time.new(2002)
|
2017-08-31 10:21:40 +00:00
|
|
|
|
2015-02-12 18:17:35 +00:00
|
|
|
expect(user.ldap_user?).to be_falsey
|
|
|
|
allow(controller).to receive(:current_user).and_return(user)
|
|
|
|
expect(controller).to receive(:redirect_to)
|
|
|
|
expect(controller).to receive(:new_profile_password_path)
|
2017-08-31 10:21:40 +00:00
|
|
|
|
2013-09-17 20:37:36 +00:00
|
|
|
controller.send(:check_password_expiration)
|
|
|
|
end
|
|
|
|
|
2016-07-25 18:16:19 +00:00
|
|
|
it 'does not redirect if the user is under their password expiry' do
|
2013-09-17 20:37:36 +00:00
|
|
|
user.password_expires_at = Time.now + 20010101
|
2017-08-31 10:21:40 +00:00
|
|
|
|
2015-02-12 18:17:35 +00:00
|
|
|
expect(user.ldap_user?).to be_falsey
|
|
|
|
allow(controller).to receive(:current_user).and_return(user)
|
|
|
|
expect(controller).not_to receive(:redirect_to)
|
2017-08-31 10:21:40 +00:00
|
|
|
|
2013-09-17 20:37:36 +00:00
|
|
|
controller.send(:check_password_expiration)
|
|
|
|
end
|
|
|
|
|
2016-07-25 18:16:19 +00:00
|
|
|
it 'does not redirect if the user is over their password expiry but they are an ldap user' do
|
2013-09-17 20:37:36 +00:00
|
|
|
user.password_expires_at = Time.new(2002)
|
2017-08-31 10:21:40 +00:00
|
|
|
|
2015-02-12 18:17:35 +00:00
|
|
|
allow(user).to receive(:ldap_user?).and_return(true)
|
|
|
|
allow(controller).to receive(:current_user).and_return(user)
|
|
|
|
expect(controller).not_to receive(:redirect_to)
|
2017-08-31 10:21:40 +00:00
|
|
|
|
2013-09-17 20:37:36 +00:00
|
|
|
controller.send(:check_password_expiration)
|
|
|
|
end
|
2017-06-27 18:02:09 +00:00
|
|
|
|
2017-11-23 13:16:14 +00:00
|
|
|
it 'does not redirect if the user is over their password expiry but password authentication is disabled for the web interface' do
|
|
|
|
stub_application_setting(password_authentication_enabled_for_web: false)
|
|
|
|
stub_application_setting(password_authentication_enabled_for_git: false)
|
2017-06-27 18:02:09 +00:00
|
|
|
user.password_expires_at = Time.new(2002)
|
2017-08-31 10:21:40 +00:00
|
|
|
|
2017-06-27 18:02:09 +00:00
|
|
|
allow(controller).to receive(:current_user).and_return(user)
|
2017-11-23 13:16:14 +00:00
|
|
|
expect(controller).not_to receive(:redirect_to)
|
2017-06-27 18:02:09 +00:00
|
|
|
|
|
|
|
controller.send(:check_password_expiration)
|
|
|
|
end
|
2013-09-17 20:37:36 +00:00
|
|
|
end
|
2016-04-19 10:52:15 +00:00
|
|
|
|
2017-10-12 09:01:12 +00:00
|
|
|
describe "#authenticate_user_from_personal_access_token!" do
|
|
|
|
controller(described_class) do
|
|
|
|
def index
|
|
|
|
render text: 'authenticated'
|
2016-06-01 08:34:38 +00:00
|
|
|
end
|
2016-04-19 10:52:15 +00:00
|
|
|
end
|
|
|
|
|
2017-10-12 09:01:12 +00:00
|
|
|
let(:personal_access_token) { create(:personal_access_token, user: user) }
|
2016-04-19 10:52:15 +00:00
|
|
|
|
2017-10-12 09:01:12 +00:00
|
|
|
context "when the 'personal_access_token' param is populated with the personal access token" do
|
|
|
|
it "logs the user in" do
|
|
|
|
get :index, private_token: personal_access_token.token
|
|
|
|
expect(response).to have_gitlab_http_status(200)
|
|
|
|
expect(response.body).to eq('authenticated')
|
2016-06-01 08:34:38 +00:00
|
|
|
end
|
2017-10-12 09:01:12 +00:00
|
|
|
end
|
2016-04-19 10:52:15 +00:00
|
|
|
|
2017-10-12 09:01:12 +00:00
|
|
|
context "when the 'PERSONAL_ACCESS_TOKEN' header is populated with the personal access token" do
|
|
|
|
it "logs the user in" do
|
|
|
|
@request.headers["PRIVATE-TOKEN"] = personal_access_token.token
|
|
|
|
get :index
|
|
|
|
expect(response).to have_gitlab_http_status(200)
|
|
|
|
expect(response.body).to eq('authenticated')
|
2016-06-01 08:34:38 +00:00
|
|
|
end
|
2017-10-12 09:01:12 +00:00
|
|
|
end
|
2016-04-19 10:52:15 +00:00
|
|
|
|
2017-10-12 09:01:12 +00:00
|
|
|
it "doesn't log the user in otherwise" do
|
|
|
|
get :index, private_token: "token"
|
|
|
|
expect(response.status).not_to eq(200)
|
|
|
|
expect(response.body).not_to eq('authenticated')
|
2016-04-19 10:52:15 +00:00
|
|
|
end
|
|
|
|
end
|
2016-11-14 14:55:31 +00:00
|
|
|
|
2017-05-17 16:17:15 +00:00
|
|
|
describe 'rescue from Gitlab::Git::Storage::Inaccessible' do
|
|
|
|
controller(described_class) do
|
|
|
|
def index
|
|
|
|
raise Gitlab::Git::Storage::Inaccessible.new('broken', 100)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'renders a 503 when storage is not available' do
|
|
|
|
sign_in(create(:user))
|
|
|
|
|
|
|
|
get :index
|
|
|
|
|
|
|
|
expect(response.status).to eq(503)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'renders includes a Retry-After header' do
|
|
|
|
sign_in(create(:user))
|
|
|
|
|
|
|
|
get :index
|
|
|
|
|
|
|
|
expect(response.headers['Retry-After']).to eq(100)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-06-20 13:53:05 +00:00
|
|
|
describe 'response format' do
|
|
|
|
controller(described_class) do
|
|
|
|
def index
|
|
|
|
respond_to do |format|
|
|
|
|
format.json do
|
|
|
|
head :ok
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-10-12 09:01:12 +00:00
|
|
|
before do
|
|
|
|
sign_in user
|
|
|
|
end
|
|
|
|
|
2017-06-20 13:53:05 +00:00
|
|
|
context 'when format is handled' do
|
|
|
|
let(:requested_format) { :json }
|
|
|
|
|
|
|
|
it 'returns 200 response' do
|
2017-10-12 09:01:12 +00:00
|
|
|
get :index, format: requested_format
|
2017-06-20 13:53:05 +00:00
|
|
|
|
2017-10-19 18:28:19 +00:00
|
|
|
expect(response).to have_gitlab_http_status 200
|
2017-06-20 13:53:05 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when format is not handled' do
|
|
|
|
it 'returns 404 response' do
|
2017-10-12 09:01:12 +00:00
|
|
|
get :index
|
2017-06-20 13:53:05 +00:00
|
|
|
|
2017-10-19 18:28:19 +00:00
|
|
|
expect(response).to have_gitlab_http_status 404
|
2017-06-20 13:53:05 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-05-23 13:59:33 +00:00
|
|
|
describe '#authenticate_user_from_rss_token' do
|
2017-05-23 20:20:53 +00:00
|
|
|
describe "authenticating a user from an RSS token" do
|
2017-05-23 13:59:33 +00:00
|
|
|
controller(described_class) do
|
|
|
|
def index
|
|
|
|
render text: 'authenticated'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-05-23 20:20:53 +00:00
|
|
|
context "when the 'rss_token' param is populated with the RSS token" do
|
2017-05-23 13:59:33 +00:00
|
|
|
context 'when the request format is atom' do
|
|
|
|
it "logs the user in" do
|
|
|
|
get :index, rss_token: user.rss_token, format: :atom
|
2017-10-19 18:28:19 +00:00
|
|
|
expect(response).to have_gitlab_http_status 200
|
2017-05-23 13:59:33 +00:00
|
|
|
expect(response.body).to eq 'authenticated'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the request format is not atom' do
|
|
|
|
it "doesn't log the user in" do
|
|
|
|
get :index, rss_token: user.rss_token
|
2017-10-19 18:28:19 +00:00
|
|
|
expect(response.status).not_to have_gitlab_http_status 200
|
2017-05-23 13:59:33 +00:00
|
|
|
expect(response.body).not_to eq 'authenticated'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-05-23 20:20:53 +00:00
|
|
|
context "when the 'rss_token' param is populated with an invalid RSS token" do
|
2017-05-23 13:59:33 +00:00
|
|
|
it "doesn't log the user" do
|
|
|
|
get :index, rss_token: "token"
|
|
|
|
expect(response.status).not_to eq 200
|
|
|
|
expect(response.body).not_to eq 'authenticated'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-11-14 14:55:31 +00:00
|
|
|
describe '#route_not_found' do
|
|
|
|
it 'renders 404 if authenticated' do
|
|
|
|
allow(controller).to receive(:current_user).and_return(user)
|
|
|
|
expect(controller).to receive(:not_found)
|
|
|
|
controller.send(:route_not_found)
|
|
|
|
end
|
|
|
|
|
2017-05-01 20:46:30 +00:00
|
|
|
it 'does redirect to login page via authenticate_user! if not authenticated' do
|
2016-11-14 14:55:31 +00:00
|
|
|
allow(controller).to receive(:current_user).and_return(nil)
|
2017-05-01 20:46:30 +00:00
|
|
|
expect(controller).to receive(:authenticate_user!)
|
2016-11-14 14:55:31 +00:00
|
|
|
controller.send(:route_not_found)
|
|
|
|
end
|
|
|
|
end
|
2017-01-24 21:09:58 +00:00
|
|
|
|
2017-10-20 16:44:29 +00:00
|
|
|
describe '#set_page_title_header' do
|
|
|
|
let(:controller) { described_class.new }
|
|
|
|
|
|
|
|
it 'URI encodes UTF-8 characters in the title' do
|
|
|
|
response = double(headers: {})
|
|
|
|
allow_any_instance_of(PageLayoutHelper).to receive(:page_title).and_return('€100 · GitLab')
|
|
|
|
allow(controller).to receive(:response).and_return(response)
|
|
|
|
|
|
|
|
controller.send(:set_page_title_header)
|
|
|
|
|
|
|
|
expect(response.headers['Page-Title']).to eq('%E2%82%AC100%20%C2%B7%20GitLab')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-01-24 21:09:58 +00:00
|
|
|
context 'two-factor authentication' do
|
2017-05-01 15:13:33 +00:00
|
|
|
let(:controller) { described_class.new }
|
2017-01-24 21:09:58 +00:00
|
|
|
|
2017-03-07 18:48:57 +00:00
|
|
|
describe '#check_two_factor_requirement' do
|
|
|
|
subject { controller.send :check_two_factor_requirement }
|
2017-01-24 21:09:58 +00:00
|
|
|
|
|
|
|
it 'does not redirect if 2FA is not required' do
|
|
|
|
allow(controller).to receive(:two_factor_authentication_required?).and_return(false)
|
|
|
|
expect(controller).not_to receive(:redirect_to)
|
|
|
|
|
|
|
|
subject
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not redirect if user is not logged in' do
|
|
|
|
allow(controller).to receive(:two_factor_authentication_required?).and_return(true)
|
|
|
|
allow(controller).to receive(:current_user).and_return(nil)
|
|
|
|
expect(controller).not_to receive(:redirect_to)
|
|
|
|
|
|
|
|
subject
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not redirect if user has 2FA enabled' do
|
|
|
|
allow(controller).to receive(:two_factor_authentication_required?).and_return(true)
|
|
|
|
allow(controller).to receive(:current_user).twice.and_return(user)
|
|
|
|
allow(user).to receive(:two_factor_enabled?).and_return(true)
|
|
|
|
expect(controller).not_to receive(:redirect_to)
|
|
|
|
|
|
|
|
subject
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not redirect if 2FA setup can be skipped' do
|
|
|
|
allow(controller).to receive(:two_factor_authentication_required?).and_return(true)
|
|
|
|
allow(controller).to receive(:current_user).twice.and_return(user)
|
|
|
|
allow(user).to receive(:two_factor_enabled?).and_return(false)
|
|
|
|
allow(controller).to receive(:skip_two_factor?).and_return(true)
|
|
|
|
expect(controller).not_to receive(:redirect_to)
|
|
|
|
|
|
|
|
subject
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'redirects to 2FA setup otherwise' do
|
|
|
|
allow(controller).to receive(:two_factor_authentication_required?).and_return(true)
|
|
|
|
allow(controller).to receive(:current_user).twice.and_return(user)
|
|
|
|
allow(user).to receive(:two_factor_enabled?).and_return(false)
|
|
|
|
allow(controller).to receive(:skip_two_factor?).and_return(false)
|
|
|
|
allow(controller).to receive(:profile_two_factor_auth_path)
|
|
|
|
expect(controller).to receive(:redirect_to)
|
|
|
|
|
|
|
|
subject
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#two_factor_authentication_required?' do
|
|
|
|
subject { controller.send :two_factor_authentication_required? }
|
|
|
|
|
|
|
|
it 'returns false if no 2FA requirement is present' do
|
|
|
|
allow(controller).to receive(:current_user).and_return(nil)
|
|
|
|
|
|
|
|
expect(subject).to be_falsey
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns true if a 2FA requirement is set in the application settings' do
|
|
|
|
stub_application_setting require_two_factor_authentication: true
|
|
|
|
allow(controller).to receive(:current_user).and_return(nil)
|
|
|
|
|
|
|
|
expect(subject).to be_truthy
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns true if a 2FA requirement is set on the user' do
|
2017-03-14 13:34:21 +00:00
|
|
|
user.require_two_factor_authentication_from_group = true
|
2017-01-24 21:09:58 +00:00
|
|
|
allow(controller).to receive(:current_user).and_return(user)
|
|
|
|
|
|
|
|
expect(subject).to be_truthy
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#two_factor_grace_period' do
|
|
|
|
subject { controller.send :two_factor_grace_period }
|
|
|
|
|
|
|
|
it 'returns the grace period from the application settings' do
|
|
|
|
stub_application_setting two_factor_grace_period: 23
|
|
|
|
allow(controller).to receive(:current_user).and_return(nil)
|
|
|
|
|
|
|
|
expect(subject).to eq 23
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with a 2FA requirement set on the user' do
|
2017-03-14 13:34:21 +00:00
|
|
|
let(:user) { create :user, require_two_factor_authentication_from_group: true, two_factor_grace_period: 23 }
|
2017-01-24 21:09:58 +00:00
|
|
|
|
|
|
|
it 'returns the user grace period if lower than the application grace period' do
|
|
|
|
stub_application_setting two_factor_grace_period: 24
|
|
|
|
allow(controller).to receive(:current_user).and_return(user)
|
|
|
|
|
|
|
|
expect(subject).to eq 23
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns the application grace period if lower than the user grace period' do
|
|
|
|
stub_application_setting two_factor_grace_period: 22
|
|
|
|
allow(controller).to receive(:current_user).and_return(user)
|
|
|
|
|
|
|
|
expect(subject).to eq 22
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#two_factor_grace_period_expired?' do
|
|
|
|
subject { controller.send :two_factor_grace_period_expired? }
|
|
|
|
|
|
|
|
before do
|
|
|
|
allow(controller).to receive(:current_user).and_return(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns false if the user has not started their grace period yet' do
|
|
|
|
expect(subject).to be_falsey
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with grace period started' do
|
|
|
|
let(:user) { create :user, otp_grace_period_started_at: 2.hours.ago }
|
|
|
|
|
|
|
|
it 'returns true if the grace period has expired' do
|
|
|
|
allow(controller).to receive(:two_factor_grace_period).and_return(1)
|
|
|
|
|
|
|
|
expect(subject).to be_truthy
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns false if the grace period is still active' do
|
|
|
|
allow(controller).to receive(:two_factor_grace_period).and_return(3)
|
|
|
|
|
|
|
|
expect(subject).to be_falsey
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#two_factor_skippable' do
|
|
|
|
subject { controller.send :two_factor_skippable? }
|
|
|
|
|
|
|
|
before do
|
|
|
|
allow(controller).to receive(:current_user).and_return(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns false if 2FA is not required' do
|
|
|
|
allow(controller).to receive(:two_factor_authentication_required?).and_return(false)
|
|
|
|
|
|
|
|
expect(subject).to be_falsey
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns false if the user has already enabled 2FA' do
|
|
|
|
allow(controller).to receive(:two_factor_authentication_required?).and_return(true)
|
|
|
|
allow(user).to receive(:two_factor_enabled?).and_return(true)
|
|
|
|
|
|
|
|
expect(subject).to be_falsey
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns false if the 2FA grace period has expired' do
|
|
|
|
allow(controller).to receive(:two_factor_authentication_required?).and_return(true)
|
|
|
|
allow(user).to receive(:two_factor_enabled?).and_return(false)
|
|
|
|
allow(controller).to receive(:two_factor_grace_period_expired?).and_return(true)
|
|
|
|
|
|
|
|
expect(subject).to be_falsey
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns true otherwise' do
|
|
|
|
allow(controller).to receive(:two_factor_authentication_required?).and_return(true)
|
|
|
|
allow(user).to receive(:two_factor_enabled?).and_return(false)
|
|
|
|
allow(controller).to receive(:two_factor_grace_period_expired?).and_return(false)
|
|
|
|
|
|
|
|
expect(subject).to be_truthy
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#skip_two_factor?' do
|
|
|
|
subject { controller.send :skip_two_factor? }
|
|
|
|
|
|
|
|
it 'returns false if 2FA setup was not skipped' do
|
|
|
|
allow(controller).to receive(:session).and_return({})
|
|
|
|
|
|
|
|
expect(subject).to be_falsey
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with 2FA setup skipped' do
|
|
|
|
before do
|
2017-03-07 18:51:22 +00:00
|
|
|
allow(controller).to receive(:session).and_return({ skip_two_factor: 2.hours.from_now })
|
2017-01-24 21:09:58 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns false if the grace period has expired' do
|
|
|
|
Timecop.freeze(3.hours.from_now) do
|
|
|
|
expect(subject).to be_falsey
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns true if the grace period is still active' do
|
|
|
|
Timecop.freeze(1.hour.from_now) do
|
|
|
|
expect(subject).to be_truthy
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2014-06-21 09:18:57 +00:00
|
|
|
end
|