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