python脚本调用api实战_python脚本调用fortigate API完整代码

该博客展示了如何使用Python脚本通过requests模块调用Fortigate API。首先定义了几个异常类,然后创建了一个FortiGate类,用于处理与FortiOS设备的连接、登录、登出以及发起HTTP请求。此外,还提供了CollectIp类来读取IP地址,并使用InvokeFortigate类将IP添加到Fortigate防火墙地址组。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

python通过requests模块可以发起get和post请求,调用第三方API接口,下面是调用fortigate API的例子代码:

#!/usr/bin/env python

# coding=utf-8

import json

import requests

from requests.exceptions import ConnectionError as ReqConnError

import inspect, sys, os, gzip, re, traceback

import logging.handlers

class FGTBaseException(Exception):

"""Wrapper to catch the unexpected"""

def __init__(self, msg=None, *args, **kwargs):

if msg is None:

msg = "An exception occurred within pyfmg"

super(FGTBaseException, self).__init__(msg, *args, **kwargs)

class FGTValidSessionException(FGTBaseException):

"""Raised when a call is made, but there is no valid login instance"""

def __init__(self, method, url, *args, **kwargs):

msg = "A call using the {method} method was requested to {url} on a FortiOS instance that had no " \

"valid session or was not connected. Paramaters were:\n{params}". \

format(method=method, url=url, params=kwargs)

super(FGTValidSessionException, self).__init__(msg, *args, **kwargs)

class FGTValueError(ValueError):

"""Catch value errors such as bad timeout values"""

def __init__(self, *args, **kwargs):

super(FGTValueError, self).__init__(*args, **kwargs)

class FGTResponseNotFormedCorrect(KeyError):

"""Used only if a response does not have a standard format as based on FGT response guidelines"""

def __init__(self, *args, **kwargs):

super(FGTResponseNotFormedCorrect, self).__init__(*args, **kwargs)

class FGTConnectionError(ReqConnError):

"""Wrap requests Connection error so requests is not a dependency outside this module"""

def __init__(self, *args, **kwargs):

super(FGTConnectionError, self).__init__(*args, **kwargs)

class FortiGate(object):

def __init__(self, host, user, passwd=None, debug=False, use_ssl=True, verify_ssl=False, timeout=300,

disable_request_warnings=False, apikey=None):

super(FortiGate, self).__init__()

self._host = host

self._user = user

self._req_id = 0

self._url = None

self._session = None

self._sid = None

self._timeout = timeout

self._debug = debug

self._use_ssl = use_ssl

self._verify_ssl = verify_ssl

self._apikeyused = True if passwd is None and apikey is not None else False

self._passwd = passwd if passwd is not None else apikey

if disable_request_warnings:

pass

#requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)

@property

def api_key_used(self):

return self._apikeyused

@api_key_used.setter

def api_key_used(self, val):

self._apikeyused = val

@property

def debug(self):

return self._debug

@debug.setter

def debug(self, val):

self._debug = val

@property

def req_id(self):

return self._req_id

@req_id.setter

def req_id(self, val):

self._req_id = val

def _update_request_id(self, reqid=0):

self.req_id = reqid if reqid != 0 else self.req_id + 1

@property

def sid(self):

return self._sid

@sid.setter

def sid(self, val):

self._sid = val

@property

def verify_ssl(self):

return self._verify_ssl

@verify_ssl.setter

def verify_ssl(self, val):

self._verify_ssl = val

@property

def timeout(self):

return self._timeout

@timeout.setter

def timeout(self, val):

self._timeout = val

@staticmethod

def jprint(json_obj):

try:

return json.dumps(json_obj, indent=2, sort_keys=True)

except TypeError as te:

return json.dumps({"Type Information": te.message})

def dprint(self, msg, s=None):

if self.debug:

print(msg)

if s is not None:

print(self.jprint(s) + "\n")

pass

def _set_sid(self, response):

if self.api_key_used:

self.sid = "apikeyusednosidavailable"

return

for cookie in response.cookies:

if cookie.name == "ccsrftoken":

csrftoken = cookie.value[1:-1]

# print(csrftoken)

self._session.headers.update({"X-CSRFTOKEN": csrftoken})

if "APSCOOKIE_" in cookie.name:

self.sid = cookie.value

def _set_url(self, url, *args):

if "logincheck" in url or "logout" in url:

self._url = "{proto}://{host}/{url}".format(proto="https" if self._use_ssl else "http",

host=self._host, url=url)

else:

if url[0] == "/":

url = url[1:]

self._url = "{proto}://{host}/api/v2/{url}".format(proto="https" if self._use_ssl else "http",

host=self._host, url=url)

if len(args) > 0:

self._url = "{url}?".format(url=self._url)

try:

self._url = self._url + "&".join(args)

except:

pass

def __handle_login_values(self, response):

# response first character defines if login was successful

# 0 Log in failure. Most likely an incorrect username/password combo.

# 1 Successful log in*

# 2 Admin is now locked out

# 3 Two-factor Authentication is needed**

try:

if response.status_code == 200:

