Here is the proposal for invoker/definer model based on StatementContext.
 
I am proposing that we continue to keep the "invoker" authorizer information in GenericeLanguageConnectionContext. In addition to that, we will keep a stack of authorizers and corresponding default schema descriptors in a StatementContext. When authorizer information (like getAuthorizationId, getDefaultSchema, getCurrentSchemaName etc) will be requested from LanguageConnectionContext, it will check if it has an active StatementContext. If it does have an active StatementContext, then the authorization information requested will be obtained from authorizer at the top of StatementContext's authorizer stack. But if there is no active StatementContext, then authorization information requested will come from LanguageConnectionContext's invoker authorizer. 
 
Any time, a new StatementContext will be pushed, it will get it's first authorizer for it's authorizer stack from it's parent StatementContext(similar to what we do for sqlAllowed information in GenericeLanguageConnectionContext.pushStatementContext ). If there is no parent StatementContext, then the first authorizer for the StatementContext will be the invoker authorizer from GenericeLanguageConnectionContext.
 
I am also proposing to add three methods to StatementContext, addAuthorizerToTopOfStack(2 variations, one that takes the name of the definer and creates an authorizer from it and adds it to the authorizer stack. This is required to put a definer authorizer on StatementContext's authorizer stack. The other method will take the invoker authorizer and will add it to the authorizer stack. This is required to put the invoker authorizer on StatementContext's authorizer stack) and removeAuthorizerFromTopOfStack(This is required to pop the authorizer on top of the authorizer stack). Calls to these methods will be generated during the generation phase of a sql depending on what that sql's needs are for different authorizers. It will be the responsibility of the sql generation phase to generate calls to removeAuthorizerFromTopOfStack when it is finished with the authorizer that it added earlier using addAuthorizerToTopOfStack.

To reitreate, a call to StatementContext.addAuthorizerToTopOfStack(Sting definerName) method should be generated if an object requires a need to switch to the object definer's authorization. The code generation will involve passing the name of the object definer to StatementContext's addAuthorizerToTopOfStack method and that method will generate definer authorizer by using the definer name and will put that authorizer on top of StatementContext's stack of authorizers. Example of code generation for adding a definer authorizer to StatementContext
//We want to put the DEFINER authorizer by finding the owner name of the object and
//generating code to call StatementContext.addAuthorizerToTopOfStack(String definerName)
 acb.pushThisAsActivation(mb);
 mb.callMethod (VMOpcode.INVOKEINTERFACE, null,
  "getLanguageConnectionContext ", ClassName.LanguageConnectionContext, 0);
 mb.callMethod(VMOpcode.INVOKEINTERFACE, null,
   "getStatementContext", " org.apache.derby.iapi.sql.conn.StatementContext", 0);
 String objectOwnerName = getDataDictionary().getSchemaDescriptor(
  objectSchemaUUID, getLanguageConnectionContext().getTransactionCompile()).getSchemaName();
 mb.push(objectOwnerName);
 mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "addAuthorizerToTopOfStack", "void", 1);

If an object needs to switch to invoker's authorization, code should be generated to get the invoker authorizer from GenericLanguageConnectionContext and put that authorizer to the top of authorizer stack by generating code addAuthorizerToTopOfStack(Authorizer invokerAuthorizer). To get the invoker authorizer, I am planning on adding method getInvokerAuthorizer to GenericLanguageConnectionContext.
Example of code generation for adding an invoker authorizer
//We want to put the INVOKER authorizer on StatementContext's authorizer stack.
//We can find the INVOKER authorizer from LanguageConnectionContext.
 acb.pushThisAsActivation(mb);
 mb.callMethod(VMOpcode.INVOKEINTERFACE, null,
  "getLanguageConnectionContext", ClassName.LanguageConnectionContext, 0);
 mb.callMethod(VMOpcode.INVOKEINTERFACE, null,
   "getStatementContext", "org.apache.derby.iapi.sql.conn.StatementContext", 0);
 acb.pushThisAsActivation(mb);
 mb.callMethod (VMOpcode.INVOKEINTERFACE, null,
  "getLanguageConnectionContext", ClassName.LanguageConnectionContext, 0);
 mb.callMethod(VMOpcode.INVOKEINTERFACE, null,
  "getInvokerAuthorizer", " org.apache.derby.iapi.sql.conn.Authorizer", 0);
 mb.callMethod(VMOpcode.INVOKEINTERFACE , null,
  "addAuthorizerToTopOfStack", "void", 1);

