Having difficulty signing requests in ruby

205 views
Skip to first unread message

Immad

unread,
Jun 25, 2008, 1:03:28 PM6/25/08
to Google Data Protocol
I have tried every method I can imagine, including working from
several other peoples examples but I just can't get the signature on
secure requests working in ruby.

I get the a "400 Bad Request error". Given that it is bad request I am
pretty sure my signature is being constructed incorrectly. Here is my
code given a specific data to sign:

data = "GET https://www.google.com/accounts/AuthSubSessionToken
1208475262 97612217129769266447"
key = OpenSSL::PKey::RSA.new(File.read("config/privkey.pem"))
sig = key.private_encrypt(Digest::SHA1::hexdigest(data))
# at this stage the data looks all crazy: ""\225\037� ~
\275 \225\211Dg\245I\261$\032u`\025�...."
sig = Base64.b64encode(sig.to_s)

This gives sig as: "lR/
mAX69wo2ViURnpUmxJBp1YBXiDTkCgtj9zTXMtjqYg8jnPg0g9FTw3pUt
\nfPVY3MPczOHcmF5NN5+UYuJbwpFMFZ2e+DZHn1gGE+XZznyNqY9tNg3szYAr
\n2okXUp5qYYnTvojiulpWQZqO2lNSo1eLmcNHSWO+79eZuJ1JQlE=\n"

And my Header ends up being:

"Authorization: AuthSub token=\"CKPrudSKERDWzqnw______8B\" sigalg=
\"rsa-sha1\" data=\"GET https://www.google.com/accounts/AuthSubSessionToken
1208475262 97612217129769266447\" sig=\"lR/
mAX69wo2ViURnpUmxJBp1YBXiDTkCgtj9zTXMtjqYg8jnPg0g9FTw3pUt
\nfPVY3MPczOHcmF5NN5+UYuJbwpFMFZ2e+DZHn1gGE+XZznyNqY9tNg3szYAr
\n2okXUp5qYYnTvojiulpWQZqO2lNSo1eLmcNHSWO+79eZuJ1JQlE=\n\""

This is what gives me a bad request. I have tried various different
ways of doing this, the other way of producing the rsa-sha1 signature
that I saw on the net was by changing sig to be:

sig = key.sign(OpenSSL::Digest::SHA1.new, data)

This ended up giving me base 64 encoded signature of:
"NkHzHLAk/PSoWf2Eie1N1DUrTXh6OtNgKl4wa9rLjeWI7Le3E0LNcvsvfRDj
\nYZ9skWLCVwmx45HxZqUSRp/06Upr9MP9oeDCPgLR35CmoVTpQFrdzD5ODt7y
\nSQuEYDn81D1vngMBJHivLjVMZDPTVyzO0xZaTb4pAkEGph/jApM=\n"

Not sure why that should be different, but I can't quite find any
documentation on what exactly the sign method does.

Either way given that I am getting bad request back, I am guessing
this is a fundamental difference between what Google Authsub API
expects and what ruby is through out.

This is with ruby 1.8.5. Running under Rails 1.2.6 (if that's
relevant)

Thanks in advance,
Immad

Jeff Fisher (Google)

unread,
Jun 26, 2008, 5:36:39 PM6/26/08
to Google Data Protocol
Hi Immad,

Since the server errors aren't always super descriptive, can you also
verify you requested the initial token with secure=1&session=1 and the
public certificate you uploaded to the ManageDomains page is correct?

Cheers,
-Jeff

On Jun 25, 10:03 am, Immad <i.akh...@gmail.com> wrote:
> I have tried every method I can imagine, including working from
> several other peoples examples but I just can't get the signature on
> secure requests working in ruby.
>
> I get the a "400 Bad Request error". Given that it is bad request I am
> pretty sure my signature is being constructed incorrectly. Here is my
> code given a specific data to sign:
>
>     data = "GEThttps://www.google.com/accounts/AuthSubSessionToken
> 1208475262 97612217129769266447"
>     key = OpenSSL::PKey::RSA.new(File.read("config/privkey.pem"))
>     sig = key.private_encrypt(Digest::SHA1::hexdigest(data))
>    # at this stage the data looks all crazy: ""\225\037� ~
> \275 \225\211Dg\245I\261$\032u`\025�...."
>     sig = Base64.b64encode(sig.to_s)
>
> This gives sig as: "lR/
> mAX69wo2ViURnpUmxJBp1YBXiDTkCgtj9zTXMtjqYg8jnPg0g9FTw3pUt
> \nfPVY3MPczOHcmF5NN5+UYuJbwpFMFZ2e+DZHn1gGE+XZznyNqY9tNg3szYAr
> \n2okXUp5qYYnTvojiulpWQZqO2lNSo1eLmcNHSWO+79eZuJ1JQlE=\n"
>
> And my Header ends up being:
>
> "Authorization: AuthSub token=\"CKPrudSKERDWzqnw______8B\" sigalg=
> \"rsa-sha1\" data=\"GEThttps://www.google.com/accounts/AuthSubSessionToken

