Learn HDAP
PingDS let you access LDAP data over HTTP using HTTP Directory Access Protocol (HDAP) APIs that transform HTTP operations into LDAP operations.
Before you try the examples, follow the instructions in Install DS.
Prepare
Get the deployment CA certificate to trust the server:
-
Bash
-
PowerShell
-
Zsh
$ dskeymgr \
export-ca-cert \
--deploymentId $DEPLOYMENT_ID \
--deploymentIdPassword password \
--outputFile ca-cert.pem
Configure Windows to trust the deployment CA certificate. Import the deployment CA from the server truststore using Microsoft Management Console (MMC):
-
Run Microsoft Management Console (
mmc.exe
). -
Add the certificates snap-in to import the deployment CA certificate:
-
In the console, select File > Add/Remove Snap-in, then Add.
-
Select Certificates from the list of snap-ins and click Add.
-
Finish the wizard.
-
-
Import the deployment CA certificate using the snap-in:
-
Select Console Root > Trusted Root Certification Authorities > Certificates.
-
In the Action menu, select Import to open the wizard.
-
Use the wizard to import the deployment CA certificate from the server truststore file,
C:\path\to\opendj\config\keystore
.The truststore password is the text in the file
C:\path\to\opendj\config\keystore.pin
.
-
% dskeymgr \
export-ca-cert \
--deploymentId $DEPLOYMENT_ID \
--deploymentIdPassword password \
--outputFile ca-cert.pem
Create
Use HDAP to create a user resource:
-
Bash
-
JavaScript
-
PowerShell
-
Python
-
Ruby
-
Zsh
$ curl \
--request POST \
--cacert ca-cert.pem \
--user uid=admin:password \
--header 'Content-Type: application/json' \
--data '{
"_id" : "dc=com/dc=example/ou=People/uid=newuser",
"objectClass" : [ "person", "inetOrgPerson", "organizationalPerson", "top" ],
"cn" : [ "New User" ],
"givenName" : [ "New" ],
"mail" : [ "newuser@example.com" ],
"manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ],
"sn" : [ "User" ],
"telephoneNumber" : [ "+1 408 555 1212" ],
"uid" : [ "newuser" ]
}' \
'https://localhost:8443/hdap/dc=com/dc=example/ou=People?_prettyPrint=true'
{
"_id" : "dc=com/dc=example/ou=People/uid=newuser",
"objectClass" : [ "person", "inetOrgPerson", "organizationalPerson", "top" ],
"cn" : [ "New User" ],
"givenName" : [ "New" ],
"mail" : [ "newuser@example.com" ],
"manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ],
"sn" : [ "User" ],
"telephoneNumber" : [ "+1 408 555 1212" ],
"uid" : [ "newuser" ]
}
const { doRequest, getOptions } = require('./utils')
const options = getOptions({
path: '/hdap/dc=com/dc=example/ou=People?_action=create',
credentials: 'uid=admin:password',
method: 'POST',
body: {
"_id": "dc=com/dc=example/ou=People/uid=newuser",
"objectClass": ["person", "inetOrgPerson", "organizationalPerson", "top"],
"cn": ["New User"],
"givenName": ["New"],
"mail": ["newuser@example.com"],
"manager": ["dc=com/dc=example/ou=People/uid=bjensen"],
"sn": ["User"],
"telephoneNumber": ["+1 408 555 1212"],
"uid": ["newuser"]
}
})
doRequest('HDAP: create with POST', options)
.then(response => { console.log(response) })
.catch(error => { console.error(error) })
Source files for this sample: create-newuser.js, utils.js
PS C:\path\to> $Credentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("uid=admin:password"))
$Headers = @{
Authorization = "Basic $Credentials"
}
Invoke-RestMethod `
-Uri https://localhost:8443/hdap/dc=com/dc=example/ou=People `
-Method Post `
-Headers $Headers `
-ContentType application/json `
-Body @"
{
"_id" : "dc=com/dc=example/ou=People/uid=newuser",
"objectClass" : [ "person", "inetOrgPerson", "organizationalPerson", "top" ],
"cn" : [ "New User" ],
"givenName" : [ "New" ],
"mail" : [ "newuser@example.com" ],
"manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ],
"sn" : [ "User" ],
"telephoneNumber" : [ "+1 408 555 1212" ],
"uid" : [ "newuser" ]
}
"@ | ConvertTo-JSON
{
"_id" : "dc=com/dc=example/ou=People/uid=newuser",
"objectClass" : [ "person", "inetOrgPerson", "organizationalPerson", "top" ],
"cn" : [ "New User" ],
"givenName" : [ "New" ],
"mail" : [ "newuser@example.com" ],
"manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ],
"sn" : [ "User" ],
"telephoneNumber" : [ "+1 408 555 1212" ],
"uid" : [ "newuser" ]
}
#!/usr/bin/env python3
import requests
from requests.auth import HTTPBasicAuth
import utils
body = {
'_id': 'dc=com/dc=example/ou=People/uid=newuser',
'objectClass': ['person', 'inetOrgPerson', 'organizationalPerson', 'top'],
'cn': ['New User'],
'givenName': ['New'],
'mail': ['newuser@example.com'],
'manager': ['dc=com/dc=example/ou=People/uid=bjensen'],
'sn': ['User'],
'telephoneNumber': ['+1 408 555 1212'],
'uid': ['newuser']
}
headers = { 'Content-Type': 'application/json' }
response = requests.post(
f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People',
auth=HTTPBasicAuth('uid=admin', 'password'),
headers=headers,
json=body,
verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))
Source files for this sample: utils.py, create-newuser.py
require_relative 'utils.rb'
require 'faraday'
require 'json'
utils = Utils.new('', '')
options = { ca_file: utils.ca_pem }
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", ssl: options) do |f|
f.headers['Content-Type'] = 'application/json'
f.request :authorization, :basic, 'uid=admin', 'password'
end
body = {
'_id' => "dc=com/dc=example/ou=People/uid=newuser",
'objectClass' => ["person", "inetOrgPerson", "organizationalPerson", "top"],
'cn' => ["New User"],
'givenName' => ["New"],
'mail' => ["newuser@example.com"],
'manager' => ["dc=com/dc=example/ou=People/uid=bjensen"],
'sn' => ["User"],
'telephoneNumber' => ["+1 408 555 1212"],
'uid' => ["newuser"]
}
response = hdap.post do |h|
h.path = 'dc=com/dc=example/ou=People'
h.body = JSON.generate(body)
end
puts "Status code: #{response.status}\nJSON: #{response.body}"
Source files for this sample: utils.rb, create-newuser.rb
HDAP Ruby examples require Ruby 3.2 and the faraday
and json
gems.
% curl \
--request POST \
--cacert ca-cert.pem \
--user uid=admin:password \
--header 'Content-Type: application/json' \
--data '{
"_id" : "dc=com/dc=example/ou=People/uid=newuser",
"objectClass" : [ "person", "inetOrgPerson", "organizationalPerson", "top" ],
"cn" : [ "New User" ],
"givenName" : [ "New" ],
"mail" : [ "newuser@example.com" ],
"manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ],
"sn" : [ "User" ],
"telephoneNumber" : [ "+1 408 555 1212" ],
"uid" : [ "newuser" ]
}' \
'https://localhost:8443/hdap/dc=com/dc=example/ou=People?_prettyPrint=true'
{
"_id" : "dc=com/dc=example/ou=People/uid=newuser",
"objectClass" : [ "person", "inetOrgPerson", "organizationalPerson", "top" ],
"cn" : [ "New User" ],
"givenName" : [ "New" ],
"mail" : [ "newuser@example.com" ],
"manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ],
"sn" : [ "User" ],
"telephoneNumber" : [ "+1 408 555 1212" ],
"uid" : [ "newuser" ]
}
-
The command makes a secure connection to the server using HTTPS.
-
The user performing the HTTP POST is the directory superuser.
The default authorization mechanism for HTTP access is HTTP Basic authentication. The superuser’s HTTP user ID,
admin
, is mapped to the LDAP DN,uid=admin
. HDAP uses the DN and password to perform a simple LDAP bind for authentication. The directory uses its LDAP-based access control mechanisms to authorize the operation. -
The successful response is the JSON resource that the command created.
Fields names starting with an underscore like
_id
are reserved. For details, refer to HDAP API reference.
For additional details, refer to HDAP API reference and Create.
Read
Use HDAP to read a user resource:
-
Bash
-
JavaScript
-
PowerShell
-
Python
-
Ruby
-
Zsh
$ curl \
--request GET \
--cacert ca-cert.pem \
--user dc=com/dc=example/ou=People/uid=bjensen:hifalutin \
--header 'Content-Type: application/json' \
'https://localhost:8443/hdap/dc=com/dc=example/ou=People/uid=newuser?_prettyPrint=true'
{
"_id" : "dc=com/dc=example/ou=People/uid=newuser",
"_rev" : "<revision>",
"objectClass" : [ "top", "person", "organizationalPerson", "inetOrgPerson" ],
"cn" : [ "New User" ],
"givenName" : [ "New" ],
"mail" : [ "newuser@example.com" ],
"manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ],
"sn" : [ "User" ],
"telephoneNumber" : [ "+1 408 555 1212" ],
"uid" : [ "newuser" ]
}
const { doRequest, getOptions } = require('./utils')
const options = getOptions({
path: '/hdap/dc=com/dc=example/ou=People/uid=newuser'
})
doRequest('HDAP: read with GET', options)
.then(response => { console.log(response) })
.catch(error => { console.error(error) })
Source files for this sample: read-newuser.js, utils.js
PS C:\path\to> $Credentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("dc=com/dc=example/ou=People/uid=bjensen:hifalutin"))
$Headers = @{
Authorization = "Basic $Credentials"
}
Invoke-RestMethod `
-Uri https://localhost:8443/hdap/dc=com/dc=example/ou=People/uid=newuser `
-Method Get `
-Headers $Headers `
-ContentType application/json | ConvertTo-JSON
{
"_id" : "dc=com/dc=example/ou=People/uid=newuser",
"_rev" : "<revision>",
"objectClass" : [ "top", "person", "organizationalPerson", "inetOrgPerson" ],
"cn" : [ "New User" ],
"givenName" : [ "New" ],
"mail" : [ "newuser@example.com" ],
"manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ],
"sn" : [ "User" ],
"telephoneNumber" : [ "+1 408 555 1212" ],
"uid" : [ "newuser" ]
}
#!/usr/bin/env python3
import requests
from requests.auth import HTTPBasicAuth
import utils
response = requests.get(
f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People/uid=newuser',
auth=HTTPBasicAuth('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery'),
verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))
Source files for this sample: utils.py, read-newuser.py
require_relative 'utils.rb'
require 'faraday'
utils = Utils.new('', '')
options = { ca_file: utils.ca_pem }
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", ssl: options) do |f|
f.headers['Content-Type'] = 'application/json'
f.request :authorization, :basic, 'dc=com/dc=example/ou=People/uid=bjensen', 'hifalutin'
end
response = hdap.get('dc=com/dc=example/ou=People/uid=newuser')
puts "Status code: #{response.status}\nJSON: #{response.body}"
Source files for this sample: utils.rb, read-newuser.rb
HDAP Ruby examples require Ruby 3.2 and the faraday
and json
gems.
% curl \
--request GET \
--cacert ca-cert.pem \
--user dc=com/dc=example/ou=People/uid=bjensen:hifalutin \
--header 'Content-Type: application/json' \
'https://localhost:8443/hdap/dc=com/dc=example/ou=People/uid=newuser?_prettyPrint=true'
{
"_id" : "dc=com/dc=example/ou=People/uid=newuser",
"_rev" : "<revision>",
"objectClass" : [ "top", "person", "organizationalPerson", "inetOrgPerson" ],
"cn" : [ "New User" ],
"givenName" : [ "New" ],
"mail" : [ "newuser@example.com" ],
"manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ],
"sn" : [ "User" ],
"telephoneNumber" : [ "+1 408 555 1212" ],
"uid" : [ "newuser" ]
}
Authenticate when making this HTTP GET request. If no credentials are specified, the response is the HTTP 401 Unauthorized:
{"code":401,"reason":"Unauthorized","message":"Invalid Credentials"}
In other words, the HTTP Basic authorization mechanism requires authentication even for read operations.
For additional details, refer to HDAP API reference and Read. You can also query collections of resources, as described in Query.
Update
Use HDAP to update a user resource:
-
Bash
-
JavaScript
-
PowerShell
-
Python
-
Ruby
-
Zsh
$ curl \
--request PUT \
--cacert ca-cert.pem \
--user uid=admin:password \
--header 'Content-Type: application/json' \
--header "If-Match: *" \
--data '{
"cn" : [ "Updated User" ],
"givenName" : [ "Updated" ],
"mail" : [ "updated.user@example.com" ],
"telephoneNumber" : [ "+1 234 567 8910" ]
}' \
'https://localhost:8443/hdap/dc=com/dc=example/ou=People/uid=newuser?_prettyPrint=true'
{
"_id" : "dc=com/dc=example/ou=People/uid=newuser",
"objectClass" : [ "top", "person", "organizationalPerson", "inetOrgPerson" ],
"cn" : [ "Updated User" ],
"givenName" : [ "Updated" ],
"mail" : [ "updated.user@example.com" ],
"manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ],
"sn" : [ "User" ],
"telephoneNumber" : [ "+1 234 567 8910" ],
"uid" : [ "newuser" ]
}
const { doRequest, getOptions } = require('./utils')
const options = getOptions({
path: '/hdap/dc=com/dc=example/ou=People/uid=newuser',
credentials: 'uid=admin:password',
method: 'PUT',
body: {
"cn": ["Updated User"],
"givenName": ["Updated"],
"mail": ["updated.user@example.com"],
"telephoneNumber": ["+1 234 567 8910"]
}
})
doRequest('HDAP: update newuser', options)
.then(response => { console.log(response) })
.catch(error => { console.error(error) })
Source files for this sample: update-newuser.js, utils.js
PS C:\path\to> $Credentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("uid=admin:password"))
$Headers = @{
"Authorization" = "Basic $Credentials"
"If-Match" = "*"
}
Invoke-RestMethod `
-Uri https://localhost:8443/hdap/dc=com/dc=example/ou=People/uid=newuser `
-Method Put `
-Headers $Headers `
-ContentType application/json `
-Body @"
{
"cn" : [ "Updated User" ],
"givenName" : [ "Updated" ],
"mail" : [ "updated.user@example.com" ],
"telephoneNumber" : [ "+1 234 567 8910" ]
}
"@ | ConvertTo-JSON
{
"_id" : "dc=com/dc=example/ou=People/uid=newuser",
"objectClass" : [ "top", "person", "organizationalPerson", "inetOrgPerson" ],
"cn" : [ "Updated User" ],
"givenName" : [ "Updated" ],
"mail" : [ "updated.user@example.com" ],
"manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ],
"sn" : [ "User" ],
"telephoneNumber" : [ "+1 234 567 8910" ],
"uid" : [ "newuser" ]
}
#!/usr/bin/env python3
import requests
from requests.auth import HTTPBasicAuth
import utils
body = {
'cn': ['Updated User'],
'givenName': ['Updated'],
'mail': ['updated.user@example.com'],
'telephoneNumber': ['+1 234 567 8910']
}
headers = { 'Content-Type': 'application/json' }
response = requests.put(
f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People/uid=newuser',
auth=HTTPBasicAuth('uid=admin', 'password'),
headers=headers,
json=body,
verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))
Source files for this sample: utils.py, update-newuser.py
require_relative 'utils.rb'
require 'faraday'
require 'json'
utils = Utils.new('', '')
options = { ca_file: utils.ca_pem }
fields = { '_fields': 'telephoneNumber' }
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", params: fields, ssl: options) do |f|
f.headers['Content-Type'] = 'application/json'
f.request :authorization, :basic, 'uid=admin', 'password'
end
body = {
"cn" => ["Updated User"],
"givenName" => ["Updated"],
"mail" => ["updated.user@example.com"],
"telephoneNumber" => ["+1 234 567 8910"]
}
response = hdap.put do |h|
h.path = 'dc=com/dc=example/ou=People/uid=newuser'
h.body = JSON.generate(body)
end
puts "Status code: #{response.status}\nJSON: #{response.body}"
Source files for this sample: utils.rb, update-newuser.rb
HDAP Ruby examples require Ruby 3.2 and the faraday
and json
gems.
% curl \
--request PUT \
--cacert ca-cert.pem \
--user uid=admin:password \
--header 'Content-Type: application/json' \
--header "If-Match: *" \
--data '{
"cn" : [ "Updated User" ],
"givenName" : [ "Updated" ],
"mail" : [ "updated.user@example.com" ],
"telephoneNumber" : [ "+1 234 567 8910" ]
}' \
'https://localhost:8443/hdap/dc=com/dc=example/ou=People/uid=newuser?_prettyPrint=true'
{
"_id" : "dc=com/dc=example/ou=People/uid=newuser",
"objectClass" : [ "top", "person", "organizationalPerson", "inetOrgPerson" ],
"cn" : [ "Updated User" ],
"givenName" : [ "Updated" ],
"mail" : [ "updated.user@example.com" ],
"manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ],
"sn" : [ "User" ],
"telephoneNumber" : [ "+1 234 567 8910" ],
"uid" : [ "newuser" ]
}
HDAP versions resources with revision numbers.
A revision is specified in the resource’s _rev
field.
The --header "If-Match: *"
tells HDAP to replace the resource regardless of its revision.
Alternatively, set --header "If-Match: revision"
to replace the resource only if its revision matches.
For additional details, refer to HDAP API reference and Update. You can also patch resources instead of replacing them entirely. Refer to Patch.
Delete
Use HDAP to delete a user resource:
-
Bash
-
JavaScript
-
PowerShell
-
Python
-
Ruby
-
Zsh
$ curl \
--request DELETE \
--cacert ca-cert.pem \
--user uid=admin:password \
--header 'Content-Type: application/json' \
'https://localhost:8443/hdap/dc=com/dc=example/ou=People/uid=newuser?_prettyPrint=true'
{
"_id" : "dc=com/dc=example/ou=People/uid=newuser",
"_rev" : "<revision>",
"objectClass" : [ "top", "person", "organizationalPerson", "inetOrgPerson" ],
"cn" : [ "Updated User" ],
"givenName" : [ "Updated" ],
"mail" : [ "updated.user@example.com" ],
"manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ],
"sn" : [ "User" ],
"telephoneNumber" : [ "+1 234 567 8910" ],
"uid" : [ "newuser" ]
}
const { doRequest, getOptions } = require('./utils')
const options = getOptions({
path: '/hdap/dc=com/dc=example/ou=People/uid=newuser',
credentials: 'uid=admin:password',
method: 'DELETE'
})
doRequest('HDAP: delete newuser', options)
.then(response => { console.log(response) })
.catch(error => { console.error(error) })
Source files for this sample: delete-newuser.js, utils.js
PS C:\path\to> $Credentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("uid=admin:password"))
$Headers = @{
Authorization = "Basic $Credentials"
}
Invoke-RestMethod `
-Uri https://localhost:8443/hdap/dc=com/dc=example/ou=People/uid=newuser `
-Method Delete `
-Headers $Headers `
-ContentType application/json | ConvertTo-JSON
{
"_id" : "dc=com/dc=example/ou=People/uid=newuser",
"_rev" : "<revision>",
"objectClass" : [ "top", "person", "organizationalPerson", "inetOrgPerson" ],
"cn" : [ "Updated User" ],
"givenName" : [ "Updated" ],
"mail" : [ "updated.user@example.com" ],
"manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ],
"sn" : [ "User" ],
"telephoneNumber" : [ "+1 234 567 8910" ],
"uid" : [ "newuser" ]
}
#!/usr/bin/env python3
import requests
from requests.auth import HTTPBasicAuth
import utils
response = requests.delete(
f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People/uid=newuser',
auth=HTTPBasicAuth('uid=admin', 'password'),
verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))
Source files for this sample: utils.py, delete-newuser.py
require_relative 'utils.rb'
require 'faraday'
utils = Utils.new('', '')
options = { ca_file: utils.ca_pem }
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", ssl: options) do |f|
f.headers['Content-Type'] = 'application/json'
f.request :authorization, :basic, 'uid=admin', 'password'
end
response = hdap.delete('dc=com/dc=example/ou=People/uid=newuser')
puts "Status code: #{response.status}\nJSON: #{response.body}"
Source files for this sample: utils.rb, delete-newuser.rb
HDAP Ruby examples require Ruby 3.2 and the faraday
and json
gems.
% curl \
--request DELETE \
--cacert ca-cert.pem \
--user uid=admin:password \
--header 'Content-Type: application/json' \
'https://localhost:8443/hdap/dc=com/dc=example/ou=People/uid=newuser?_prettyPrint=true'
{
"_id" : "dc=com/dc=example/ou=People/uid=newuser",
"_rev" : "<revision>",
"objectClass" : [ "top", "person", "organizationalPerson", "inetOrgPerson" ],
"cn" : [ "Updated User" ],
"givenName" : [ "Updated" ],
"mail" : [ "updated.user@example.com" ],
"manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ],
"sn" : [ "User" ],
"telephoneNumber" : [ "+1 234 567 8910" ],
"uid" : [ "newuser" ]
}
For additional details, refer to HDAP API reference and Delete.