parent
7468e610a7
commit
c1b2c126dd
@ -0,0 +1,82 @@
|
||||
module Carto
|
||||
module OauthProvider
|
||||
module Scopes
|
||||
class AllDatasetsScope < DefaultScope
|
||||
|
||||
READ_PERMISSIONS = ['select'].freeze
|
||||
WRITE_PERMISSIONS = ['insert', 'update', 'delete'].freeze
|
||||
|
||||
PERMISSIONS = {
|
||||
r: READ_PERMISSIONS,
|
||||
rw: READ_PERMISSIONS + WRITE_PERMISSIONS
|
||||
}.with_indifferent_access.freeze
|
||||
|
||||
DESCRIPTIONS = {
|
||||
r: 'All datasets (read access)',
|
||||
rw: 'All datasets (read/write access)'
|
||||
}.with_indifferent_access.freeze
|
||||
|
||||
EXCLUDED_INTERNAL_TABLES = %w(
|
||||
geography_columns
|
||||
geometry_columns
|
||||
raster_columns
|
||||
raster_overviews
|
||||
spatial_ref_sys
|
||||
).freeze
|
||||
|
||||
attr_reader :description, :permission_key, :permission
|
||||
|
||||
def self.is_a?(scope)
|
||||
scope =~ /^datasets:(?:rw|r):\*$/
|
||||
end
|
||||
|
||||
def self.valid_scopes(scopes)
|
||||
scopes.select { |scope| AllDatasetsScope.is_a?(scope) }
|
||||
end
|
||||
|
||||
def initialize(scope)
|
||||
@permission_key = scope.split(':').second.to_sym
|
||||
@permission = PERMISSIONS[permission_key]
|
||||
@description = DESCRIPTIONS[permission_key]
|
||||
@grant_key = :tables
|
||||
super('database', permission_key, CATEGORY_DATASETS, description)
|
||||
end
|
||||
|
||||
def name
|
||||
"datasets:#{permission_key}:*"
|
||||
end
|
||||
|
||||
def add_to_api_key_grants(grants, user)
|
||||
ensure_includes_apis(grants, ['maps', 'sql'])
|
||||
database_section = grant_section(grants)
|
||||
granted_tables = user.db_service.tables_granted
|
||||
|
||||
return unless granted_tables
|
||||
|
||||
granted_tables.each do |table|
|
||||
database_section[@grant_key] << {
|
||||
name: table.name,
|
||||
permissions: combined_permissions(table.mode.to_sym),
|
||||
schema: table.table_schema
|
||||
}
|
||||
end
|
||||
|
||||
ensure_grant_section(grants, database_section)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def combined_permissions(table_mode)
|
||||
if permission_key == table_mode
|
||||
PERMISSIONS[@permission_key]
|
||||
elsif [permission_key, table_mode] == [:rw, :r] || [permission_key, table_mode] == [:r, :rw]
|
||||
PERMISSIONS[:r]
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,156 @@
|
||||
require 'spec_helper_min'
|
||||
require './spec/support/factories/organizations'
|
||||
require_dependency 'carto/oauth_provider/scopes/scopes'
|
||||
|
||||
describe Carto::OauthProvider::Scopes::AllDatasetsScope do
|
||||
include CartoDB::Factories
|
||||
include Carto::Factories::Visualizations
|
||||
include TableSharing
|
||||
|
||||
let(:r_scope_string) { 'datasets:r:*' }
|
||||
let(:rw_scope_string) { 'datasets:rw:*' }
|
||||
let(:invalid_scope_string) { 'datasets:rx:*' }
|
||||
let(:scope_string) { r_scope_string }
|
||||
let(:scope) { described_class.new(scope_string) }
|
||||
let(:user) { create(:valid_user).carto_user }
|
||||
let!(:organization) { OrganizationFactory.new.create_organization_with_users.carto_organization }
|
||||
let!(:org_admin) { organization.owner }
|
||||
let(:organization_user) { organization.users.where.not(id: org_admin.id).first }
|
||||
let(:tables_grants) { grants.find { |grant| grant[:type] == 'database' }[:tables] }
|
||||
|
||||
describe '::is_a?' do
|
||||
subject { described_class.is_a?(scope_string) }
|
||||
|
||||
context 'when scope matches' do
|
||||
it { should be_true }
|
||||
end
|
||||
|
||||
context 'when scope does not match' do
|
||||
let(:scope_string) { invalid_scope_string }
|
||||
|
||||
it { should be_false }
|
||||
end
|
||||
end
|
||||
|
||||
describe '::valid_scopes' do
|
||||
subject(:valid_scopes) { described_class.valid_scopes([r_scope_string, rw_scope_string, invalid_scope_string]) }
|
||||
|
||||
it 'returns only the valid scopes' do
|
||||
expect(valid_scopes).to include(r_scope_string)
|
||||
expect(valid_scopes).to include(rw_scope_string)
|
||||
expect(valid_scopes).not_to include(invalid_scope_string)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#name' do
|
||||
subject(:name) { scope.name }
|
||||
|
||||
context 'for read permissions' do
|
||||
it 'returns the scope name' do
|
||||
expect(name).to eq('datasets:r:*')
|
||||
end
|
||||
end
|
||||
|
||||
context 'for read-write permissions' do
|
||||
let(:scope_string) { rw_scope_string }
|
||||
|
||||
it 'returns the scope name' do
|
||||
expect(name).to eq('datasets:rw:*')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#add_to_api_key_grants' do
|
||||
let!(:user_table) { create_full_visualization(user)[2] }
|
||||
let(:grants) { [{ type: 'apis', apis: [] }] }
|
||||
let(:granted_permissions) { tables_grants.find { |t| t[:name] == user_table.name }[:permissions] }
|
||||
let(:granted_tables) { tables_grants.map { |table| table[:name] } }
|
||||
|
||||
context 'when granting read-only permissions' do
|
||||
before { scope.add_to_api_key_grants(grants, user) }
|
||||
|
||||
it 'only grants read permissions' do
|
||||
expect(granted_permissions).to include('select')
|
||||
expect(granted_permissions).not_to include('insert')
|
||||
expect(granted_permissions).not_to include('update')
|
||||
expect(granted_permissions).not_to include('delete')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when granting read-write permissions' do
|
||||
let(:scope_string) { rw_scope_string }
|
||||
|
||||
before { scope.add_to_api_key_grants(grants, user) }
|
||||
|
||||
it 'grants read-write permissions' do
|
||||
expect(granted_permissions).to include('select')
|
||||
expect(granted_permissions).to include('insert')
|
||||
expect(granted_permissions).to include('update')
|
||||
expect(granted_permissions).to include('delete')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user belongs to organization' do
|
||||
let(:user) { organization_user }
|
||||
let!(:other_user_table) { create_full_visualization(org_admin)[2] }
|
||||
|
||||
before do
|
||||
user.update!(organization: organization)
|
||||
scope.add_to_api_key_grants(grants, user)
|
||||
end
|
||||
|
||||
it 'only grants permissions to user datasets when in an organization' do
|
||||
expect(granted_tables).to include(user_table.name)
|
||||
expect(granted_tables).not_to include(other_user_table.name)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has access to other shared datasets' do
|
||||
let(:user) { organization_user }
|
||||
let(:full_visualization_objects) { create_full_visualization(org_admin) }
|
||||
let(:other_table) { full_visualization_objects[1] }
|
||||
let!(:other_user_table) { full_visualization_objects[2] }
|
||||
let(:granted_permissions) { tables_grants.find { |t| t[:name] == other_user_table.name }[:permissions] }
|
||||
|
||||
context 'with read-only access' do
|
||||
before do
|
||||
share_table_with_user(other_table, user)
|
||||
scope.add_to_api_key_grants(grants, user)
|
||||
end
|
||||
|
||||
it 'only grants read permissions' do
|
||||
expect(granted_tables).to include(other_user_table.name)
|
||||
|
||||
expect(granted_permissions).to include('select')
|
||||
expect(granted_permissions).not_to include('insert')
|
||||
expect(granted_permissions).not_to include('update')
|
||||
expect(granted_permissions).not_to include('delete')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with read-write access' do
|
||||
let(:scope_string) { rw_scope_string }
|
||||
|
||||
before do
|
||||
share_table_with_user(other_table, user, access: Carto::Permission::ACCESS_READWRITE)
|
||||
scope.add_to_api_key_grants(grants, user)
|
||||
end
|
||||
|
||||
it 'grants read-write permissions' do
|
||||
expect(granted_tables).to include(other_user_table.name)
|
||||
|
||||
expect(granted_permissions).to include('select')
|
||||
expect(granted_permissions).to include('insert')
|
||||
expect(granted_permissions).to include('update')
|
||||
expect(granted_permissions).to include('delete')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not grant permissions over internal tables' do
|
||||
scope.add_to_api_key_grants(grants, user)
|
||||
|
||||
expect(granted_tables).not_to include('spatial_ref_sys')
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,16 @@
|
||||
require 'spec_helper_min'
|
||||
require_dependency 'carto/oauth_provider/scopes/scopes'
|
||||
require_relative '../../../../factories/organizations_contexts'
|
||||
|
||||
describe Carto::OauthProvider::Scopes::ApisScope do
|
||||
include_context 'organization with users helper'
|
||||
|
||||
describe '#add_to_api_key_grants' do
|
||||
it 'adds apis scope with do subset' do
|
||||
scope = Carto::OauthProvider::Scopes::ApisScope.new('do', 'Data Observatory API')
|
||||
grants = [{ type: 'apis', apis: [] }]
|
||||
scope.add_to_api_key_grants(grants, nil)
|
||||
expect(grants).to(eq([{ type: 'apis', apis: ['do'] }]))
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,23 @@
|
||||
require 'spec_helper_min'
|
||||
require_dependency 'carto/oauth_provider/scopes/scopes'
|
||||
require_relative '../../../../factories/organizations_contexts'
|
||||
|
||||
describe Carto::OauthProvider::Scopes::DataservicesScope do
|
||||
include_context 'organization with users helper'
|
||||
|
||||
describe '#add_to_api_key_grants' do
|
||||
let(:scope) { Carto::OauthProvider::Scopes::DataservicesScope.new('geocoding', 'GC') }
|
||||
|
||||
it 'adds SQL api and dataservice' do
|
||||
grants = [{ type: 'apis', apis: [] }]
|
||||
scope.add_to_api_key_grants(grants, nil)
|
||||
expect(grants).to(eq([{ type: 'apis', apis: ['sql'] }, { type: 'dataservices', services: ['geocoding'] }]))
|
||||
end
|
||||
|
||||
it 'does not add duplicate SQL api' do
|
||||
grants = [{ type: 'apis', apis: ['sql'] }]
|
||||
scope.add_to_api_key_grants(grants, nil)
|
||||
expect(grants).to(include(type: 'apis', apis: ['sql']))
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,119 @@
|
||||
require 'spec_helper_min'
|
||||
require_dependency 'carto/oauth_provider/scopes/scopes'
|
||||
require_relative '../../../../factories/organizations_contexts'
|
||||
|
||||
describe Carto::OauthProvider::Scopes::DatasetsScope do
|
||||
include_context 'organization with users helper'
|
||||
|
||||
describe '#add_to_api_key_grants' do
|
||||
let(:full_dataset_scope) { Carto::OauthProvider::Scopes::DatasetsScope.new('datasets:rw:untitled_table') }
|
||||
let(:read_dataset_scope) { Carto::OauthProvider::Scopes::DatasetsScope.new('datasets:r:untitled_table') }
|
||||
let(:schema_scope) { Carto::OauthProvider::Scopes::SchemasScope.new('schemas:c') }
|
||||
let(:dataset_metadata_scope) { Carto::OauthProvider::Scopes::DatasetsMetadataScope.new('datasets:metadata') }
|
||||
let(:full_table_grants) do
|
||||
[
|
||||
{
|
||||
apis: [
|
||||
'maps',
|
||||
'sql'
|
||||
],
|
||||
type: 'apis'
|
||||
},
|
||||
{
|
||||
tables: [
|
||||
{
|
||||
name: 'untitled_table',
|
||||
permissions: [
|
||||
'select',
|
||||
'insert',
|
||||
'update',
|
||||
'delete'
|
||||
],
|
||||
schema: 'wadus'
|
||||
}
|
||||
],
|
||||
schemas: [
|
||||
{
|
||||
name: 'wadus',
|
||||
permissions: [
|
||||
'create'
|
||||
]
|
||||
}
|
||||
],
|
||||
type: 'database'
|
||||
}
|
||||
]
|
||||
end
|
||||
let(:read_table_grants) do
|
||||
[
|
||||
{
|
||||
apis: [
|
||||
'maps',
|
||||
'sql'
|
||||
],
|
||||
type: 'apis'
|
||||
},
|
||||
{
|
||||
tables: [
|
||||
{
|
||||
name: 'untitled_table',
|
||||
permissions: [
|
||||
'select'
|
||||
],
|
||||
schema: 'wadus'
|
||||
}
|
||||
],
|
||||
type: 'database'
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
let(:metadata_grants) do
|
||||
[
|
||||
{
|
||||
apis: [
|
||||
'sql'
|
||||
],
|
||||
type: 'apis'
|
||||
},
|
||||
{
|
||||
table_metadata: [],
|
||||
type: 'database'
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
|
||||
before(:all) do
|
||||
@user = mock
|
||||
@user.stubs(:database_schema).returns('wadus')
|
||||
end
|
||||
|
||||
it 'adds full access permissions' do
|
||||
grants = [{ type: 'apis', apis: [] }]
|
||||
full_dataset_scope.add_to_api_key_grants(grants, @user)
|
||||
schema_scope.add_to_api_key_grants(grants, @user)
|
||||
expect(grants).to(eq(full_table_grants))
|
||||
end
|
||||
|
||||
it 'does not add write permissions' do
|
||||
grants = [{ type: 'apis', apis: [] }]
|
||||
read_dataset_scope.add_to_api_key_grants(grants, @user)
|
||||
expect(grants).to(eq(read_table_grants))
|
||||
end
|
||||
|
||||
it 'adds metadata permissions' do
|
||||
grants = [{ type: 'apis', apis: [] }]
|
||||
dataset_metadata_scope.add_to_api_key_grants(grants, @user)
|
||||
expect(grants).to(eq(metadata_grants))
|
||||
end
|
||||
|
||||
it 'does add full access permissions and metadata' do
|
||||
grants = [{ type: 'apis', apis: [] }]
|
||||
dataset_metadata_scope.add_to_api_key_grants(grants, @user)
|
||||
full_dataset_scope.add_to_api_key_grants(grants, @user)
|
||||
expect(grants[1]).to have_key(:table_metadata)
|
||||
expect(grants[1]).to have_key(:tables)
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,16 @@
|
||||
require 'spec_helper_min'
|
||||
require_dependency 'carto/oauth_provider/scopes/scopes'
|
||||
require_relative '../../../../factories/organizations_contexts'
|
||||
|
||||
describe Carto::OauthProvider::Scopes::UserScope do
|
||||
include_context 'organization with users helper'
|
||||
|
||||
describe '#add_to_api_key_grants' do
|
||||
it 'adds user scope with profile subset' do
|
||||
scope = Carto::OauthProvider::Scopes::UserScope.new('profile', 'User public profile')
|
||||
grants = [{ type: 'apis', apis: [] }]
|
||||
scope.add_to_api_key_grants(grants, nil)
|
||||
expect(grants).to(eq([{ type: 'apis', apis: [] }, { type: 'user', data: ['profile'] }]))
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in new issue