cancel
Showing results for 
Search instead for 
Did you mean: 
Read only

Python Odata Error with Cloud Connector

irubioaxpo
Discoverer
0 Likes
1,196

I've built a simple demo program to consume OData from a Python program in the Cloud Foundry Environment, i've followed some posts about the topic (maybe a little bit old but still valid i guess):
https://community.sap.com/t5/technology-blogs-by-sap/part-2-how-to-use-sap-cloud-platform-connectivi...

https://community.sap.com/t5/technology-blogs-by-members/exposing-on-premise-data-to-sap-cloud-found...

Attached you'll see the basic code (basic_code.py) i'm using to make the call to the OData service from an On-premise S4Hana system, in the program code appears all the steps to reach from Cloud Foundry the OData service but the final step is failing with this error: "Response from Step 5: Access denied to system <system_id>:443. In case this was a valid request, ensure to expose the system correctly in your cloud connector.Status code: 403"


As far as i see in google the problems seems to be related with the cloud connector, but i'm having problems to see where's exactly the problem, here are some things and info about the destination on BTP and the cloud connector configuration:

-- Destination in BTP: Seems to be fine as works from BAS terminal if i execute the command: "curl <Destination Name>.dest/sap/opu/odata/sap/API_BUSINESS_PARTNER/A_AddressEmailAddress?$format=json"

irubioaxpo_1-1722253849316.png

-- Cloud Connector Config:

irubioaxpo_2-1722255439715.png

My main problem is my lack of knowledge on Cloud Connector, from the program and through the proxy of the connection service i use the virtual host with the corresponding OData path using the proper credentials.

I've checked this note but i don't see any problem in the CC config, so there's no conflict as the subaccount is unique and the location ID used it's also unique.

So the question in this case would be What's the problem?

Also as a side question i would like to use the pyOdata library for this case but i'm not sure how to do it properly once the prior issue is solved.

Any suggestion will be welcome and of course if some other info is required please let me know.

Thanks a lot.

Best Regards.

logging.info("-------------------Step 1: Read the environment variables--------------------")
env = AppEnv()
uaa_service = env.get_service(name='xsuaa-demo-app')
dest_service = env.get_service(name='destination-demo-app')
conn_service = env.get_service(name='connectivity-demo-app')

#logging.info(f"CONNECTIVITY: {conn_service}")
sUaaCredentials = dest_service.credentials["clientid"] + ':' + dest_service.credentials["clientsecret"]
sDestinationName = 'DS4_450_CLONING'
sUaaCredentials_bytes = sUaaCredentials.encode('utf-8')
encoded_credentials = base64.b64encode(sUaaCredentials_bytes).decode('utf-8')
logging.info("------------------Step 2: Request a JWT token to access the destination service----------------------")
headers = {'Authorization': 'Basic '+encoded_credentials, 'content-type': 'application/x-www-form-urlencoded'}
form = [('client_id', dest_service.credentials["clientid"] ), ('grant_type', 'client_credentials')]

r = requests.post(uaa_service.credentials["url"] + '/oauth/token', data=form, headers=headers)

logging.info("-------------------Step 3: Search your destination in the destination service---------------------")
token = r.json()["access_token"]
headers= { 'Authorization': 'Bearer ' + token }
r = requests.get(dest_service.credentials["uri"] + '/destination-configuration/v1/destinations/'+sDestinationName, headers=headers)
#logging.info(f"Response from Step 3 --- DESTINATION ---: {r.json()}")
destination = r.json()

logging.info("-------------------Step 4: Request a JWT token to access the connectivity service---------------------")
#create authorization with basic authentication using connectivity credentials as base64 format
conn_sUaaCredentials = conn_service.credentials["clientid"] + ':' + conn_service.credentials["clientsecret"]

conn_sUaaCredentials_bytes = conn_sUaaCredentials.encode('utf-8')
conn_encoded_credentials = base64.b64encode(conn_sUaaCredentials_bytes).decode('utf-8')

headers = {'Authorization': 'Basic '+ conn_encoded_credentials, 'content-type': 'application/x-www-form-urlencoded'}
#create formdata with client ID and grant type
formdata = [('client_id', conn_service.credentials["clientid"] ),('client_secret', conn_service.credentials["clientsecret"] ), ('grant_type', 'client_credentials')]

#call the xsuaa service to retrieve JWT
response_conn = requests.post(uaa_service.credentials["url"] + '/oauth/token', data=formdata, headers=headers)

logging.info("-------------------Step 5: Make a call to backend system via SAP CC to read data---------------------")

onpremise_auth = requests.auth.HTTPBasicAuth(destination["destinationConfiguration"]["User"] , destination["destinationConfiguration"]["Password"])

# read the On premise proxy host and on premise proxy port for the connectivity service
proxy_url = conn_service.credentials["onpremise_proxy_host"] + ':' + conn_service.credentials["onpremise_proxy_port"]   
logging.info(f"Proxy URL: {proxy_url}")

#Enter the exact path to your OData service in the SAP System using the virtual host:port details mentioned in the SAP Cloud Connector
url_cc = destination['destinationConfiguration']['URL'] + '/sap/opu/odata/sap/EPM_REF_APPS_SHOP_SRV/Products'
logging.info(f"URL CC: {url_cc}")

#create a dict with proxy relevant information
proxyDict = { 'http' : proxy_url }

# Get JWT token
jwt_conn = response_conn.json()["access_token"]

#create a header with authorization to the proxy server with the JWT retrieved in Step 2
headers = {
'content-type': 'application/json',
'Proxy-Authorization': 'Bearer ' + jwt_conn,
'cache-control': 'no-cache'
}

token = destination["authTokens"][0]

data_response = requests.get( url_cc, proxies=proxyDict, headers=headers, auth = onpremise_auth)
#conver the data 
logging.info(f"Response from Step 5: {str(data_response.text)}")
logging.info(f"Status code: {str(data_response.status_code)}")

 

 

 

Accepted Solutions (0)

Answers (0)