diff --git a/LICENSE b/LICENSE index b7b3c69..12536c5 100644 --- a/LICENSE +++ b/LICENSE @@ -198,4 +198,4 @@ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file + limitations under the License. diff --git a/exclude_files.txt b/exclude_files.txt deleted file mode 100644 index 436f030..0000000 --- a/exclude_files.txt +++ /dev/null @@ -1,8 +0,0 @@ -docker-compose.yml -.gitlab-ci.yml -Makefile -.git* -whitesource-results -*.postman_collection.json -whitesource* -gl-*.csv diff --git a/maxmind.json b/maxmind.json index 4450e7b..cf07ec5 100644 --- a/maxmind.json +++ b/maxmind.json @@ -4,17 +4,22 @@ "description": "This app provides IP geolocation with the included MaxMind database", "type": "information", "publisher": "Splunk", + "contributors": [ + { + "name": "Brady Davis" + } + ], "main_module": "maxmind_connector.py", - "app_version": "2.2.6", + "app_version": "2.3.0", "utctime_updated": "2022-04-26T17:17:54.000000Z", "package_name": "phantom_maxmind", "product_name": "GeoIP2", "product_vendor": "MaxMind", "product_version_regex": ".*", - "min_phantom_version": "5.2.0", + "min_phantom_version": "6.1.1", "fips_compliant": true, "latest_tested_versions": [ - "GeoLite2-City MMDB Updated 2020-11-03" + "GeoLite2-City MMDB Updated 2024-03-11" ], "python_version": "3", "configuration": { @@ -33,34 +38,6 @@ "logo": "logo_maxmind.svg", "logo_dark": "logo_maxmind_dark.svg", "license": "Copyright (c) 2016-2024 Splunk Inc.", - "pip_dependencies": { - "wheel": [ - { - "module": "geoip2", - "input_file": "wheels/shared/geoip2-2.9.0-py2.py3-none-any.whl" - }, - { - "module": "ipaddress", - "input_file": "wheels/shared/ipaddress-1.0.23-py2.py3-none-any.whl" - }, - { - "module": "maxminddb", - "input_file": "wheels/py2/maxminddb-1.5.1-py2-none-any.whl" - }, - { - "module": "python_dateutil", - "input_file": "wheels/shared/python_dateutil-2.8.1-py2.py3-none-any.whl" - }, - { - "module": "six", - "input_file": "wheels/shared/six-1.16.0-py2.py3-none-any.whl" - }, - { - "module": "urllib3", - "input_file": "wheels/shared/urllib3-1.26.18-py2.py3-none-any.whl" - } - ] - }, "actions": [ { "action": "test connectivity", @@ -84,10 +61,11 @@ "parameters": { "ip": { "order": 0, - "description": "IP to geolocate", + "description": "IP (IPv4/IPv6) to geolocate", "data_type": "string", "contains": [ - "ip" + "ip", + "ipv6" ], "primary": true, "required": true, @@ -155,18 +133,8 @@ "203.88.139.34" ], "contains": [ - "ip" - ], - "map_info": "IP Address" - }, - { - "data_path": "action_result.parameter.ip", - "data_type": "string", - "example_values": [ - "203.88.139.34" - ], - "contains": [ - "ip" + "ip", + "ipv6" ], "map_info": "name" }, @@ -427,6 +395,7 @@ { "action": "on poll", "description": "Update the database if there is a newer one on the server", + "verbose": "This action replaces the maxmind database if database is updated.", "type": "ingest", "identifier": "on_poll", "read_only": true, @@ -434,20 +403,17 @@ "container_id": { "data_type": "string", "order": 0, - "description": "Container IDs to limit the ingestion to", - "allow_list": true + "description": "Container IDs to limit the ingestion to" }, "start_time": { "data_type": "numeric", "order": 1, - "description": "Start of time range, in epoch time (milliseconds)", - "verbose": "If not specified, the default is past 10 days." + "description": "Start of time range, in epoch time (milliseconds)" }, "end_time": { "data_type": "numeric", "order": 2, - "description": "End of time range, in epoch time (milliseconds)", - "verbose": "If not specified, the default is now." + "description": "End of time range, in epoch time (milliseconds)" }, "container_count": { "data_type": "numeric", diff --git a/maxmind_connector.py b/maxmind_connector.py index 9eac279..e2c5f97 100644 --- a/maxmind_connector.py +++ b/maxmind_connector.py @@ -13,6 +13,7 @@ # either express or implied. See the License for the specific language governing permissions # and limitations under the License. import ipaddress +import json import os import pathlib import sys @@ -50,7 +51,6 @@ def __init__(self): self.reader = None self._ip_address = None - self._python_version = None self._state = {} def finalize(self): @@ -60,11 +60,8 @@ def finalize(self): def initialize(self): self._state = self.load_state() - # Fetching the Python major version - try: - self._python_version = int(sys.version_info[0]) - except: - return self.set_status(phantom.APP_ERROR, "Error occurred while getting the Phantom server's Python major version.") + # custom contain for validating ipv6 + self.set_validator('ipv6', self._is_ip) # Validate the configuration parameters config = self.get_config() @@ -72,10 +69,7 @@ def initialize(self): self._license_key = config.get('license_key') try: - if self._python_version == 2: - ipaddress.ip_address(unicode(self._ip_address)) - else: - ipaddress.ip_address(self._ip_address) + ipaddress.ip_address(self._ip_address) except: return self.set_status(phantom.APP_ERROR, "Please provide a valid IP Address in the configuration parameters") @@ -89,6 +83,20 @@ def initialize(self): self.save_progress(MAXMIND_MSG_DB_LOADED) return phantom.APP_SUCCESS + def _is_ip(self, input_ip_address): + """ + Function that checks given address and return True if address is valid IPv4 or IPV6 address. + + :param input_ip_address: IP address + :return: status (success/failure) + """ + + try: + ipaddress.ip_address(input_ip_address) + except Exception: + return False + return True + def _handle_test_connectivity(self, param): # Create a ActionResult object to store the result @@ -329,26 +337,69 @@ def handle_action(self, param): if __name__ == '__main__': - import json - # import pudb - from traceback import format_exc + import argparse + + import pudb + + pudb.set_trace() + + argparser = argparse.ArgumentParser() - # pudb.set_trace() + argparser.add_argument('input_test_json', help='Input Test JSON file') + argparser.add_argument('-u', '--username', help='username', required=False) + argparser.add_argument('-p', '--password', help='password', required=False) + argparser.add_argument('-v', '--verify', action='store_true', help='verify', required=False, default=False) - if (len(sys.argv) < 2): - print('No test json specified as input') - sys.exit(0) + args = argparser.parse_args() + session_id = None - with open(sys.argv[1]) as f: + username = args.username + password = args.password + verify = args.verify + + if (username is not None and password is None): + # User specified a username but not a password, so ask + import getpass + + password = getpass.getpass("Password: ") + + if (username and password): + try: + print("Accessing the Login page") + r = requests.get( # nosemgrep: python.requests.best-practice.use-timeout.use-timeout + BaseConnector._get_phantom_base_url() + "login", verify=verify) + csrftoken = r.cookies['csrftoken'] + + data = dict() + data['username'] = username + data['password'] = password + data['csrfmiddlewaretoken'] = csrftoken + + headers = dict() + headers['Cookie'] = 'csrftoken=' + csrftoken + headers['Referer'] = BaseConnector._get_phantom_base_url() + 'login' + + print("Logging into Platform to get the session id") + r2 = requests.post( # nosemgrep: python.requests.best-practice.use-timeout.use-timeout + BaseConnector._get_phantom_base_url() + "login", verify=verify, data=data, headers=headers) + session_id = r2.cookies['sessionid'] + except Exception as e: + print("Unable to get session id from the platfrom. Error: " + str(e)) + sys.exit(1) + + with open(args.input_test_json) as f: in_json = f.read() in_json = json.loads(in_json) print(json.dumps(in_json, indent=4)) + connector = MaxmindConnector() connector.print_progress_message = True - try: - ret_val = connector._handle_action(json.dumps(in_json), None) - except: - print(format_exc()) + + if (session_id is not None): + in_json['user_session_token'] = session_id + connector._set_csrf_info(csrftoken, headers['Referer']) + + ret_val = connector._handle_action(json.dumps(in_json), None) print(json.dumps(json.loads(ret_val), indent=4)) sys.exit(0) diff --git a/release_notes/unreleased.md b/release_notes/unreleased.md index fbcb2fd..abb506a 100644 --- a/release_notes/unreleased.md +++ b/release_notes/unreleased.md @@ -1 +1,2 @@ **Unreleased** +* Added the support for IPv6 in 'geolocate ip' action diff --git a/wheels/py2/maxminddb-1.5.1-py2-none-any.whl b/wheels/py2/maxminddb-1.5.1-py2-none-any.whl deleted file mode 100644 index 7bfe3ec..0000000 Binary files a/wheels/py2/maxminddb-1.5.1-py2-none-any.whl and /dev/null differ diff --git a/wheels/shared/ipaddress-1.0.23-py2.py3-none-any.whl b/wheels/shared/ipaddress-1.0.23-py2.py3-none-any.whl deleted file mode 100644 index 8721f5a..0000000 Binary files a/wheels/shared/ipaddress-1.0.23-py2.py3-none-any.whl and /dev/null differ