ey-hmac 0.0.5 → 0.1.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.
- checksums.yaml +7 -0
- data/lib/ey-hmac/adapter.rb +23 -20
- data/lib/ey-hmac/adapter/faraday.rb +3 -3
- data/lib/ey-hmac/adapter/rack.rb +1 -1
- data/lib/ey-hmac/rack.rb +2 -1
- data/lib/ey-hmac/version.rb +1 -1
- data/spec/faraday_spec.rb +41 -1
- data/spec/rack_spec.rb +40 -3
- metadata +9 -16
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d66a44d088fc9384dc6e9058dad00bb4264dcbb6
|
4
|
+
data.tar.gz: 0cc4a68974d4f73b2f3081c2d58e59d235456445
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c3dcc933b1577141c16c55e861fc09bedba9ed6558b517a91e2d75f9a8882b3473b45222473029d4931aa2948e96b11d7396ee2e078adf108f6f4957b3952643
|
7
|
+
data.tar.gz: 2aa4b84886e85a7be13db759a22aa337fa566b0ca1cfd9a5f1372872b583e91d15b89179cd3b7ac2dd9779ec0e74ec29b676b17a5e1c01d40613cd66bc14eea8
|
data/lib/ey-hmac/adapter.rb
CHANGED
@@ -6,7 +6,7 @@ class Ey::Hmac::Adapter
|
|
6
6
|
autoload :Rack, "ey-hmac/adapter/rack"
|
7
7
|
autoload :Faraday, "ey-hmac/adapter/faraday"
|
8
8
|
|
9
|
-
attr_reader :request, :options, :authorization_header, :service
|
9
|
+
attr_reader :request, :options, :authorization_header, :service, :sign_with, :accept_digests
|
10
10
|
|
11
11
|
# @param [Object] request signer-specific request implementation
|
12
12
|
# @option options [Integer] :version signature version
|
@@ -16,7 +16,9 @@ class Ey::Hmac::Adapter
|
|
16
16
|
@request, @options = request, options
|
17
17
|
|
18
18
|
@authorization_header = options[:authorization_header] || 'Authorization'
|
19
|
-
@service
|
19
|
+
@service = options[:service] || 'EyHmac'
|
20
|
+
@sign_with = options[:sign_with] || :sha256
|
21
|
+
@accept_digests = Array(options[:accept_digests] || :sha256)
|
20
22
|
end
|
21
23
|
|
22
24
|
# In order for the server to correctly authorize the request, the client and server MUST AGREE on this format
|
@@ -28,17 +30,17 @@ class Ey::Hmac::Adapter
|
|
28
30
|
end
|
29
31
|
|
30
32
|
# @param [String] key_secret private HMAC key
|
33
|
+
# @param [String] signature digest hash function. Defaults to #sign_with
|
31
34
|
# @return [String] HMAC signature of {#request}
|
32
|
-
|
33
|
-
|
34
|
-
Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha1'), key_secret, canonicalize)).strip
|
35
|
+
def signature(key_secret, digest = self.sign_with)
|
36
|
+
Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new(digest.to_s), key_secret, canonicalize)).strip
|
35
37
|
end
|
36
38
|
|
37
39
|
# @param [String] key_id public HMAC key
|
38
40
|
# @param [String] key_secret private HMAC key
|
39
41
|
# @return [String] HMAC header value of {#request}
|
40
42
|
def authorization(key_id, key_secret)
|
41
|
-
"#{service} #{key_id}:#{signature(key_secret)}"
|
43
|
+
"#{service} #{key_id}:#{signature(key_secret, sign_with)}"
|
42
44
|
end
|
43
45
|
|
44
46
|
# @abstract
|
@@ -55,7 +57,6 @@ class Ey::Hmac::Adapter
|
|
55
57
|
|
56
58
|
# @abstract
|
57
59
|
# Digest of body. Default is MD5.
|
58
|
-
# @todo support explicit digest methods
|
59
60
|
# @return [String] digest of body
|
60
61
|
def content_digest
|
61
62
|
raise NotImplementedError
|
@@ -99,7 +100,7 @@ class Ey::Hmac::Adapter
|
|
99
100
|
# @yieldparam key_id [String] public HMAC key
|
100
101
|
# @return [Boolean] true if block yields matching private key and signature matches, else false
|
101
102
|
# @see #authenticated!
|
102
|
-
def authenticated?(&block)
|
103
|
+
def authenticated?(options={}, &block)
|
103
104
|
authenticated!(&block)
|
104
105
|
rescue Ey::Hmac::Error
|
105
106
|
false
|
@@ -107,20 +108,22 @@ class Ey::Hmac::Adapter
|
|
107
108
|
|
108
109
|
# @see Ey::Hmac#authenticate!
|
109
110
|
def authenticated!(&block)
|
110
|
-
|
111
|
-
key_id = authorization_match[1]
|
112
|
-
signature_value = authorization_match[2]
|
113
|
-
|
114
|
-
if key_secret = block.call(key_id)
|
115
|
-
calculated_signature = signature(key_secret)
|
116
|
-
if secure_compare(signature_value, calculated_signature)
|
117
|
-
else raise(Ey::Hmac::SignatureMismatch, "Calculated siganature #{signature_value} does not match #{calculated_signature} using #{canonicalize.inspect}")
|
118
|
-
end
|
119
|
-
else raise(Ey::Hmac::MissingSecret, "Failed to find secret matching #{key_id.inspect}")
|
120
|
-
end
|
121
|
-
else
|
111
|
+
unless authorization_match = AUTHORIZATION_REGEXP.match(authorization_signature)
|
122
112
|
raise(Ey::Hmac::MissingAuthorization, "Failed to parse authorization_signature #{authorization_signature}")
|
123
113
|
end
|
114
|
+
|
115
|
+
key_id = authorization_match[1]
|
116
|
+
signature_value = authorization_match[2]
|
117
|
+
|
118
|
+
unless key_secret = block.call(key_id)
|
119
|
+
raise(Ey::Hmac::MissingSecret, "Failed to find secret matching #{key_id.inspect}")
|
120
|
+
end
|
121
|
+
|
122
|
+
calculated_signatures = self.accept_digests.map { |ad| signature(key_secret, ad) }
|
123
|
+
|
124
|
+
unless calculated_signatures.any? { |cs| secure_compare(signature_value, cs) }
|
125
|
+
raise(Ey::Hmac::SignatureMismatch, "Calculated siganature #{signature_value} does not match #{calculated_signatures.inspect} using #{canonicalize.inspect}")
|
126
|
+
end
|
124
127
|
true
|
125
128
|
end
|
126
129
|
alias authenticate! authenticated!
|
@@ -4,11 +4,11 @@ class Ey::Hmac::Adapter::Faraday < Ey::Hmac::Adapter
|
|
4
4
|
end
|
5
5
|
|
6
6
|
def content_type
|
7
|
-
%w[CONTENT-TYPE CONTENT_TYPE Content-Type Content_Type].inject(nil){|r,
|
7
|
+
%w[CONTENT-TYPE CONTENT_TYPE Content-Type Content_Type].inject(nil) { |r,h| r || request[:request_headers][h] }
|
8
8
|
end
|
9
9
|
|
10
10
|
def content_digest
|
11
|
-
if existing = %w[CONTENT-DIGEST CONTENT_DIGEST Content-Digest Content_Digest].inject(nil){|r,h| r || request[:request_headers][h]}
|
11
|
+
if existing = %w[CONTENT-DIGEST CONTENT_DIGEST Content-Digest Content_Digest].inject(nil) { |r,h| r || request[:request_headers][h] }
|
12
12
|
existing
|
13
13
|
elsif digestable = body && Digest::MD5.hexdigest(body)
|
14
14
|
request[:request_headers]['Content-Digest'] = digestable
|
@@ -24,7 +24,7 @@ class Ey::Hmac::Adapter::Faraday < Ey::Hmac::Adapter
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def date
|
27
|
-
existing = %w[DATE Date].inject(nil){|r,h| r || request[h]}
|
27
|
+
existing = %w[DATE Date].inject(nil) { |r,h| r || request[h] }
|
28
28
|
existing || (request[:request_headers]['Date'] = Time.now.httpdate)
|
29
29
|
end
|
30
30
|
|
data/lib/ey-hmac/adapter/rack.rb
CHANGED
data/lib/ey-hmac/rack.rb
CHANGED
@@ -9,7 +9,8 @@ class Ey::Hmac::Rack
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def call(env)
|
12
|
-
Ey::Hmac.sign!(env, key_id, key_secret, {adapter: Ey::Hmac::Adapter::Rack}.merge(options))
|
12
|
+
Ey::Hmac.sign!(env, key_id, key_secret, { adapter: Ey::Hmac::Adapter::Rack }.merge(options))
|
13
|
+
|
13
14
|
@app.call(env)
|
14
15
|
end
|
15
16
|
end
|
data/lib/ey-hmac/version.rb
CHANGED
data/spec/faraday_spec.rb
CHANGED
@@ -97,7 +97,27 @@ describe "faraday" do
|
|
97
97
|
end
|
98
98
|
|
99
99
|
describe "middleware" do
|
100
|
-
it "should
|
100
|
+
it "should accept a SHA1 signature" do
|
101
|
+
require 'ey-hmac/faraday'
|
102
|
+
Bundler.require(:rack)
|
103
|
+
|
104
|
+
app = lambda do |env|
|
105
|
+
authenticated = Ey::Hmac.authenticated?(env, accept_digests: :sha1, adapter: Ey::Hmac::Adapter::Rack) do |auth_id|
|
106
|
+
(auth_id == key_id) && key_secret
|
107
|
+
end
|
108
|
+
[(authenticated ? 200 : 401), {"Content-Type" => "text/plain"}, []]
|
109
|
+
end
|
110
|
+
|
111
|
+
request_env = nil
|
112
|
+
connection = Faraday.new do |c|
|
113
|
+
c.request :hmac, key_id, key_secret, sign_with: :sha1
|
114
|
+
c.adapter(:rack, app)
|
115
|
+
end
|
116
|
+
|
117
|
+
connection.get("/resources").status.should == 200
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should accept a SHA256 signature" do # default
|
101
121
|
require 'ey-hmac/faraday'
|
102
122
|
Bundler.require(:rack)
|
103
123
|
|
@@ -117,6 +137,26 @@ describe "faraday" do
|
|
117
137
|
connection.get("/resources").status.should == 200
|
118
138
|
end
|
119
139
|
|
140
|
+
it "should accept multiple digest signatures" do # default
|
141
|
+
require 'ey-hmac/faraday'
|
142
|
+
Bundler.require(:rack)
|
143
|
+
|
144
|
+
app = lambda do |env|
|
145
|
+
authenticated = Ey::Hmac.authenticated?(env, accept_digests: [:sha1, :sha256], adapter: Ey::Hmac::Adapter::Rack) do |auth_id|
|
146
|
+
(auth_id == key_id) && key_secret
|
147
|
+
end
|
148
|
+
[(authenticated ? 200 : 401), {"Content-Type" => "text/plain"}, []]
|
149
|
+
end
|
150
|
+
|
151
|
+
request_env = nil
|
152
|
+
connection = Faraday.new do |c|
|
153
|
+
c.request :hmac, key_id, key_secret
|
154
|
+
c.adapter(:rack, app)
|
155
|
+
end
|
156
|
+
|
157
|
+
connection.get("/resources").status.should == 200
|
158
|
+
end
|
159
|
+
|
120
160
|
it "should sign empty request" do
|
121
161
|
require 'ey-hmac/faraday'
|
122
162
|
Bundler.require(:rack)
|
data/spec/rack_spec.rb
CHANGED
@@ -3,8 +3,8 @@ require 'spec_helper'
|
|
3
3
|
describe "rack" do
|
4
4
|
before(:all) { Bundler.require(:rack) }
|
5
5
|
|
6
|
-
let!(:key_id) { (
|
7
|
-
let!(:key_secret) { (
|
6
|
+
let!(:key_id) { SecureRandom.hex(8) }
|
7
|
+
let!(:key_secret) { SecureRandom.hex(16) }
|
8
8
|
|
9
9
|
describe "adapter" do
|
10
10
|
let(:adapter) { Ey::Hmac::Adapter::Rack }
|
@@ -89,7 +89,24 @@ describe "rack" do
|
|
89
89
|
end
|
90
90
|
|
91
91
|
describe "middleware" do
|
92
|
-
it "should
|
92
|
+
it "should accept a SHA1 signature" do
|
93
|
+
app = lambda do |env|
|
94
|
+
authenticated = Ey::Hmac.authenticated?(env, accept_digests: [:sha1, :sha256], adapter: Ey::Hmac::Adapter::Rack) do |auth_id|
|
95
|
+
(auth_id == key_id) && key_secret
|
96
|
+
end
|
97
|
+
[(authenticated ? 200 : 401), {"Content-Type" => "text/plain"}, []]
|
98
|
+
end
|
99
|
+
|
100
|
+
_key_id, _key_secret = key_id, key_secret
|
101
|
+
client = Rack::Client.new do
|
102
|
+
use Ey::Hmac::Rack, _key_id, _key_secret, sign_with: :sha1
|
103
|
+
run app
|
104
|
+
end
|
105
|
+
|
106
|
+
client.get("/resource").status.should == 200
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should accept a SHA256 signature" do # default
|
93
110
|
app = lambda do |env|
|
94
111
|
authenticated = Ey::Hmac.authenticated?(env, adapter: Ey::Hmac::Adapter::Rack) do |auth_id|
|
95
112
|
(auth_id == key_id) && key_secret
|
@@ -105,5 +122,25 @@ describe "rack" do
|
|
105
122
|
|
106
123
|
client.get("/resource").status.should == 200
|
107
124
|
end
|
125
|
+
|
126
|
+
it "should accept multiple digest signatures" do # default
|
127
|
+
require 'ey-hmac/faraday'
|
128
|
+
Bundler.require(:rack)
|
129
|
+
|
130
|
+
app = lambda do |env|
|
131
|
+
authenticated = Ey::Hmac.authenticated?(env, adapter: Ey::Hmac::Adapter::Rack) do |auth_id|
|
132
|
+
(auth_id == key_id) && key_secret
|
133
|
+
end
|
134
|
+
[(authenticated ? 200 : 401), {"Content-Type" => "text/plain"}, []]
|
135
|
+
end
|
136
|
+
|
137
|
+
request_env = nil
|
138
|
+
connection = Faraday.new do |c|
|
139
|
+
c.request :hmac, key_id, key_secret, digest: [:sha1, :sha256]
|
140
|
+
c.adapter(:rack, app)
|
141
|
+
end
|
142
|
+
|
143
|
+
connection.get("/resources").status.should == 200
|
144
|
+
end
|
108
145
|
end
|
109
146
|
end
|
metadata
CHANGED
@@ -1,36 +1,32 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ey-hmac
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Josh Lane & Jason Hansen
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-02-19 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rake
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - '>='
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '0'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: bundler
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ~>
|
36
32
|
- !ruby/object:Gem::Version
|
@@ -38,7 +34,6 @@ dependencies:
|
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ~>
|
44
39
|
- !ruby/object:Gem::Version
|
@@ -71,31 +66,29 @@ files:
|
|
71
66
|
- spec/spec_helper.rb
|
72
67
|
homepage: ''
|
73
68
|
licenses: []
|
69
|
+
metadata: {}
|
74
70
|
post_install_message:
|
75
71
|
rdoc_options: []
|
76
72
|
require_paths:
|
77
73
|
- lib
|
78
74
|
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
-
none: false
|
80
75
|
requirements:
|
81
|
-
- -
|
76
|
+
- - '>='
|
82
77
|
- !ruby/object:Gem::Version
|
83
78
|
version: '0'
|
84
79
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
-
none: false
|
86
80
|
requirements:
|
87
|
-
- -
|
81
|
+
- - '>='
|
88
82
|
- !ruby/object:Gem::Version
|
89
83
|
version: '0'
|
90
84
|
requirements: []
|
91
85
|
rubyforge_project:
|
92
|
-
rubygems_version:
|
86
|
+
rubygems_version: 2.0.3
|
93
87
|
signing_key:
|
94
|
-
specification_version:
|
88
|
+
specification_version: 4
|
95
89
|
summary: Lightweight HMAC signing libraries and middleware for Farday and Rack
|
96
90
|
test_files:
|
97
91
|
- spec/faraday_spec.rb
|
98
92
|
- spec/rack_spec.rb
|
99
93
|
- spec/shared/authenticated.rb
|
100
94
|
- spec/spec_helper.rb
|
101
|
-
has_rdoc:
|