Enrico Rossi

Urllib3 json cookie

Login with a Json authentication into an https server with TLSv1 only SSL connection capabilities.

Python has 3 different urllib library in order to manipulate http connections, which unfortunately are not the evolution of the same project. Plus there are others libraries based on these as well.

The urllib2 has a great cookie handling capabilities with the cookielib, but it cannot change the SSL connection’s propriety easily, see internet for overriding the socket connection proprieties.

The urllib3 instead can change the SSL option with no problem, but lack support for cookies (yet!).

This piece of code shows how to login to an https server using a Json POST, retrieve the resulting cookie, store it and reuse it for later operation.

#!/usr/bin/env python
# coding: utf-8

# Copyright (C) 2014 Enrico Rossi
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import urllib3
import json
import Cookie
from time import sleep

user = 'myusername'
passwd = 'mypassword'
headers = {'content-type': 'application/json'}

# Prepare the connection with TLSv1 as SSL support for the HTTPS.
conn = urllib3.connectionpool.HTTPSConnectionPool('myhostname.mydomain', ssl_version='TLSv1')

# The 1st post will be a json with username and password.
payload = json.dumps({'username':user, 'password':passwd})

# Do the connection and retrieve the result.
r=conn.urlopen('POST', '/login', body=payload, headers=headers)

# Debug the result.
jsonr = json.loads(r.data)
print 'HDR:', r.headers
print 'DATA:', r.data
print 'JSON:',jsonr.keys()

# get the cookie from the headers
# and set the next header to send with the cookie in it.
headers['Cookie']=cookie.output(attrs=[], header='').strip()

# delay some seconds.
print 'Wait ...'

# re-connect the server, sending back the cookie in order to get the
# password-protected page.
r=conn.urlopen('GET', '/getsomejsonthing', headers=headers)

# debug
jsonr = json.loads(r.data)
print 'HDR:', r.headers
print 'DATA:', r.data
print 'JSON:',jsonr.keys()

# update the new header with the (optionally) re-newed cookie from the server to be ready for the next request.
headers['Cookie']=cookie.output(attrs=[], header='').strip()

# debug the new cookie. Normally now you will get a new protected-page
# as before.
print cookie.output(attrs=[], header='').strip()

# end

# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

and this is the output on a testing WSGI python site.

enrico@xyz:~/devel$ python urllib3_https.py 
HDR: {'date': 'Tue, 08 Apr 2014 12:45:21 GMT', 'set-cookie': 'the_cookie_name="a lot of cookie garbage if it is encrypted"; httponly; Max-Age=600; Path=/', 'content-length': '32', 'content-type': 'application/json', 'server': 'WSGIServer/0.1 Python/2.7.3'}
DATA: {"OK": "200: Login successful."}
JSON: [u'OK']

Wait ...

HDR: {'date': 'Tue, 08 Apr 2014 12:45:31 GMT', 'set-cookie': 'the_cookie_name="another lot of cookie garbage"; httponly; Max-Age=600; Path=/', 'content-length': '727', 'content-type': 'application/json', 'server': 'WSGIServer/0.1 Python/2.7.3'}
DATA: JSON data that should appear as a dictionary {...}
JSON: The JSON keys [...]
the_cookie_name="another lot of cookie garbage"