if response.text == "" or response.text[0] == "0":

return -1, {"status_code": response.status_code,

"message": "Failed Login - Most likely incorrect username/password used"}

elif response.text[0] == "1":

self._set_sid(response)

return 0, {"status_code": response.status_code, "message": "Login Successful"}

elif response.text[0] == "2":

return -1, {"status_code": response.status_code, "message": "Admin Locked Out"}

elif response.text[0] == "3":

return -1, {"status_code": response.status_code, "message": "Two-factor Required"}

else:

return -1, {"status_code": response.status_code, "message": "Unknown Error Occurred"}

else:

return -1, {"status_code": response.status_code,

"message": "Login Failed Status Code {} Returned".format(response.status_code)}

except IndexError as err:

self.dprint("Index error in response: {err_type} {err}\n\n".format(err_type=type(err), err=err))

raise FGTResponseNotFormedCorrect(err)

def __handle_response_login(self, response):

login_response = self.__handle_login_values(response)

self.dprint("RESPONSE:", login_response[1])

return login_response

def __handle_response_logout(self, response):

self._sid = None

self._req_id = 0

if response.status_code == 200:

self.dprint("RESPONSE:", {"status_code": response.status_code, "message": "Logout Successful"})

return 0, {"status_code": response.status_code, "message": "Logout Successful"}

else:

self.dprint("RESPONSE:", {"status_code": response.status_code, "message": "Logout Failed"})

return -1, {"status_code": response.status_code, "message": "Logout Failed"}

def _handle_response(self, response):

if "logincheck" in self._url:

return self.__handle_response_login(response)

elif "logout" in self._url:

return self.__handle_response_logout(response)

else:

try:

if "text" in response:

if type(response["text"]["results"]) is list:

result = response["text"]["results"][0]

else:

result = response["text"]["results"]

self.dprint("RESPONSE:", result)

if "http_status" in response:

return response["http_status"], result

else:

return response["status"], result

else:

if "http_status" in response:

self.dprint("RESPONSE:", response)

return response["http_status"], response

else:

self.dprint("RESPONSE:", response)

return response["status"], response

except IndexError as err:

self.dprint("Index error in response: {err_type} {err}\n\n".format(err_type=type(err), err=err))

raise FGTResponseNotFormedCorrect(err)

except Exception as e:

print("Response parser error: {err_type} {err}".format(err_type=type(e), err=e))

return -1, e

def _post_request(self, method, url, params):

class InterResponse(object):

def __init__(self):

self.status_code = 200

self.text = "1"

if self.sid is None and "logincheck" not in url:

raise FGTValidSessionException(method, params)

self._update_request_id()

if self.api_key_used:

headers = {"content-type": "application/json",

"Authorization": "Bearer {apikey}".format(apikey=self._passwd)}

self._session.headers.update(headers)

else:

headers = {"content-type": "application/json"}

self._session.headers.update(headers)

try:

if "logincheck" in self._url:

if self.api_key_used:

iresponse = InterResponse()

return self._handle_response(iresponse)

else:

method_to_call = getattr(self._session, method)

json_request = "username={uname}&secretkey={pword}&ajax=1".format(uname=self._user,

pword=self._passwd)

self.dprint("{method} REQUEST: {url} for user {uname} with password {passwd} ".

format(method=method.upper(), url=self._url, uname=self._user, passwd=self._passwd))

response = method_to_call(self._url, headers=headers, data=json_request, verify=self.verify_ssl,

timeout=self.timeout)

elif "logout" in self._url:

if self.api_key_used:

iresponse = InterResponse()

return self._handle_response(iresponse)

else:

self._session.headers = None

method_to_call = getattr(self._session, method)

self.dprint("{method} REQUEST: {url}".format(method=method.upper(), url=self._url, uname=self._user,

passwd=self._passwd))

response = method_to_call(self._url, headers=headers, verify=self.verify_ssl, timeout=self.timeout)

else:

json_request = {}

if params is not None:

json_request = params

method_to_call = getattr(self._session, method)

self.dprint("{method} REQUEST: {url}".format(method=method.upper(), url=self._url), json_request)

response = method_to_call(self._url, headers=headers, data=json.dumps(json_request),

verify=self.verify_ssl, timeout=self.timeout).json()

except ReqConnError as err:

self.dprint("Connection error: {err_type} {err}\n\n".format(err_type=type(err), err=err))

raise FGTConnectionError(err)

except ValueError as err:

self.dprint("Value error: {err_type} {err}\n\n".format(err_type=type(err), err=err))

raise FGTValueError(err)

except KeyError as err:

self.dprint("Key error in response: {err_type} {err}\n\n".format(err_type=type(err), err=err))

raise FGTResponseNotFormedCorrect(err)

except Exception as err:

self.dprint("Response parser error: {err_type} {err}".format(err_type=type(err), err=err))

raise FGTBaseException(err)

return self._handle_response(response)

def login(self):

self._session = requests.session()

login_response = self.post("logincheck")

if login_response[0] == 0:

return login_response

elif login_response[0] == -1 and login_response[1]["message"] == "Two-factor Required":

