Skip to content

Commit

Permalink
Added support to class methods sign! and authenticated? for receiving…
Browse files Browse the repository at this point in the history
… options hash including service_id and custom signature method.

Added rspec tests.
  • Loading branch information
ascarter committed Jan 8, 2009
1 parent a686ffd commit eecd76c
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 43 deletions.
25 changes: 20 additions & 5 deletions lib/auth-hmac.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ def find_header(keys, headers)

include Headers

@@default_signature_method = lambda { |r| CanonicalString.new(r) }

# Create an AuthHMAC instance using the given credential store
#
# Credential Store:
Expand All @@ -62,19 +64,32 @@ def find_header(keys, headers)
#
def initialize(credential_store, options = nil)
@credential_store = credential_store

# Defaults
@service_id = self.class.name
@signature_method = lambda { |r| CanonicalString.new(r) }
@signature_method = @@default_signature_method

parse_options(options)
end

# Signs a request using a given access key id and secret.
#
def AuthHMAC.sign!(request, access_key_id, secret)
self.new(access_key_id => secret).sign!(request, access_key_id)
# Supports same options as AuthHMAC.initialize for overriding service_id and
# signature method.
#
def AuthHMAC.sign!(request, access_key_id, secret, options = nil)
credentials = { access_key_id => secret }
self.new(credentials, options).sign!(request, access_key_id)
end

def AuthHMAC.authenticated?(request, access_key_id, secret)
self.new(access_key_id => secret).authenticated?(request)
# Authenticates a request using HMAC
#
# Supports same options as AuthHMAC.initialize for overriding service_id and
# signature method.
#
def AuthHMAC.authenticated?(request, access_key_id, secret, options)
credentials = { access_key_id => secret }
self.new(credentials, options).authenticated?(request)
end

# Signs a request using the access_key_id and the secret associated with that id
Expand Down
133 changes: 95 additions & 38 deletions spec/auth-hmac_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@
require 'active_resource'
require 'active_resource/http_mock'

# Class for doing a custom signature
class CustomSignature < String
def initialize(request)
self << "Custom signature string: #{request.method}"
end
end

describe AuthHMAC do
describe ".sign!" do
it "should sign using the key passed in as a parameter" do
Expand All @@ -20,6 +27,28 @@
AuthHMAC.sign!(request, "my-key-id", "secret")
request['Authorization'].should == "AuthHMAC my-key-id:71wAJM4IIu/3o6lcqx/tw7XnAJs="
end

it "should sign using custom service id" do
request = Net::HTTP::Put.new("/path/to/put?foo=bar&bar=foo",
'content-type' => 'text/plain',
'content-md5' => 'blahblah',
'date' => "Thu, 10 Jul 2008 03:29:56 GMT")
AuthHMAC.sign!(request, "my-key-id", "secret", { :service_id => 'MyService' })
request['Authorization'].should == "MyService my-key-id:71wAJM4IIu/3o6lcqx/tw7XnAJs="
end

it "should sign using custom signature method" do
request = Net::HTTP::Put.new("/path/to/put?foo=bar&bar=foo",
'content-type' => 'text/plain',
'content-md5' => 'blahblah',
'date' => "Thu, 10 Jul 2008 03:29:56 GMT")
options = {
:service_id => 'MyService',
:signature_method => lambda { |r| CustomSignature.new(r) }
}
AuthHMAC.sign!(request, "my-key-id", "secret", options)
request['Authorization'].should == "MyService my-key-id:/L4N1v1BZSHfAYkQjsvZn696D9c="
end
end

describe "#sign!" do
Expand All @@ -28,45 +57,73 @@
@store.stub!(:[]).and_return("")
@authhmac = AuthHMAC.new(@store)
end

it "should add an Authorization header" do
request = Net::HTTP::Get.new("/")
@authhmac.sign!(request, 'key-id')
request.key?("Authorization").should be_true
end

it "should fetch the secret from the store" do
request = Net::HTTP::Get.new("/")
@store.should_receive(:[]).with('key-id').and_return('secret')
@authhmac.sign!(request, 'key-id')
end

