Using templates, variables and filters when provisioning VMRs, devices and users

When you configure an LDAP synchronization template to provision VMRs, devices and users, you define patterns for how some of those properties — such as the VMR name or a device alias — are generated from the data in the LDAP sync source.

Pexip Infinity's LDAP sync templates use a subset of the jinja2 templating language (https://jinja.palletsprojects.com/en/2.10.x/templates/).

These templates consist of the following elements:

  • literal text that you want to add to the output or result, such as prefixing every generated VMR name with meet.
  • variables that are substituted with values from the LDAP sync source, such as givenName
  • filters that can manipulate text or modify the content of variables or text strings, such as join or lower
  • delimiters such as {{...}} and pipes | which are used to enclose variables and define filter expressions
  • jinja statements and control structures (see https://jinja.palletsprojects.com/en/2.10.x/templates/#list-of-control-structures)

An example pattern would be meet.{{givenName|lower}}.{{sn|lower}}. This concatenates the literal text meet. with the content of the givenName variable that has been converted to lower case by the lower filter. This is then concatenated with a period . and then the sn (surname) variable, also piped through the lower filter.

Therefore if Alice Parkes had an entry in the LDAP directory with givenName=Alice and sn=Parkes, the example pattern above would produce meet.alice.parkes.

The following sections provide more information about the supported variables, jinja2 filters and custom Pexip filters, with each section including example expressions that demonstrate how to format your patterns.

For more reference information and to see where else jinja2 templates are used within Pexip Infinity, see Jinja2 templates and filters.

Supported variables

When syncing each VMR, device or user record, Pexip Infinity extracts LDAP fields from the directory records in the LDAP data source and makes them available as variables (with the same name) for use in the sync template. Pexip Infinity offers several standard fields, and administrators can also add their own custom set of fields. Fields with multiple values are also supported.

When using variables:

  • You must enclose the variable name within {{...}} delimiters, for example {{givenName}}.
  • Any combination of the variables can be used in any synchronization template pattern field.
  • Fields that are not present in the LDAP source will appear as "None".
  • Capitalization of the variable name is important. The variable must be spelled exactly as shown below.

Standard LDAP fields

Pexip Infinity automatically extracts and makes available the following standard LDAP fields:

Variable name Description
company Company/organization name
department Department name
displayName User's preferred display name
employeeID * Employee reference number
givenName First name
mail Email address
mailNickname * Typically used to store an alternative email address (e.g. based on a maiden name); see Change of name below
mobile Mobile phone number
objectGUID Globally unique identifier for the directory object (user entry)
sAMAccountName Logon name (domainname\username format)
sn Last name or surname
telephoneNumber Telephone number
title Job title
userPrincipalName Logon name (username@domainname format)

* Not present in all AD schemas.

Custom LDAP fields

In addition to the standard set of fields made available automatically by Pexip Infinity, administrators can configure their own custom set of fields to support additional attributes in their LDAP/AD schemas.

To add a custom LDAP field:

  1. Go to Utilities > LDAP sync fields.
  2. Select Add LDAP sync field, and then complete the following fields:

    LDAP field name

    The name of LDAP field to be read from the LDAP server.

    The name is case sensitive. If the name does not match exactly against a field in the LDAP data source its value will appear (when used in a template) as "None".

    Template variable name

    The name of the variable to use in sync templates that will contain the value of the LDAP field.

    We recommend that you set this name to something similar to the LDAP field name, but note that this name cannot contain hyphens.

    Description An optional description of the LDAP attribute.
    Is binary (advanced options)

    In advanced scenarios, some binary LDAP fields such as GUIDs require special encoding. In such cases, expand the advanced options and select Is binary.

    Do not select this option for ordinary textual or numeric LDAP fields.

  3. Select Save.

    The Template variable name that represents the custom LDAP field can now be used in a template along with the standard LDAP fields.

LDAP fields with multiple values

In some scenarios, an LDAP field could contain multiple values for a given user. For example the LDAP proxyAddresses field (which you would have to configure as a custom LDAP field as described above) could contain many addresses.

In these cases, a special multi_valued_attrs variable is automatically created. This variable will contain all of the LDAP fields that are found to have multiple values for a given user. This means if two fields have multiple values, the multi_valued_attrs variable will contain all of the values for those two fields. It will not contain any of the fields that have just a single value.

You can then use the pex_find_first_match filter to extract values from the variable. This filter can be used to extract from a string list the first value that matches a specified regex.

Example usage: {{pex_find_first_match(multi_valued_attrs.proxyAddresses, "^sip:.*")}}

This would extract the first proxyAddresses value that starts with "sip:" i.e. the first proxy that has a SIP-style address.

However, as the multi_valued_attrs variable is only populated with LDAP fields that contain multiple values, a better expression in this case would be: {{pex_find_first_match(multi_valued_attrs.proxyAddresses, "^sip:.*") or proxyAddresses}} which will return the first/only value in the standard proxyAddresses variable if only one value is available or the regex does not find a match.

More complex matching is possible by iterating over the multi_valued_attrs collection in other ways.

Change of name

A typical scenario encountered by IT administrators is when someone changes their name (e.g. after getting married) and wants to preserve their original contact address alongside their new contact details.

One way in which you could support this in Pexip Infinity is by defining multiple VMR alias patterns in your template. This example approach assumes that the LDAP mail field holds the user's contact address, and a mailNickname field is used to hold an alternative address. Thus, you could define the following patterns:

VMR alias 1 pattern: meet.{{mail}}
VMR alias 2 pattern: {%if mailNickname %}{#Add alias based on user's maiden name mailNickname#}meet.{{mailNickname}}{% else %}{#intentionally leave the alias blank#}{% endif %}

For most users, this will generate a single VMR alias in the format meet.<email address>, and the VMR's second alias will remain blank as the LDAP mailNickname field for those users will be empty.

For example, user Ann Jones has her LDAP mail field set to ann.jones@example.com and her LDAP mailNickname field is blank. Her VMR will have a single alias of meet.ann.jones@example.com.

When a user changes their name, the administrator would update the user's LDAP mail field to match their new name and populate the mailNickname field with the previous value of the mail field.

Now, the next time the administrator performs a template synchronization, the user's VMR aliases will be updated. The first alias will be changed to a new string based on the user's new email address, and a second alias will also be generated based upon the mailNickname field. This means that the user can be contacted via either their previous VMR alias or the new alias.

In our example, let's assume that Ann Jones changes her name to Ann Smith. The administrator changes her LDAP mail field to ann.smith@example.com and sets her LDAP mailNickname field to ann.jones@example.com. Her VMR will now have two aliases: meet.ann.smith@example.com and meet.ann.jones@example.com.

Supported jinja2 filters

Pexip Infinity supports a subset of filters from the jinja2 templating language. Any jinja filters that are not listed below have been disabled in Pexip Infinity. See https://jinja.palletsprojects.com/en/2.10.x/templates/#list-of-builtin-filters for more information about these filters.

abs float last replace truncate
capitalize format length round upper
default int lower striptags  
first join range trim  

To use a filter you would typically follow the syntax {{<source_value>|<filter_name>}}.

In most cases the <source_value> is likely to be a variable, for example {{givenName|upper}}, although it could be one or more literal values, for example {{ [1, 2, 3, 4]|join }}.

Some filters take parameters, for example {{sn|truncate(5)}}. You can also use multiple filters in the same expression, for example {{sn|truncate(5)|upper}}.

The trim filter is often used. This trims leading and trailing whitespace from the string held in the <source_value>.

Example usage: {{title|trim}}

If the title field contained "   Project Manager   ", this would be converted to "Project Manager".

The replace filter is also often used. This replaces one string with another string. The first argument of the filter is the substring that should be replaced, the second is the replacement string. If the optional third argument count is given, only the first count occurrences are replaced.

Example usage: {{ department|replace("Personnel", "HR") }}

If the department field contained "Personnel Department Personnel", this would be converted to "HR Department HR".

Example usage: {{ department|replace("Personnel", "HR", 1) }}

In this case a count of 1 is specified, thus if the department field contained "Personnel Department Personnel", it would be converted to "HR Department Personnel".

For more complicated search and replace patterns, use the custom Pexip pex_regex_replace filter described below.

Custom Pexip filters

In addition to the jinja filters, Pexip also provides the following custom filters, which are typically used to manipulate data:

Filter Description and example usage
pex_base64

Performs Base64 encoding on the input field.

Example usage: {{provisiondata|pex_base64}}

In this example, a local variable named provisiondata is encoded as Base64.

pex_clean_phone_number

This extracts only +0123456789 characters (and removes ()&%#@|"':;, A-Z,a-z etc).

Example usage: {{ telephoneNumber|pex_clean_phone_number }}

In this example, if telephoneNumber is '+44 (20) 12345678', this expression would return '+442012345678'.

pex_debug_log(message)

The pex_debug_log filter can be used to help debug your script. It writes debug messages to the Pexip Infinity support log. You can include literal text and variables.

To avoid filling the support log and causing it to rotate, remove all pex_debug_log filters from your scripts as soon as they are working correctly.

pex_find_first_match(string_list, 'find_regex')

This extracts from the list the first value that matches the specified regex.

It is typically used to extract a value from the multi_valued_attrsvariable where an LDAP field, such as proxyAddresses, contains multiple values.

Example usage: {{pex_find_first_match(multi_valued_attrs.proxyAddresses, "^sip:.*")}}

This would extract the first proxyAddresses value that starts with "sip:" i.e. the first proxy that has a SIP-style address.

pex_hash

Performs a hash of a field.

You could use this, for example, to generate random-looking PINs based on a hash of one or more fields from the directory (you would also need to apply another filter such as pex_tail to set the PIN to an appropriate valid length).

Example usage: {{ sAMAccountName|pex_hash|pex_tail(6) }}

pex_head(maxlength)

Returns, at most, the first maxlength characters from the input field.

Example usage: {{ givenName|pex_head(4) }}

In this example, for a givenName of 'Alice' this expression would return 'Alic', and a givenName of 'Bob' would return 'Bob'.

pex_in_subnet

Tests whether a given address is within one or more subnets. It takes as input the address you want to test, and one or more subnet ranges, and returns either True or False.

pex_md5

Applies an MD5 hash to the input field.

Example usage: https://www.gravatar.com/avatar/{{mail|trim|lower|pex_md5}}?d=404

This example generates a URL that conforms with how the Gravatar service constructs its URLs based on users' email addresses.

pex_now(timezone)

The pex_now filter takes an optional parameter of a timezone description e.g. 'UTC', 'Asia/Tokyo', or 'US/Eastern' and returns the current date and time for that timezone. UTC is assumed if a timezone is not provided.

The resulting available attributes are year, month, day, hour, minute, second and microsecond.

Example usage:
{% set now = pex_now("Europe/London") %}
{% if now.month == 2 and now.day == 29 %}

pex_random_pin(length)

Generates a random PIN of the given length. Note that this filter does not take any input.

Example usage: {{ [9,pex_random_pin(5)]|join }} for the Host PIN, and {{ [2,pex_random_pin(5)]|join }} for the Guest PIN.

A usage pattern such as this (where the Host PIN starts with a 9, and the Guest PIN starts with a 2) ensures that a VMR can never be configured with a Host PIN that is the same as the Guest PIN.

You would typically use this filter in conjunction with the Allow PIN settings to be manually overridden option to ensure that the PIN is not reset every time a template resync is performed.

Do not use pex_random_pin() to generate aliases. This filter generates a truly random number, with each number generated independently of any previous output. Therefore, with many thousands of users, a 5 digit numeric alias (e.g. pex_random_pin(5) ) is statistically quite likely to clash with a random alias generated using pex_random_pin(5) for another user. With 10,001 or more users and a 4 digit random alias, a clash is guaranteed (with multiple clashes being likely).

pex_regex_replace('find_regex', 'replace_string')

This performs a regex find and replace.

Example usage: {{mail|pex_regex_replace('@.+','@otherdomain.com')}}

This example takes as input an email address contained in the mail variable and changes the domain portion of the address to @otherdomain.com. For example, it will transform user1@domainA.com to user1@otherdomain.com, and user2@domainB.com to user2@otherdomain.com etc.

See Regular expression (regex) reference for information about writing regular expressions.

pex_regex_search('regex pattern', 'string_to_search')

This performs a regex search for the first location that matches the pattern and returns the regex groups.

Example usage:

{% set groups = pex_regex_search("([a-z0-9.-]+)@([a-z0-9.-]+.com)", "example string with someone@example.com") %}
{% if groups %}
{{ groups[0] }}@{{ groups[1] }}
{% endif %}

This example takes as input a string containing an email address and extracts the email using two regex groups.

See Regular expression (regex) reference for information about writing regular expressions.

pex_require_min_length(length)

This validates that the input string field has the specified minimum length.

Syntax: {{ some_string|pex_require_min_length(2) }}

You can use this filter to control if VMRs are created or not, based on the length of a string or variable.

For example, you could set the VMR description pattern as {{ mail|pex_require_min_length(1) }}. This means that the VMR will not be created if the mail variable is empty. (When subsequently syncing, the VMR would be deleted if the condition is not met.)

Example usage: {{ telephoneNumber|pex_require_min_length(4) }}

This example ensures that a VMR is created only if telephoneNumber is at least 4 characters long.

pex_reverse

This reverses the characters in the input field.

Example usage: {{ givenName|pex_reverse|lower }}

In this example, if givenName is 'Alice', this expression would return 'ecila'.

pex_strlen

Returns the length of string. The basic usage syntax is:

{% set some_length = "Example"|pex_strlen %}
{# sets a variable named some_length to the value 7 #}

Example usage: {%set a = telephoneNumber|pex_clean_phone_number|pex_head(8)%}{%set b = mobile|pex_clean_phone_number|pex_head(8)%}{%if a|pex_strlen== 8%}{{a}}{%else%}{{b}}{%endif%}

In this example, the expression returns the value of the telephoneNumber field if it is present and at least 8 characters long after cleaning and truncation, otherwise it returns the value of the mobile field that has been cleaned and truncated to at most 8 characters.

Example usage: {%if telephoneNumber|pex_strlen == 5 %}{#return user's phone number#}{{telephoneNumber|pex_clean_phone_number}}{% else %}{#intentionally leave blank#}{% endif %}

In this example, the expression returns a cleaned value of the telephoneNumber field if it is 5 characters long, otherwise it returns an empty string.

pex_tail(maxlength)

Returns, at most, the last maxlength characters from the input field.

Example usage: {{ telephoneNumber|pex_tail(4) }}

In this example, if telephoneNumber is '+44 (20) 12345678', this expression would return '5678'.

pex_to_json

Converts a Python dictionary variable into JSON format.

pex_to_uuid

Converts a base64 string to a UUID.

GUIDs that are retrieved from LDAP are encoded as base64 and typically need converting to a human readable UUID such as a59da36d-9b16-430a-80f7-cb1b01d4bd45 for subsequent use within Pexip Infinity.

Example usage: {{objectGUID|pex_to_uuid}}

pex_update

Updates Python dictionary variables.

pex_url_encode

This filter creates URL parameters that are safely URL-encoded.

It takes any number of two-element tuples and converts them into a percent-encoded string of key=value pairs. It does not take any input; the syntax is:

{{ pex_url_encode(('key_1', 'data_1'), ('key_2', 'data_2'), ..., ('key_n', 'value_n')) }}

Example usage: {{ pex_url_encode(('data', '8J+UpcKvXF8o44OEKV8vwq/wn5Sl'), ('message', 'A test message')) }} which would produce: data=8J%2BUpcKvXF8o44OEKV8vwq%2Fwn5Sl&message=A+test+message

pex_uuid4()

This generates a uuid (universally unique identifier). Note that this filter does not take any input.

Example usage: {{ pex_uuid4() }}

In a similar manner to the pex_random_pin filter, you would typically use this in conjunction with the appropriate Allow <field> to be manually overridden template setting, to ensure that after a uuid has been assigned to a field, another different uuid is not assigned every time a template resync is performed.