Interface with Untangle firewall

  • Untangle NGWF is a router / firewall with an API (JSON RPC over HTTP).
  • The documentation for this API is here.
  • I would like to build a quick and dirty flow to get active DHCP leases

Can someone help me get started with authentication?

From the API doc:
Each request your application sends must include an authentication token in the JSON object. To get a token, your application must send an administrative username and password via HTTP POST method to your server. If the authentication succeeds, the server responds with a JSON object containing an authentication token.

So do I need to set up an HTTP Auth node?

Or should I just use an HTTP request node, and what type of authentication should I use (basic / digest / bearer)?

If someone could point me in the right direction that would be most appreciated - I can definitely do all the work to implement this myself just need a little help to get started.

Thanks

Hello Mat,

Start by doing an initial http-request for the login
We use a Function node to prepare the headers and body of the POST request and if its succesful with a token we proceed with another request for the actual data.

but lets see what you get with this

[{"id":"c3b10b18e3287446","type":"inject","z":"54efb553244c241f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":180,"y":1260,"wires":[["963d0c9becbb9200"]]},{"id":"dd8e8ceb7aebe7ae","type":"http request","z":"54efb553244c241f","name":"","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"x":470,"y":1260,"wires":[["53a5168189f9717c"]]},{"id":"963d0c9becbb9200","type":"function","z":"54efb553244c241f","name":"initial req","func":"let username = \"your-username\"\nlet password = \"your-password\"\n\nmsg.url = \"https://10.11.12.223/auth/login\"\n\nmsg.method =  \"POST\"\n\nmsg.headers = {\n   'Content-Type': 'application/x-www-form-urlencoded'\n}\n\nmsg.payload = {\n    \"username\": username,\n    \"password\" : password\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":320,"y":1260,"wires":[["dd8e8ceb7aebe7ae"]]},{"id":"53a5168189f9717c","type":"debug","z":"54efb553244c241f","name":"1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":630,"y":1260,"wires":[]}]

ps. change the function to match your login details and ip

1 Like

Thanks. That works, I get a message object back with lots of data including msg.statusCode: 200, which sounds like it succeeded.

Do I need to feed the cookie received back into a new request? Or can I just make a new request? I'm guessing I do the same, but change the URL to https://10.11.12.223/admin/JSON-RPC. How do I achieve sending the raw body data as per:

curl --location --request POST 'https://10.11.12.223/admin/JSON-RPC' \
--data-raw '{
	"id":297,
	"nonce":ec61pq84h9ov52ev9nurmldr95,
	"method":".obj#{{configManagerID}}.getActiveDhcpLeases",
	"params":[]
}'

yes .. you chain on another http-request and according to the manual this is to actually get the nonce token.
so its 2 requests to get the token and then a 3rd one for the actual data

[{"id":"c3b10b18e3287446","type":"inject","z":"54efb553244c241f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":200,"y":1640,"wires":[["963d0c9becbb9200"]]},{"id":"dd8e8ceb7aebe7ae","type":"http request","z":"54efb553244c241f","name":"","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"x":510,"y":1640,"wires":[["6551e8bf49c82aff","53a5168189f9717c"]]},{"id":"9ad658b016e11dfd","type":"debug","z":"54efb553244c241f","name":"2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1070,"y":1640,"wires":[]},{"id":"963d0c9becbb9200","type":"function","z":"54efb553244c241f","name":"session req","func":"let username = \"your-username\"\nlet password = \"your-password\"\n\nmsg.url = \"https://10.11.12.223/auth/login\"\n\nmsg.method = \"POST\"\n\nmsg.headers = {\n   'Content-Type': 'application/x-www-form-urlencoded'\n}\n\nmsg.payload = {\n    \"username\": username,\n    \"password\" : password\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":350,"y":1640,"wires":[["dd8e8ceb7aebe7ae"]]},{"id":"3463d537603ad2bf","type":"http request","z":"54efb553244c241f","name":"","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"x":870,"y":1640,"wires":[["9ad658b016e11dfd"]]},{"id":"53a5168189f9717c","type":"debug","z":"54efb553244c241f","name":"1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":650,"y":1560,"wires":[]},{"id":"6551e8bf49c82aff","type":"function","z":"54efb553244c241f","name":"token req","func":"\nmsg.url = \"https://10.11.12.223/admin/JSON-RPC\"\n\nmsg.method = \"POST\"\n\n// msg.cookies = msg.responseCookies;\n\nmsg.headers = {\n   'Content-Type': 'application/json'\n}\n\nmsg.payload = {\n   \"id\": 297,  // ? \n   \"nonce\": \"\",\n   \"method\": \"system.getNonce\",\n   \"params\": []\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":680,"y":1640,"wires":[["3463d537603ad2bf"]]}]

