Python Requests SSL error: hostname doesn't mactch either of - python

I'm trying to connect to one of my internal services at: https://myservice.my-alternative-domain.com through Python Requests. I'm using Python 3.6
I'm using a custom CA bundle to verify the request, and I'm getting the next error:
SSLError: hostname 'myservice.my-domain.com' doesn't match either of 'my-domain.com', 'my-alternative-domain.com'
The SSL certificate that the internal service uses has as CN: my-domain.com, and as SAN (Subject Alternative Names): 'my-domain.com', 'my-alternative-domain.com'
So, I'm trying to access the service through one of the alternative names (this has to be like this and it's not under my control)
I think the error is correct, and that the certificate should have also as SAN:
'*.my-alternative-domain.com'
in order for the request to work.
The only thing that puzzles me is that I can access the service through the browser.
Can somebody confirm the behavior of Python Requests is correct?
This is how I call the service:
response = requests.get('https://myservice.my-alternative-domain.com', params=params, headers=headers, verify=ca_bundle)
Thanks

pass verify as false might work
x=requests.get(-----,verify=false)

Related

Python - Requests Library - How to ensure HTTPS requests

This is probably a dumb question, but I just want to make sure with the below.
I am currently using the requests library in python. I am using this to call an external API hosted on Azure cloud.
If I use the requests library from a virtual machine, and the requests library sends to URL: https://api-management-example/run, does that mean my communication to this API, as well as the entire payload I send through is secure? I have seen in my Python site-packages in my virtual environment, there is a cacert.pem file. Do I need to update that at all? Do I need to do anything else on my end to ensure the communication is secure, or the fact that I am calling the HTTPS URL means it is secure?
Any information/guidance would be much appreciated.
Thanks,
A HTTPS is secure with valid signed certificate. Some people use self signed certificate to maintain HTTPS. In requests library, you explicitly verify your certificate. If you have self-signed HTTPS then, you need to pass the certificate to cross verify with your local certificate.
verify = True
import requests
response = requests.get("https://api-management-example/run", verify=True)
Self Signed Certificate
import requests
response = requests.get("https://api-management-example/run", verify="/path/to/local/certificate/file/")
Post requests are more secure because they can carry data in an encrypted form as a message body. Whereas GET requests append the parameters in the URL, which is also visible in the browser history, SSL/TLS and HTTPS connections encrypt the GET parameters as well. If you are not using HTTPs or SSL/TSL connections, then POST requests are the preference for security.
A dictionary object can be used to send the data, as a key-value pair, as a second parameter to the post method.
The HTTPS protocol is safe provided you have a valid SSL certificate on your API. If you want to be extra safe, you can implement end-to-end encryption/cryptography. Basically converting your so called plaintext, and converting it to scrambled text, called ciphertext.
You can explicitly enable verification in requests library:
import requests
session = requests.Session()
session.verify = True
session.post(url='https://api-management-example/run', data={'bar':'baz'})
This is enabled by default. you can also verify the certificate per request:
requests.get('https://github.com', verify='/path/to/certfile')
Or per session:
s = requests.Session()
s.verify = '/path/to/certfile'
Read the docs.

Safe PUT authentication in python requests

I am trying to make a script that uploads files to a nextcloud server via webdav. The documentation says this can be done using a PUT HTTP request, like so:
import requests
url = "https://example.com/path/to/file.txt"
file = open("file/to/upload.txt")
response = requests.put(url, auth=(user, passwd), data=file)
This works just fine, and I get a 201 status code as a response, which means the file has been created, but I feel like its quite unsafe to do it this way.
I can add the parameter verify=True to make sure the file is sent encrypted if the web has a valid SSL certificate, but I don't know if the authentication credentials are encrypted too.
In case they're not, how would I securely make the request without revealing my password?
You're PUTting to a url that starts with https so you're making the request over TLS which is secure if you have a good certificate. If you have a good certificate, your username and password will also be sent over TLS and be secure.
To find out if your certificate is good, try running openssl s_client -showcerts -connect example.com:443 from the commandline and check that it reports Verify return code: 0 (ok) or try opening a browser and type in https://example.com and see if the browser complains.

How to authenticate HashiCorp Vault without certificate?

