Technical Articles
How to consume the Credential store with python
For those interested in a secure repository for passwords and keys for applications running on SAP Business Technology Platform, the Credential store is the way to go. This blog describes very well how to set up the service
The aim of this post is to explain how to consume this service with Python 3. The blog mentioned above describes how to consume the service with Node.js. You can find in the official how to consume it with Java, Javascript, Swift, Curl, ABAP and SAPUI5. A GoLang sample is also available in this other . Almost all languages but Python.
and we don’t want these written in plain text
The core python libraries are and , which have Apache 2-0 and MIT license respectively.
All of what follow could be written nicely in a function but I want to emphasise what do what.
Initialisation
After creating the service mycreds
(free plan), we add in the namespace test
the password Azerty
for id_conn
.
Let’s start with the libraries:
import json
from cfenv import AppEnv
from jose import jwe
import requests
from requests.auth import HTTPBasicAuth
env = AppEnv()
creds = env.get_service(name="mycreds") #name of the Cred.Store service
id_conn
.
headers = {'Accept': 'application/json',
'Content-Type': 'application/jose',
'DataServiceVersion': '2.0',
'If-None-Match': '',
'sapcp-credstore-namespace': 'test'} # name of the namespace
response = requests.get(creds.credentials.get('url')+"/password?name=id_conn",
headers=headers,
auth=HTTPBasicAuth(creds.credentials.get("username"),
creds.credentials.get("password"))
)
The response is a JSON Web Encryption (JWE) with a four parts structure: Header, Encrypted Key, Ciphertext and the JWE Integrity Value.
The first part of the JWE will tell you something like
{ "alg": "RSA-OAEP-256", "enc": "A256GCM", "iat": 1631885785 }
The message encryption is implemented via symmetric encryption using Advanced Encryption Standard (AES), Galois Counter Mode (GCM) with 256 bit key size. The encryption of keys is supported using RSA Optimal Asymmetric Encryption Padding (OAEP).
The private key is given in the parameters but one needs to run some transformations before using it: first add header and footer and then convert in bytes:
private = creds.credentials.get("encryption",{}).get("client_private_key")
private_key = ("-----BEGIN PRIVATE KEY-----\n" +
private +
"\n-----END PRIVATE KEY-----")
private_key = private_key.encode()
Finally, one can decode the message and get the password
cred = jwe.decrypt(response.content, private_key)
cred = json.loads(cred.decode())
pwd= cred.get("value")
Another key can be useful : cred.get("modifiedAt")
which indicates the last modification.
Test
If you want to “see” the password in a web application, you can encapsulate the code in this script
# -*- coding: utf-8 -*-
import os
from flask import Flask
### Add the previous lines here ####
@app.route("/")
def locale():
return pwd
if __name__ == "__main__":
app.run(host='0.0.0.0', port=port)
You should get :
Conclusion
As you can see, it’s pretty easy to store and consume a password in a secured manner using this service. We have not cover the other functionalities here (like updating a password) but the main difficulties, from my point of view, are to know which python library to use for the encryption and how to format the API call. If some people are interested, I may write a follow up for the other functionalities.
That’s all for today !
Great Article Yann Miquel .. Keep writing many more...
Thanks Yogananda !
I am trying to refer below link to access username and password, part of credential store in BTP.
https://blogs.sap.com/2021/09/19/how-to-consume-the-credential-store-with-python/
Getting error for following :
cred = jwe.decrypt(response.content , private_key)
Error :
alg: RSA-OAEP-256 is not supported by the RSA backend.
Although, same thing working locally very fine but giving above error when trying to run on BTP space CF APP.
Local output :
>>> from jose import jwe
>>> jwe.decrypt(response_content, private_key)
b'{"id":"8XXXXXXX5","name":"dbXXXXe","modifiedAt":"2022-07-21T15:32:00.687Z","value":"ok######","status":"enabled","username":"L######","type":"password"}'>>>
Please suggest. if i am missing to add any modules in requirement.txt or any other change.
Thanks
Hi Awadhesh Kumar Gupta,
If only these two libraries are installed :
one get the error you describe.
To avoid the error, one must add a third library in the requirement to impose the cryptographic algo
This third one comes with Spyder so I didn't notice the importance of this one until I look attentively to your comment.
Why python_jose has added the RSA-OAEP-256 in the unsupported list is obscure for me yet. I will have a look.
Did you find some information about it since you noticed the error ?
Regards,
Yann