Qualys API client examples

Document created by Parag Baxi on Oct 3, 2013Last modified by Jeff Leggett on Sep 3, 2019
Version 58Show Document
  • View in full screen mode

Note: This is unsupported.

 


Purpose

This is a community driven document to demonstrate examples of how to connect to the Qualys API using various platforms.

 

C#, RestSharp

The open source library assists in making calls to all API versions:

http://restsharp.org/

 

API v1

Sample code:

 


using System;

using System.Collections.Generic;

using System.Xml;

using System.Xml.Linq;

using System.Linq;

using System.Text;

using RestSharp;



// Set up REST client to connect to US Platform 1.

var client = new RestClient("
https://qualysapi.qualys.com
");


// Set up credentials.

client.Authenticator = new HttpBasicAuthenticator("username", "password");

//

// GET request

// See QualysGuard version.

//

var request = new RestRequest("msp/about.php");

IRestResponse response = client.Execute(request);

// Response contains the XML file.


Console.WriteLine (response.Content);


//

// POST request.

// Download raw scan results of scan/1234567890.12345.

//

// This method does not work!

// var request_post = new RestRequest ("msp/scan_report.php", Method.POST);

// request_post.AddParameter("ref", "scan/1390453521.15910");

//

// This method does work.

var endpoint = String.Format("msp/scan_report.php?{0}={1}",

"ref", "scan/1234567890.12345");

var request_post = new RestRequest (endpoint, Method.POST);

response = client.Execute(request_post);

// Print out headers to see remaining calls against API limits.

foreach (var header in response.Headers){

Console.WriteLine(header);

}

// Print scan results.

Console.WriteLine(response.Content)





 

API v2

Sample code:

 


using System;

using System.Collections.Generic;

using System.Xml;

using System.Xml.Linq;

using System.Linq;

using System.Text;

using RestSharp;



// Set up REST client to connect to US Platform 1.

var client = new RestClient("
https://qualysapi.qualys.com
");


// Set up credentials.

client.Authenticator = new HttpBasicAuthenticator("username", "password");

//

// v2 GET request.


// Print out scans that ended in error.

//

var request = new RestRequest("api/2.0/fo/scan/", Method.GET);

// Add header, reqiured for v2 API.

request.AddHeader("X-Requested-With", "RestSharp");

request.AddParameter("action", "list");

response = client.Execute(request);

var xml_text = response.Content;

// Let's see where we are on our API limit. Do we need to throttle our script?

foreach (var header in response.Headers){

Console.WriteLine(header);

}

Console.WriteLine ("\n(Press enter to continue.)");

pause_me = Console.ReadLine();

//

// Parse the XML to make it actionable.

//

// Load XML string.

XDocument xdoc = XDocument.Parse(xml_text);

// Parse XML for each scan.

var scans = from scan in xdoc.Descendants ("SCAN")

select new {

scan_ref = (string)scan.Element ("REF"),

title = (string)scan.Element ("TITLE"),

status = (string)scan.Element("STATUS").Element("STATE")

};





// Print out each scan reference, title, and status.

// Join the data into a string.

StringBuilder result = new StringBuilder();

//Loop through results

foreach (var scan in scans)

{

result.AppendLine(scan.scan_ref + " " + scan.title + " " + scan.status);

}

Console.WriteLine(result.ToString());





// Print only scans that ended in error.

StringBuilder error_result = new StringBuilder();

//Loop through results

foreach (var scan in scans)

{

if (scan.status == "Error") {

error_result.AppendLine (scan.scan_ref + " " + scan.title + " " + scan.status);

}

}

Console.WriteLine(error_result.ToString());





 

Go Language Example

AM API

Go lends itself very well to Qualys' REST based API's - it includes builtin library support for HTTP and XML parsing.  Further it's built in concurrency support will make multi threaded apps easy to use as well.  Here's an initial example of using Go with the Asset Management API's

package main

import (
"encoding/base64"
"encoding/xml"
"flag"
"fmt"
"io/ioutil"
"net/http"
)

func Get_Credential_Hash(User string, Password string) string {

return base64.StdEncoding.EncodeToString([]byte(User + ":" + Password))
}

func Get_Command_Line_Args() (string, string, string) {
/* Get cmd line paramters */
UserPtr := flag.String("User", "BOGUS", "Qualys Account User Name")
PasswordPtr := flag.String("Password", "BOGUS", "Qualys Account password")
APIURLPtr := flag.String("API URL", "https://qualysapi.qualys.com/", "Qualys API endpoint")
flag.Parse()
return *UserPtr, *PasswordPtr, *APIURLPtr
}

func QAPI_Hostasset_Count() int {

type Hostasset_Count struct {
ResponseCode string `xml:"responseCode"`
Count int `xml:"count"`
}
User, Password, APIURL := Get_Command_Line_Args()
encodedcred := Get_Credential_Hash(User, Password)

url := APIURL + "qps/rest/2.0/count/am/hostasset/"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-requested-with", "GOLANG")
req.Header.Add("authorization", "Basic "+encodedcred)
/* req.Header.Add() */
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
/* fmt.Println(res)
fmt.Println(string(body)) */
var c Hostasset_Count
xml.Unmarshal(body, &c)
if c.ResponseCode == "SUCCESS" {
return c.Count
} else {
return -1
}
}

func main() {

var numassets int
numassets = QAPI_Hostasset_Count()
if numassets >= 0 {
fmt.Println("Numnber of Assets:", numassets)
}
}
 

WAS API

Sample code: Create Web App in GO Lang - simple example to read a CSV of the form "WebAppName,WebAppURL" and create the Web App in WAS.

 

package main

import (
"bufio"
"bytes"
"encoding/base64"
"encoding/csv"
// "encoding/xml"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
)

func Get_Credential_Hash(User string, Password string) string {

return base64.StdEncoding.EncodeToString([]byte(User + ":" + Password))
}

func Usage() {
fmt.Println("usage: createwebapps [-user -password -APIURL -filename]")
fmt.Println(" -filename is optional, if not used, default will be webappnames.txt in local directory. This file must have URL and names of 1 per line separated by comma")
fmt.Println("Make sure the APIURL includes the https:// at the beginning or you will get run time error ")
}

func Get_Command_Line_Args() (string, string, string, string) {
/* Get cmd line paramters */
UserPtr := flag.String("user", "XXXX", "Qualys Account User Name")
PasswordPtr := flag.String("password", "XXXXXXX", "Qualys Account password")
APIURLPtr := flag.String("APIURL", "https://qualysapi.qualys.com/", "Qualys API endpoint")
CSVName := flag.String("filename", "webapps.csv", "WebApp Names File")
flag.Parse()
return *UserPtr, *PasswordPtr, *APIURLPtr, *CSVName
}

func Create_WebApp(EncodedCred string, APIURL string, WASName string, WASURL string) string {

resource := "qps/rest/3.0/create/was/webapp"
SRXML := "<ServiceRequest><data><WebApp><name>" + WASName + "</name><url>" + WASURL + "</url></WebApp></data></ServiceRequest>"
fmt.Println(APIURL + resource + ":" + SRXML)
//client := &http.Client{}

req, _ := http.NewRequest("POST", APIURL+resource, bytes.NewBuffer([]byte(SRXML)))
req.Header.Add("X-requested-With", "GOLANG")
req.Header.Add("authorization", "Basic "+EncodedCred)
req.Header.Add("Content-Type", "text/xml")
response, _ := http.DefaultClient.Do(req)

respStatus := response.Status
fmt.Println(respStatus)
defer response.Body.Close()

body, _ := ioutil.ReadAll(response.Body)

//XMLRET := xml.Unmarshal(body)
if respStatus == "200 OK" {
f, err := os.OpenFile("webapps_XMLOUTPUT.xml", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
}
if _, err := f.Write(body); err != nil {
log.Fatal(err)
}
if err := f.Close(); err != nil {
log.Fatal(err)
}
} else {
fmt.Println(response, body)
return "FAILED"

}
return "OK"
}

func main() {
User, Password, APIURL, CSVFileName := Get_Command_Line_Args()
EncodedCred := Get_Credential_Hash(User, Password)

/* Opent the input file for reading */
file, err := os.Open(CSVFileName)
if err != nil {
log.Fatal(err)
return
}
defer file.Close()
/* main loop of work - get a line from input file and process it */
reader := csv.NewReader(bufio.NewReader(file))
for {
line, error := reader.Read()
if error == io.EOF {
break
} else if error != nil {
log.Fatal(error)
}
fmt.Println("APIURL: " + APIURL)
fmt.Println("WebAppName: " + line[0])
fmt.Println("WebAppURL: " + line[1])
CallStatus := Create_WebApp(EncodedCred, APIURL, line[0], line[1])
fmt.Println(CallStatus)
//if CallStatus == "FAILED" {
// break
//}
}
}

Groovy, httpbuilder's RESTClient

This open source package assists in making calls to all API versions.

 

API v1

Sample code:

 


import groovyx.net.http.RESTClient

// Set up REST client.

def qgc = new RESTClient('
https://qualysapi.qualys.com/msp/
')


// Set headers.

qgc.defaultRequestHeaders.'X-Requested-With' = 'Groovy'

qgc.auth.basic 'username', 'password'

// Optional: Force response handler to pass raw text to pass onto a parser like SAX.

//qgc.parser.'application/xml' = qgc.parser.'text/plain'

// Call API via GET.

def response = qgc.get(path:'about.php')

// Store body of data separately.

def xml = response.getData()





 

API v2

Sample code:

 


TODO





 


AM API

Sample code:

 


TODO







 

Perl, LWP

The open source library assists in making calls to all API versions.

API v1 and v2

Sample code:

 


use LWP;                # retrieving data via HTTPS



# Set base url to US Pod 1.

my $APIURL = "qualysguard.qualys.com"



# retrieves Scan_history for the account and saves to file

my $url = "
https://$APIURL/api/2.0/fo/asset/host/?action=list&details=All&ag_titles=All+Compliance&no_vm_scan_since=2013-12-07
";




# Set creds.

my $username = "username";

my $passwd = "password";



# Set up request headers.

my $browser = LWP::UserAgent->new;

$browser->default_headers->header('X-Requested-With' => 'Sample');

$browser->agent("libwww - script");



# Send GET request.

my $request = HTTP::Request->new( GET=>$url );

$request->authorization_basic($username, $passwd);

my $response = $browser->request($request);

my $content = $response->content;



## Save to file.

open( XMLOUT, ">output.xml" );

print XMLOUT $content;

close( XMLOUT );





 

WAS API

Sample code:

 


TODO





 

AM API

Sample code:

 


TODO





 

PHP 5+, SimpleQAPI class

This community published package by Peter Stiehl assists in making calls to the API:

Simple PHP Qualys API class

API v1 and v2

Sample code:

 


$params = array('qlogin' => 'Qualys login',

'connectTimeout' => 10',

'timeout' => 59',

'qpassword' => 'Qualys Password',

'qdomain' => 'Qualys domain without HTTP', // For example 'qualysapi.qualys.com'

'plogin' => 'Proxy login',

'ppassword' => 'Proxy password',

'headers' => array('X-Requested-With: SimpleQAPI'),




'purl' => '
http://proxy.to.use
',




'pport' => 'port number');

$SimpleQAPI = new SimpleQAPI($params);

// You have to use the login() method to be able to launch the view_xxx_list() methods

// For each request the answer is stored in $SimpleQAPI->resp

$SimpleQAPI->login();

// This should print : 201x-xx-xxTxx:xx:xxZ Logged in

echo $SimpleQAPI->resp;

$SimpleQAPI->logout();





 

WAS API

Sample code:

 


TODO





 

PHP 4+, curl

Initialize a cURL session from PHP: http://www.php.net/manual/en/function.curl-exec.php

API v1 and v2

Sample code:

 


<?php

$username=ENTER_YOUR_USERNAME;

$password=ENTER_YOUR_PASSWORD;

$ch = curl_init();

$cookieJar = dirname(__FILE__) . '/cookie.txt';

curl_setopt($ch, CURLOPT_URL, "
https://qualysapi.qualys.com/api/2.0/fo/session/
");


curl_setopt($ch, CURLOPT_HTTPHEADER, array('X-Requested-With: PHP curl
'));

curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieJar);

curl_setopt($ch, CURLOPT_POST, 1);

curl_setopt($ch, CURLOPT_POSTFIELDS, "action=login&username=$username&password=$password");

$result = curl_exec ($ch) or die(curl_error($ch));

echo $result;

echo curl_error($ch);

$ch = curl_init ("
https://qualysapi.qualys.com/api/2.0/fo/appliance/
");


curl_setopt($ch, CURLOPT_HTTPHEADER, array('X-Requested-With: PHP curl'));

curl_setopt ($ch, CURLOPT_COOKIEFILE, $cookieJar);

curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);

curl_setopt($ch, CURLOPT_POST, 1);

curl_setopt($ch, CURLOPT_POSTFIELDS, "action=list&output_mode=full");

$output = curl_exec ($ch);

echo $output;

curl_close ($ch);

?>






 

WAS API

Sample code:

 


TODO





 

AM API

Sample code:

 


TODO





 

Python 2.x, qualysapi

This open source package assists in making calls to all API versions.

 

More info:

https://github.com/paragbaxi/qualysapi

API v1

Sample code:

 


import qualysapi



# Setup connection to QualysGuard API -- only perform once per script.

qgc = qualysapi.connect('config.txt')

# API v1 call: Scan the New York & Las Vegas asset groups

# The call is our request's first parameter.

call = 'scan.php'

# The parameters to append to the url is our request's second parameter.

parameters = {'scan_title': 'Go big or go home', 'asset_groups': 'New York&Las Vegas', 'option': 'Initial+Options'}

# Note qualysapi will automatically convert spaces into plus signs for API v1 & v2.

# Let's call the API and store the result in xml_output.

xml_output = qgc.request(call, parameters)

print xml_output





 

API v2

Sample code:

 


import qualysapi



# Setup connection to QualysGuard API -- only perform once per script.

qgc = qualysapi.connect('config.txt')

# API v2 call: Print out DNS name for a range of IPs.

call = '/api/2.0/fo/asset/host/'

parameters = {'action': 'list', 'ips': '10.0.0.10-10.0.0.11'}

xml_output = qgc.request(call, parameters)





 

WAS API

Sample code:

 


import qualysapi

from lxml import objectify



# Setup connection to QualysGuard API -- only perform once per script.

qgc = qualysapi.connect('config.txt')

# API v3 WAS call: Print out number of webapps.

call = '/count/was/webapp'

# Note that this call does not have a payload so we don't send any data parameters.

xml_output = qgc.request(call)

root = objectify.fromstring(xml_output)

# Print out count of webapps.

print root.count.text

# Prints out:

# 89

#

# API v3 WAS call: Print out number of webapps containing title 'Supafly'.

call = '/count/was/webapp'

# We can send a string XML for the data.

parameters = '<ServiceRequest><filters><Criteria operator="CONTAINS" field="name">Supafly</Criteria></filters></ServiceRequest>'

xml_output = qgc.request(call, parameters)

root = objectify.fromstring(xml_output)

# Print out count of webapps.

print root.count.text

# Prints out:

# 3

#

# API v3 WAS call: Print out number of webapps containing title 'Lightsabertooth Tiger'.

call = '/count/was/webapp'

# We can also send an lxml.builder E object.

parameters = (

E.ServiceRequest(

E.filters(

E.Criteria('Lightsabertooth Tiger', field='name',operator='CONTAINS'))))

xml_output = qgc.request(call, parameters)

root = objectify.fromstring(xml_output)

# Print out count of webapps.

print root.count.text

# Prints out:

# 0

# Too bad, because that is an awesome webapp name!





 

AM API

Sample code:

 


import qualysapi

from lxml import objectify



# Setup connection to QualysGuard API -- only perform once per script.

qgc = qualysapi.connect('config.txt')

# API v3 Asset Management call: Count tags.

call = '/count/am/tag'

xml_output = qgc.request(call)

root = objectify.fromstring(xml_output)

# We can use XPATH to find the count.

print root.xpath('count')[0].text

# Prints out:

# 840

#

# API v3 Asset Management call: Find asset by name.

call = '/search/am/tag'

parameters = '''<ServiceRequest>

<preferences>

<limitResults>10</limitResults>

</preferences>

<filters>

<Criteria field="name" operator="CONTAINS">PB</Criteria>

</filters>

</ServiceRequest>'''


xml_output = qgc.request(call, parameters)





 

Pagination

Sample code for v2 Host list & detection API:

 


import qualysapi

from lxml import etree, objectify

qgc = qualysapi.connect()

# Start with first host, which starts at 1.

id_min = 1

while True:

print 'Downloading hosts from ID %d' % id_min

xml = qgc.request('/api/2.0/fo/asset/host/', {'action': 'list', 'ips': '10.10.10.220,10.10.24.78', 'truncation_limit': '1', 'id_min': id_min})

# Parse.

tree = etree.fromstring(xml)

# Iterate through each host.

elems = tree.findall('.//HOST')

for host in elems:

print host.xpath('IP')[0].text

# Set up next request, if applicable.

try:

url = tree.xpath('/HOST_LIST_OUTPUT/RESPONSE/WARNING/URL')[0].text

start = url.find('id_min') + 7

end = url.find('&',start)

id_min = int(url[start:end])

except IndexError, e:

# No next url. All hosts downloaded.

break





 

Ruby, rest-client

Leveraging the rest-client gem, it's simple to call the Qualys API.

 

API v1

Sample code:

 


require 'rest-client'

RestClient.get '
https://username:password@qualysapi.qualys.com/msp/about.phppassword@qualysapi.qualys.com/msp/about.php
password@qualysapi.qualys.com
/msp/about.phppassword@qualysapi.qualys.com
/msp/about.php'





 

API v2

Sample code:

 


TODO





 

 

WAS

Sample code:

 


TODO





 

AM

Sample code:

 


TODO





 

 

Ruby, httparty

Leveraging the httparty gem, it's simple to call the Qualys API.

 

API v1

Sample code:

 


require 'httparty'

auth = {:username => "username", :password => "password"}

HTTParty.get("
https://qualysapi.qualys.com/msp/about.php
",


:basic_auth => auth)




 

API v2

Sample code:

 


require 'httparty'

auth = {:username => "username", :password => "password"}

HTTParty.post("
https://qualysapi.qualys.com/api/2.0/fo/scan/
",


:basic_auth => auth,

:query => { :action => "list" },

:headers => { "X-Requested-With" => "ruby httparty"})





 

 

WAS

 

Sample code:

 


TODO




 

AM

Sample code:

 


TODO





 

VB.NET, vb_net_rest_sharp

This community published example by BD@Huntington assists in making calls to API v1 & API v2:

vb_net_rest_sharp

 

VB Script, getXMLFile

This community published package by Scr1ptW1zard assists in making calls to API v1 & API v2:

 

The getXMLFile subroutine takes 4 arguments:

  1. The first argument is the API version you want to use (1 or 2).
  2. The second argument is the file to store the output in.
  3. The third argument is the API call and arguments to pass.
  4. The fourth argument is the method to use when sending the data (GET or POST).

 

API v1

Sample code:

 


getXMLFile 2, xmlResponse,"about.php", "GET"






 

API v2

Sample code:

 


getXMLFile 2, xmlName,"report/?action=fetch&id=" & reportID, "POST"





 

Postman (Mac, Windows, or Linux)

This native Postman application speeds up development by adding a User Interface. 

Postman Collection v3 Updated on: 8/28/2019

Updated authentication for api gateway services (IOC, CertView, FIM, ITAM). Added new Qualys Application-Specific APIs and new Common Use Case examples.

 

Install and Configure POSTMAN

A one-time installation of POSTMAN and environment set up is required for POSTMAN to point your request to the appropriate Qualys platform.

 

Install POSTMAN:

  1. Download the correct POSTMAN version for your operating system and install it: getpostman.com
  2. Run the newly installed application from your desktop:
    • You will be prompted to sign-up for a POSTMAN account (optional). It is highly recommended that you create an account so that all of your work is backed-up.

Import Qualys API POSTMAN Configurations and Settings:

  1. Download Qualys API POSTMAN Collection and Qualys Postman Environments
  2. To Import the Collection:
    • Import -> Import File > Choose File or Drag & Drop -> Select and Import the above file "Qualys API Collection v2.0.postman_collection.json" (unzip file):
    • POSTMAN - Import Collection Tutorial
  3. To Import the Environment Variables:
    • Click the Gear Icon in the top right of your screen -> Import > Choose File or Drag & Drop -> Select and Import the .json files in the "Qualys Postman Environments.zip" you downloaded above:
      • Note: You only need to import the Platforms relevant to your Qualys account. If you do not know what platform your Qualys account is on, please reference the next section.

 

Configure POSTMAN's environment to match your Qualys platform:

  1. Identify your Qualys platform and select the correlating environment configuration: Identify your Qualys Cloud Platform.
  2. Click on "No Environment" button on the top right of the window. Select your corresponding Qualys Cloud Platform:
    • POSTMAN - Environment Variable


How to Use the Sample Collections

In order to leverage the sample collections, you need to enter your API-Enabled Qualys credentials (the below is just one option for authentication you can use):

  1. This collection has been updated to leverage global credentials. Navigate to the gear button for "Manage Environments":
    • Click on "Manage Environments" Gear Icon
  2. Now click the name of the platform your API credentials are tied to:
    • Edit environmental variable by clicking the name
  3. Now you can update the section under "CURRENT VALUE" to your username and password. Then click the "Update" button:
    • Now Update your API Creds and Click Update
  4. Your Postman setup should now look like this where "Basic Auth" is selected under the "Authorization" tab and the "Username" & "Password" fields have the global variables filled in:
    • Final Config Example
  5. To edit the collection's pre-built queries, select the "Body" tab (or Params for some queries) and modify the "Values" to your use cases:
    • POSTMAN - Body Tab Tutorial
  6. Once the Authorization, Body, etc are filled out for your desired use case, you can click the blue "Send" button to execute the API query.

 

Windows Powershell 3.0

This is standard on Windows 8.

API v1

Sample code:

 


$username = "username"

$password = "password"

$password_base64 = ConvertTo-SecureString $password -AsPlainText -Force

$creds = New-Object System.Management.Automation.PSCredential ($username, $password_base64)

$headers = @{"X-Requested-With"="powershell"}

$url = "https://qualysapi.qualys.com/about.php
"

Invoke-RestMethod -Headers $headers -Uri $url -Method Post -Credential $creds -OutFile response.xml





 

WAS API

Sample code:

 


TODO





 

AM API

Sample code:

 


TODO





6 people found this helpful

Attachments

    Outcomes