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? Dag