# todo send a login again after getting the 2FA key

#pass

return login_response

else:

self._sid = None

return login_response

def logout(self):

return self.post("logout")

def __enter__(self):

self.login()

return self

def __exit__(self):

self.logout()

def common_datagram_params(self, url, *args, **kwargs):

self._set_url(url, *args)

params = {}

if kwargs:

keylist = list(kwargs)

for k in keylist:

kwargs[k.replace("__", "-")] = kwargs.pop(k)

params.update(kwargs)

return params

def get(self, url, *args, **kwargs):

# print(self._session.headers)

return self._post_request("get", url, self.common_datagram_params(url, *args, **kwargs))

def post(self, url, *args, **kwargs):

return self._post_request("post", url, self.common_datagram_params(url, *args, **kwargs))

def put(self, url, *args, **kwargs):

return self._post_request("put", url, self.common_datagram_params(url, *args, **kwargs))

def delete(self, url, *args, **kwargs):

return self._post_request("delete", url, self.common_datagram_params(url, *args, **kwargs))

def __str__(self):

if self.sid is not None:

return "FortiOS instance connnected to {host}.".format(host=self._host)

return "FortiOS object with no valid connection to a FortiOS appliance."

def __repr__(self):

if self.sid is not None:

return "{classname}(host={host}, pwd omitted, debug={debug}, use_ssl={use_ssl}, " \

"verify_ssl={verify_ssl}, timeout={timeout})".format(classname=self.__class__.__name__,

host=self._host, debug=self._debug,

use_ssl=self._use_ssl, timeout=self._timeout,

verify_ssl=self._verify_ssl)

return "FortiOS object with no valid connection to a FortiOS appliance."

class CollectIp(object):

def __init__(self, rfile):

super(CollectIp, self).__init__()

self._rfile = rfile

def read_gz_file(self):

block_ips = []

#

if os.path.exists(self._rfile):

reg = re.compile(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')

fin = gzip.open(self._rfile, 'rb')

line = fin.readline('results.csv')

while line:

item = re.findall(reg, line)

if item and len(item) > 0 :

block_ips.append(item[0])

line = fin.readline('results.csv')

fin.close()

else:

logger.info("the file [{file}] is not exist!".format(file=self._rfile))

return block_ips

class InvokeFortigate(object):

def __init__(self, host, gpname, ip_list, forsapi):

super(InvokeFortigate, self).__init__()

self._host = host

self._gpname = gpname

self._ip_list = ip_list

self._forsapi = forsapi

def add_address(self, name, ip):

param={

"json" : {

'name' : name,

'subnet' : ip

}

}

url="/cmdb/firewall/address?vdom=root"

return self._forsapi.post(url, param)

def update_group(self, addr_list):

param={

"json" : {

"member" : addr_list

}

}

url="/cmdb/firewall/addrgrp/{gpname}?vdom=root".format(gpname=self._gpname)

return self._forsapi.post(url, param)

def block(self):

if self._ip_list:

addr_list = []

for ip in self._ip_list:

name="block_{ip}".format(ip=ip.replace(".", "_"))

ip="{ip}/32".format(ip=ip)

#

res = self.add_address(name, ip)

if res[0] == 200:

addr_list.append({'name': name})

else:

logger.info('add [{ip}] to address failure, reason: {reason}'.format(ip=ip, reason=res[1]))

#

#

if addr_list:

gres = self.update_group(addr_list)

if gres[0] == 200:

addr_list.append({'name': name})

else:

logger.info('update address group [{gpname}] failure, reason: {reason}'.format(gpname=self._gpname, reason=gres[1]))

if __name__ == '__main__':

#

host='192.168.1.196'

username='admin'

password='123456'

addrgrp_name='GRP_001'

#

logging.basicConfig(level=logging.DEBUG)

logger = logging.getLogger('block_ip')

#

this_file = inspect.getfile(inspect.currentframe())

dirpath = os.path.abspath(os.path.dirname(this_file))

log_path = os.path.join(dirpath,'block_logs')

if not os.path.exists(log_path):

os.makedirs(log_path)

log_file = os.path.join(log_path,'block_ip.log')

#

handler = logging.handlers.TimedRotatingFileHandler(log_file, "midnight", 1, 30)

formatter = logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s')

handler.setFormatter(formatter)

logger.addHandler(handler)

logger.setLevel(logging.INFO)

logger.info('begin')

#

try:

#results_file = sys.argv[8]

results_file='D:/results.csv.gz'

#

collectip = CollectIp(results_file)

ips = collectip.read_gz_file();

logger.info(ips)

#

forsapi = FortiGate(host, username, password, use_ssl=False)

#

logger.info('login [{host}]'.format(host=host))

rs = forsapi.login()

if(rs[0] == 0):

iforti = InvokeFortigate(host, addrgrp_name, ips, forsapi)

iforti.block()

#

logger.info('logout')

forsapi.logout()

else:

logger.info('login failure')

except Exception as err:

logger.info("error: {error}".format(error=traceback.format_exc()))

logger.info('end')

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值