Irrespective of which authorizer was added (definer/invoker) to StatementContext, the sql code generation phase should make sure that it generates the code to pop that authorizer from the stack when it is finished with that authorizer. Example of code generation for popping the authorizer that was added earlier and should not be used anymore
 acb.pushThisAsActivation(mb);
 mb.callMethod(VMOpcode.INVOKEINTERFACE, null,
  "getLanguageConnectionContext", ClassName.LanguageConnectionContext, 0);
 mb.callMethod(VMOpcode.INVOKEINTERFACE, null,
   "getStatementContext", "org.apache.derby.iapi.sql.conn.StatementContext", 0);
 mb.callMethod(VMOpcode.INVOKEINTERFACE, null,
  "removeAuthorizerFromTopOfStack", "void", 0);

In case the sql being executed runs into an exception, the StatementContext gets popped out and hence no cleanup action is required for authorizers.  
 
I think this covers it all. Please send your feedback.
Mamta
On 3/13/06, Mamta Satoor <[EMAIL PROTECTED]> wrote:
Thanks, Dan and Satheesh, for your comments. I can see why having the authorizer information at LanguageConnectionContext won't work. I will look into putting this information in StatementContext, similar to what is done for SQL permissions for routines.
 
thanks,
Mamta
 
On 3/13/06, Daniel John Debrunner <[EMAIL PROTECTED] > wrote:
Mamta Satoor wrote:
> While going through some of the Derbylist mails on Grant/Revoke, I
> realized that various database objects in a sqlStandard mode may require
> switching authorizers from the invoker to different definers and vice
> versa. This piece of task sounds interesting to me and hence I have
> following proposal for implementing it.


[snip view example]
>
> I am considering implementing above scenario of switching from one
> authorizer to another by keeping a stack of authorizers in
> GenericLanguageConnectionContext. Prior to intoduction of sqlStandard
> mode for Grant/Revoke, Derby was written to run everything with invoker
> as the authorizer. This single invoker authorizer information is
> currently kept in GenericLanguageConnectionContext's
> authorizer(GenericAuthorizer) field. This field gets set to invoker's
> authorizer when GenericLanguageConnectionContext gets initialized at the
> database connect time. This happens in
> GenericLanguageConnectionContext.initilize method. In addition to
> initilizing authorizer, this method also sets the default schema to a
> schema with the same name as the invoker. So, as we can see,
> GenericLanguageConnectionContext currently just deals with one
> authorizer and that authorizer is always the authorizer corresponding to
> the user who has made connection to the database.
>
> But with the addition of Grant/Revoke to Derby, we can have different
> authorizers active during the execution of a single sql statement. To
> support multiple authorizers, GenericLanguageConnectionContext will need
> to keep a stack of these authorizers and a corresponding stack of
> default schemas descriptors for those authorizers.

How will this handle multiple open statements within a Connection, each
with a different stack of authorization identifiers? Maybe with
Satheesh's comment that this scheme wouldn't work for views makes this
an irrelevant question. Though, while the language connection context
seems ideal when there was only a single authorization identifier, it
doesn't quite seem right now, when statement execution drives the
current authorization identifier.

How similar or different is the requirement to the existing model for
pushing and popping SQL permission restrictions for routines (NO SQL,
CONTAINS SQL etc.)? In that case the current sql permission level is
maintained in the statement context, and not the language connection
context.

The statement context might match exception clean up better:

> In case the sql being executed runs into an exception, as part of the cleanup work,
> we need to remove all the authorizers (except the first one on the
stack since
> it belongs to the "invoker" ie the user who has made this connection to the database)

I don't think is correct, consider any nested situation, for example
routines with server-side JDBC logic, the exception can be caught in the
routine and execution continued. The effective authorization identifer
can not be revoked back to the initial connection, it needs to be reset
to the correct level. For example if the routine was invoked by a
trigger then the authorization identifier should revert to the definer
of the trigger. Using the statement context might provide the correct
behaviour here, as statement contexts are (hopefully :-) popped
correctly in such a situation.

Thanks,
Dan.



Reply via email to