[EDIT]

I didnt understand from the manual, from where that id comes from though
did you get one from the first request ?

this is sent in msg.payload

There is no id from the first request. However when I post your code for the second request, I get this back (which contains that id):

{"result":"m6eaa0fafj783d3b2ms6fu481r","id":297}"

Is the result the "nonce" that I then need to use to go and make a third request to actually get data? Or have I misunderstood?

EDIT: I have just seen this:
request_id The id of each request. This value should increment by one for each new request.

1 Like

exactly ..

msg.payload = {
    "id": 297,
    "nonce": msg.payload.result,  // "ec61pq84h9ov52ev9nurmldr95"
    "method": ".obj#{{configManagerID}}.getActiveDhcpLeases",
    "params": []
}

but we may be missing yet another piece of information
what is that configManagerID ? ( link )
i think you gonna need that too :wink:

Yes, so I have no idea but it seems this can be retrieved. So I have made a third request to get the configManagerID and get this response:

payload: "{"result":{"javaClass":"com.untangle.uvm.ConfigManagerImpl","JSONRPCType":"CallableReference","objectID":334228777},"id":297}"

Hopefully this objectID is the configManagerID?

But I have tried to feed this in to a 4th POST request like below, but I get a status code 500 back:

msg.url = "http://10.1.1.1/admin/JSON-RPC"
msg.method = "POST"
msg.headers = { 'Content-Type': 'application/json' }

msg.payload = {
   "id": 297,
   "nonce": "m6eaa0fafj783d3b2ms6fu481r",
   "method":".obj#{{334228777}}.getActiveDhcpLeases",
   "params":[]
}

(that nonce is the one I got back from the second request! I hard coded it temporarily...)

hmm .. maybe the curly brackets are not needed and they are just there in the example to denote that
that part needs to be replaced with the configManagerID?

"method":".obj#334228777.getActiveDhcpLeases",

Okay you are an excellent teacher (I'm guessing from your style of response that you are an actual teacher? :slight_smile: If not you really should be!)

That worked a treat.

So, a couple more questions... if you don't mind?

  1. Back to the id. The doc says "this value should increment by one for each new request". I have not done this, but it seems to work perfectly fine. Should I be incrementing it for each of these multiple requests (i.e. session req, token req, configManagerID req, data req)?

  2. Do I need to set up that session just once, forever? Or once for each request I make?

  3. Is it the best way to just add a JSON node on the output of each HTTP request node, to convert the msg.payload into objects, so they can be used in each subsequent request?

Thanks so much for your very helpful and subtle helping!

1 Like

hehe .. not at all .. my main job is video editing and part of a camera crew for weddings and christenings :wink:

im new to this stuff also .. learning along

  1. the id .. good question .. i have no id-ea :wink:

  2. sessions from what i know expire at some point .. depending on the server settings .. in this case your firewall device ? so avoid having anything hardcoded cause its going to change.

  3. json node is not needed because if the reply is json the http-request nodes have the option to parse it into JS object if you choose that setting

image

Haha, that wasn't obvious!

Thanks for your help, I am now able to query for all IP address on the network and display them in a little dashboard control panel!

Every time you make a request the server will respond with an id that should increment by 1, I think this is so you can check that no other request have been slipped in, on your session. So you do not have to increment, but you can use this as a security check if you wish.

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.