suus-io / rls_rails

Row Level Security for Ruby on Rails
MIT License
70 stars 17 forks source link

Help with Setup #28

Open joeyk16 opened 2 years ago

joeyk16 commented 2 years ago

Hello, I've read all the docs about RLS and I still can't get it to work. I feel there's something I'm missing so any help would be great! If we can get it to work we start using it on a large-scale application.

Issue

Basically when I set the current tenant and run User.all I expect only the Users for the current tenant to be returned but I'm getting all users for all tenants. Can you see why it won't return only one User?

admin_1 = Admin.create(name: 'Admin 1')
admin_2 = Admin.create(name: 'Admin 2')
user_1 = User.create(name: 'user 1', admin: admin_1)
user_2 = User.create(name: 'user 2', admin: admin_2)

RLS.set_tenant Admin.first
RLS.enable!

User.all.pluck(:name)
   (2.5ms)  SELECT "users"."name" FROM "users"
 => ["user 1", "user 2"]

 # As you can see it returns both names. I'm expecting it to return  ["user 1"]

Setup

I've created a new rails app so I can test how this works.

I have 2 models, an Admin and a User. Admin has many users and Admin is the tenant model.

My setup is this:

# /initalizers
RLS.configure do |config|
  config.tenant_class = Admin
  config.tenant_fk = :admin_id
  config.policy_dir = 'db/policies'
end
# /db/users/usersv01.rb

RLS.policies_for :users do
  using_tenant
end

I've run the create_rls_functions.rb migration and the below one

# migration

class CreatePolicies < ActiveRecord::Migration[6.1]
  def change
    create_policy(:users, version: 1)

    enable_rls(:users, force: false)
  end
end

It's created a user table that looks like this. I can see the policy below:

row_level_security_development=# \d users
                                          Table "public.users"
   Column   |              Type              | Collation | Nullable |              Default
------------+--------------------------------+-----------+----------+-----------------------------------
 id         | bigint                         |           | not null | nextval('users_id_seq'::regclass)
 admin_id   | bigint                         |           | not null |
 name       | character varying              |           |          |
 created_at | timestamp(6) without time zone |           | not null |
 updated_at | timestamp(6) without time zone |           | not null |
Indexes:
    "users_pkey" PRIMARY KEY, btree (id)
    "index_users_on_admin_id" btree (admin_id)
Foreign-key constraints:
    "fk_rails_1694bfe639" FOREIGN KEY (admin_id) REFERENCES admins(id)
Referenced by:
    TABLE "books" CONSTRAINT "fk_rails_bc582ddd02" FOREIGN KEY (user_id) REFERENCES users(id)
Policies (forced row security enabled):
    POLICY "all_when_disabled_rls"
      USING (rls_disabled())
    POLICY "match_tenant"
      USING ((current_tenant_id() = admin_id))
joeyk16 commented 2 years ago

Hiyasirazgar can you see any issues with my setup?

sbiastoch commented 2 years ago

Maybe your database user is a superuser? In this case RLS is bypassed. See postgres docs:

Superusers and roles with the BYPASSRLS attribute always bypass the row security system when accessing a table. Table owners normally bypass row security as well, though a table owner can choose to be subject to row security with ALTER TABLE ... FORCE ROW LEVEL SECURITY.