granar 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +53 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/config/rbac_rls_manifest.js +2 -0
  6. data/app/assets/javascripts/rbac_rls/application.js +1 -0
  7. data/app/assets/stylesheets/rbac_rls/application.css.scss +16 -0
  8. data/app/controllers/concerns/connection_rls_user_concern.rb +31 -0
  9. data/app/controllers/rbac_rls/application_controller.rb +3 -0
  10. data/app/controllers/rbac_rls/groups_controller.rb +94 -0
  11. data/app/controllers/rbac_rls/home_controller.rb +5 -0
  12. data/app/controllers/rbac_rls/permissions_controller.rb +69 -0
  13. data/app/controllers/rbac_rls/roles_controller.rb +61 -0
  14. data/app/helpers/rbac_rls/application_helper.rb +4 -0
  15. data/app/helpers/rbac_rls/groups_helper.rb +4 -0
  16. data/app/helpers/rbac_rls/permissions_helper.rb +41 -0
  17. data/app/helpers/rbac_rls/roles_helper.rb +4 -0
  18. data/app/jobs/rbac_rls/application_job.rb +4 -0
  19. data/app/mailers/rbac_rls/application_mailer.rb +6 -0
  20. data/app/models/concerns/connection_rls_concern.rb +19 -0
  21. data/app/models/rbac_rls/application_record.rb +3 -0
  22. data/app/models/rbac_rls/group.rb +14 -0
  23. data/app/models/rbac_rls/group_permission.rb +20 -0
  24. data/app/models/rbac_rls/group_user.rb +7 -0
  25. data/app/models/rbac_rls/permission.rb +68 -0
  26. data/app/models/rbac_rls/role.rb +10 -0
  27. data/app/models/rbac_rls/role_permission.rb +6 -0
  28. data/app/models/rbac_rls/user_role.rb +7 -0
  29. data/app/views/layouts/rbac_rls/application.html.erb +55 -0
  30. data/app/views/rbac_rls/groups/_form.html.erb +97 -0
  31. data/app/views/rbac_rls/groups/_group.html.erb +12 -0
  32. data/app/views/rbac_rls/groups/_group_permission_fields.html.erb +18 -0
  33. data/app/views/rbac_rls/groups/_group_user_fields.html.erb +9 -0
  34. data/app/views/rbac_rls/groups/edit.html.erb +10 -0
  35. data/app/views/rbac_rls/groups/index.html.erb +14 -0
  36. data/app/views/rbac_rls/groups/new.html.erb +9 -0
  37. data/app/views/rbac_rls/groups/show.html.erb +10 -0
  38. data/app/views/rbac_rls/home/_link_to_home_page.html.erb +3 -0
  39. data/app/views/rbac_rls/home/index.html.erb +28 -0
  40. data/app/views/rbac_rls/permissions/_form.html.erb +78 -0
  41. data/app/views/rbac_rls/permissions/_permission.html.erb +54 -0
  42. data/app/views/rbac_rls/permissions/_role_permission_fields.html.erb +9 -0
  43. data/app/views/rbac_rls/permissions/edit.html.erb +7 -0
  44. data/app/views/rbac_rls/permissions/index.html.erb +18 -0
  45. data/app/views/rbac_rls/permissions/new.html.erb +9 -0
  46. data/app/views/rbac_rls/permissions/show.html.erb +10 -0
  47. data/app/views/rbac_rls/roles/_form.html.erb +42 -0
  48. data/app/views/rbac_rls/roles/_role.html.erb +2 -0
  49. data/app/views/rbac_rls/roles/_user_role_fields.html.erb +9 -0
  50. data/app/views/rbac_rls/roles/edit.html.erb +9 -0
  51. data/app/views/rbac_rls/roles/index.html.erb +19 -0
  52. data/app/views/rbac_rls/roles/new.html.erb +8 -0
  53. data/app/views/rbac_rls/roles/show.html.erb +12 -0
  54. data/config/assets.rb +12 -0
  55. data/config/importmap.rb +9 -0
  56. data/config/routes.rb +14 -0
  57. data/config/setup.rb +0 -0
  58. data/db/migrate/20220411125339_create_rbac_rls_roles.rb +9 -0
  59. data/db/migrate/20220411125613_create_rbac_rls_user_roles.rb +9 -0
  60. data/db/migrate/20220411133054_create_rbac_rls_permissions.rb +18 -0
  61. data/db/migrate/20220425212731_create_role_permissions.rb +9 -0
  62. data/db/migrate/20220912104712_create_rbac_rls_groups.rb +10 -0
  63. data/db/migrate/20220912104929_create_rbac_rls_group_permissions.rb +12 -0
  64. data/db/migrate/20220914004802_create_rbac_rls_group_users.rb +10 -0
  65. data/db/migrate/20220914004803_create_basic_permissions_for_application_acess.rb +18 -0
  66. data/lib/generators/generator_helpers.rb +8 -0
  67. data/lib/generators/rbac_rls/custom_migration_generator.rb +78 -0
  68. data/lib/generators/rbac_rls/group_permission_generator.rb +57 -0
  69. data/lib/generators/rbac_rls/templates/group_permission_migration.rb +83 -0
  70. data/lib/generators/rbac_rls/templates/rls_migration.rb +81 -0
  71. data/lib/generators/rbac_rls/templates/rls_migration.rb.erb +64 -0
  72. data/lib/generators/rbac_rls/templates/rls_migration2.rb.erb +80 -0
  73. data/lib/rbac_rls/engine.rb +21 -0
  74. data/lib/rbac_rls/version.rb +3 -0
  75. data/lib/rbac_rls.rb +6 -0
  76. data/lib/tasks/rbac_rls_tasks.rake +4 -0
  77. metadata +178 -0
