api-auth 1.5.0 → 2.6.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.
Files changed (68) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/main.yml +71 -0
  3. data/.gitignore +13 -44
  4. data/.rubocop.yml +39 -0
  5. data/.rubocop_todo.yml +83 -0
  6. data/Appraisals +12 -36
  7. data/CHANGELOG.md +75 -1
  8. data/README.md +155 -52
  9. data/Rakefile +1 -1
  10. data/VERSION +1 -1
  11. data/api_auth.gemspec +35 -23
  12. data/gemfiles/rails_60.gemfile +9 -0
  13. data/gemfiles/rails_61.gemfile +9 -0
  14. data/gemfiles/rails_70.gemfile +9 -0
  15. data/lib/api-auth.rb +1 -1
  16. data/lib/api_auth/base.rb +41 -35
  17. data/lib/api_auth/errors.rb +4 -3
  18. data/lib/api_auth/headers.rb +38 -42
  19. data/lib/api_auth/helpers.rb +7 -16
  20. data/lib/api_auth/railtie.rb +34 -74
  21. data/lib/api_auth/request_drivers/action_controller.rb +27 -27
  22. data/lib/api_auth/request_drivers/action_dispatch.rb +0 -6
  23. data/lib/api_auth/request_drivers/curb.rb +16 -21
  24. data/lib/api_auth/request_drivers/faraday.rb +25 -34
  25. data/lib/api_auth/request_drivers/faraday_env.rb +102 -0
  26. data/lib/api_auth/request_drivers/grape_request.rb +87 -0
  27. data/lib/api_auth/request_drivers/http.rb +96 -0
  28. data/lib/api_auth/request_drivers/httpi.rb +22 -27
  29. data/lib/api_auth/request_drivers/net_http.rb +21 -26
  30. data/lib/api_auth/request_drivers/rack.rb +23 -28
  31. data/lib/api_auth/request_drivers/rest_client.rb +24 -29
  32. data/lib/api_auth.rb +4 -0
  33. data/lib/faraday/api_auth/middleware.rb +35 -0
  34. data/lib/faraday/api_auth.rb +8 -0
  35. data/spec/api_auth_spec.rb +135 -96
  36. data/spec/faraday_middleware_spec.rb +17 -0
  37. data/spec/headers_spec.rb +148 -108
  38. data/spec/helpers_spec.rb +8 -10
  39. data/spec/railtie_spec.rb +80 -99
  40. data/spec/request_drivers/action_controller_spec.rb +122 -79
  41. data/spec/request_drivers/action_dispatch_spec.rb +212 -85
  42. data/spec/request_drivers/curb_spec.rb +36 -33
  43. data/spec/request_drivers/faraday_env_spec.rb +188 -0
  44. data/spec/request_drivers/faraday_spec.rb +87 -83
  45. data/spec/request_drivers/grape_request_spec.rb +280 -0
  46. data/spec/request_drivers/http_spec.rb +190 -0
  47. data/spec/request_drivers/httpi_spec.rb +59 -59
  48. data/spec/request_drivers/net_http_spec.rb +70 -66
  49. data/spec/request_drivers/rack_spec.rb +101 -97
  50. data/spec/request_drivers/rest_client_spec.rb +218 -144
  51. data/spec/spec_helper.rb +15 -12
  52. metadata +144 -83
  53. data/.travis.yml +0 -40
  54. data/Gemfile.lock +0 -115
  55. data/gemfiles/rails_23.gemfile +0 -9
  56. data/gemfiles/rails_23.gemfile.lock +0 -70
  57. data/gemfiles/rails_30.gemfile +0 -9
  58. data/gemfiles/rails_30.gemfile.lock +0 -92
  59. data/gemfiles/rails_31.gemfile +0 -9
  60. data/gemfiles/rails_31.gemfile.lock +0 -98
  61. data/gemfiles/rails_32.gemfile +0 -9
  62. data/gemfiles/rails_32.gemfile.lock +0 -97
  63. data/gemfiles/rails_4.gemfile +0 -9
  64. data/gemfiles/rails_4.gemfile.lock +0 -94
  65. data/gemfiles/rails_41.gemfile +0 -9
  66. data/gemfiles/rails_41.gemfile.lock +0 -98
  67. data/gemfiles/rails_42.gemfile +0 -9
  68. data/gemfiles/rails_42.gemfile.lock +0 -115
