ey-hmac 2.3.0 → 2.3.1

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/lib/ey-hmac.rb CHANGED
@@ -1,101 +1,102 @@
1
- require "ey-hmac/version"
1
+ # frozen_string_literal: true
2
+
3
+ require 'ey-hmac/version'
2
4
 
3
5
  require 'base64'
4
6
  require 'digest/md5'
5
7
  require 'openssl'
6
8
  require 'time'
7
9
 
8
- module Ey
9
- module Hmac
10
- Error = Class.new(StandardError)
11
-
12
- MissingSecret = Class.new(Error)
13
- MissingAuthorization = Class.new(Error)
14
- SignatureMismatch = Class.new(Error)
15
- ExpiredHmac = Class.new(Error)
16
-
17
- autoload :Adapter, "ey-hmac/adapter"
18
- autoload :Faraday, "ey-hmac/faraday"
19
- autoload :Rack, "ey-hmac/rack"
20
-
21
- def self.default_adapter=(default_adapter)
22
- @default_adapter = default_adapter
23
- end
24
-
25
- def self.default_adapter
26
- @default_adapter ||= if defined?(::Rack) || defined?(::Rails)
27
- Ey::Hmac::Adapter::Rack
28
- elsif defined?(::Faraday)
29
- Ey::Hmac::Adapter::Faraday
30
- end
31
- end
32
-
33
- # Signs request by calculating signature and adding it to the specified header
34
- # @example
35
- # Ey::Hmac.sign!(env, @key_id, @key_secret)
36
- #
37
- # @see Ey::Hmac::Adapter#sign!
38
- #
39
- # @param request [Hash] request environment
40
- # @option options [Ey::Hmac::Adapter] :adapter (#{default_adapter}) adapter to sign request with
41
- # @option options [Integer] :version (nil) signature version
42
- # @option options [String] :authorization_header ('Authorization') Authorization header key.
43
- # @option options [String] :service ('EyHmac') service name prefixed to {Ey::Hmac::Adapter#authorization}
44
- #
45
- # @return [String] authorization signature
46
- def self.sign!(request, key_id, key_secret, options={})
47
- adapter = options[:adapter] || Ey::Hmac.default_adapter
48
-
49
- raise ArgumentError, "Missing adapter and Ey::Hmac.default_adapter" unless adapter
50
-
51
- adapter.new(request, options).sign!(key_id, key_secret)
52
- end
53
-
54
- # @example
55
- # Ey::Hmac.authenticated? do |key_id|
56
- # @consumer = Consumer.where(auth_id: key_id).first
57
- # @consumer && @consumer.auth_key
58
- # end
59
- #
60
- # @see Ey::Hmac::Adapter#authenticated?
61
- # @see Ey::Hmac#authenticate!
62
- #
63
- # @param request [Hash] request environment
64
- # @option options [Ey::Hmac::Adapter] :adapter ({#default_adapter}) adapter to verify request with
65
- # @yieldparam key_id [String] public HMAC key
66
- #
67
- # @return [Boolean] success of authentication
68
- def self.authenticated?(request, options={}, &block)
69
- adapter = options[:adapter] || Ey::Hmac.default_adapter
70
-
71
- raise ArgumentError, "Missing adapter and Ey::Hmac.default_adapter" unless adapter
72
-
73
- adapter.new(request, options).authenticated?(&block)
74
- end
75
-
76
- # Check {Ey::Hmac::Adapter#authorization_signature} against calculated {Ey::Hmac::Adapter#signature}
77
- # @example
78
- # Ey::Hmac.authenticate! do |key_id|
79
- # @consumer = Consumer.where(auth_id: key_id).first
80
- # @consumer && @consumer.auth_key
81
- # end
82
- #
83
- # @see Ey::Hmac::Adapter#authenticate!
84
- #
85
- # @param request [Hash] request environment
86
- # @yieldparam key_id [String] public HMAC key
87
- # @option options [Ey::Hmac::Adapter] :adapter ({#default_adapter}) adapter to verify request with
88
- #
89
- # @raise [SignatureMismatch] if the value of {Ey::Hmac::Adapter#authorization_signature} does not match {Ey::Hmac::Adapter#signature}
90
- # @raise [MissingSecret] if the block does not return a private key matching +key_id+
91
- # @raise [MissingAuthorization] if the value of {Ey::Hmac::Adapter#authorization_signature} is nil
92
- # @return [TrueClass] if authentication was successful
93
- def self.authenticate!(request, options={}, &block)
94
- adapter = options[:adapter] || Ey::Hmac.default_adapter
95
-
96
- raise ArgumentError, "Missing adapter and Ey::Hmac.default_adapter" unless adapter
97
-
98
- adapter.new(request, options).authenticate!(&block)
99
- end
10
+ module Ey::Hmac
11
+ Error = Class.new(StandardError)
12
+
13
+ MissingSecret = Class.new(Error)
14
+ MissingAuthorization = Class.new(Error)
15
+ SignatureMismatch = Class.new(Error)
16
+ ExpiredHmac = Class.new(Error)
17
+
18
+ autoload :Adapter, 'ey-hmac/adapter'
19
+ autoload :Faraday, 'ey-hmac/faraday'
20
+ autoload :Rack, 'ey-hmac/rack'
21
+
22
+ def self.default_adapter=(default_adapter)
23
+ @default_adapter = default_adapter
24
+ end
25
+
26
+ def self.default_adapter
27
+ @default_adapter ||= if defined?(::Rack) || defined?(::Rails)
28
+ Ey::Hmac::Adapter::Rack
29
+ elsif defined?(::Faraday)
30
+ Ey::Hmac::Adapter::Faraday
31
+ end
32
+ end
33
+
34
+ # Signs request by calculating signature and adding it to the specified header
35
+ # @example
36
+ # Ey::Hmac.sign!(env, @key_id, @key_secret)
37
+ #
38
+ # @see Ey::Hmac::Adapter#sign!
39
+ #
40
+ # @param request [Hash] request environment
41
+ # @option options [Ey::Hmac::Adapter] :adapter (#{default_adapter}) adapter to sign request with
42
+ # @option options [Integer] :version (nil) signature version
43
+ # @option options [String] :authorization_header ('Authorization') Authorization header key.
44
+ # @option options [String] :service ('EyHmac') service name prefixed to {Ey::Hmac::Adapter#authorization}
45
+ #
46
+ # @return [String] authorization signature
47
+ def self.sign!(request, key_id, key_secret, options = {})
48
+ adapter = options[:adapter] || Ey::Hmac.default_adapter
49
+
50
+ raise ArgumentError, 'Missing adapter and Ey::Hmac.default_adapter' unless adapter
51
+
52
+ adapter.new(request, options).sign!(key_id, key_secret)
53
+ end
54
+
55
+ # @example
56
+ # Ey::Hmac.authenticated? do |key_id|
57
+ # @consumer = Consumer.where(auth_id: key_id).first
58
+ # @consumer && @consumer.auth_key
59
+ # end
60
+ #
61
+ # @see Ey::Hmac::Adapter#authenticated?
62
+ # @see Ey::Hmac#authenticate!
63
+ #
64
+ # @param request [Hash] request environment
65
+ # @option options [Ey::Hmac::Adapter] :adapter ({#default_adapter}) adapter to verify request with
66
+ # @yieldparam key_id [String] public HMAC key
67
+ #
68
+ # @return [Boolean] success of authentication
69
+ def self.authenticated?(request, options = {}, &block)
70
+ adapter = options[:adapter] || Ey::Hmac.default_adapter
71
+
72
+ raise ArgumentError, 'Missing adapter and Ey::Hmac.default_adapter' unless adapter
73
+
74
+ adapter.new(request, options).authenticated?(&block)
75
+ end
76
+
77
+ # Check {Ey::Hmac::Adapter#authorization_signature} against calculated {Ey::Hmac::Adapter#signature}
78
+ # @example
79
+ # Ey::Hmac.authenticate! do |key_id|
80
+ # @consumer = Consumer.where(auth_id: key_id).first
81
+ # @consumer && @consumer.auth_key
82
+ # end
83
+ #
84
+ # @see Ey::Hmac::Adapter#authenticate!
85
+ #
86
+ # @param request [Hash] request environment
87
+ # @yieldparam key_id [String] public HMAC key
88
+ # @option options [Ey::Hmac::Adapter] :adapter ({#default_adapter}) adapter to verify request with
89
+ #
90
+ # @raise [SignatureMismatch] if the value of {Ey::Hmac::Adapter#authorization_signature} does not
91
+ # match {Ey::Hmac::Adapter#signature}
92
+ # @raise [MissingSecret] if the block does not return a private key matching +key_id+
93
+ # @raise [MissingAuthorization] if the value of {Ey::Hmac::Adapter#authorization_signature} is nil
94
+ # @return [TrueClass] if authentication was successful
95
+ def self.authenticate!(request, options = {}, &block)
96
+ adapter = options[:adapter] || Ey::Hmac.default_adapter
97
+
98
+ raise ArgumentError, 'Missing adapter and Ey::Hmac.default_adapter' unless adapter
99
+
100
+ adapter.new(request, options).authenticate!(&block)
100
101
  end
