net-http-auth-hmac 0.0.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/Gemfile +4 -0
- data/Gemfile.lock +16 -0
- data/README.md +34 -0
- data/Rakefile +12 -0
- data/lib/net/http/auth/hmac.rb +64 -0
- data/net-http-auth-hmac.gemspec +11 -0
- data/test/net-http-auth-hmac_test.rb +57 -0
- metadata +53 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/README.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# net-http-auth-hmac
|
2
|
+
|
3
|
+

|
4
|
+
|
5
|
+
Signs a request with given token to be validated in the backend.
|
6
|
+
|
7
|
+
## Usage
|
8
|
+
|
9
|
+
Sending a request
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
uri = URI.parse("http://google.com/")
|
13
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
14
|
+
|
15
|
+
signer = Net::HTTP::Auth::HMAC.new('super_secret_secret')
|
16
|
+
request = Net::HTTP::Post.new('/somewhere')
|
17
|
+
request.body = 'super_secret_value=42'
|
18
|
+
|
19
|
+
signed_request = signer.sign_request(request)
|
20
|
+
http.request request
|
21
|
+
```
|
22
|
+
|
23
|
+
Receiving a request
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
signer = Net::HTTP::Auth::HMAC.new('super_secret_secret')
|
27
|
+
unsigned_request = signer.unsign_request(request)
|
28
|
+
request.body
|
29
|
+
```
|
30
|
+
|
31
|
+
## Installation
|
32
|
+
```bash
|
33
|
+
gem install net-http-auth-hmac
|
34
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'net/http'
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
class Net::HTTP
|
6
|
+
class Auth
|
7
|
+
class HMAC
|
8
|
+
def initialize(shared_secret)
|
9
|
+
@secret = shared_secret
|
10
|
+
end
|
11
|
+
|
12
|
+
def sign_request(request)
|
13
|
+
raise BodyNotFound if !request.body
|
14
|
+
request.body = base64_encode(request.body)
|
15
|
+
request['X-HMAC-Digest'] = base64_encode(signature(request.body))
|
16
|
+
request
|
17
|
+
end
|
18
|
+
|
19
|
+
def unsign_request(request)
|
20
|
+
raise DigestNotFound if !request['X-HMAC-Digest']
|
21
|
+
request_signature = base64_decode(request['X-HMAC-Digest'])
|
22
|
+
raise InvalidSignature if request_signature != signature(request.body)
|
23
|
+
|
24
|
+
request.body = base64_decode(request.body)
|
25
|
+
request
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def signature(payload)
|
31
|
+
OpenSSL::HMAC.digest('sha256', @secret, payload)
|
32
|
+
end
|
33
|
+
|
34
|
+
def base64_encode(string)
|
35
|
+
Base64.urlsafe_encode64(string)
|
36
|
+
end
|
37
|
+
|
38
|
+
def base64_decode(string)
|
39
|
+
Base64.urlsafe_decode64(string)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
class Net::HTTP::Auth::HMAC
|
47
|
+
class InvalidSignature < StandardError
|
48
|
+
def message
|
49
|
+
"The X-HMAC-Digest it's invalid"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class BodyNotFound < StandardError
|
54
|
+
def message
|
55
|
+
"The body of the request it's missing"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class DigestNotFound < StandardError
|
60
|
+
def message
|
61
|
+
"The X-HMAC-Digest it's missing"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "net-http-auth-hmac"
|
3
|
+
s.version = "0.0.1"
|
4
|
+
s.summary = "HMAC base identity authentication"
|
5
|
+
s.description = "Exchanges a digest to be validated against a token"
|
6
|
+
s.authors = ["elcuervo"]
|
7
|
+
s.email = ["yo@brunoaguirre.com"]
|
8
|
+
s.homepage = "http://github.com/elcuervo/net-http-auth-hmac"
|
9
|
+
s.files = `git ls-files`.split("\n")
|
10
|
+
s.test_files = `git ls-files test`.split("\n")
|
11
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
$: << File.join(File.dirname(__FILE__), '../lib')
|
2
|
+
require 'test/unit'
|
3
|
+
require 'net/http'
|
4
|
+
require 'net/http/auth/hmac'
|
5
|
+
|
6
|
+
class TestNetHTTPAuthHMAC < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
@body = 'Once upon a midnight dreary, while I pondered weak and weary'
|
9
|
+
@request = Net::HTTP::Post.new('/signed')
|
10
|
+
@request.body = @body
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_sending_and_unsigning_a_request
|
14
|
+
secret = 'changeme'
|
15
|
+
signer = Net::HTTP::Auth::HMAC.new(secret)
|
16
|
+
signed_request = signer.sign_request(@request)
|
17
|
+
|
18
|
+
assert signed_request.is_a?(Net::HTTP::Post)
|
19
|
+
assert signed_request['X-HMAC-Digest']
|
20
|
+
assert signed_request.body != @body
|
21
|
+
|
22
|
+
unsigned_request = signer.unsign_request(signed_request)
|
23
|
+
assert_equal unsigned_request.body, @body
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_raising_an_error_when_the_header_is_missing
|
27
|
+
signer = Net::HTTP::Auth::HMAC.new('one')
|
28
|
+
request = Net::HTTP::Post.new('/somewhere')
|
29
|
+
request.body = 'something'
|
30
|
+
|
31
|
+
assert_raise Net::HTTP::Auth::HMAC::DigestNotFound do
|
32
|
+
signer.unsign_request(request)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_raising_an_error_when_the_body_is_missing
|
37
|
+
signer = Net::HTTP::Auth::HMAC.new('one')
|
38
|
+
request = Net::HTTP::Post.new('/somewhere')
|
39
|
+
|
40
|
+
assert_raise Net::HTTP::Auth::HMAC::BodyNotFound do
|
41
|
+
signer.sign_request(request)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_raising_an_error_when_the_signature_is_invalid
|
46
|
+
one = Base64.urlsafe_encode64('one')
|
47
|
+
two = Base64.urlsafe_encode64('two')
|
48
|
+
|
49
|
+
signer = Net::HTTP::Auth::HMAC.new(one)
|
50
|
+
signed_request = signer.sign_request(@request)
|
51
|
+
signed_request['X-HMAC-Digest'] = two
|
52
|
+
|
53
|
+
assert_raise Net::HTTP::Auth::HMAC::InvalidSignature do
|
54
|
+
signer.unsign_request(signed_request)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: net-http-auth-hmac
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- elcuervo
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-14 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Exchanges a digest to be validated against a token
|
15
|
+
email:
|
16
|
+
- yo@brunoaguirre.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- Gemfile
|
22
|
+
- Gemfile.lock
|
23
|
+
- README.md
|
24
|
+
- Rakefile
|
25
|
+
- lib/net/http/auth/hmac.rb
|
26
|
+
- net-http-auth-hmac.gemspec
|
27
|
+
- test/net-http-auth-hmac_test.rb
|
28
|
+
homepage: http://github.com/elcuervo/net-http-auth-hmac
|
29
|
+
licenses: []
|
30
|
+
post_install_message:
|
31
|
+
rdoc_options: []
|
32
|
+
require_paths:
|
33
|
+
- lib
|
34
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
+
none: false
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
requirements: []
|
47
|
+
rubyforge_project:
|
48
|
+
rubygems_version: 1.8.22
|
49
|
+
signing_key:
|
50
|
+
specification_version: 3
|
51
|
+
summary: HMAC base identity authentication
|
52
|
+
test_files:
|
53
|
+
- test/net-http-auth-hmac_test.rb
|