# Policy Marker

The marker is a way to inject dynamic values into a policy. Depending on the library, various markers are supported by default. However, it is really easy to add customer markers. You can find more details about this on the respective language library reference page.

The marker is declared with the leading dollar sign $ and wrapped in curly brackets {…}. It consists of two parts. The source of data (marker name) and data path delimited by a dot .. For example, if you need to get the current user’s email, you can use the ${USER.user_email} marker.

The data path can be complex to give you more flexibility to define its true nature. For example, you can use square brackets [] to access an array element by index or get a deeply nested property in the multi-level object. These are just a few examples of valid paths:

  • ${CONTEXT.Players[0].profile.name}
  • ${USER.address["physical"].zip}
  • ${MAP.Country[USA][NC][Charlotte]}
  • ${PURCHASE.0929431.amount}

Almost in all instances, a policy marker is expected to be a string unless it is explicitly type cast to a different data type.

Markers can be used for two main purposes:

The main difference is that resources and params are compiled once when JSON policy manager is instantiated and conditions are evaluated every single time JSON policy manager is invoked. That is why any conditional statement or param that contains dynamic markers, can be both applicable and not within the same application execution if dynamic markers' values changed.

# Type Casting

The typecasting is extremely important to improve the quality of conditions as it allows you to explicitly convert data points to very specific data types before condition evaluates.

For developers that used to work with strongly typed programming languages (e.g. Java, C#, or C++), this is already second nature. However, for engineers that primarily focus on loosely typed languages (e.g. PHP or JavaScript), typecasting can be taken for granted as most of the time they do not have to worry about data types.

Disregarding what is your background, it is strongly encouraged to typecast markers' values to expected data types especially within conditions. This will significantly reduce the chances of any unexpected logical bugs.

By default JSON policy framework supports type casting fo the following data types:

  • (*string) - convert value to string
  • (*int) - convert numeric value to integer
  • (*float) - convert decimal value to float
  • (*bool) or (*boolean) - convert boolean value representations (varies by language) to true or false
  • (*array) - convert value to array
  • (*json) - decode valid JSON string to array or object (depending on programming language)
  • (*null) - convert null or empty values to null
  • (*date) - convert value to date object
  • (*ip) - convert a readable IP address into a packed format

The custom typecasting can be easily added and for more information, check the respective language reference page.

Most condition types that work with scalar operands (e.g. Equals or In), do a literal comparison, that is why it is some important to make sure that values are typecasted accordingly.

For example, the below statement will not be applicable without proper typecasting because HTTP query params are all strings.

{
    "Statement": {
        "Effect": "allow",
        "Resource": "Page:hello-world",
        "Condition": {
            "Equals": {
                "(*int)${HTTP_QUERY.preview}": 1
            }
        }
    }
}

# Dynamic Mapping

From the policy resources or params you have the way to dynamically declare multiple instances from the array of scalar values.

When JSON policy parser detects the reserved construct => then it assumes that the left side of the expression contains template name with %s part that is going to be replaced with each scalar value from the right side value.

Let's analyze a couple of examples.

{
    "Param": [
        {
            "Key": "country:%s:status => ${ARGS.active_countries}",
            "Value": "active"
        }
    ]
}

Some active_countries property that is fetched from the context may contain an array of country names like Array(Sudan, Yemen, Turkey) and JSON policy parser will declare 3 separate params accordingly. Based on this example, the equivalent for the above policy is the following one:

{
    "Param": [
        {
            "Key": "country:Sudan:status",
            "Value": "active"
        },
        {
            "Key": "country:Yemen:status",
            "Value": "active"
        },
        {
            "Key": "country:Turkey:status",
            "Value": "active"
        }
    ]
}

You can also declare an inline array of values to reduce the size of policies if you know ahead of all the desired values.

{
    "Param": [
        {
            "Key": "player:position:%s => (*json)[1, 2, 3]",
            "Value": true
        }
    ]
}