How to do 1st step in 'Cookie-based authentication' using python, "requests" library.

Corinne C Nakashima October 5, 2016

My ultimate goal is to have a program automatically download a JSON output from a JIRA bug repository, via the JIRA API.  I have experience in python but almost none in RESTful API development.  Currently trying to follow directions located here: https://developer.atlassian.com/jiradev/jira-apis/jira-rest-apis/jira-rest-api-tutorials/jira-rest-api-example-cookie-based-authentication, and I cannot seem to get past Step 1, where at first, it seems simple to do: 

Step 1. Create a new session using the JIRA REST API

We need to get a session cookie from JIRA, so the first thing we need to do is create a new session using the session resource in the JIRA REST API. 
Tip: You can also use the session resource to get information about the currently authenticated user in the current session (GET), or log the current user out of JIRA (DELETE).

To do this, just POST the desired user credentials (as JSON) to the session resource:

Example resourcehttp://jira.example.com:8090/jira/rest/auth/1/session
Example credentials{ "username": "myuser", "password": "mypassword" }

This will create a new session and return the requested session information, which will look similar to the following:

{
	"session":
		{
			"name":"JSESSIONID",
			"value":"6E3487971234567896704A9EB4AE501F"
		},
	"loginInfo":
		{
			"failedLoginCount":1,
			"loginCount":2,
			"lastFailedLoginTime":"2013-11-27T09:43:28.839+0000",
			"previousLoginTime":"2013-12-04T07:54:59.824+0000"
		}
}

More importantly, you will get the session cookie (in the header of the response) from the server, which you can use in subsequent requests. You can see an example of this below. You'll notice that the cookie name and value are the same as the cookie name and value in the session response above.

Set-Cookie: JSESSIONID=6E3487971234567896704A9EB4AE501F; Path=/; HttpOnly

 

Since use of 'requests' library is recommended everywhere in help forums I've seen attempting to help people who are new to RESTful development because it's the simplest to use, I attempted to create a new session in my python 2.7 program in the following way, using the above tutorial info, plus info from the 'requests' libary tutorial site, http://docs.python-requests.org/en/master/user/quickstart/#make-a-request :

jirainterface.py:

import requests

loginurl = 'https://jira01.devtools.mycompany.com/rest/auth/1/session'

resp = requests.post(loginurl, data={'username': 'myusername','password': 'mypassword'})

print(resp.status_code, resp.reason)

 

Error Response:

Traceback (most recent call last):

  File "jiraIinterface.py", line 21, in <module>

    resp = requests.post(loginurl, data={'username': 'myusername','password': 'mypassword'})

  File "C:\Python27\lib\site-packages\requests\api.py", line 110, in post

    return request('post', url, data=data, json=json, **kwargs)

  File "C:\Python27\lib\site-packages\requests\api.py", line 56, in request

    return session.request(method=method, url=url, **kwargs)

  File "C:\Python27\lib\site-packages\requests\sessions.py", line 475, in request

    resp = self.send(prep, **send_kwargs)

  File "C:\Python27\lib\site-packages\requests\sessions.py", line 596, in send

    r = adapter.send(request, **kwargs)

  File "C:\Python27\lib\site-packages\requests\adapters.py", line 497, in send

    raise SSLError(e, request=request)                               

requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590)

 

There is nothing wrong with the loginurl, if I type it in to a browser, I get a response very much like the above sample requested session info.

Any help or insight is appreciated.

2 answers

1 accepted

1 vote
Answer accepted
Petar Petrov (Appfire)
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
October 5, 2016

The error says that the python client does not trust the SSL certificate of the server. In your browser it works, because usually browsers have a broader list of trusted certificate authorities or your due to a company policy the CA certificate has already been preinstalled on your PC.

What you need to do is export the CA certificate to a pem format (you can do this in the browser - look in Google) and use the "verify" parameter when doing the POST request - see documentation here (section "SSL Cert Verification").

You can also disable certificate verification altogether by passing verify=False to the requests.post method.

Corinne C Nakashima October 6, 2016

I appreciate your response.  When using chrome or IE Certificate Export Wizard, the option to export to .pem is not available :-/  I did look around on my computer and found that there are several .pem files like 'cacert.pem' here C:\Python27\Lib\site-packages\certifi.  Certifi documentation says python will automatically use this if certify is available which it is. The cacert.pem did not contain any reference to 'jira' however so I'm assuming I will be adding a CA certificate(s) for JIRA here?

Corinne C Nakashima October 6, 2016

I figured it out! There isn't one tutorial on the internet that described exactly how to get from the step of extracting CA certificates for a site from the browser to having a working .pem file ready for verification use for the python program, so I had to follow a few different tutorials.  I'll describe this in a subsequent answer.

Petar Petrov (Appfire)
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
October 10, 2016

Cool! I was on the road and could not respond earlier - you are correct, you need to either add the CA certificate to the file where python looks OR package it in a separate file and pass the full path to the verify parameter.

1 vote
Corinne C Nakashima October 11, 2016

Thank you very much Petar, your answer was EXTREMELY helpful! laugh  However, since the creation of the CA certificates to pem format from JIRA isn't trivial, I will give a brief run down of how I did it

1) Follow this tutorial 

 http://docs.bvstools.com/home/ssl-documentation/exporting-certificate-authorities-cas-from-a-website 

or search 'How to Export Certificate Authorities from a Website' and export the CA certificates.  Instead of what they suggest in the tutorial, make sure to export to file format "Base-64 encoded X.509 (.CER) "

2)  Then follow this tutorial to use these CA certificates to build your .pem file:

https://www.digicert.com/ssl-support/pem-ssl-creation.htm or search "How to create a .pem file for SSL certificate installations with the Server and Intermediate Certificates"

My program now looks something like this, which works:

jirainterface.py:

import requests

loginurl = 'https://jira01.devtools.mycompany.com/rest/auth/1/session'

filepath = 'C:\Path\To\My\JIRA.pem'

loginArgs = {'username': 'myusername','password': 'mypassword'}

 

resp = requests.post(loginurl, json=loginArgs, verify=filepath)

print(resp.status_code, resp.reason)

>> (200, ‘OK’)

Yeah!

Nemanja Peshovich October 5, 2017

Corinne,

Could you elaborate on the step 2? I am interested in understanding which certificates are concatenated. For instance, once the JIRA certificate is found by inspection in step 1, are there any other certificates that should be concatenated?

I was also using wincertstore package to decode the certificates - it short-circuits the need to export them to .cer then convert to .pem if name is known; which comes from the inspection of the certificate as you suggest it in step 1. This example shows how to print the ASCII texts for the certificates: https://pypi.python.org/pypi/wincertstore 

import wincertstore
for storename in ("CA", "ROOT"):
with wincertstore.CertSystemStore(storename) as store:
for cert in store.itercerts(usage=wincertstore.SERVER_AUTH):
if cert.get_name()=="The name of CERT found":
print(cert.get_pem().decode("ascii"))
print(cert.get_name())
print(cert.enhanced_keyusage_names())

Thank you in advance.

Suggest an answer

Log in or Sign up to answer