net-http-signature 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 791d4891ed58fa87c4b08c571899d6aeba4bf48a
4
+ data.tar.gz: 00f3c6d94312b5bd6db8312c5091e0d54c0dbbf4
5
+ SHA512:
6
+ metadata.gz: a24a2b2ce36768bc0fd3d9dffa5859bdecd1d2541411834278eba26ef231b92da015b5475a45865057c2619404efaae8280de3187f191954435933459ee28906
7
+ data.tar.gz: eafde53865e3469a14256af39513f7ee1363a93f2cea5750cade230df65ada2ff991042e619f53ea5c8e3fb06a1854688524fa633c7a88f72bbc062320efe382
@@ -0,0 +1 @@
1
+ require_relative "net/http/signature"
@@ -0,0 +1,45 @@
1
+ require "base64"
2
+ require "openssl"
3
+
4
+ module Net
5
+ class HTTP
6
+ class Signature
7
+ require_relative "signature/request"
8
+ require_relative "signature/signer"
9
+ require_relative "signature/version"
10
+
11
+ HEADER = "Signature"
12
+
13
+ def initialize(key:, signer:)
14
+ @key = key
15
+ @signer = signer
16
+ end
17
+
18
+ def valid?(string)
19
+ to_s == string
20
+ end
21
+
22
+ def to_s
23
+ "key=#{key} algorithm=#{algorithm} token=#{signer}"
24
+ end
25
+
26
+ def to_h
27
+ {
28
+ HEADER => to_s
29
+ }
30
+ end
31
+
32
+ private def key
33
+ @key
34
+ end
35
+
36
+ private def algorithm
37
+ @signer.algorithm
38
+ end
39
+
40
+ private def signer
41
+ @signer
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,36 @@
1
+ module Net
2
+ class HTTP
3
+ class Signature
4
+ class Request
5
+ def initialize(verb:, uri:, headers:, body:)
6
+ @verb = verb
7
+ @uri = uri
8
+ @headers = headers
9
+ @body = body
10
+
11
+ fail ArgumentError, "Date header required" unless @headers.key?("Date")
12
+ end
13
+
14
+ def to_s
15
+ "#{verb} #{uri} #{headers} #{body}"
16
+ end
17
+
18
+ private def headers
19
+ @headers.to_a.sort_by(&:first).map { |(key, value)| "#{key}: #{value}" }.join("\n")
20
+ end
21
+
22
+ private def verb
23
+ @verb.upcase
24
+ end
25
+
26
+ private def uri
27
+ @uri
28
+ end
29
+
30
+ private def body
31
+ @body
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,47 @@
1
+ module Net
2
+ class HTTP
3
+ class Signature
4
+ class Signer
5
+ def initialize(request:, algorithm:, secret:)
6
+ @request = request
7
+ @algorithm = algorithm
8
+ @secret = secret
9
+
10
+ unless @algorithm =~ /.+-.+/
11
+ fail ArgumentError, "Invalid algorithm format: {{key}}-{{digester}}"
12
+ end
13
+
14
+ unless key
15
+ fail ArgumentError, "Crypto scheme not supported"
16
+ end
17
+ end
18
+
19
+ def algorithm
20
+ @algorithm
21
+ end
22
+
23
+ def to_s
24
+ Base64.encode64(key.update(request).digest)
25
+ end
26
+
27
+ private def secret
28
+ @secret
29
+ end
30
+
31
+ private def request
32
+ @request.to_s
33
+ end
34
+
35
+ private def key
36
+ case algorithm.split("-").first
37
+ when "hmac" then OpenSSL::HMAC.new(secret, digester)
38
+ end
39
+ end
40
+
41
+ private def digester
42
+ algorithm.split("-").last.upcase
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,7 @@
1
+ module Net
2
+ class HTTP
3
+ class Signature
4
+ VERSION = "1.0.0"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,52 @@
1
+ require "spec_helper"
2
+
3
+ describe Net::HTTP::Signature::Request do
4
+ let(:verb) { "GET" }
5
+ let(:uri) { "http://api.example.com" }
6
+ let(:headers) do
7
+ {
8
+ "Host" => "api.example.com",
9
+ "Date" => "2014-10-13 00:48:28 -0500",
10
+ "Content-Type" => "application/json",
11
+ "Accept" => "application/json",
12
+ "Authentication" => "Bearer fas425fmig.idfiodf"
13
+ }
14
+ end
15
+ let(:body) { "examplebody" }
16
+ let(:request) { described_class.new(verb: verb, uri: uri, headers: headers, body: body) }
17
+
18
+ context "with an missing Date header" do
19
+ let(:headers) do
20
+ {
21
+ "Host" => "api.example.com",
22
+ "Content-Type" => "application/json",
23
+ "Accept" => "application/json",
24
+ "Authentication" => "Bearer fas425fmig.idfiodf"
25
+ }
26
+ end
27
+
28
+ it "raises an error" do
29
+ expect { request }.to raise_error(ArgumentError)
30
+ end
31
+ end
32
+
33
+ describe "#to_s" do
34
+ let(:to_s) { request.to_s }
35
+
36
+ it "includes the verb" do
37
+ expect(to_s).to include(verb)
38
+ end
39
+
40
+ it "includes the uri" do
41
+ expect(to_s).to include(uri)
42
+ end
43
+
44
+ it "includes the headers" do
45
+ expect(to_s).to include(headers.to_a.sort_by(&:first).map { |(key, value)| "#{key}: #{value}" }.join("\n"))
46
+ end
47
+
48
+ it "includes the body" do
49
+ expect(to_s).to include(body)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,68 @@
1
+ require "spec_helper"
2
+
3
+ describe Net::HTTP::Signature::Signer do
4
+ let(:verb) { "GET" }
5
+ let(:uri) { "http://api.example.com" }
6
+ let(:headers) do
7
+ {
8
+ "Host" => "api.example.com",
9
+ "Date" => "2014-10-13 00:48:28 -0500",
10
+ "Content-Type" => "application/json",
11
+ "Accept" => "application/json",
12
+ "Authentication" => "Bearer fas425fmig.idfiodf"
13
+ }
14
+ end
15
+ let(:body) { "examplebody" }
16
+ let(:request) { Net::HTTP::Signature::Request.new(verb: verb, uri: uri, headers: headers, body: body) }
17
+ let(:digester) { "hmac" }
18
+ let(:sha) { "sha512" }
19
+ let(:algorithm_name) { "#{digester}-#{sha}" }
20
+ let(:secret) { "foo" }
21
+ let(:signer) { described_class.new(request: request, algorithm: algorithm_name, secret: secret) }
22
+
23
+ context "with an invalid digester" do
24
+ let(:algorithm_name) { "example-sha512" }
25
+
26
+ it "raises an error" do
27
+ expect { signer }.to raise_error(ArgumentError)
28
+ end
29
+ end
30
+
31
+ context "with an invalid sha" do
32
+ let(:algorithm_name) { "hmac-sha666" }
33
+
34
+ it "raises an error" do
35
+ expect { signer }.to raise_error(RuntimeError)
36
+ end
37
+ end
38
+
39
+ context "with an invalid algorithm name" do
40
+ let(:algorithm_name) { "hmac sha512" }
41
+
42
+ it "raises an error" do
43
+ expect { signer }.to raise_error(ArgumentError)
44
+ end
45
+ end
46
+
47
+ describe "#algorithm" do
48
+ let(:algorithm) { signer.algorithm }
49
+
50
+ it "includes the digester" do
51
+ expect(algorithm).to include(digester)
52
+ end
53
+
54
+ it "includes the sha" do
55
+ expect(algorithm).to include(sha)
56
+ end
57
+ end
58
+
59
+ describe "#to_s" do
60
+ let(:to_s) { signer.to_s }
61
+ let(:signature) { OpenSSL.const_get(digester.upcase).digest(sha, secret, request.to_s) }
62
+ let(:encoded_signature) { Base64.encode64(signature) }
63
+
64
+ it "includes the base64'd signature token" do
65
+ expect(to_s).to eq(encoded_signature)
66
+ end
67
+ end
68
+ end
File without changes
@@ -0,0 +1,124 @@
1
+ require "spec_helper"
2
+
3
+ describe Net::HTTP::Signature do
4
+ let(:verb) { "GET" }
5
+ let(:uri) { "http://api.example.com" }
6
+ let(:headers) do
7
+ {
8
+ "Host" => "api.example.com",
9
+ "Date" => "2014-10-13 00:48:28 -0500",
10
+ "Content-Type" => "application/json",
11
+ "Accept" => "application/json",
12
+ "Authentication" => "Bearer fas425fmig.idfiodf"
13
+ }
14
+ end
15
+ let(:body) { "" }
16
+ let(:secret) { "examplesecret" }
17
+ let(:algorithm) { "hmac-sha512" }
18
+ let(:request) { Net::HTTP::Signature::Request.new(verb: verb, uri: uri, headers: headers, body: body) }
19
+ let(:signer) { Net::HTTP::Signature::Signer.new(request: request, algorithm: algorithm, secret: secret) }
20
+ let(:key) { "examplekey" }
21
+ let(:signature) { described_class.new(signer: signer, key: key) }
22
+
23
+ let(:comparison_verb) { verb }
24
+ let(:comparison_uri) { uri }
25
+ let(:comparison_headers) { headers }
26
+ let(:comparison_body) { body }
27
+ let(:comparison_secret) { secret }
28
+ let(:comparison_algorithm) { algorithm }
29
+ let(:comparison_request) { Net::HTTP::Signature::Request.new(verb: comparison_verb, uri: comparison_uri, headers: comparison_headers, body: comparison_body) }
30
+ let(:comparison_signer) { Net::HTTP::Signature::Signer.new(request: comparison_request, algorithm: comparison_algorithm, secret: comparison_secret) }
31
+ let(:comparison_key) { key }
32
+ let(:comparison_signature) { described_class.new(signer: comparison_signer, key: comparison_key) }
33
+ let(:comparison) { comparison_signature.to_h["Signature"] }
34
+
35
+ describe "#valid?" do
36
+ let(:valid?) { signature.valid?(comparison) }
37
+
38
+ context "with a valid secret" do
39
+ it "returns true" do
40
+ expect(valid?).to be(true)
41
+ end
42
+ end
43
+
44
+ context "with an non-same secret" do
45
+ let(:comparison_secret) { "nonexamplesecret" }
46
+
47
+ it "returns false" do
48
+ expect(valid?).to be(false)
49
+ end
50
+ end
51
+
52
+ context "with an non-same verb" do
53
+ let(:comparison_verb) { "POST" }
54
+
55
+ it "returns false" do
56
+ expect(valid?).to be(false)
57
+ end
58
+ end
59
+
60
+ context "with non-same body" do
61
+ let(:comparison_body) { "f" }
62
+
63
+ it "returns false" do
64
+ expect(valid?).to be(false)
65
+ end
66
+ end
67
+
68
+ context "with non-same headers" do
69
+ let(:comparison_headers) do
70
+ {
71
+ "Date" => "2014-10-13 00:48:20 -0500"
72
+ }
73
+ end
74
+
75
+ it "returns false" do
76
+ expect(valid?).to be(false)
77
+ end
78
+ end
79
+
80
+ context "with non-same uri" do
81
+ let(:comparison_uri) { "http://aii.example.com" }
82
+
83
+ it "returns false" do
84
+ expect(valid?).to be(false)
85
+ end
86
+ end
87
+
88
+ context "with an invalid string" do
89
+ let(:comparison) { "foobar" }
90
+
91
+ it "returns false" do
92
+ expect(valid?).to be(false)
93
+ end
94
+ end
95
+ end
96
+
97
+ describe "#to_s" do
98
+ let(:to_s) { signature.to_s }
99
+
100
+ it "includes the algorithm" do
101
+ expect(to_s).to include("algorithm=#{algorithm}")
102
+ end
103
+
104
+ it "includes the key" do
105
+ expect(to_s).to include("key=#{key}")
106
+ end
107
+
108
+ it "includes the token" do
109
+ expect(to_s).to include("token=#{signer}")
110
+ end
111
+ end
112
+
113
+ describe "#to_h" do
114
+ let(:to_h) { signature.to_h }
115
+
116
+ it "includes the Signature key" do
117
+ expect(to_h.keys).to include("Signature")
118
+ end
119
+
120
+ it "includes the string form as a value to Signature key" do
121
+ expect(to_h["Signature"]).to eq(signature.to_s)
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,3 @@
1
+ require "pry"
2
+ require "rspec"
3
+ require "net-http-signature"
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: net-http-signature
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Kurtis Rainbolt-Greene
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-10-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.9'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.9'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry-doc
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.6'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.6'
83
+ description: A signing library for HTTP requests
84
+ email:
85
+ - me@kurtisrainboltgreene.name
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - lib/net-http-signature.rb
91
+ - lib/net/http/signature.rb
92
+ - lib/net/http/signature/request.rb
93
+ - lib/net/http/signature/signer.rb
94
+ - lib/net/http/signature/version.rb
95
+ - spec/lib/net/http/signature/request_spec.rb
96
+ - spec/lib/net/http/signature/signer_spec.rb
97
+ - spec/lib/net/http/signature/version_spec.rb
98
+ - spec/lib/net/http/signature_spec.rb
99
+ - spec/spec_helper.rb
100
+ homepage: http://krainboltgreene.github.io/net-http-signature
101
+ licenses:
102
+ - MIT
103
+ metadata: {}
104
+ post_install_message:
105
+ rdoc_options: []
106
+ require_paths:
107
+ - lib
108
+ required_ruby_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ requirements: []
119
+ rubyforge_project:
120
+ rubygems_version: 2.2.2
121
+ signing_key:
122
+ specification_version: 4
123
+ summary: A signing library for HTTP requests
124
+ test_files:
125
+ - spec/lib/net/http/signature/request_spec.rb
126
+ - spec/lib/net/http/signature/signer_spec.rb
127
+ - spec/lib/net/http/signature/version_spec.rb
128
+ - spec/lib/net/http/signature_spec.rb
129
+ - spec/spec_helper.rb
130
+ has_rdoc: