SGNL Policy Snippet Advanced Reference

Introduction

This document deals with advanced functions that go beyond the basic capabilities detailed in the SGNL Policy Snippet Reference. There are 2 advanced snippet capabilities that are available in the SGNL product today, these include:

  • Location-Based Snippets
  • Temporal Snippets

To simplify builing these more advanced Snippets, both types are included as Snippet Templates in the SGNL Snippet Builder, enabling SGNL Administrators to create these types of Snippets with a single click and providing the specific business logic desired.

Location-Based Functions

SGNL supports the ability to evaluate an IP Address that was provided during an access evaluation to a resolved location. Various granularites of resolution are available, including:

PropertyDescriptionExample ValueQuery Field Name Attribute
CityThe City resolved from the IP Address presented in the Access Evaluation.“San Francisco”principal.ipAddress.location.city
State/Province/RegionThe region resolved from the IP Address presented in the Access Evaluation.“CA”principal.ipAddress.location.region
CountryThe Country (as an alpha-2 ISO 3166-2 code) resolved from the IP Address presented in the Access Evaluation.“US”principal.ipAddress.location.country
Postal/Zip CodeThe Postal Code resolved from the IP Address presented in the Access Evaluation.“94101”principal.ipAddress.location.postalCode
TimeZoneThe TimeZone of the location that was resolved from the IP Address that was presented in the Access Evaluation“America/Los_Angeles”principal.ipAddress.location.timezone

For production use-cases, SGNL recommends a granularity of Country as the preferred resolution, however SGNL Customers may choose a different resolution granularity depending on their needs/use-case.

Example Location-Based Snippets

Countries are resolved to their 2 character ISO 3166-2 alpha-2 code. The most straightforward example is available to SGNL Administrators as part of our Snippet Templates - it checks to see if the request is coming from a specific country and matches if that’s the case.

To evaluate location as part of an Access Decision, include the ipAddress field and value in the access evaluation

    {
        "principal": {
            "id": "alejandro@wholesalechips.co",
            "ipAddress": "69.181.81.65",
            "deviceId": "48:65:ee:17:7e:0b"
        },
        "queries": [
            {
            "action": "access",
            "assetId": "11754"
            }
        ]
    }

The Snippet Template using the United States as the Country is below:

  {
  "condition": {
      "predicate": {
      "lhs": {
          "queryFieldName": "principal.ipAddress.location.country"
      },
      "op": "EqualTo",
      "rhs": {
          "string": "US"
      }
      }
  },
  "description": "User is physically located in the United States"
  }

You’re able to use combinations of AND, OR, and NOT as detailed in the Policy Snippet Reference, say you wanted to match the snippet if a request was coming from Australia or New Zealand:

{
  "condition": {
    "or": [
      {
        "predicate": {
          "lhs": {
            "queryFieldName": "principal.ipAddress.location.country"
          },
          "op": "EqualTo",
          "rhs": {
            "string": "AU"
          }
        }
      },
      {
        "predicate": {
          "lhs": {
            "queryFieldName": "principal.ipAddress.location.country"
          },
          "op": "EqualTo",
          "rhs": {
            "string": "NZ"
          }
        }
      }
    ]
  },
  "description": "User is physically located in Australia or New Zealand"
}

Where this becomes most powerful is dynamically verifying that a given Principal is in the same location as a specific piece of data that they are trying to access. One we hear frequently at SGNL is the location of an Account in Salesforce. Salesforce has adopted ISO 3166 codes as the standard for Country Picklists and thus allows dynamic comparison between as principal’s current location and the location of Salesforce Data.

Note: The Attribute ID below represents a Salesforce Account’s

