cartodb/spec/models/carto/user_multifactor_auth_spec.rb
2020-06-15 10:58:47 +08:00

157 lines
5.1 KiB
Ruby

require 'spec_helper_min'
describe Carto::UserMultifactorAuth do
def totp_code(mfa)
ROTP::TOTP.new(mfa.shared_secret).now
end
before :all do
@valid_type = 'totp'
@carto_user = FactoryGirl.create(:carto_user)
end
before :each do
Cartodb::Central.stubs(:sync_data_with_cartodb_central?).returns(false)
@carto_user.reload.user_multifactor_auths.each(&:destroy!)
end
after :all do
@carto_user.destroy!
end
describe '#create' do
it 'does not validate an unsupported multi-factor authentication type' do
mfa = Carto::UserMultifactorAuth.new(user_id: @carto_user.id, type: 'wadus')
mfa.valid?.should eq(false)
end
it 'validates supported multi-factor authentication types' do
mfa = Carto::UserMultifactorAuth.new(user_id: @carto_user.id, type: @valid_type)
expect { mfa.valid? }.to be_true
end
it 'creates a new multifactor auth for a user' do
expect {
Carto::UserMultifactorAuth.create!(user_id: @carto_user.id, type: @valid_type)
}.to_not raise_error
end
it 'populates shared_secret' do
mfa = Carto::UserMultifactorAuth.create!(user_id: @carto_user.id, type: @valid_type)
expect { mfa.shared_secret }.to_not be_nil
end
it 'is disabled by default' do
mfa = Carto::UserMultifactorAuth.create!(user_id: @carto_user.id, type: @valid_type)
expect { mfa.disabled? }.to be_true
end
it 'syncs to central' do
Cartodb::Central.stubs(:sync_data_with_cartodb_central?).returns(true)
Cartodb::Central
.any_instance
.expects(:update_user)
.with(@carto_user.username,
has_entries(multifactor_authentication_status: User::MULTIFACTOR_AUTHENTICATION_NEEDS_SETUP))
.once
Carto::UserMultifactorAuth.create!(user_id: @carto_user.id, type: @valid_type)
end
end
describe '#update' do
it 'syncs enabled to central' do
mfa = Carto::UserMultifactorAuth.create!(user_id: @carto_user.id, type: @valid_type)
Cartodb::Central.stubs(:sync_data_with_cartodb_central?).returns(true)
Cartodb::Central
.any_instance
.expects(:update_user)
.with(@carto_user.username,
has_entries(multifactor_authentication_status: User::MULTIFACTOR_AUTHENTICATION_ENABLED))
.once
mfa.enabled = true
mfa.save!
end
it 'syncs needs setup to central' do
mfa = Carto::UserMultifactorAuth.create!(user_id: @carto_user.id, type: @valid_type, enabled: true)
Cartodb::Central.stubs(:sync_data_with_cartodb_central?).returns(true)
Cartodb::Central
.any_instance
.expects(:update_user)
.with(@carto_user.username,
has_entries(multifactor_authentication_status: User::MULTIFACTOR_AUTHENTICATION_NEEDS_SETUP))
.once
mfa.enabled = false
mfa.save!
end
it 'syncs disabled to central' do
mfa = Carto::UserMultifactorAuth.create!(user_id: @carto_user.id, type: @valid_type)
Cartodb::Central.stubs(:sync_data_with_cartodb_central?).returns(true)
Cartodb::Central
.any_instance
.expects(:update_user)
.with(@carto_user.username,
has_entries(multifactor_authentication_status: User::MULTIFACTOR_AUTHENTICATION_DISABLED))
.once
mfa.destroy!
end
end
describe '#verify!' do
it 'verifies a valid code' do
mfa = Carto::UserMultifactorAuth.create!(user_id: @carto_user.id, type: @valid_type)
code = totp_code(mfa)
mfa.verify!(code)
expect { mfa.enabled }.to be_true
end
it 'does not allow reuse of a valid code' do
mfa = Carto::UserMultifactorAuth.create!(user_id: @carto_user.id, type: @valid_type)
code = totp_code(mfa)
mfa.verify!(code)
expect { mfa.verify!(code) }.to raise_error("The code is not valid")
end
it 'does not verify an invalid code' do
mfa = Carto::UserMultifactorAuth.create!(user_id: @carto_user.id, type: @valid_type)
totp = ROTP::TOTP.new(ROTP::Base32.random_base32)
expect { mfa.verify!(totp.now) }.to raise_error("The code is not valid")
end
it 'does not allow use of future/past tokens' do
mfa = Carto::UserMultifactorAuth.create!(user_id: @carto_user.id, type: @valid_type)
totp = ROTP::TOTP.new(mfa.shared_secret)
expect { mfa.verify!(totp.at(Time.now - 90.seconds)) }.to raise_error("The code is not valid")
end
it 'verifies a code taking into account 30 seconds drift' do
mfa = Carto::UserMultifactorAuth.create!(user_id: @carto_user.id, type: @valid_type)
totp = ROTP::TOTP.new(mfa.shared_secret)
expect { mfa.verify!(totp.at(Time.now - 30.seconds)) }.to be_true
end
end
describe '#provisioning_uri' do
before :each do
@multifactor_auth = FactoryGirl.create(:totp, :active, user: @carto_user)
end
after :each do
@multifactor_auth.destroy!
end
it 'provides a provisioning_uri' do
uri = "otpauth://totp/CARTO:#{@carto_user.username}?secret=#{@multifactor_auth.shared_secret}&issuer=CARTO"
@multifactor_auth.provisioning_uri.should eq uri
end
end
end