The following sections demonstrate how to interact with WAPI through curl ( see http://curl.haxx.se/ for more information). This sample code shows you how to create an object, modify it, search for it, and delete it. The sample code uses the network object and assumes that no other networks exist on the appliance.
Use -k1 in curl to allow connections even if the appliance SSL certificate is not signed by a recognized SSL authority and to force TLS negotiation. If you want to capture the actual traffic, use the –trace or –trace-ascii options to invoke curl.
These tests assume that the appliance ip is 192.168.1.2, and that you have a valid user name of ‘admin’ and a password of ‘testpw’.
\ at the end of the line means the line was wrapped for documentation purposes but should be joined with the previous line(s) when entering the command in your shell.
Note that some shells can interact with quote characters inside the requests. In case of a failure, consider using the curl -v and –trace-ascii options to inspect what has been sent to the server to ensure that your shell did not affect the requested data.
To create networks, use a POST request:
curl -k1 -u admin:testpw -X POST https://192.168.1.2/wapi/v2.12.3/network \
-d network=10.1.0.0/16
The server returns a reference of the created network:
"network/ZG5zLm5ldHdvcmskMTAuMS4wLjAvMTYvMA:10.1.0.0%2F16"
To create another network, send another POST request:
curl -k1 -u admin:testpw -X POST https://192.168.1.2/wapi/v2.12.3/network \
-d network=10.2.0.0/16
To verify that both networks have been created, send a GET request:
curl -k1 -u admin:testpw -X GET https://192.168.1.2/wapi/v2.12.3/network
The server returns a list with both networks:
[
{
"_ref": "network/ZG5zLm5ldHdvcmskMTAuMS4wLjAvMTYvMA:10.1.0.0%2F16",
"network": "10.1.0.0/16",
"network_view": "default"
},
{
"_ref": "network/ZG5zLm5ldHdvcmskMTAuMi4wLjAvMTYvMA:10.2.0.0%2F16",
"network": "10.2.0.0/16",
"network_view": "default"
}
]
Note that the returned references could be different in your installation. The sample code uses references returned in the above example. Depending on your installation, make sure that you use the references your server returns.
To modify a network, send a PUT request. Send the following to modify its comment:
curl -k1 -u admin:testpw -X PUT \
https://192.168.1.2/wapi/v2.12.3/network/ZG5zLm5ldHdvcmskMTAuMS4wLjAvMTYvMA:\
10.1.0.0%2F16 -d comment='Sample comment'
The server still returns the network reference. Note that this could be different from before:
"network/ZG5zLm5ldHdvcmskMTAuMS4wLjAvMTYvMA:10.1.0.0%2F16"
Check that the network was modified, since comment is not a field that is returned by default add _return_fields to the GET request:
curl -k1 -u admin:testpw -X GET https://192.168.1.2/wapi/v2.12.3/network \
-d _return_fields=network,network_view,comment
Note that the 10.1.0.0/16 network has been modified:
[
{
"_ref": "network/ZG5zLm5ldHdvcmskMTAuMS4wLjAvMTYvMA:10.1.0.0%2F16",
"comment": "Sample comment",
"network": "10.1.0.0/16",
"network_view": "default"
},
{
"_ref": "network/ZG5zLm5ldHdvcmskMTAuMi4wLjAvMTYvMA:10.2.0.0%2F16",
"network": "10.2.0.0/16",
"network_view": "default"
}
]
To find networks with comments that contain the word sample in a case-insensitive way:
curl -k1 -u admin:testpw -X GET https://192.168.1.2/wapi/v2.12.3/network \
-d comment~:=sample
The server returns the network we just modified:
[
{
"_ref": "network/ZG5zLm5ldHdvcmskMTAuMS4wLjAvMTYvMA:10.1.0.0%2F16",
"comment": "Sample comment",
"network": "10.1.0.0/16",
"network_view": "default"
}
]
If there is no match, the server returns an empty list:
curl -k1 -u admin:testpw -X GET https://192.168.1.2/wapi/v2.12.3/network \
-d comment~:=nomatch
The server returns the following:
[]
To delete a network, send a DELETE request using a reference you have retrieved by searching. For example, to delete the networks we created above, send the following:
curl -k1 -u admin:testpw -X DELETE \
https://192.168.1.2/wapi/v2.12.3/network/ZG5zLm5ldHdvcmskMTAuMS4wLjAvMTYvMA:\
10.1.0.0%2F16
The server returns the reference of the object it just deleted, if the deletion was successful:
"network/ZG5zLm5ldHdvcmskMTAuMS4wLjAvMTYvMA:10.1.0.0%2F16"
To delete the other network, send the following:
curl -k1 -u admin:testpw -X DELETE \
https://192.168.1.2/wapi/v2.12.3/network/ZG5zLm5ldHdvcmskMTAuMi4wLjAvMTYvMA:\
10.2.0.0%2F16
Note that both networks have been removed:
curl -k1 -u admin:testpw -X GET https://192.168.1.2/wapi/v2.12.3/network
The server returns the following:
[]
To create a host record in a specified zone, first send the following request to create the zone:
curl -k1 -u admin:testpw -H "Content-Type: application/json" \
-X POST https://192.168.1.2/wapi/v2.12.3/zone_auth \
-d '{"fqdn": "zone.com"}'
Then send the following request to create the host:
curl -k1 -u admin:testpw -H "Content-Type: application/json" \
-X POST https://192.168.1.2/wapi/v2.12.3/record:host -d \
'{"ipv4addrs":[{"ipv4addr":"10.222.0.12"}],"name":"host.zone.com"}'
Note that it might be necessary to specify the content type explicitly when using the -d option in curl.
To schedule an object creation, use a POST request with the _schedinfo.scheduled_time parameter:
curl -k1 -u admin:testpw -X POST https://192.168.1.2/wapi/v2.12.3/network \
-d network=10.1.0.0/16 -d _schedinfo.scheduled_time=1367752903
The server returns a reference of the created scheduled task:
"scheduledtask/b25lLnF1ZXVlZF90YXNrJDY:6/PENDING"
To execute a function call, use a POST request with the _function parameter. For example, first create a network:
curl -k1 -u admin:testpw -X POST https://192.168.1.2/wapi/v2.12.3/network \
-d network=10.1.0.0/16
the server will then return a reference to the network that was just created:
"network/ZG5zLm5ldHdvcmskMTAuMS4wLjAvMTYvMA:10.1.0.0/16/default"
now use this reference to retrieve the next three available /24 networks in this network excluding 10.1.1.0/24 and 10.1.3.0/24:
curl -k1 -u admin:testpw -X POST \
https://192.168.1.2/wapi/v2.12.3/network/ZG5zLm5ldHdvcmskMTAuMS4wLjAvMTYvMA:10.1.0.0\
/16/default?_function=next_available_network -H "Content-Type: application/json" \
-d '{"exclude": ["10.1.1.0/24", "10.1.3.0/24"], "cidr": 24, "num": 3}'
The server returns a list of available networks with the above constraints:
{
"networks": [
"10.1.0.0/24",
"10.1.2.0/24",
"10.1.4.0/24"
]
}
To upload a file to the appliance, first tell the appliance so:
curl -k1 -u admin:testpw -X POST \
'https://192.168.1.2/wapi/v2.12.3/fileop?_function=uploadinit'
The appliance will return the URL and a token value:
{
"token": "eJydkMFOwzAMhu9+k......",
"url": "https://192.168.1.2/...."
}
The file can then be uploaded to the specified URL:
curl -k1 -u admin:testpw -F name=somefile.txt -F filedata=@somefile.txt \
'https://192.168.1.2/...'
Finally, we need to signal to the appliance that the upload has been completed and that it needs to perform the requested action on the uploaded file. In this example, we will use setfiledest:
curl -k1 -u admin:testpw -X POST \
'https://192.168.1.2/wapi/v2.12.3/fileop?_function=setfiledest' \
-H "Content-Type: application/json" \
-d '{ "dest_path": "/somefile.txt", "type": "TFTP_FILE", '
'"token": "eJydkMFOwzAMhu9+k..." }'
To download a file from the appliance, first select what to download. In this example, we will download a backup:
curl -k1 -u admin:testpw -X POST \
'https://192.168.1.2/wapi/v2.12.3/fileop?_function=getgriddata' \
-H "Content-Type: application/json" -d '{"type": "BACKUP"}'
The appliance will return a token and a URL from which the file should be downloaded:
{
"token": "eJydUMtuwyAQvO....",
"url": "https://192.168.1.2/...."
}
We can then download the file:
curl -k1 -u admin:testpw -H "Content-type:application/force-download" -O \
"https://192.168.1.2/...."
After the download has been completed, we can signal to the appliance that the operation is done by calling downloadcomplete and passing the token we have retrieved in the first step:
curl -k1 -u admin:testpw -X POST \
'https://192.168.1.2/wapi/v2.12.3/fileop?_function=downloadcomplete' \
-H "Content-Type: application/json" -d '{ "token": "eJydUMtuwyAQvO+...."}'
First insert a zone and some A records:
curl -k1 -u admin:testpw -X POST https://127.0.0.1/wapi/v2.12.3/zone_auth \
-d fqdn=test1.com
curl -k1 -u admin:testpw -X POST https://127.0.0.1/wapi/v2.12.3/network \
-d network=10.1.0.0/16
curl -k1 -u admin:testpw -X POST https://127.0.0.1/wapi/v2.12.3/record:a \
-d ipv4addr=10.1.0.1 -d name=a1.test1.com
curl -k1 -u admin:testpw -X POST https://127.0.0.1/wapi/v2.12.3/record:a \
-d ipv4addr=10.1.0.2 -d name=a2.test1.com
curl -k1 -u admin:testpw -X POST https://127.0.0.1/wapi/v2.12.3/record:a \
-d ipv4addr=10.1.0.3 -d name=a3.test1.com
curl -k1 -u admin:testpw -X POST https://127.0.0.1/wapi/v2.12.3/record:a \
-d ipv4addr=10.1.0.4 -d name=a4.test1.com
curl -k1 -u admin:testpw -X POST https://127.0.0.1/wapi/v2.12.3/record:a \
-d ipv4addr=10.1.0.5 -d name=a5.test1.com
Then check that all records have been inserted correctly:
curl -k1 -u admin:testpw -X GET \
'https://127.0.0.1/wapi/v2.12.3/record:a?name~=test1.com&_return_fields=name'
[
{
"_ref": "record:a/ZG5zLmJpbmRfYSQuXY29tLn3DEwLjEuMC4x:a1.test1.com/default",
"name": "a1.test1.com"
},
{
"_ref": "record:a/ZG5zLmJpbmRLnRlc3QxLGE1LDEwLjEuMC41:a5.test1.com/default",
"name": "a5.test1.com"
},
{
"_ref": "record:a/ZG5zLmJpbmRfYSQc3QxLGE0LDEwLjEuMC40:a4.test1.com/default",
"name": "a4.test1.com"
},
{
"_ref": "record:a/ZG5zLmuY29tLnRlc3QxLGEzLDEwLjEuMC4z:a3.test1.com/default",
"name": "a3.test1.com"
},
{
"_ref": "record:a/ZG5zLmJpbmRfYSQuX2RLGEyLDEwLjEuMC4y:a2.test1.com/default",
"name": "a2.test1.com"
}
]
Now request two records at a time:
curl -k1 -u admin:testpw -X GET \
'https://127.0.0.1/wapi/v2.12.3/record:a?\
name~=test1.com&_return_fields=name&_paging=1&_max_results=2&_return_as_object=1'
{
"next_page_id": "789c5590...4efc1732",
"result": [
{
"_ref": "record:a/ZG5zLmJpbmRfYSQuXY29tLn3DEwLjEuMC4x:a1.test1.com/default",
"name": "a1.test1.com"
},
{
"_ref": "record:a/ZG5zLmJpbmRLnRlc3QxLGE1LDEwLjEuMC41:a5.test1.com/default",
"name": "a5.test1.com"
}
]
}
The server has returned the first page of results and a next_page_id to be used for the next page request. Note that the actual next_page_id will not contain periods (.). The periods are used here to shorten the actual ID:
curl -k1 -u admin:testpw -X GET \
'https://127.0.0.1/wapi/v2.12.3/record:a?_page_id=789c5590...4efc1732'
{
"next_page_id": "789c5590...3e113c3d4d",
"result": [
{
"_ref": "record:a/ZG5zLmJpbmRfYSQc3QxLGE0LDEwLjEuMC40:a4.test1.com/default",
"name": "a4.test1.com"
},
{
"_ref": "record:a/ZG5zLmuY29tLnRlc3QxLGEzLDEwLjEuMC4z:a3.test1.com/default",
"name": "a3.test1.com"
}
]
}
Let’s now fetch the last page of results using the page_id that was just returned:
curl -k1 -u admin:testpw -X GET \
'https://127.0.0.1/wapi/v2.12.3/record:a?_page_id=789c5590...3e113c3d4d'
{
"result": [
{
"_ref": "record:a/ZG5zLmJpbmRfYSQuX2RLGEyLDEwLjEuMC4y:a2.test1.com/default",
"name": "a2.test1.com"
}
]
}
Note that the server has not returned a next_page_id because this was the last page of results.
To create networks, use a POST request:
curl -k1 -u admin:testpw -X POST -HContent-Type:text/xml --data-binary \
'<value type="object"><network>10.1.0.0/16</network></value>' \
https://192.168.1.2/wapi/v2.12.3/network?_return_type=xml-pretty
The server returns a reference of the created network:
<?xml version="1.0"?>
<value>network/ZG5zLm5ldHdvMS4wLjAvMTYvMA:10.1.0.0%2F16</value>
To create another network, send another POST request:
curl -k1 -u admin:testpw -X POST -HAccept:text/xml -HContent-Type:text/xml \
--data-binary '<value type="object"><network>10.2.0.0/16</network></value>' \
https://192.168.1.2/wapi/v2.12.3/network?_return_type=xml-pretty
To verify that both networks have been created, send a GET request:
curl -k1 -u admin:testpw -X GET \
https://192.168.1.2/wapi/v2.12.3/network?_return_type=xml-pretty
The server returns a list with both networks:
<?xml version="1.0"?>
<list>
<value type="object">
<network_view>default</network_view>
<_ref>network/ZG5zLm5ldHdvMS4wLjAvMTYvMA:10.1.0.0%2F16</_ref>
<network>10.1.0.0/16</network>
</value>
<value type="object">
<network_view>default</network_view>
<_ref>network/ZG5zLm5ldHduMi4wLjAvMTYvMA:10.2.0.0%2F16</_ref>
<network>10.2.0.0/16</network>
</value>
</list>
Note that the returned references could be different in your installation. The sample code uses references returned in the above example. Depending on your installation, make sure that you use the references your server returns.
To modify a network, send a PUT request. Send the following to modify its comment:
curl -k1 -u admin:testpw -X PUT -HAccept:text/xml -HContent-Type:text/xml \
--data-binary '<value type="object"><comment>Sample comment</comment></value>' \
https://192.168.1.2/wapi/v2.12.3/network/ZG5zLm5ldHdvMS4wLjAvMTYvMA:10.1.0.0%2F16?\
_return_type=xml-pretty
The server still returns the network reference. Note that this could be different from before:
<?xml version="1.0"?>
<value>network/ZG5zLm5ldHdvMS4wLjAvMTYvMA:10.1.0.0%2F16</value>
Check that the network was modified, since comment is not a field that is returned by default add _return_fields to the GET request:
curl -k1 -u admin:testpw -X GET -HAccept:text/xml \
https://192.168.1.2/wapi/v2.12.3/network \
-d _return_fields=network,network_view,comment -d _return_type=xml-pretty
Note that the 10.1.0.0/16 network has been modified:
<?xml version="1.0"?>
<list>
<value type="object">
<comment>Sample comment</comment>
<network_view>default</network_view>
<_ref>network/ZG5zLm5ldHdvMS4wLjAvMTYvMA:10.1.0.0%2F16</_ref>
<network>10.1.0.0/16</network>
</value>
<value type="object">
<network_view>default</network_view>
<_ref>network/ZG5zLm5ldHduMi4wLjAvMTYvMA:10.2.0.0%2F16</_ref>
<network>10.2.0.0/16</network>
</value>
</list>
To find networks with comments that contain the word sample in a case-insensitive way:
curl -k1 -u admin:testpw -X GET -HAccept:text/xml \
https://192.168.1.2/wapi/v2.12.3/network -d comment~:=sample \
-d _return_type=xml-pretty
The server returns the network we just modified:
<?xml version="1.0"?>
<list>
<value type="object">
<comment>Sample comment</comment>
<network_view>default</network_view>
<_ref>network/ZG5zLm5ldHdvcmskMTAuMS4wLjAvMTYvMA:10.1.0.0%2F16</_ref>
<network>10.1.0.0/16</network>
</value>
</list>
If there is no match, the server returns an empty list:
curl -k1 -u admin:testpw -X GET -HAccept:text/xml \
https://192.168.1.2/wapi/v2.12.3/network -d comment~:=nomatch \
-d _return_type=xml-pretty
The server returns the following:
<?xml version="1.0"?>
<list>
</list>
To delete a network, send a DELETE request using a reference you have retrieved by searching. For example, to delete the networks we created above, send the following:
curl -k1 -u admin:testpw -X DELETE -HAccept:text/xml \
https://192.168.1.2/wapi/v2.12.3/network/ZG5zLm5ldHdvcmskMLjAvMTYvMA:10.1.0.0%2F16 \
-d _return_type=xml-pretty
The server returns the reference of the object it just deleted, if the deletion was successful:
<?xml version="1.0"?>
<value>network/ZG5zLm5ldHdvcmskMLjAvMTYvMA:10.1.0.0%2F16</value>
To delete the other network, send the following:
curl -k1 -u admin:testpw -X DELETE -HAccept:text/xml \
https://192.168.1.2/wapi/v2.12.3/network/ZG5zLm5ldHdAuMi4wLjAvMTYvMA:10.2.0.0%2F16 \
-d _return_type=xml-pretty
Note that both networks have been removed:
curl -k1 -u admin:testpw -X GET -HAccept:text/xml \
https://192.168.1.2/wapi/v2.12.3/network -d _return_type=xml-pretty
The server returns the following:
<?xml version="1.0"?>
<list>
</list>
To create a host record in a specified zone, first send the following request to create the zone:
curl -k1 -u admin:testpw -H "Content-Type: application/xml" -X POST \
https://192.168.1.2/wapi/v2.12.3/zone_auth -d \
'<?xml version="1.0"?><value type="object"><fqdn>zone.com</fqdn></value>'
Then send the following request to create the host:
curl -k1 -u admin:testpw -H "Content-Type: application/xml" -X POST \
https://192.168.1.2/wapi/v2.12.3/record:host -d \
'<?xml version="1.0"?><value type="object"><name>host.zone.com</name>'\
'<ipv4addrs><list><value type="object"><ipv4addr>10.222.0.12</ipv4addr>'\
'</value></list></ipv4addrs></value>'
Note that it might be necessary to specify the content type explicitly when using the -d option in curl.
To schedule an object creation, use a POST request with the _schedinfo.scheduled_time parameter:
curl -k1 -u admin:testpw -X POST -HContent-Type:text/xml --data-binary \
'<value type="object"><network>10.1.0.0/16</network></value>' \
'https://192.168.1.2/wapi/v2.12.3/network'\
'?_return_type=xml-pretty&_schedinfo.scheduled_time=1367752903'
The server returns a reference of the created scheduled task:
<?xml version="1.0"?>
<value>scheduledtask/b25lLnF1ZXVlZF90YXNrJDA:0/PENDING</value>
To execute a function call, use a POST request with the _function parameter. For example, first create a network:
curl -k1 -u admin:testpw -X POST -HContent-Type:text/xml --data-binary \
'<value type="object"><network>10.2.0.0/16</network></value>' \
https://192.168.1.2/wapi/v2.12.3/network?_return_type=xml-pretty
the server will then return a reference to the network that was just created:
<?xml version="1.0"?>
<value>network/ZG5zLm5ldHdvcmskMTAuMS4wLjAvMTYvMA:10.1.0.0/16/default</value>
now use this reference to retrieve the next three available /24 networks in this network excluding 10.1.1.0/24 and 10.1.3.0/24:
curl -k1 -u admin:testpw -X POST -HContent-Type:text/xml --data-binary \
'<value type="object"><exclude><list><value>10.1.1.0/24</value>'\
'<value>10.1.3.0/24</value></list></exclude><cidr type="int">24</cidr>'\
'<num type="int">3</num></value>' \
'https://192.168.1.2/wapi/v2.12.3/network/ZG5zLm5ldHdvcmskMTAuMS4wLjAvMTYvMA:'\
'10.1.0.0/16/default?_function=next_available_network&_return_type=xml-pretty'
The server returns a list of available networks with the above constraints:
<?xml version="1.0"?>
<value type="object">
<networks> <list>
<value>10.1.0.0/24</value>
<value>10.1.2.0/24</value>
<value>10.1.4.0/24</value>
</list>
</networks></value>
This section includes examples for configuring certificate based authentication. To simplify the examples, self-signed certificate is generated for client certificate signing.
Generate a self-signed certificate and use it as a Certificate Authority (CA) certificate that is treated as a trusted source for signing client certificates *. To do so, run the openssl req command with the -x509 argument.
To generate a private key alongside with a certificate, run the -newkey command with the argument that tells openssl that you need a RSA private key of length 4096. The -nodes (literally “No-DES”) parameter is used to skip passphrase private key protection, as follows:
openssl req -x509 -newkey rsa:4096 -nodes -keyout ca.key.pem \
-out ca.cert.pem -days 365 -subj '/CN=ib-root-ca'
* - however in a real world using real Certificate Authorities is preferred.
Output:
Generating a 4096 bit RSA private key
..........................................................++
..........................................................++
writing new private key to 'ca.key.pem'
-----
The first step in acquiring client certificate is to create a Certificate Signing Request (CSR) that is signed by the Certificate Authority. To generate a CSR, run the openssl req command with the -new argument. Same as for the CA certificate, a client private key is generated using the -newkey option without passphrase protection (-nodes). The CSR validity period is determined by the -days argument and is equal to 365 days. Note that the Canonical Name (CN) in the subject should contain the desired user name, as follows:
openssl req -new -sha256 -newkey rsa:4096 -nodes \
-keyout client.key.pem -days 365 -out client.req.pem \
-subj '/CN=ib-employee'
Output:
Generating a 4096 bit RSA private key
..........................................................++
.................++
writing new private key to 'client.key.pem'
-----
The last step in generating the client certificate is the CSR signing by CA. (In this example, we are using a previously generated CA certificate). To sign the CSR by a CA, run the openssl x509 command with the -req argument and pass the client CSR (client.req.pem), CA Certificate (ca.cert.pem), CA private key (ca.key.pem) and an arbitrary serial number (1209199). To include SAN (Subject Alternative Name) e-mail address use -extfile argument (or explicit configuration file) with subjectAltName set to a desired e-mail address, as follows:
openssl x509 -req -days 365 \
-extfile <(printf "subjectAltName=email:employee@infoblox.com") \
-in client.req.pem -CA ca.cert.pem -CAkey ca.key.pem -set_serial 1209199 \
-out client.cert.pem
Output:
Signature ok
subject=/CN=ib-employee
Getting CA Private Key
To upload the CA certificate, you first initialize the data upload procedure. To initialize the data upload procedure, call the fileop datauploadinit function that returns the URL of the destination file and the token that will be used in the certificate upload operations, as follows:
curl -H "Content-Type:application/json" -k -u admin:infoblox -X POST \
https://127.0.0.1/wapi/v2.12.3/fileop?_function=uploadinit -d '{}'
The server will return URL for direct upload and file token to use in fileop function calls:
{
"token": "eJydUMtOwzAQvO+...",
"url": "https://127.0.0.1/http_direct_file_io/..."
}
Using curl we can upload contents of the CA certificate (ca.cert.pem) to a URL returned from datauploadinit operation:
curl -k1 -u admin:infoblox -F file=@ca.cert.pem \
"https://127.0.0.1/http_direct_file_io/..."
To upload the CA certificate (cacertificate), call the fileop uploadcertificate function with the certificate_usage parameter set to EAP_CA, member set to a desired member hostname, and token set to a token value returned by a fileop datauploadinit function call, as follows:
curl -k1 -u admin:infoblox -X POST -H "Content-Type: application/json" \
https://127.0.0.1/wapi/v2.12.3/fileop?_function=uploadcertificate -d \
'{
"certificate_usage": "EAP_CA",
"member": "infoblox.localdomain",
"token": "eJydUMtOwzAQvO+..."
}'
The server will return empty dictionary if operation succeeds:
{}
Run the GET operation to verify that the cacertificate is now present in the database, as follows:
curl -k1 -u admin:infoblox -X GET https://127.0.0.1/wapi/v2.12.3/cacertificate
The server will return cacertificate object:
[
{
"_ref": "cacertificate/b25lLmVhcF9j...",
"distinguished_name": "CN=\"ib-root-ca\"",
"issuer": "CN=\"ib-root-ca\"",
"serial": "9f770b9a53359c6b",
"valid_not_after": 1528955885,
"valid_not_before": 1497419885
}
]
Create adminuser object with name matching the client.cert.pem SAN e-mail, as follows:
curl -k1 -u admin:infoblox -H "Content-Type: application/json" -X POST \
https://127.0.0.1/wapi/v2.12.3/adminuser -d \
'{
"admin_groups": ["admin-group"],
"name": "employee@infoblox.com",
"password": "infoblox"
}'
The server will return a reference to the adminuser that was just created:
"adminuser/b25lLmFkbWluJGVtcGxveWVlQGluZm9ibG94LmNvbQ:employee%40infoblox.com"
Create certificate:authservice object with OCSP disabled (for simplicity), and the CA certificate set to a previously installed CA certificate (ca.cert.pem). To drop password authentication, enable_password_request is set to “false”. The AUTO_MATCH match type forces NIOS to extract the username from the certificate and searches for it in effective authorization policies based on the configured match policies. The auto_populate_login setting specifies the match policy, that is, match by e-mail address in the SAN, as follows:
curl -k1 -u admin:infoblox -H "Content-Type: application/json" -X POST \
https://127.0.0.1/wapi/v2.12.3/certificate:authservice -d \
'{
"name": "cert-login",
"ocsp_check": "DISABLED",
"ca_certificates": [
"cacertificate/b25lLmVhcF9j..."
],
"enable_password_request": false,
"client_cert_subject": "",
"trust_model": "DIRECT",
"user_match_type": "AUTO_MATCH",
"auto_populate_login": "SAN_EMAIL"
}'
The server will return a reference to the certificate:authservice object that was just created:
"certificate:authservice/b25lLm9jc3BfYXV0aF9zZXJ2aWNlJGNlcnQtbG9naW4:cert-login"
You need to include the Certificate Authentication Policy in the list of Grid authentication policies. To do so, first perform the GET operation on the authpolicy object object, as follows:
curl -k1 -u admin:infoblox -X GET \
https://127.0.0.1/wapi/v2.12.3/authpolicy?_return_fields=auth_services
The server will return an authpolicy object:
[
{
"_ref": "authpolicy/b25lLnJlbW90ZV9hZG1pbl9wb2xpY3kkMA:authpolicy",
"auth_services": [
"localuser:authservice/Li5sb2NhbF91c2VyX2F1dGhfc2VydmljZSQw:Local%20Admin"
]
}
]
Then, update the authpolicy object. Note that the CAS reference should precede the Local User Authentication Service to avoid server performing password authentication, as follows:
curl -k1 -u admin:infoblox -H "Content-Type: application/json" -X PUT \
https://127.0.0.1/wapi/v2.12.3/authpolicy/b25lLnJlbW90ZV9hZG1pbl9wb2xpY3kkMA:authpolicy -d \
'{
"auth_services": [
"certificate:authservice/b25lLm9jc3BfYXV0aF9zZXJ2aWNlJGNlcnQtbG9naW4:cert-login",
"localuser:authservice/Li5sb2NhbF91c2VyX2F1dGhfc2VydmljZSQw:Local%20Admin"
]
}'
The server will return reference to the authpolicy object if the operation succeeds:
"authpolicy/b25lLnJlbW90ZV9hZG1pbl9wb2xpY3kkMA:authpolicy"
Perform the GET operation on any object (admingroup in our example) using the client key and client certificate, as follows:
curl -k -v -s --key client.key.pem --cert client.cert.pem \
-X GET https://127.0.0.1/wapi/v2.12.3/admingroup
Verbose (-v) output of the curl command is included to verify the TLS connection, as follows:
* Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 443 (#0)
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
* CAfile: /etc/pki/tls/certs/ca-bundle.crt
CApath: none
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / DHE-RSA-AES128-GCM-SHA256
* ALPN, server did not agree to a protocol
* Server certificate:
* subject: C=US; ST=California; L=Sunnyvale; O=Infoblox; OU=Engineering; CN=www.infoblox.com
* start date: 2017-07-13 08:09:23 GMT
* expire date: 2018-07-13 08:09:23 GMT
* issuer: C=US; ST=California; L=Sunnyvale; O=Infoblox; OU=Engineering; CN=www.infoblox.com
* SSL certificate verify result: self signed certificate (18), continuing anyway.
> GET /wapi/v2.12.3/admingroup HTTP/1.1
> Host: 127.0.0.1
> User-Agent: curl/7.43.0
> Accept: */*
>
* TLSv1.2 (IN), TLS handshake, Hello request (0):
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS handshake, CERT verify (15):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
< HTTP/1.1 200 OK
< Date: Thu, 13 Jul 2017 08:25:10 GMT
< WWW-Authenticate: Basic realm="InfoBlox ONE Platform"
< Cache-Control: no-cache, no-store
< Pragma: no-cache
< Content-Type: application/json
< set-cookie: ibapauth="ip=127.0.0.1,client=API,group=admin-group,ctime=1499934313,timeout=600,mtime=1499934313,su=1,auth=LOCAL,user=employee@infoblox.com,X8E/BVuFP95+srDuipWO5n5xqThqK5XA2F4"; httponly; Path=/; secure
< Transfer-Encoding: chunked
<
[
{
"_ref": "admingroup/b25lLmFkbWluX2dyb3VwJC5zcGx1bmstcmVwb3J0aW5nLWdyb3Vw:splunk-reporting-group",
"name": "splunk-reporting-group"
},
{
"_ref": "admingroup/b25lLmFkbWluX2dyb3VwJC5hZG1pbi1ncm91cA:admin-group",
"name": "admin-group"
},
{
"_ref": "admingroup/b25lLmFkbWluX2dyb3VwJC5jbG91ZC1hcGktb25seQ:cloud-api-only",
"comment": "Admins allowed to perform API request on Cloud API",
"name": "cloud-api-only"
}
]
* Connection #0 to host 127.0.0.1 left intact
Note that you can incorporate the client key in the client certificate (simply concatenate the certificate and key files), and then use only the –cert option.