RLS works
This commit is contained in:
@@ -69,17 +69,20 @@ public class RLSTestController {
|
||||
"SELECT current_setting('app.current_user_id', true)",
|
||||
String.class
|
||||
);
|
||||
result.put("user1Context", ctx);
|
||||
result.put("user1Context", ctx.isEmpty() ? "EMPTY" : ctx);
|
||||
return null;
|
||||
});
|
||||
|
||||
// Check if context leaked (should be null or empty)
|
||||
String leakedContext = null;
|
||||
String leakedContext;
|
||||
try {
|
||||
leakedContext = jdbcTemplate.queryForObject(
|
||||
"SELECT current_setting('app.current_user_id', true)",
|
||||
String.class
|
||||
);
|
||||
if (leakedContext == null || leakedContext.isEmpty()) {
|
||||
leakedContext = "NOT_SET";
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Expected - variable should not be set
|
||||
leakedContext = "NOT_SET";
|
||||
@@ -92,7 +95,7 @@ public class RLSTestController {
|
||||
"SELECT current_setting('app.current_user_id', true)",
|
||||
String.class
|
||||
);
|
||||
result.put("user2Context", ctx);
|
||||
result.put("user2Context", ctx.isEmpty() ? "EMPTY" : ctx);
|
||||
return null;
|
||||
});
|
||||
|
||||
@@ -102,6 +105,9 @@ public class RLSTestController {
|
||||
"SELECT current_setting('app.current_user_id', true)",
|
||||
String.class
|
||||
);
|
||||
if (leakedContext == null || leakedContext.isEmpty()) {
|
||||
leakedContext = "NOT_SET";
|
||||
}
|
||||
} catch (Exception e) {
|
||||
leakedContext = "NOT_SET";
|
||||
}
|
||||
@@ -157,27 +163,43 @@ public class RLSTestController {
|
||||
// Enable RLS
|
||||
jdbcTemplate.execute("ALTER TABLE documents ENABLE ROW LEVEL SECURITY");
|
||||
|
||||
// CRITICAL: Force RLS even for table owner (postgres superuser)
|
||||
// Without this, RLS policies are bypassed for the table owner
|
||||
jdbcTemplate.execute("ALTER TABLE documents FORCE ROW LEVEL SECURITY");
|
||||
|
||||
// Create RLS policy
|
||||
// USING clause: determines which rows are visible (for SELECT)
|
||||
// WITH CHECK clause: determines which rows can be inserted/updated
|
||||
// Using NULLIF to handle empty strings from current_setting when variable isn't set
|
||||
jdbcTemplate.execute("""
|
||||
CREATE POLICY user_documents_policy ON documents
|
||||
FOR ALL
|
||||
USING (user_id = current_setting('app.current_user_id', true)::bigint)
|
||||
USING (user_id = NULLIF(current_setting('app.current_user_id', true), '')::bigint)
|
||||
WITH CHECK (user_id = NULLIF(current_setting('app.current_user_id', true), '')::bigint)
|
||||
""");
|
||||
|
||||
// Insert test data
|
||||
jdbcTemplate.update(
|
||||
"INSERT INTO documents (title, content, user_id) VALUES (?, ?, ?)",
|
||||
"User 1 Document", "Private content for user 1", 1L
|
||||
);
|
||||
jdbcTemplate.update(
|
||||
"INSERT INTO documents (title, content, user_id) VALUES (?, ?, ?)",
|
||||
"User 2 Document", "Private content for user 2", 2L
|
||||
);
|
||||
jdbcTemplate.update(
|
||||
"INSERT INTO documents (title, content, user_id) VALUES (?, ?, ?)",
|
||||
"Another User 1 Doc", "More private content for user 1", 1L
|
||||
);
|
||||
// Insert test data WITH RLS context set
|
||||
// Now that FORCE RLS is enabled, even our inserts must respect the policy
|
||||
rlsManager.executeWithRLSContext(1L, scopedTemplate -> {
|
||||
scopedTemplate.update(
|
||||
"INSERT INTO documents (title, content, user_id) VALUES (?, ?, ?)",
|
||||
"User 1 Document", "Private content for user 1", 1L
|
||||
);
|
||||
scopedTemplate.update(
|
||||
"INSERT INTO documents (title, content, user_id) VALUES (?, ?, ?)",
|
||||
"Another User 1 Doc", "More private content for user 1", 1L
|
||||
);
|
||||
return null;
|
||||
});
|
||||
|
||||
return "Database setup complete with RLS enabled";
|
||||
rlsManager.executeWithRLSContext(2L, scopedTemplate -> {
|
||||
scopedTemplate.update(
|
||||
"INSERT INTO documents (title, content, user_id) VALUES (?, ?, ?)",
|
||||
"User 2 Document", "Private content for user 2", 2L
|
||||
);
|
||||
return null;
|
||||
});
|
||||
|
||||
return "Database setup complete with RLS enabled and FORCED for table owner";
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user