739 lines
28 KiB
Ruby
739 lines
28 KiB
Ruby
|
require 'spec_helper_min'
|
||
|
require 'helpers/database_connection_helper'
|
||
|
|
||
|
module Carto
|
||
|
describe OauthAppUser do
|
||
|
include_context 'organization with users helper'
|
||
|
include CartoDB::Factories
|
||
|
include DatabaseConnectionHelper
|
||
|
|
||
|
describe 'validation' do
|
||
|
before(:all) do
|
||
|
user = FactoryGirl.create(:valid_user)
|
||
|
@user = Carto::User.find(user.id)
|
||
|
@app = FactoryGirl.create(:oauth_app, user: @user)
|
||
|
end
|
||
|
|
||
|
after(:all) do
|
||
|
@user.destroy
|
||
|
@app.destroy
|
||
|
end
|
||
|
|
||
|
it 'requires user' do
|
||
|
app_user = OauthAppUser.new
|
||
|
expect(app_user).to_not(be_valid)
|
||
|
expect(app_user.errors[:user]).to(include("can't be blank"))
|
||
|
end
|
||
|
|
||
|
it 'requires oauth app_user' do
|
||
|
app_user = OauthAppUser.new
|
||
|
expect(app_user).to_not(be_valid)
|
||
|
expect(app_user.errors[:oauth_app]).to(include("can't be blank"))
|
||
|
end
|
||
|
|
||
|
it 'does not allow duplicates' do
|
||
|
begin
|
||
|
@app_user1 = OauthAppUser.create!(user: @user, oauth_app: @app)
|
||
|
app_user2 = OauthAppUser.new(user: @user, oauth_app: @app)
|
||
|
expect(app_user2).to_not(be_valid)
|
||
|
expect(app_user2.errors[:user]).to(include("has already been taken"))
|
||
|
ensure
|
||
|
@app_user1.destroy if @app_user1
|
||
|
end
|
||
|
end
|
||
|
|
||
|
it 'does not accept invalid scopes' do
|
||
|
app_user = OauthAppUser.new(scopes: ['wadus'])
|
||
|
expect(app_user).to_not(be_valid)
|
||
|
expect(app_user.errors[:scopes]).to(include("contains unsupported scopes: wadus"))
|
||
|
end
|
||
|
|
||
|
it 'validates' do
|
||
|
app_user = OauthAppUser.new(user: @user, oauth_app: @app)
|
||
|
expect(app_user).to(be_valid)
|
||
|
end
|
||
|
|
||
|
describe 'restricted app' do
|
||
|
before(:all) do
|
||
|
@app.update!(restricted: true)
|
||
|
end
|
||
|
|
||
|
before(:each) do
|
||
|
@app.oauth_app_organizations.each(&:destroy!)
|
||
|
@app.oauth_app_organizations.create!(organization: @carto_organization, seats: 1)
|
||
|
end
|
||
|
|
||
|
after(:all) do
|
||
|
@app.destroy
|
||
|
end
|
||
|
|
||
|
it 'does not accept non-organization users' do
|
||
|
app_user = OauthAppUser.new(user: @user, oauth_app: @app)
|
||
|
expect(app_user).not_to(be_valid)
|
||
|
expect(app_user.errors[:user]).to(include("is not part of an organization"))
|
||
|
end
|
||
|
|
||
|
it 'does not accept users from unknown organizations' do
|
||
|
@app.oauth_app_organizations.each(&:destroy!)
|
||
|
@app.oauth_app_organizations.create!(organization: @carto_organization_2, seats: 1)
|
||
|
|
||
|
app_user = OauthAppUser.new(user: @carto_org_user_1, oauth_app: @app)
|
||
|
expect(app_user).not_to(be_valid)
|
||
|
expect(app_user.errors[:user]).to(include("is part of an organization which is not allowed access to this application"))
|
||
|
end
|
||
|
|
||
|
it 'accepts users from the authorized organization' do
|
||
|
app_user = OauthAppUser.new(user: @carto_org_user_1, oauth_app: @app)
|
||
|
expect(app_user).to(be_valid)
|
||
|
end
|
||
|
|
||
|
it 'does not accepts users over the seat limit' do
|
||
|
OauthAppUser.create!(user: @carto_org_user_1, oauth_app: @app)
|
||
|
app_user = OauthAppUser.new(user: @carto_org_user_2, oauth_app: @app)
|
||
|
expect(app_user).not_to(be_valid)
|
||
|
expect(app_user.errors[:user]).to(include("does not have an available seat to use this application"))
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe '#authorized?' do
|
||
|
before(:all) do
|
||
|
@user = FactoryGirl.create(:valid_user)
|
||
|
@carto_user = Carto::User.find(@user.id)
|
||
|
end
|
||
|
|
||
|
before(:each) do
|
||
|
@app = FactoryGirl.create(:oauth_app, user: @carto_user)
|
||
|
@t1 = create_table(user_id: @carto_user.id)
|
||
|
@t2 = create_table(user_id: @carto_user.id)
|
||
|
end
|
||
|
|
||
|
after(:each) do
|
||
|
@t1.destroy
|
||
|
@t2.destroy
|
||
|
@app.destroy
|
||
|
end
|
||
|
|
||
|
after(:all) do
|
||
|
@user.destroy
|
||
|
@carto_user.destroy
|
||
|
end
|
||
|
|
||
|
it 'is authorized only if all requested scopes are already granted' do
|
||
|
o1 = "datasets:rw:#{@carto_user.database_schema}.#{@t1.name}"
|
||
|
o2 = "datasets:rw:#{@carto_user.database_schema}.#{@t2.name}"
|
||
|
o3 = "schemas:c:#{@carto_user.database_schema}"
|
||
|
|
||
|
oau = OauthAppUser.create!(user: @carto_user, oauth_app: @app, scopes: [o1, o2, o3])
|
||
|
|
||
|
expect(oau).to(be_authorized([o1]))
|
||
|
expect(oau).to(be_authorized([o2]))
|
||
|
expect(oau).to(be_authorized([o3]))
|
||
|
expect(oau).to(be_authorized([o1, o2, o3]))
|
||
|
|
||
|
expect(oau).not_to(be_authorized(['not_allowed']))
|
||
|
expect(oau).not_to(be_authorized([o1, 'not_allowed']))
|
||
|
end
|
||
|
|
||
|
it 'should be authorized if requesting read permission having read-write' do
|
||
|
write_read = "datasets:rw:#{@t1.name}"
|
||
|
read = "datasets:r:#{@t1.name}"
|
||
|
|
||
|
oau = OauthAppUser.create!(user: @carto_user, oauth_app: @app, scopes: [write_read])
|
||
|
|
||
|
expect(oau).to(be_authorized([read]))
|
||
|
end
|
||
|
|
||
|
it 'should NOT be authorized if requesting read-write permission having only read' do
|
||
|
write_read = "datasets:rw:#{@t1.name}"
|
||
|
read = "datasets:r:#{@t1.name}"
|
||
|
|
||
|
oau = OauthAppUser.create!(user: @carto_user, oauth_app: @app, scopes: [read])
|
||
|
|
||
|
expect(oau).not_to(be_authorized([write_read]))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe '#upgrade!' do
|
||
|
before(:all) do
|
||
|
@user = FactoryGirl.create(:valid_user)
|
||
|
@carto_user = Carto::User.find(@user.id)
|
||
|
@app = FactoryGirl.create(:oauth_app, user: @carto_user)
|
||
|
@t1 = create_table(user_id: @carto_user.id)
|
||
|
@t2 = create_table(user_id: @carto_user.id)
|
||
|
@t3 = create_table(user_id: @carto_user.id)
|
||
|
@t4 = create_table(user_id: @carto_user.id)
|
||
|
end
|
||
|
|
||
|
after(:all) do
|
||
|
@t1.destroy
|
||
|
@t2.destroy
|
||
|
@t3.destroy
|
||
|
@t4.destroy
|
||
|
@app.destroy
|
||
|
@user.destroy
|
||
|
@carto_user.destroy
|
||
|
end
|
||
|
|
||
|
it 'grants all new scopes without duplicates' do
|
||
|
o1 = "datasets:rw:#{@t1.name}"
|
||
|
o2 = "datasets:rw:#{@t2.name}"
|
||
|
o3 = "datasets:rw:#{@t3.name}"
|
||
|
o4 = "datasets:rw:#{@t4.name}"
|
||
|
o5 = "schemas:c:#{@carto_user.database_schema}"
|
||
|
|
||
|
oau = OauthAppUser.create!(user: @carto_user, oauth_app: @app, scopes: [o1, o2])
|
||
|
|
||
|
oau.upgrade!([])
|
||
|
expect(oau.scopes).to(match_array([o1, o2]))
|
||
|
|
||
|
oau.upgrade!([o1])
|
||
|
expect(oau.scopes).to(match_array([o1, o2]))
|
||
|
|
||
|
oau.upgrade!([o3])
|
||
|
expect(oau.scopes).to(match_array([o1, o2, o3]))
|
||
|
|
||
|
oau.upgrade!([o2, o4])
|
||
|
expect(oau.scopes).to(match_array([o1, o2, o3, o4]))
|
||
|
|
||
|
oau.upgrade!([])
|
||
|
expect(oau.scopes).to(match_array([o1, o2, o3, o4]))
|
||
|
|
||
|
oau.upgrade!([o5])
|
||
|
expect(oau.scopes).to(match_array([o1, o2, o3, o4, o5]))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe 'datasets scope' do
|
||
|
before(:each) do
|
||
|
@user = FactoryGirl.create(:valid_user)
|
||
|
@carto_user = Carto::User.find(@user.id)
|
||
|
@app = FactoryGirl.create(:oauth_app, user: @carto_user)
|
||
|
@table1 = create_table(user_id: @carto_user.id)
|
||
|
end
|
||
|
|
||
|
after(:each) do
|
||
|
@table1.destroy
|
||
|
@app.destroy
|
||
|
@user.destroy
|
||
|
@carto_user.destroy
|
||
|
end
|
||
|
|
||
|
it 'creation and update' do
|
||
|
table2 = create_table(user_id: @carto_user.id)
|
||
|
dataset_scope1 = "datasets:rw:#{@table1.name}"
|
||
|
dataset_scope2 = "datasets:r:#{table2.name}"
|
||
|
scopes = ['user:profile', dataset_scope1, dataset_scope2]
|
||
|
|
||
|
oau = OauthAppUser.create!(user: @carto_user, oauth_app: @app, scopes: scopes)
|
||
|
expect(oau.scopes).to(match_array(scopes))
|
||
|
|
||
|
oau.upgrade!([])
|
||
|
expect(oau.scopes).to(match_array(scopes))
|
||
|
|
||
|
oau.upgrade!([dataset_scope1])
|
||
|
expect(oau.scopes).to(match_array(scopes))
|
||
|
|
||
|
table2.destroy
|
||
|
oau.destroy
|
||
|
end
|
||
|
|
||
|
it 'rename table and check how it affects the scopes' do
|
||
|
scopes_before = ['user:profile', "datasets:rw:#{@table1.name}"]
|
||
|
oau = OauthAppUser.create!(user: @carto_user, oauth_app: @app, scopes: scopes_before)
|
||
|
expect(oau.all_scopes).to(match_array(scopes_before))
|
||
|
|
||
|
@table1.name = 'table_renamed_' + @table1.name
|
||
|
@table1.save
|
||
|
|
||
|
expect(oau.all_scopes).to_not(match_array(scopes_before))
|
||
|
|
||
|
scopes_after = ['user:profile', "datasets:rw:#{@table1.name}"]
|
||
|
expect(oau.all_scopes).to(match_array(scopes_after))
|
||
|
|
||
|
oau.destroy
|
||
|
end
|
||
|
|
||
|
it 'write on table with the proper permissions' do
|
||
|
scopes_before = ['user:profile', "datasets:rw:#{@table1.name}"]
|
||
|
oau = OauthAppUser.create!(user: @carto_user, oauth_app: @app, scopes: scopes_before)
|
||
|
expect(oau.all_scopes).to(match_array(scopes_before))
|
||
|
access_token = OauthAccessToken.create!(oauth_app_user: oau, scopes: scopes_before)
|
||
|
|
||
|
with_connection_from_api_key(access_token.api_key) do |connection|
|
||
|
connection.execute("insert into #{@table1.name} (cartodb_id) values (999)")
|
||
|
connection.execute("select cartodb_id from #{@table1.name}") do |result|
|
||
|
result[0]['cartodb_id'].should eq '999'
|
||
|
end
|
||
|
end
|
||
|
|
||
|
oau.destroy
|
||
|
end
|
||
|
|
||
|
it 'should fail if we change the write permissions and we try to write in the table' do
|
||
|
scopes_before = ['offline', 'user:profile', "datasets:rw:#{@table1.name}"]
|
||
|
scopes_after = ['offline', 'user:profile']
|
||
|
oau = OauthAppUser.create!(user: @carto_user, oauth_app: @app, scopes: scopes_before)
|
||
|
expect(oau.all_scopes).to(match_array(scopes_before))
|
||
|
refresh_token = oau.oauth_refresh_tokens.create!(scopes: scopes_before)
|
||
|
access_token = refresh_token.exchange!(requested_scopes: scopes_before)[0]
|
||
|
|
||
|
with_connection_from_api_key(access_token.api_key) do |connection|
|
||
|
connection.execute("insert into #{@table1.name} (cartodb_id) values (999)")
|
||
|
connection.execute("select cartodb_id from #{@table1.name}") do |result|
|
||
|
result[0]['cartodb_id'].should eq '999'
|
||
|
end
|
||
|
end
|
||
|
|
||
|
access_token_new = refresh_token.exchange!(requested_scopes: scopes_after)[0]
|
||
|
expect(access_token.api_key.db_role).to_not(eq(access_token_new.api_key.db_role))
|
||
|
with_connection_from_api_key(access_token_new.api_key) do |connection|
|
||
|
expect {
|
||
|
connection.execute("insert into #{@table1.name} (cartodb_id) values (1000)")
|
||
|
}.to raise_exception(Sequel::DatabaseError, /permission denied for (relation|table) #{@table1.name}/)
|
||
|
end
|
||
|
|
||
|
oau.destroy
|
||
|
end
|
||
|
|
||
|
it 'should let downgrade scope for datasets from rw to r scope' do
|
||
|
scopes_before = ['offline', 'user:profile', "datasets:rw:#{@table1.name}"]
|
||
|
scopes_after = ['offline', 'user:profile', "datasets:r:#{@table1.name}"]
|
||
|
oau = OauthAppUser.create!(user: @carto_user, oauth_app: @app, scopes: scopes_before)
|
||
|
expect(oau.all_scopes).to(match_array(scopes_before))
|
||
|
refresh_token = oau.oauth_refresh_tokens.create!(scopes: scopes_before)
|
||
|
access_token = refresh_token.exchange!(requested_scopes: scopes_before)[0]
|
||
|
|
||
|
with_connection_from_api_key(access_token.api_key) do |connection|
|
||
|
connection.execute("insert into #{@table1.name} (cartodb_id) values (999)")
|
||
|
connection.execute("select cartodb_id from #{@table1.name}") do |result|
|
||
|
result[0]['cartodb_id'].should eq '999'
|
||
|
end
|
||
|
end
|
||
|
|
||
|
access_token_new = refresh_token.exchange!(requested_scopes: scopes_after)[0]
|
||
|
expect(access_token.api_key.db_role).to_not(eq(access_token_new.api_key.db_role))
|
||
|
with_connection_from_api_key(access_token_new.api_key) do |connection|
|
||
|
connection.execute("select cartodb_id from #{@table1.name}") do |result|
|
||
|
result[0]['cartodb_id'].should eq '999'
|
||
|
end
|
||
|
expect {
|
||
|
connection.execute("insert into #{@table1.name} (cartodb_id) values (999)")
|
||
|
}.to raise_exception(Sequel::DatabaseError, /permission denied for (relation|table) #{@table1.name}/)
|
||
|
end
|
||
|
|
||
|
oau.destroy
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
describe 'schemas scope' do
|
||
|
before(:all) do
|
||
|
@user = FactoryGirl.create(:valid_user)
|
||
|
@carto_user = Carto::User.find(@user.id)
|
||
|
@app = FactoryGirl.create(:oauth_app, user: @carto_user)
|
||
|
@table1 = create_table(user_id: @carto_user.id)
|
||
|
@table2 = create_table(user_id: @carto_user.id)
|
||
|
end
|
||
|
|
||
|
after(:all) do
|
||
|
@table1.destroy
|
||
|
@table2.destroy
|
||
|
@app.destroy
|
||
|
@user.destroy
|
||
|
@carto_user.destroy
|
||
|
end
|
||
|
|
||
|
it 'creation and update' do
|
||
|
table2 = create_table(user_id: @carto_user.id)
|
||
|
dataset_scope1 = "datasets:rw:#{@table1.name}"
|
||
|
dataset_scope2 = "datasets:r:#{table2.name}"
|
||
|
scopes = ['user:profile', dataset_scope1, dataset_scope2]
|
||
|
|
||
|
oau = OauthAppUser.create!(user: @carto_user, oauth_app: @app, scopes: scopes)
|
||
|
expect(oau.scopes).to(match_array(scopes))
|
||
|
|
||
|
oau.upgrade!([])
|
||
|
expect(oau.scopes).to(match_array(scopes))
|
||
|
|
||
|
oau.upgrade!([dataset_scope1])
|
||
|
expect(oau.scopes).to(match_array(scopes))
|
||
|
|
||
|
table2.destroy
|
||
|
oau.destroy
|
||
|
end
|
||
|
|
||
|
it 'create table with permissions should work and assign it to the owner_role' do
|
||
|
schemas_scope = "schemas:c"
|
||
|
scopes = ['user:profile', schemas_scope]
|
||
|
|
||
|
oau = OauthAppUser.create!(user: @carto_user, oauth_app: @app, scopes: scopes)
|
||
|
expect(oau.scopes).to(match_array(scopes))
|
||
|
access_token = OauthAccessToken.create!(oauth_app_user: oau, scopes: scopes)
|
||
|
|
||
|
with_connection_from_api_key(access_token.api_key) do |connection|
|
||
|
connection.execute("create table test_table as select 1 as test")
|
||
|
connection.execute("select count(1) from test_table") do |result|
|
||
|
result[0]['count'].should eq '1'
|
||
|
end
|
||
|
connection.execute("select pg_catalog.pg_get_userbyid(relowner) as owner from pg_class where relname = 'test_table'") do |result|
|
||
|
result[0]['owner'].should eq oau.ownership_role_name
|
||
|
end
|
||
|
connection.execute("drop table test_table")
|
||
|
end
|
||
|
|
||
|
oau.destroy
|
||
|
end
|
||
|
|
||
|
it 'create table without permissions should fail' do
|
||
|
scopes = ['user:profile']
|
||
|
|
||
|
oau = OauthAppUser.create!(user: @carto_user, oauth_app: @app, scopes: scopes)
|
||
|
expect(oau.scopes).to(match_array(scopes))
|
||
|
access_token = OauthAccessToken.create!(oauth_app_user: oau, scopes: scopes)
|
||
|
|
||
|
with_connection_from_api_key(access_token.api_key) do |connection|
|
||
|
expect {
|
||
|
connection.execute("create table test_table as select 1 as test")
|
||
|
}.to raise_exception(Sequel::DatabaseError, /permission denied for schema public/)
|
||
|
end
|
||
|
|
||
|
oau.destroy
|
||
|
end
|
||
|
|
||
|
it 'create table with permission, then refresh token and drop the table with the new db role' do
|
||
|
schemas_scope = "schemas:c"
|
||
|
scopes = ['offline', 'user:profile', schemas_scope]
|
||
|
|
||
|
oau = OauthAppUser.create!(user: @carto_user, oauth_app: @app, scopes: scopes)
|
||
|
expect(oau.scopes).to(match_array(scopes))
|
||
|
refresh_token = oau.oauth_refresh_tokens.create!(scopes: scopes)
|
||
|
access_token = refresh_token.exchange!(requested_scopes: scopes)[0]
|
||
|
|
||
|
with_connection_from_api_key(access_token.api_key) do |connection|
|
||
|
connection.execute("create table test_table as select 1 as test")
|
||
|
connection.execute("select count(1) from test_table") do |result|
|
||
|
result[0]['count'].should eq '1'
|
||
|
end
|
||
|
connection.execute("select pg_catalog.pg_get_userbyid(relowner) as owner from pg_class where relname = 'test_table'") do |result|
|
||
|
result[0]['owner'].should eq oau.ownership_role_name
|
||
|
end
|
||
|
end
|
||
|
|
||
|
access_token_new = refresh_token.exchange!(requested_scopes: scopes)[0]
|
||
|
expect(access_token.api_key.db_role).to_not(eq(access_token_new.api_key.db_role))
|
||
|
with_connection_from_api_key(access_token_new.api_key) do |connection|
|
||
|
connection.execute("drop table test_table")
|
||
|
end
|
||
|
|
||
|
oau.destroy
|
||
|
end
|
||
|
|
||
|
it 'create table with permission, then refresh token and remove permission, then try to create another table and get exception' do
|
||
|
schemas_scope = "schemas:c"
|
||
|
scopes = ['offline', 'user:profile', schemas_scope]
|
||
|
|
||
|
oau = OauthAppUser.create!(user: @carto_user, oauth_app: @app, scopes: scopes)
|
||
|
expect(oau.scopes).to(match_array(scopes))
|
||
|
refresh_token = oau.oauth_refresh_tokens.create!(scopes: scopes)
|
||
|
access_token = refresh_token.exchange!(requested_scopes: scopes)[0]
|
||
|
|
||
|
with_connection_from_api_key(access_token.api_key) do |connection|
|
||
|
connection.execute("create table test_table as select 1 as test")
|
||
|
connection.execute("select count(1) from test_table") do |result|
|
||
|
result[0]['count'].should eq '1'
|
||
|
end
|
||
|
connection.execute("select pg_catalog.pg_get_userbyid(relowner) as owner from pg_class where relname = 'test_table'") do |result|
|
||
|
result[0]['owner'].should eq oau.ownership_role_name
|
||
|
end
|
||
|
connection.execute("drop table test_table")
|
||
|
end
|
||
|
|
||
|
access_token_new = refresh_token.exchange!(requested_scopes: ['offline', 'user:profile'])[0]
|
||
|
expect(access_token.api_key.db_role).to_not(eq(access_token_new.api_key.db_role))
|
||
|
with_connection_from_api_key(access_token_new.api_key) do |connection|
|
||
|
expect {
|
||
|
connection.execute("create table test_table_without_permissions as select 1 as test")
|
||
|
}.to raise_exception(Sequel::DatabaseError, /permission denied for schema public/)
|
||
|
end
|
||
|
|
||
|
oau.destroy
|
||
|
end
|
||
|
|
||
|
it 'master role can drop tables created with access token API key' do
|
||
|
schemas_scope = "schemas:c"
|
||
|
scopes = ['offline', 'user:profile', schemas_scope]
|
||
|
|
||
|
oau = OauthAppUser.create!(user: @carto_user, oauth_app: @app, scopes: scopes)
|
||
|
expect(oau.scopes).to(match_array(scopes))
|
||
|
refresh_token = oau.oauth_refresh_tokens.create!(scopes: scopes)
|
||
|
access_token = refresh_token.exchange!(requested_scopes: scopes)[0]
|
||
|
|
||
|
with_connection_from_api_key(access_token.api_key) do |connection|
|
||
|
connection.execute("create table test_table as select 1 as test")
|
||
|
connection.execute("select count(1) from test_table") do |result|
|
||
|
result[0]['count'].should eq '1'
|
||
|
end
|
||
|
end
|
||
|
|
||
|
with_connection_from_api_key(@carto_user.api_keys.master.first) do |connection|
|
||
|
connection.execute("drop table test_table")
|
||
|
connection.execute("select * from pg_class where relname = 'test_table'") do |result|
|
||
|
result.count.should eq 0
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe 'shared datasets' do
|
||
|
before :each do
|
||
|
@app = FactoryGirl.create(:oauth_app, user: @carto_org_user_1)
|
||
|
@shared_table = create_table(user_id: @carto_org_user_1.id)
|
||
|
not_shared_table = create_table(user_id: @carto_org_user_1.id)
|
||
|
|
||
|
perm = @shared_table.table_visualization.permission
|
||
|
perm.acl = [{ type: 'user', entity: { id: @carto_org_user_2.id }, access: 'rw' }]
|
||
|
perm.save!
|
||
|
|
||
|
@shared_dataset_scope = "datasets:r:#{@carto_org_user_1.database_schema}.#{@shared_table.name}"
|
||
|
@non_shared_dataset_scope = "datasets:r:#{@carto_org_user_1.database_schema}.#{not_shared_table.name}"
|
||
|
end
|
||
|
|
||
|
after :each do
|
||
|
@app.destroy
|
||
|
end
|
||
|
|
||
|
it 'works with shared dataset' do
|
||
|
oau = OauthAppUser.create!(user: @carto_org_user_2, oauth_app: @app, scopes: [@shared_dataset_scope])
|
||
|
expect(oau.all_scopes).to(eq([@shared_dataset_scope]))
|
||
|
end
|
||
|
|
||
|
it 'should fail with non shared dataset' do
|
||
|
expect {
|
||
|
OauthAppUser.create!(user: @carto_org_user_2, oauth_app: @app, scopes: [@non_shared_dataset_scope])
|
||
|
}.to raise_error(Carto::OauthProvider::Errors::InvalidScope)
|
||
|
end
|
||
|
|
||
|
it 'should fail with shared and non shared dataset' do
|
||
|
expect {
|
||
|
OauthAppUser.create!(
|
||
|
user: @carto_org_user_2,
|
||
|
oauth_app: @app,
|
||
|
scopes: [@shared_dataset_scope, @non_shared_dataset_scope]
|
||
|
)
|
||
|
}.to raise_error(Carto::OauthProvider::Errors::InvalidScope)
|
||
|
end
|
||
|
|
||
|
it 'should revoke permissions removing shared permissions' do
|
||
|
oau = OauthAppUser.create!(user: @carto_org_user_2, oauth_app: @app, scopes: [@shared_dataset_scope])
|
||
|
expect(oau.all_scopes).to(eq([@shared_dataset_scope]))
|
||
|
|
||
|
expect(oau.authorized?([@shared_dataset_scope])).to eq(true)
|
||
|
expect(oau.authorized?([@non_shared_dataset_scope])).to eq(false)
|
||
|
|
||
|
# remove shared permissions
|
||
|
@shared_table.table_visualization.reload
|
||
|
perm = @shared_table.table_visualization.permission
|
||
|
perm.acl = [{ type: 'user', entity: { id: @carto_org_user_2.id }, access: 'r' }]
|
||
|
perm.save!
|
||
|
|
||
|
shared_dataset_scope_rw = "datasets:rw:#{@carto_org_user_1.database_schema}.#{@shared_table.name}"
|
||
|
expect(oau.authorized?([@shared_dataset_scope])).to eq(true)
|
||
|
expect(oau.authorized?([shared_dataset_scope_rw])).to eq(false)
|
||
|
|
||
|
# remove shared permissions
|
||
|
@shared_table.table_visualization.reload
|
||
|
perm = @shared_table.table_visualization.permission
|
||
|
perm.acl = []
|
||
|
perm.save!
|
||
|
|
||
|
expect(oau.authorized?([@shared_dataset_scope])).to eq(false)
|
||
|
expect(oau.authorized?([@non_shared_dataset_scope])).to eq(false)
|
||
|
end
|
||
|
|
||
|
describe 'read - write permissions' do
|
||
|
before :each do
|
||
|
@only_read_table = create_table(user_id: @carto_org_user_1.id)
|
||
|
|
||
|
perm = @only_read_table.table_visualization.permission
|
||
|
perm.acl = [{ type: 'user', entity: { id: @carto_org_user_2.id }, access: 'r' }]
|
||
|
perm.save!
|
||
|
end
|
||
|
|
||
|
after :each do
|
||
|
@only_read_table.destroy
|
||
|
end
|
||
|
|
||
|
it 'should fail write scope in shared dataset with only read perms' do
|
||
|
rw_scope = "datasets:rw:#{@carto_org_user_1.database_schema}.#{@only_read_table.name}"
|
||
|
expect {
|
||
|
OauthAppUser.create!(user: @carto_org_user_2, oauth_app: @app, scopes: [rw_scope])
|
||
|
}.to raise_error(Carto::OauthProvider::Errors::InvalidScope)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe 'organization shared datasets' do
|
||
|
before :each do
|
||
|
@org_shared_table = create_table(user_id: @carto_org_user_1.id)
|
||
|
non_org_shared_table = create_table(user_id: @carto_org_user_1.id)
|
||
|
|
||
|
perm = @org_shared_table.table_visualization.permission
|
||
|
perm.acl = [
|
||
|
{
|
||
|
type: Permission::TYPE_ORGANIZATION,
|
||
|
entity: { id: @carto_organization.id },
|
||
|
access: Permission::ACCESS_READWRITE
|
||
|
}
|
||
|
]
|
||
|
perm.save!
|
||
|
|
||
|
@org_shared_dataset_scope = "datasets:r:#{@carto_org_user_1.database_schema}.#{@org_shared_table.name}"
|
||
|
@non_org_shared_dataset_scope = "datasets:r:#{@carto_org_user_1.database_schema}.#{non_org_shared_table.name}"
|
||
|
end
|
||
|
|
||
|
it 'works with org shared dataset' do
|
||
|
oau = OauthAppUser.create!(user: @carto_org_user_2, oauth_app: @app, scopes: [@org_shared_dataset_scope])
|
||
|
expect(oau.all_scopes).to(eq([@org_shared_dataset_scope]))
|
||
|
end
|
||
|
|
||
|
it 'should fail with non org shared dataset' do
|
||
|
expect {
|
||
|
OauthAppUser.create!(user: @carto_org_user_2, oauth_app: @app, scopes: [@non_org_shared_dataset_scope])
|
||
|
}.to raise_error(Carto::OauthProvider::Errors::InvalidScope)
|
||
|
end
|
||
|
|
||
|
it 'should fail with org shared and non org shared dataset' do
|
||
|
expect {
|
||
|
OauthAppUser.create!(
|
||
|
user: @carto_org_user_2,
|
||
|
oauth_app: @app,
|
||
|
scopes: [@org_shared_dataset_scope, @non_org_shared_dataset_scope]
|
||
|
)
|
||
|
}.to raise_error(Carto::OauthProvider::Errors::InvalidScope)
|
||
|
end
|
||
|
|
||
|
describe 'read - write permissions' do
|
||
|
before :each do
|
||
|
@only_read_table = create_table(user_id: @carto_org_user_1.id)
|
||
|
|
||
|
perm = @only_read_table.table_visualization.permission
|
||
|
perm.acl = [
|
||
|
{
|
||
|
type: Permission::TYPE_ORGANIZATION,
|
||
|
entity: { id: @carto_organization.id },
|
||
|
access: Permission::ACCESS_READONLY
|
||
|
}
|
||
|
]
|
||
|
perm.save!
|
||
|
end
|
||
|
|
||
|
after :each do
|
||
|
@only_read_table.destroy
|
||
|
end
|
||
|
|
||
|
it 'should fail write scope in org shared dataset with only read perms' do
|
||
|
rw_scope = "datasets:rw:#{@carto_org_user_1.database_schema}.#{@only_read_table.name}"
|
||
|
expect {
|
||
|
OauthAppUser.create!(user: @carto_org_user_2, oauth_app: @app, scopes: [rw_scope])
|
||
|
}.to raise_error(Carto::OauthProvider::Errors::InvalidScope)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe 'views' do
|
||
|
before :all do
|
||
|
@user = FactoryGirl.create(:valid_user)
|
||
|
@carto_user = Carto::User.find(@user.id)
|
||
|
@user_table = create_table(user_id: @carto_user.id)
|
||
|
|
||
|
@view_name = "#{@user_table.name}_view"
|
||
|
@materialized_view_name = "#{@user_table.name}_matview"
|
||
|
@carto_user.in_database do |db|
|
||
|
query = %{
|
||
|
CREATE VIEW #{@view_name} AS SELECT * FROM #{@user_table.name};
|
||
|
CREATE MATERIALIZED VIEW #{@materialized_view_name} AS SELECT * FROM #{@user_table.name};
|
||
|
}
|
||
|
db.execute(query)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
before :each do
|
||
|
@app = FactoryGirl.create(:oauth_app, user: @carto_user)
|
||
|
end
|
||
|
|
||
|
after :each do
|
||
|
@app.destroy
|
||
|
end
|
||
|
|
||
|
after :all do
|
||
|
@carto_user.in_database do |db|
|
||
|
query = %{
|
||
|
DROP VIEW #{@view_name};
|
||
|
DROP MATERIALIZED VIEW #{@materialized_view_name};
|
||
|
}
|
||
|
db.execute(query)
|
||
|
end
|
||
|
|
||
|
@user_table.destroy
|
||
|
@user.destroy
|
||
|
@carto_user.destroy
|
||
|
end
|
||
|
|
||
|
it 'validates view scope' do
|
||
|
oau = OauthAppUser.create!(
|
||
|
user: @carto_user,
|
||
|
oauth_app: @app,
|
||
|
scopes: ["datasets:r:#{@view_name}"]
|
||
|
)
|
||
|
expect(oau.all_scopes).to(eq(["datasets:r:#{@view_name}"]))
|
||
|
end
|
||
|
|
||
|
it 'validates materialized view scope' do
|
||
|
oau = OauthAppUser.create!(
|
||
|
user: @carto_user,
|
||
|
oauth_app: @app,
|
||
|
scopes: ["datasets:r:#{@materialized_view_name}"]
|
||
|
)
|
||
|
expect(oau.all_scopes).to(eq(["datasets:r:#{@materialized_view_name}"]))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe '#destroy' do
|
||
|
before(:each) do
|
||
|
@user = FactoryGirl.create(:valid_user)
|
||
|
@app = FactoryGirl.create(:oauth_app, user_id: @user.id)
|
||
|
@app_user = Carto::OauthAppUser.create!(user_id: @user.id, oauth_app: @app)
|
||
|
access_token = OauthAccessToken.create!(oauth_app_user: @app_user,
|
||
|
scopes: ["schemas:c:#{@user.database_schema}"])
|
||
|
@api_key = access_token.api_key
|
||
|
end
|
||
|
|
||
|
after(:each) do
|
||
|
@app.destroy
|
||
|
@user.destroy
|
||
|
end
|
||
|
|
||
|
it 'drops the created roles' do
|
||
|
find_role_query = "SELECT * FROM pg_roles WHERE rolname LIKE '%#{@app_user.id}'"
|
||
|
@user.in_database.fetch(find_role_query).count.should eq 2
|
||
|
|
||
|
@app_user.destroy
|
||
|
|
||
|
@user.in_database.fetch(find_role_query).count.should eq 0
|
||
|
end
|
||
|
|
||
|
it 'reassigns the ownership of created tables to the master role' do
|
||
|
with_connection_from_api_key(@api_key) { |db| db.execute('CREATE TABLE puxa()') }
|
||
|
find_owner_query = "SELECT tableowner FROM pg_tables WHERE tablename = 'puxa'"
|
||
|
@user.in_database.fetch(find_owner_query).first[:tableowner].should eql @app_user.ownership_role_name
|
||
|
|
||
|
@app_user.destroy
|
||
|
|
||
|
@user.in_database.fetch(find_owner_query).first[:tableowner].should eql @user.database_username
|
||
|
end
|
||
|
end
|
||
|
|
||
|
end
|
||
|
end
|