@@ -0,0 +1,188 @@
1
+ require 'spec_helper'
2
+
3
+ describe ApiAuth::RequestDrivers::FaradayEnv do
4
+ let(:timestamp) { Time.now.utc.httpdate }
5
+
6
+ let(:request) do
7
+ Faraday::Env.new(verb, body, URI(uri), {}, Faraday::Utils::Headers.new(headers))
8
+ end
9
+
10
+ let(:verb) { :put }
11
+ let(:uri) { 'https://localhost/resource.xml?foo=bar&bar=foo' }
12
+ let(:body) { "hello\nworld" }
13
+
14
+ let(:headers) do
15
+ {
16
+ 'Authorization' => 'APIAuth 1044:12345',
17
+ 'X-Authorization-Content-SHA256' => '47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=',
18
+ 'content-type' => 'text/plain',
19
+ 'date' => timestamp
20
+ }
21
+ end
22
+
23
+ subject(:driven_request) { described_class.new(request) }
24
+
25
+ describe 'getting headers correctly' do
26
+ it 'gets the content_type' do
27
+ expect(driven_request.content_type).to eq('text/plain')
28
+ end
29
+
30
+ context 'without Content-Type' do
31
+ let(:headers) { {} }
32
+
33
+ it 'defaults to url-encoded' do
34
+ expect(driven_request.content_type).to eq 'application/x-www-form-urlencoded'
35
+ end
36
+ end
37
+
38
+ it 'gets the content_hash' do
39
+ expect(driven_request.content_hash).to eq('47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=')
40
+ end
41
+
42
+ it 'gets the request_uri' do
43
+ expect(driven_request.request_uri).to eq('/resource.xml?foo=bar&bar=foo')
44
+ end
45
+
46
+ it 'gets the timestamp' do
47
+ expect(driven_request.timestamp).to eq(timestamp)
48
+ end
49
+
50
+ it 'gets the authorization_header' do
51
+ expect(driven_request.authorization_header).to eq('APIAuth 1044:12345')
52
+ end
53
+
54
+ describe '#calculated_hash' do
55
+ it 'calculates hash from the body' do
56
+ expect(driven_request.calculated_hash).to eq('JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g=')
57
+ expect(driven_request.body.bytesize).to eq(11)
58
+ end
59
+
60
+ context 'no body' do
61
+ let(:body) { nil }
62
+
63
+ it 'treats no body as empty string' do
64
+ expect(driven_request.calculated_hash).to eq('47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=')
65
+ expect(driven_request.body.bytesize).to eq(0)
66
+ end
67
+ end
68
+
69
+ context 'multipart content' do
70
+ let(:body) { File.new('spec/fixtures/upload.png') }
71
+
72
+ it 'calculates correctly for multipart content' do
73
+ expect(driven_request.calculated_hash).to eq('AlKDe7kjMQhuKgKuNG8I7GA93MasHcaVJkJLaUT7+dY=')
74
+ expect(driven_request.body.bytesize).to eq(5112)
75
+ end
76
+ end
77
+ end
78
+
79
+ describe 'http_method' do
80
+ context 'when put request' do
81
+ let(:verb) { :put }
82
+
83
+ it 'returns upcased put' do
84
+ expect(driven_request.http_method).to eq('PUT')
85
+ end
86
+ end
87
+
88
+ context 'when get request' do
89
+ let(:verb) { :get }
90
+
91
+ it 'returns upcased get' do
92
+ expect(driven_request.http_method).to eq('GET')
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ describe 'setting headers correctly' do
99
+ let(:headers) do
100
+ {
101
+ 'content-type' => 'text/plain'
102
+ }
103
+ end
104
+
105
+ describe '#populate_content_hash' do
106
+ context 'when request type has no body' do
107
+ let(:verb) { :get }
108
+
109
+ it "doesn't populate content hash" do
110
+ driven_request.populate_content_hash
111
+ expect(request.request_headers['X-Authorization-Content-SHA256']).to be_nil
112
+ end
113
+ end
114
+
115
+ context 'when request type has a body' do
116
+ let(:verb) { :put }
117
+
118
+ it 'populates content hash' do
119
+ driven_request.populate_content_hash
120
+ expect(request.request_headers['X-Authorization-Content-SHA256']).to eq('JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g=')
121
+ end
122
+
123
+ it 'refreshes the cached headers' do
124
+ driven_request.populate_content_hash
125
+ expect(driven_request.content_hash).to eq('JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g=')
126
+ end
127
+ end
128
+ end
129
+
130
+ describe '#set_date' do
131
+ before do
132
+ allow(Time).to receive_message_chain(:now, :utc, :httpdate).and_return(timestamp)
133
+ end
134
+
135
+ it 'sets the date header of the request' do
136
+ driven_request.set_date
137
+ expect(request.request_headers['DATE']).to eq(timestamp)
138
+ end
139
+ end
140
+
141
+ describe '#set_auth_header' do
142
+ it 'sets the auth header' do
143
+ driven_request.set_auth_header('APIAuth 1044:54321')
144
+ expect(request.request_headers['Authorization']).to eq('APIAuth 1044:54321')
145
+ end
146
+ end
147
+ end
148
+
149
+ describe 'content_hash_mismatch?' do
150
+ context 'when request type has no body' do
151
+ let(:verb) { :get }
152
+
153
+ it 'is false' do
154
+ expect(driven_request.content_hash_mismatch?).to be false
155
+ end
156
+ end
157
+
158
+ context 'when request type has a body' do
159
+ let(:verb) { :put }
160
+
161
+ context 'when calculated matches sent' do
162
+ before do
163
+ request.request_headers['X-Authorization-Content-SHA256'] = 'JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g='
164
+ end
165
+
166
+ it 'is false' do
167
+ expect(driven_request.content_hash_mismatch?).to be false
168
+ end
169
+ end
170
+
171
+ context "when calculated doesn't match sent" do
172
+ before do
173
+ request['X-Authorization-Content-SHA256'] = '3'
174
+ end
175
+
176
+ it 'is true' do
177
+ expect(driven_request.content_hash_mismatch?).to be true
178
+ end
179
+ end
180
+ end
181
+ end
182
+
183
+ describe 'fetch_headers' do
184
+ it 'returns request headers' do
185
+ expect(driven_request.fetch_headers).to include('CONTENT-TYPE' => 'text/plain')
186
+ end
187
+ end
188
+ end
@@ -1,8 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ApiAuth::RequestDrivers::FaradayRequest do
4
-
5
- let(:timestamp){ Time.now.utc.httpdate }
4
+ let(:timestamp) { Time.now.utc.httpdate }
6
5
 
