Actual code example of using KACE API through JavaScript?
The K1000 7.0 Reference Guide certainly is useful for understanding the capabilities of the KACE API, but it doesn't have any code samples that would indicate how the information could be used in a browser with JavaScript.
I've looked through all the usual places for code samples, including ITNinja, StackOverflow, and GitHub, and couldn't find anything. The closest thing I could find were PowerShell scripts meant for WSAPI.
For starters, some simple code on how to authorize with POST and XMLHttpRequest(), and receive some kind of status or response text in return, would be extremely useful. Additional code for querying assets by location would be excellent, if at all possible. But really, I'd be very thankful for any guidance I can get on this.
Just to get the ball rolling, this is what I have so far for a POST authentication request. The documentation does not explain what headers are necessary for the initial authentication specifically. For example, the documentation mentions a token is returned during authentication in a response header named x-dell-csrf-token, but unsure how to write a request header for authentication when I haven't yet received this token. For what it's worth, my dev console tells me the Access-Control-Allow-Headers from the response headers from the server are "x-dell-auth-timestamp, x-dell-auth-key, x-dell-auth-signature, accept, origin, content-type," yet mentions no csrf header.
It's also unclear which password to use (is it the user's password or the API password I specified when I enabled "inventory API access" under /system?) However, when I do use my username and password with the following script, I get a 403 "Forbidden" response, despite the fact I'm an admin. Our KACE version is 7.0.121306.
var url = "https://our.k1000/ams/shared/api/security/login"; var myAuth = { "password" : "adminUserPassword", "userName" : "adminUser", "organizationName" : "Default" }; var myJSON = JSON.stringify(myAuth); sendText(myJSON); function sendText(auth) { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { console.log("Status 200!"); console.log(this.responseText); document.getElementById("httpResult").innerHTML = xhr.responseText; } }; xhr.open('POST', url, true); xhr.setRequestHeader("Accept", "text/xml"); xhr.setRequestHeader("Content-type", "text/xml"); xhr.setRequestHeader("x-dell-api-version", "1"); xhr.send(auth);}
0 Comments
[ + ] Show comments
Answers (1)
Please log in to answer
Posted by:
KevinG
7 years ago
/* This Sample Software is provided for illustrative purposes only.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT SUPPORT OR WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT.
// IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR
// OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// A simple C# console application to illustrative the GET /api/inventory/machines/
// No parsing of the json response is done in this example.
// This is a functional console application.
// Usage: Protocol (http or https), K1 Hostname or IP, UserID, Password, Organization Name (If not supplied Default will be used)
// Command line usage example.
// K1APIConsoleApplication.exe http k1hostname admin admin_pw Default
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace K1APIConsoleApplication
{
class Program
{
static string authToken;
static string hostURL;
static CookieContainer savedCookies = new CookieContainer();
static string userAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0";
static void Main(string[] args)
{
string org;
if(args.Length < 4)
{
string msg = "Usage: Protocol (http or https), K1 Hostname or IP, UserID, Password, Organization Name (If not supplied Default will be used)";
Console.WriteLine(msg);
return;
}
if(args.Length == 4)
{
org = "Default";
}
else
{
org = args[4];
}
if(!Login(args[0], args[1], args[2], args[3], args[4]))
{
Console.WriteLine("Login failed. Please check your input perameters");
return;
}
hostURL = args[0] + "://" + args[1] + "/api/inventory/machines/";
MakeRequest(authToken, "GET", hostURL);
}
static private bool Login(string protocol, string host, string userID, string pw, string orgname )
{
bool bStatus = false;
string hostURL = protocol + "://" + host + "/ams/shared/api/security/login";
// ignore ssl certificate
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
CookieContainer cookies = new CookieContainer();
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(hostURL);
request.Accept = "application/json";
request.ContentType = "application/json";
request.Method = "POST";
request.UserAgent = userAgent;
request.CookieContainer = cookies;
request.KeepAlive = false;
request.Headers.Add("x-dell-api-version: 1");
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
string json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(new
{
userName = userID,
password = pw,
organizationName = orgname
});
streamWriter.Write(json);
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
response.Cookies = request.CookieContainer.GetCookies(request.RequestUri);
cookies.Add(response.Cookies);
savedCookies = cookies;
authToken = response.GetResponseHeader("x-dell-csrf-token");
if (authToken.Length != 0)
{
bStatus = true;
}
}
catch (Exception e)
{
Console.WriteLine("Error in AuthToken process: " + e.ToString());
}
return bStatus;
}
static private bool MakeRequest(string token, string method, string url)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(url));
request.Accept = "application/json";
request.ContentType = "application/json";
request.Method = method;
request.UserAgent = userAgent;
request.CookieContainer = savedCookies;
request.KeepAlive = false;
request.Headers.Add("x-dell-api-version", "1");
request.Headers.Add("x-dell-csrf-token", token);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode != HttpStatusCode.OK)
{
throw new Exception(String.Format(
"Server error (HTTP {0}: {1}).",
response.StatusCode,
response.StatusDescription));
}
// Display the status.
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
// Get the stream containing content returned by the server.
Stream dataStream = response.GetResponseStream();
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader(dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd();
// Display the content.
Console.WriteLine(responseFromServer);
// Clean up the streams.
reader.Close();
dataStream.Close();
response.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
return true;
}
}
}
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT SUPPORT OR WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT.
// IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR
// OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// A simple C# console application to illustrative the GET /api/inventory/machines/
// No parsing of the json response is done in this example.
// This is a functional console application.
// Usage: Protocol (http or https), K1 Hostname or IP, UserID, Password, Organization Name (If not supplied Default will be used)
// Command line usage example.
// K1APIConsoleApplication.exe http k1hostname admin admin_pw Default
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace K1APIConsoleApplication
{
class Program
{
static string authToken;
static string hostURL;
static CookieContainer savedCookies = new CookieContainer();
static string userAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0";
static void Main(string[] args)
{
string org;
if(args.Length < 4)
{
string msg = "Usage: Protocol (http or https), K1 Hostname or IP, UserID, Password, Organization Name (If not supplied Default will be used)";
Console.WriteLine(msg);
return;
}
if(args.Length == 4)
{
org = "Default";
}
else
{
org = args[4];
}
if(!Login(args[0], args[1], args[2], args[3], args[4]))
{
Console.WriteLine("Login failed. Please check your input perameters");
return;
}
hostURL = args[0] + "://" + args[1] + "/api/inventory/machines/";
MakeRequest(authToken, "GET", hostURL);
}
static private bool Login(string protocol, string host, string userID, string pw, string orgname )
{
bool bStatus = false;
string hostURL = protocol + "://" + host + "/ams/shared/api/security/login";
// ignore ssl certificate
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
CookieContainer cookies = new CookieContainer();
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(hostURL);
request.Accept = "application/json";
request.ContentType = "application/json";
request.Method = "POST";
request.UserAgent = userAgent;
request.CookieContainer = cookies;
request.KeepAlive = false;
request.Headers.Add("x-dell-api-version: 1");
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
string json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(new
{
userName = userID,
password = pw,
organizationName = orgname
});
streamWriter.Write(json);
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
response.Cookies = request.CookieContainer.GetCookies(request.RequestUri);
cookies.Add(response.Cookies);
savedCookies = cookies;
authToken = response.GetResponseHeader("x-dell-csrf-token");
if (authToken.Length != 0)
{
bStatus = true;
}
}
catch (Exception e)
{
Console.WriteLine("Error in AuthToken process: " + e.ToString());
}
return bStatus;
}
static private bool MakeRequest(string token, string method, string url)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(url));
request.Accept = "application/json";
request.ContentType = "application/json";
request.Method = method;
request.UserAgent = userAgent;
request.CookieContainer = savedCookies;
request.KeepAlive = false;
request.Headers.Add("x-dell-api-version", "1");
request.Headers.Add("x-dell-csrf-token", token);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode != HttpStatusCode.OK)
{
throw new Exception(String.Format(
"Server error (HTTP {0}: {1}).",
response.StatusCode,
response.StatusDescription));
}
// Display the status.
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
// Get the stream containing content returned by the server.
Stream dataStream = response.GetResponseStream();
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader(dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd();
// Display the content.
Console.WriteLine(responseFromServer);
// Clean up the streams.
reader.Close();
dataStream.Close();
response.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
return true;
}
}
}
Comments:
-
Which account/pw do I use? I set the API password, and have tried it with user "admin" but got Login fail. I tried with my own personal account and the default admin account and the respective passwords, but this also gives 400 Bad Request and Login Failed - JasonEgg 7 years ago
-
Here is the above as is code complied into a C# console application and it's output using the K1000 admin login. Since this is just an example no parsing on the JSON was done. The raw data is displayed to screen.
....\K1APIConsoleApplication\bin\Release>K1APIConsoleApplication.exe http kbox70 admin AdminPW Default
OK
{"Count":1,"Warnings":[],"Machines":[{"Id":"1","Modified":"2017-03-06 13:16:55","Created":"2017-02-21 20:28:38","User":"KevinG","Name":"KevinG-PC64","Ip":"192.168.1.148","Os_name":"Microsoft Windows 10 Pro x64","Os_number":"10.0.14393","Last_inventory":"2017-03-06 13:16:28","Ram Total":"16384 Bytes","Ram_used":"6582.7","Ram_max":"32768","Bios_identification_code":"","Sound_devices":"NVIDIA High Definition Audio\nRealtek High Definition Audio","Cdrom_devices":"PLDS DVD+-RW DH-16ACS","Video_controllers":"NVIDIA Quadro 2000:1024 MB","Monitor":"Dell U2410(Digital)","Registry_size":"343","Registry_max_size":"4095","Pagefile_size":"46","Pagefile_max_size":"46"}]} - KevinG 7 years ago
-
I was able to build and run KevinG's C# code, as long as I selected the .NET Framework 4 when creating the project in Visual Studio, and added using System.Web.Script.Serialization.
This helped me confirm that I can log into the API just fine with my own credentials. However, this didn't put me much closer to creating a JavaScript solution to use the API, as I still get a 403 response when using the same login credentials.
In addition to the 403 response, I get this console message in Chrome:
"XMLHttpRequest cannot load https://[our k1000]/ams/shared/api/security/login. Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://localhost' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute."
Part of the issue may be that my script, which is served via localhost on my machine (using WAMP in this case), is making POST requests to K1000, which naturally resides on a different server. I'm no security expert and this still is all new to me, but some Googling shows that this practice (Cross-Origin Resource Sharing, or CORS) is generally frowned upon.
Still investigating options. - schroccc 7 years ago-
Hello, did you handle the problem? I am also getting 403 response. - altank52 7 years ago
-
You're right. The KACE API doens't allow cross-site requests.
I bypassed this issue by using CURL via PHP:
###### JS [inline or file] ######
[code]
<script>
var url = 'kace.php';
var xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.send();
xhr.onreadystatechange = function()
{
if (this.readyState == 4 && this.status == 200)
{
console.debug(this);
}
};
</script>
[/code]
###### PHP [kace.php] ######
[code]
<?php
$data = array("password" => 'myPassword', "userName" => "myUsername");
$data_string = json_encode($data);
$ch = curl_init('myKace/ams/shared/api/security/login');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/xml','Content-Type: application/json','x-dell-api-version: 1'));
$result = curl_exec($ch);
curl_close($ch);
?>
[/code]
Further benfit: The user credentials stored in plain text in myAuth are hidden. - dows 6 years ago-
hey dows, could you elaborate a bit more on your solution?
I seem to be getting a 405 error (method not allowed) when I attempt to do this.
I'm using http-server just serving these files statically.
Thanks! - kblippert 6 years ago
-
Tried the above C# code (added System.Web.Extensions in order to gain access to Serialization) as well, but like JasonEgg, I'm also getting consistent 400 (Bad Request) issues.
We have our system installed locally, and I'm able to get the list of machines using Postman. With Javascript and C# I haven't had any luck yet - kblippert 6 years ago