"Dag H. Wanvik" <[EMAIL PROTECTED]> writes: > Working on SQL roles, I have encountered a problem related to > invalidation of prepared statements. > > My understanding at this point: Presently, at execute time, permission > is only checked the first time a prepared statement is executed for a > connection, as part of creating a result set object structure which is > subsequently reused (BaseActivation#resultSet). > > When permissions are revoked, invalidation is signaled from > GrantRevokeConstantAction (see TablePrivilegeInfo and > RoutinePrivilegeInfo respectively) via the dependency the prepared > statement has on the *SQL object* (e.g. table) for which premission is > revoked, cf. DERBY-2594, via the action USER_RECOMPILE_REQUEST > (*not* via dependency on the permission descriptor itself). > > This causes the prepare statement to be recompiled, and hence also a > new permissions check (the call to authorize happen as part of > fillResultSet which is conditional, c.f code generation in > StatementNode#generate which generates call to fillResultSet which in > turn calls authorize (see CursorNode#generate which calls > generateAuthorizeCheck to accomplish this). Earlier, permissions > checking happened every time a prepared statement was executed, but > this was changed with the work to reuse result sets, cf. DERBY-827. > > Now, with the introduction of roles, when checking permissions at > execute time, an activation can come to rely on a privilege obtained > indirectly via a role grant to the user of the current session. But > when this role is revoked from the user, execution of the (prepared) > statement should (possibly) no longer be allowed. (Note: there is no > revoke of a privilege here, since the grant of the privilege is to the > role, so the current mechanism to force recompilation is > unsufficient). > > To accomplish the required behavior, the authorize check needs to be > executed anew, possibly leading to an error if no other applicable > privilege can be found to satisfy the query in question. > > I can imagine the following ways of making this happen: > > a) going back to checking permissions for every execution > Any revoked role grant would then be effective immediately. > > b) as part of authorize() (e.g. in > StatementTablePermission#hasPermissionOnTable), introduce a > dependency for the activation on a role grant descriptor (that is, > if indeed a role is required to satisfy the required privilege), > causing the dropping of that descriptor to invalidate any dependent > activation, so a new permission check can take place when the > statement is executed next time. > > c) as part of authorize() introduce a dependency on the Prepared > statement on the role grant descriptor, causing the dropping of > that descriptor to invalidate any dependent prepared statement. > > Currently, a prepared statement can be a Dependent, but not the > activation as far as i can see. I tried c) and it seems to work (but > is it safe to register a dependency at execute time for a prepared > statement?). This is essentially extending the present solution. It > seems a bit heavy, though, to have to recompile, when all that is > needed is a new check in the current connection? Maybe there is a > reason why we cannot make an activation a Dependent? > > I would also like to avoid a) for performance reasons, so b) seems to > have the correct granularity. Comments?
I agree that b) seems reasonable. However, based on my experience from DERBY-827 and DERBY-2594, I think you really need to engage Dan on this. At least, I would never have come up with the idea of using a dependency to invalidate prepared statements by simply looking at the code. Before Dan pointed out how it was supposed to work I was more inclined to perform the check on every execute as that seemed to be more in line with the old behavior. -- dt
