USER MANUALS

Dynamic Restrictions Policy

The Dynamic Restriction Policy is designed for generic access control based on external security tables. It is available for selection in various restriction definition dialogs where a Custom View Policy can be chosen.

This policy generates dynamic restrictions by querying a specified security table (a Denodo view) and applying rules to the retrieved data. This allows for flexible and context-aware access control.

Parameters

The Dynamic Restriction Policy receives the following parameters during its configuration:

  • Database view name: The name of the Denodo database containing the view that serves as the security table.

  • View name: The name of the view used as the security table.

  • Policy rules: A JSON-formatted text defining a list of rules for generating restrictions. Tags may be used within the rule definitions, which will be resolved dynamically at runtime.

  • On rule absent: Defines the default restriction behavior when no policy rules generate restrictions (i.e., no rows from the security table match any rule, or no rules are defined). Valid options are:

    • ACCEPT: The query is accepted without any restrictions.

    • DENY: A privileges error accessing the view will be thrown.

    • REJECT: The rows which do not meet the generated condition will be excluded from the results.

    • MASKING: Masking is applied to sensitive fields, as defined in the policy rules.

Policy Rules (JSON Configuration)

The Policy rules parameter is a JSON text object containing the configuration for how the policy generates restrictions. It must include the following elements:

  • searchExpression: This is a condition applied to the WHERE clause when executing the specified Denodo view (View name parameter). It filters the rows retrieved from the security table. It supports the use of predefined wildcards, which return data available from the com.denodo.common.custom.policy.CustomRestrictionPolicyContext class:

    • @ELEMENT_DATABASE: The database of the element to which the custom policy is assigned.

    • @ELEMENT_NAME: The name of the element to which the custom policy is assigned.

    • @ELEMENT_TYPE: The type of the element to which the custom policy is assigned (e.g., ‘VIEW’, ‘STORED PROCEDURE’).

    • @USER_AGENT: The user agent that executes the query.

    • @USER_NAME: The name of the user executing the query.

    • @USER_ROLES: The roles of the user to whom the policy is being checked.

    Note

    The value will be a text with the roles separated by commas which can be used with the IN operator.

    • @CREDENTIALS_NAME: The name of the credential to which the custom policy is assigned.

    • @CREDENTIALS_TYPE: The type of credential to which the custom policy is assigned (e.g., ‘USER’, ‘ROLE’).

    The searchExpression is modified based on the tags of the view specified as the security table. Tags present in the expression are replaced with the corresponding tagged field from the security view, if it exists.

  • restriction: When creating a restriction, you need to specify its type. If no value is provided, the restriction defaults to REJECT. However, if you want to apply masking, you have two options:

    • MASKING_IF_ANY_FIELD: This option applies masking if any of the fields specified in sensitiveFields are present in the query’s selection list.

    • MASKING_IF_ALL_FIELDS: This option applies masking only when all of the fields specified in sensitiveFields are present in the query’s selection list.

  • sensitiveFields: This is a list of objects, required when the restriction type is MASKING. For each element in this list, you must provide:

    • The name of the field (or tag) to be masked.

    • The masking expression to be applied to that field. Valid values are specified by com.denodo.common.custom.policy.CustomMaskingExpression and include: CUSTOM, DEFAULT, FIRST_4, HIDE, LATEST_4, ONLY_YEAR, REDACT, REDACT_ASTERISK, REMOVE_TIME, REMOVE_DAY, ROUND, SET_0, SET_MINUS_1. If CUSTOM is selected, an additional expression field must be provided with the custom masking VQL expression.

    The sensitiveFields list is also modified based on the tags of the view used as the security table.

  • rules: An array of rule definitions that define how the retrieved rows from the executed Denodo view (after applying the searchExpression) are converted into restrictions enforced by the policy. Each rule consists of the following elements:

    • antecedentCondition: A condition applied to the rows returned from the security table. If this condition is met for a given row, the rule is triggered.

      The antecedentCondition is modified based on the tags of the view specified in the custom view policy.

    • mappings: An array of objects defining how to extract data from the security table’s rows to be used in the consequentCondition. Each mapping object has:

      • key: The name of the field from the security table whose value will be assigned to the value variable. Tags can be also applied.

      • value: The name of a variable to be used in the consequentCondition.

    • consequentCondition: Specifies the condition that will be generated by this rule and added at runtime to the view involved in the query. This is the actual restriction applied.

      The consequentCondition is modified based on the tags of the view to which the restriction is being applied.

    Rule Logic:

    • When multiple rows from the security table match a single rule, the restrictions generated by each matching row for that rule are combined with an OR condition.

    • When Conditions are generated by different rules they are combined using AND conditions.

    Note

    Conditions used in antecedentCondition and consequentCondition must not allow subqueries.

