Created
July 14, 2009 09:37
-
-
Save hannestyden/146876 to your computer and use it in GitHub Desktop.
Reference implementation for OAuth request signing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Signing an OAuth request | |
# Hannes Tydén, hannes@soundcloud.com, 2009-07-14 | |
# Updated at 2009-09-03 to support OAuth 1.0a | |
# This is designed to be executed in an editor evaluating expressions and outputting the result inline. | |
# The spec: | |
# http://oauth.net/core/1.0#signing_process | |
# Read more: | |
# http://www.hueniverse.com/hueniverse/2008/10/beginners-gui-1.html | |
require 'rubygems' | |
require 'cgi' | |
require 'uri' | |
require 'base64' | |
require 'hmac/sha1' | |
# Constants | |
ENCODING = { | |
:form => 'application/x-www-form-urlencoded', | |
:multipart => 'multipart/form-data' | |
} | |
### SETUP | |
# Change these variables | |
use_oauth_10a = false | |
oauth_callback = nil | |
#### | |
## Consumer specific | |
# FROM EXAMPLE | |
consumer_key = "dpf43f3p2l4k3l03" | |
consumer_secret = "kd94hf93k423kf44" | |
#### | |
## Token specific | |
# FROM EXAMPLE | |
token_key = "nnch734d00sl2jdk" | |
token_secret = "pfkkdhi9sl3r4s00" | |
#### | |
## Request specific | |
request_method = 'GET' | |
# FROM EXAMPLE | |
request_url = "http://photos.example.net/photos" | |
request_content_type = ENCODING[:form] | |
oauth_nonce = "kllo9940pd9333jh" | |
oauth_timestamp = "1191242096" | |
# FROM EXAMPLE | |
request_uri_parameters = { | |
"size" => "original", | |
"file" => "vacation.jpg" | |
} | |
request_body_parameters = { | |
} | |
# Setup is done, please proceed | |
### /SETUP | |
### GENERIC CODE | |
# Just change below this point if you want to change behavior. | |
oauth_parameters = { | |
'oauth_consumer_key' => consumer_key, | |
'oauth_nonce' => oauth_nonce, | |
'oauth_timestamp' => oauth_timestamp, | |
'oauth_signature_method' => "HMAC-SHA1", | |
'oauth_version' => "1.0" | |
} | |
unless token_key == '' | |
oauth_parameters.merge!( | |
'oauth_token' => token_key | |
) | |
end | |
if use_oauth_10a | |
oauth_parameters.merge!( | |
'oauth_callback' => oauth_callback || 'oob' | |
) | |
end | |
# Merge all parameters together | |
merged_parameters = request_uri_parameters.merge(oauth_parameters) | |
# Only use parameters sent in body when encoding is "application/x-www-form-urlencoded" and HTTP method is POST | |
# See http://groups.google.com/group/oauth/browse_thread/thread/42ef5fecc54a7e9a | |
if request_content_type == ENCODING[:form] && request_method == 'POST' | |
merged_parameters.merge!(request_body_parameters) | |
end | |
# 9.1. Signature Base String | |
# 9.1.1. Normalize Request Parameters | |
normalized_request_parameters = merged_parameters.map { |name, value| "#{CGI.escape(name)}=#{CGI.escape(value)}" }.sort.join("&") | |
normalized_request_parameters # => "file=vacation.jpg&oauth_consumer_key=dpf43f3p2l4k3l03&oauth_nonce=kllo9940pd9333jh&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1191242096&oauth_token=nnch734d00sl2jdk&oauth_version=1.0&size=original" | |
# 9.1.2. Construct Request URL | |
uri = URI.parse(request_url) | |
normalizied_request_url = "#{uri.scheme}://#{uri.host}#{uri.path}".downcase | |
normalizied_request_url # => "http://photos.example.net/photos" | |
# 9.1.3. Concatenate Request Elements | |
normalizied_request_method = request_method.upcase | |
signature_base_string = [ normalizied_request_method, normalizied_request_url, normalized_request_parameters ].map { |element| CGI.escape(element) }.join("&") | |
signature_base_string # => "GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal" | |
# 9.2. HMAC-SHA1 | |
# 9.2.1. Generating Signature | |
concatenated_secrets = "#{consumer_secret}&#{token_secret}" | |
concatenated_secrets # => "kd94hf93k423kf44&pfkkdhi9sl3r4s00" | |
hmac_sha1_digest = HMAC::SHA1.digest(concatenated_secrets, signature_base_string) | |
oauth_signature = Base64.encode64(hmac_sha1_digest).strip | |
oauth_signature # => "tR3+Ty81lMeYAr/Fid0kMTYa/WM=" | |
# Signed request | |
uri = URI.parse(request_url) | |
uri_query = uri.query.gsub(/\&$/, "") # Remove trailing ampersands | |
uri.query = [ uri_query, normalized_request_parameters, "oauth_signature=#{CGI.escape(oauth_signature)}" ].reject { |s| s.to_s == "" }.join("&") | |
signed_request_url = uri.to_s | |
signed_request_url # => "http://photos.example.net/photos?file=vacation.jpg&oauth_consumer_key=dpf43f3p2l4k3l03&oauth_nonce=kllo9940pd9333jh&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1191242096&oauth_token=nnch734d00sl2jdk&oauth_version=1.0&size=original&oauth_signature=tR3%2BTy81lMeYAr%2FFid0kMTYa%2FWM%3D" | |
# "http://photos.example.net/photos?file=vacation.jpg&oauth_consumer_key=dpf43f3p2l4k3l03&oauth_nonce=kllo9940pd9333jh&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1191242096&oauth_token=nnch734d00sl2jdk&oauth_version=1.0&size=original&oauth_signature=tR3%2BTy81lMeYAr%2FFid0kMTYa%2FWM%3D" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment