api-auth 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.travis.yml +17 -0
- data/Appraisals +29 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +42 -11
- data/LICENSE.txt +1 -1
- data/README.md +15 -13
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/api_auth.gemspec +5 -3
- data/gemfiles/rails_23.gemfile +7 -0
- data/gemfiles/rails_23.gemfile.lock +57 -0
- data/gemfiles/rails_30.gemfile +7 -0
- data/gemfiles/rails_30.gemfile.lock +79 -0
- data/gemfiles/rails_31.gemfile +9 -0
- data/gemfiles/rails_31.gemfile.lock +85 -0
- data/gemfiles/rails_32.gemfile +9 -0
- data/gemfiles/rails_32.gemfile.lock +84 -0
- data/gemfiles/rails_4.gemfile +9 -0
- data/gemfiles/rails_4.gemfile.lock +81 -0
- data/lib/api_auth.rb +1 -0
- data/lib/api_auth/base.rb +1 -1
- data/lib/api_auth/headers.rb +4 -0
- data/lib/api_auth/helpers.rb +18 -5
- data/lib/api_auth/request_drivers/action_controller.rb +2 -2
- data/lib/api_auth/request_drivers/httpi.rb +80 -0
- data/lib/api_auth/request_drivers/net_http.rb +3 -1
- data/lib/api_auth/request_drivers/rack.rb +1 -1
- data/lib/api_auth/request_drivers/rest_client.rb +4 -4
- data/spec/api_auth_spec.rb +97 -22
- data/spec/headers_spec.rb +64 -3
- data/spec/railtie_spec.rb +51 -36
- data/spec/spec_helper.rb +2 -1
- metadata +55 -9
data/spec/headers_spec.rb
CHANGED
@@ -91,6 +91,18 @@ describe "ApiAuth::Headers" do
|
|
91
91
|
headers.canonical_string
|
92
92
|
request.headers['DATE'].should be_nil
|
93
93
|
end
|
94
|
+
|
95
|
+
it "doesn't mess up symbol based headers" do
|
96
|
+
headers = { 'Content-MD5' => "e59ff97941044f85df5297e1c302d260",
|
97
|
+
:content_type => "text/plain",
|
98
|
+
'Date' => "Mon, 23 Jan 1984 03:29:56 GMT" }
|
99
|
+
@request = RestClient::Request.new(:url => "/resource.xml?foo=bar&bar=foo",
|
100
|
+
:headers => headers,
|
101
|
+
:method => :put)
|
102
|
+
@headers = ApiAuth::Headers.new(@request)
|
103
|
+
ApiAuth.sign!(@request, "some access id", "some secret key")
|
104
|
+
@request.processed_headers.should have_key('Content-Type')
|
105
|
+
end
|
94
106
|
end
|
95
107
|
|
96
108
|
describe "with Curb" do
|
@@ -138,8 +150,10 @@ describe "ApiAuth::Headers" do
|
|
138
150
|
|
139
151
|
describe "with ActionController" do
|
140
152
|
|
153
|
+
let(:request_klass){ ActionDispatch::Request rescue ActionController::Request }
|
154
|
+
|
141
155
|
before(:each) do
|
142
|
-
@request =
|
156
|
+
@request = request_klass.new(
|
143
157
|
'PATH_INFO' => '/resource.xml',
|
144
158
|
'QUERY_STRING' => 'foo=bar&bar=foo',
|
145
159
|
'REQUEST_METHOD' => 'PUT',
|
@@ -159,7 +173,7 @@ describe "ApiAuth::Headers" do
|
|
159
173
|
end
|
160
174
|
|
161
175
|
it "should set the DATE header if one is not already present" do
|
162
|
-
@request =
|
176
|
+
@request = request_klass.new(
|
163
177
|
'PATH_INFO' => '/resource.xml',
|
164
178
|
'QUERY_STRING' => 'foo=bar&bar=foo',
|
165
179
|
'REQUEST_METHOD' => 'PUT',
|
@@ -170,7 +184,7 @@ describe "ApiAuth::Headers" do
|
|
170
184
|
end
|
171
185
|
|
172
186
|
it "should not set the DATE header just by asking for the canonical_string" do
|
173
|
-
request =
|
187
|
+
request = request_klass.new(
|
174
188
|
'PATH_INFO' => '/resource.xml',
|
175
189
|
'QUERY_STRING' => 'foo=bar&bar=foo',
|
176
190
|
'REQUEST_METHOD' => 'PUT',
|
@@ -220,4 +234,51 @@ describe "ApiAuth::Headers" do
|
|
220
234
|
end
|
221
235
|
end
|
222
236
|
|
237
|
+
describe "with HTTPI" do
|
238
|
+
before(:each) do
|
239
|
+
@request = HTTPI::Request.new("http://localhost/resource.xml?foo=bar&bar=foo")
|
240
|
+
@request.headers.merge!({
|
241
|
+
'content-type' => 'text/plain',
|
242
|
+
'content-md5' => 'e59ff97941044f85df5297e1c302d260',
|
243
|
+
'date' => "Mon, 23 Jan 1984 03:29:56 GMT"
|
244
|
+
})
|
245
|
+
@headers = ApiAuth::Headers.new(@request)
|
246
|
+
end
|
247
|
+
|
248
|
+
it "should generate the proper canonical string" do
|
249
|
+
@headers.canonical_string.should == CANONICAL_STRING
|
250
|
+
end
|
251
|
+
|
252
|
+
it "should set the authorization header" do
|
253
|
+
@headers.sign_header("alpha")
|
254
|
+
@headers.authorization_header.should == "alpha"
|
255
|
+
end
|
256
|
+
|
257
|
+
it "should set the DATE header if one is not already present" do
|
258
|
+
@request = Net::HTTP::Put.new("/resource.xml?foo=bar&bar=foo",
|
259
|
+
'content-type' => 'text/plain',
|
260
|
+
'content-md5' => 'e59ff97941044f85df5297e1c302d260')
|
261
|
+
ApiAuth.sign!(@request, "some access id", "some secret key")
|
262
|
+
@request['DATE'].should_not be_nil
|
263
|
+
end
|
264
|
+
|
265
|
+
it "should not set the DATE header just by asking for the canonical_string" do
|
266
|
+
request = Net::HTTP::Put.new("/resource.xml?foo=bar&bar=foo",
|
267
|
+
'content-type' => 'text/plain',
|
268
|
+
'content-md5' => 'e59ff97941044f85df5297e1c302d260')
|
269
|
+
headers = ApiAuth::Headers.new(request)
|
270
|
+
headers.canonical_string
|
271
|
+
request['DATE'].should be_nil
|
272
|
+
end
|
273
|
+
|
274
|
+
context "md5_mismatch?" do
|
275
|
+
it "is false if no md5 header is present" do
|
276
|
+
request = Net::HTTP::Put.new("/resource.xml?foo=bar&bar=foo",
|
277
|
+
'content-type' => 'text/plain')
|
278
|
+
headers = ApiAuth::Headers.new(request)
|
279
|
+
headers.md5_mismatch?.should be_false
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
223
284
|
end
|
data/spec/railtie_spec.rb
CHANGED
@@ -1,20 +1,20 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
3
|
describe "Rails integration" do
|
4
|
-
|
4
|
+
|
5
5
|
API_KEY_STORE = { "1044" => "l16imAXie1sRMcJODpOG7UwC1VyoqvO13jejkfpKWX4Z09W8DC9IrU23DvCwMry7pgSFW6c5S1GIfV0OY6F/vUA==" }
|
6
|
-
|
6
|
+
|
7
7
|
describe "Rails controller integration" do
|
8
|
-
|
8
|
+
|
9
9
|
class ApplicationController < ActionController::Base
|
10
|
-
|
10
|
+
|
11
11
|
private
|
12
|
-
|
12
|
+
|
13
13
|
def require_api_auth
|
14
14
|
if (access_id = get_api_access_id_from_request)
|
15
15
|
return true if api_authenticated?(API_KEY_STORE[access_id])
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
respond_to do |format|
|
19
19
|
format.xml { render :xml => "You are unauthorized to perform this action.", :status => 401 }
|
20
20
|
format.json { render :json => "You are unauthorized to perform this action.", :status => 401 }
|
@@ -23,82 +23,97 @@ describe "Rails integration" do
|
|
23
23
|
end
|
24
24
|
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
class TestController < ApplicationController
|
28
28
|
before_filter :require_api_auth, :only => [:index]
|
29
|
-
|
29
|
+
|
30
|
+
if defined?(ActionDispatch)
|
31
|
+
def self._routes
|
32
|
+
ActionDispatch::Routing::RouteSet.new
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
30
36
|
def index
|
31
37
|
render :text => "OK"
|
32
38
|
end
|
33
|
-
|
39
|
+
|
34
40
|
def public
|
35
41
|
render :text => "OK"
|
36
42
|
end
|
37
43
|
|
38
44
|
def rescue_action(e); raise(e); end
|
39
45
|
end
|
40
|
-
|
41
|
-
|
46
|
+
|
47
|
+
unless defined?(ActionDispatch)
|
48
|
+
ActionController::Routing::Routes.draw {|map| map.resources :test }
|
49
|
+
end
|
50
|
+
|
51
|
+
def generated_response(request, action = :index)
|
52
|
+
if defined?(ActionDispatch)
|
53
|
+
TestController.action(action).call(request.env).last
|
54
|
+
else
|
55
|
+
request.action = action.to_s
|
56
|
+
request.path = "/#{action.to_s}"
|
57
|
+
TestController.new.process(request, ActionController::TestResponse.new)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
42
61
|
it "should permit a request with properly signed headers" do
|
43
62
|
request = ActionController::TestRequest.new
|
44
63
|
request.env['DATE'] = Time.now.utc.httpdate
|
45
|
-
request.action = 'index'
|
46
|
-
request.path = "/index"
|
47
64
|
ApiAuth.sign!(request, "1044", API_KEY_STORE["1044"])
|
48
|
-
|
65
|
+
response = generated_response(request, :index)
|
66
|
+
response.code.should == "200"
|
49
67
|
end
|
50
|
-
|
68
|
+
|
51
69
|
it "should forbid a request with properly signed headers but timestamp > 15 minutes" do
|
52
70
|
request = ActionController::TestRequest.new
|
53
71
|
request.env['DATE'] = "Mon, 23 Jan 1984 03:29:56 GMT"
|
54
|
-
request.action = 'index'
|
55
|
-
request.path = "/index"
|
56
72
|
ApiAuth.sign!(request, "1044", API_KEY_STORE["1044"])
|
57
|
-
|
73
|
+
response = generated_response(request, :index)
|
74
|
+
response.code.should == "401"
|
58
75
|
end
|
59
|
-
|
76
|
+
|
60
77
|
it "should insert a DATE header in the request when one hasn't been specified" do
|
61
78
|
request = ActionController::TestRequest.new
|
62
|
-
request.action = 'index'
|
63
|
-
request.path = "/index"
|
64
79
|
ApiAuth.sign!(request, "1044", API_KEY_STORE["1044"])
|
65
80
|
request.headers['DATE'].should_not be_nil
|
66
81
|
end
|
67
82
|
|
68
83
|
it "should forbid an unsigned request to a protected controller action" do
|
69
84
|
request = ActionController::TestRequest.new
|
70
|
-
|
71
|
-
|
85
|
+
response = generated_response(request, :index)
|
86
|
+
response.code.should == "401"
|
72
87
|
end
|
73
88
|
|
74
89
|
it "should forbid a request with a bogus signature" do
|
75
90
|
request = ActionController::TestRequest.new
|
76
|
-
request.action = 'index'
|
77
91
|
request.env['Authorization'] = "APIAuth bogus:bogus"
|
78
|
-
|
92
|
+
response = generated_response(request, :index)
|
93
|
+
response.code.should == "401"
|
79
94
|
end
|
80
|
-
|
95
|
+
|
81
96
|
it "should allow non-protected controller actions to function as before" do
|
82
97
|
request = ActionController::TestRequest.new
|
83
|
-
|
84
|
-
|
85
|
-
TestController.new.process(request, ActionController::TestResponse.new).code.should == "200"
|
98
|
+
response = generated_response(request, :public)
|
99
|
+
response.code.should == "200"
|
86
100
|
end
|
87
|
-
|
101
|
+
|
88
102
|
end
|
89
|
-
|
103
|
+
|
90
104
|
describe "Rails ActiveResource integration" do
|
91
|
-
|
105
|
+
|
92
106
|
class TestResource < ActiveResource::Base
|
93
107
|
with_api_auth "1044", API_KEY_STORE["1044"]
|
94
108
|
self.site = "http://localhost/"
|
109
|
+
self.format = :xml
|
95
110
|
end
|
96
|
-
|
111
|
+
|
97
112
|
it "should send signed requests automagically" do
|
98
113
|
timestamp = Time.parse("Mon, 23 Jan 1984 03:29:56 GMT")
|
99
114
|
Time.should_receive(:now).at_least(1).times.and_return(timestamp)
|
100
115
|
ActiveResource::HttpMock.respond_to do |mock|
|
101
|
-
mock.get "/test_resources/1.xml",
|
116
|
+
mock.get "/test_resources/1.xml",
|
102
117
|
{
|
103
118
|
'Authorization' => 'APIAuth 1044:IbTx7VzSOGU55HNbV4y2jZDnVis=',
|
104
119
|
'Accept' => 'application/xml',
|
@@ -108,7 +123,7 @@ describe "Rails integration" do
|
|
108
123
|
end
|
109
124
|
TestResource.find(1)
|
110
125
|
end
|
111
|
-
|
126
|
+
|
112
127
|
end
|
113
|
-
|
128
|
+
|
114
129
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -5,11 +5,12 @@ require 'api_auth'
|
|
5
5
|
require 'amatch'
|
6
6
|
require 'rest_client'
|
7
7
|
require 'curb'
|
8
|
+
require 'httpi'
|
8
9
|
|
9
10
|
require 'active_support'
|
10
11
|
require 'active_support/test_case'
|
11
12
|
require 'action_controller'
|
12
|
-
require 'action_controller/
|
13
|
+
require 'action_controller/test_case'
|
13
14
|
require 'active_resource'
|
14
15
|
require 'active_resource/http_mock'
|
15
16
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: api-auth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-05-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: appraisal
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
14
30
|
- !ruby/object:Gem::Dependency
|
15
31
|
name: rake
|
16
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,7 +82,7 @@ dependencies:
|
|
66
82
|
requirements:
|
67
83
|
- - ~>
|
68
84
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
85
|
+
version: 3.0.0
|
70
86
|
type: :development
|
71
87
|
prerelease: false
|
72
88
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -74,7 +90,7 @@ dependencies:
|
|
74
90
|
requirements:
|
75
91
|
- - ~>
|
76
92
|
- !ruby/object:Gem::Version
|
77
|
-
version:
|
93
|
+
version: 3.0.0
|
78
94
|
- !ruby/object:Gem::Dependency
|
79
95
|
name: activesupport
|
80
96
|
requirement: !ruby/object:Gem::Requirement
|
@@ -82,7 +98,7 @@ dependencies:
|
|
82
98
|
requirements:
|
83
99
|
- - ~>
|
84
100
|
- !ruby/object:Gem::Version
|
85
|
-
version:
|
101
|
+
version: 3.0.0
|
86
102
|
type: :development
|
87
103
|
prerelease: false
|
88
104
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -90,7 +106,7 @@ dependencies:
|
|
90
106
|
requirements:
|
91
107
|
- - ~>
|
92
108
|
- !ruby/object:Gem::Version
|
93
|
-
version:
|
109
|
+
version: 3.0.0
|
94
110
|
- !ruby/object:Gem::Dependency
|
95
111
|
name: activeresource
|
96
112
|
requirement: !ruby/object:Gem::Requirement
|
@@ -98,7 +114,7 @@ dependencies:
|
|
98
114
|
requirements:
|
99
115
|
- - ~>
|
100
116
|
- !ruby/object:Gem::Version
|
101
|
-
version:
|
117
|
+
version: 3.0.0
|
102
118
|
type: :development
|
103
119
|
prerelease: false
|
104
120
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -106,7 +122,7 @@ dependencies:
|
|
106
122
|
requirements:
|
107
123
|
- - ~>
|
108
124
|
- !ruby/object:Gem::Version
|
109
|
-
version:
|
125
|
+
version: 3.0.0
|
110
126
|
- !ruby/object:Gem::Dependency
|
111
127
|
name: rest-client
|
112
128
|
requirement: !ruby/object:Gem::Requirement
|
@@ -139,6 +155,22 @@ dependencies:
|
|
139
155
|
- - ~>
|
140
156
|
- !ruby/object:Gem::Version
|
141
157
|
version: 0.8.1
|
158
|
+
- !ruby/object:Gem::Dependency
|
159
|
+
name: httpi
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ! '>='
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
142
174
|
description: Full HMAC auth implementation for use in your gems and Rails apps.
|
143
175
|
email: mauricio@edge14.com
|
144
176
|
executables: []
|
@@ -148,6 +180,9 @@ files:
|
|
148
180
|
- .document
|
149
181
|
- .gitignore
|
150
182
|
- .rspec
|
183
|
+
- .travis.yml
|
184
|
+
- Appraisals
|
185
|
+
- CHANGELOG.md
|
151
186
|
- Gemfile
|
152
187
|
- Gemfile.lock
|
153
188
|
- LICENSE.txt
|
@@ -155,6 +190,16 @@ files:
|
|
155
190
|
- Rakefile
|
156
191
|
- VERSION
|
157
192
|
- api_auth.gemspec
|
193
|
+
- gemfiles/rails_23.gemfile
|
194
|
+
- gemfiles/rails_23.gemfile.lock
|
195
|
+
- gemfiles/rails_30.gemfile
|
196
|
+
- gemfiles/rails_30.gemfile.lock
|
197
|
+
- gemfiles/rails_31.gemfile
|
198
|
+
- gemfiles/rails_31.gemfile.lock
|
199
|
+
- gemfiles/rails_32.gemfile
|
200
|
+
- gemfiles/rails_32.gemfile.lock
|
201
|
+
- gemfiles/rails_4.gemfile
|
202
|
+
- gemfiles/rails_4.gemfile.lock
|
158
203
|
- lib/api-auth.rb
|
159
204
|
- lib/api_auth.rb
|
160
205
|
- lib/api_auth/base.rb
|
@@ -165,6 +210,7 @@ files:
|
|
165
210
|
- lib/api_auth/request_drivers/action_controller.rb
|
166
211
|
- lib/api_auth/request_drivers/action_dispatch.rb
|
167
212
|
- lib/api_auth/request_drivers/curb.rb
|
213
|
+
- lib/api_auth/request_drivers/httpi.rb
|
168
214
|
- lib/api_auth/request_drivers/net_http.rb
|
169
215
|
- lib/api_auth/request_drivers/rack.rb
|
170
216
|
- lib/api_auth/request_drivers/rest_client.rb
|
@@ -195,7 +241,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
195
241
|
version: '0'
|
196
242
|
requirements: []
|
197
243
|
rubyforge_project:
|
198
|
-
rubygems_version: 1.8.
|
244
|
+
rubygems_version: 1.8.23.2
|
199
245
|
signing_key:
|
200
246
|
specification_version: 3
|
201
247
|
summary: Simple HMAC authentication for your APIs
|