Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python urllib2 Basic Auth Problem

Update: based on Lee's comment I decided to condense my code to a really simple script and run it from the command line:

import urllib2 import sys  username = sys.argv[1] password = sys.argv[2] url = sys.argv[3] print("calling %s with %s:%s\n" % (url, username, password))  passman = urllib2.HTTPPasswordMgrWithDefaultRealm() passman.add_password(None, url, username, password) urllib2.install_opener(urllib2.build_opener(urllib2.HTTPBasicAuthHandler(passman)))  req = urllib2.Request(url) f = urllib2.urlopen(req) data = f.read() print(data) 

Unfortunately it still won't generate the Authorization header (per Wireshark) :(

I'm having a problem sending basic AUTH over urllib2. I took a look at this article, and followed the example. My code:

passman = urllib2.HTTPPasswordMgrWithDefaultRealm() passman.add_password(None, "api.foursquare.com", username, password) urllib2.install_opener(urllib2.build_opener(urllib2.HTTPBasicAuthHandler(passman)))  req = urllib2.Request("http://api.foursquare.com/v1/user")     f = urllib2.urlopen(req) data = f.read() 

I'm seeing the following on the Wire via wireshark:

GET /v1/user HTTP/1.1 Host: api.foursquare.com Connection: close Accept-Encoding: gzip User-Agent: Python-urllib/2.5  

You can see the Authorization is not sent, vs. when I send a request via curl: curl -u user:password http://api.foursquare.com/v1/user

GET /v1/user HTTP/1.1 Authorization: Basic =SNIP= User-Agent: curl/7.19.4 (universal-apple-darwin10.0) libcurl/7.19.4 OpenSSL/0.9.8k zlib/1.2.3 Host: api.foursquare.com Accept: */* 

For some reason my code seems to not send the authentication - anyone see what I'm missing?

thanks

-simon

like image 287
Simon Avatar asked Mar 09 '10 06:03

Simon


People also ask

Is urllib2 deprecated?

urllib2 is deprecated in python 3. x. use urllib instaed.

Can I use urllib2 in python3?

NOTE: urllib2 is no longer available in Python 3 You can get more idea about urllib.

How do you pass basic authentication in header in Python?

To achieve this authentication, typically one provides authentication data through Authorization header or a custom header defined by server. Replace “user” and “pass” with your username and password. It will authenticate the request and return a response 200 or else it will return error 403.

Is urllib2 built in Python?

urllib2 is a Python module that can be used for fetching URLs. The magic starts with importing the urllib2 module.


2 Answers

The problem could be that the Python libraries, per HTTP-Standard, first send an unauthenticated request, and then only if it's answered with a 401 retry, are the correct credentials sent. If the Foursquare servers don't do "totally standard authentication" then the libraries won't work.

Try using headers to do authentication:

import urllib2, base64  request = urllib2.Request("http://api.foursquare.com/v1/user") base64string = base64.b64encode('%s:%s' % (username, password)) request.add_header("Authorization", "Basic %s" % base64string)    result = urllib2.urlopen(request) 

Had the same problem as you and found the solution from this thread: http://forums.shopify.com/categories/9/posts/27662

like image 69
yayitswei Avatar answered Sep 24 '22 01:09

yayitswei


(copy-paste/adapted from https://stackoverflow.com/a/24048772/1733117).

First you can subclass urllib2.BaseHandler or urllib2.HTTPBasicAuthHandler, and implement http_request so that each request has the appropriate Authorization header.

import urllib2 import base64  class PreemptiveBasicAuthHandler(urllib2.HTTPBasicAuthHandler):     '''Preemptive basic auth.      Instead of waiting for a 403 to then retry with the credentials,     send the credentials if the url is handled by the password manager.     Note: please use realm=None when calling add_password.'''     def http_request(self, req):         url = req.get_full_url()         realm = None         # this is very similar to the code from retry_http_basic_auth()         # but returns a request object.         user, pw = self.passwd.find_user_password(realm, url)         if pw:             raw = "%s:%s" % (user, pw)             auth = 'Basic %s' % base64.b64encode(raw).strip()             req.add_unredirected_header(self.auth_header, auth)         return req      https_request = http_request 

Then if you are lazy like me, install the handler globally

api_url = "http://api.foursquare.com/" api_username = "johndoe" api_password = "some-cryptic-value"  auth_handler = PreemptiveBasicAuthHandler() auth_handler.add_password(     realm=None, # default realm.     uri=api_url,     user=api_username,     passwd=api_password) opener = urllib2.build_opener(auth_handler) urllib2.install_opener(opener) 
like image 40
dnozay Avatar answered Sep 23 '22 01:09

dnozay