IDIEP-129
Author
SponsorUnknown User (nizhikov) 
Created 10.09.2024
Status


Motivation

When processing data, users want to have access to non-tabular (not stored in cache structures) data. 

  1. Application attributes - an associative array of Strings specified on an application side. Business logic might depend on such attributes - application language, application name for audit, etc ([2], [4]).
  2. SecuritySubject can be used to provide fine-grained access control to cache data. For example, CacheInterceptor saves the subject id it along with data and it can be used for fine-grained access control.

The requirements include:

  1. Data must be accessible from user defined functions (QuerySqlFunction, CacheInterceptor) on all nodes participated in queries.
  2. Application attributes ​​can change during the life of the connection (a connection from a connection pool can be sequentially used by different applications).

Ignite does not have a such API:

  1. ServiceCallContext helps solve similar problems, but has several limitations - available only by calls via the IgniteService API and cannot be used for primitive operations.
  2. UserAttributes - allows to set user attributes, but the attribute values ​​are fixed for the entire lifetime of the connection.
  3. ClientListenerConnectionContext - it's available only on single node which directly accepts a client connection.

Application context mechanism exists in Oracle [1] and it's widely used [6]. Support similar mechanisms (custom session variables) exist in multiple DBMS (e.g. SQLServer [8], Snowflake [7], MySQL [9]).

Description

Accessing application attributes

  1. ApplicationContext is an entrypoint for accessing all non-tabular data.
  2. The access requires static methods, because objects injection isn't possible for user functions (QuerySqlFunction are static, CacheInterceptor is a cache singleton).
  3. User can easily create own QuerySqlFunction  to get access to the attributes in SQL queries if needed (see example below).


/** ApplicationContext interface. It's an entrypoint for all non-tabular data. */
public class ApplicationContext {
    /** @return Application attributes set for current thread. */
    public static @Nullable Map<String, String> getAttributes();

    /** @return Current SecuritySubject. */
	public static @Nullable SecuritySubject getSecuritySubject();
 }
 
/** Example, use it in QuerySqlFunction. */
public static class UserDefinedFunctions {
    /** @return Session ID set with application attributes. */
    @QuerySqlFunction
    public static @Nullable String sessionId() {
        Map<String, String> appAttrs = ApplicationContext.getAttributes();
 
        return appAttrs == null ? null : appAttr.get("SESSION_ID");
    }
}

Setting application attributes

Ignite 

  1. Users set attributes with IgniteCache#withApplicationAttributes.
  2. Application attributes are propagated with all messages sent within operation on remote nodes (similar to GridIoSecurityAwareMessage)
  3. Application attributes set to ThreadLocal<Map<String, String>>  in each thread that process operation (similar to SecurityContext#withSecurityContext() ).


// Example of usage.
try (Ignite ign = Ignition.start(ignCfg)) {
    Map<String, String> appAttrs = F.asMap("SESSION_ID", "1234");

	IgniteCache<?, ?> cache = ign.cache("CACHE").withApplicationAttributes(appAttrs);	

 	...
}

IgniteClient (Java) 

  1. Users set attributes with ClientCache#withApplicationAttributes.
  2. New feature is needed in the ClientBitmaskFeature protocol.


// Example of usage.
try (IgniteClient cln = Ignition.startClient(clnCfg)) {
    Map<String, String> appAttrs = F.asMap("SESSION_ID", "1234");

	ClientCache<?, ?> cache = cln.cache("CACHE").withApplicationAttributes(appAttrs);	

 	...
}

JDBC

The standard jdbc protocol describes the methods Connection#setClientInfo, which allow changing the values ​​of client attributes during the life of the connection [3]. Implementation features:

  1. The list of attributes that can be set using #setClientInfo is arbitrary. The documentation recommends strictly limiting the set of attributes, but this is not necessary. For example, Oracle does not have such a limitation [5]. The setClientInfo array is completely translated into the getClientAttributes array.
  2. The parameters set in setClientInfo are passed along with each JdbcRequest (this requires a new feature in JdbcThinFeature).
  3. The client must reset the set values ​​itself.


// JDBC connection to Ignite server.
try (Connection conn = DriverManager.getConnection(URL)) {
    conn.setClientInfo("SESSION_ID", "1234");
 
    ...
}

Risks and Assumptions

  1. No security checks are performed on the application attributes.
  2. Application attributes keys and values are strings, to avoid serialization problems.
  3. Application attributes should be small. 

Discussion Links

// Links to discussions on the devlist, if applicable.

Reference Links

[1] https://docs.oracle.com/en/database/oracle/oracle-database/19/dbseg/using-application-contexts-to-retrieve-user-information.html#GUID-51C9D5FA-6787-4F05-82EF-A5968BEDC5A0

[2] https://stackoverflow.com/questions/71067911/use-oracles-dbms-session-set-context-in-entity-framework-core

[3] https://docs.oracle.com/en/java/javase/11/docs/api/java.sql/java/sql/Connection.html#setClientInfo(java.lang.String,java.lang.String)

[4] https://torofimofu.blogspot.com/2014/05/oracle.html

[5] https://docs.oracle.com/database/121/JJDBC/jdbcvers.htm#BABDAEEC

[6] https://stackoverflow.com/search?tab=newest&q=SYS_CONTEXT

[7] https://docs.snowflake.com/en/sql-reference/session-variables#session-variable-functions

[8] https://learn.microsoft.com/en-us/sql/t-sql/functions/session-context-transact-sql?view=sql-server-ver16

[9] https://dev.mysql.com/doc/refman/8.4/en/user-variables.html

Tickets

// Links or report with relevant JIRA tickets.