lib/atom/http.rb in atom-tools-2.0.1 vs lib/atom/http.rb in atom-tools-2.0.2

- old
+ new

@@ -1,8 +1,9 @@ require "net/http" require "net/https" require "uri" +require "cgi" require "atom/cache" require "sha1" require "digest/md5" @@ -14,11 +15,12 @@ class String # :nodoc: def to_uri; URI.parse(self); end end module Atom - UA = "atom-tools 2.0.1" + TOOLS_VERSION = '2.0.2' + UA = "atom-tools " + TOOLS_VERSION module DigestAuth CNONCE = Digest::MD5.hexdigest("%x" % (Time.now.to_i + rand(65535))) @@nonce_count = -1 @@ -128,10 +130,12 @@ # :digest won't work, since Digest authentication requires an # initial challenge to generate a response # # defaults to nil attr_accessor :always_auth + # if this is true, we tell Net::HTTP to die if it can't verify the SSL when doing https + attr_accessor :strict_ssl # automatically handle redirects, even for POST/PUT/DELETE requests? # # defaults to false, which will transparently redirect GET requests # but return a Net::HTTPRedirection object when the server @@ -252,14 +256,94 @@ req['X-WSSE'] = %Q<UsernameToken Username="#{user}", PasswordDigest="#{digest}", Nonce="#{nonce_enc}", Created="#{now}"> req["Authorization"] = 'WSSE profile="UsernameToken"' end - def authsub_authenticate req, url + def authsub_authenticate req, url, param_string = "" req["Authorization"] = %{AuthSub token="#{@token}"} end + # GoogleLogin support thanks to Adrian Hosey + def googlelogin_authenticate(req, url, param_string) + params_h = Hash.new + param_string.split(',').each do |p| + k, v = p.split('=') + # No whitespace in the key + k.delete!(' ') + # Values come wrapped in doublequotes - remove + v.gsub!(/^"|"$/, '') + params_h[k] = v + end + + abs_url = (url + "/").to_s + user, pass = @get_auth_details.call(abs_url, params_h["realm"]) + token = fetch_googlelogin_token(user, pass, params_h["realm"], params_h["service"]) + if !token.nil? + req["Authorization"] = "GoogleLogin auth=#{token}" + end + end + + def fetch_googlelogin_token(user, pass, url_s, service) + req, url = new_request(url_s, Net::HTTP::Post) + http_obj = Net::HTTP.new(url.host, url.port) + if url.scheme == "https" + http_obj.use_ssl = true + probe_for_cafile(http_obj) + end + + body = "Email=#{CGI.escape(user)}&Passwd=#{CGI.escape(pass)}&service=#{CGI.escape(service)}" + body += "&accountType=GOOGLE&source=ruby-atom-tools-#{CGI.escape(TOOLS_VERSION)}" + res = http_obj.start do |h| + h.request(req, body) + end + + retval = nil + case res + when Net::HTTPUnauthorized + raise Unauthorized, "Your authorization was rejected" + when Net::HTTPOK, Net::HTTPNonAuthoritativeInformation + res.body.each_line do |l| + k, v = l.split('=') + if k == "Auth" + retval = v.chomp + end + end + end + + retval + end + + # Look for a root CA file and set the relevant options on the passed-in Net::HTTP object. + def probe_for_cafile(http_obj) + ca_possibles = [ + '/usr/share/curl/curl-ca-bundle.crt', # OS X + '/etc/pki/tls/certs/ca-bundle.crt', # newer Redhat + '/usr/share/ssl/certs/ca-bundle.crt', # older Redhat + '/etc/ssl/certs/ca-certificates.crt', # Ubuntu (I think) + # <irony>Dear LSB: Thank you for standardizing Linux</irony> + ] + cafile = nil + ca_possibles.each do |ca| + if File.exist? ca + cafile = ca + break + end + end + if cafile.nil? + if @strict_ssl + # set this knowing it will die, since we didn't find a good cafile + http_obj.verify_mode = OpenSSL::SSL::VERIFY_PEER + else + http_obj.verify_mode = OpenSSL::SSL::VERIFY_NONE + end + else + http_obj.ca_file = cafile + http_obj.verify_mode = OpenSSL::SSL::VERIFY_PEER + http_obj.verify_depth = 5 + end + end + def username_and_password_for_realm(url, realm) abs_url = (url + "/").to_s user, pass = @get_auth_details.call(abs_url, realm) unless user and pass @@ -311,10 +395,13 @@ elsif www_authenticate dispatch_authorization www_authenticate, req, url end http_obj = Net::HTTP.new(url.host, url.port) - http_obj.use_ssl = true if url.scheme == "https" + if url.scheme == "https" + http_obj.use_ssl = true + probe_for_cafile(http_obj) + end res = http_obj.start do |h| h.request(req, body) end