cancel
Showing results for 
Search instead for 
Did you mean: 

Seeking Assistance with Python Script for Multi-Action Execution in SAC API

pradeep_prakash2
Discoverer

Hello Community,

I'm reaching out for support regarding an issue I'm encountering while trying to trigger a multi-action using Python with the SAC API. Despite extensive research and testing, I've hit a roadblock that I hope someone here can help me resolve.

Background and Research:

  1. SAC API Documentation: I've consulted the official SAC API documentation for details on APIs but found no explicit mention of Python support for multi-actions.
  2. Successful ABAP Implementation: A blog post in SAP Community Blogs shows successful multiAction execution using ABAP, indicating API support in different programming environments.
  3. Execution via Postman: Following SAP KB Article 3407120, I've successfully replicated the multi-action execution using Postman, confirming the viability of necessary API calls.

Python Implementation Challenge: My script successfully runs multi-actions when initiated from Postman to Visual Studio. However, integrating code for obtaining the API token, CSRF token, and building headers for the multi-action endpoint is problematic.

Code Snippets and Output: I'm providing code and execution output (with sensitive data omitted). The issue seems to lie in the headers section of the run_multi_action function, where the session/Bearer/csrf token combination is not accepted. Replacing the run_multi_action header with one from Postman triggers successful script execution.

-----------------------------------------------------------------Actual Code------------------------------------------------------------------------------

import json

import requests

import base64

import os

# Constants

API_OAUTH_CLIENT_ID = '<<Client ID>>'

API_SECRET = '<<secret key>>'

API_URL_BASE = 'https://<<sac tenent URL>>/api/v1/csrf'

API_TOKEN_URL = 'https://<<sac tenent URL>>/oauth/token'

API_MULTIACTION_URL = "https://<<sac tenent URL>>/executions"

AUTH_URL = 'https://<<sac tenent URL>>/oauth/authorize'

def get_api_token():

"""Retrieve the API token."""

print("get_api_token: started")

auth = f'{API_OAUTH_CLIENT_ID}:{API_SECRET}'

token_headers = {

'Authorization': f'Basic {base64.b64encode(auth.encode()).decode()}',

'Content-Type': 'application/json'

}

params = {'grant_type': 'client_credentials'}

try:

response = requests.post(API_TOKEN_URL, headers=token_headers, params=params)

data = json.loads(response.content.decode('utf-8'))

api_token = data['access_token']

print(len(api_token))

return response.json()

except requests.RequestException as e:

print(f"Error getting API token: {e}")

return None

def get_crsf_token(api_token):

"""Get the CSRF token."""

headers = {

'Authorization': f'Bearer {api_token}',

'x-sap-sac-custom-auth': 'true',

'x-csrf-token': 'fetch'

}

try:

response = requests.get(API_URL_BASE, headers=headers)

response.raise_for_status()

return response

except requests.RequestException as e:

print(f"Error getting CSRF token: {e}")

return None

def run_multi_action(api_token, csrf_token, csrf_cookies):

"""Run a multi-action with the provided tokens and cookies."""

headers = {

'x-csrf-token': csrf_token,

'Content-Type': 'application/json',

'Authorization': f'Bearer {api_token}',

'Cookie': f'signature; JSESSIONID={csrf_cookies["JSESSIONID"]}; __VCAP_ID__={csrf_cookies["__VCAP_ID__"]}'

}

payload = json.dumps({"parameterValues": []})

print("Sending request to:", API_MULTIACTION_URL)

print("Headers:", headers)

print("Payload:", payload)

try:

response = requests.post(API_MULTIACTION_URL, headers=headers, data=payload)

response.raise_for_status()

return response.text

except requests.RequestException as e:

error_message = f"Request Exception: {e}"

if hasattr(e, 'response'):

error_message += f"\nResponse: {e.response.text}\nStatus Code: {e.response.status_code}"

print(error_message)

return None

def main():

"""Main function to execute the script logic."""

print("Script started")

api_token_info = get_api_token()

if not api_token_info:

print("Failed to get API token")

return

api_token = api_token_info['access_token']

print(f"Token Length: {len(api_token)}")

csrf_response = get_crsf_token(api_token)

if not csrf_response:

return

csrf_token = csrf_response.headers['x-csrf-token']

csrf_cookies = csrf_response.cookies

multi_action_response = run_multi_action(api_token, csrf_token, csrf_cookies)

if multi_action_response:

print(multi_action_response)

if __name__ == "__main__":

main()

-----------------------------------------------------------------Code End------------------------------------------------------------------------------

Output

Script started
get_api_token: started
2038
Token Length: 2038
Sending request to: <<sac tenent URL>>/api/v1/multiActions/t.cfgsd50/executions
Headers: {'x-csrf-token': '<<csrf_token>>', 'Content-Type': 'application/json', 'Authorization': 'Bearer <<bearer_token>>', 'Cookie': 'signature; JSESSIONID=<<session_id>>; __VCAP_ID__=<<vcap_id>>'}
Payload: {"parameterValues": []}
Request Exception: 401 Client Error: Unauthorized for url: <<sac tenent URL>>/api/v1/multiActions/<<multiaction_id>>/executions
Response: Unauthorized
Status Code: 401

New Challenge with Bearer Token:

  • Token Length Discrepancy: The Bearer token response in Python is truncated at 2038 characters, whereas tokens from Postman are approximately 2082 characters long. I'm puzzled about why this discrepancy is occurring with Python.

Steps Taken to Investigate:

  1. Verification Script: I created a small script to check the Bearer token length, which confirmed the 2038 character.
  2. Cross-Usage Test: Using the Python-generated Bearer token in a Postman script worked, indicating the token is valid despite its shorter length.
  3. Cookie Analysis: Initially suspecting the cookie, I observed it's a constant in our Postman code. Hardcoding this cookie in my Python code worked only while the Postman session was active. Once inactive (after 60 mins), it resulted in an Unauthorized error.
  4. Removing Cookie from Headers: Excluding the cookie from headers in Python led to an Unauthorized error.
  5. Comparing Cookie Behavior: In Postman, the cookie appears when calling the CSRF token, but not in Python. Hardcoding the Postman cookie in the Python script for the CSRF token had the same limited success as before - it worked only while the Postman session was active.

Specific Problem: The headers section in the run_multi_action function seems to be the issue. When using headers from Postman, the script works, but not with the generated headers in Python.

Request for Assistance: Could anyone provide insights or suggestions on how to correctly format or authenticate the headers in Python for successful multi-action execution? Any help or guidance would be greatly appreciated.

Accepted Solutions (0)

Answers (0)