it "should prefix the Authorization Header with AuthHMAC" do
request = Net::HTTP::Get.new("/")
@authhmac.sign!(request, 'key-id')
request['Authorization'].should match(/^AuthHMAC /)
end

it "should include the key id as the first part of the Authorization header value" do
request = Net::HTTP::Get.new("/")
@authhmac.sign!(request, 'key-id')
request['Authorization'].should match(/^AuthHMAC key-id:/)
end

it "should include the base64 encoded HMAC signature as the last part of the header value" do
request = Net::HTTP::Get.new("/path")
@authhmac.sign!(request, 'key-id')
request['Authorization'].should match(/:[A-Za-z0-9+\/]{26,28}[=]{0,2}$/)

describe "default AuthHMAC with CanonicalString signature" do
it "should add an Authorization header" do
request = Net::HTTP::Get.new("/")
@authhmac.sign!(request, 'key-id')
request.key?("Authorization").should be_true
end

it "should fetch the secret from the store" do
request = Net::HTTP::Get.new("/")
@store.should_receive(:[]).with('key-id').and_return('secret')
@authhmac.sign!(request, 'key-id')
end

it "should prefix the Authorization Header with AuthHMAC" do
request = Net::HTTP::Get.new("/")
@authhmac.sign!(request, 'key-id')
request['Authorization'].should match(/^AuthHMAC /)
end

it "should include the key id as the first part of the Authorization header value" do
request = Net::HTTP::Get.new("/")
@authhmac.sign!(request, 'key-id')
request['Authorization'].should match(/^AuthHMAC key-id:/)
end

it "should include the base64 encoded HMAC signature as the last part of the header value" do
request = Net::HTTP::Get.new("/path")
@authhmac.sign!(request, 'key-id')
request['Authorization'].should match(/:[A-Za-z0-9+\/]{26,28}[=]{0,2}$/)
end

it "should create a complete signature" do
@store.should_receive(:[]).with('my-key-id').and_return('secret')
request = Net::HTTP::Put.new("/path/to/put?foo=bar&bar=foo",
'content-type' => 'text/plain',
'content-md5' => 'blahblah',
'date' => "Thu, 10 Jul 2008 03:29:56 GMT")
@authhmac.sign!(request, "my-key-id")
request['Authorization'].should == "AuthHMAC my-key-id:71wAJM4IIu/3o6lcqx/tw7XnAJs="
end
end

it "should create a complete signature" do
@store.should_receive(:[]).with('my-key-id').and_return('secret')
request = Net::HTTP::Put.new("/path/to/put?foo=bar&bar=foo",
'content-type' => 'text/plain',
'content-md5' => 'blahblah',
'date' => "Thu, 10 Jul 2008 03:29:56 GMT")
@authhmac.sign!(request, "my-key-id")
request['Authorization'].should == "AuthHMAC my-key-id:71wAJM4IIu/3o6lcqx/tw7XnAJs="

describe "custom signatures" do
before(:each) do
@options = {
:service_id => 'MyService',
:signature_method => lambda { |r| CustomSignature.new(r) }
}
@authhmac = AuthHMAC.new(@store, @options)
end

it "should prefix the Authorization header with custom service id" do
request = Net::HTTP::Get.new("/")
@authhmac.sign!(request, 'key-id')
request['Authorization'].should match(/^MyService /)
end

it "should create a complete signature using options" do
@store.should_receive(:[]).with('my-key-id').and_return('secret')
request = Net::HTTP::Put.new("/path/to/put?foo=bar&bar=foo",
'content-type' => 'text/plain',
'content-md5' => 'blahblah',
'date' => "Thu, 10 Jul 2008 03:29:56 GMT")
@authhmac.sign!(request, "my-key-id")
request['Authorization'].should == "MyService my-key-id:/L4N1v1BZSHfAYkQjsvZn696D9c="
end
end
end

Expand Down

0 comments on commit eecd76c

Please sign in to comment.