Below is my code:
import hvac
client = hvac.Client(
url='https://vault-abc.net',token='s.d0AGS4FE3o6UxUpVTQ0h0RRd',verify='False'
)
print(client.is_authenticated())
ERROR in output:
in cert_verify
raise IOError("Could not find a suitable TLS CA certificate bundle, " OSError: Could not find a suitable TLS CA certificate
bundle, invalid path: False
I got only token and URL to login on console from client no certificates shared! In other java applications code without using any certificate authentication working but in python code under hvac module or CURL or vault CLI expecting certificates to be passed. Any way I can handle this and fix above error?
Do we have any certificate check skip option?
Agenda is authenticate and do fetch vault secrets using python program, without any certificates need to fetch just with Token & vault URL.
You can disable certificate checks, but for something like Vault that's generally a bad idea (disabling security checks on a security service).
In any case, your problem is simple: You are passing 'False' (a string) where you should be passing False (a boolean) as the verify argument.
Passing a string causes the library to look for a certificate at that path; since there is no certificate at the path 'False', you get the error that you are seeing.

Downloading files from nextcloud with python script with 2-factor authentication enabled

I set up a nextcloud instance and I would like to download files from there using a python script. My nextcloud instance enforces 2-factor authentication for all users and I want it to remain that way.
My dream scenario would be to use the requests library, so following the docs here https://docs.nextcloud.com/server/15/developer_manual/client_apis/WebDAV/basic.html , I tried to do something like this:
from requests.auth import HTTPBasicAuth
r = requests.request(
method='get',
url='https://mycloudinstance/index.php/apps/files/?dir=/Test&fileid=431',
auth=('username', 'pass')
)
print(r.status_code)
print(r.text)
That gives me an 401 error saying {"message":"Current user is not logged in"}.
When I change the above URL to https://remote.php/dav/myinstance/index.php/apps/files/?dir=/Test&fileid=431 I get
ConnectionError(': Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))
As an alternative I was trying to use trying to use this library https://github.com/owncloud/pyocclient just to see if I can create a testfolder with it (it is from owncloud but should work with nextcloud too):
import owncloud
oc = owncloud.Client('https://mycloudinstance')
oc.login('username', 'pass')
oc.mkdir('cooldir')
This throws me an owncloud.owncloud.HTTPResponseError: HTTP error: 401 error. I think that might either be because I just use it incorrectly or because of 2-factor auth.
I am not sure how to use the webdav protocol combined with the python requests library and also I am not sure how to get two-factor authorization to work with it. Has anyone ever done this?
Help is very much appreciated, thanks so much in advance.
You can bypass the 2-factor authentication by generating a secure password for a single application.
In next cloud, go to: Settings -> Personal -> Security -> Create New App Password
The password will be shown to you once (and only once), use it in place of your normal password in your script.

How to authenticate in Jenkins while remotely accessing its JSON API?

I need to access the Jenkins JSON API from a Python script. The problem is that our Jenkins installation is secured so to log in users have to select a certificate. Sadly, in Jenkins Remote Access Documentation they don't mention a thing about certificates and I tried using the API Token without success.
How can I get to authenticate from a Python script to use their JSON API?
Thanks in advance!
You have to authenticate to the JSON API using HTTP Basic Auth.
To make scripted clients (such as wget) invoke operations that require authorization (such as scheduling a build), use HTTP BASIC authentication to specify the user name and the API token. This is often more convenient than emulating the form-based authentication
https://wiki.jenkins-ci.org/display/JENKINS/Authenticating+scripted+clients
Here is a sample of using Basic Auth with Python.
http://docs.python-requests.org/en/master/user/authentication/
Keep in mind if you are using a Self Signed certificate on an internal Jenkin Server you'll need to turn off certificate validation OR get the certificate from the server and add it to the HTTP request
http://docs.python-requests.org/en/master/user/advanced/
I finally found out how to authenticate to Jenkins using certs and wget. I had to convert my pfx certificates into pem ones with cert and keys in separate files For more info about that come here. In the end this is the command I used.
wget --certificate=/home/B/cert.pem --private-key=/home/B/key.pem --no-check-certificate --output-document=jenkins.json https:<URL>
I'm not completely sure it covers your certificate use case, but since it took me some time to find out, I still want to share this snipped that retrieves the email address for a given user name in Python without special Jenkins libraries. It uses an API token and "supports" (actually ignores) https:
def _get_email_adress(user):
request = urllib.request.Request("https://jenkins_server/user/"+ user +"/api/json")
#according to https://stackoverflow.com/a/28052583/4609258 the following is ugly
context = ssl._create_unverified_context()
base64string = base64.b64encode(bytes('%s:%s' % ('my user name', 'my API token'),'ascii'))
request.add_header("Authorization", "Basic %s" % base64string.decode('utf-8'))
with urllib.request.urlopen(request, context=context) as url:
user_data = json.loads(url.read().decode())
for property in user_data['property']:
if property["_class"]=="hudson.tasks.Mailer$UserProperty":
return property["address"];

Categories