cartodb-4.42/spec/requests/warden_spec.rb
2024-04-06 05:25:13 +00:00

392 lines
10 KiB
Ruby

require 'spec_helper_min'
require 'support/helpers'
describe 'Warden' do
def login
# Manual login because `login_as` skips normal warden hook processing
host! "#{@user.username}.localhost.lan"
post create_session_url(email: @user.email, password: @user.password)
end
def wrong_login
host! "#{@user.username}.localhost.lan"
post create_session_url(email: @user.email, password: 'bla')
end
def logout
# Manual login because `login_as` skips normal warden hook processing
host! "#{@user.username}.localhost.lan"
get logout_url
end
describe ':auth_api Strategy' do
include_context 'users helper'
include HelperMethods
def generate_api_key_url
api_keys_url(user_domain: @user_api_keys.username)
end
before :all do
@user_api_keys = FactoryGirl.create(:valid_user)
@master_api_key = Carto::ApiKey.where(user_id: @user_api_keys.id).master.first
end
after :all do
@user_api_keys.destroy
end
it 'authenticates with header' do
get_json generate_api_key_url, {}, http_json_headers.merge(
'Authorization' => 'Basic ' + Base64.strict_encode64("#{@user_api_keys.username}:#{@master_api_key.token}")
) do |response|
response.status.should eq 200
end
end
it 'returns 401 if header is missing' do
get_json generate_api_key_url, {}, http_json_headers do |response|
response.status.should eq 401
end
end
it 'returns 401 if header is malformed' do
get_json generate_api_key_url, {}, http_json_headers.merge(
'Authorization' => 'Basicss ' + Base64.encode64("#{@user_api_keys.username}:#{@master_api_key.token}")
) do |response|
response.status.should eq 401
end
end
it 'returns 401 if base64 is malforemd' do
get_json generate_api_key_url, {}, http_json_headers.merge(
'Authorization' => 'Basic ' + "asda2" + Base64.encode64("#{@user_api_keys.username}:#{@master_api_key.token}")
) do |response|
response.status.should eq 401
end
end
end
describe 'password expiration' do
include HelperMethods
before(:all) do
@user = FactoryGirl.create(:valid_user)
@user.password = @user.password_confirmation = '000qwaszx'
@user.save
end
after(:all) do
@user.destroy
end
let (:session_expired_message) { 'Your session has expired' }
it 'allows access for non-expired session' do
# we use this to avoid generating the static assets in CI
Admin::VisualizationsController.any_instance.stubs(:render).returns('')
Cartodb.with_config(passwords: { 'expiration_in_d' => nil }) do
login
host! "#{@user.username}.localhost.lan"
get dashboard_url
expect(response.status).to eq 200
end
end
it 'UI redirects to login page if password is expired' do
Cartodb::Central.any_instance.stubs(:send_request)
login
Cartodb.with_config(passwords: { 'expiration_in_d' => 1 }) do
Delorean.jump(2.days)
host! "#{@user.username}.localhost.lan"
get dashboard_url
expect(response.status).to eq 302
follow_redirect!
expect(request.fullpath).to end_with "/login?error=session_expired"
Delorean.back_to_the_present
end
end
it 'redirects to the original url after changing the expired password' do
# we use this to avoid generating the static assets in CI
Admin::VisualizationsController.any_instance.stubs(:render).returns('')
Cartodb::Central.any_instance.stubs(:send_request)
login
Cartodb.with_config(passwords: { 'expiration_in_d' => 1 }) do
Delorean.jump(2.days)
get notifications_url
follow_redirect!
login
follow_redirect!
change_password_payload = {
username: @user.username, old_password: @user.password, password: 'pass123', password_confirmation: 'pass123'
}
put password_change_url(@user.username), change_password_payload
follow_redirect!
request.path.should eq notifications_path
Delorean.back_to_the_present
end
@user.password = @user.password_confirmation = '000qwaszx'
@user.save
end
it 'API returns 403 with an error if password is expired' do
Cartodb::Central.any_instance.stubs(:send_request)
login
Cartodb.with_config(passwords: { 'expiration_in_d' => 1 }) do
Delorean.jump(2.days)
host! "#{@user.username}.localhost.lan"
get_json api_v3_users_me_url
expect(response.status).to eq 403
expect(JSON.parse(response.body)).to eq('error' => 'session_expired')
Delorean.back_to_the_present
end
end
it 'does not allow access password_change if password is not expired' do
login
Cartodb.with_config(passwords: { 'expiration_in_d' => nil }) do
host! "#{@user.username}.localhost.lan"
get edit_password_change_path(@user.username)
expect(response.status).to eq 403
end
end
it 'does not validate password expiration for API-key requests' do
Cartodb.with_config(passwords: { 'expiration_in_d' => 1 }) do
Delorean.jump(2.days)
get_json api_v3_users_me_url, user_domain: @user.username, api_key: @user.api_key do |response|
expect(response.status).to eq 200
expect(response.body[:user_data]).to be
end
Delorean.back_to_the_present
end
end
end
shared_examples_for 'login locked' do
include HelperMethods
before(:each) do
SessionsController.any_instance.stubs(:central_enabled?).returns(false)
# we use this to avoid generating the static assets in CI
Admin::VisualizationsController.any_instance.stubs(:render).returns('')
end
def expect_password_locked
expect(response.status).to eq 302
follow_redirect!
expect(request.fullpath).to include "/login?error=password_locked"
expect(response.body).to include "Too many failed login attempts"
end
def expect_login
host! "#{@user.username}.localhost.lan"
get dashboard_url
expect(response.status).to eq 200
end
it 'redirects to login page with an error if password is locked' do
Cartodb.with_config(
passwords: {
'rate_limit' => {
'max_burst' => 0,
'count' => 1,
'period' => 60
}
}
) do
@user.reset_password_rate_limit
wrong_login
wrong_login
expect_password_locked
end
end
it 'allows to login after the locked password period' do
Cartodb.with_config(
passwords: {
'rate_limit' => {
'max_burst' => 0,
'count' => 1,
'period' => 1
}
}
) do
@user.reset_password_rate_limit
wrong_login
wrong_login
expect_password_locked
sleep(3)
login
expect_login
end
end
it 'does not allow to login during the locked password period' do
Cartodb.with_config(
passwords: {
'rate_limit' => {
'max_burst' => 0,
'count' => 1,
'period' => 10
}
}
) do
@user.reset_password_rate_limit
wrong_login
wrong_login
login
expect_password_locked
end
end
it 'allows to login if password is changed' do
Cartodb.with_config(
passwords: {
'rate_limit' => {
'max_burst' => 0,
'count' => 2,
'period' => 10
}
}
) do
@user.reset_password_rate_limit
wrong_login
wrong_login
expect_password_locked
old_password = @user.password
new_password = '00012345678'
@user.password = @user.password_confirmation = new_password
@user.save
login
expect_login
@user.password = @user.password_confirmation = old_password
@user.save
end
end
end
describe 'with Sequel user' do
it_behaves_like 'login locked' do
before(:all) do
@user = FactoryGirl.create(:user, password: '000qwaszx', password_confirmation: '000qwaszx')
end
after(:all) do
@user.destroy
end
end
end
describe 'with AR user' do
it_behaves_like 'login locked' do
before(:all) do
@user = FactoryGirl.create(:carto_user, password: '000qwaszx', password_confirmation: '000qwaszx')
end
after(:all) do
@user.destroy
end
end
end
describe 'session' do
before(:all) do
@user = FactoryGirl.create(:valid_user)
end
before(:each) do
Cartodb::Central.stubs(:sync_data_with_cartodb_central?).returns(true)
Cartodb::Central.any_instance.stubs(:send_request)
end
after(:all) do
@user.destroy
end
after(:each) do
Cartodb::Central.unstub(:sync_data_with_cartodb_central?)
Cartodb::Central.any_instance.unstub(:send_request)
end
it 'should be valid for current security token ' do
# we use this to avoid generating the static assets in CI
Admin::VisualizationsController.any_instance.stubs(:render).returns('')
login
cookies["_cartodb_session"] = response.cookies["_cartodb_session"]
get dashboard_url
response.status.should == 200
end
# Skip until invalid session forces a new login
xit 'should not be valid for different security token' do
login
@user.session_salt = "1234567f"
@user.save
get account_user_url
response.status.should == 302
request.fullpath.should eql '/account'
follow_redirect!
response.status.should == 200
request.fullpath.should eql '/login'
end
it 'updates the session_salt at logout' do
initial_session_salt = @user.session_salt
logout
initial_session_salt.should_not == @user.reload.session_salt
end
it 'updates the user in Central at logout' do
Cartodb::Central.any_instance.expects(:send_request).once
logout
end
end
end