PingDS 7.5.1

Query

Examples in this documentation depend on features activated in the ds-evaluation setup profile. For details, refer to Learn about the evaluation setup profile.

The code samples demonstrate how to contact the server over HTTPS using the deployment CA certificate. Before trying the samples, generate the CA certificate in PEM format from the server deployment ID and password:

$ dskeymgr \
 export-ca-cert \
 --deploymentId $DEPLOYMENT_ID \
 --deploymentIdPassword password \
 --outputFile ca-cert.pem

To search, use HTTP GET with at least a _queryFilter=<filter-expression> parameter and other applicable parameters as necessary, such as scope. For reference details, refer to:

Example query filters

The following table shows LDAP search filters and corresponding query filter expressions:

LDAP Filter REST Filter

(&)

_queryFilter=true

(uid=*)

_queryFilter=uid+pr

(uid=bjensen)

_queryFilter=uid+eq+'bjensen'

(uid=*jensen*)

_queryFilter=uid+co+'jensen'

(uid=jensen*)

_queryFilter=uid+sw+'jensen'

(&(uid=*jensen*)(cn=babs*))

_queryFilter=(uid+co+'jensen'and+cn+sw'babs')

(|(uid=*jensen*)(cn=sam*))

_queryFilter=(uid+co+'jensen'or+cn+sw'sam')

(!(uid=*jensen*))

_queryFilter=!(uid+co+'jensen')

(uid<=jensen)

_queryFilter=uid+le+'jensen'

(uid>=jensen)

_queryFilter=uid+ge+'jensen'

For details on which index to configure for a specific filter, refer to Necessary indexes.

Build query filters

For query operations, the <filter-expression> has the following building blocks. You must URL-encode the filter expressions. This page shows them without URL-encoding to make them easier to read.

In filter expressions, the simplest <json-pointer> is a JSON field name. A <json-pointer> can also reference nested elements. For details, read RFC 6901, JavaScript Object Notation (JSON) Pointer.

The co (contains) and sw (starts with) query filter expressions match part of a value.

HDAP does not support co and sw to match values for:

  • Binary fields, such as photos or digital certificates (binary attributes in LDAP)

  • _id and JSON fields whose values are the _ids of other resources, such as manager (DN attributes in LDAP)

  • Time fields, such as a last login time (generalized time attributes in LDAP)

Comparison expressions

Build filters using the following comparison expressions:

<json-pointer> eq <json-value>

Matches when the pointer equals the value.

Show example
  • Curl

  • JavaScript

  • Python

  • Ruby

$ curl \
 --get \
 --cacert ca-cert.pem \
 --user dc=com/dc=example/ou=People/uid=kvaughan:bribery \
 --data "_queryFilter=mail+eq+'bjensen@example.com'" \
 --data '_fields=cn' \
 --data '_prettyPrint=true' \
 --data 'scope=sub' \
 'https://localhost:8443/hdap/dc=com/dc=example/ou=People'
{
  "result" : [ {
    "_id" : "dc=com/dc=example/ou=People/uid=bjensen",
    "_rev" : "<revision>",
    "cn" : [ "Barbara Jensen", "Babs Jensen" ]
  } ],
  "resultCount" : 1,
  "pagedResultsCookie" : null,
  "totalPagedResultsPolicy" : "NONE",
  "totalPagedResults" : -1,
  "remainingPagedResults" : -1
}
(async () => {
    const { authenticate, doRequest, getOptions } = require('./utils')
    const options = getOptions({
        path: "/hdap/dc=com/dc=example/ou=People?_queryFilter=mail+eq+'bjensen@example.com'&_fields=cn&scope=sub"
    })
    const jwt = await authenticate(options)
    options.headers['Authorization'] = 'Bearer ' + jwt
    const response = await doRequest('HDAP: query eq', options)
    console.log(response)
})().catch(error => { console.error(error) })

Source files for this sample: query-eq.js, utils.js

#!/usr/bin/env python3

import requests
import utils

params = {
    '_fields': 'cn',
    '_queryFilter': 'mail eq "bjensen@example.com"',
    'scope': 'sub'
}
jwt = utils.authenticate('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {jwt}' }
response = requests.get(
    f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People',
    headers=headers,
    params=params,
    verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))

Source files for this sample: utils.py, query-eq.py

require_relative 'utils.rb'
require 'faraday'

utils = Utils.new('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
options = { ca_file: utils.ca_pem }
jwt = utils.authenticate
query = {
    "_fields": "cn",
    "_queryFilter": "mail eq 'bjensen@example.com'",
    "scope": "sub"
}
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", params: query, ssl: options) do |f|
    f.headers['Content-Type'] = 'application/json'
    f.request :authorization, 'Bearer', jwt
end
response = hdap.get('dc=com/dc=example/ou=People')

puts "Status code: #{response.status}\nJSON: #{response.body}"

Source files for this sample: utils.rb, query-eq.rb

HDAP Ruby examples require Ruby 3.2 and the faraday and json gems.

<json-pointer> co <json-value>

Matches when the pointer contains the value.

Show example
  • Curl

  • JavaScript

  • Python

  • Ruby

$ curl \
 --get \
 --cacert ca-cert.pem \
 --user dc=com/dc=example/ou=People/uid=kvaughan:bribery \
 --data "_queryFilter=mail+co+'jensen'" \
 --data '_fields=cn' \
 --data '_prettyPrint=true' \
 --data 'scope=sub' \
 'https://localhost:8443/hdap/dc=com/dc=example/ou=People'
{
  "result" : [ {
    "_id" : "dc=com/dc=example/ou=People/uid=ajensen",
    "_rev" : "<revision>",
    "cn" : [ "Allison Jensen" ]
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=bjensen",
    "_rev" : "<revision>",
    "cn" : [ "Barbara Jensen", "Babs Jensen" ]
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=gjensen",
    "_rev" : "<revision>",
    "cn" : [ "Gern Jensen" ]
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=jjensen",
    "_rev" : "<revision>",
    "cn" : [ "Jody Jensen" ]
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=kjensen",
    "_rev" : "<revision>",
    "cn" : [ "Kurt Jensen" ]
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=rjensen",
    "_rev" : "<revision>",
    "cn" : [ "Richard Jensen" ]
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=tjensen",
    "_rev" : "<revision>",
    "cn" : [ "Ted Jensen" ]
  } ],
  "resultCount" : 7,
  "pagedResultsCookie" : null,
  "totalPagedResultsPolicy" : "NONE",
  "totalPagedResults" : -1,
  "remainingPagedResults" : -1
}
(async () => {
    const { authenticate, doRequest, getOptions } = require('./utils')
    const options = getOptions({
        path: "/hdap/dc=com/dc=example/ou=People?_queryFilter=mail+co+'jensen'&_fields=cn&scope=sub"
    })
    const jwt = await authenticate(options)
    options.headers['Authorization'] = 'Bearer ' + jwt
    const response = await doRequest('HDAP: query co', options)
    console.log(response)
})().catch(error => { console.error(error) })

Source files for this sample: query-co.js, utils.js

#!/usr/bin/env python3

import requests
import utils

params = {
    '_fields': 'cn',
    '_queryFilter': 'mail co "jensen"',
    'scope': 'sub'
}
jwt = utils.authenticate('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {jwt}' }
response = requests.get(
    f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People',
    headers=headers,
    params=params,
    verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))