Immad Akhund

unread,
Jun 26, 2008, 5:41:43 PM6/26/08
to google-he...@googlegroups.com
I did do secure=1&session=1

The public certificate is correct, although the google management interface does not let me check the current uploaded certificate (unless I am missing where you can do that).

If I change the signature to a random string like "kgljakg" then instead of saying bad request I get the error that the signature is invalid. Therefore I am guessing its actually in the wrong format rather than just an incorrect signature.

Thanks for the help,

Immad
--
Cell: +1 617 460 7271
Mobile: +44 797399 3672
Skype: i.akhund
Blog: http://immadsnewworld.com

Clickpass, CTO

Jeff Fisher (Google)

unread,
Jun 26, 2008, 7:26:56 PM6/26/08
to Google Data Protocol
Hi,

Ah, good to know it provides a different message for an invalid
signature. Your Authorization header looks correct to me. Can you use
Wireshark and see what is actually being sent over the wire?

Cheers,
-Jeff

Immad

unread,
Jun 26, 2008, 9:06:53 PM6/26/08
to Google Data Protocol
Hi Jeff,

I have fixed the problem!

It turns out all I had to do was remove the '\n' inserted by the
encode64 function. Also using sig =
key.sign(OpenSSL::Digest::SHA1.new, data) is that way to do it just
in case any one else is stuck on something similar.

Thanks fro your help Jeff.

Immad

Ps: this is the ruby function for making a signed header just in case
anyone else wants need:

def google_header url, token
time = Time.now.to_i.to_s
nonce = OpenSSL::BN.rand_range(2**64)
data = "GET #{url} #{time} #{nonce}"

key = OpenSSL::PKey::RSA.new(File.read("config/privkey.pem"))
sig = key.sign(OpenSSL::Digest::SHA1.new, (data))
sig = Base64.b64encode(sig).gsub(/\n/, '')

header = {'Authorization' => "AuthSub token=\"#{token}\" sigalg=
\"rsa-sha1\" data=\"#{data}\" sig=\"#{sig}\""}
header["Content-Type"] = "application/x-www-form-urlencoded"

return header
end


On Jun 26, 4:26 pm, "Jeff Fisher (Google)" <api.jfis...@google.com>

Jeff Fisher (Google)

unread,
Jun 27, 2008, 2:28:31 PM6/27/08
to Google Data Protocol

Haha, an extra newline! Amazing how the small things can trip you up.
Thanks for sharing your code!

Cheers,
-Jeff

sgudibanda

unread,
Jul 22, 2008, 3:14:02 AM7/22/08
to Google Data Protocol

I am trying to import gmail contacts securely as well. This mailing
group came as ray of hope, after a long battle on my own. I am yet to
fix this:

These are two issues i am facing:

1. I am being asked to enter PEM passphrase everytime :( I need to
give my password on command line everytime i call google_header to
build the header. How can i fix this?
2. I get this error Errno::ECONNRESET (An existing connection was
forcibly closed by the remote host.): when i try to
resp,data = http.get(path, header)

This is how my header looks :
AuthorizationAuthSub token="CNvq7vHhDRDzr7n7Ag" sigalg= "rsa-sha1"
data="GET /accounts/AuthSubSessionToken 1216710691
3871674252761877297" sig="bGvjD1X4L3ELGGgxpoym7ZFMbczunMm
+gy3NesOmeJBBcT9uiX8SdeFwWD+b9Zcxs680b9v1C/
RmvbN1qtHF0alLxXoq6Ucu9H15jnG7kimQrRjqtkMcNLTWPhpJMuzzTvIR/
RLNzNul9mtplWumkRz5zKtjo5mjrEQX/Ub2R78="Content-Typeapplication/x-www-
form-urlencoded

Please help me here :(
Thanks in advance,
SG

mtz

unread,
Jul 24, 2008, 6:05:25 PM7/24/08
to Google Data Protocol
I might be able to help you with the first point.

The ruby method for getting the key from the file takes an optional
argument which is the password.

so instead of
key = OpenSSL::PKey::RSA.new(File.read("config/privkey.pem"))

you can call
key = OpenSSL::PKey::RSA.new(File.read("config/privkey.pem"),
passphrase)

I believe this is the api page that has describes the
OpenSSL::PKey::RSA.new method
http://www.ruby-doc.org/stdlib/libdoc/openssl/rdoc/index.html

Good luck.
> > Ps: this is therubyfunction for making a signed header just in case
> > > > > > This is withruby1.8.5. Running under Rails 1.2.6 (if that's

sgudibanda

unread,
Jul 26, 2008, 2:47:45 AM7/26/08
to Google Data Protocol
Thanks mtz. Now i can key in my passphrase directly in there.
But i am still receiving 401 status back though.
Any suggestions?

On Jul 25, 3:05 am, mtz <tracey.zellm...@gmail.com> wrote:
> I might be able to help you with the first point.
>
> The ruby method for getting the key from the file takes an optional
> argument which is the password.
>
> so instead of
> key = OpenSSL::PKey::RSA.new(File.read("config/privkey.pem"))
>
> you can call
> key = OpenSSL::PKey::RSA.new(File.read("config/privkey.pem"),
> passphrase)
>
> I believe this is the api page that has describes the
> OpenSSL::PKey::RSA.new methodhttp://www.ruby-doc.org/stdlib/libdoc/openssl/rdoc/index.html

sgudibanda

unread,
Jul 26, 2008, 4:45:26 AM7/26/08
to Google Data Protocol
I get 403 status code, even if i pass in some arbitrary value . sig
=kljlkjljlk gives me the same error.
I am doing something completely stupid?

mtz

unread,
Aug 1, 2008, 10:44:18 AM8/1/08
to Google Data Protocol
Not sure if you have made progress. I had to struggle through some
things with my service provider,
but after that, I had a problem like yours because I forgot to set the
connect to use_ssl

So, something like this works for me (adapted form Peter Winer's
suggestion
http://github.com/stuart/google-authsub/tree/master/lib/googleauthsub.rb
)

method = Net::HTTP.get
url = Net::HTTPS.build(:host => "www.google.com", :path => "/accounts/
AuthSubSessionToken")
request = method.new(url.path)
request['Authorization'] = google_auth(url, once_token)
#once_token is what you got and need to exchange for a session token
#google_auth described below
request['Content-Type'] = "application/x-new-form-urlencoded"
logger.info(request.to_yaml) #I found this very helpful - the yaml
format is easy to read
connection = Net::HTTP.new(url.host, url.port)
connection.use_ssl = true #don't forget this
response = connection.start {|http| http.request(request) }
session_token = response.body.match(/^Token-(.*)$/([1]

where the google_auth function is like so
def google_auth(url, t)
time = Time.now.toi.to_s
nonce = OpenSSL::BN.rand_range(2**64)
data = "GET #{url} #{time} #{nonce}"
f = File.new(File.join(RAILS_ROOT, 'config', 'keys.pem'))
key = OpenSSL::PKey::RSA.new(f.read)
sig = key.sign(OpenSSL::Digest::SHA1.new, (data))
sig = Base64.b64encode(sig).gsub(/\n/, '')
return "AuthSub token=\"#{t}\" sigalg=\"rsa-sha1\" data=\"#data}\"
sig=\"#{sig}\""
end

Note that I haven't put in error checking for the connection process
Also, I found that I could not successfully read a pem file that had
been created by openssl
I had to create the file with Ruby's facilities, and then Ruby's
OpenSSL::PKey::RAS.new would work

Also, I need to put the key into a constant rather than reading it
every time I need a token.

But , hopefully this may help you

On Jul 26, 4:45 am, sgudibanda <sgudiba...@gmail.com> wrote:
> I get 403 status code, even if i pass in some arbitrary value . sig
> =kljlkjljlk gives me the same error.
> I am doing something completely stupid?
>
> On Jul 26, 11:47 am, sgudibanda <sgudiba...@gmail.com> wrote:
>
> > Thanks mtz. Now i can key in my passphrase directly in there.
> > But i am still receiving 401 status back though.
> > Any suggestions?
>
> > On Jul 25, 3:05 am, mtz <tracey.zellm...@gmail.com> wrote:
>
> > > I might be able to help you with the first point.
>
> > > Therubymethod for getting the key from the file takes an optional
Reply all
Reply to author
Forward
0 new messages