<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>spec/gmail/myrsakey.pem</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -78,9 +78,34 @@ module Contacts
     #   (default: false)
     def self.authentication_url(target, options = {})
       params = authentication_url_options.merge(options)
+      key = params.delete(:key)
+      params[:secure] = true if !params[:secure] &amp;&amp; key
       params[:next] = target
       query = query_string(params)
-      &quot;https://#{DOMAIN}#{AuthSubPath}Request?#{query}&quot;
+      url = &quot;https://#{DOMAIN}#{AuthSubPath}Request?#{query}&quot;
+      sig = generate_sig(url, key) if key
+      key ? &quot;#{url}&amp;#{query_string(:sig =&gt; sig)}&quot; : url
+    end
+
+    # Generates the signature for a secure AuthSub request. +key+ may be an IO, String or
+    # OpenSSL::PKey::RSA.
+    # Stolen from http://github.com/stuart/google-authsub/lib/googleauthsub.rb
+    def self.generate_sig(url, key)
+      pkey = case key
+      when OpenSSL::PKey::RSA
+        key
+      when File
+        OpenSSL::PKey::RSA.new(key.read)
+      when String
+        OpenSSL::PKey::RSA.new(key)
+      else
+        raise &quot;Private Key in wrong format. Require IO, String or OpenSSL::PKey::RSA, you gave me #{key.class}&quot;
+      end
+      timestamp = Time.now.to_i
+      nonce     = OpenSSL::BN.rand_range(2**64)
+      data      = &quot;GET #{url} #{timestamp} #{nonce}&quot;
+      digest    = OpenSSL::Digest::SHA1.new(data).hexdigest
+      sig       = [pkey.private_encrypt(digest)].pack(&quot;m&quot;)  #Base64 encode
     end
 
     # Makes an HTTPS request to exchange the given token with a session one. Session</diff>
      <filename>lib/contacts/google.rb</filename>
    </modified>
    <modified>
      <diff>@@ -28,6 +28,43 @@ describe Contacts::Google, '.authentication_url' do
     pairs.should include('session=1')
   end
 
+  it 'should imply secure=true when the key parameter is set' do
+    rsa = mock('OpenSSL::PKey::RSA', :private_encrypt =&gt; 'signature')
+    digest = mock('OpenSSL::Digest::SHA1', :hexdigest =&gt; 'digest')
+    OpenSSL::Digest::SHA1.expects(:new).returns(digest).at_least_once
+    OpenSSL::PKey::RSA.expects(:new).with('secret-key').returns(rsa).at_least_once
+
+    pairs = parse_authentication_url(nil, :key =&gt; 'secret-key').query.split('&amp;')
+
+    pairs.should include('secure=1')
+    pairs.should include('sig=c2lnbmF0dXJl%0A') # ['signature'].pack('m')
+    pairs.should_not include('key=secret-key')
+  end
+
+  it 'should accept File or IO key parameter' do
+    rsa = mock('OpenSSL::PKey::RSA', :private_encrypt =&gt; 'signature')
+    digest = mock('OpenSSL::Digest::SHA1', :hexdigest =&gt; 'digest')
+    OpenSSL::Digest::SHA1.expects(:new).returns(digest).at_least_once
+    OpenSSL::PKey::RSA.expects(:new).with(File.open(File.join(File.dirname(__FILE__), 'myrsakey.pem')).read).returns(rsa).at_least_once
+
+    pairs = parse_authentication_url(nil, :key =&gt; File.open(File.join(File.dirname(__FILE__), 'myrsakey.pem'))).query.split('&amp;')
+
+    pairs.should include('secure=1')
+    pairs.should include('sig=c2lnbmF0dXJl%0A') # ['signature'].pack('m')
+    pairs.should_not include('key=secret-key')
+  end
+
+  it 'should accept OpenSSL::Pkey::RSA key parameter' do
+    digest = mock('OpenSSL::Digest::SHA1', :hexdigest =&gt; 'digest')
+    OpenSSL::Digest::SHA1.expects(:new).returns(digest).at_least_once
+
+    pairs = parse_authentication_url(nil, :key =&gt; OpenSSL::PKey::RSA.new(File.open(File.join(File.dirname(__FILE__), 'myrsakey.pem')).read)).query.split('&amp;')
+
+    pairs.should include('secure=1')
+    pairs.should include('sig=nhzzbfqHUOhN6iE%2BkyHQabRvtfc3pbxKQt4hHqlNtBZVliswTFfVIISFPo5Z%0Ads6YVeAKdqAAZuVFUwMDihA83ihIf8spWN%2BrKpeLxAhrUCM69oihD7csdedG%0AbN9TCToIp4q9tJj2o4SsAgxs3dK55Nc1vhCOlVB7mIbxM%2B8YGL4%3D%0A') # based on 'digest' data
+    pairs.should_not include('key=secret-key')
+  end
+
   it 'skips parameters that have nil value' do
     query = parse_authentication_url(nil, :secure =&gt; nil).query
     query.should_not include('next')</diff>
      <filename>spec/gmail/auth_spec.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>c8d99af7dac8b9ca24accca9053a4eb46f447bff</id>
    </parent>
  </parents>
  <author>
    <name>Kamal Fariz Mahyuddin</name>
    <email>kamal.fariz@gmail.com</email>
  </author>
  <url>http://github.com/kamal/contacts/commit/2ceaadbcc8e18cd94759399c357ef0db051ba513</url>
  <id>2ceaadbcc8e18cd94759399c357ef0db051ba513</id>
  <committed-date>2009-03-17T09:48:03-07:00</committed-date>
  <authored-date>2009-03-17T09:31:51-07:00</authored-date>
  <message>Support signing the Gmail AuthSub using the :key parameter</message>
  <tree>e0edfcf9d92e5a90ba0a5c78f765139ed706359c</tree>
  <committer>
    <name>Kamal Fariz Mahyuddin</name>
    <email>kamal.fariz@gmail.com</email>
  </committer>
</commit>