Source files for this sample: utils.py, query-co.py

require_relative 'utils.rb'
require 'faraday'

utils = Utils.new('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
options = { ca_file: utils.ca_pem }
jwt = utils.authenticate
query = {
    "_fields": "cn",
    "_queryFilter": "mail co 'jensen'",
    "scope": "sub"
}
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", params: query, ssl: options) do |f|
    f.headers['Content-Type'] = 'application/json'
    f.request :authorization, 'Bearer', jwt
end
response = hdap.get('dc=com/dc=example/ou=People')

puts "Status code: #{response.status}\nJSON: #{response.body}"

Source files for this sample: utils.rb, query-co.rb

HDAP Ruby examples require Ruby 3.2 and the faraday and json gems.

<json-pointer> sw <json-value>

Matches when the pointer starts with the value.

Show example
  • Curl

  • JavaScript

  • Python

  • Ruby

$ curl \
 --get \
 --cacert ca-cert.pem \
 --user dc=com/dc=example/ou=People/uid=kvaughan:bribery \
 --data "_queryFilter=mail+sw+'ab'" \
 --data '_fields=cn' \
 --data '_prettyPrint=true' \
 --data 'scope=sub' \
 'https://localhost:8443/hdap/dc=com/dc=example/ou=People'
{
  "result" : [ {
    "_id" : "dc=com/dc=example/ou=People/uid=abarnes",
     "_rev" : "<revision>",
    "cn" : [ "Anne-Louise Barnes" ]
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=abergin",
    "_rev" : "<revision>",
    "cn" : [ "Andy Bergin" ]
  } ],
  "resultCount" : 2,
  "pagedResultsCookie" : null,
  "totalPagedResultsPolicy" : "NONE",
  "totalPagedResults" : -1,
  "remainingPagedResults" : -1
}
(async () => {
    const { authenticate, doRequest, getOptions } = require('./utils')
    const options = getOptions({
        path: "/hdap/dc=com/dc=example/ou=People?_queryFilter=mail+sw+'ab'&_fields=cn&scope=sub"
    })
    const jwt = await authenticate(options)
    options.headers['Authorization'] = 'Bearer ' + jwt
    const response = await doRequest('HDAP: query sw', options)
    console.log(response)
})().catch(error => { console.error(error) })

Source files for this sample: query-sw.js, utils.js

#!/usr/bin/env python3

import requests
import utils

params = {
    '_fields': 'cn',
    '_queryFilter': 'mail sw "ab"',
    'scope': 'sub'
}
jwt = utils.authenticate('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {jwt}' }
response = requests.get(
    f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People',
    headers=headers,
    params=params,
    verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))

Source files for this sample: utils.py, query-sw.py

require_relative 'utils.rb'
require 'faraday'

utils = Utils.new('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
options = { ca_file: utils.ca_pem }
jwt = utils.authenticate
query = {
    "_fields": "cn",
    "_queryFilter": "mail sw 'ab'",
    "scope": "sub"
}
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", params: query, ssl: options) do |f|
    f.headers['Content-Type'] = 'application/json'
    f.request :authorization, 'Bearer', jwt
end
response = hdap.get('dc=com/dc=example/ou=People')

puts "Status code: #{response.status}\nJSON: #{response.body}"

Source files for this sample: utils.rb, query-eq.rb

HDAP Ruby examples require Ruby 3.2 and the faraday and json gems.

<json-pointer> lt <json-value>

Matches when the pointer is less than the value.

Show example
  • Curl

  • JavaScript

  • Python

  • Ruby

$ curl \
 --get \
 --cacert ca-cert.pem \
 --user dc=com/dc=example/ou=People/uid=kvaughan:bribery \
 --data "_queryFilter=mail+lt+'ac'" \
 --data '_fields=cn' \
 --data '_prettyPrint=true' \
 --data 'scope=sub' \
 'https://localhost:8443/hdap/dc=com/dc=example/ou=People'
{
  "result" : [ {
    "_id" : "dc=com/dc=example/ou=People/uid=abarnes",
    "_rev" : "<revision>",
    "cn" : [ "Anne-Louise Barnes" ]
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=abergin",
    "_rev" : "<revision>",
    "cn" : [ "Andy Bergin" ]
  } ],
  "resultCount" : 2,
  "pagedResultsCookie" : null,
  "totalPagedResultsPolicy" : "NONE",
  "totalPagedResults" : -1,
  "remainingPagedResults" : -1
}
(async () => {
    const { authenticate, doRequest, getOptions } = require('./utils')
    const options = getOptions({
        path: "/hdap/dc=com/dc=example/ou=People?_queryFilter=mail+lt+'ac'&_fields=cn&scope=sub"
    })
    const jwt = await authenticate(options)
    options.headers['Authorization'] = 'Bearer ' + jwt
    const response = await doRequest('HDAP: query lt', options)
    console.log(response)
})().catch(error => { console.error(error) })

Source files for this sample: query-lt.js, utils.js

#!/usr/bin/env python3

import requests
import utils

params = {
    '_fields': 'cn',
    '_queryFilter': 'mail lt "ac"',
    'scope': 'sub'
}
jwt = utils.authenticate('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {jwt}' }
response = requests.get(
    f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People',
    headers=headers,
    params=params,
    verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))

Source files for this sample: utils.py, query-lt.py

require_relative 'utils.rb'
require 'faraday'

