Auto Validation

Auto-validation can be enabled on the following protocols:

When the auto-validation mode is enabled, Validation Rules are evaluated to allow or deny an enrollment request.

Multiple rules can be defined on each profile, and the minimum number of passing rules can be defined.

Validation Rules

A validation rule is a condition that can be true or false. Inputs are taken from dictionary entries and can be manipulated using Computation Rules and validation functions and operators.

For example, to allow all requests coming from a subnet and having all DNS SANs that resolves on the Horizon server, the following rule can be used:

{{http.request.ip}} in 154.12.45.0/24 and [[csr.san.dnsname]] resolvesDNS

Here, two expressions are combined using the and operator:

  • {{http.request.ip}} in 154.12.45.0/24: a computation rule {{http.request.ip}} fetches the value of the IP from the incoming request, and checks that this ip is in the 154.12.45.0/24 subnet, using the In operator.

  • [[csr.san.dnsname]] resolvesDNS : a computation rule [[csr.san.dnsname]] fetches the values of the DNS SANs from the csr in the incoming request, and checks that these SANs resolvesDNS.

Examples

DNS Validation

To validate that all DNS requested in a WebRA enroll request resolve on the DNS Server with IP 192.10.132.2, the following rule can be used:

[[webra.enroll.san.dnsname]] resolvesDNS(192.10.132.2:53)

Here all the dns sans from the request are fetched and are submitted to the dns server.

Email validation

To validate that the Email SAN requested in an EST enroll request are associated to the requester’s Common Name, using a datasource that fetches the emails on an external LDAP server, the following rule can be used:

{{csr.san.rfc822name.1}} = {{ds.1.1.mail}}

Here the condition checks if the first Email SAN from the CSR is equal to the mail fetched from the LDAP datasource (supposing the LDAP datasource is the first in the flow).

Quick Reference

The table below lists the possible operators for a validation rule:

Operator Name Syntax

And

expression and expression

Or

expression or expression

Equals

expression equals expression

In

expression in expression

Exists

expression exists

Contains

expression contains expression

Matches

expression matches expression

Within

expression within expression

Is Empty

expression is empty

Starts With

expression starts with expression

Ends With

expression ends with expression

Resolves DNS

expression resolvesDNS

And

left:<expression> and right:<expression>

This outputs the logical and operation on the result evaluated from left and right

"left" = "left" and "right"="right" => true
Upper("left") = "left" and "right"="right" => false

Or

left:<expression> or right:<expression>

This outputs the logical or operation on the result evaluated from left and right

"left" = "left" or "right"="right" => true
Upper("left") = "left" or "right"="right" => true

Equals

left:<expression> equals right:<expression>
left:<expression> = right:<expression>

This tests the equality operation on the result evaluated from left and right

"left" = "left"  => true
Upper("left") equals "left" => false

Not Equals

left:<expression> not equals right:<expression>
left:<expression> != right:<expression>
"left" != "left"  => false
Upper("left") not equals "left" => true

In

Element inclusion

elem:<single expression> in array:<multi expression>

This tests if elem is contained in array

"left" in [ "left" ]  => true
Upper("left") in ["left"] => false

Multiple Element inclusion

any of elems:<multi expression> in array:<multi expression>
all of elems:<multi expression> in array:<multi expression>

This tests if all or any element in elems is contained in array

any of ["left", "right"] in [ "left" ]  => true
all of ["left", "right"] in [ "left" ]  => false

Ip in CIDR

ip:<single expression> in subnet:<subnet>

This tests if ip is contained in subnet (cidr notation)

"128.12.13.14" in 128.12.15.0/24  => false
"2001:0db8:85a3:0000:0000:0000:0000:0001" in 2001:db8:85a3::8a2e:370:7334/64 => true

Multiple Ips in CIDR

any of ips:<multi expression> in subnet:<subnet>
all of ips:<multi expression> in subnet:<subnet>

This tests if all or any ip in ips is contained in subnet (cidr notation)

any of ["128.12.13.14", "128.12.15.32" ] in 128.12.15.0/24  => true
all of [ "2001:0db8:85a3:0000:0000:0000:0000:0001", "2002:0db8:85a3:0000:0000:0000:0000:0001"] in 2001:db8:85a3::8a2e:370:7334/64 => false

Element not included

elem:<single expression> not in array:<multi expression>
any of elems:<multi expression> not in array:<multi expression>
all of elems:<multi expression> not in array:<multi expression>
"left" not in ["right"]  => true
any of ["left", "right"] not in [ "left" ] => true
all of ["left", "right"] not in [ "left" ] => false
"128.12.13.14" not in 128.12.15.0/24  => true

Exists

elem:<expression> exists

This tests if elem exists. For single values, this will be true if the dictionary key is defined and for multi values if the array is not empty.

"" exists  => true
{{will.not.exist}} exists => false
[[will.not.exist]] exists => false

Not exists

elem:<expression> not exists
"" not exists  => false
{{will.not.exist}} not exists => true
[[will.not.exist]] not exists => true

Is Empty

elem:<expression> is empty

This tests if elem is empty. For single values, this will be true if the dictionary key is not defined or if the value is empty, and for multi values if the array is empty or if all values are empty.

"" is empty  => true
{{will.not.exist}} is empty => true
[[will.not.exist]] is empty => true
[ "", ""] is empty => true

Is Not empty

elem:<expression> is not empty
"" is not empty  => false
{{will.not.exist}} is not empty => false
[[will.not.exist]] is not empty => false