7
6
  let(:faraday_stubs) do
8
7
  Faraday::Adapter::Test::Stubs.new do |stub|
@@ -20,8 +19,8 @@ describe ApiAuth::RequestDrivers::FaradayRequest do
20
19
 
21
20
  let(:request_headers) do
22
21
  {
23
- 'Authorization' => 'APIAuth 1044:12345',
24
- 'Content-MD5' => "1B2M2Y8AsgTpgAmY7PhCfg==",
22
+ 'Authorization' => 'APIAuth 1044:12345',
23
+ 'X-Authorization-Content-SHA256' => '47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=',
25
24
  'content-type' => 'text/plain',
26
25
  'DATE' => timestamp
27
26
  }
@@ -38,42 +37,42 @@ describe ApiAuth::RequestDrivers::FaradayRequest do
38
37
  faraday_request
39
38
  end
40
39
 
41
- subject(:driven_request){ ApiAuth::RequestDrivers::FaradayRequest.new(request) }
40
+ subject(:driven_request) { ApiAuth::RequestDrivers::FaradayRequest.new(request) }
42
41
 
43
- describe "getting headers correctly" do
44
- it "gets the content_type" do
42
+ describe 'getting headers correctly' do
43
+ it 'gets the content_type' do
45
44
  expect(driven_request.content_type).to eq('text/plain')
46
45
  end
47
46
 
48
- it "gets the content_md5" do
49
- expect(driven_request.content_md5).to eq('1B2M2Y8AsgTpgAmY7PhCfg==')
47
+ it 'gets the content_hash' do
48
+ expect(driven_request.content_hash).to eq('47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=')
50
49
  end
51
50
 
52
- it "gets the request_uri" do
51
+ it 'gets the request_uri' do
53
52
  expect(driven_request.request_uri).to eq('/resource.xml?bar=foo&foo=bar')
54
53
  end
55
54
 
56
- it "gets the timestamp" do
55
+ it 'gets the timestamp' do
57
56
  expect(driven_request.timestamp).to eq(timestamp)
58
57
  end
59
58
 
60
- it "gets the authorization_header" do
59
+ it 'gets the authorization_header' do
61
60
  expect(driven_request.authorization_header).to eq('APIAuth 1044:12345')
62
61
  end
63
62
 
64
- describe "#calculated_md5" do
65
- it "calculates md5 from the body" do
66
- expect(driven_request.calculated_md5).to eq('kZXQvrKoieG+Be1rsZVINw==')
63
+ describe '#calculated_hash' do
64
+ it 'calculates hash from the body' do
65
+ expect(driven_request.calculated_hash).to eq('JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g=')
67
66
  end
68
67
 
69
- it "treats no body as empty string" do
68
+ it 'treats no body as empty string' do
70
69
  request.body = nil
