Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I want to implement oracle row level security kind of feature in Java using JOOQ library

Here is an example JOOQ query code:

Result<Record> result = dslContext.select().from(Employee.EMPLOYEE).fetch();

The code above will generate SQL as below:

select [dbo].[Employee].Id,... from [dbo].[Employee]

I want to add a where clause to filter data specific to user security as below:

select [dbo].[Employee].Id,... from [dbo].[Employee] WHERE [dbo].[Employee].Security IN (1,2)
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
478 views
Welcome To Ask or Share your Answers For Others

1 Answer

Explicit predicates

Unless I'm missing some nice SQL Server feature where rows / records contain a pseudo-column called .Security to implement row level security, you should be able to simply write

dslContext.select()
          .from(EMPLOYEE)
          .where(EMPLOYEE.SECURITY.in(1, 2))
          .fetch();

For more info about jOOQ predicate building, see the manual here:

And in particular, the IN predicate:

General solution using jOOQ's ExecuteListener

Given your comments, you're looking for a general way to patch all SQL statements with an additional predicate, no matter what the particular programmer is typing.

You can do this with jOOQ, but beware of the fact that this will just help you enforcing the predicate, not guarantee it, if programmers bypass jOOQ. What you can do is set up an ExecuteListener, intercepting the renderStart() event in order to patch / replace the query being executed. Something along these lines:

@Override
public void renderStart(ExecuteContext ctx) {
    if (ctx.query() instanceof Select) {

        // Operate on jOOQ's internal query model
        SelectQuery<?> select = null;

        // Check if the query was constructed using the "model" API
        if (ctx.query() instanceof SelectQuery) {
            select = (SelectQuery<?>) ctx.query();
        }

        // Check if the query was constructed using the DSL API
        else if (ctx.query() instanceof SelectFinalStep) {
            select = ((SelectFinalStep<?>) ctx.query()).getQuery();
        }

        if (select != null) {
            // Use a more appropriate predicate expression
            // to form more generic predicates which work on all tables
            select.addConditions(EMPLOYEE.SECURITY.in(1, 2));
        }
    }
}

Of course, there's room for improvement to the above. Feel free to discuss use-cases on the user group

General solution using jOOQ's VisitListener

If you're willing to go deep into jOOQ's internals, you an also try to implement a VisitListener and actually transform jOOQ's AST representation of your query. This is documented here:

General solution using views

While the above works, I would personally suggest you use views for this and hide the actual tables from developers. Example:

CREATE VIEW v_employee AS
SELECT a, b, c, ... 
FROM t_employee
WHERE t_employee.security in (1, 2)

With appropriate grants, you can hide the tables from the developers, making sure they will only ever use the views with your desired predicate always in place


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...