{
  "nodes": [
    {
      "entityId": "{{Salesforce Account Entity ID}}",
      "nodeName": "sfdcAccount",
      "queryFieldName": "assetId"
    }
  ],
  "condition": {
    "and": [
      {
        "predicate": {
          "lhs": {
            "queryFieldName": "principal.ipAddress.location.country"
          },
          "op": "EqualTo",
          "rhs": {
            "attributeId": "{{Attribute ID for the 'Billing Country' attribute on Salesforce Accounts}}",
            "nodeName": "sfdcAccount"
          }
        }
      }
    ]
  }
  "description": "Principal Location Matches Customer Location"
}

Temporal Snippets

SGNL supports the ability to evaluate the time an Access Evaluation as context in making an access decision. A range of operations are available to evaluate and compare time, as well as to craft snippets that can look at durations and more. Temporal Snippets allow a range of expressions and functions, which we’ll cover in this section.

There are a number of operators that you’ll encounter when working with Temporal Snippets, including:

OperatorDescriptionExample Value to provide to Operator
ToTimezoneConvert a DateTime attribute to a specific TimeZoneAmerica/Los_Angeles
GetFieldGet a specific portion of a DateTime to perform some operation onSee Below
AddAdd some period of time to an attribute of type DateTime8 Hours
SubtractSubtract some period of time to an attribute of type DateTime8 Hours
LessThanOrEqualToWhen working with DateTime attributes, serves as a function to check if one DateTime is before another DateTime17 (5pm)
GreaterThanOrEqualToWhen working with DateTime attributes, serves as a function to check if one DateTime is after another DateTime8 (8am)

When comparing Dates and Times, you’ll likely find the need to just compare or evaluate just one part of the Date or Time, in these cases, you’ll use the operator GetField, fields that are availble with this operator include:

Available FieldsDescriptionSample Value
SecondThe second45
MinuteThe minute31
HourThe hour of the day, expressed in 24-hour time17
DayThe day of the month22
MonthThe month of the year12
YearThe year2024
DayOfWeekThe ISO8601 Day of the Week (1 is Monday, 7 is Sunday)5
OffsetThe Offset from UTC time, with Z as the shorthand for UTC time+10:00

The easiest way to create your first Temporal Snippet is to create a new Condition Snippet and use our Snippet Templates to select ‘During Business Hours’, by default this snippet localizes to your current timezone. This snippet uses the current time of the request to evaluate whether it was made during US Pacific Time Business Hours, from Monday to Friday.

{
  "condition": {
    "and": [
      {
        "predicate": {
          "lhs": {
            "expr": {
              "lhs": {
                "expr": {
                  "lhs": {
                    "queryFieldName": "time.now"
                  },
                  "op": "ToTimezone",
                  "rhs": {
                    "string": "America/Los_Angeles"
                  }
                }
              },
              "op": "GetField",
              "rhs": {
                "string": "Hour"
              }
            }
          },
          "op": "GreaterThanOrEqualTo",
          "rhs": {
            "integer": 9
          }
        }
      },
      {
        "predicate": {
          "lhs": {
            "expr": {
              "lhs": {
                "expr": {
                  "lhs": {
                    "queryFieldName": "time.now"
                  },
                  "op": "ToTimezone",
                  "rhs": {
                    "string": "America/Los_Angeles"
                  }
                }
              },
              "op": "GetField",
              "rhs": {
                "string": "Hour"
              }
            }
          },
          "op": "LessThanOrEqualTo",
          "rhs": {
            "integer": 17
          }
        }
      },
      {
        "predicate": {
          "lhs": {
            "expr": {
              "lhs": {
                "expr": {
                  "lhs": {
                    "queryFieldName": "time.now"
                  },
                  "op": "ToTimezone",
                  "rhs": {
                    "string": "America/Los_Angeles"
                  }
                }
              },
              "op": "GetField",
              "rhs": {
                "string": "DayOfWeek"
              }
            }
          },
          "op": "LessThanOrEqualTo",
          "rhs": {
            "integer": 5
          }
        }
      }
    ]
  },
  "description": "During US PST Business Hours - Monday to Friday",
}