101
102
  end
data/spec/faraday_spec.rb CHANGED
@@ -1,20 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
- describe "faraday" do
5
+ describe 'faraday' do
4
6
  before(:all) { Bundler.require(:faraday) }
5
7
 
6
8
  let!(:key_id) { SecureRandom.hex(8) }
7
9
  let!(:key_secret) { SecureRandom.hex(16) }
8
10
 
9
- describe "adapter" do
11
+ describe 'adapter' do
10
12
  let!(:adapter) { Ey::Hmac::Adapter::Faraday }
11
13
 
12
- it "signs a multipart post" do
14
+ it 'signs a multipart post' do
13
15
  app = lambda do |env|
14
16
  authenticated = Ey::Hmac.authenticate!(env, adapter: Ey::Hmac::Adapter::Rack) do |auth_id|
15
17
  (auth_id == key_id) && key_secret
16
18
  end
17
- [(authenticated ? 200 : 401), {"Content-Type" => "text/plain"}, []]
19
+ [(authenticated ? 200 : 401), { 'Content-Type' => 'text/plain' }, []]
18
20
  end
19
21
 
20
22
  require 'ey-hmac/faraday'
@@ -28,113 +30,115 @@ describe "faraday" do
28
30
  c.adapter(:rack, app)
29
31
  end
