At PLANET ARGON we use Basecamp for project tracking. Basecamp offers rss feeds of any new posts either globally or per project which is very handy for keeping track of things. The problem is that the rss feeds use http authentication which many feed readers (especially web based ones) don’t support. As a Google Reader user, I was out of luck.
After suffering through using email as my notification system, I decided to write a quick script to convert parameters to the url into http authentication. I initially considered doing this with cgi, but eventually decided to write a quick mongrel handler for the task. It actually turned out to be a lot easier than I thought it would be.
Here is the code:
require 'rubygems'
require 'mongrel'
require 'net/http'
HOSTNAME='your basecamp url'
class SimpleHandler < Mongrel::HttpHandler
def process(request, response)
params = {}
request.params["QUERY_STRING"].split('&').each do |param|
param = param.split('=')
params[param[0]] = param[1]
end
response.start(200) do |head,out|
head["Content-Type"] = "application/xml"
Net::HTTP.start(HOSTNAME) do |http|
req = Net::HTTP::Get.new(params["url"])
req.basic_auth params["user"], params["password"]
response = http.request(req)
out.write response.body
end
end
end
end
h = Mongrel::HttpServer.new("0.0.0.0", "9898")
h.register("/feed", SimpleHandler.new)
h.run.join
It works really well, just run the script and point your feed reader at:
http://hostname:9898/feed?user=<username>&password=<password>&url=<path of the rss feed>
for a normal global basecamp feed, it would look like:
http://hostname:9898/feed?user=andy.delcambre&password=mypassword&url=/feed/recent_items_rss
Robby has confirmed that this works with open id basecamp logins as well.
This could be easily used with any authenticated rss feed you wanted. My goal was to make it general enough and easy enough for everyone at PLANET ARGON to use.
I had no idea it was so easy to add an http server to your script with mongrel. Zed Shaw is the man.
Had never bothered to learn Mongrel’s HttpHandler. Thanks for this code.
But I believe CGI.unescape is needed?params = request.params["QUERY_STRING"].split('&').inject({}) do |sum,pair| (key, value) = pair.split('=') sum.merge(CGI.unescape(key) => CGI.unescape(value)) endI’ve been thinking about deploying an authenticated RSS system and this is a nice technique to broaden the available readers.
I wonder, though, what could be done to make it a little more secure. Having plaintext passwords right in the URL seems non-ideal (browser caching, traffic sniffing, etc). I guess SSL would be a start.
If you had control of the RSS server (not that you do with Basecamp), maybe it would make sense to hash the password? Assuming that your app is providing the URL to the user, it wouldn’t seem too bad from a usability standpoint. Like this:
https://yourapp.com/feed/243?username=admin&password=823dh71b89s
Where that junk is your hashed password. I guess that really wouldn’t change the caching problem, but at least the password wouldn’t just be ‘out there’ in plaintext. Thoughts?