I installed Python and co-req packaged on my z/OS system, described here. I wanted to run a REST workload into z/OSMF. I could have used, Liberty, z/OS Connect or MQWEB as the backend.
It makes use of the python requests package.
Initial script
#!/usr/bin/env python3
import requests
from timeit import default_timer as timer
import urllib3
my_header = {
'Connection': 'keep-alive',
'Content-Type': 'application/json',
'Cache-Control': 'max-age=0',
'Authorization': 'Basic Y395aW46cGFu67GhlMG4=',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'en-GB,en;q=0.5',
'DNT': '1',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
'Cache-Control': 'max-age=0'
}
urllib3.disable_warnings()
geturl ="https://10.1.1.2:29443/zosmf/rest/mvssubs?ssid=IZUG"
jar = requests.cookies.RequestsCookieJar()
start=timer()
res = requests.get(geturl,headers=my_header,verify=False,cookies=jar)
end=timer()
print("duration=",end-start)
if res.status_code != 200:
print(res.status_code)
print("Output=",res.text)
jar= res.cookies
Comments on the python script
- Authorization’: ‘Basic Y395aW46cGFu67GhlMG4=’ is the 64 bit encoding of the userid and password. Which is trivial(!) to decode.
- urllib3.disable_warnings() Without this set you get a message InsecureRequestWarning: Unverified HTTPS request is being made to host ‘10.1.1.2’. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings. This is because the certificate sent down from the server has not been validated.
- jar= res.cookies says save the cookies into the jar dictionary, for future use
The output was
duration= 1.210928201675415
output= {“items”:[
{“subsys”:”IZUG”, “active”:true, “dynamic”:true, “funcs”:[10]}
],”JSONversion”:1}
Verifying TLS certificate
With urllib3.disable_warnings() present it will cause error warnings to be suppressed.
When this statement is not present, there will be warnings about certificate problems.
In the statement res = requests.get(geturl,headers=my_header,verify=False,cookies=jar) verify is either “False” or the name of a CA .pem file containing the CA certificates. I used verify=ABC and got
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed:
I got the error because “ABC” is not a valid file, and the verification could not be done.
I exported the CA certificate used by the server using
RACDCERT CERTAUTH EXPORT(LABEL('TEMP-CA')) - DSN('IBMUSER.CERT.TEMP.CA.PEM') - FORMAT(CERTB64) - PASSWORD('password')
I could only get verify=…. to work with a USS file, so I had to copy the dataset IBMUSER.CERT.TEMP.CA.PEM into a USS file CACert.pem. Then when I used
res = requests.get(geturl,headers=my_header,verify=CACert.pem,cookies=jar)
it worked fine.
Using a client certificate.
You cannot use RACF certificate with the requests facility, because the underlying code does not support it. You have to use .pem style certificate.
The support does not allow you to specify a password for the private key, so this is not very secure.
You define
cf=”colinpaicesECp256r1.pem”
kf=”colinpaicesECp256r1.key.pem”
cpcert=(cf,kf)
where
- cf is the name of the file with the certificate in it
- kf is the name of the file with the private key in it
- cpcert is the python tuple.
If your certificate file also includes the private key, you do not need the kf, just use cpcert=(cf).
You use it
res = requests.get(geturl,headers=my_header,verify=CACert.pem,cookies=jar,cert=cpcert)
I tried exporting a certificate from z/OS using RACDCERT EXPORT … format(PKCS12B64), copying it to a uss file, and using that, but it did not work. The file could not be read.
I tried creating a private key with a password (to make it more secure) but when I used it I got the message
urllib3.exceptions.SSLError: Client private key is encrypted, password is required
There is a package request_pkcs12 which provides support for a password on the certificate. https://github.com/m-click/requests_pkcs12. I did not use this, I recreated my certificate and private key without a password.
I tried running on Linux using my Hardware Security Module (which plugs into a USB socket). This also failed as I could not enter the PIN for the device.
Compare the response time to running across the network.
I ran the same python script on z/OS and on Linux. The round trip time of the rest request was
- 1.41 seconds on z/OS
- 0.92 seconds on Linux.
I think I’ll run my tests from Linux in future.