From 9ea6ab7eabe1dd0affda9db2149d3b25da83edaa Mon Sep 17 00:00:00 2001 From: Jon Schipp Date: Wed, 5 Jun 2019 16:02:45 -0500 Subject: [PATCH] AbuseIPDB 3.0.1: Improved error handling --- abuseipdb/Dockerfile | 23 +++++++---- abuseipdb/Makefile | 2 +- abuseipdb/bin/komand_abuseipdb | 2 +- abuseipdb/help.md | 1 + .../actions/check_cidr/action.py | 36 +++-------------- .../actions/check_cidr/schema.py | 4 ++ .../actions/check_ip/action.py | 39 +++---------------- .../actions/check_ip/schema.py | 4 ++ .../actions/report_ip/action.py | 39 ++----------------- .../actions/report_ip/schema.py | 4 ++ .../komand_abuseipdb/connection/connection.py | 19 +++++++++ abuseipdb/plugin.spec.yaml | 4 +- abuseipdb/setup.py | 2 +- abuseipdb/tests/check_cidr.json | 25 +++++------- abuseipdb/tests/check_cidr_error.json | 25 +++++------- abuseipdb/tests/check_ip.json | 27 ++++++------- abuseipdb/tests/check_ip_error.json | 27 ++++++------- abuseipdb/tests/report_ip.json | 27 ++++++------- abuseipdb/tests/report_ip_error.json | 27 ++++++------- 19 files changed, 131 insertions(+), 206 deletions(-) diff --git a/abuseipdb/Dockerfile b/abuseipdb/Dockerfile index fe6bfe395e..a4a22c4897 100755 --- a/abuseipdb/Dockerfile +++ b/abuseipdb/Dockerfile @@ -1,20 +1,27 @@ -FROM komand/python-pypy3-plugin:2 +FROM komand/python-3-37-slim-plugin:3 +# Refer to the following documentation for available SDK parent images: https://komand.github.io/python/sdk.html#version + LABEL organization=komand LABEL sdk=python LABEL type=plugin -ENV SSL_CERT_FILE /etc/ssl/certs/ca-certificates.crt -ENV SSL_CERT_DIR /etc/ssl/certs -ENV REQUESTS_CA_BUNDLE /etc/ssl/certs/ca-certificates.crt +# Add any custom package dependencies here +# NOTE: Add pip packages to requirements.txt -ADD ./plugin.spec.yaml /plugin.spec.yaml -ADD . /python/src +# End package dependencies +# Add source code WORKDIR /python/src -# Add any package dependencies here +ADD ./plugin.spec.yaml /plugin.spec.yaml +ADD . /python/src -# End package dependencies +# Install pip dependencies RUN if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + +# Install plugin RUN python setup.py build && python setup.py install +# User to run plugin code. The two supported users are: root, nobody +USER nobody + ENTRYPOINT ["/usr/local/bin/komand_abuseipdb"] \ No newline at end of file diff --git a/abuseipdb/Makefile b/abuseipdb/Makefile index ef91038338..05b5e26d2b 100755 --- a/abuseipdb/Makefile +++ b/abuseipdb/Makefile @@ -50,4 +50,4 @@ export: image # Make will not run a target if a file of the same name exists unless setting phony targets # https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html -.PHONY: default tarball image regenerate \ No newline at end of file +.PHONY: default tarball image regenerate diff --git a/abuseipdb/bin/komand_abuseipdb b/abuseipdb/bin/komand_abuseipdb index 7369105b5e..173158e914 100755 --- a/abuseipdb/bin/komand_abuseipdb +++ b/abuseipdb/bin/komand_abuseipdb @@ -6,7 +6,7 @@ from komand_abuseipdb import connection, actions, triggers Name = 'AbuseIPDB' Vendor = 'rapid7' -Version = '3.0.0' +Version = '3.0.1' Description = 'AbuseIPDB is a free service which allows you to look up IP reports, or report an abusive IP' diff --git a/abuseipdb/help.md b/abuseipdb/help.md index 8f98b98ddb..7217616813 100644 --- a/abuseipdb/help.md +++ b/abuseipdb/help.md @@ -243,6 +243,7 @@ There's a rate limit on the free API service. The following error messags `429 C * 1.0.0 - Initial plugin * 2.0.0 - Add `found` output to Check IP action | Support new credential type * 3.0.0 - Support new credential_secret_key type +* 3.0.1 - Improve error handling in the Check IP, Check CIDR, and Report IP actions | Update to use the `komand/python-3-37-slim-plugin` Docker image to reduce plugin size | Run plugin as least privileged user | Add connection test ## Workflows diff --git a/abuseipdb/komand_abuseipdb/actions/check_cidr/action.py b/abuseipdb/komand_abuseipdb/actions/check_cidr/action.py index 889251aa3e..402d4464b9 100755 --- a/abuseipdb/komand_abuseipdb/actions/check_cidr/action.py +++ b/abuseipdb/komand_abuseipdb/actions/check_cidr/action.py @@ -1,6 +1,8 @@ import komand from .schema import CheckCidrInput, CheckCidrOutput # Custom imports below +from komand.exceptions import PluginException +import json import requests import logging logging.getLogger('requests').setLevel(logging.WARNING) @@ -27,6 +29,9 @@ def run(self, params={}): r = requests.get(url) # Not using r.raise_for_status() since we get useful JSON information on an API 4** out = r.json() + except json.decoder.JSONDecodeError: + raise PluginException(cause='Received an unexpected response from AbuseIPDB.', + assistance="(non-JSON or no response was received). Response was: %s" % r.text) except Exception as e: self.logger.error(e) raise @@ -37,36 +42,7 @@ def run(self, params={}): if isinstance(error, dict): if error['id']: msg = '{}: {}: {}'.format(error.get('id'), error.get('title'), error.get('detail')) - self.logger.error(msg) - return error - except KeyError: - # All good, no error because 'id' key is not present - self.logger.info('No errors') - - return out - - def test(self): - try: - url = '{base}/{endpoint}/json?key={key}&network=207.126.144.0/20&days=30'.format( - base=self.connection.base, - endpoint='check-block', - key=self.connection.api_key, - ) - r = requests.get(url) - # Not using r.raise_for_status() since we get useful JSON information on an API 4** - out = r.json() - except Exception as e: - self.logger.error(e) - raise - - try: - if isinstance(out, list): - error = out[0] - if isinstance(error, dict): - if error['id']: - msg = '{}: {}: {}'.format(error.get('id'), error.get('title'), error.get('detail')) - self.logger.error(msg) - return error + raise PluginException(cause='Received an error response from AbuseIPDB.', assistance=msg) except KeyError: # All good, no error because 'id' key is not present self.logger.info('No errors') diff --git a/abuseipdb/komand_abuseipdb/actions/check_cidr/schema.py b/abuseipdb/komand_abuseipdb/actions/check_cidr/schema.py index 514570a89d..11619924ea 100755 --- a/abuseipdb/komand_abuseipdb/actions/check_cidr/schema.py +++ b/abuseipdb/komand_abuseipdb/actions/check_cidr/schema.py @@ -3,6 +3,10 @@ import json +class Component: + DESCRIPTION = "Look up a CIDR address in the database" + + class Input: CIDR = "cidr" DAYS = "days" diff --git a/abuseipdb/komand_abuseipdb/actions/check_ip/action.py b/abuseipdb/komand_abuseipdb/actions/check_ip/action.py index f722ccc95b..83ec919d69 100755 --- a/abuseipdb/komand_abuseipdb/actions/check_ip/action.py +++ b/abuseipdb/komand_abuseipdb/actions/check_ip/action.py @@ -1,6 +1,8 @@ import komand from .schema import CheckIpInput, CheckIpOutput # Custom imports below +from komand.exceptions import PluginException +import json import requests import logging logging.getLogger('requests').setLevel(logging.WARNING) @@ -33,6 +35,9 @@ def run(self, params={}): r = requests.get(url) # Not using r.raise_for_status() since we get useful JSON information on an API 4** out = r.json() + except json.decoder.JSONDecodeError: + raise PluginException(cause='Received an unexpected response from AbuseIPDB.', + assistance="(non-JSON or no response was received). Response was: %s" % r.text) except Exception as e: self.logger.error(e) raise @@ -50,8 +55,7 @@ def run(self, params={}): # If the id key is present, an error has occurred if error['id']: msg = '{}: {}: {}'.format(error.get('id'), error.get('title'), error.get('detail')) - self.logger.error(msg) - return error + raise PluginException(cause='Received an error response from AbuseIPDB.', assistance=msg) # UnboundLocalError is raised if variable error is not set # Error will not be set if out[0] doesn't exist per the catching of the IndexError exception above except UnboundLocalError: @@ -67,34 +71,3 @@ def run(self, params={}): found = False return { 'list': out, 'found': found } - - def test(self): - try: - # https://www.abuseipdb.com/check/[IP]/json?key=[API_KEY]&days=[DAYS][&verbose] - url = '{base}/{endpoint}/{ip}/json?key={key}&days={days}'.format( - base=self.connection.base, - endpoint='check', - ip='8.8.8.8', - key=self.connection.api_key, - days='30' - ) - r = requests.get(url) - # Not using r.raise_for_status() since we get useful JSON information on an API 4** - out = r.json() - except Exception as e: - self.logger.error(e) - raise - - try: - if isinstance(out, list): - error = out[0] - if isinstance(error, dict): - if error['id']: - msg = '{}: {}: {}'.format(error.get('id'), error.get('title'), error.get('detail')) - self.logger.error(msg) - return error - except KeyError: - # All good, no error because 'id' key is not present - self.logger.info('No errors') - - return { 'list': out, 'found': True } diff --git a/abuseipdb/komand_abuseipdb/actions/check_ip/schema.py b/abuseipdb/komand_abuseipdb/actions/check_ip/schema.py index dc6cf7a293..af69ba38f8 100755 --- a/abuseipdb/komand_abuseipdb/actions/check_ip/schema.py +++ b/abuseipdb/komand_abuseipdb/actions/check_ip/schema.py @@ -3,6 +3,10 @@ import json +class Component: + DESCRIPTION = "Look up an IP address in the database" + + class Input: ADDRESS = "address" DAYS = "days" diff --git a/abuseipdb/komand_abuseipdb/actions/report_ip/action.py b/abuseipdb/komand_abuseipdb/actions/report_ip/action.py index dea2f1c12c..69e00d7ae9 100755 --- a/abuseipdb/komand_abuseipdb/actions/report_ip/action.py +++ b/abuseipdb/komand_abuseipdb/actions/report_ip/action.py @@ -1,6 +1,8 @@ import komand from .schema import ReportIpInput, ReportIpOutput # Custom imports below +from komand.exceptions import PluginException +import json import requests import logging logging.getLogger('requests').setLevel(logging.WARNING) @@ -30,7 +32,6 @@ def run(self, params={}): if comment: if len(comment) > 0: # Comment provided - self.logger.info('Adding comment') url = '{}&comment={}'.format(url, comment) r = requests.get(url) @@ -41,46 +42,12 @@ def run(self, params={}): raise try: - self.logger.info(out) if isinstance(out, list): error = out[0] if isinstance(error, dict): if error['id']: msg = '{}: {}: {}'.format(error.get('id'), error.get('title'), error.get('detail')) - self.logger.error(msg) - return error - except KeyError: - # All good, no error because 'id' key is not present - self.logger.info('No errors') - - return out - - def test(self): - try: - url = '{base}/{endpoint}/json?key={key}&category={category}&ip={ip}'.format( - base=self.connection.base, - endpoint='report', - key=self.connection.api_key, - category=10, - # Should return an API error without raising an exception as we don't want to taint the database with false reporting - ip='1.2.3.4', - ) - r = requests.get(url) - # Not using r.raise_for_status() since we get useful JSON information on an API 4** - out = r.json() - except Exception as e: - self.logger.error(e) - raise - - try: - self.logger.info(out) - if isinstance(out, list): - error = out[0] - if isinstance(error, dict): - if error['id']: - msg = '{}: {}: {}'.format(error.get('id'), error.get('title'), error.get('detail')) - self.logger.error(msg) - return error + raise PluginException(cause='Received an error response from AbuseIPDB.', assistance=msg) except KeyError: # All good, no error because 'id' key is not present self.logger.info('No errors') diff --git a/abuseipdb/komand_abuseipdb/actions/report_ip/schema.py b/abuseipdb/komand_abuseipdb/actions/report_ip/schema.py index 1792c87c20..e2bf4b53fd 100755 --- a/abuseipdb/komand_abuseipdb/actions/report_ip/schema.py +++ b/abuseipdb/komand_abuseipdb/actions/report_ip/schema.py @@ -3,6 +3,10 @@ import json +class Component: + DESCRIPTION = "Report an abusive IP address" + + class Input: ADDRESS = "address" CATEGORIES = "categories" diff --git a/abuseipdb/komand_abuseipdb/connection/connection.py b/abuseipdb/komand_abuseipdb/connection/connection.py index 08431d8db1..33116100a8 100755 --- a/abuseipdb/komand_abuseipdb/connection/connection.py +++ b/abuseipdb/komand_abuseipdb/connection/connection.py @@ -1,6 +1,9 @@ import komand from .schema import ConnectionSchema # Custom imports below +from komand.exceptions import ConnectionTestException +import json +import requests class Connection(komand.Connection): @@ -13,3 +16,19 @@ def connect(self, params): self.base = 'https://www.abuseipdb.com' self.logger.info('Connect: Connecting to %s...' % self.base) + + def test(self): + # Use private IP Addresses for testing the API (e.g. 127.0.0.1) from https://www.abuseipdb.com/api + url = 'https://www.abuseipdb.com/check/127.0.0.1/json' + try: + r = requests.get(url) + json_ = r.json() + except json.decoder.JSONDecodeError: + raise ConnectionTestException(cause='Received an unexpected response from AbuseIPDB.', + assistance="(non-JSON or no response was received). Response was: %s" % r.text) + except Exception as e: + self.logger.error(e) + raise + + #return { 'list': out, 'found': True } + return json_ diff --git a/abuseipdb/plugin.spec.yaml b/abuseipdb/plugin.spec.yaml index 5a19312775..b0e3eec468 100644 --- a/abuseipdb/plugin.spec.yaml +++ b/abuseipdb/plugin.spec.yaml @@ -3,9 +3,9 @@ name: abuseipdb title: AbuseIPDB description: AbuseIPDB is a free service which allows you to look up IP reports, or report an abusive IP -version: 3.0.0 +version: 3.0.1 vendor: rapid7 -status: ["unsupported"] +status: ["supported"] tags: - ip - intelligence diff --git a/abuseipdb/setup.py b/abuseipdb/setup.py index 589a24285c..d30a1d8ba7 100755 --- a/abuseipdb/setup.py +++ b/abuseipdb/setup.py @@ -3,7 +3,7 @@ setup(name='abuseipdb-rapid7-plugin', - version='3.0.0', + version='3.0.1', description='AbuseIPDB is a free service which allows you to look up IP reports, or report an abusive IP', author='rapid7', author_email='', diff --git a/abuseipdb/tests/check_cidr.json b/abuseipdb/tests/check_cidr.json index 88e137ca90..9f05d91458 100644 --- a/abuseipdb/tests/check_cidr.json +++ b/abuseipdb/tests/check_cidr.json @@ -1,17 +1,12 @@ { - "body": { - "action": "check_cidr", - "meta": {}, - "input": { - "cidr": "207.126.144.0/20", - "days": "30" + "body": { + "action": "check_cidr", + "input": { + "cidr": "207.126.144.0/20", + "days": "30" + }, + "meta": {} }, - "connection": { - "credentials": { - "secretKey": "" - } - } - }, - "type": "action_start", - "version": "v1" -} + "type": "action_start", + "version": "v1" +} \ No newline at end of file diff --git a/abuseipdb/tests/check_cidr_error.json b/abuseipdb/tests/check_cidr_error.json index 91dd8b5f30..090f548191 100644 --- a/abuseipdb/tests/check_cidr_error.json +++ b/abuseipdb/tests/check_cidr_error.json @@ -1,17 +1,12 @@ { - "body": { - "action": "check_cidr", - "meta": {}, - "input": { - "cidr": "1/20", - "days": "30" + "body": { + "action": "check_cidr", + "input": { + "cidr": "1/20", + "days": "30" + }, + "meta": {} }, - "connection": { - "credentials": { - "secretKey": "" - } - } - }, - "type": "action_start", - "version": "v1" -} + "type": "action_start", + "version": "v1" +} \ No newline at end of file diff --git a/abuseipdb/tests/check_ip.json b/abuseipdb/tests/check_ip.json index d4beab7879..905f59368b 100644 --- a/abuseipdb/tests/check_ip.json +++ b/abuseipdb/tests/check_ip.json @@ -1,18 +1,13 @@ { - "body": { - "action": "check_ip", - "meta": {}, - "input": { - "address": "8.8.8.8", - "days": "30", - "verbose": true + "body": { + "action": "check_ip", + "input": { + "address": "8.8.8.8", + "days": "30", + "verbose": true + }, + "meta": {} }, - "connection": { - "credentials": { - "secretKey": "" - } - } - }, - "type": "action_start", - "version": "v1" -} + "type": "action_start", + "version": "v1" +} \ No newline at end of file diff --git a/abuseipdb/tests/check_ip_error.json b/abuseipdb/tests/check_ip_error.json index bf558300ab..d177a923f5 100644 --- a/abuseipdb/tests/check_ip_error.json +++ b/abuseipdb/tests/check_ip_error.json @@ -1,18 +1,13 @@ { - "body": { - "action": "check_ip", - "meta": {}, - "input": { - "address": "1.2", - "days": "30", - "verbose": true + "body": { + "action": "check_ip", + "input": { + "address": "1.2", + "days": "30", + "verbose": true + }, + "meta": {} }, - "connection": { - "credentials": { - "secretKey": "" - } - } - }, - "type": "action_start", - "version": "v1" -} + "type": "action_start", + "version": "v1" +} \ No newline at end of file diff --git a/abuseipdb/tests/report_ip.json b/abuseipdb/tests/report_ip.json index e2a0f6c664..cf81217c22 100644 --- a/abuseipdb/tests/report_ip.json +++ b/abuseipdb/tests/report_ip.json @@ -1,18 +1,13 @@ { - "body": { - "action": "report_ip", - "meta": {}, - "input": { - "address": "1.2.3.4", - "categories": "10,12", - "comment": "Testing" + "body": { + "action": "report_ip", + "input": { + "address": "1.2.3.4", + "categories": "10,12", + "comment": "Testing" + }, + "meta": {} }, - "connection": { - "credentials": { - "secretKey": "" - } - } - }, - "type": "action_start", - "version": "v1" -} + "type": "action_start", + "version": "v1" +} \ No newline at end of file diff --git a/abuseipdb/tests/report_ip_error.json b/abuseipdb/tests/report_ip_error.json index b1028d61e1..27ff19bcb1 100644 --- a/abuseipdb/tests/report_ip_error.json +++ b/abuseipdb/tests/report_ip_error.json @@ -1,18 +1,13 @@ { - "body": { - "action": "report_ip", - "meta": {}, - "input": { - "address": "1.", - "categories": "10,12", - "comment": "Testing" + "body": { + "action": "report_ip", + "input": { + "address": "1.", + "categories": "10,12", + "comment": "Testing" + }, + "meta": {} }, - "connection": { - "credentials": { - "secretKey": "" - } - } - }, - "type": "action_start", - "version": "v1" -} + "type": "action_start", + "version": "v1" +} \ No newline at end of file