utils = Utils.new('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
options = { ca_file: utils.ca_pem }
jwt = utils.authenticate
query = {
    "_fields": "cn",
    "_queryFilter": "mail lt 'ac'",
    "scope": "sub"
}
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", params: query, ssl: options) do |f|
    f.headers['Content-Type'] = 'application/json'
    f.request :authorization, 'Bearer', jwt
end
response = hdap.get('dc=com/dc=example/ou=People')

puts "Status code: #{response.status}\nJSON: #{response.body}"

Source files for this sample: utils.rb, query-lt.rb

HDAP Ruby examples require Ruby 3.2 and the faraday and json gems.

<json-pointer> le <json-value>

Matches when the pointer is less than or equal to the value.

Show example
  • Curl

  • JavaScript

  • Python

  • Ruby

$ curl \
 --get \
 --cacert ca-cert.pem \
 --user dc=com/dc=example/ou=People/uid=kvaughan:bribery \
 --data "_queryFilter=mail+le+'ad'" \
 --data '_fields=cn' \
 --data '_prettyPrint=true' \
 --data 'scope=sub' \
 'https://localhost:8443/hdap/dc=com/dc=example/ou=People'
{
  "result" : [ {
    "_id" : "dc=com/dc=example/ou=People/uid=abarnes",
    "_rev" : "<revision>",
    "cn" : [ "Anne-Louise Barnes" ]
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=abergin",
    "_rev" : "<revision>",
    "cn" : [ "Andy Bergin" ]
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=achassin",
    "_rev" : "<revision>",
    "cn" : [ "Ashley Chassin" ]
  } ],
  "resultCount" : 3,
  "pagedResultsCookie" : null,
  "totalPagedResultsPolicy" : "NONE",
  "totalPagedResults" : -1,
  "remainingPagedResults" : -1
}
(async () => {
    const { authenticate, doRequest, getOptions } = require('./utils')
    const options = getOptions({
        path: "/hdap/dc=com/dc=example/ou=People?_queryFilter=mail+le+'ad'&_fields=cn&scope=sub"
    })
    const jwt = await authenticate(options)
    options.headers['Authorization'] = 'Bearer ' + jwt
    const response = await doRequest('HDAP: query le', options)
    console.log(response)
})().catch(error => { console.error(error) })

Source files for this sample: query-le.js, utils.js

#!/usr/bin/env python3

import requests
import utils

params = {
    '_fields': 'cn',
    '_queryFilter': 'mail le "ad"',
    'scope': 'sub'
}
jwt = utils.authenticate('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {jwt}' }
response = requests.get(
    f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People',
    headers=headers,
    params=params,
    verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))

Source files for this sample: utils.py, query-le.py

require_relative 'utils.rb'
require 'faraday'

utils = Utils.new('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
options = { ca_file: utils.ca_pem }
jwt = utils.authenticate
query = {
    "_fields": "cn",
    "_queryFilter": "mail le 'ad'",
    "scope": "sub"
}
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", params: query, ssl: options) do |f|
    f.headers['Content-Type'] = 'application/json'
    f.request :authorization, 'Bearer', jwt
end
response = hdap.get('dc=com/dc=example/ou=People')

puts "Status code: #{response.status}\nJSON: #{response.body}"

Source files for this sample: utils.rb, query-le.rb

HDAP Ruby examples require Ruby 3.2 and the faraday and json gems.

<json-pointer> gt <json-value>

Matches when the pointer is greater than the value.

Show example
  • Curl

  • JavaScript

  • Python

  • Ruby

$ curl \
 --get \
 --cacert ca-cert.pem \
 --user dc=com/dc=example/ou=People/uid=kvaughan:bribery \
 --data "_queryFilter=mail+gt+'wa'" \
 --data '_fields=cn' \
 --data '_prettyPrint=true' \
 --data 'scope=sub' \
 'https://localhost:8443/hdap/dc=com/dc=example/ou=People'
{
  "result" : [ {
    "_id" : "dc=com/dc=example/ou=People/uid=wlutz",
    "_rev" : "<revision>",
    "cn" : [ "Wendy Lutz" ]
  } ],
  "resultCount" : 1,
  "pagedResultsCookie" : null,
  "totalPagedResultsPolicy" : "NONE",
  "totalPagedResults" : -1,
  "remainingPagedResults" : -1
}
(async () => {
    const { authenticate, doRequest, getOptions } = require('./utils')
    const options = getOptions({
        path: "/hdap/dc=com/dc=example/ou=People?_queryFilter=mail+gt+'wa'&_fields=cn&scope=sub"
    })
    const jwt = await authenticate(options)
    options.headers['Authorization'] = 'Bearer ' + jwt
    const response = await doRequest('HDAP: query gt', options)
    console.log(response)
})().catch(error => { console.error(error) })

Source files for this sample: query-gt.js, utils.js

#!/usr/bin/env python3

import requests
import utils

params = {
    '_fields': 'cn',
    '_queryFilter': 'mail gt "wa"',
    'scope': 'sub'
}
jwt = utils.authenticate('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {jwt}' }
response = requests.get(
    f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People',
    headers=headers,
    params=params,
    verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))

Source files for this sample: utils.py, query-gt.py

require_relative 'utils.rb'
require 'faraday'

utils = Utils.new('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
options = { ca_file: utils.ca_pem }
jwt = utils.authenticate
query = {
    "_fields": "cn",
    "_queryFilter": "mail gt 'wa'",
    "scope": "sub"
}
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", params: query, ssl: options) do |f|
    f.headers['Content-Type'] = 'application/json'
    f.request :authorization, 'Bearer', jwt
end
response = hdap.get('dc=com/dc=example/ou=People')

puts "Status code: #{response.status}\nJSON: #{response.body}"

Source files for this sample: utils.rb, query-gt.rb

HDAP Ruby examples require Ruby 3.2 and the faraday and json gems.

<json-pointer> ge <json-value>

Matches when the pointer is greater than or equal to the value.

Show example
  • Curl

  • JavaScript

  • Python

  • Ruby

$ curl \
 --get \
 --cacert ca-cert.pem \
 --user dc=com/dc=example/ou=People/uid=kvaughan:bribery \
 --data "_queryFilter=mail+ge+'va'" \
 --data '_fields=cn' \
 --data '_prettyPrint=true' \
 --data 'scope=sub' \
 'https://localhost:8443/hdap/dc=com/dc=example/ou=People'
{
  "result" : [ {
    "_id" : "dc=com/dc=example/ou=People/uid=wlutz",
    "_rev" : "<revision>",
    "cn" : [ "Wendy Lutz" ]
  } ],
  "resultCount" : 1,
  "pagedResultsCookie" : null,
  "totalPagedResultsPolicy" : "NONE",
  "totalPagedResults" : -1,
  "remainingPagedResults" : -1
}
(async () => {
    const { authenticate, doRequest, getOptions } = require('./utils')
    const options = getOptions({
        path: "/hdap/dc=com/dc=example/ou=People?_queryFilter=mail+ge+'va'&_fields=cn&scope=sub"
    })
    const jwt = await authenticate(options)
    options.headers['Authorization'] = 'Bearer ' + jwt
    const response = await doRequest('HDAP: query ge', options)
    console.log(response)
})().catch(error => { console.error(error) })

Source files for this sample: query-ge.js, utils.js

#!/usr/bin/env python3

import requests
import utils

params = {
    '_fields': 'cn',
    '_queryFilter': 'mail ge "va"',
    'scope': 'sub'
}
jwt = utils.authenticate('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {jwt}' }
response = requests.get(
    f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People',
    headers=headers,
    params=params,
    verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))

Source files for this sample: utils.py, query-ge.py

require_relative 'utils.rb'
require 'faraday'