71
- expect(driven_request.calculated_md5).to eq('1B2M2Y8AsgTpgAmY7PhCfg==')
70
+ expect(driven_request.calculated_hash).to eq('47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=')
72
71
  end
73
72
  end
74
73
 
75
- describe "http_method" do
76
- context "when put request" do
74
+ describe 'http_method' do
75
+ context 'when put request' do
77
76
  let(:request) do
78
77
  faraday_request = nil
79
78
 
@@ -85,12 +84,12 @@ describe ApiAuth::RequestDrivers::FaradayRequest do
85
84
  faraday_request
86
85
  end
87
86
 
88
- it "returns upcased put" do
87
+ it 'returns upcased put' do
89
88
  expect(driven_request.http_method).to eq('PUT')
90
89
  end
91
90
  end
92
91
 
93
- context "when get request" do
92
+ context 'when get request' do
94
93
  let(:request) do
95
94
  faraday_request = nil
96
95
 
@@ -102,160 +101,165 @@ describe ApiAuth::RequestDrivers::FaradayRequest do
102
101
  faraday_request
103
102
  end
104
103
 
105
- it "returns upcased get" do
104
+ it 'returns upcased get' do
106
105
  expect(driven_request.http_method).to eq('GET')
107
106
  end
108
107
  end
109
108
  end
110
109
  end
111
110
 
112
- describe "setting headers correctly" do
111
+ describe 'setting headers correctly' do
113
112
  let(:request_headers) do
114
113
  {
115
114
  'content-type' => 'text/plain'
116
115
  }
117
116
  end
118
117
 
119
- describe "#populate_content_md5" do
120
- context "when getting" do
121
- it "doesn't populate content-md5" do
122
- request.method = :get
123
- driven_request.populate_content_md5
124
- expect(request.headers["Content-MD5"]).to be_nil
118
+ describe '#populate_content_hash' do
119
+ context 'when getting' do
120
+ it "doesn't populate content hash" do
121
+ request.http_method = :get
122
+ driven_request.populate_content_hash
123
+ expect(request.headers['X-Authorization-Content-SHA256']).to be_nil
125
124
  end
126
125
  end
127
126
 
128
- context "when posting" do
129
- it "populates content-md5" do
130
- request.method = :post
131
- driven_request.populate_content_md5
132
- expect(request.headers["Content-MD5"]).to eq('kZXQvrKoieG+Be1rsZVINw==')
127
+ context 'when posting' do
128
+ it 'populates content hash' do
129
+ request.http_method = :post
130
+ driven_request.populate_content_hash
131
+ expect(request.headers['X-Authorization-Content-SHA256']).to eq('JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g=')
133
132
  end
134
133
 
135
- it "refreshes the cached headers" do
136
- driven_request.populate_content_md5
137
- expect(driven_request.content_md5).to eq('kZXQvrKoieG+Be1rsZVINw==')
134
+ it 'refreshes the cached headers' do
135
+ driven_request.populate_content_hash
136
+ expect(driven_request.content_hash).to eq('JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g=')
138
137
  end
139
138
  end
140
139
 
141
- context "when putting" do
142
- it "populates content-md5" do
143
- request.method = :put
144
- driven_request.populate_content_md5
145
- expect(request.headers["Content-MD5"]).to eq('kZXQvrKoieG+Be1rsZVINw==')
140
+ context 'when putting' do
141
+ it 'populates content hash' do
142
+ request.http_method = :put
143
+ driven_request.populate_content_hash
144
+ expect(request.headers['X-Authorization-Content-SHA256']).to eq('JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g=')
146
145
  end
147
146
 
148
- it "refreshes the cached headers" do
149
- driven_request.populate_content_md5
150
- expect(driven_request.content_md5).to eq('kZXQvrKoieG+Be1rsZVINw==')
147
+ it 'refreshes the cached headers' do
148
+ driven_request.populate_content_hash
149
+ expect(driven_request.content_hash).to eq('JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g=')
151
150
  end
152
151
  end
153
152
 
154
- context "when deleting" do
155
- it "doesn't populate content-md5" do
156
- request.method = :delete
157
- driven_request.populate_content_md5
158
- expect(request.headers["Content-MD5"]).to be_nil
153
+ context 'when deleting' do
154
+ it "doesn't populate content hash" do
155
+ request.http_method = :delete
156
+ driven_request.populate_content_hash
157
+ expect(request.headers['X-Authorization-Content-SHA256']).to be_nil
159
158
  end
160
159
  end
161
-
162
160
  end
163
161
 
164
- describe "#set_date" do
162
+ describe '#set_date' do
165
163
  before do