Policy Execution Flow

  1. The custom policy dynamic_restrictions_policy executes the specified view (security table) as defined.

  2. The searchExpression is added as a WHERE clause to this execution, filtering the rows from the security table.

  3. Each tuple (row) returned after executing the security view with the searchExpression is matched against each defined rule in the rules array.

  4. If the antecedentCondition of a rule is met by a tuple, the condition defined in the consequentCondition is generated. The mappings indicate how fields from the security view are used as values for variables in the consequentCondition.

  5. Finally, the generated restrictions are returned by the custom view policy.

  6. If no condition is generated by any rule (i.e., no rows match any rule), then the restriction defined by the On rule absent parameter is returned.

Examples

Consider the following example security and data tables:

Security Table

userid

sec_level

value

role_name

A123

WW

ALL

reader

A555

REGION

ASIA

editor

A555

SBE

HPA

reader

A432

REGION

ASIA

editor

A432

REGION

EU

reader

A111

SBE

HPA

reader

A111

SBE

PWR

editor

Data Table

id

sensitive_data

region

sbe

1

Only for Asia HPA

ASIA

HPA

2

Only for Asia PWR

ASIA

PWR

3

Only for Asia TPR

ASIA

TPR

4

Only for EU HPA

EU

HPA

5

Only for EU PWR

EU

PWR

6

Only for EU TPR

EU

TPR

7

Only for America PWR

America

PWR

8

Only for America HPA

America

HPA

9

Only for America TPR

America

TPR

REJECT Example

Let’s assume the user A555 queries a view. The policy will use the security table to determine restrictions.

Policy Configuration (JSON for Rules definition):

{
    "searchExpression": "lower(userid_tag)=lower(@USER_NAME)",
    "rules": [
        {
            "antecedentCondition": "sec_level_tag = 'REGION'",
            "mappings": [
                {
                    "key": "value",
                    "value": "region_value"
                }
            ],
            "consequentCondition": "region_tag = region_value"
        },
        {
            "antecedentCondition": "sec_level_tag ='SBE'",
            "mappings": [
                {
                    "key": "value",
                    "value": "sbe_value"
                }
            ],
            "consequentCondition": "sbe_tag = sbe_value"
        }
    ]
}

Explanation:

  • searchExpression: lower(userid_tag)=lower(@USER_NAME)

    When user A555 queries, this translates to lower(userid) = 'a555' when querying the Security table. This will retrieve rows for user A555.

  • Default Restriction: REJECT:

    The policy applies a REJECT restriction by default because none is provided.

  • First Rule (sec_level_tag = ‘REGION’):

    The antecedent sec_level_tag = 'REGION' matches the row where userId = 'A555' and sec_level = 'REGION'.

    The mapping "key": "value", "value": "region_value" will then extract the value field from this row, which is 'ASIA'. This 'ASIA' value is assigned to the region_value variable.

    Consequently, the consequent region_tag = region_value becomes region_tag = 'ASIA'.

  • Second Rule (sec_level_tag = ‘SBE’):

    The antecedent sec_level_tag = 'SBE' matches the row where userId = 'A555' and sec_level = 'SBE'.

    The mapping "key": "value", "value": "sbe_value" will extract the value field from this row, which is 'HPA'. This 'HPA' value is assigned to the sbe_value variable.

    As a result, the consequent sbe_tag = sbe_value becomes sbe_tag = 'HPA'.

  • Combined Restriction:

    Since both rules generate restrictions for user A555, these are combined with an AND condition. The final restriction applied to the query would be:

    (region_tag = 'ASIA') AND (sbe_tag = 'HPA')

    This ensures that user A555 can only see data where the region field is ‘ASIA’ and the sbe field is ‘HPA’.

    Result example 1

    id

    sensitive_data

    region

    sbe

    1

    Only for Asia HPA

    ASIA

    HPA