utils = Utils.new('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
options = { ca_file: utils.ca_pem }
jwt = utils.authenticate
query = {
    "_fields": "cn",
    "_queryFilter": "mail ge 'va'",
    "scope": "sub"
}
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", params: query, ssl: options) do |f|
    f.headers['Content-Type'] = 'application/json'
    f.request :authorization, 'Bearer', jwt
end
response = hdap.get('dc=com/dc=example/ou=People')

puts "Status code: #{response.status}\nJSON: #{response.body}"

Source files for this sample: utils.rb, query-ge.rb

HDAP Ruby examples require Ruby 3.2 and the faraday and json gems.

Presence expression

<json-pointer> pr matches a resource where the pointer is present.

Show example
  • Curl

  • JavaScript

  • Python

  • Ruby

$ curl \
 --get \
 --cacert ca-cert.pem \
 --user dc=com/dc=example/ou=People/uid=kvaughan:bribery \
 --data "_queryFilter=cn+pr" \
 --data '_fields=cn' \
 --data '_prettyPrint=true' \
 --data 'scope=sub' \
 'https://localhost:8443/hdap/dc=com/dc=example/ou=Groups'
{
  "result" : [ {
    "_id" : "dc=com/dc=example/ou=groups/cn=Accounting%20Managers",
    "_rev" : "<revision>",
    "cn" : [ "Accounting Managers" ]
  }, {
    "_id" : "dc=com/dc=example/ou=Groups/cn=Directory%20Administrators",
    "_rev" : "<revision>",
    "cn" : [ "Directory Administrators" ]
  }, {
    "_id" : "dc=com/dc=example/ou=groups/cn=HR%20Managers",
    "_rev" : "<revision>",
    "cn" : [ "HR Managers" ]
  }, {
    "_id" : "dc=com/dc=example/ou=groups/cn=PD%20Managers",
    "_rev" : "<revision>",
    "cn" : [ "PD Managers" ]
  }, {
    "_id" : "dc=com/dc=example/ou=groups/cn=QA%20Managers",
    "_rev" : "<revision>",
    "cn" : [ "QA Managers" ]
  }, {
    "_id" : "dc=com/dc=example/ou=Groups/ou=Self%20Service/cn=Carpoolers",
    "_rev" : "<revision>",
    "cn" : [ "Carpoolers" ]
  } ],
  "resultCount" : 6,
  "pagedResultsCookie" : null,
  "totalPagedResultsPolicy" : "NONE",
  "totalPagedResults" : -1,
  "remainingPagedResults" : -1
}
(async () => {
    const { authenticate, doRequest, getOptions } = require('./utils')
    const options = getOptions({
        path: '/hdap/dc=com/dc=example/ou=Groups?_queryFilter=cn+pr&_fields=cn&scope=sub'
    })
    const jwt = await authenticate(options)
    options.headers['Authorization'] = 'Bearer ' + jwt
    const response = await doRequest('HDAP: query pr', options)
    console.log(response)
})().catch(error => { console.error(error) })

Source files for this sample: query-pr.js, utils.js

#!/usr/bin/env python3

import requests
import utils

params = {
    '_fields': 'cn',
    '_queryFilter': 'cn pr',
    'scope': 'sub'
}
jwt = utils.authenticate('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {jwt}' }
response = requests.get(
    f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=Groups',
    headers=headers,
    params=params,
    verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))

Source files for this sample: utils.py, query-pr.py

require_relative 'utils.rb'
require 'faraday'

utils = Utils.new('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
options = { ca_file: utils.ca_pem }
jwt = utils.authenticate
query = {
    "_fields": "cn",
    "_queryFilter": "cn pr",
    "scope": "sub"
}
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", params: query, ssl: options) do |f|
    f.headers['Content-Type'] = 'application/json'
    f.request :authorization, 'Bearer', jwt
end
response = hdap.get('dc=com/dc=example/ou=Groups')

puts "Status code: #{response.status}\nJSON: #{response.body}"

Source files for this sample: utils.rb, query-pr.rb

HDAP Ruby examples require Ruby 3.2 and the faraday and json gems.

Literal expressions

true matches any resource in scope.

false matches no resources.

Show example
  • Curl

  • JavaScript

  • Python

  • Ruby

$ curl \
 --get \
 --cacert ca-cert.pem \
 --user dc=com/dc=example/ou=People/uid=kvaughan:bribery \
 --data "_queryFilter=true" \
 --data '_fields=_id' \
 --data '_prettyPrint=true' \
 'https://localhost:8443/hdap/dc=com/dc=example/ou=Groups'
{
  "result" : [ {
    "_id" : "dc=com/dc=example/ou=groups/cn=Accounting%20Managers",
    "_rev" : "<revision>"
  }, {
    "_id" : "dc=com/dc=example/ou=Groups/cn=Directory%20Administrators",
    "_rev" : "<revision>"
  }, {
    "_id" : "dc=com/dc=example/ou=groups/cn=HR%20Managers",
    "_rev" : "<revision>"
  }, {
    "_id" : "dc=com/dc=example/ou=groups/cn=PD%20Managers",
    "_rev" : "<revision>"
  }, {
    "_id" : "dc=com/dc=example/ou=groups/cn=QA%20Managers",
    "_rev" : "<revision>"
  }, {
    "_id" : "dc=com/dc=example/ou=Groups/ou=Self%20Service",
    "_rev" : "<revision>"
  } ],
  "resultCount" : 6,
  "pagedResultsCookie" : null,
  "totalPagedResultsPolicy" : "NONE",
  "totalPagedResults" : -1,
  "remainingPagedResults" : -1
}
(async () => {
    const { authenticate, doRequest, getOptions } = require('./utils')
    const options = getOptions({
        path: '/hdap/dc=com/dc=example/ou=Groups?_queryFilter=true&_fields=cn&scope=sub'
    })
    const jwt = await authenticate(options)
    options.headers['Authorization'] = 'Bearer ' + jwt
    const response = await doRequest('HDAP: query true', options)
    console.log(response)
})().catch(error => { console.error(error) })

Source files for this sample: query-true.js, utils.js

#!/usr/bin/env python3

import requests
import utils

params = {
    '_fields': 'cn',
    '_queryFilter': True,
    'scope': 'sub'
}
jwt = utils.authenticate('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {jwt}' }
response = requests.get(
    f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=Groups',
    headers=headers,
    params=params,
    verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))

Source files for this sample: utils.py, query-true.py

require_relative 'utils.rb'
require 'faraday'

