Listing WAS Applications in Subscription - Python Module

Discussion created by jkent on Aug 31, 2012
Latest reply on Sep 1, 2012 by Parag Baxi

I worked with QNimbus yesterday and pulled this out of the multiple site scanning code.  The same libraries are needed.


The call pulls all applications and application id's from the applications in the subscription and puts them into a file.

make the call with

python AppList.py -u (USERNAME) -p (PASSWORD)


#!/usr/bin/env python


'''Run multiple WAS v2 scans as a workaround to the concurrency limit.


Author: Qnimbus.co

License: GPL



'''To do:

Add ability to import CSV.



import argparse

import base64, urllib2

import datetime, time

import logging, os, sys

from collections import defaultdict

from lxml import objectify

from texttable import Texttable


def qg_was_api(uri, data = None):

    """Returns XML for API call requested.

       GET call if data is None. POST call otherwise.


    global base64string

    logging.debug('qg_was_api(%s, %s)' % (uri, data))

    # Set request. Force add creds. Let API know type of content in POST.

    req = urllib2.Request(uri, data)

    req.add_header("Authorization", "Basic %s" % base64string)

    req.add_header("Content-Type", "text/xml")

    # Make request.

    result = urllib2.urlopen(req)

    response = result.read()

    logging.debug('qg_was_api.response = %s' % (response))

    return response


def list_apps(apps):

    """Print applications into a pretty table.


    table = Texttable()

    table.set_cols_align(["r", "l", "l"])

    table.set_cols_valign(["m", "m", "m"])

    table.add_rows([ ['App #', 'App name', 'App ID #'], ], header = True)


    for webapp in apps:


        table.add_row([c, webapp['name'], webapp['id']])

    # Print table.

    print (table.draw() + '\n')

    return True


# Start of script.

print 'Warning, I do not support more than 1000 app records, yet.\n'

# Declare the command line flags/options we want to allow.

parser = argparse.ArgumentParser(description = 'Run multiple QualysGuard WAS v2 scans.')

parser.add_argument('-a', '--all_apps', action = 'store_true', default = True,

                    help = 'Select all web applications. Overwrites any tag filters.')

parser.add_argument('--debug', action = 'store_true',

                    help = 'Outputs additional information to log.')

parser.add_argument('-f', '--file', default = 'AppList.txt',

                    help = 'Output file to store XML results from initiating scans. (Default = AppList.txt)')

parser.add_argument('-l', '--list', action = 'store_true', default = True,

                    help = 'List all selected web applications. (Default = True)')

parser.add_argument('-p', '--password', required = True,

                    help = 'Corresponding QualysGuard WAS v2 API password.')

parser.add_argument('-t', '--tag',

                    help = 'Filter selection of web applications to those with TAG.')

parser.add_argument('-u', '--username', required = True,

                    help = 'QualysGuard WAS v2 API username.')


# Parse arguements.

c_args = parser.parse_args()

# Create log directory.

PATH_LOG = 'log'

if not os.path.exists(PATH_LOG):


# Set log options.

now = datetime.datetime.now()

LOG_FILENAME = '%s/%s-%s.log' % (PATH_LOG,



# Set logging level.

if c_args.debug:

    # Enable debug level of logging.

    print "Logging level set to debug."

    logging.basicConfig(filename = LOG_FILENAME, format = '%(asctime)s %(message)s',

                        level = logging.DEBUG)


    logging.basicConfig(filename = LOG_FILENAME, format = '%(asctime)s %(message)s',

                        level = logging.INFO)

# Validate arguements.

if not ((c_args.all_apps or c_args.tag or c_args.Tags_file)):


    logging.error('Invalid run parameters.')


# Credentials for basic authorization.

logging.info('username = %s' % (c_args.username))

logging.debug('password = %s' % (c_args.password))

base64string = base64.encodestring('%s:%s' % (c_args.username, c_args.password))[:-1]

# Get list of web apps.

query_uri = 'https://qualysapi.qualys.com/qps/rest/3.0/search/was/webapp'

if c_args.all_apps:

    data = '''


        <filters><Criteria field="createdDate" operator="GREATER">2000-02-21T00:00:00Z</Criteria></filters>



elif c_args.tag:

    data = '''



            <Criteria field="tags.name" operator="EQUALS">%s</Criteria>



    </ServiceRequest>''' % (c_args.tag)

search_apps = qg_was_api(query_uri, data)

# Parse list of web apps to associate each web app id with web app name.

tree = objectify.fromstring(search_apps)

apps_to_scan = []

for webapp in tree.data.WebApp:

    app = defaultdict(str)




logging.info('apps_to_scan = %s' % (apps_to_scan))

if c_args.list:


if c_args.file:

    f = file(c_args.file, 'w')

    for webapp in apps_to_scan:

        f.write('%s %s\n' % (webapp['id'], webapp['name']))