Roles-Based Filtering Example

This example demonstrates how to filter data based on a user’s assigned roles using the predefined @USER_ROLES wildcard. In this scenario, the user executing the query has been assigned the reader and unloader roles.

{
    "searchExpression": "role_name IN (@USER_ROLES)",
    "rules": [
        {
            "antecedentCondition": "sec_level_tag = 'REGION'",
            "mappings": [
                {
                    "key": "value",
                    "value": "region_value"
                }
            ],
            "consequentCondition": "region_tag = region_value"
        }
    ]
}

Explanation:

  • searchExpression: role_name IN (@USER_ROLES)

    The system substitutes @USER_ROLES with the user’s assigned roles. In this scenario, this results in the filter role_name IN ('reader', 'unloader').

  • First Rule (sec_level_tag = ‘REGION’):

    The antecedent sec_level_tag = 'REGION' matches the row where sec_level = 'REGION' and role_name = 'reader'.

    The mapping "key": "value", "value": "region_value" will then extract the value field from this row, which is 'EU'. This 'EU' value is assigned to the region_value variable.

    Consequently, the consequent region_tag = region_value becomes region_tag = 'EU'.

    Result example roles filtering

    id

    sensitive_data

    region

    sbe

    4

    Only for EU HPA

    EU

    HPA

    5

    Only for EU PWR

    EU

    PWR

    6

    Only for EU TPR

    EU

    TPR

MASKING Example

This example demonstrates how to apply masking to sensitive fields based on policy rules.

Policy Configuration (JSON for Policy rules):

{
    "searchExpression": "lower(userid_tag)=lower(@USER_NAME)",
    "restriction": "MASKING_IF_ANY_FIELD",
    "sensitiveFields": [
        {"tagged_field1":
            {"type": "DEFAULT"}
        },
        {"tagged_field2":
            {"type":"REDACT"}
        },
        {"tagged_field3":
            {"type":"SET_0"}
        },
        {"tagged_field4": {
            "type": "CUSTOM",
            "expression": "HASH(tagged_field3)"}
        }
    ],
    "rules": [
        {
            "antecedentCondition": "sec_level_tag = 'REGION'",
            "mappings": [
                {
                    "key": "value",
                    "value": "region_value"
                }
            ],
            "consequentCondition": "region_tag = region_value"
        }
    ]
}

Explanation:

  • searchExpression: Similar to the REJECT example, this filters the security table based on the current user. For this example, user A555 executes the query.

  • restriction: Set to MASKING_IF_ANY_FIELD, meaning if any of the fields listed in sensitiveFields are part of the query’s output, masking will be applied.

  • sensitiveFields: Defines the fields that are considered sensitive and their respective masking expressions:

    • tagged_field1 will use the default masking.

      Note

      HIDE is the DEFAULT custom expression type

    • tagged_field2 will be redacted.

    • tagged_field3 will be set to 0.

    • tagged_field4 will be masked using a custom hash expression derived from the value of tagged_field3.

    The sensitiveFields are dynamically resolved based on the tags of the view to which the policy is applied. For more detailed information about row restrictions and masking expressions see Row Restrictions.

  • rules: Similar to the REJECT example, these rules define conditions that, if met, will display the rows of the data table and mask the rows that do not meet the constraint. In this example the final restriction will be region='ASIA'.

    Result example 2

    id

    sensitive_data

    region

    sbe

    1

    Only for Asia HPA

    ASIA

    HPA

    2

    Only for Asia PWR

    ASIA

    PWR

    3

    Only for Asia TPR

    ASIA

    TPR

    ********

    0

    8ubjub/1nyk/DpAZoeyrxQ==

    ********

    0

    8ubjub/1nyk/DpAZoeyrxQ==

    ********

    0

    8ubjub/1nyk/DpAZoeyrxQ==

    ********

    0

    CI8AODPVI9nczFKekpr9xw==

    ********

    0

    CI8AODPVI9nczFKekpr9xw==

    ********

    0

    CI8AODPVI9nczFKekpr9xw==