utils = Utils.new('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
options = { ca_file: utils.ca_pem }
jwt = utils.authenticate
query = {
    "_fields": "cn",
    "_queryFilter": true,
    "scope": "sub"
}
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", params: query, ssl: options) do |f|
    f.headers['Content-Type'] = 'application/json'
    f.request :authorization, 'Bearer', jwt
end
response = hdap.get('dc=com/dc=example/ou=Groups')

puts "Status code: #{response.status}\nJSON: #{response.body}"

Source files for this sample: utils.rb, query-true.rb

HDAP Ruby examples require Ruby 3.2 and the faraday and json gems.

Complex expressions

Combine expressions using boolean operators and, or, and ! (not), and by using parentheses (<filter-expression>) with group expressions.

Show example
  • Curl

  • JavaScript

  • Python

  • Ruby

$ curl \
 --get \
 --cacert ca-cert.pem \
 --user dc=com/dc=example/ou=People/uid=kvaughan:bribery \
 --data "_queryFilter=mail+co+'jensen'+and+givenName+sw+'Al'" \
 --data '_fields=cn' \
 --data '_prettyPrint=true' \
 --data 'scope=sub' \
 'https://localhost:8443/hdap/dc=com/dc=example/ou=People'
{
  "result" : [ {
    "_id" : "dc=com/dc=example/ou=People/uid=ajensen",
    "_rev" : "<revision>",
    "cn" : [ "Allison Jensen" ]
  } ],
  "resultCount" : 1,
  "pagedResultsCookie" : null,
  "totalPagedResultsPolicy" : "NONE",
  "totalPagedResults" : -1,
  "remainingPagedResults" : -1
}
(async () => {
    const { authenticate, doRequest, getOptions } = require('./utils')
    const filter = encodeURIComponent("mail co 'jensen' and givenName sw 'Al'")
    const options = getOptions({
        path: `/hdap/dc=com/dc=example/ou=People?_queryFilter=${filter}&_fields=cn&scope=sub`
    })
    const jwt = await authenticate(options)
    options.headers['Authorization'] = 'Bearer ' + jwt
    const response = await doRequest('HDAP: complex query', options)
    console.log(response)
})().catch(error => { console.error(error) })

Source files for this sample: query-complex.js, utils.js

#!/usr/bin/env python3

import requests
import utils

params = {
    '_fields': 'cn',
    '_queryFilter': 'mail co "jensen" and givenName sw "Al"',
    'scope': 'sub'
}
jwt = utils.authenticate('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {jwt}' }
response = requests.get(
    f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People',
    headers=headers,
    params=params,
    verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))

Source files for this sample: utils.py, query-complex.py

require_relative 'utils.rb'
require 'faraday'

utils = Utils.new('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
options = { ca_file: utils.ca_pem }
jwt = utils.authenticate
query = {
    "_fields": "cn",
    "_queryFilter": "mail co 'jensen' and givenName sw 'Al'",
    "scope": "sub"
}
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", params: query, ssl: options) do |f|
    f.headers['Content-Type'] = 'application/json'
    f.request :authorization, 'Bearer', jwt
end
response = hdap.get('dc=com/dc=example/ou=People')

puts "Status code: #{response.status}\nJSON: #{response.body}"

Source files for this sample: utils.rb, query-complex.rb

HDAP Ruby examples require Ruby 3.2 and the faraday and json gems.

Graph-like queries

Collective attributes provide a mechanism to inherit LDAP attributes from other entries. HDAP relies on this mechanism for graph-like queries.

The ds-evaluation setup profile uses collective attributes to inherit LDAP attribute values for street address from location and quota settings from class of service.

Show example
  • Curl

  • JavaScript

  • Python

  • Ruby

$ curl \
 --get \
 --cacert ca-cert.pem \
 --user dc=com/dc=example/ou=People/uid=kvaughan:bribery \
 --data "_queryFilter=(mail+co+'jensen'+and+l+eq+'San+Francisco'+and+classOfService+eq+'bronze')" \
 --data '_fields=diskQuota,mailQuota,street' \
 --data '_prettyPrint=true' \
 --data 'scope=sub' \
 'https://localhost:8443/hdap/dc=com/dc=example/ou=People'
{
  "result" : [ {
    "_id" : "dc=com/dc=example/ou=People/uid=bjensen",
    "_rev" : "<revision>",
    "street" : [ "201 Mission Street Suite 2900" ],
    "mailQuota" : [ "1 GB" ],
    "diskQuota" : [ "10 GB" ]
  } ],
  "resultCount" : 1,
  "pagedResultsCookie" : null,
  "totalPagedResultsPolicy" : "NONE",
  "totalPagedResults" : -1,
  "remainingPagedResults" : -1
}
(async () => {
    const { authenticate, doRequest, getOptions } = require('./utils')
    const filter = "mail+co+'jensen'+and+l+eq+'San+Francisco'+and+classOfService+eq+'bronze'"
    const options = getOptions({
        path: `/hdap/dc=com/dc=example/ou=People?_queryFilter=${filter}&_fields=diskQuota,mailQuota,street&scope=sub`
    })
    const jwt = await authenticate(options)
    options.headers['Authorization'] = 'Bearer ' + jwt
    const response = await doRequest('HDAP: graph query', options)
    console.log(response)
})().catch(error => { console.error(error) })

Source files for this sample: query-graph.js, utils.js

#!/usr/bin/env python3

import requests
import utils

params = {
    '_fields': 'diskQuota,mailQuota,street',
    '_queryFilter': 'mail co "jensen" and l eq "San Francisco" and classOfService eq "bronze"',
    'scope': 'sub'
}
jwt = utils.authenticate('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {jwt}' }
response = requests.get(
    f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People',
    headers=headers,
    params=params,
    verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))

Source files for this sample: utils.py, query-graph.py

require_relative 'utils.rb'
require 'faraday'

