halorgium-auth-hmac 1.1.1.2010090301

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,320 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+ require "net/http"
3
+ require 'time'
4
+ require 'yaml'
5
+ require 'ruby-debug'
6
+ require 'active_support/core_ext/hash/except'
7
+
8
+ # Class for doing a custom signature
9
+ class CustomSignature < String
10
+ def initialize(request, authenticate_referrer=false)
11
+ self << "Custom signature string: #{request.method}"
12
+ end
13
+ end
14
+
15
+ def signature(value, secret)
16
+ digest = OpenSSL::Digest::Digest.new('sha1')
17
+ Base64.encode64(OpenSSL::HMAC.digest(digest, secret, value)).strip
18
+ end
19
+
20
+ describe AuthHMAC do
21
+ before(:each) do
22
+ @request = Net::HTTP::Put.new("/path/to/put?foo=bar&bar=foo",
23
+ 'content-type' => 'text/plain',
24
+ 'content-md5' => 'blahblah',
25
+ 'date' => "Thu, 10 Jul 2008 03:29:56 GMT")
26
+ end
27
+
28
+ describe ".canonical_string" do
29
+ it "should generate a canonical string using default method" do
30
+ AuthHMAC.canonical_string(@request).should == "PUT\ntext/plain\nblahblah\nThu, 10 Jul 2008 03:29:56 GMT\n/path/to/put"
31
+ end
32
+ end
33
+
34
+ describe ".signature" do
35
+ it "should generate a valid signature string for a secret" do
36
+ AuthHMAC.signature(@request, 'secret').should == "71wAJM4IIu/3o6lcqx/tw7XnAJs="
37
+ end
38
+ end
39
+
40
+ describe ".sign!" do
41
+ before(:each) do
42
+ @request = Net::HTTP::Put.new("/path/to/put?foo=bar&bar=foo",
43
+ 'content-type' => 'text/plain',
44
+ 'content-md5' => 'blahblah',
45
+ 'date' => "Thu, 10 Jul 2008 03:29:56 GMT")
46
+ end
47
+
48
+ it "should sign using the key passed in as a parameter" do
49
+ AuthHMAC.sign!(@request, "my-key-id", "secret")
50
+ @request['Authorization'].should == "AuthHMAC my-key-id:71wAJM4IIu/3o6lcqx/tw7XnAJs="
51
+ end
52
+
53
+ it "should sign using custom service id" do
54
+ AuthHMAC.sign!(@request, "my-key-id", "secret", { :service_id => 'MyService' })
55
+ @request['Authorization'].should == "MyService my-key-id:71wAJM4IIu/3o6lcqx/tw7XnAJs="
56
+ end
57
+
58
+ it "should sign using custom signature method" do
59
+ options = {
60
+ :service_id => 'MyService',
61
+ :signature => CustomSignature
62
+ }
63
+ # debugger
64
+ AuthHMAC.sign!(@request, "my-key-id", "secret", options)
65
+ @request['Authorization'].should == "MyService my-key-id:/L4N1v1BZSHfAYkQjsvZn696D9c="
66
+ end
67
+ end
68
+
69
+ describe "#sign!" do
70
+ before(:each) do
71
+ @get_request = Net::HTTP::Get.new("/")
72
+ @put_request = Net::HTTP::Put.new("/path/to/put?foo=bar&bar=foo",
73
+ 'content-type' => 'text/plain',
74
+ 'content-md5' => 'blahblah',
75
+ 'date' => "Thu, 10 Jul 2008 03:29:56 GMT")
76
+ @store = mock('store')
77
+ @store.stub!(:[]).and_return("")
78
+ @authhmac = AuthHMAC.new(@store)
79
+ end
80
+
81
+ describe "default AuthHMAC with CanonicalString signature" do
82
+ it "should add an Authorization header" do
83
+ @authhmac.sign!(@get_request, 'key-id')
84
+ @get_request.key?("Authorization").should be_true
85
+ end
86
+
87
+ it "should fetch the secret from the store" do
88
+ @store.should_receive(:[]).with('key-id').and_return('secret')
89
+ @authhmac.sign!(@get_request, 'key-id')
90
+ end
91
+
92
+ it "should prefix the Authorization Header with AuthHMAC" do
93
+ @authhmac.sign!(@get_request, 'key-id')
94
+ @get_request['Authorization'].should match(/^AuthHMAC /)
95
+ end
96
+
97
+ it "should include the key id as the first part of the Authorization header value" do
98
+ @authhmac.sign!(@get_request, 'key-id')
99
+ @get_request['Authorization'].should match(/^AuthHMAC key-id:/)
100
+ end
101
+
102
+ it "should include the base64 encoded HMAC signature as the last part of the header value" do
103
+ @authhmac.sign!(@get_request, 'key-id')
104
+ @get_request['Authorization'].should match(/:[A-Za-z0-9+\/]{26,28}[=]{0,2}$/)
105
+ end
106
+
107
+ it "should create a complete signature" do
108
+ @store.should_receive(:[]).with('my-key-id').and_return('secret')
109
+ @authhmac.sign!(@put_request, "my-key-id")
110
+ @put_request['Authorization'].should == "AuthHMAC my-key-id:71wAJM4IIu/3o6lcqx/tw7XnAJs="
111
+ end
112
+ end
113
+
114
+ describe "custom signatures" do
115
+ before(:each) do
116
+ @options = {
117
+ :service_id => 'MyService',
118
+ :signature => CustomSignature
119
+ }
120
+ @authhmac = AuthHMAC.new(@store, @options)
121
+ end
122
+
123
+ it "should prefix the Authorization header with custom service id" do
124
+ @authhmac.sign!(@get_request, 'key-id')
125
+ @get_request['Authorization'].should match(/^MyService /)
126
+ end
127
+
128
+ it "should create a complete signature using options" do
129
+ @store.should_receive(:[]).with('my-key-id').and_return('secret')
130
+ @authhmac.sign!(@put_request, "my-key-id")
131
+ @put_request['Authorization'].should == "MyService my-key-id:/L4N1v1BZSHfAYkQjsvZn696D9c="
132
+ end
133
+ end
134
+ end
135
+
136
+ describe "authenticated?" do
137
+ before(:each) do
138
+ @credentials = YAML.load(File.read(File.join(File.dirname(__FILE__), 'fixtures', 'credentials.yml')))
139
+ @authhmac = AuthHMAC.new(@credentials)
140
+ @request = Net::HTTP::Get.new("/path/to/get?foo=bar&bar=foo", 'date' => "Thu, 10 Jul 2008 03:29:56 GMT")
141
+ end
142
+
143
+ it "should return false when there is no Authorization Header" do
144
+ @authhmac.authenticated?(@request).should be_false
145
+ end
146
+
147
+ it "should return false when the Authorization value isn't prefixed with HMAC" do
148
+ @request['Authorization'] = "id:secret"
149
+ @authhmac.authenticated?(@request).should be_false
150
+ end
151
+
152
+ it "should return false when the access key id can't be found" do
153
+ @request['Authorization'] = 'AuthHMAC missing-key:blah'
154
+ @authhmac.authenticated?(@request).should be_false
155
+ end
156
+
157
+ it "should return false when there is no hmac" do
158
+ @request['Authorization'] = 'AuthHMAC missing-key:'
159
+ @authhmac.authenticated?(@request).should be_false
160
+ end
161
+
162
+ it "should return false when the hmac doesn't match" do
163
+ @request['Authorization'] = 'AuthHMAC access key 1:blah'
164
+ @authhmac.authenticated?(@request).should be_false
165
+ end
166
+
167
+ it "should return false if the request was modified after signing" do
168
+ @authhmac.sign!(@request, 'access key 1')
169
+ @request.content_type = 'text/plain'
170
+ @authhmac.authenticated?(@request).should be_false
171
+ end
172
+
173
+ it "should return true when the hmac does match" do
174
+ @authhmac.sign!(@request, 'access key 1')
175
+ @authhmac.authenticated?(@request).should be_true
176
+ end
177
+
178
+ describe "custom signatures" do
179
+ before(:each) do
180
+ @options = {
181
+ :service_id => 'MyService',
182
+ :signature => CustomSignature
183
+ }
184
+ end
185
+
186
+ it "should return false for invalid service id" do
187
+ @authhmac.sign!(@request, 'access key 1')
188
+ AuthHMAC.new(@credentials, @options.except(:signature)).authenticated?(@request).should be_false
189
+ end
190
+
191
+ it "should return false for request using default CanonicalString signature" do
192
+ @authhmac.sign!(@request, 'access key 1')
193
+ AuthHMAC.new(@credentials, @options.except(:service_id)).authenticated?(@request).should be_false
194
+ end
195
+
196
+ it "should return true when valid" do
197
+ @authhmac = AuthHMAC.new(@credentials, @options)
198
+ @authhmac.sign!(@request, 'access key 1')
199
+ @authhmac.authenticated?(@request).should be_true
200
+ end
201
+ end
202
+ end
203
+
204
+ describe "#sign! with YAML credentials" do
205
+ before(:each) do
206
+ @authhmac = AuthHMAC.new(YAML.load(File.read(File.join(File.dirname(__FILE__), 'fixtures', 'credentials.yml'))))
207
+ @request = Net::HTTP::Get.new("/path/to/get?foo=bar&bar=foo", 'date' => "Thu, 10 Jul 2008 03:29:56 GMT")
208
+ end
209
+
210
+ it "should raise an argument error if credentials are missing" do
211
+ lambda { @authhmac.sign!(@request, 'missing') }.should raise_error(ArgumentError)
212
+ end
213
+
214
+ it "should sign with the secret" do
215
+ @authhmac.sign!(@request, "access key 1")
216
+ @request['Authorization'].should == "AuthHMAC access key 1:ovwO0OBERuF3/uR3aowaUCkFMiE="
217
+ end
218
+
219
+ it "should sign with the other secret" do
220
+ @authhmac.sign!(@request, "access key 2")
221
+ @request['Authorization'].should == "AuthHMAC access key 2:vT010RQm4IZ6+UCVpK2/N0FLpLw="
222
+ end
223
+ end
224
+
225
+ describe AuthHMAC::Headers do
226
+ before(:each) do
227
+ @authhmac = AuthHMAC.new(YAML.load(File.read(File.join(File.dirname(__FILE__), 'fixtures', 'credentials.yml'))))
228
+ end
229
+
230
+ it "should support Rack::Request objects" do
231
+ rack_req = mock("MockRackRequest")
232
+ headers = {
233
+ 'HTTP_AUTHORIZATION' => ["AuthHMAC access key 1:ovwO0OBERuF3/uR3aowaUCkFMiE="],
234
+ 'HTTP_DATE' => ['Thu, 10 Jul 2008 03:29:56 GMT']
235
+ }
236
+ rack_req.stub!(:env).and_return(headers)
237
+ rack_req.stub!(:request_method).and_return('GET')
238
+ rack_req.stub!(:path).and_return("/path/to/get?foo=bar&bar=foo")
239
+ rack_req.stub!(:[]).and_return({'foo' => 'bar', 'bar' => 'foo'})
240
+ rack_req.stub!(:body).and_return(StringIO.new(''))
241
+ @authhmac.authenticated?(rack_req).should be_true
242
+ end
243
+ end
244
+
245
+ describe AuthHMAC::CanonicalString do
246
+ it "should include the http verb when it is GET" do
247
+ request = Net::HTTP::Get.new("/")
248
+ AuthHMAC::CanonicalString.new(request).should match(/GET/)
249
+ end
250
+
251
+ it "should include the http verb when it is POST" do
252
+ request = Net::HTTP::Post.new("/")
253
+ AuthHMAC::CanonicalString.new(request).should match(/POST/)
254
+ end
255
+
256
+ it "should include the content-type" do
257
+ request = Net::HTTP::Put.new("/", {'Content-Type' => 'application/xml'})
258
+ AuthHMAC::CanonicalString.new(request).should match(/application\/xml/)
259
+ end
260
+
261
+ it "should include the content-type even if the case is messed up" do
262
+ request = Net::HTTP::Put.new("/", {'cOntent-type' => 'text/html'})
263
+ AuthHMAC::CanonicalString.new(request).should match(/text\/html/)
264
+ end
265
+
266
+ it "should include the content-md5" do
267
+ request = Net::HTTP::Put.new("/", {'Content-MD5' => 'skwkend'})
268
+ AuthHMAC::CanonicalString.new(request).should match(/skwkend/)
269
+ end
270
+
271
+ it "should include the content-md5 even if the case is messed up" do
272
+ request = Net::HTTP::Put.new("/", {'content-md5' => 'adsada'})
273
+ AuthHMAC::CanonicalString.new(request).should match(/adsada/)
274
+ end
275
+
276
+ it "should generate the content-md5 if one wasn't included and there is a request body" do
277
+ request = Net::HTTP::Put.new("/")
278
+ request.body = "foo=bar&baz=qux"
279
+ content_md5 = OpenSSL::Digest::MD5.hexdigest(request.body)
280
+ AuthHMAC::CanonicalString.new(request).should match(/#{content_md5}/)
281
+ end
282
+
283
+ it "should not generate a content-md5 when there is no request body" do
284
+ request = Net::HTTP::Get.new("/")
285
+ AuthHMAC::CanonicalString.new(request).should match(/^GET\n\n\n/)
286
+ end
287
+
288
+ it "should include the date" do
289
+ date = Time.now.httpdate
290
+ request = Net::HTTP::Put.new("/", {'Date' => date})
291
+ AuthHMAC::CanonicalString.new(request).should match(/#{date}/)
292
+ end
293
+
294
+ it "should include the request path" do
295
+ request = Net::HTTP::Get.new("/path/to/file")
296
+ AuthHMAC::CanonicalString.new(request).should match(/\/path\/to\/file[^?]?/)
297
+ end
298
+
299
+ it "should ignore the query string of the request path" do
300
+ request = Net::HTTP::Get.new("/other/path/to/file?query=foo")
301
+ AuthHMAC::CanonicalString.new(request).should match(/\/other\/path\/to\/file[^?]?/)
302
+ end
303
+
304
+ it "should build the correct string" do
305
+ date = Time.now.httpdate
306
+ request = Net::HTTP::Put.new("/path/to/put?foo=bar&bar=foo",
307
+ 'content-type' => 'text/plain',
308
+ 'content-md5' => 'blahblah',
309
+ 'date' => date)
310
+ AuthHMAC::CanonicalString.new(request).should == "PUT\ntext/plain\nblahblah\n#{date}\n/path/to/put"
311
+ end
312
+
313
+ it "should build the correct string when some elements are missing" do
314
+ date = Time.now.httpdate
315
+ request = Net::HTTP::Get.new("/path/to/get?foo=bar&bar=foo",
316
+ 'date' => date)
317
+ AuthHMAC::CanonicalString.new(request).should == "GET\n\n\n#{date}\n/path/to/get"
318
+ end
319
+ end
320
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,10 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ gem 'rspec'
6
+ require 'spec'
7
+ end
8
+
9
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
10
+ require 'auth-hmac'
@@ -0,0 +1,34 @@
1
+ desc 'Release the website and new gem version'
2
+ task :deploy => [:check_version, :website, :release] do
3
+ puts "Remember to create SVN tag:"
4
+ puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " +
5
+ "svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
6
+ puts "Suggested comment:"
7
+ puts "Tagging release #{CHANGES}"
8
+ end
9
+
10
+ desc 'Runs tasks website_generate and install_gem as a local deployment of the gem'
11
+ task :local_deploy => [:website_generate, :install_gem]
12
+
13
+ task :check_version do
14
+ unless ENV['VERSION']
15
+ puts 'Must pass a VERSION=x.y.z release version'
16
+ exit
17
+ end
18
+ unless ENV['VERSION'] == VERS
19
+ puts "Please update your version.rb to match the release version, currently #{VERS}"
20
+ exit
21
+ end
22
+ end
23
+
24
+ desc 'Install the package as a gem, without generating documentation(ri/rdoc)'
25
+ task :install_gem_no_doc => [:clean, :package] do
26
+ sh "#{'sudo ' unless Hoe::WINDOZE }gem install pkg/*.gem --no-rdoc --no-ri"
27
+ end
28
+
29
+ namespace :manifest do
30
+ desc 'Recreate Manifest.txt to include ALL files'
31
+ task :refresh do
32
+ `rake check_manifest | patch -p0 > Manifest.txt`
33
+ end
34
+ end
@@ -0,0 +1,7 @@
1
+ task :ruby_env do
2
+ RUBY_APP = if RUBY_PLATFORM =~ /java/
3
+ "jruby"
4
+ else
5
+ "ruby"
6
+ end unless defined? RUBY_APP
7
+ end
data/tasks/rspec.rake ADDED
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require 'spec'
6
+ end
7
+ begin
8
+ require 'spec/rake/spectask'
9
+ rescue LoadError
10
+ puts <<-EOS
11
+ To use rspec for testing you must install rspec gem:
12
+ gem install rspec
13
+ EOS
14
+ exit(0)
15
+ end
16
+
17
+ desc "Run the specs under spec/models"
18
+ Spec::Rake::SpecTask.new do |t|
19
+ t.spec_opts = ['--options', "spec/spec.opts"]
20
+ t.spec_files = FileList['spec/**/*_spec.rb']
21
+ end
@@ -0,0 +1,9 @@
1
+ # stubs for the website generation
2
+ # To install the website framework:
3
+ # script/generate website
4
+
5
+ task :website_generate
6
+
7
+ task :website_upload
8
+
9
+ task :website => :publish_docs
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: halorgium-auth-hmac
3
+ version: !ruby/object:Gem::Version
4
+ hash: 4020180521
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 1
9
+ - 1
10
+ - 2010090301
11
+ version: 1.1.1.2010090301
12
+ platform: ruby
13
+ authors:
14
+ - Sean Geoghegan
15
+ - ascarter
16
+ - Wes Morgan
17
+ - Adrian Cushman
18
+ autorequire:
19
+ bindir: bin
20
+ cert_chain: []
21
+
22
+ date: 2010-09-02 00:00:00 -07:00
23
+ default_executable:
24
+ dependencies:
25
+ - !ruby/object:Gem::Dependency
26
+ name: hoe
27
+ prerelease: false
28
+ requirement: &id001 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ hash: 51
34
+ segments:
35
+ - 1
36
+ - 8
37
+ - 2
38
+ version: 1.8.2
39
+ type: :development
40
+ version_requirements: *id001
41
+ description: A gem providing HMAC based authentication for HTTP. This is the DNC Labs fork.
42
+ email: innovationlab@dnc.org
43
+ executables: []
44
+
45
+ extensions: []
46
+
47
+ extra_rdoc_files:
48
+ - History.txt
49
+ - License.txt
50
+ - Manifest.txt
51
+ - PostInstall.txt
52
+ - README.txt
53
+ files:
54
+ - History.txt
55
+ - License.txt
56
+ - Manifest.txt
57
+ - PostInstall.txt
58
+ - README.txt
59
+ - Rakefile
60
+ - config/hoe.rb
61
+ - config/requirements.rb
62
+ - lib/auth-hmac.rb
63
+ - lib/auth-hmac/version.rb
64
+ - script/console
65
+ - script/destroy
66
+ - script/generate
67
+ - setup.rb
68
+ - spec/auth-hmac_spec.rb
69
+ - spec/spec.opts
70
+ - spec/spec_helper.rb
71
+ - tasks/deployment.rake
72
+ - tasks/environment.rake
73
+ - tasks/rspec.rake
74
+ - tasks/website.rake
75
+ has_rdoc: true
76
+ homepage: http://github.com/dnclabs/auth-hmac/
77
+ licenses: []
78
+
79
+ post_install_message:
80
+ rdoc_options:
81
+ - --main
82
+ - README.txt
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ hash: 3
91
+ segments:
92
+ - 0
93
+ version: "0"
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ hash: 3
100
+ segments:
101
+ - 0
102
+ version: "0"
103
+ requirements: []
104
+
105
+ rubyforge_project: auth-hmac
106
+ rubygems_version: 1.3.7
107
+ signing_key:
108
+ specification_version: 2
109
+ summary: A gem providing HMAC based authentication for HTTP
110
+ test_files: []
111
+