166
164
  allow(Time).to receive_message_chain(:now, :utc, :httpdate).and_return(timestamp)
167
165
  end
168
166
 
169
- it "sets the date header of the request" do
167
+ it 'sets the date header of the request' do
170
168
  driven_request.set_date
171
169
  expect(request.headers['DATE']).to eq(timestamp)
172
170
  end
173
171
 
174
- it "refreshes the cached headers" do
172
+ it 'refreshes the cached headers' do
175
173
  driven_request.set_date
176
174
  expect(driven_request.timestamp).to eq(timestamp)
177
175
  end
178
176
  end
179
177
 
180
- describe "#set_auth_header" do
181
- it "sets the auth header" do
178
+ describe '#set_auth_header' do
179
+ it 'sets the auth header' do
182
180
  driven_request.set_auth_header('APIAuth 1044:54321')
183
181
  expect(request.headers['Authorization']).to eq('APIAuth 1044:54321')
184
182
  end
185
183
  end
186
184
  end
187
185
 
188
- describe "md5_mismatch?" do
189
- context "when getting" do
186
+ describe 'content_hash_mismatch?' do
187
+ context 'when getting' do
190
188
  before do
191
- request.method = :get
189
+ request.http_method = :get
192
190
  end
193
191
 
194
- it "is false" do
195
- expect(driven_request.md5_mismatch?).to be false
192
+ it 'is false' do
193
+ expect(driven_request.content_hash_mismatch?).to be false
196
194
  end
197
195
  end
198
196
 
199
- context "when posting" do
197
+ context 'when posting' do
200
198
  before do
201
- request.method = :post
199
+ request.http_method = :post
202
200
  end
203
201
 
204
- context "when calculated matches sent" do
202
+ context 'when calculated matches sent' do
205
203
  before do
206
- request.headers["Content-MD5"] = 'kZXQvrKoieG+Be1rsZVINw=='
204
+ request.headers['X-Authorization-Content-SHA256'] = 'JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g='
207
205
  end
208
206
 
209
- it "is false" do
210
- expect(driven_request.md5_mismatch?).to be false
207
+ it 'is false' do
208
+ expect(driven_request.content_hash_mismatch?).to be false
211
209
  end
212
210
  end
213
211
 
214
212
  context "when calculated doesn't match sent" do
215
213
  before do
216
- request.headers["Content-MD5"] = "3"
214
+ request.headers['X-Authorization-Content-SHA256'] = '3'
217
215
  end
218
216
 
219
- it "is true" do
220
- expect(driven_request.md5_mismatch?).to be true
217
+ it 'is true' do
218
+ expect(driven_request.content_hash_mismatch?).to be true
221
219
  end
222
220
  end
223
221
  end
224
222
 
225
- context "when putting" do
223
+ context 'when putting' do
226
224
  before do
227
- request.method = :put
225
+ request.http_method = :put
228
226
  end
229
227
 
230
- context "when calculated matches sent" do
228
+ context 'when calculated matches sent' do
231
229
  before do
232
- request.headers["Content-MD5"] = 'kZXQvrKoieG+Be1rsZVINw=='
230
+ request.headers['X-Authorization-Content-SHA256'] = 'JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g='
233
231
  end
234
232
 
235
- it "is false" do
236
- expect(driven_request.md5_mismatch?).to be false
233
+ it 'is false' do
234
+ expect(driven_request.content_hash_mismatch?).to be false
237
235
  end
238
236
  end
239
237
 
240
238
  context "when calculated doesn't match sent" do
241
239
  before do
242
- request.headers["Content-MD5"] = "3"
240
+ request.headers['X-Authorization-Content-SHA256'] = '3'
243
241
  end
244
242
 
245
- it "is true" do
246
- expect(driven_request.md5_mismatch?).to be true
243
+ it 'is true' do
244
+ expect(driven_request.content_hash_mismatch?).to be true
247
245
  end
248
246
  end
249
247
  end
250
248
 
251
- context "when deleting" do
249
+ context 'when deleting' do
252
250
  before do
253
- request.method = :delete
251
+ request.http_method = :delete
254
252
  end
255
253
 
256
- it "is false" do
257
- expect(driven_request.md5_mismatch?).to be false
254
+ it 'is false' do
255
+ expect(driven_request.content_hash_mismatch?).to be false
258
256
  end
259
257
  end
260
258
  end
259
+
260
+ describe 'fetch_headers' do
261
+ it 'returns request headers' do
262
+ expect(driven_request.fetch_headers).to include('CONTENT-TYPE' => 'text/plain')
263
+ end
264
+ end
261
265
  end