FortiSASE API cURL script
As FortiSASE currently lacks an official public API, I thought I'd share a little bash-script I just wrote that uses cURL to login to FortiSASE via SAML/SSO and can then access the backend REST(ish)-API used by the FortiSASE portal natively.
I needed this to automate the process of adding ZTNA destinations as part of our customers build pipeline.
Please ignore the ugly grep/sed's and just see this as proof-of-concept code for inspiration.
Also be aware that as the API is currently not documented or intended to be used by end customers, I assume Fortinet will not give you any support if you experience problems with the API, so please use this code on your own risk.
#!/bin/bash ################################################################################# # CURL snippet to use SAML IAM Login to FortiSASE to consume it's REST API. ################################################################################# curl_opts="-s --cookie-jar saseCookieFile --cookie saseCookieFile --insecure" fortisase_baseurl="https://portal.prod.fortisase.com" fortisase_loginurl="https://portal.prod.fortisase.com/saml/ssoLogin" fortisase_apiloginurl="https://portal.prod.fortisase.com/api/v1/system/login/sso" fortisso_baseurl="https://customersso1.fortinet.com" fortisso_loginurl="https://customersso1.fortinet.com/saml-idp/iam_login/" forti_account="123456" forti_username="firstname.lastname" forti_password="xxxxx" # Delete old Cookie-file: rm saseCookieFile &> /dev/null # Get FortiSASE pre-login page and save SAMLRequest: echo "GET ${fortisase_baseurl}/pre-login" saml_loginurl=$(curl -i ${curl_opts} ${fortisase_baseurl}/pre-login | grep Location | sed "s/Location: //g" | tr -d $'\r') saml_request=$(echo "${saml_loginurl}" | sed 's/^.*\?SAMLRequest=/\?SAMLRequest=/') # Get SAML pre-login page and save sessionid Cookie: echo "GET ${saml_loginurl}" curl ${curl_opts} ${saml_loginurl} &> /dev/null # Get Fortinet IAM Login page and save CSRFTOKEN in login form: echo "GET ${fortisso_loginurl}/?SAMLRequest=xxxx" res=$(curl ${curl_opts} ${fortisso_loginurl}/${saml_request}) csrftoken=`echo "${res}" | grep csrfmiddlewaretoken | awk -F '"' '{print $6}' ` # Perform Forinet IAM SAML Login and save SAMLResponse: echo "POST ${fortisso_loginurl}" data="csrfmiddlewaretoken=${csrftoken}&next=/saml-idp/portal/&account=${forti_account}&username=${forti_username}&password=${forti_password}" res=$(curl ${curl_opts} --location --referer ${fortisso_baseurl} --data ${data} ${fortisso_loginurl}${saml_request}) saml_response=`echo "${res}" | grep SAMLResponse | awk -F '"' '{print $6}'` # Perform SAML SSO Login to FortiSASE to get x-auth-token Cookie: echo "POST ${fortisase_loginurl}" res=$(curl -i ${curl_opts} --location --referer ${fortisso_baseurl} --data-urlencode RelayState= --data-urlencode SAMLResponse=${saml_response} ${fortisase_loginurl}) xauthtoken=$(echo "${res}" | grep x-auth-token | sed -n 's/.*=\([^;]*\);.*/\1/p') # Parse SAMLResponse and create API Login JSON data: echo "Parse SAMLResponse and generate JSON Login data" saml_decoded=$(echo "${saml_response}" | base64 -d | xmllint --format -) iam_account_alias=$(echo "${saml_decoded}" | grep -A1 IAM_account_alias | sed -n 2p | sed -n 's/.*>\(.*\)<.*/\1/p') iam_account_name=$(echo "${saml_decoded}" | grep -A1 IAM_account_name | sed -n 2p | sed -n 's/.*>\(.*\)<.*/\1/p') iam_user_name=$(echo "${saml_decoded}" | grep -A1 IAM_username | sed -n 2p | sed -n 's/.*>\(.*\)<.*/\1/p') nameID=$(echo "${saml_decoded}" | grep -A1 idp_user_id | sed -n 2p | sed -n 's/.*>\(.*\)<.*/\1/p') data=' { "auth_type": "iam", "authentication_status": "password only", "company": { "name": "" }, "iam_account_alias": "IAM_ACCOUNT_ALIAS", "iam_account_name": "IAM_ACCOUNT_NAME", "iam_user_name": "IAM_USER_NAME", "name": "IAM_USER_NAME", "nameID": "NAMEID", "principal": "IAM_USER_NAME", "root": false, "tenant": { "account_id": "IAM_ACCOUNT_NAME", "root_principal": "IAM_ACCOUNT_NAME" } }' data=$(sed "s/IAM_ACCOUNT_ALIAS/$iam_account_alias/g" <<< "$data") data=$(sed "s/IAM_ACCOUNT_NAME/$iam_account_name/g" <<< "$data") data=$(sed "s/IAM_USER_NAME/$iam_user_name/g" <<< "$data") data=$(sed "s/NAMEID/$nameID/g" <<< "$data") # Login to FortiSASE API to get access and refresh tokens: echo "POST ${fortisase_apiloginurl}" response=$(curl ${curl_opts} --referer ${fortisase_baseurl}/sso-login -H "auth-token: ${xauthtoken}" -H "Content-Type: application/json" -d "${data}" ${fortisase_apiloginurl}) access_token=$(echo "${response}" | jq -r .data.access_token) refresh_token=$(echo "${response}" | jq -r .data.refresh_token) # Perform API to get list of ZTNA destinations: curl -s -H "Authorization: Bearer ${access_token}" https://portal.prod.fortisase.com/endpoint/fct/api/public/v1/sase_to_ems/profiles/ztna/2/get | jq .
