rls_rails
rls_rails copied to clipboard
Help with Setup
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))
```
Hiyasirazgar can you see any issues with my setup?
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.