Tuesday, July 28, 2009

Gigya Ruby Integration: Signatures and Authentications

Here we sign the status REST API call and pass it to gigya's servers.
I am using here the hmac/sha1 lib you can find here:

http://rubyforge.org/projects/ruby-hmac/

This authentication method only works for the status api call as the http parameters are ordered hard coded and not sorted automatically.
Some modifications may be needed for other API calls.

The user, id, status_message are instance methods of the Post class.
See the comments embeded in the code.

class Post
  def authenticate_and_share
     #@shmu: escape the status message and replace all + with %20 as spaces are CGI.escaped to +
     message_text = CGI.escape(status_message).gsub('+', '%20')
     user_id = user.id
  
     #@shmu: here are the parameters you need to supply from your Gigya site's settings page.
     api_url = "http://socialize.api.gigya.com/socialize.setStatus"
     api_key = "HERE_GOES_YOUR_API_KEY"
     gigya_secret_key = "HERE_GOES_YOUR_GIGYA_SECRET_KEY"
  
     #@shmu: decode secret key and prepare nonce.
     gigya_secret = Base64.decode64(gigya_secret_key)
     timestamp = Time.now.gmtime.to_i
     nonce = "#{user_id}#{id}#{timestamp}"
     http_method = "GET" #@shmu: define your HTTP method

     #@shmu: parameters are ordered alphabetically, base string include http method api call and parameters, all seperetaed with unescaped "&"
     parameters = CGI.escape("apiKey=#{CGI.escape(api_key)}&nonce=#{CGI.escape(nonce)}&status=#{message_text}&timestamp=#{timestamp}&uid=#{user_id}")
     base_string = "#{http_method}&#{CGI.escape(api_url)}&#{parameters}"
  
     #@shmu: hmac/sha1 encription for the gigya secret and the base_string
     hmacsha1 = HMAC::SHA1.digest(gigya_secret, base_string)
     gigya_sign = Base64.encode64(hmacsha1).chomp.gsub(/\n/,'')
     gigya_sign = CGI.escape(gigya_sign) #@shmu: we must escape the signature as well.
  
     #@shmu: finalized api request url with the signed signature
     request_url = "#{api_url}?apiKey=#{api_key}&nonce=#{nonce}&status=#{message_text}&timestamp=#{timestamp}&uid=#{user_id}&sig=#{gigya_sign}"
     puts request_url.inspect
  
     #@shmu: read the response
     response_text = open(request_url).read

     #@shmu: handle error messages from gigya XML output.
     regexp = /\(.*?)\<\/statusCode\>/
     status_code = response_text.scan(regexp).to_s.to_i
     if status_code == 200
       okmsg = "Gigya: Content Shared: #{status_message} [#{user.nick}]"
       logger.info okmsg
       return okmsg
     else
       raise "GIGYA RESPONSE ERROR: #{response_text.scan(/\(.*?)\<\/errorMessage\>/).to_s} \n\n #{response_text.inspect} \n\n\n [id:#{id}, user:#{user}]\n\nStatusMessage: #{status_message}\n\n Basestring: #{base_string}\n\n RequestURL: #{request_url}\n\n\n"
     end
   end
end



And here is the controller method for the ajax singature call:

class GigyaController < ApplicationController
  #@shmu
  # seal a signature to be passed by the user's client to gigya, to register its user id and the corresponding gigya user.
  # returns a json with all the parameters that are passed through the client.
  def signature
    if authenticated_user
      user_id = @user.id
    
      #@shmu: timestamp is GMT 0
      gmtimestamp = Time.now.gmtime.to_s(:db)
      base_string = "#{gmtimestamp}_#{user_id.to_s}"
      gigya_secret_key = "YOUR_GIGYA_SECRET_KEY"
    
      #@shmu: decode secret key and sign it with the base_string
      gigya_secret = Base64.decode64(gigya_secret_key)
      hmacsha1 = HMAC::SHA1.digest(gigya_secret, base_string)
    
      gigya_sign = Base64.encode64(hmacsha1).chomp.gsub(/\n/,'')
    
      #@shmu: signature is passed back to client in JSON format
      render :inline => "{ 'user_id' : \"#{user_id}\", 'timestamp' : \"#{gmtimestamp}\", 'signature' : \"#{gigya_sign}\" }" and return
    else
      render :inline => 'failed' and return
    end
  end
end


Post question in the comments, and i will be happy to answer

5 comments:

Jack Dempsey said...

Shmuel,

Thanks for the nice writeup. I spent a lot of time trying to get this working, and your post was hugely helpful.

I had to do a couple things differently, most importantly to CGI.escape my uid, as it was of the form "_gid_AHLj25weRIsBSKfS...."

I will probably take what I've done and make a gem out of it on github. If you're interested, I can leave another post here when its ready.

Thanks again!
Jack

Anonymous said...

I consider, that you commit an error. I can defend the position. Write to me in PM, we will communicate. indian ciallis pill splitter I have a nice joke for you) Why do carpenters believe that there is no such thing as stone? Because they never SAW it!!

Corporate Entertainment said...

A very nice informational blog.Keep on making such important blog post.Your work is really being appreciated by some one.

Carpet cleaners Sacramento said...

Can you afford to keep integrating newer social networks and deprecate older ones?

Nolle Prosequi said...

The SDKs make it simple to integrate Gigya's service for various applications.

:popular_tags => [ruby, rails, ruby-on-rails, רובי-און-ריילס, console,,tricks, youtube, links, screeshots, toturials],
:email_me => 'shmuel@ahdut.com',
:subscribe_to_rss => ,
:sites => [pawst.com, urlazy.com],
:sponsored_by =>