@@ -0,0 +1,18 @@
1
+ class CreateRbacRlsPermissions < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :permissions do |t|
4
+ t.string :name, limit: 30
5
+ t.string :table_name, limit: 255, null: false
6
+ t.boolean :read, default: false
7
+ t.boolean :write, default: false
8
+ t.boolean :change, default: false
9
+ t.boolean :remove, default: false
10
+ t.boolean :owner_read, default: false
11
+ t.boolean :owner_change, default: false
12
+ t.boolean :owner_remove, default: false
13
+ t.references :permission, null: true, index: true
14
+
15
+ t.timestamps
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,9 @@
1
+ class CreateRolePermissions < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :role_permissions do |t|
4
+ t.references :role, null: false, foreign_key: true
5
+ t.references :permission, null: false, foreign_key: true
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ class CreateRbacRlsGroups < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :groups do |t|
4
+ t.string :name, limit: 60
5
+ t.string :comments, limit: 255
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ class CreateRbacRlsGroupPermissions < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :group_permissions do |t|
4
+ t.references :permission, null: false, foreign_key: true
5
+ t.references :group, null: false, foreign_key: true
6
+ t.string :table_key, null: false, limit: 60
7
+ t.string :table_value, null: false, limit: 60
8
+
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ class CreateRbacRlsGroupUsers < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :group_users do |t|
4
+ t.references :user, null: false, foreign_key: true
5
+ t.references :group, null: false, foreign_key: true
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,18 @@
1
+ class CreateBasicPermissionsForApplicationAcess < ActiveRecord::Migration[7.0]
2
+ def change
3
+ schema = 'public'
4
+ user = 'app_user'
5
+ where_schema = ->(schema_name = nil) do
6
+ schema_name.present? ? "WHERE table_schema = '#{schema_name}'" : ''
7
+ end
8
+
9
+ sql = "SELECT table_name FROM information_schema.tables #{where_schema[schema]}"
10
+ result = ActiveRecord::Base.connection.select_all(sql)
11
+ tables = result.map { |k| k['table_name'] }
12
+ tables&.each do |table|
13
+ execute "GRANT ALL PRIVILEGES on #{schema}.#{table} TO #{user}"
14
+ end
15
+
16
+ execute 'GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO app_user'
17
+ end
18
+ end
@@ -0,0 +1,8 @@
1
+ module RbacRls
2
+ module Generators
3
+ # Some helpers for generating scaffolding
4
+ module GeneratorHelpers
5
+ attr_accessor :options, :attributes
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,78 @@
1
+ # class_option :skip_show, type: :boolean, default: false, desc: 'Skip "show" action'
2
+ # class_option :attributes, type: :hash, default: {}
3
+ # require 'rails/generators'
4
+ # exemplo: # rails generate rbac_rls:custom_migration products
5
+
6
+ require 'rails/command/base'
7
+ require 'rails/generators/named_base'
8
+ require 'generators/generator_helpers'
9
+ require 'rails/generators/rails/migration/migration_generator'
10
+ require 'rails/generators/migration'
11
+ require 'active_record/migration'
12
+ require 'thor/actions/inject_into_file'
13
+ module Rails
14
+ module Generators
15
+ module Migration
16
+ module ClassMethods
17
+ def next_migration_number(dirname)
18
+ next_migration_number = current_migration_number(dirname) + 1
19
+ ActiveRecord::Migration.next_migration_number(next_migration_number)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ #deve se sobrescrever os tipos pois será criado um novo tipo para o row level security
26
+ # ActiveRecord::Base.connection.native_database_types
27
+ ActiveRecord::Base.connection.class_eval do
28
+ def native_database_types # :nodoc:
29
+ { role: { name: "rls" },
30
+ all: { name: "rls" },
31
+ user: { name: "rls" }, }
32
+ end
33
+ end
34
+
35
+ #
36
+ module RbacRls
37
+ module Generators
38
+ class CustomMigrationGenerator < Rails::Generators::NamedBase
39
+ attr_accessor :time_now
40
+ argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"
41
+
42
+ class_option :permission_identifier, type: :string, default: Time.now.getutc.to_i.to_s, desc: ''
43
+ # class_option :sufix_migration_name, type: :string, default: Time.now.getutc.to_i.to_s, desc: ''
44
+ include Rails::Generators::Migration
45
+ include RbacRls::Generators::GeneratorHelpers
46
+ # ActiveRecord::ConnectionAdapters::SchemaStatements
47
+ # include Rails::Generators::MigrationGenerator
48
+ # ActiveRecord::ConnectionAdapters::Table
49
+ # Rails::Generators::Error
50
+ # ActiveRecord::Base.connection.valid_type?
51
+
52
+ source_root File.expand_path('../templates', __FILE__)
53
+
54
+ def migration_define_template
55
+ attrs = attributes.map { |i| i.name }
56
+ str = attrs.join('_')
57
+
58
+ migration_template('../templates/rls_migration.rb',
59
+ File.join('db/migrate', "create_#{name.underscore}_#{options[:permission_identifier]}_policy.rb")
60
+ )
61
+ end
62
+
63
+ end
64
+ end
65
+ end
66
+
67
+ # def insert_code
68
+ # insert_into_file 'app/controllers/application_controller.rb', :before => "end" do
69
+ # "\n around_action :with_customer_id \n"
70
+ # end
71
+ # insert_into_file 'app/controllers/application_controller.rb', :before => "end" do
72
+ # "\ndef with_customer_id
73
+ # ApplicationRecord.with_customer_id(current_user.id) do
74
+ # yield
75
+ # end
76
+ # end\n"
77
+ # end
78
+ # end
@@ -0,0 +1,57 @@
1
+ # exemplo: # rails generate rbac_rls:custom_migration products
2
+
3
+ require 'rails/command/base'
4
+ require 'rails/generators/named_base'
5
+ require 'generators/generator_helpers'
6
+ require 'rails/generators/rails/migration/migration_generator'
7
+ require 'rails/generators/migration'
8
+ require 'active_record/migration'
9
+ require 'thor/actions/inject_into_file'
10
+ module Rails
11
+ module Generators
12
+ module Migration
13
+ module ClassMethods
14
+ def next_migration_number(dirname)
15
+ next_migration_number = current_migration_number(dirname) + 1
16
+ ActiveRecord::Migration.next_migration_number(next_migration_number)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ #deve se sobrescrever os tipos pois será criado um novo tipo para o row level security
24
+ # ActiveRecord::Base.connection.native_database_types
25
+ ActiveRecord::Base.connection.class_eval do
26
+ def native_database_types # :nodoc:
27
+ { table_key: { name: "rls" },
28
+ table_value: { name: "rls" },
29
+ user: { name: "rls" }, }
30
+ end
31
+ end
32
+
33
+ #
34
+ module RbacRls
35
+ module Generators
36
+ class GroupPermissionGenerator < Rails::Generators::NamedBase
37
+ attr_accessor :time_now
38
+ argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"
39
+ class_option :identifier, type: :string, default: Time.now.getutc.to_i.to_s, desc: ''
40
+ include Rails::Generators::Migration
41
+ include RbacRls::Generators::GeneratorHelpers
42
+
43
+ source_root File.expand_path('../templates', __FILE__)
44
+
45
+ def migration_define_template
46
+ attrs = attributes.map { |i| i.name }
47
+ str = attrs.join('_')
48
+
49
+ full_name = "#{name}#{options[:identifier]}".underscore
50
+ # byebug
51
+ migration_template('../templates/group_permission_migration.rb',
52
+ File.join('db/migrate', "create_#{full_name}_gpolicy.rb"))
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,83 @@
1
+ <%
2
+ # rails generate rbac_rls:custom_migration table_name
3
+ time_now = Time.now.getutc.to_i
4
+ attrs = attributes.map { |i| i.name.camelize }
5
+ table_key = attributes.select{ |attr| attr.type.to_sym == :table_key }.first.name
6
+ table_value = attributes.select{ |attr| attr.type.to_sym == :table_value }.first.name
7
+ gen_table_name = name.underscore
8
+
9
+ limit_policy_name = 63
10
+ type_polices = {insert: :write,
11
+ select: :read,
12
+ update: :change,
13
+ delete: :remove}
14
+ type_polices_owner = {select: :owner_read,
15
+ update: :owner_change,
16
+ delete: :owner_remove}
17
+ # byebug
18
+ %>
19
+ class Create<%= "#{"#{name}#{options[:identifier]}".camelize}" %>Gpolicy < ActiveRecord::Migration[7.0]
20
+
21
+ def change
22
+ <%
23
+ policy_name = ->(table_name,method) { "p#{time_now}#{table_name}#{method}"[0,limit_policy_name] }
24
+ db_role = "app_user"
25
+ permission_id = options[:permission_identifier]
26
+ owner_rls_policy = ->(type){
27
+ if type.to_sym != :insert
28
+ "
29
+ or
30
+ (
31
+ NULLIF(current_setting('rls.user_id', TRUE), '')::bigint in
32
+ (
33
+ SELECT
34
+ gu.user_id
35
+ FROM permissions p
36
+ INNER JOIN group_permissions gp on gp.permission_id = p.id
37
+ INNER JOIN group_users gu on gu.group_id = gp.group_id
38
+ WHERE (p.\"#{type_polices[type.to_sym]}\")
39
+ AND p.table_name = '#{gen_table_name}'
40
+ ) and owner_id = NULLIF(current_setting('rls.user_id', TRUE), '')::bigint )
41
+ "
42
+ end
43
+ }
44
+ constraint_for_rls = ->(type) {"
45
+ ((
46
+ NULLIF(current_setting('rls.user_id', TRUE), '')::bigint in
47
+ (
48
+ SELECT
49
+ gu.user_id
50
+ FROM permissions p
51
+ INNER JOIN group_permissions gp on gp.permission_id = p.id
52
+ INNER JOIN group_users gu on gu.group_id = gp.group_id
53
+ WHERE (p.\"#{type_polices[type.to_sym]}\")
54
+ AND p.table_name = '#{gen_table_name}'
55
+ )
56
+ ) #{owner_rls_policy[type]} ) and #{table_key.to_s} LIKE '%#{table_value}%'
57
+
58
+ "
59
+ }
60
+ %>
61
+
62
+ <% %i(insert select update delete).each do |attr| %>
63
+ execute '<%="GRANT #{attr} ON #{name} TO #{db_role}"%>'
64
+ execute '<%= "ALTER TABLE #{name} ENABLE ROW LEVEL SECURITY" %>'
65
+ reversible do |dir|
66
+ dir.up do
67
+ <%if attr.to_sym ==:insert %>
68
+ execute <<-SQL
69
+ <%= "CREATE POLICY #{policy_name.(name, attr.to_sym)} ON #{name} for #{attr.to_s} TO #{db_role} with check (#{constraint_for_rls[attr.to_s]})" %>
70
+ SQL
71
+ <% elsif %i(select update delete).include?(attr.to_sym) %>
72
+ execute <<-SQL
73
+ <%= "CREATE POLICY #{policy_name.(name, attr.to_sym)} ON #{name} for #{attr.to_s} TO #{db_role} using (#{constraint_for_rls[attr.to_s]})" %>
74
+ SQL
75
+ <%end%>
76
+ end
77
+ end
78
+ <% end %>
79
+
80
+
81
+
82
+ end
83
+ end
@@ -0,0 +1,81 @@
1
+ <%
2
+ # rails generate rbac_rls:custom_migration table_name
3
+ time_now = Time.now.getutc.to_i
4
+ attrs = attributes.map { |i| i.name.camelize }
5
+
6
+ limit_policy_name = 63
7
+ type_polices = {insert: :write,
8
+ select: :read,
9
+ update: :change,
10
+ delete: :remove}
11
+ type_polices_owner = {select: :owner_read,
12
+ update: :owner_change,
13
+ delete: :owner_remove}
14
+ %>
15
+
16
+ class Create<%= "#{name.underscore.camelize}#{options[:permission_identifier]}" %>Policy < ActiveRecord::Migration[7.0]
17
+
18
+ def change
19
+ <%
20
+ policy_name = ->(table_name,method) { "p#{time_now}#{table_name}#{method}"[0,limit_policy_name] }
21
+ db_role = "app_user"
22
+ permission_id = options[:permission_identifier]
23
+ owner_rls_policy = ->(type){
24
+ if type.to_sym != :insert
25
+ "
26
+ or
27
+ (
28
+ NULLIF(current_setting('rls.user_id', TRUE), '')::bigint in
29
+ (
30
+ SELECT
31
+ ur.user_id
32
+ FROM permissions p
33
+ INNER JOIN role_permissions rp on rp.permission_id = p.id
34
+ INNER JOIN user_roles ur on rp.role_id = ur.role_id
35
+ WHERE (p.\"#{type_polices_owner[type.to_sym]}\")
36
+ AND p.table_name = 'products'
37
+ ) and owner_id = NULLIF(current_setting('rls.user_id', TRUE), '')::bigint )
38
+ "
39
+ end
40
+ }
41
+ constraint_for_rls = ->(type) {"
42
+ NULLIF(current_setting('rls.user_id', TRUE), '')::bigint in
43
+ (
44
+ SELECT
45
+ ur.user_id
46
+ FROM permissions p
47
+ INNER JOIN role_permissions rp on rp.permission_id = p.id
48
+ INNER JOIN user_roles ur on rp.role_id = ur.role_id
49
+ WHERE (p.\"#{type_polices[type.to_sym]}\")
50
+ AND p.table_name = 'products'
51
+ )
52
+ #{owner_rls_policy[type]}
53
+ "
54
+ }
55
+ %>
56
+
57
+
58
+
59
+
60
+ <% %i(insert select update delete).each do |attr| %>
61
+ execute '<%="GRANT #{attr} ON #{name} TO #{db_role}"%>'
62
+ execute '<%= "ALTER TABLE #{name} ENABLE ROW LEVEL SECURITY" %>'
63
+ reversible do |dir|
64
+ dir.up do
65
+ <%if attr.to_sym ==:insert %>
66
+ execute <<-SQL
67
+ <%= "CREATE POLICY #{policy_name.(name, attr.to_sym)} ON #{name} for #{attr.to_s} TO #{db_role} with check (#{constraint_for_rls[attr.to_s]})" %>
68
+ SQL
69
+ <% elsif %i(select update delete).include?(attr.to_sym) %>
70
+ execute <<-SQL
71
+ <%= "CREATE POLICY #{policy_name.(name, attr.to_sym)} ON #{name} for #{attr.to_s} TO #{db_role} using (#{constraint_for_rls[attr.to_s]})" %>
72
+ SQL
73
+ <%end%>
74
+ end
75
+ end
76
+ <% end %>
77
+
78
+
79
+
80
+ end
81
+ end
@@ -0,0 +1,64 @@
1
+ <%
2
+ time_now = Time.now.getutc.to_i
3
+ attrs = attributes.map { |i| i.name.camelize }
4
+ str = attrs.join('')
5
+ limit_policy_name = 63
6
+ type_polices = {insert: :write,select: :read,update: :change, delete: :remove}
7
+ type_polices_owner = {insert: :owner_write,select: :owner_read,update: :owner_change, delete: :owner_remove}
8
+
9
+ %>
10
+
11
+ class Create<%= "#{name.underscore.camelize}" %>Policy<%="#{}" %> < ActiveRecord::Migration[7.0]
12
+
13
+ def change
14
+ <%
15
+ policy_name = ->(table_name,method) { "p#{time_now}#{table_name}#{method}"[0,limit_policy_name] }
16
+ db_role = "app_user"
17
+ permission_id = options[:permission_identifier]
18
+
19
+ constraint_for_rls = ->(type) {"
20
+ NULLIF(current_setting('rls.user_id', TRUE), '')::bigint in
21
+ (
22
+ SELECT
23
+ ur.user_id
24
+ FROM permissions p
25
+ INNER JOIN role_permissions rp on rp.permission_id = p.id
26
+ INNER JOIN user_roles ur on rp.role_id = ur.role_id
27
+ WHERE (p.\"#{type_polices[type.to_sym]}\")
28
+ AND p.table_name = 'products'
29
+ )
30
+ or
31
+ (
32
+ NULLIF(current_setting('rls.user_id', TRUE), '')::bigint in
33
+ (
34
+ SELECT
35
+ ur.user_id
36
+ FROM permissions p
37
+ INNER JOIN role_permissions rp on rp.permission_id = p.id
38
+ INNER JOIN user_roles ur on rp.role_id = ur.role_id
39
+ WHERE (p.\"#{type_polices_owner[type.to_sym]}\")
40
+ AND p.table_name = 'products'
41
+ ) and owner_id = NULLIF(current_setting('rls.user_id', TRUE), '')::bigint
42
+ )
43
+ "
44
+ }
45
+ %>
46
+ <% %i(insert select update delete).each do |attr| %>
47
+ execute '<%="GRANT #{attr} ON #{name} TO #{db_role}"%>'
48
+ execute '<%= "ALTER TABLE #{name} ENABLE ROW LEVEL SECURITY" %>'
49
+ reversible do |dir|
50
+ dir.up do
51
+ <%if attr.to_sym ==:insert %>
52
+ execute <<-SQL
53
+ <%= "CREATE POLICY #{policy_name.(name, attr.to_sym)} ON #{name} for #{attr.to_s} TO #{db_role} with check (#{constraint_for_rls[attr.to_s]})" %>
54
+ SQL
55
+ <% elsif %i(select update delete).include?(attr.to_sym) %>
56
+ execute <<-SQL
57
+ <%= "CREATE POLICY #{policy_name.(name, attr.to_sym)} ON #{name} for #{attr.to_s} TO #{db_role} using (#{constraint_for_rls[attr.to_s]})" %>
58
+ SQL
59
+ <%end%>
60
+ end
61
+ end
62
+ <% end %>
63
+ end
64
+ end
@@ -0,0 +1,80 @@
1
+ <%
2
+ time_now = Time.now.getutc.to_i
3
+ attrs = attributes.map { |i| i.name.camelize }
4
+
5
+ limit_policy_name = 63
6
+ type_polices = {insert: :write,
7
+ select: :read,
8
+ update: :change,
9
+ delete: :remove}
10
+ type_polices_owner = {select: :owner_read,
11
+ update: :owner_change,
12
+ delete: :owner_remove}
13
+ %>
14
+
15
+ class Create<%= "#{name.underscore.camelize}#{options[:permission_identifier]}" %>Policy < ActiveRecord::Migration[7.0]
16
+
17
+ def change
18
+ <%
19
+ policy_name = ->(table_name,method) { "p#{time_now}#{table_name}#{method}"[0,limit_policy_name] }
20
+ db_role = "app_user"
21
+ permission_id = options[:permission_identifier]
22
+ owner_rls_policy = ->(type){
23
+ if type.to_sym != :insert
24
+ "
25
+ or
26
+ (
27
+ NULLIF(current_setting('rls.user_id', TRUE), '')::bigint in
28
+ (
29
+ SELECT
30
+ ur.user_id
31
+ FROM permissions p
32
+ INNER JOIN role_permissions rp on rp.permission_id = p.id
33
+ INNER JOIN user_roles ur on rp.role_id = ur.role_id
34
+ WHERE (p.\"#{type_polices_owner[type.to_sym]}\")
35
+ AND p.table_name = 'products'
36
+ ) and owner_id = NULLIF(current_setting('rls.user_id', TRUE), '')::bigint )
37
+ "
38
+ end
39
+ }
40
+ constraint_for_rls = ->(type) {"
41
+ NULLIF(current_setting('rls.user_id', TRUE), '')::bigint in
42
+ (
43
+ SELECT
44
+ ur.user_id
45
+ FROM permissions p
46
+ INNER JOIN role_permissions rp on rp.permission_id = p.id
47
+ INNER JOIN user_roles ur on rp.role_id = ur.role_id
48
+ WHERE (p.\"#{type_polices[type.to_sym]}\")
49
+ AND p.table_name = 'products'
50
+ )
51
+ #{owner_rls_policy[type]}
52
+ "
53
+ }
54
+ %>
55
+
56
+
57
+
58
+
59
+ <% %i(insert select update delete).each do |attr| %>
60
+ execute '<%="GRANT #{attr} ON #{name} TO #{db_role}"%>'
61
+ execute '<%= "ALTER TABLE #{name} ENABLE ROW LEVEL SECURITY" %>'
62
+ reversible do |dir|
63
+ dir.up do
64
+ <%if attr.to_sym ==:insert %>
65
+ execute <<-SQL
66
+ <%= "CREATE POLICY #{policy_name.(name, attr.to_sym)} ON #{name} for #{attr.to_s} TO #{db_role} with check (#{constraint_for_rls[attr.to_s]})" %>
67
+ SQL
68
+ <% elsif %i(select update delete).include?(attr.to_sym) %>
69
+ execute <<-SQL
70
+ <%= "CREATE POLICY #{policy_name.(name, attr.to_sym)} ON #{name} for #{attr.to_s} TO #{db_role} using (#{constraint_for_rls[attr.to_s]})" %>
71
+ SQL
72
+ <%end%>
73
+ end
74
+ end
75
+ <% end %>
76
+
77
+
78
+
79
+ end
80
+ end
@@ -0,0 +1,21 @@
1
+ require 'importmap-rails'
2
+ require 'importmap/commands'
3
+ require 'importmap/map'
4
+ require 'importmap/packager'
5
+ require 'importmap/reloader'
6
+
7
+ require 'bootstrap'
8
+ require 'vanilla_nested'
9
+ require 'vanilla_nested/view_helpers'
10
+
11
+ module RbacRls
12
+ class Engine < ::Rails::Engine
13
+ isolate_namespace RbacRls
14
+
15
+ # initializer "rbac_rls.precompile" do |app|
16
+ # app.config.assets.paths << Rails.root.join('app/assets/javascripts')
17
+ # app.config.assets.precompile << "application.js"
18
+ # end
19
+
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ module RbacRls
2
+ VERSION = "0.1.1"
3
+ end
data/lib/rbac_rls.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "rbac_rls/version"
2
+ require "rbac_rls/engine"
3
+
4
+ module RbacRls
5
+ # Your code goes here...
6
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :rbac_rls do
3
+ # # Task goes here
4
+ # end