utils = Utils.new('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
options = { ca_file: utils.ca_pem }
jwt = utils.authenticate
query = {
    "_fields": "diskQuota,mailQuota,street",
    "_queryFilter": "mail co 'jensen' and l eq 'San Francisco' and classOfService eq 'bronze'",
    "scope": "sub"
}
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", params: query, ssl: options) do |f|
    f.headers['Content-Type'] = 'application/json'
    f.request :authorization, 'Bearer', jwt
end
response = hdap.get('dc=com/dc=example/ou=People')

puts "Status code: #{response.status}\nJSON: #{response.body}"

Source files for this sample: utils.rb, query-graph.rb

HDAP Ruby examples require Ruby 3.2 and the faraday and json gems.

Configure collective attributes as necessary for your graph-like queries.

Queries and JSON attributes

The default JSON query index works for JSON attributes that hold arbitrary JSON objects. This includes JSON with nested objects, such as {"array":[{"x":1,"y":2},{"x":3,"y":4}]}. As a result, HDAP filter expressions can target JSON fields in indexed JSON attribute objects.

HDAP query filter expressions support the grouping operators described in RFC 7644, section 3.4.2.2. Filtering, Table 5: Grouping Operators. In other words, HDAP query filter expressions can use complex attribute filter grouping, with brackets ([]) to group expressions in the filter.

Complex attribute filter grouping lets filter expressions target array objects. This search finds an entry with a json attribute containing an array of objects:

  • Curl

  • JavaScript

  • Python

  • Ruby

$ curl \
 --get \
 --cacert ca-cert.pem \
 --user dc=com/dc=example/ou=People/uid=kvaughan:bribery \
 --data-urlencode "_queryFilter=(json/array[x eq 1] and json/array[y eq 4])" \
 --data '_fields=json' \
 --data '_prettyPrint=true' \
 --data 'scope=sub' \
 'https://localhost:8443/hdap/dc=com/dc=example/ou=People'
{
  "result" : [ {
    "_id" : "dc=com/dc=example/ou=People/uid=abarnes",
    "_rev" : "<revision>",
    "json" : [ {
      "array" : [ {
        "x" : 1,
        "y" : 2
      }, {
        "x" : 3,
        "y" : 4
      } ]
    } ]
  } ],
  "resultCount" : 1,
  "pagedResultsCookie" : null,
  "totalPagedResultsPolicy" : "NONE",
  "totalPagedResults" : -1,
  "remainingPagedResults" : -1
}
(async () => {
    const { authenticate, doRequest, getOptions } = require('./utils')
    const filter = encodeURIComponent('(json/array[x eq 1] and json/array[y eq 4])')
    const options = getOptions({
        path: `/hdap/dc=com/dc=example/ou=People?_queryFilter=${filter}&_fields=json&scope=sub`
    })
    const jwt = await authenticate(options)
    options.headers['Authorization'] = 'Bearer ' + jwt
    const response = await doRequest('HDAP: JSON query', options)
    console.log(response)
})().catch(error => { console.error(error) })

Source files for this sample: query-json.js, utils.js

#!/usr/bin/env python3

import requests
import utils

params = {
    '_fields': 'json',
    '_queryFilter': '(json/array[x eq 1] and json/array[y eq 4])',
    'scope': 'sub'
}
jwt = utils.authenticate('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {jwt}' }
response = requests.get(
    f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People',
    headers=headers,
    params=params,
    verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))

Source files for this sample: utils.py, query-json.py

require_relative 'utils.rb'
require 'faraday'

