Class ListenNotify
java.lang.Object
dk.cloudcreate.essentials.components.foundation.postgresql.ListenNotify
Helper class for setting up the NOTIFY part of the classical Postgresql LISTEN/NOTIFY concept.
See Listen Notify and
SQL Notify Security It is the responsibility of the user of this component to sanitize any table or column names provided to methods in this class to ensure the security of all the SQL statements generated by this component. The
The
However, Essentials components as well as
The responsibility for implementing protective measures against SQL Injection lies exclusively with the users/developers using the Essentials components and its supporting classes.
Users must ensure thorough sanitization and validation of API input parameters, column, table, and index names.
Insufficient attention to these practices may leave the application vulnerable to SQL injection, potentially endangering the security and integrity of the database.
It is highly recommended that the
To mitigate the risk of SQL injection attacks, external or untrusted inputs should never directly provide the table/column name values.
Failure to adequately sanitize and validate this value could expose the application to SQL injection vulnerabilities, compromising the security and integrity of the database.
See Listen Notify and
SQL Notify Security It is the responsibility of the user of this component to sanitize any table or column names provided to methods in this class to ensure the security of all the SQL statements generated by this component. The
ListenNotify component will
call the PostgresqlUtil.checkIsValidTableOrColumnName(String) method to validate the table/column names as a first line of defense.The
PostgresqlUtil.checkIsValidTableOrColumnName(String) provides an initial layer of defense against SQL injection by applying naming conventions intended to reduce the risk of malicious input.However, Essentials components as well as
PostgresqlUtil.checkIsValidTableOrColumnName(String) does not offer exhaustive protection, nor does it assure the complete security of the resulting SQL against SQL injection threats.The responsibility for implementing protective measures against SQL Injection lies exclusively with the users/developers using the Essentials components and its supporting classes.
Users must ensure thorough sanitization and validation of API input parameters, column, table, and index names.
Insufficient attention to these practices may leave the application vulnerable to SQL injection, potentially endangering the security and integrity of the database.
It is highly recommended that the
tableName value is only derived from a controlled and trusted source.To mitigate the risk of SQL injection attacks, external or untrusted inputs should never directly provide the table/column name values.
Failure to adequately sanitize and validate this value could expose the application to SQL injection vulnerabilities, compromising the security and integrity of the database.
- See Also:
-
Nested Class Summary
Nested Classes -
Field Summary
Fields -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionstatic voidaddChangeNotificationTriggerToTable(org.jdbi.v3.core.Handle handle, String tableName, List<ListenNotify.SqlOperation> triggerOnSqlOperations, String... includeAdditionalTableColumnsInNotificationPayload) Create (or replace an existing) Table change notificationFUNCTIONand an AFTERTRIGGERto the given Table in order to support the classical Postgresql LISTEN/NOTIFY concept.
The NOTIFY/LISTEN channel is defined by theresolveTableChangeChannelName(String)and the payload is a JSON formatted string containing a "table_name" property as well as any additional columns provided in theincludeAdditionalTableColumnsInNotificationPayloadparameter.static reactor.core.publisher.Flux<String>Listen to notifications related to the given table that was setup usingaddChangeNotificationTriggerToTable(Handle, String, List, String...)
As the default Postgresql driver doesn't support asynchronous notification, we're using a polling mechanism.
Note: If you need to listen to notification from multiple tables, then you MUST useMultiTableChangeListenerinstead. Example:static voidremoveChangeNotificationTriggerFromTable(org.jdbi.v3.core.Handle handle, String tableName) Remove Table change notificationFUNCTIONand an AFTERTRIGGERto the given Table in order to support the classical Postgresql LISTEN/NOTIFY concept.static StringresolveTableChangeChannelName(String tableName) Resolve the Postgresql LISTEN/NOTIFY channel name used to communicate each notification related to the changes that we NOTIFY, based on theaddChangeNotificationTriggerToTable(Handle, String, List, String...)setup.
-
Field Details
-
TABLE_NAME
- See Also:
-
SQL_OPERATION
- See Also:
-
-
Constructor Details
-
ListenNotify
public ListenNotify()
-
-
Method Details
-
resolveTableChangeChannelName
Resolve the Postgresql LISTEN/NOTIFY channel name used to communicate each notification related to the changes that we NOTIFY, based on theaddChangeNotificationTriggerToTable(Handle, String, List, String...)setup.- Parameters:
tableName- the name of the table Note:
ThetableNameand thereby the resolvedTable Change Channel Namewill be directly used in constructing SQL statements through string concatenation, which exposes the component to SQL injection attacks.
Security Note:
It is the responsibility of the user of this component to sanitize thetableNameto ensure the security of all the SQL statements generated by this component. TheListenNotifycomponent will call thePostgresqlUtil.checkIsValidTableOrColumnName(String)method to validate the table name as a first line of defense.
ThePostgresqlUtil.checkIsValidTableOrColumnName(String)provides an initial layer of defense against SQL injection by applying naming conventions intended to reduce the risk of malicious input.
However, Essentials components as well asPostgresqlUtil.checkIsValidTableOrColumnName(String)does not offer exhaustive protection, nor does it assure the complete security of the resulting SQL against SQL injection threats.
The responsibility for implementing protective measures against SQL Injection lies exclusively with the users/developers using the Essentials components and its supporting classes.
Users must ensure thorough sanitization and validation of API input parameters, column, table, and index names.
Insufficient attention to these practices may leave the application vulnerable to SQL injection, potentially endangering the security and integrity of the database.
It is highly recommended that thetableNamevalue is only derived from a controlled and trusted source.
To mitigate the risk of SQL injection attacks, external or untrusted inputs should never directly provide thetableNamevalue.
Failure to adequately sanitize and validate this value could expose the application to SQL injection vulnerabilities, compromising the security and integrity of the database.- Returns:
- the resolved channel name (the same as the
tableNamewith thetableNamechecked againstPostgresqlUtil.checkIsValidTableOrColumnName(String)as a first link of defense)
-
addChangeNotificationTriggerToTable
public static void addChangeNotificationTriggerToTable(org.jdbi.v3.core.Handle handle, String tableName, List<ListenNotify.SqlOperation> triggerOnSqlOperations, String... includeAdditionalTableColumnsInNotificationPayload) Create (or replace an existing) Table change notificationFUNCTIONand an AFTERTRIGGERto the given Table in order to support the classical Postgresql LISTEN/NOTIFY concept.
The NOTIFY/LISTEN channel is defined by theresolveTableChangeChannelName(String)and the payload is a JSON formatted string containing a "table_name" property as well as any additional columns provided in theincludeAdditionalTableColumnsInNotificationPayloadparameter.
You can use
listen(Jdbi, String, Duration)to setup asynchronous change notificationImportant information from SQL Notify:
NOTIFY interacts with SQL transactions in some important ways. Firstly, if a NOTIFY is executed inside a transaction, the notify events are not delivered until and unless the transaction is committed. This is appropriate, since if the transaction is aborted, all the commands within it have had no effect, including NOTIFY. But it can be disconcerting if one is expecting the notification events to be delivered immediately. Secondly, if a listening session receives a notification signal while it is within a transaction, the notification event will not be delivered to its connected client until just after the transaction is completed (either committed or aborted). Again, the reasoning is that if a notification were delivered within a transaction that was later aborted, one would want the notification to be undone somehow — but the server cannot “take back” a notification once it has sent it to the client. So notification events are only delivered between transactions. The upshot of this is that applications using NOTIFY for real-time signaling should try to keep their transactions short.
Example:
If the same channel name is signaled multiple times with identical payload strings within the same transaction, only one instance of the notification event is delivered to listeners. On the other hand, notifications with distinct payload strings will always be delivered as distinct notifications.
Given this table definition:
CREATE TABLE test_table (id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, column1 TEXT, column2 TEXT)
When adding notification trigger:
Then the listener subscription:jdbi.useTransaction(handle -> { ListenNotify.addChangeNotificationTriggerToTable(handle, "test_table", List.of(ListenNotify.TriggerOnEvent.INSERT), "column1", "column2"); });
will for an inserted row:subscription = ListenNotify.listen(jdbi, "test_table", Duration.ofMillis(200)) .subscribe(notificationPayload -> { // Handle the String based notification payload received });
receive this payload:jdbi.useTransaction(handle -> { handle.execute("INSERT INTO test_table (column1, column2) VALUES ('Column1Value', 'Column2Value')"); });
{"table_name":"test_table","column1":"Column1Value","column2":"Column2Value"}which you can parse into an Object using e.g. Jacksons ObjectMapper.
If you extendTableChangeNotificationyou automatically inherit the mapping for the table-name and theListenNotify.SqlOperationproperties:class TestTableNotification extends TableChangeNotification { @JsonProperty("column1") private String column1; @JsonProperty("column2") private String column2; } var notification = objectMapper.readValue(notificationPayload, TestTableNotification.class);- Parameters:
handle- the jdbi handletableName- the name of the table for which we want to setup a Table change notification FUNCTION and TRIGGER that can be used for LISTEN/NOTIFY
Note:
ThetableNameas well the result ofresolveTableChangeChannelName(String)will be directly used in constructing SQL statements through string concatenation, which exposes the component to SQL injection attacks.
Security Note:
It is the responsibility of the user of this component to sanitize thetableNameto ensure the security of all the SQL statements generated by this component. TheListenNotifycomponent will call thePostgresqlUtil.checkIsValidTableOrColumnName(String)method to validate the table name as a first line of defense.
ThePostgresqlUtil.checkIsValidTableOrColumnName(String)provides an initial layer of defense against SQL injection by applying naming conventions intended to reduce the risk of malicious input.
However, Essentials components as well asPostgresqlUtil.checkIsValidTableOrColumnName(String)does not offer exhaustive protection, nor does it assure the complete security of the resulting SQL against SQL injection threats.
The responsibility for implementing protective measures against SQL Injection lies exclusively with the users/developers using the Essentials components and its supporting classes.
Users must ensure thorough sanitization and validation of API input parameters, column, table, and index names.
Insufficient attention to these practices may leave the application vulnerable to SQL injection, potentially endangering the security and integrity of the database.
It is highly recommended that thetableNamevalue is only derived from a controlled and trusted source.
To mitigate the risk of SQL injection attacks, external or untrusted inputs should never directly provide thetableNamevalue.
Failure to adequately sanitize and validate this value could expose the application to SQL injection vulnerabilities, compromising the security and integrity of the database.triggerOnSqlOperations- what type ofshould result in a notificationincludeAdditionalTableColumnsInNotificationPayload- any additional column names that should be included in the NOTIFY JSON formatted String payload
Note:
The individual column names inincludeAdditionalTableColumnsInNotificationPayloadwill be directly used in constructing SQL statements through string concatenation, which exposes the component to SQL injection attacks.
Security Note:
It is the responsibility of the user of this component to sanitize theincludeAdditionalTableColumnsInNotificationPayloadto ensure the security of all the SQL statements generated by this component. TheListenNotifycomponent will call thePostgresqlUtil.checkIsValidTableOrColumnName(String)method to validate the column names as a first line of defense.
ThePostgresqlUtil.checkIsValidTableOrColumnName(String)provides an initial layer of defense against SQL injection by applying naming conventions intended to reduce the risk of malicious input.
However, Essentials components as well asPostgresqlUtil.checkIsValidTableOrColumnName(String)does not offer exhaustive protection, nor does it assure the complete security of the resulting SQL against SQL injection threats.
The responsibility for implementing protective measures against SQL Injection lies exclusively with the users/developers using the Essentials components and its supporting classes.
Users must ensure thorough sanitization and validation of API input parameters, column, table, and index names.
Insufficient attention to these practices may leave the application vulnerable to SQL injection, potentially endangering the security and integrity of the database.
It is highly recommended that theincludeAdditionalTableColumnsInNotificationPayloadvalue is only derived from a controlled and trusted source.
To mitigate the risk of SQL injection attacks, external or untrusted inputs should never directly provide theincludeAdditionalTableColumnsInNotificationPayloadvalue.
Failure to adequately sanitize and validate this value could expose the application to SQL injection vulnerabilities, compromising the security and integrity of the database.
-
removeChangeNotificationTriggerFromTable
public static void removeChangeNotificationTriggerFromTable(org.jdbi.v3.core.Handle handle, String tableName) Remove Table change notificationFUNCTIONand an AFTERTRIGGERto the given Table in order to support the classical Postgresql LISTEN/NOTIFY concept.- Parameters:
handle- the jdbi handletableName- the name of the table for which we want to remove the Table change notification FUNCTION and TRIGGER used for LISTEN/NOTIFY
Note:
ThetableNameas well the result ofresolveTableChangeChannelName(String)will be directly used in constructing SQL statements through string concatenation, which exposes the component to SQL injection attacks.
Security Note:
It is the responsibility of the user of this component to sanitize thetableNameto ensure the security of all the SQL statements generated by this component. TheListenNotifycomponent will call thePostgresqlUtil.checkIsValidTableOrColumnName(String)method to validate the table name as a first line of defense.
ThePostgresqlUtil.checkIsValidTableOrColumnName(String)provides an initial layer of defense against SQL injection by applying naming conventions intended to reduce the risk of malicious input.
However, Essentials components as well asPostgresqlUtil.checkIsValidTableOrColumnName(String)does not offer exhaustive protection, nor does it assure the complete security of the resulting SQL against SQL injection threats.
The responsibility for implementing protective measures against SQL Injection lies exclusively with the users/developers using the Essentials components and its supporting classes.
Users must ensure thorough sanitization and validation of API input parameters, column, table, and index names.
Insufficient attention to these practices may leave the application vulnerable to SQL injection, potentially endangering the security and integrity of the database.
It is highly recommended that thetableNamevalue is only derived from a controlled and trusted source.
To mitigate the risk of SQL injection attacks, external or untrusted inputs should never directly provide thetableNamevalue.
Failure to adequately sanitize and validate this value could expose the application to SQL injection vulnerabilities, compromising the security and integrity of the database.
-
listen
public static reactor.core.publisher.Flux<String> listen(org.jdbi.v3.core.Jdbi jdbi, String tableName, Duration pollingInterval) Listen to notifications related to the given table that was setup usingaddChangeNotificationTriggerToTable(Handle, String, List, String...)
As the default Postgresql driver doesn't support asynchronous notification, we're using a polling mechanism.
Note: If you need to listen to notification from multiple tables, then you MUST useMultiTableChangeListenerinstead.Example:
subscription = ListenNotify.listen(jdbi, "test_table", Duration.ofMillis(200)) .subscribe(notificationPayload -> { // Handle the String based notification payload received });- Parameters:
jdbi- the jdbi instancetableName- the name of the table for which we want to remove the Table change notification FUNCTION and TRIGGER used for LISTEN/NOTIFY
Note:
ThetableNameas well the result ofresolveTableChangeChannelName(String)will be directly used in constructing SQL statements through string concatenation, which exposes the component to SQL injection attacks.
Security Note:
It is the responsibility of the user of this component to sanitize thetableNameto ensure the security of all the SQL statements generated by this component. TheListenNotifycomponent will call thePostgresqlUtil.checkIsValidTableOrColumnName(String)method to validate the table name as a first line of defense.
ThePostgresqlUtil.checkIsValidTableOrColumnName(String)provides an initial layer of defense against SQL injection by applying naming conventions intended to reduce the risk of malicious input.
However, Essentials components as well asPostgresqlUtil.checkIsValidTableOrColumnName(String)does not offer exhaustive protection, nor does it assure the complete security of the resulting SQL against SQL injection threats.
The responsibility for implementing protective measures against SQL Injection lies exclusively with the users/developers using the Essentials components and its supporting classes.
Users must ensure thorough sanitization and validation of API input parameters, column, table, and index names.
Insufficient attention to these practices may leave the application vulnerable to SQL injection, potentially endangering the security and integrity of the database.
It is highly recommended that thetableNamevalue is only derived from a controlled and trusted source.
To mitigate the risk of SQL injection attacks, external or untrusted inputs should never directly provide thetableNamevalue.
Failure to adequately sanitize and validate this value could expose the application to SQL injection vulnerabilities, compromising the security and integrity of the database.pollingInterval- the interval between each polling attempt- Returns:
- a
Fluxthat contains the notification payload as a String. - See Also:
-