30
32
 
31
- tempfile = Tempfile.new("hmac")
33
+ tempfile = Tempfile.new('hmac')
32
34
  tempfile.write SecureRandom.hex(512)
33
35
  tempfile.close
34
36
 
35
37
  expect(
36
- connection.post { |req| req.body = {"output" => Faraday::UploadIO.new(tempfile.path, "text/plain")} }.status
38
+ connection.post { |req| req.body = { 'output' => Faraday::UploadIO.new(tempfile.path, 'text/plain') } }.status
37
39
  ).to eq(200)
38
40
  end
39
41
 
40
- it "signs and reads a request" do
41
- request = Faraday::Request.create(:get) { |r|
42
- r.path = "/auth"
43
- r.body = "{1: 2}"
44
- r.headers = {"Content-Type" => "application/xml"}
45
- }.to_env(
46
- Faraday::Connection.new("http://localhost")
42
+ it 'signs and reads a request' do
43
+ request = Faraday::Request.create(:get) do |r|
44
+ r.path = '/auth'
45
+ r.body = '{1: 2}'
46
+ r.headers = { 'Content-Type' => 'application/xml' }
47
+ end.to_env(
48
+ Faraday::Connection.new('http://localhost')
47
49
  )
48
50
 
49
51
  Ey::Hmac.sign!(request, key_id, key_secret, adapter: adapter)
50
52
 
51
- expect(request[:request_headers]['Authorization']).to start_with("EyHmac")
53
+ expect(request[:request_headers]['Authorization']).to start_with('EyHmac')
52
54
  expect(request[:request_headers]['Content-Digest']).to eq(Digest::MD5.hexdigest(request[:body]))
53
55
  expect(Time.parse(request[:request_headers]['Date'])).not_to be_nil
54
56
 
55
57
  yielded = false
56
58
 
57
- expect(Ey::Hmac.authenticated?(request, adapter: adapter) do |key_id|
59
+ expect(Ey::Hmac).to be_authenticated(request, adapter: adapter) do |key_id|
58
60
  expect(key_id).to eq(key_id)
59
61
  yielded = true
60
62
  key_secret
61
- end).to be_truthy
63
+ end
62
64
 
63
65
  expect(yielded).to be_truthy
64
66
  end
65
67
 
66
- it "does not set Content-Digest if body is nil" do
67
- request = Faraday::Request.create(:get) { |r|
68
- r.path = "/auth"
68
+ it 'does not set Content-Digest if body is nil' do
69
+ request = Faraday::Request.create(:get) do |r|
70
+ r.path = '/auth'
69
71
  r.body = nil
70
- r.headers = {"Content-Type" => "application/xml"}
71
- }.to_env(
72
- Faraday::Connection.new("http://localhost")
72
+ r.headers = { 'Content-Type' => 'application/xml' }
73
+ end.to_env(
74
+ Faraday::Connection.new('http://localhost')
73
75
  )
74
76
 
75
77
  Ey::Hmac.sign!(request, key_id, key_secret, adapter: adapter)
76
78
 
77
- expect(request[:request_headers]['Authorization']).to start_with("EyHmac")
79
+ expect(request[:request_headers]['Authorization']).to start_with('EyHmac')
78
80
  expect(request[:request_headers]).not_to have_key('Content-Digest')
79
81
  expect(Time.parse(request[:request_headers]['Date'])).not_to be_nil
80
82
 
81
83
  yielded = false
82
84
 
83
- expect(Ey::Hmac.authenticated?(request, adapter: adapter) do |key_id|
85
+ expect(Ey::Hmac).to be_authenticated(request, adapter: adapter) do |key_id|
84
86
  expect(key_id).to eq(key_id)
85
87
  yielded = true
86
88
  key_secret
87
- end).to be_truthy
89
+ end
88
90
 
89
91
  expect(yielded).to be_truthy
90
92
  end
91
93
 
92
- it "does not set Content-Digest if body is empty" do
94
+ it 'does not set Content-Digest if body is empty' do
93
95
  request = Faraday::Request.create(:get) do |r|
94
- r.path = "/auth"
95
- r.body = ""
96
- r.headers = {"Content-Type" => "application/xml"}
97
- end.to_env(Faraday::Connection.new("http://localhost"))
96
+ r.path = '/auth'
97
+ r.body = ''
98
+ r.headers = { 'Content-Type' => 'application/xml' }
99
+ end.to_env(Faraday::Connection.new('http://localhost'))
98
100
 
99
101
  Ey::Hmac.sign!(request, key_id, key_secret, adapter: adapter)
100
102
 
101
- expect(request[:request_headers]['Authorization']).to start_with("EyHmac")
103
+ expect(request[:request_headers]['Authorization']).to start_with('EyHmac')
102
104
  expect(request[:request_headers]).not_to have_key('Content-Digest')
103
- #expect(Time.parse(request[:request_headers]['Date'])).not_to be_nil
105
+ # expect(Time.parse(request[:request_headers]['Date'])).not_to be_nil
104
106
 
105
107
  yielded = false
106
108
 
107
- expect(Ey::Hmac.authenticated?(request, adapter: adapter) do |key_id|
109
+ expect(Ey::Hmac).to be_authenticated(request, adapter: adapter) do |key_id|
108
110
  expect(key_id).to eq(key_id)
109
111
  yielded = true
110
112
  key_secret
111
- end).to be_truthy
113
+ end
112
114
 
113
115
  expect(yielded).to be_truthy
114
116
  end
115
117
 
116
- context "with a request" do
118
+ context 'with a request' do
117
119
  let!(:request) do
118
120
  Faraday::Request.create(:get) do |r|
119
- r.path = "/auth"
120
- r.body = "{1: 2}"
121
- r.headers = {"Content-Type" => "application/xml"}
122
- end.to_env(Faraday::Connection.new("http://localhost"))
121
+ r.path = '/auth'
122
+ r.body = '{1: 2}'
123
+ r.headers = { 'Content-Type' => 'application/xml' }
124
+ end.to_env(Faraday::Connection.new('http://localhost'))
123
125
  end
124
- include_examples "authentication"
126
+
127
+ include_examples 'authentication'
125
128
  end
126
129
  end
127
130
 
128
- describe "middleware" do
129
- it "accepts a SHA1 signature" do
131
+ describe 'middleware' do
132
+ it 'accepts a SHA1 signature' do
130
133
  require 'ey-hmac/faraday'
131
134
  Bundler.require(:rack)
132
135
 
133
136
  app = lambda do |env|
134
- authenticated = Ey::Hmac.authenticated?(env, accept_digests: :sha1, adapter: Ey::Hmac::Adapter::Rack) do |auth_id|
137
+ authenticated = Ey::Hmac.authenticated?(env, accept_digests: :sha1,
138
+ adapter: Ey::Hmac::Adapter::Rack) do |auth_id|
135
139
  (auth_id == key_id) && key_secret
136
140
  end
137
- [(authenticated ? 200 : 401), {"Content-Type" => "text/plain"}, []]
141
+ [(authenticated ? 200 : 401), { 'Content-Type' => 'text/plain' }, []]
138
142
  end
139
143
 
140
144
  connection = Faraday.new do |c|
@@ -142,10 +146,10 @@ describe "faraday" do
142
146
  c.adapter(:rack, app)
143
147
  end
144
148
 
145
- expect(connection.get("/resources").status).to eq(200)
149
+ expect(connection.get('/resources').status).to eq(200)
146
150
  end
147
151
 
148
- it "accepts a SHA256 signature" do # default
152
+ it 'accepts a SHA256 signature' do # default
149
153
  require 'ey-hmac/faraday'
150
154
  Bundler.require(:rack)
151
155
 
@@ -153,7 +157,7 @@ describe "faraday" do
153
157
  authenticated = Ey::Hmac.authenticated?(env, adapter: Ey::Hmac::Adapter::Rack) do |auth_id|
154
158
  (auth_id == key_id) && key_secret
155
159
  end
156
- [(authenticated ? 200 : 401), {"Content-Type" => "text/plain"}, []]
160
+ [(authenticated ? 200 : 401), { 'Content-Type' => 'text/plain' }, []]
157
161
  end
158
162
 
159
163
  connection = Faraday.new do |c|
@@ -161,18 +165,19 @@ describe "faraday" do
161
165
  c.adapter(:rack, app)
162
166
  end
163
167
 
164
- expect(connection.get("/resources").status).to eq(200)
168
+ expect(connection.get('/resources').status).to eq(200)
165
169
  end
166
170
 
167
- it "accepts multiple digest signatures" do # default
171
+ it 'accepts multiple digest signatures' do # default
168
172
  require 'ey-hmac/faraday'
169
173
  Bundler.require(:rack)
170
174
 
171
175
  app = lambda do |env|
172
- authenticated = Ey::Hmac.authenticated?(env, accept_digests: [:sha1, :sha256], adapter: Ey::Hmac::Adapter::Rack) do |auth_id|
176
+ authenticated = Ey::Hmac.authenticated?(env, accept_digests: %i[sha1 sha256],
177
+ adapter: Ey::Hmac::Adapter::Rack) do |auth_id|
173
178
  (auth_id == key_id) && key_secret
174
179
  end
175
- [(authenticated ? 200 : 401), {"Content-Type" => "text/plain"}, []]
180
+ [(authenticated ? 200 : 401), { 'Content-Type' => 'text/plain' }, []]
176
181
  end
177
182
 
178
183
  connection = Faraday.new do |c|
@@ -180,23 +185,24 @@ describe "faraday" do
180
185
  c.adapter(:rack, app)
181
186
  end
182
187
 
183
- expect(connection.get("/resources").status).to eq(200)
188
+ expect(connection.get('/resources').status).to eq(200)
184
189
  end
185
190
 
186
- it "signs empty request" do
191
+ it 'signs empty request' do
187
192
  require 'ey-hmac/faraday'
188
193
  Bundler.require(:rack)
189
194
 
190
- _key_id, _key_secret = key_id, key_secret
195
+ outer_key_id = key_id
196
+ outer_key_secret = key_secret
191
197
  app = Rack::Builder.new do
192
198
  use Rack::Config do |env|
193
- env["CONTENT_TYPE"] ||= "text/html"
199
+ env['CONTENT_TYPE'] ||= 'text/html'
194
200
  end
195
- run(lambda {|env|
201
+ run(lambda { |env|
196
202
  authenticated = Ey::Hmac.authenticate!(env, adapter: Ey::Hmac::Adapter::Rack) do |auth_id|
197
- (auth_id == _key_id) && _key_secret
203
+ (auth_id == outer_key_id) && outer_key_secret
198
204
  end
199
- [(authenticated ? 200 : 401), {"Content-Type" => "text/plain"}, []]
205
+ [(authenticated ? 200 : 401), { 'Content-Type' => 'text/plain' }, []]
200
206
  })
201
207
  end
202
208
 
@@ -206,10 +212,10 @@ describe "faraday" do
206
212
  end
207
213
 
208
214
  expect(connection.get do |req|
209
- req.path = "/resource"
215
+ req.path = '/resource'
210
216
  req.body = nil
211
- req.params = {"a" => "1"}
212
- req.headers = {"Content-Type" => "application/x-www-form-urlencoded"}
217
+ req.params = { 'a' => '1' }
218
+ req.headers = { 'Content-Type' => 'application/x-www-form-urlencoded' }
213
219
  end.status).to eq(200)
214
220
  end
215
221
  end