MASKING Example Affecting All Rows

This scenario shows how to mask sensitive data for users meeting the searchExpression, while allowing users not matching the searchExpression to see the data (due to On rule Absent: ACCEPT).

Policy Configuration:

  • On rule absent: ACCEPT (configured outside the JSON rules, in the policy definition dialog)

  • Policy Configuration (JSON for Policy rules):

{
    "searchExpression": "lower(userid_tag)=lower(@USER_NAME)",
    "restriction": "MASKING_IF_ANY_FIELD",
    "sensitiveFields": [
        {"sensitive_data":
            {"type": "REDACT"}
        }
    ],
    "rules": [
        {
            "antecedentCondition": "1=1",
            "mappings": [],
            "consequentCondition": "1=0"
        }
    ]
}

Explanation:

  • searchExpression: lower(userid_tag)=lower(@USER_NAME). This will filter the security table for the current user.

  • restriction: MASKING_IF_ANY_FIELD, meaning sensitive fields will be masked.

  • sensitiveFields: sensitive_data is defined as a field to be redacted.

  • rules:

    antecedentCondition: 1=1

    This condition is always true, meaning that for any row retrieved from the security table (after applying searchExpression), this rule will always apply.

    consequentCondition: 1=0

    This is a false condition. While this condition is technically generated, it acts as a placeholder that will never be met by any row in the data view. This effectively means that for users who trigger this rule, no data rows would satisfy the restriction. However, the purpose here is not to filter rows, but to trigger the masking.

Behavior for a user matching the searchExpression (e.g., user A555):

  1. If the current user matches the searchExpression, the policy will execute the security table query.

  2. Since antecedentCondition is 1=1, the rule will always be activated for any rows returned from the security table.

  3. The policy generates a restriction (even though it’s 1=0). The critical point is that a restriction is generated. Given the MASKING_IF_ANY_FIELD setting and the successful generation of a rule, the sensitive_data field will be redacted for all rows returned to this user, as the 1=0 condition effectively activates the masking behavior without filtering any data rows.

    Result example 3 user A555

    id

    sensitive_data

    region

    sbe

    1

    ********

    ASIA

    HPA

    2

    ********

    ASIA

    PWR

    3

    ********

    ASIA

    TPR

    4

    ********

    EU

    HPA

    5

    ********

    EU

    PWR

    6

    ********

    EU

    TPR

    7

    ********

    America

    HPA

    8

    ********

    America

    PWR

    9

    ********

    America

    TPR

Behavior for a user NOT matching the searchExpression (e.g., user B222):

  1. If the current user does not match the searchExpression, no rows will be returned from the security table after applying the searchExpression.

  2. Consequently, no rules will be triggered, as their antecedentCondition cannot be met by any rows from the (empty) result of the security table query.

  3. In this scenario, the On rule absent parameter comes into play. Since it’s explicitly set to ACCEPT, the query will proceed without any restrictions, including no masking. The user will see all data from the view without any redactions.

Result example 3 user B222

id

sensitive_data

region

sbe

1

Only for Asia HPA

ASIA

HPA

2

Only for Asia PWR

ASIA

PWR

3

Only for Asia TPR

ASIA

TPR

4

Only for EU HPA

EU

HPA

5

Only for EU PWR

EU

PWR

6

Only for EU TPR

EU

TPR

7

Only for America HPA

America

HPA

8

Only for America PWR

America

PWR

9

Only for America TPR

America

TPR

Add feedback