Python client certicate request fails on Ubuntu - python-requests

I have the following minimal file:
import requests
index_response = requests.get("https://my.end.point.com/", cert="mypem.pem")
print(index_response.status_code)
Windows Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)] on win32 gives a response of 200
Ubuntu Python 2.7.15 (default, Jun 3 2019, 14:08:52) [GCC 4.8.4] on
linux2 gives a response of 403
Both use Python 2.7.15 and there's no error displayed, so I’m not clear on where to start looking. I appreciate this isn’t an easily reproducible example; if there are any example PEM/endpoints I can use, I’d be happy to edit my question.

First, as #wowkin2 mentioned, make sure you use the same versions of requests and urllib3 on your two computers. I'm using requests==2.22.0 and urllib3==1.25.7 here.
And please consider switching to Python 3, Python 2 support ends in January 2020.
OK, so if you have the same versions but still see the issue, let's try to debug it by first using another client certificate. badssl.com is a TLS test service who provides such a client certificate. Testing with badssl.com is more complicated than it should be because it uses a password and requests does not support that out of the box, but here's how you can do it:
import requests
from requests.adapters import HTTPAdapter
from urllib3.poolmanager import PoolManager
class ClientCertPasswordAdapter(HTTPAdapter):
def __init__(self, password):
self.password = password
super(ClientCertPasswordAdapter, self).__init__()
def init_poolmanager(self, connections, maxsize, block=False):
self.poolmanager = PoolManager(
num_pools=connections,
maxsize=maxsize,
block=block,
key_password=self.password,
)
print("fetching client certificate")
with open("client.pem", "wb") as f:
r = requests.get("https://badssl.com/certs/badssl.com-client.pem")
f.write(r.content)
print("requesting data")
s = requests.Session()
s.mount("https://client.badssl.com/", ClientCertPasswordAdapter("badssl.com"))
r = s.get("https://client.badssl.com/", cert="client.pem")
print(r.status_code)
Does this print 200 for your two OSes? This would allow to rule out an issue in your certificate.
Another test you can make is to use your client certificate and give it to a server that won't verify it but will print you the public information it received. I'm sending the badssl.com client certificate here:
import requests
from requests.adapters import HTTPAdapter
from urllib3.poolmanager import PoolManager
class ClientCertPasswordAdapter(HTTPAdapter):
def __init__(self, password):
self.password = password
super(ClientCertPasswordAdapter, self).__init__()
def init_poolmanager(self, connections, maxsize, block=False):
self.poolmanager = PoolManager(
num_pools=connections,
maxsize=maxsize,
block=block,
key_password=self.password,
)
print("fetching client certificate")
with open("client.pem", "wb") as f:
r = requests.get("https://badssl.com/certs/badssl.com-client.pem")
f.write(r.content)
print("requesting data")
s = requests.Session()
s.mount("https://server.cryptomix.com/", ClientCertPasswordAdapter("badssl.com"))
r = s.get("https://server.cryptomix.com/secure/", cert="client.pem")
print(r.status_code)
print(r.text)
This should print debug information including SSL_CLIENT information:
[SSL_CLIENT_S_DN_C] => US
[SSL_CLIENT_S_DN_ST] => California
[SSL_CLIENT_S_DN_L] => San Francisco
[SSL_CLIENT_S_DN_O] => BadSSL
[SSL_CLIENT_S_DN_CN] => BadSSL Client Certificate
[SSL_CLIENT_I_DN_C] => US
[SSL_CLIENT_I_DN_ST] => California
[SSL_CLIENT_I_DN_L] => San Francisco
[SSL_CLIENT_I_DN_O] => BadSSL
[SSL_CLIENT_I_DN_CN] => BadSSL Client Root Certificate Authority
[SSL_CLIENT_VERIFY] => GENEROUS
[SSL_CLIENT_M_VERSION] => 3
[SSL_CLIENT_M_SERIAL] => 2B936CE32D82CE8B01FD9A0595AC6366AA014C82
[SSL_CLIENT_V_START] => Nov 27 00:19:57 2019 GMT
[SSL_CLIENT_V_END] => Nov 26 00:19:57 2021 GMT
[SSL_CLIENT_V_REMAIN] => 730
[SSL_CLIENT_S_DN] => CN=BadSSL Client Certificate,O=BadSSL,L=San Francisco,ST=California,C=US
[SSL_CLIENT_I_DN] => CN=BadSSL Client Root Certificate Authority,O=BadSSL,L=San Francisco,ST=California,C=US
[SSL_CLIENT_A_KEY] => rsaEncryption
[SSL_CLIENT_A_SIG] => sha256WithRSAEncryption
[SSL_CLIENT_CERT_RFC4523_CEA] => { serialNumber 248774298121081469895139733087446207053965642882, issuer rdnSequence:"CN=BadSSL Client Root Certificate Authority,O=BadSSL,L=San Francisco,ST=California,C=US" }
Do you see the same values with your two OSes?

