Skip to content

Commit

Permalink
Merge pull request #85 from MarianG/Extend_Functionality
Browse files Browse the repository at this point in the history
Extend Functionaly and include more Error Handling
  • Loading branch information
paragbaxi authored May 26, 2020
2 parents 5c4e632 + 0999685 commit 95ac304
Show file tree
Hide file tree
Showing 2 changed files with 199 additions and 2 deletions.
109 changes: 108 additions & 1 deletion qualysapi/api_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,55 @@ def getHost(self, host):
hostData.find("TRACKING_METHOD"),
)

def listHosts(
self,
ips=None,
tags=None,
os_pattern=None,
tag_set_exclude=None,
id_min=None,
detailed=False,
echo_request=None,
limit=100,
):

call = "/api/2.0/fo/asset/host/"
parameters = {"action": "list", "truncation_limit": str(limit)}
if detailed:
parameters["details"] = "All/AGs"
if tag_set_exclude:
parameters["tag_set_exclude"] = tags
if id_min:
parameters["id_min"] = str(id_min)
if ips:
parameters["ips"] = str(ips)
if tags:
parameters["use_tags"] = "1"
parameters["tag_set_by"] = "name"
parameters["tag_set_include"] = tags
parameters["show_tags"] = "1"
if os_pattern:
parameters["os_pattern"] = os_pattern
if echo_request:
parameters["echo_request"] = echo_request

hostData = objectify.fromstring(self.request(call, parameters).encode("utf-8"))
hostArray = []
for host in hostData.RESPONSE.HOST_LIST.HOST:
hostArray.append(
Host(
host.find("DNS"),
host.find("ID"),
host.find("IP"),
host.find("LAST_VULN_SCAN_DATETIME"),
host.find("NETBIOS"),
host.find("OS"),
host.find("TRACKING_METHOD"),
)
)

return hostArray

def getHostRange(self, start, end):
call = "/api/2.0/fo/asset/host/"
parameters = {"action": "list", "ips": f"{start}-{end}"}
Expand Down Expand Up @@ -142,14 +191,24 @@ def listReportTemplates(self):

def listReports(self, id=0):
call = "/api/2.0/fo/report"

max_retries = 10
if id == 0:
parameters = {"action": "list"}

repData = objectify.fromstring(
self.request(call, parameters).encode("utf-8")
).RESPONSE
reportsArray = []
while repData.find("REPORT_LIST") is None and max_retries > 0:
max_retries = max_retries - 1
time.sleep(30)
qualys_resp = self.request(call, parameters).encode("utf-8")
logging.info("QUALYS_REPONSE " + str(qualys_resp))
repData = objectify.fromstring(qualys_resp).RESPONSE

if max_retries <= 0:
logging.info("Report Listing not successful")
return None

for report in repData.REPORT_LIST.REPORT:
reportsArray.append(
Expand All @@ -170,6 +229,19 @@ def listReports(self, id=0):

else:
parameters = {"action": "list", "id": id}
qualys_resp = self.request(call, parameters).encode("utf-8")

repData_debug = objectify.fromstring(qualys_resp).RESPONSE
while repData_debug.find("REPORT_LIST") is None and max_retries > 0:
max_retries = max_retries - 1
time.sleep(30)
qualys_resp = self.request(call, parameters).encode("utf-8")
logging.info("QUALYS_REPONSE " + str(qualys_resp))
repData_debug = objectify.fromstring(qualys_resp).RESPONSE

if max_retries <= 0:
logging.info("Report Listing not successful")
return None
repData = objectify.fromstring(
self.request(call, parameters).encode("utf-8")
).RESPONSE.REPORT_LIST.REPORT
Expand Down Expand Up @@ -366,6 +438,41 @@ def listScans(self, launched_after="", state="", target="", type="", user_login=

return scanArray

def listChildTags(self, tag_name=None, tag_id=None, filename=None):
if tag_id:
files = (
"""<ServiceRequest>
<filters>
<Criteria field="id" operator="EQUALS">"""
+ tag_id
+ """</Criteria>
</filters>
</ServiceRequest>"""
)
elif filename:
files = open(filename, "rb").read()
elif tag_name:
files = (
"""<ServiceRequest>
<filters>
<Criteria field="name" operator="EQUALS">"""
+ tag_name
+ """</Criteria>
</filters>
</ServiceRequest>"""
).encode("ascii", "ignore")

call = "/qps/rest/2.0/search/am/tag"
parameters = files
response = objectify.fromstring(
self.request(call, parameters, api_version=2, http_method="post").encode("utf-8")
)
childs = list()
for child in response.getchildren()[3][0].Tag.children.list.getchildren():
childs.append(child.getchildren())

return childs

def launchScan(self, title, option_title, iscanner_name, asset_groups="", ip=""):
# TODO: Add ability to scan by tag.
call = "/api/2.0/fo/scan/"
Expand Down
92 changes: 91 additions & 1 deletion qualysapi/connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,97 @@ def request(
api_call,
self.rate_limit_remaining[api_call],
)
if self.rate_limit_remaining[api_call] > rate_warn_threshold:
response = request.text
if (
"<CODE>1960</CODE>" in response
and "<TEXT>This API cannot be run again until" in response
):
max_retries = 10
retry_count = 0
while (
"<CODE>1960</CODE>" in response
and "<TEXT>This API cannot be run again until" in response
):
retry_count += 1
time_to_wait = int(30)
logger.info(
"Concurrency Limit Exceeded waiting %d seconds. %d retries remaining"
% (time_to_wait, max_retries - retry_count)
)
time.sleep(time_to_wait)

logger.info(str(url), str(data)) # self.auth, headers, self.proxies)
if http_method == "get":
# GET
logger.debug("GET request.")
request = self.session.get(
url,
params=data,
auth=self.auth,
headers=headers,
proxies=self.proxies,
)
else:
# POST
logger.debug("POST request.")
# Make POST request.
request = self.session.post(
url,
data=data,
auth=self.auth,
headers=headers,
proxies=self.proxies,
)
logger.debug("response headers =\n%s" % (str(request.headers)))
response = request.text
if retry_count >= max_retries:
break
elif (
"<CODE>1965</CODE>" in response
and "<TEXT>This API cannot be run again for another" in response
):
max_retries = 10
retry_count = 0
while (
"<CODE>1965</CODE>" in response
and "<TEXT>This API cannot be run again for another" in response
):
retry_count += 1
time_to_wait = int(request.headers["x-ratelimit-towait-sec"])
logger.info(
"API Limit Exceeded waiting %d seconds. %d retries remaining"
% (time_to_wait, max_retries - retry_count)
)
time.sleep(time_to_wait)

logger.info(str(url), str(data)) # self.auth, headers, self.proxies)
if http_method == "get":
# GET
logger.debug("GET request.")
request = self.session.get(
url,
params=data,
auth=self.auth,
headers=headers,
proxies=self.proxies,
)
else:
# POST
logger.debug("POST request.")
# Make POST request.
request = self.session.post(
url,
data=data,
auth=self.auth,
headers=headers,
proxies=self.proxies,
)
logger.debug("response headers =\n%s" % (str(request.headers)))
response = request.text
if retry_count >= max_retries:
break

elif self.rate_limit_remaining[api_call] > rate_warn_threshold:
logger.debug(
"rate limit for api_call, %s = %s",
api_call,
Expand Down

0 comments on commit 95ac304

Please sign in to comment.