cartodb-4.42/spec/models/user_part_validation_and_authentication_spec.rb

535 lines
19 KiB
Ruby
Raw Permalink Normal View History

2024-04-06 13:25:13 +08:00
require_relative '../spec_helper'
require_relative 'user_shared_examples'
require 'helpers/user_part_helper'
describe User do
include UserPartHelper
include_context 'user spec configuration'
it "should only allow legal usernames" do
illegal_usernames = %w(si$mon 'sergio estella' j@vi sergio£££ simon_tokumine SIMON Simon jose.rilla -rilla rilla-)
legal_usernames = %w(simon javier-de-la-torre sergio-leiva sergio99)
illegal_usernames.each do |name|
@user.username = name
@user.valid?.should be_false
@user.errors[:username].should be_present
end
legal_usernames.each do |name|
@user.username = name
@user.valid?.should be_true
@user.errors[:username].should be_blank
end
end
it "should not allow a username in use by an organization" do
org = create_org('testusername', 10.megabytes, 1)
@user.username = org.name
@user.valid?.should be_false
@user.username = 'wadus'
@user.valid?.should be_true
end
describe "email validation" do
before(:all) do
EmailAddress::Config.configure(local_format: :conventional, host_validation: :mx)
end
after(:all) do
EmailAddress::Config.configure(local_format: :conventional, host_validation: :syntax)
end
it "disallows wrong domains" do
invalid_emails = ['pimpam@example.com',
'pimpam@ageval.dr',
'pimpam@qq.ocm',
'pimpam@aa.ww',
'pimpam@iu.eduy',
'pimpam@gmail.como',
'pimpam@namr.cim',
'pimpam@buffalo.edi']
invalid_emails.each do |email|
user = ::User.new(email: email)
user.valid?.should be_false
user.errors.should include :email
end
end
it 'disallows a wrong domain if the email changes' do
EmailAddress::Config.configure(local_format: :conventional, host_validation: :syntax)
user = create_user
EmailAddress::Config.configure(local_format: :conventional, host_validation: :mx)
user.email = 'email@wrongdomain.fake'
user.valid?.should be_false
user.errors.should include :email
end
it 'allows wrong domain if the email does not change' do
EmailAddress::Config.configure(local_format: :conventional, host_validation: :syntax)
user = create_user
EmailAddress::Config.configure(local_format: :conventional, host_validation: :mx)
user.name = 'new name'
user.valid?.should be_true
end
end
it "should validate that password is present if record is new and crypted_password is blank" do
user = ::User.new
user.username = "adminipop"
user.email = "adminipop@example.com"
user.valid?.should be_false
user.errors[:password].should be_present
another_user = new_user(user.values.merge(:password => "admin123"))
user.crypted_password = another_user.crypted_password
user.valid?.should be_true
user.save
# Let's ensure that crypted_password does not change
user_check = ::User[user.id]
user_check.crypted_password.should == another_user.crypted_password
user.password = nil
user.valid?.should be_true
user.destroy
end
it "should validate password presence and length" do
user = ::User.new
user.username = "adminipop"
user.email = "adminipop@example.com"
user.valid?.should be_false
user.errors[:password].should be_present
user.password = 'short'
user.valid?.should be_false
user.errors[:password].should be_present
user.password = 'manolo' * 11
user.valid?.should be_false
user.errors[:password].should be_present
end
it "should validate password is different than username" do
user = ::User.new
user.username = "adminipop"
user.email = "adminipop@example.com"
user.password = user.password_confirmation = "adminipop"
user.valid?.should be_false
user.errors[:password].should be_present
end
it "should validate password is not a common one" do
user = ::User.new
user.username = "adminipop"
user.email = "adminipop@example.com"
user.password = user.password_confirmation = '123456'
user.valid?.should be_false
user.errors[:password].should be_present
end
describe "#change_password" do
before(:all) do
@new_valid_password = '000123456'
@user3 = create_user(password: @user_password)
end
after(:all) do
@user3.destroy
end
it "updates crypted_password" do
initial_crypted_password = @user3.crypted_password
@user3.change_password(@user_password, @new_valid_password, @new_valid_password)
@user3.valid?.should eq true
@user3.save(raise_on_failure: true)
@user3.crypted_password.should_not eql initial_crypted_password
@user3.change_password(@new_valid_password, @user_password, @user_password)
@user3.save(raise_on_failure: true)
end
it "checks old password" do
@user3.change_password('aaabbb', @new_valid_password, @new_valid_password)
@user3.valid?.should eq false
@user3.errors.fetch(:old_password).nil?.should eq false
expect {
@user3.save(raise_on_failure: true)
}.to raise_exception(Sequel::ValidationFailed, /old_password Old password not valid/)
end
it "checks password confirmation" do
@user3.change_password(@user_password, 'aaabbb', 'bbbaaa')
@user3.valid?.should eq false
@user3.errors.fetch(:new_password).nil?.should eq false
expect {
@user3.save(raise_on_failure: true)
}.to raise_exception(Sequel::ValidationFailed, "new_password doesn't match confirmation")
end
it "can throw several errors" do
@user3.change_password('aaaaaa', 'aaabbb', 'bbbaaa')
@user3.valid?.should eq false
@user3.errors.fetch(:old_password).nil?.should eq false
@user3.errors.fetch(:new_password).nil?.should eq false
expected_errors = "old_password Old password not valid, new_password doesn't match confirmation"
expect {
@user3.save(raise_on_failure: true)
}.to raise_exception(Sequel::ValidationFailed, expected_errors)
end
it "checks minimal length" do
@user3.change_password(@user_password, 'tiny', 'tiny')
@user3.valid?.should eq false
@user3.errors.fetch(:new_password).nil?.should eq false
expect {
@user3.save(raise_on_failure: true)
}.to raise_exception(Sequel::ValidationFailed, "new_password must be at least 6 characters long")
end
it "checks maximal length" do
long_password = 'long' * 20
@user3.change_password(@user_password, long_password, long_password)
@user3.valid?.should eq false
@user3.errors.fetch(:new_password).nil?.should eq false
expect {
@user3.save(raise_on_failure: true)
}.to raise_exception(Sequel::ValidationFailed, "new_password must be at most 64 characters long")
end
it "checks that the new password is not nil" do
@user3.change_password(@user_password, nil, nil)
@user3.valid?.should eq false
@user3.errors.fetch(:new_password).nil?.should eq false
expect {
@user3.save(raise_on_failure: true)
}.to raise_exception(Sequel::ValidationFailed, "new_password can't be blank")
end
end
describe '#needs_password_confirmation?' do
it 'is true for a normal user' do
user = FactoryGirl.build(:carto_user, :google_sign_in => nil)
user.needs_password_confirmation?.should == true
user = FactoryGirl.build(:user, :google_sign_in => false)
user.needs_password_confirmation?.should == true
end
it 'is false for users that signed in with Google' do
user = FactoryGirl.build(:user, :google_sign_in => true)
user.needs_password_confirmation?.should == false
end
it 'is true for users that signed in with Google but changed the password' do
user = FactoryGirl.build(:user, :google_sign_in => true, :last_password_change_date => Time.now)
user.needs_password_confirmation?.should == true
end
it 'is false for users that were created with http authentication' do
user = FactoryGirl.build(:valid_user, last_password_change_date: nil)
Carto::UserCreation.stubs(:http_authentication).returns(stub(find_by_user_id: FactoryGirl.build(:user_creation)))
user.needs_password_confirmation?.should == false
end
end
describe '#password_expired?' do
before(:all) do
@organization_password = create_organization_with_owner
end
after(:all) do
@organization_password.destroy
end
before(:each) do
@github_user = FactoryGirl.build(:valid_user, github_user_id: 932847)
@google_user = FactoryGirl.build(:valid_user, google_sign_in: true)
@password_user = FactoryGirl.build(:valid_user)
@org_user = FactoryGirl.create(:valid_user,
account_type: 'ORGANIZATION USER',
organization: @organization_password)
end
it 'never expires without configuration' do
Cartodb.with_config(passwords: { 'expiration_in_d' => nil }) do
expect(@github_user.password_expired?).to be_false
expect(@google_user.password_expired?).to be_false
expect(@password_user.password_expired?).to be_false
expect(@org_user.password_expired?).to be_false
end
end
it 'never expires for users without password' do
Cartodb.with_config(passwords: { 'expiration_in_d' => 5 }) do
Delorean.jump(10.days)
expect(@github_user.password_expired?).to be_false
expect(@google_user.password_expired?).to be_false
Delorean.back_to_the_present
end
end
it 'expires for users with oauth and changed passwords' do
Cartodb.with_config(passwords: { 'expiration_in_d' => 5 }) do
@github_user.last_password_change_date = Time.now - 10.days
expect(@github_user.password_expired?).to be_true
@google_user.last_password_change_date = Time.now - 10.days
expect(@google_user.password_expired?).to be_true
end
end
it 'expires for password users after a while has passed' do
@password_user.save
Cartodb.with_config(passwords: { 'expiration_in_d' => 15 }) do
expect(@password_user.password_expired?).to be_false
Delorean.jump(30.days)
expect(@password_user.password_expired?).to be_true
@password_user.password = @password_user.password_confirmation = 'waduspass'
@password_user.save
expect(@password_user.password_expired?).to be_false
Delorean.jump(30.days)
expect(@password_user.password_expired?).to be_true
Delorean.back_to_the_present
end
@password_user.destroy
end
it 'expires for org users with password_expiration set' do
@organization_password.stubs(:password_expiration_in_d).returns(2)
org_user2 = FactoryGirl.create(:valid_user,
account_type: 'ORGANIZATION USER',
organization: @organization_password)
Cartodb.with_config(passwords: { 'expiration_in_d' => 5 }) do
expect(org_user2.password_expired?).to be_false
Delorean.jump(1.day)
expect(org_user2.password_expired?).to be_false
Delorean.jump(5.days)
expect(org_user2.password_expired?).to be_true
org_user2.password = org_user2.password_confirmation = 'waduspass'
org_user2.save
Delorean.jump(1.day)
expect(org_user2.password_expired?).to be_false
Delorean.jump(5.day)
expect(org_user2.password_expired?).to be_true
Delorean.back_to_the_present
end
end
it 'never expires for org users with no password_expiration set' do
@organization_password.stubs(:password_expiration_in_d).returns(nil)
org_user2 = FactoryGirl.create(:valid_user, organization: @organization_password)
Cartodb.with_config(passwords: { 'expiration_in_d' => 5 }) do
expect(org_user2.password_expired?).to be_false
Delorean.jump(10.days)
expect(org_user2.password_expired?).to be_false
org_user2.password = org_user2.password_confirmation = 'waduspass'
org_user2.save
Delorean.jump(10.days)
expect(org_user2.password_expired?).to be_false
Delorean.back_to_the_present
end
end
end
describe "when user is signed up with google sign-in and don't have any password yet" do
before(:each) do
@user.google_sign_in = true
@user.last_password_change_date = nil
@user.save
@user.needs_password_confirmation?.should == false
new_valid_password = '000123456'
@user.change_password("doesn't matter in this case", new_valid_password, new_valid_password)
@user.needs_password_confirmation?.should == true
end
it 'should allow updating password w/o a current password' do
@user.valid?.should eq true
@user.save
end
it 'should have updated last password change date' do
@user.last_password_change_date.should_not eq nil
@user.save
end
end
describe 'api keys' do
before(:all) do
@auth_api_user = FactoryGirl.create(:valid_user)
end
after(:all) do
@auth_api_user.destroy
end
describe 'create api keys on user creation' do
it "creates master api key on user creation" do
api_keys = Carto::ApiKey.where(user_id: @auth_api_user.id)
api_keys.should_not be_empty
master_api_key = Carto::ApiKey.where(user_id: @auth_api_user.id).master.first
master_api_key.should be
master_api_key.token.should eq @auth_api_user.api_key
end
end
it 'syncs api key changes with master api key' do
master_key = Carto::ApiKey.where(user_id: @auth_api_user.id).master.first
expect(@auth_api_user.api_key).to eq master_key.token
expect { @auth_api_user.regenerate_api_key }.to(change { @auth_api_user.api_key })
master_key.reload
expect(@auth_api_user.api_key).to eq master_key.token
end
describe 'are enabled/disabled' do
before(:all) do
@regular_key = @auth_api_user.api_keys.create_regular_key!(name: 'regkey', grants: [{ type: 'apis', apis: [] }])
end
after(:all) do
@regular_key.destroy
end
before(:each) do
@auth_api_user.state = 'active'
@auth_api_user.engine_enabled = true
@auth_api_user.save
end
def enabled_api_key?(api_key)
$users_metadata.exists(api_key.send(:redis_key))
end
it 'disables all api keys for locked users' do
@auth_api_user.state = 'locked'
@auth_api_user.save
expect(@auth_api_user.api_keys.none? { |k| enabled_api_key?(k) }).to be_true
expect(@auth_api_user.api_key).to_not eq($users_metadata.HGET(@auth_api_user.send(:key), 'map_key'))
end
it 'disables regular keys for engine disabled' do
@auth_api_user.engine_enabled = false
@auth_api_user.save
expect(@auth_api_user.api_keys.regular.none? { |k| enabled_api_key?(k) }).to be_true
expect(@auth_api_user.api_keys.master.all? { |k| enabled_api_key?(k) }).to be_true
expect(@auth_api_user.api_keys.default_public.all? { |k| enabled_api_key?(k) }).to be_true
expect(@auth_api_user.api_key).to eq($users_metadata.HGET(@auth_api_user.send(:key), 'map_key'))
end
it 'enables all keys for active engine users' do
expect(@auth_api_user.api_keys.all? { |k| enabled_api_key?(k) }).to be_true
expect(@auth_api_user.api_key).to eq($users_metadata.HGET(@auth_api_user.send(:key), 'map_key'))
end
end
describe '#regenerate_all_api_keys' do
before(:all) do
@regular_key = @auth_api_user.api_keys.create_regular_key!(name: 'regkey', grants: [{ type: 'apis', apis: [] }])
end
after(:all) do
@regular_key.destroy
end
it 'regenerates master key at user model' do
expect { @auth_api_user.regenerate_all_api_keys }.to(change { @auth_api_user.api_key })
end
it 'regenerates master key model' do
expect { @auth_api_user.regenerate_all_api_keys }.to(change { @auth_api_user.api_keys.master.first.token })
end
it 'regenerates regular key' do
expect { @auth_api_user.regenerate_all_api_keys }.to(change { @regular_key.reload.token })
end
end
describe '#has_feature_flag?' do
before :all do
@account_type_org = create_account_type_fg('ORGANIZATION USER')
@organization = FactoryGirl.create(:organization)
@owner = FactoryGirl.create(:user, account_type: @account_type_org)
uo = CartoDB::UserOrganization.new(@organization.id, @owner.id)
uo.promote_user_to_admin
@organization.reload
@user_org = FactoryGirl.build(:user, account_type: 'FREE')
@user_org.organization = @organization
@user_org.enabled = true
@user_org.save
@user_regu = FactoryGirl.create(:valid_user)
@ff_owner = create(:feature_flag, name: 'drop', restricted: true)
@ff_user = create(:feature_flag, name: 'drop-user', restricted: true)
@owner.activate_feature_flag!(@ff_owner)
@user_org.activate_feature_flag!(@ff_user)
@user_regu.activate_feature_flag!(@ff_user)
end
after :all do
@user_org.destroy!
@user_regu.destroy!
@owner.destroy!
@organization.destroy!
@account_type_org.destroy!
@ff_owner.destroy!
@ff_user.destroy!
end
it 'inherits feature flags from owner if inherit_owner_ffs' do
@organization.stubs(:inherit_owner_ffs).returns(true)
@user_org.has_feature_flag?('drop').should eq true
@user_org.has_feature_flag?('drop-user').should eq true
@user_org.feature_flags.count.should eq 2
end
it 'does not inherit feature flags from owner if not inherit_owner_ffs' do
@organization.stubs(:inherit_owner_ffs).returns(false)
@user_org.reload
@user_org.has_feature_flag?('drop').should eq false
@user_org.has_feature_flag?('drop-user').should eq true
@user_org.feature_flags.count.should eq 1
end
it 'does not inherit feature flags for regular users' do
@organization.stubs(:inherit_owner_ffs).returns(true)
@user_regu.reload
@user_regu.has_feature_flag?('drop').should eq false
@user_regu.has_feature_flag?('drop-user').should eq true
@user_regu.feature_flags.count.should eq 1
end
it 'does not inherit feature flags for owner' do
@organization.stubs(:inherit_owner_ffs).returns(true)
@owner.reload
@owner.has_feature_flag?('drop').should eq true
@owner.has_feature_flag?('drop-user').should eq false
@owner.feature_flags.count.should eq 1
end
end
end
end