Related

Micropython uasyncio websocket server

I need to run a websocket server on ESP32 and the official example raises the following exception when I connect from any client:
MPY: soft reboot
Network config: ('192.168.0.200', '255.255.255.0', '192.168.0.1', '8.8.8.8')
b'Sec-WebSocket-Version: 13\r\n'
b'Sec-WebSocket-Key: k5Lr79cZgBQg7irI247FMw==\r\n'
b'Connection: Upgrade\r\n'
b'Upgrade: websocket\r\n'
b'Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n'
b'Host: 192.168.0.200\r\n'
b'\r\n'
Finished webrepl handshake
Task exception wasn't retrieved
future: <Task> coro= <generator object 'echo' at 3ffe79b0>
Traceback (most recent call last):
File "uasyncio/core.py", line 1, in run_until_complete
File "main.py", line 22, in echo
File "uasyncio/websocket/server.py", line 60, in WSReader
AttributeError: 'Stream' object has no attribute 'ios'
My micropython firmware and libraries:
Micropython firmware: https://micropython.org/resources/firmware/esp32-idf3-20200902-v1.13.bin
Pip libraries installed: micropython-ulogging, uasyncio.websocket.server
My main.py:
import network
import machine
sta_if = network.WLAN(network.STA_IF)
sta_if.active(True)
sta_if.ifconfig(('192.168.0.200', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
if not sta_if.isconnected():
print('connecting to network...')
sta_if.connect('my-ssid', 'my-password')
while not sta_if.isconnected():
machine.idle() # save power while waiting
print('Network config:', sta_if.ifconfig())
# from https://github.com/micropython/micropython-lib/blob/master/uasyncio.websocket.server/example_websock.py
import uasyncio
from uasyncio.websocket.server import WSReader, WSWriter
def echo(reader, writer):
# Consume GET line
yield from reader.readline()
reader = yield from WSReader(reader, writer)
writer = WSWriter(reader, writer)
while 1:
l = yield from reader.read(256)
print(l)
if l == b"\r":
await writer.awrite(b"\r\n")
else:
await writer.awrite(l)
import ulogging as logging
#logging.basicConfig(level=logging.INFO)
logging.basicConfig(level=logging.DEBUG)
loop = uasyncio.get_event_loop()
loop.create_task(uasyncio.start_server(echo, "0.0.0.0", 80))
loop.run_forever()
loop.close()
MicroPython 1.13 implements asyncio v3 which has a number of breaking changes compared to the 3 year old sample referenced.
I suggest you refer to Peter Hinch's excellent documentation on asyncio,
and the asyncio V3 tutorial
I encountered the same problem. I looked at the old implementation of Stream class [1] and the new one [2].
It seems to me, that you need to edit server.py from uasyncio/websocket/.
You can download the files from [3] to your PC. Then at the bottom of the file replace the two instances of "reader.ios" by "reader.s".
Save the file to your ESP32 and it should work. Of course you need to use "from server import WSReader, WSWriter" instead of "from uasyncio.websocket.server import WSReader, WSWriter".
[1] https://github.com/pfalcon/pycopy-lib/blob/master/uasyncio/uasyncio/__init__.py
[2] https://github.com/micropython/micropython/blob/master/extmod/uasyncio/stream.py
[3] https://pypi.org/project/micropython-uasyncio.websocket.server/#files
https://github.com/pfalcon/pycopy-lib/tree/master/uasyncio has a recent (may'21) sample that should also work on standard MicroPython.
or checkout https://awesome-micropython.com under web servers

Pact: Error when trying to setup mock provider

I'm trying to write my first Pact-python test using pytest, Could someone please tell me what's wrong with my code?
import unittest
import requests
import json
import pytest
import atexit
from pact import Consumer, Provider
pact = Consumer('Consumer').has_pact_with(Provider('Provider'), host_name='mockservice', port=8080)
pact.start_service()
atexit.register(pact.stop_service)
class InterviewDetails(unittest.TestCase):
def test_candidate_report_api(self):
candidate_report_payload = {}
resp = requests.post("http://localhost:1234/users/",data=json.dumps(candidate_report_payload))
response = json.loads(resp.text)
return response
#pytest.mark.health1
def test_candidate_report(self):
expected = {}
(pact.given('Comment')
.upon_receiving('comment')
.with_request(method='POST', path="http://localhost:1234/users/", headers={})
.will_respond_with(200, body=expected))
with pact:
pact.setup()
result = self.test_candidate_report_api()
self.assertEqual(result, expected)
pact.verify()
The error from stacktrace:
AttributeError: module 'pact' has no attribute 'Like'
Can you please confirm you're using pact-python from https://github.com/pact-foundation/pact-python/ (and not pactman, a project that is not maintained by the Pact Foundation)?
It might be related to the way you have setup your test?
Here is an example project you can use for reference: https://github.com/pactflow/example-consumer-python/
Relevant test code:
"""pact test for product service client"""
import json
import logging
import os
import requests
from requests.auth import HTTPBasicAuth
import pytest
from pact import Consumer, Like, Provider, Term, Format
from src.consumer import ProductConsumer
log = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
print(Format().__dict__)
PACT_MOCK_HOST = 'localhost'
PACT_MOCK_PORT = 1234
PACT_DIR = os.path.dirname(os.path.realpath(__file__))
#pytest.fixture
def consumer():
return ProductConsumer(
'http://{host}:{port}'
.format(host=PACT_MOCK_HOST, port=PACT_MOCK_PORT)
)
#pytest.fixture(scope='session')
def pact(request):
pact = Consumer('pactflow-example-consumer-python').has_pact_with(
Provider('pactflow-example-provider-python'), host_name=PACT_MOCK_HOST, port=PACT_MOCK_PORT,
pact_dir="./pacts", log_dir="./logs")
try:
print('start service')
pact.start_service()
yield pact
finally:
print('stop service')
pact.stop_service()
def test_get_product(pact, consumer):
expected = {
'id': "27",
'name': 'Margharita',
'type': 'Pizza'
}
(pact
.given('a product with ID 10 exists')
.upon_receiving('a request to get a product')
.with_request('GET', '/product/10')
.will_respond_with(200, body=Like(expected)))
with pact:
user = consumer.get_product('10')
assert user.name == 'Margharita'

How to set OpenStack API configuration in Centos 7?

Please tell me which SDK is better to call OpenStack APIs.
I haven't found much information or tutorials on this subject.
If you are using the CLI; the official Openstack client is the obvious choice. If you are trying to make programmatic API calls you can use anything from simple http request to a client library like shade for Python, or gophercloud for Golang.
pip install openstacksdk
Conneect to the cloud:
"""
Connect to an OpenStack cloud.
For a full guide see TODO(etoews):link to docs on developer.openstack.org
"""
import argparse
import os
import openstack
from openstack.config import loader
import sys
openstack.enable_logging(True, stream=sys.stdout)
#: Defines the OpenStack Config loud key in your config file,
#: typically in $HOME/.config/openstack/clouds.yaml. That configuration
#: will determine where the examples will be run and what resource defaults
#: will be used to run the examples.
TEST_CLOUD = os.getenv('OS_TEST_CLOUD', 'devstack-admin')
config = loader.OpenStackConfig()
cloud = openstack.connect(cloud=TEST_CLOUD)
class Opts(object):
def __init__(self, cloud_name='devstack-admin', debug=False):
self.cloud = cloud_name
self.debug = debug
# Use identity v3 API for examples.
self.identity_api_version = '3'
def _get_resource_value(resource_key, default):
return config.get_extra_config('example').get(resource_key, default)
SERVER_NAME = 'openstacksdk-example'
IMAGE_NAME = _get_resource_value('image_name', 'cirros-0.3.5-x86_64-disk')
FLAVOR_NAME = _get_resource_value('flavor_name', 'm1.small')
NETWORK_NAME = _get_resource_value('network_name', 'private')
KEYPAIR_NAME = _get_resource_value('keypair_name', 'openstacksdk-example')
SSH_DIR = _get_resource_value(
'ssh_dir', '{home}/.ssh'.format(home=os.path.expanduser("~")))
PRIVATE_KEYPAIR_FILE = _get_resource_value(
'private_keypair_file', '{ssh_dir}/id_rsa.{key}'.format(
ssh_dir=SSH_DIR, key=KEYPAIR_NAME))
EXAMPLE_IMAGE_NAME = 'openstacksdk-example-public-image'
def create_connection_from_config():
return openstack.connect(cloud=TEST_CLOUD)
def create_connection_from_args():
parser = argparse.ArgumentParser()
config = loader.OpenStackConfig()
config.register_argparse_arguments(parser, sys.argv[1:])
args = parser.parse_args()
return openstack.connect(config=config.get_one(argparse=args))
def create_connection(auth_url, region, project_name, username, password):
return openstack.connect(
auth_url=auth_url,
project_name=project_name,
username=username,
password=password,
region_name=region,
app_name='examples',
app_version='1.0',
)
Complete guide

When calling a function, how to feed variable as an arg

I have the code below that works, but instead of calling the function with "www.google.com", i need to be able to pass as arg:
python certexp.py www.google.com:
import ssl
import OpenSSL
import time
def get_SSL_Expiry_Date(host, port):
cert = ssl.get_server_certificate((host, 443))
x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
raw_date = x509.get_notAfter()
decoded_date = raw_date.decode("utf-8")
print (decoded_date)
dexpires = time.strptime(decoded_date, "%Y%m%d%H%M%Sz")
print (dexpires.tm_mon,"/",dexpires.tm_mday,"/",dexpires.tm_year)
get_SSL_Expiry_Date("google.com", 443)
Thank you
In python the sys module handles command line arguments.
This gives you an array of command line parameters, with sys.argv[0] being the name of the executable, then any subsequent elements being user parameters.
This makes your code:
import ssl
import OpenSSL
import time
import sys
def get_SSL_Expiry_Date(host, port):
cert = ssl.get_server_certificate((host, 443))
x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
raw_date = x509.get_notAfter()
decoded_date = raw_date.decode("utf-8")
print (decoded_date)
dexpires = time.strptime(decoded_date, "%Y%m%d%H%M%Sz")
print (dexpires.tm_mon,"/",dexpires.tm_mday,"/",dexpires.tm_year)
if (len(sys.argv) == 1):
sys.stderr.write("%s: Give hostname as an argument, optionally a port too" % (sys.argv[0]))
sys.exit(1)
hostname = sys.argv[1]
port = 443
if (len(sys.argv) == 3):
port = int(sys.argv[2])
get_SSL_Expiry_Date(hostname, port)
Obviously you could do that for the port too. There's other command line parsing modules too, so you can say --port= etc.

How to get the Tor ExitNode IP with Python and Stem

I'm trying to get the external IP that Tor uses, as mentioned here. When using something like myip.dnsomatic.com, this is very slow. I tried what was suggested in the aforementioned link (python + stem to control tor through the control port), but all you get is circuit's IPs with no assurance of which one is the one on the exitnode, and, sometimes the real IP is not even among the results.
Any help would be appreciated.
Also, from here, at the bottom, Amine suggests a way to renew the identity in Tor. There is an instruction, controller.get_newnym_wait(), which he uses to wait until the new connection is ready (controller is from Control in steam.control), isn't there any thing like that in Steam (sorry, I checked and double/triple checked and couldn't find nothing) that tells you that Tor is changing its identity?
You can get the exit node ip without calling a geoip site.
This is however on a different stackexchange site here - https://tor.stackexchange.com/questions/3253/how-do-i-trap-circuit-id-none-errors-in-the-stem-script-exit-used-py
As posted by #mirimir his code below essentially attaches a stream event listener function, which is then used to get the circuit id, circuit fingerprint, then finally the exit ip address -
#!/usr/bin/python
import functools
import time
from stem import StreamStatus
from stem.control import EventType, Controller
def main():
print "Tracking requests for tor exits. Press 'enter' to end."
print
with Controller.from_port() as controller:
controller.authenticate()
stream_listener = functools.partial(stream_event, controller)
controller.add_event_listener(stream_listener, EventType.STREAM)
raw_input() # wait for user to press enter
def stream_event(controller, event):
if event.status == StreamStatus.SUCCEEDED and event.circ_id:
circ = controller.get_circuit(event.circ_id)
exit_fingerprint = circ.path[-1][0]
exit_relay = controller.get_network_status(exit_fingerprint)
t = time.localtime()
print "datetime|%d-%02d-%02d %02d:%02d:%02d % (t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec)
print "website|%s" % (event.target)
print "exitip|%s" % (exit_relay.address)
print "exitport|%i" % (exit_relay.or_port)
print "fingerprint|%s" % exit_relay.fingerprint
print "nickname|%s" % exit_relay.nickname
print "locale|%s" % controller.get_info("ip-to-country/%s" % exit_relay.address, 'unknown')
print
You can use this code for check current IP (change SOCKS_PORT value to yours):
import re
import stem.process
import requesocks
SOCKS_PORT = 9053
tor_process = stem.process.launch_tor()
proxy_address = 'socks5://127.0.0.1:{}'.format(SOCKS_PORT)
proxies = {
'http': proxy_address,
'https': proxy_address
}
response = requesocks.get("http://httpbin.org/ip", proxies=proxies)
print re.findall(r'[\d.-]+', response.text)[0]
tor_process.kill()
If you want to use socks you should do:
pip install requests[socks]
Then you can do:
import requests
import json
import stem.process
import stem
SOCKS_PORT = "9999"
tor = stem.process.launch_tor_with_config(
config={
'SocksPort': SOCKS_PORT,
},
tor_cmd= 'absolute_path/to/tor.exe',
)
r = requests.Session()
proxies = {
'http': 'socks5://localhost:' + SOCKS_PORT,
'https': 'socks5://localhost:' + SOCKS_PORT
}
response = r.get("http://httpbin.org/ip", proxies=proxies)
self.current_ip = response.json()['origin']

Resources