Contains

Single element contained

containing:<expression> contains elem:<single expression>

This tests if containing contains the elem value. If containing is a string, the presence of the substring elem is checked, if it is an array the presence of the element in the array is checked.

"google.com" contains "google"  => true
["google.com", "google.fr"] contains "google.fr"  => true
"google.com" contains {{does.not.exist}}  => true

Multiple elements contained

containing:<multi expression> contains all of elems:<multi expression>
containing:<multi expression> contains any of elems:<multi expression>

This tests if containing contains all or any of the elements of the elems array. An empty elems array will always be contained.

["google.com", "google.fr"] contains all of ["test.com"]  => false
["google.com"] contains all of [[does.not.exist]]  => true
["google.com", "google.fr"] contains any of ["google.com", "a"]  => true

Single element not contained

containing:<expression> not contains elem:<single expression>
"google.com" not contains ""  => false

Multiple elements not contained

containing:<multi expression> not contains all of elems:<multi expression>
containing:<multi expression> not contains any of elems:<multi expression>
["test", "abc" ] not contains all of ["abc", "d"] => true
["test", "abcf", "d"] not contains any of ["f", "e"] => true

Matches

Single element match

elem:<single expression> matches regex:<single expression>
elem:<single expression> ~ regex:<single expression>

This tests if elem matches the regex. If regex is None, this will output false.

"left" matches "\d+"  => false
Upper("left") ~ "[A-Z]+" => true

Multiple element match

any of elems:<multi expression> matches regex:<single expression>
all of elems:<multi expression> matches regex:<single expression>

This tests if any or all element in elems matches the regex. If regex is None, this will output false.

any of ["left", "42"] matches "\d+"  => true
all of Upper(["left", "42"]) matches "[A-Z]+" => false

Not matching

elem:<single expression> not matches regex:<single expression>
any of elems:<multi expression> not matches regex:<single expression>
all of elems:<multi expression> not matches regex:<single expression>
"left" not matches "\d+" => true
any of ["left", "aaaaa"] not matches "a+"  => true
all of ["left", "aaaaa"] not matches "a+"  => false

Within

Element matching

elem:<single expression> within array:<multi expression>

This tests if elem matches a regex in array.

"left" within [ "\d+", "[a-z]+" ]  => true
Upper("left") within [ "\d+", "[a-z]+" ] => false

Multiple Element matching

any of elems:<multi expression> within array:<multi expression>
all of elems:<multi expression> within array:<multi expression>

This tests if all or any element in elems matches a regex in array

any of ["left", "aaaaa"] within [ "\d+", "a+" ]  => true
all of ["left", "aaaaa"] within [ "\d+", "a+" ]  => false

Element not matching

elem:<single expression> not within array:<multi expression>
any of elems:<multi expression> not within array:<multi expression>
all of elems:<multi expression> not within array:<multi expression>
"left" not within [ "\d+", "[a-z]+" ]  => false
any of ["left", "aaaaa"] not within [ "\d+", "a+" ]  => true
all of ["left", "aaaaa"] not within [ "\d+", "a+" ]  => false

Starts With

Element matching

elem:<single expression> starts with start:<single expression>

This tests if elem starts with start value. An empty elem will send return false.

"left" starts with "le"  => true
Upper("left") starts with "le" => false

Multiple Element matching

any of elems:<multi expression> starts with start:<single expression>
all of elems:<multi expression> starts with start:<single expression>

This tests if all or any element in elems starts with start

any of ["left", "aaaaa"] starts with "aaa" => true
all of ["left", "aaaaa"] starts with "aaa" => false

Element not matching

elem:<single expression> starts not with start:<single expression>
any of elems:<multi expression> starts not with start:<single expression>
all of elems:<multi expression> starts not with start:<single expression>
"left" starts not with "le"  => false
any of ["left", "aaaaa"] starts not with "a"  => true
all of ["left", "aaaaa"] starts not with "a"  => false

Ends With

Element matching

elem:<single expression> ends with start:<single expression>

This tests if elem ends with start value. An empty elem will send return false.

"left" ends with "ft"  => true
Upper("left") ends with "ft" => false

Multiple Element matching

any of elems:<multi expression> ends with start:<single expression>
all of elems:<multi expression> ends with start:<single expression>

This tests if all or any element in elems ends with start

any of ["left", "aaaaa"] ends with "aaa" => true
all of ["left", "aaaaa"] ends with "aaa" => false

Element not matching

elem:<single expression> ends not with start:<single expression>
any of elems:<multi expression> ends not with start:<single expression>
all of elems:<multi expression> ends not with start:<single expression>
"left" ends not with "ft"  => false
any of ["left", "aaaaa"] ends not with "a"  => true
all of ["left", "aaaaa"] ends not with "a"  => false

Resolves DNS

host:<expression> resolvesDNS
host:<expression> resolvesDNS(101.12.13.14:53)

This tests if host resolves on the DNS server. An optional DNS server in the ip:port format can be used. If host is an array, DNS must resolve for each value. An empty array returns false.

"google.com" resolvesDNS  => true
["google.com", "google.fr"] resolvesDNS  => true
["google.com", "not.resolving"] resolvesDNS  => false

Not Resolves DNS

host:<expression> not resolvesDNS
host:<expression> not resolvesDNS(101.12.13.14:53)
"google.com" not resolvesDNS  => false
["google.com", "google.fr"] not resolvesDNS  => false