Let’s say you wanted to create a snippet that checked to see if a ServiceNow Case assigned to a ServiceNow User was still in it’s approved window of time

{
  "condition": {
    "expr": {
      "lhs": {
        "queryFieldName": "time.now"
      },
      "op": "LessThanOrEqualTo",
      "rhs": {
        "attributeId": "{{DateTime Due Date of an Approved ServiceNow Case}}",
        "nodeName": "snowCase"
      }
    }
  },
  "nodes": [
    {
      "entityId": "{{ServiceNow User Entity ID}}",
      "nodeName": "snowUser",
      "queryFieldName": "principalId"
    },
    {
      "entityId": "{{ServiceNow Case Entity ID}}",
      "nodeName": "snowCase"
    }
  ],
  "relationships": [
    {
      "fromNodeName": "snowCase",
      "relationshipName": "AssignedTo",
      "toNodeName": "snowUser",
      "transitive": true,
      "undirected": false
    }
  ],
 "description": "Approved ServiceNow Case is not expired",
}

Let’s say you wanted to evaluate whether a JIRA Change Request was in it’s approval window, and you had the “Time of Approval” and the “Length of Approval” values stored on the JIRA ticket:

"condition": {
    "expr": {
      "lhs": {
        "queryFieldName": "time.now"
      },
      "op": "LessThanOrEqualTo",
      "rhs": {
        "expr": {
          "lhs": {
            "attributeId": "{{JIRA Issue Approved Time Attribute}}",
            "nodeName": "jiraIssue"
          },
          "op": "Add",
          "rhs": {
            "attributeId": "{{JIRA Issue Length of Approval Attribute}",
            "nodeName": "jiraIssue"
          }
        }
      }
    }
  },
  "nodes": [
    {
      "entityId": "{{JIRA User Entity ID}}",
      "nodeName": "jiraUser",
      "queryFieldName": "principalId"
    },
    {
      "entityId": "{{JIRA Issue Entity ID}}",
      "nodeName": "jiraIssue"
    }
  ],
  "relationships": [
    {
      "fromNodeName": "jiraIssue",
      "relationshipName": "AssignedTo",
      "toNodeName": "jiraUser",
      "transitive": false,
      "undirected": false
    }
  ],
 "description": "Approved JIRA Issue is in its approval window",

SGNL also supports the dynamic evaluation of durations against dates and times or other durations. This is particularly useful if you want to understand whether some amount of time has passed that should change the result of policy evaluation. SGNL uses ISO8601 Duration Formats to perform the evaluation using the operators above.

Some example durations that might be useful:

  • 20 Seconds: PT20S
  • 14 Days: P14D
  • 7 Years and 30 Seconds: P7YT30S

An arbitrarily complex example:

  • 2 Years, 3 Months, 4 Days, 12 Hours, 30 Minutes, and 5 Seconds: P2Y3M4DT12H30M5S

With that, say you wanted to see if a ServiceNow Case has been closed for less than 14 days:

{
  "condition": {
    "expr": {
      "lhs": {
        "expr": {
          "lhs": {
            "queryFieldName": "time.now"
          },
          "op": "Subtract",
          "rhs": {
            "duration": "P14D"
          }
        }
      },
      "op": "LessThanOrEqualTo",
      "rhs": {
        "attributeId": "{{closedTime Attribute ID}}",
        "nodeName": "snowCase"
      }
    }
  },
  "description": "Ensure a Case assigned to the User has not been closed for more than 14 days",
  "nodes": [
    {
      "entityId": "{{Service Now Case Entity ID}}",
      "nodeName": "snowCase"
    },
    {
      "entityId": "{{Service Now User Entity ID}}",
      "nodeName": "snowUser",
      "queryFieldName": "principalId"
    }
  ],
  "relationships": [
    {
      "fromNodeName": "snowCase",
      "relationshipName": "AssignedTo",
      "toNodeName": "snowUser",
      "transitive": false,
      "undirected": false
    }
  ],
}