utils = Utils.new('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
options = { ca_file: utils.ca_pem }
jwt = utils.authenticate
query = {
    "_fields": "json",
    "_queryFilter": "(json/array[x eq 1] and json/array[y eq 4])",
    "scope": "sub"
}
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", params: query, ssl: options) do |f|
    f.headers['Content-Type'] = 'application/json'
    f.request :authorization, 'Bearer', jwt
end
response = hdap.get('dc=com/dc=example/ou=People')

puts "Status code: #{response.status}\nJSON: #{response.body}"

Source files for this sample: utils.rb, query-json.rb

HDAP Ruby examples require Ruby 3.2 and the faraday and json gems.

  • The filter json/array[x eq 1] and json/array[y eq 4] matches because it matches both objects in the array.

  • The filter json/array[x eq 1 and y eq 2] matches because it matches the first object of the array.

  • The filter json/array[x eq 1 and y eq 4] fails to match, because the array has no object {"x":1,"y":4}.

Count child resources

Use the _countOnly=true query string parameter to get the number of child resources directly beneath a resource. You must also set _queryFilter=true and leave scope=one (default):

  • Curl

  • JavaScript

  • Python

  • Ruby

$ curl \
 --get \
 --user dc=com/dc=example/ou=People/uid=kvaughan:bribery \
 --cacert ca-cert.pem \
 --header 'Accept-API-Version: protocol=2.2,resource=1.0' \
 --data '_countOnly=true' \
 --data '_queryFilter=true' \
 --data '_prettyPrint=true' \
 'https://localhost:8443/hdap/dc=com/dc=example/ou=People'
{
  "result" : [ ],
  "resultCount" : 100153,
  "pagedResultsCookie" : null,
  "totalPagedResultsPolicy" : "ESTIMATE",
  "totalPagedResults" : 100153,
  "remainingPagedResults" : -1
}
(async () => {
    const { authenticate, doRequest, getOptions } = require('./utils')
    const options = getOptions({
        path: '/hdap/dc=com/dc=example/ou=People?_queryFilter=true&_countOnly=true',
    })
    const jwt = await authenticate(options)
    options.headers['Accept-API-Version'] = 'protocol=2.2,resource=1.0'
    options.headers['Authorization'] = 'Bearer ' + jwt
    const response = await doRequest('HDAP: query for count', options)
    console.log(response)
})().catch(error => { console.error(error) })

Source files for this sample: query-count.js, utils.js

#!/usr/bin/env python3

import requests
import utils

params = {
    '_countOnly': True,
    '_queryFilter': True
}
jwt = utils.authenticate('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
headers = {
    'Content-Type': 'application/json',
    'Authorization': f'Bearer {jwt}',
    'Accept-API-Version': 'protocol=2.2,resource=1.0'
}
response = requests.get(
    f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People',
    headers=headers,
    params=params,
    verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))

Source files for this sample: utils.py, query-count.py

require_relative 'utils.rb'
require 'faraday'

utils = Utils.new('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
options = { ca_file: utils.ca_pem }
jwt = utils.authenticate
query = {
    "_countOnly": true,
    "_queryFilter": true
}
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", params: query, ssl: options) do |f|
    f.headers['Content-Type'] = 'application/json'
    f.headers['Accept-API-Version'] = 'protocol=2.2,resource=1.0'
    f.request :authorization, 'Bearer', jwt
end
response = hdap.get('dc=com/dc=example/ou=People')

puts "Status code: #{response.status}\nJSON: #{response.body}"

Source files for this sample: utils.rb, query-count.rb

HDAP Ruby examples require Ruby 3.2 and the faraday and json gems.

Notice the search returns an empty result array. This feature relies on the numSubordinates virtual attribute.

Paged results

Get results one page at a time with these query string parameters:

  • _pageSize=<number>

  • _pagedResultsCookie=<cookie>

Show request for first page of five results
  • Curl

  • JavaScript

  • Python

  • Ruby

# Request five results per page and retrieve the first page:
$ curl \
 --get \
 --cacert ca-cert.pem \
 --user dc=com/dc=example/ou=People/uid=kvaughan:bribery \
 --data "_queryFilter=objectClass+eq+'posixAccount'" \
 --data '_pageSize=5' \
 --data '_fields=_id' \
 --data '_prettyPrint=true' \
 --data 'scope=sub' \
 'https://localhost:8443/hdap/dc=com/dc=example/ou=People'
{
  "result" : [ {
    "_id" : "dc=com/dc=example/ou=People/uid=abarnes",
    "_rev" : "<revision>"
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=abergin",
    "_rev" : "<revision>"
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=achassin",
    "_rev" : "<revision>"
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=ahall",
    "_rev" : "<revision>"
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=ahel",
    "_rev" : "<revision>"
  } ],
  "resultCount" : 5,
  "pagedResultsCookie" : "AAAAAAAAABE=",
  "totalPagedResultsPolicy" : "NONE",
  "totalPagedResults" : -1,
  "remainingPagedResults" : -1
}
(async () => {
    const { authenticate, doRequest, getOptions } = require('./utils')
    const filter = "objectClass+eq+'posixAccount'"
    const options = getOptions({
        path: `/hdap/dc=com/dc=example/ou=People?_queryFilter=${filter}&_pageSize=5&_fields=_id&scope=sub`
    })
    const jwt = await authenticate(options)
    options.headers['Authorization'] = 'Bearer ' + jwt
    const response = await doRequest('HDAP: query first five paged results', options)
    console.log(response)
})().catch(error => { console.error(error) })

Source files for this sample: query-paged-first-five.js, utils.js

#!/usr/bin/env python3

import requests
import utils

params = {
    '_fields': '_id',
    '_queryFilter': 'objectClass eq "posixAccount"',
    '_pageSize': 5,
    'scope': 'sub'
}
jwt = utils.authenticate('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {jwt}' }
response = requests.get(
    f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People',
    headers=headers,
    params=params,
    verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))

Source files for this sample: utils.py, query-paged-first-five.py

require_relative 'utils.rb'
require 'faraday'

utils = Utils.new('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
options = { ca_file: utils.ca_pem }
jwt = utils.authenticate
query = {
    "_fields": "_id",
    "_queryFilter": "objectClass eq 'posixAccount'",
    "_pageSize": 5,
    "scope": "sub"
}
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", params: query, ssl: options) do |f|
    f.headers['Content-Type'] = 'application/json'
    f.request :authorization, 'Bearer', jwt
end
response = hdap.get('dc=com/dc=example/ou=People')

puts "Status code: #{response.status}\nJSON: #{response.body}"

Source files for this sample: utils.rb, query-paged-first-five.rb

HDAP Ruby examples require Ruby 3.2 and the faraday and json gems.

Show request for next page of five results
  • Curl

  • JavaScript

  • Python

  • Ruby

# Provide the cookie to request the next five results:
$ export COOKIE=$(cut -d \" -f 4 <(grep pagedResultsCookie \
 <(curl \
 --get \
 --cacert ca-cert.pem \
 --user dc=com/dc=example/ou=People/uid=kvaughan:bribery \
 --data "_queryFilter=objectClass+eq+'posixAccount'" \
 --data '_pageSize=5' \
 --data '_fields=_id' \
 --data '_prettyPrint=true' \
 --data 'scope=sub' \
 'https://localhost:8443/hdap/dc=com/dc=example/ou=People')))
$ curl \
 --get \
 --cacert ca-cert.pem \
 --user dc=com/dc=example/ou=People/uid=kvaughan:bribery \
 --data "_queryFilter=objectClass+eq+'posixAccount'" \
 --data '_pageSize=5' \
 --data "_pagedResultsCookie=$COOKIE" \
 --data '_fields=_id' \
 --data '_prettyPrint=true' \
 --data 'scope=sub' \
 'https://localhost:8443/hdap/dc=com/dc=example/ou=People'
{
  "result" : [ {
    "_id" : "dc=com/dc=example/ou=People/uid=ahunter",
    "_rev" : "<revision>"
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=ajensen",
    "_rev" : "<revision>"
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=aknutson",
    "_rev" : "<revision>"
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=alangdon",
    "_rev" : "<revision>"
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=alutz",
    "_rev" : "<revision>"
  } ],
  "resultCount" : 5,
  "pagedResultsCookie" : "AAAAAAAAABE=",
  "totalPagedResultsPolicy" : "NONE",
  "totalPagedResults" : -1,
  "remainingPagedResults" : -1
}
(async () => {
    const { authenticate, doRequest, getOptions } = require('./utils')
    const filter = "objectClass+eq+'posixAccount'"
    const options = getOptions({
        path: `/hdap/dc=com/dc=example/ou=People?_queryFilter=${filter}&_pageSize=5&_fields=_id&scope=sub`
    })
    const jwt = await authenticate(options)
    options.headers['Authorization'] = 'Bearer ' + jwt
    let response = await doRequest('HDAP: query first five paged results', options)
    console.log(response)
    const cookie = JSON.parse(response.data).pagedResultsCookie
    options.path += `&_pagedResultsCookie=${cookie}`
    response = await doRequest('HDAP: query next five paged results', options)
    console.log(response)
})().catch(error => { console.error(error) })

Source files for this sample: query-paged-next-five.js, utils.js

#!/usr/bin/env python3

import requests
import utils

resource = f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People'
params = {
    '_fields': '_id',
    '_queryFilter': 'objectClass eq "posixAccount"',
    '_pageSize': 5,
    'scope': 'sub'
}
jwt = utils.authenticate('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {jwt}' }
response = requests.get(
    resource,
    headers=headers,
    params=params,
    verify=utils.ca_pem)

cookie = response.json()['pagedResultsCookie']
params['_pagedResultsCookie'] = cookie

response = requests.get(
    resource,
    headers=headers,
    params=params,
    verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))

Source files for this sample: utils.py, query-paged-next-five.py

require_relative 'utils.rb'
require 'faraday'

utils = Utils.new('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
options = { ca_file: utils.ca_pem }
jwt = utils.authenticate
query = {
    "_fields": "_id",
    "_queryFilter": "objectClass eq 'posixAccount'",
    "_pageSize": 5,
    "scope": "sub"
}
resource = 'dc=com/dc=example/ou=People'
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", params: query, ssl: options) do |f|
    f.headers['Content-Type'] = 'application/json'
    f.request :authorization, 'Bearer', jwt
end
cookie = JSON.parse(hdap.get(resource).body, symbolize_names: true)[:pagedResultsCookie]

query['_pagedResultsCookie'] = cookie
hdap.params = query
response = hdap.get(resource)

puts "Status code: #{response.status}\nJSON: #{response.body}"

Source files for this sample: utils.rb, query-paged-next-five.rb

HDAP Ruby examples require Ruby 3.2 and the faraday and json gems.

Notice the following features of the responses:

  • "totalPagedResultsPolicy" : "NONE" means HDAP did not calculate the counts.

  • "remainingPagedResults" : -1 means HDAP did not count the remaining results.

    HDAP never counts remainingPagedResults because it would require a potentially costly calculation to determine the current position in the total result set.

  • "totalPagedResults" : -1 means HDAP did not count the total results.

When the query has the following characteristics, the response contains an estimated totalPagedResults count:

  • The request specifies the policy using the parameter _totalPagedResultsPolicy=ESTIMATE.

  • The _pageSize parameter is an integer greater than zero.

  • The LDAP search for the query is indexed.

  • Curl

  • JavaScript

  • Python

  • Ruby

$ curl \
 --get \
 --cacert ca-cert.pem \
 --user dc=com/dc=example/ou=People/uid=kvaughan:bribery \
 --data "_queryFilter=mail+co+'jensen'" \
 --data '_pageSize=2' \
 --data '_totalPagedResultsPolicy=ESTIMATE' \
 --data '_fields=_id' \
 --data '_prettyPrint=true' \
 --data 'scope=sub' \
 'https://localhost:8443/hdap/dc=com/dc=example/ou=People'
{
  "result" : [ {
    "_id" : "dc=com/dc=example/ou=People/uid=ajensen",
    "_rev" : "<revision>"
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=bjensen",
    "_rev" : "<revision>"
  } ],
  "resultCount" : 2,
  "pagedResultsCookie" : "AAAAAAAAAEI=",
  "totalPagedResultsPolicy" : "ESTIMATE",
  "totalPagedResults" : 7,
  "remainingPagedResults" : -1
}
(async () => {
    const { authenticate, doRequest, getOptions } = require('./utils')
    const filter = "mail+co+'jensen'"
    const pageParams = '_pageSize=2&_totalPagedResultsPolicy=ESTIMATE'
    const options = getOptions({
        path: `/hdap/dc=com/dc=example/ou=People?_queryFilter=${filter}&${pageParams}&_fields=_id&scope=sub`
    })
    const jwt = await authenticate(options)
    options.headers['Authorization'] = 'Bearer ' + jwt
    const response = await doRequest('HDAP: paged query', options)
    console.log(response)
})().catch(error => { console.error(error) })

Source files for this sample: query-paged.js, utils.js

#!/usr/bin/env python3

import requests
import utils

params = {
    '_fields': '_id',
    '_queryFilter': 'mail co "jensen"',
    '_pageSize': 2,
    '_totalPagedResultsPolicy': 'ESTIMATE',
    'scope': 'sub'
}
jwt = utils.authenticate('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {jwt}' }
response = requests.get(
    f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People',
    headers=headers,
    params=params,
    verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))

Source files for this sample: utils.py, query-paged.py

require_relative 'utils.rb'
require 'faraday'

utils = Utils.new('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
options = { ca_file: utils.ca_pem }
jwt = utils.authenticate
query = {
    "_fields": "_id",
    "_queryFilter": "mail co 'jensen'",
    "_pageSize": 2,
    "_totalPagedResultsPolicy": "ESTIMATE",
    "scope": "sub"
}
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", params: query, ssl: options) do |f|
    f.headers['Content-Type'] = 'application/json'
    f.request :authorization, 'Bearer', jwt
end
response = hdap.get('dc=com/dc=example/ou=People')

puts "Status code: #{response.status}\nJSON: #{response.body}"

Source files for this sample: utils.rb, query-paged.rb

HDAP Ruby examples require Ruby 3.2 and the faraday and json gems.

The estimated number of results can be useful, for example, when the LDAP search uses a big index or a VLV index and the total number of results is large.

Server-side sort

Use the _sortKeys parameter to have HDAP sort the query results based on one or more fields in the resources.

The following example sorts results in reverse order by given name (-givenName):

  • Curl

  • JavaScript

  • Python

  • Ruby

$ curl \
 --get \
 --cacert ca-cert.pem \
 --user dc=com/dc=example/ou=People/uid=kvaughan:bribery \
 --data "_queryFilter=sn+co+'barnes'" \
 --data '_sortKeys=-givenName' \
 --data '_fields=cn' \
 --data '_prettyPrint=true' \
 --data 'scope=sub' \
 'https://localhost:8443/hdap/dc=com/dc=example/ou=People'
(async () => {
    const { authenticate, doRequest, getOptions } = require('./utils')
    const filter = "sn+co+'barnes'"
    const options = getOptions({
        path: `/hdap/dc=com/dc=example/ou=People?_queryFilter=${filter}&_sortKeys=-givenName&_fields=cn&scope=sub`
    })
    const jwt = await authenticate(options)
    options.headers['Authorization'] = 'Bearer ' + jwt
    const response = await doRequest('HDAP: query with server-side sort', options)
    console.log(response)
})().catch(error => { console.error(error) })

Source files for this sample: query-sss.js, utils.js

#!/usr/bin/env python3

import requests
import utils

params = {
    '_fields': 'cn',
    '_queryFilter': 'sn co "barnes"',
    '_sortKeys': '-givenName',
    'scope': 'sub'
}
jwt = utils.authenticate('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {jwt}' }
response = requests.get(
    f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People',
    headers=headers,
    params=params,
    verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))

Source files for this sample: utils.py, query-sss.py

require_relative 'utils.rb'
require 'faraday'

utils = Utils.new('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery')
options = { ca_file: utils.ca_pem }
jwt = utils.authenticate
query = {
    "_fields": "cn",
    "_queryFilter": "sn co 'barnes'",
    "_sortKeys": "-givenName",
    "scope": "sub"
}
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", params: query, ssl: options) do |f|
    f.headers['Content-Type'] = 'application/json'
    f.request :authorization, 'Bearer', jwt
end
response = hdap.get('dc=com/dc=example/ou=People')

puts "Status code: #{response.status}\nJSON: #{response.body}"

Source files for this sample: utils.rb, query-sss.rb

HDAP Ruby examples require Ruby 3.2 and the faraday and json gems.

Show results
{
  "result" : [ {
    "_id" : "dc=com/dc=example/ou=People/uid=user.94561",
    "_rev" : "<revision>",
    "cn" : [ "Atsushi Barnes" ]
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=user.81142",
    "_rev" : "<revision>",
    "cn" : [ "Atsuo Barnes" ]
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=user.67723",
    "_rev" : "<revision>",
    "cn" : [ "Atmane Barnes" ]
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=user.54304",
    "_rev" : "<revision>",
    "cn" : [ "Atlante Barnes" ]
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=user.40885",
    "_rev" : "<revision>",
    "cn" : [ "Atlanta Barnes" ]
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=user.27466",
    "_rev" : "<revision>",
    "cn" : [ "Atl-Sales Barnes" ]
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=user.14047",
    "_rev" : "<revision>",
    "cn" : [ "Atl Barnes" ]
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=user.628",
    "_rev" : "<revision>",
    "cn" : [ "Atique Barnes" ]
  }, {
    "_id" : "dc=com/dc=example/ou=People/uid=abarnes",
    "_rev" : "<revision>",
    "cn" : [ "Anne-Louise Barnes" ]
  } ],
  "resultCount" : 9,
  "pagedResultsCookie" : null,
  "totalPagedResultsPolicy" : "NONE",
  "totalPagedResults" : -1,
  "remainingPagedResults" : -1
}
  • To specify multiple sort keys, use a comma-separated list of fields.

  • The sort key fields you specify must exist in the result entries.

    You do not need to include the sort field(s) in the results.

  • VLV for paged server-side sort shows an HDAP query using a browsing index.

HDAP stores the entire result set before sorting the results. If you expect a large result set for your search, use paged results to limit the performance cost and get results quickly.