I have 3 files/certificates:
I need to send a POST request to the bank attaching all these 3 certificates to these url:
This is my code:
import requests
url = 'https://ecomm.pashabank.az:18443/ecomm2/MerchantHandler'
data = { # for example
"command": "v",
"amount": "1",
"currency": "932",
"client_ip_addr": "167.172.184.123",
"msg_type": "SMS"
}
cert_file = "certificate.0025598.der"
key_file = "certificate.0025598.pem"
psroot = "PSroot.pem"
certs = (cert_file, key_file, psroot)
response = requests.post(url, cert=certs)
But it doesn't work, giving this error:
raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='ecomm.pashabank.az', port=18443): Max retries exceeded with url: /ecomm2/MerchantHandler (Caused by SSLError(SSLError(9, '[SSL] PEM lib (_ssl.c:4027)')))
Maybe I am attaching certificates incorrectly? Please help!
I wanted to send the request via Postman, but I also failed there. Could you explain how to do that?
make sure your cert is format in pem.
pass the filename to param cert (or file path, which means your pem file is in current directory)
https://requests.readthedocs.io/en/latest/user/advanced/?highlight=cert#client-side-certificates
Related
Set-up
I use the following Python code to log-in to a Adobe Commerce test environment via the Rest API,
import requests
host = 'https://b2b.test.163.com.pl'
store_code = 'PL_B2B_PL'
# Set the API endpoint for getting a customer token
endpoint = host + "/rest/" + store_code + "/V1/integration/customer/token"
# Set the credentials for the login request
credentials = {
"username": "myusername",
"password": "mypassword"
}
# Send a POST request to the login endpoint with the credentials
response = requests.post(endpoint, json=credentials, headers={"Content-Type": "application/json"})
# Check the response status code to see if the request was successful
if response.status_code == 200:
# Get the customer token from the response
customer_token = response.text
# Use the customer token in the Authorization header of subsequent API requests
headers = {
"Authorization": f"Bearer {customer_token}"
}
else:
# Handle the error response if the request was unsuccessful
print(f"Request failed: {response.text}")
Issue
Running the above code yields the following error,
ConnectionError: HTTPSConnectionPool(host='b2b.test.163.com.pl', port=443): Max retries exceeded with url: /rest/PL_B2B_PL/V1/integration/customer/token (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7f7b718ed880>: Failed to establish a new connection: [Errno 60] Operation timed out'))
Question
How do I correctly connect to the test environment?
I think this code should've worked, but clearly I am wrong.
I'm trying to request data from endpoints, I can do that with curl -k --key a-key.pem --cert a.pem https://<endpoint>
But when I using python3 to do that, I failed every time
Examples:
With curl:
root#control-plane-0:~# curl -k --key /etc/kubernetes/a-key.pem --cert /etc/kubernetes/a.pem https://127.0.0.1:6443/api/
{
"kind": "APIVersions",
"versions": [
"v1"
],
"serverAddressByClientCIDRs": [
{
"clientCIDR": "0.0.0.0/0",
"serverAddress": "10.0.31.2:6443"
}
]
}
With python:
(code):
from flask import Flask, render_template
import requests
from ast import literal_eval
app = Flask(__name__)
#app.route('/metrics')
def metrics():
data = requests.get("https://127.0.0.1:6443/api/, cert=('/etc/kubernetes/a.pem', '/etc/kubernetes/a-key.pem'))
print(data)
return data
if __name__ == '__main__':
app.run(host='0.0.0.0',port="5001", debug=True)
Result:
r = adapter.send(request, **kwargs)
File "/usr/local/lib/python3.9/site-packages/requests/adapters.py", line 514, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='127.0.0.1', port=6443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1121)')))
Are there any problems with requests libs ?
I can't find a way to make it work
Have you got your certificates verified using
openssl verify -CAfile your-cert.pm
I got the same Problem and solved by using full-chain certificates.please see your certificate contains fullchain(root,intermediate).
And you can try like
import requests
test=request.get("url",verify="certificate-with-path")
I'm trying to pull data from an API which is secured by SSL. I wrote a python script to pull the data. Beforehand I have to convert a .p12 file to an openSSL certificate. When I use the following code it works just fine:
# ----- SCRIPT 1 -----
def pfx_to_pem(pfx_path, pfx_password):
''' Decrypts the .pfx file to be used with requests. '''
with tempfile.NamedTemporaryFile(suffix='.pem') as t_pem:
f_pem = open(t_pem.name, 'wb')
pfx = open(pfx_path, 'rb').read()
p12 = OpenSSL.crypto.load_pkcs12(pfx, pfx_password)
f_pem.write(OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, p12.get_privatekey()))
f_pem.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, p12.get_certificate()))
ca = p12.get_ca_certificates()
if ca is not None:
for cert in ca:
f_pem.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert))
f_pem.close()
yield t_pem.name
# read some config
with open('config.json') as config_json:
config = json.load(config_json)
api_url = config['api_url']
cert = config['cert']
cert_pem_path = cert['file']
cert_key_file = cert['pass']
# make the request
with pfx_to_pem(cert_pem_path, cert_key_file) as cert:
r = requests.get(api_url, cert = cert)
Because I'm also using the same functionality to authenticate my Flask web service towards the server I split up the cert file into three files:
# ----- SCRIPT 1 -----
# get certificate
f_pem.write(OpenSSL.crypto.dump_certificate(
OpenSSL.crypto.FILETYPE_PEM, p12.get_certificate())
)
# get keyfile
f_key.write(OpenSSL.crypto.dump_privatekey(
OpenSSL.crypto.FILETYPE_PEM, p12.get_privatekey())
)
# get CA_BUNDLE
ca = p12.get_ca_certificates()
if ca is not None:
for cert in ca:
f_ca.write(
OpenSSL.crypto.dump_certificate(
OpenSSL.crypto.FILETYPE_PEM, cert
))
Then I'm running the web service with the following code:
# ----- SCRIPT 2 -----
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
context.verify_mode = ssl.CERT_REQUIRED
context.load_verify_locations(cert_ca)
context.load_cert_chain(cert_pem, cert_key)
app.run(ssl_context = context, host = '0.0.0.0')
and changed the requests call to
# ----- SCRIPT 1 -----
r = requests.get(api_url, cert = (cert_pem, cert_key), verify = cert_ca)
When trying to pull data from the API I get the error
requests.exceptions.SSLError: HTTPSConnectionPool(host='some.host', port=443): Max retries exceeded with url: /some/path/var?ID=xxxxxx (Caused by SSLError(SSLError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:847)'),))
Question 1: What am I doing wrong creating the CA_BUNDLE?
Question 2: Am I handling the creation of the web service correctly? My goal is to verify my server against the server holding the data to eventually be able to receive the data by push request.
EDIT: when connecting to my web service (in a browser) I receive the warning that the connection is not secure, because the certificate is not valid, despite the fact that I imported the .p12 certificate into my browser.
So I'm using the request and json library to call API, in my case I can set-up the request to ignore the certificate and this quickly solved my issue
requests.get(url, headers=headers, verify=False)
the argument verify=False ignore the certificate but when you run your code it will show a warning message as output saying that the certificate is wrong, so you can add this other piece of code to don't get request warning showed:
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
I know that doesn't answer your question but maybe you can try to see if without certificate you are able to get information without problem.
I have generated following self-signed certificates for my server and client.
I have created ca.crt & ca.key. Using ca.crt & ca.key, I have created server.crt, server.key for server and client.crt, client.key for client respectively.
I am using python requests library as client. Below is the code snippet:
import json
import requests
cert = ("/home/tests/certs/client.crt",
"/home/tests/certs/client.key")
class TestCart():
def test_cart(self, **kwargs):
url = "https://192.168.X.Y/cart"
cart_data = {
'id': kwargs.get('id'),
'items': kwargs.get('items')
}
req_data = json.dumps(cart_data)
resp = requests.post(url,
data=req_data,
verify="/home/certs/ca.cert",
cert=cert)
print resp.text
if __name__ == '__main__':
t_cart = TestCart()
data = {'id': 'ba396e79-0f0f-4952-a931-5a528c9ff72c', 'items': []}
t_cart.test_cart(**data)
This gives exception:
requests.exceptions.SSLError: HTTPSConnectionPool(host='192.168.X.Y',
port=443): Max retries exceeded with url: /cart (Caused by
SSLError(SSLError(1, u'[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify
failed (_ssl.c:590)'),))
If I use verify=False, code works, but I want to verify. What should be the value of verify in my request ?
It is highly recommended to have a deeper look at the excellent documentation for requests. It has a special chapter about SSL Cert Validation which explains:
You can pass verify the path to a CA_BUNDLE file or directory with certificates of trusted CAs:
>>> requests.get('https://github.com', verify='/path/to/certfile')
Assuming that your server certificate was signed by your ca.crt you should use this for the verify parameter.
EDIT: based on the discussion it looks like that CA and server certificate used the same subject. This means that the certificate validation assumes that this is a self-signed certificate which thus results in an certificate validation error.
I am trying to use Twilio in pythonanywhere and I know I need a proxy to make it work. My code looks like this:
class ProxiedTwilioHttpClient(HttpClient):
"""
General purpose HTTP Client for interacting with the Twilio API
"""
def request(self, method, url, params=None, data=None, headers=None, auth=None, timeout=None,
allow_redirects=False):
session = Session()
session.verify = get_cert_file()
session.proxies = {
"https" : "https://52.14.161.178:3128"
}
request = Request(method.upper(), url, params=params, data=data, headers=headers, auth=auth)
prepped_request = session.prepare_request(request)
response = session.send(
prepped_request,
allow_redirects=allow_redirects,
timeout=timeout,
)
return Response(int(response.status_code), response.content.decode('utf-8'))
def send_sms(phone, content):
client = Client(api_key, api_secret, account_sid, http_client=ProxiedTwilioHttpClient())
message = client.messages.create(
to=phone,
from_="+19999999999", #of course I use the correct one
body=content)
return(message.sid)
But then it returns the following error:
.virtualenvs/sms/local/lib/python2.7/site-packages/requests/adapters.py",
line 502, in send raise ProxyError(e, request=request) requests.exceptions.ProxyError:
HTTPSConnectionPool(host='api.twilio.com', port=443):
Max retries exceeded with url: /2010-04-01/Accounts/XXXXXXXXX/Messages.json (Caused by ProxyError('Cannot connect to proxy.',
NewConnectionError('<urllib3.connection.Verif iedHTTPSConnection object at 0x7fa41a55e090>:
Failed to establish a new connection: [Errno 111] Connection refused',)))
I am using the following answer that seems to work for others: https://stackoverflow.com/a/43608637/7298530
How can I solve it?
You're specifying that your code should use a proxy at https://52.14.161.178:3128. That won't work on PythonAnywhere, you need to use the proxy that the service provides. To find out what address to use for that, start a Bash console and run
echo $http_proxy
[2018 edit] We now have a specific page on getting twilio to work with the pythonanywhere proxy