ey_api_hmac 0.0.1 → 0.0.2

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.lock CHANGED
@@ -2,6 +2,7 @@ PATH
2
2
  remote: .
3
3
  specs:
4
4
  ey_api_hmac (0.0.1)
5
+ json
5
6
  rack-client
6
7
 
7
8
  GEM
@@ -9,6 +10,7 @@ GEM
9
10
  specs:
10
11
  diff-lcs (1.1.2)
11
12
  halorgium-auth-hmac (1.1.1.2010100601)
13
+ json (1.5.3)
12
14
  rack (1.3.2)
13
15
  rack-client (0.4.0)
14
16
  rack (>= 1.0.0)
data/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # Engine Yard HMAC api implementation
2
+
3
+ HMAC basic implementation for Engine Yard services.
4
+
5
+ # How to use it
6
+
7
+ Server Rack middleware:
8
+
9
+ ```ruby
10
+ use EY::ApiHMAC::ApiAuth::Server, Consumer
11
+ ```
12
+
13
+ Where `Consumer` is a class that responds to find_by_auth_id(auth_id), and returns an object that responds to `id` and `auth_key`.
14
+
15
+ ```ruby
16
+ use EY::ApiHMAC::ApiAuth::LookupServer do |env, auth_id|
17
+ #return the appropriate auth_key here
18
+ end
19
+ ```
20
+
21
+ this will validate the Authorization header for all requests and raise on failures
22
+
23
+ Rack-Client middleware:
24
+
25
+ ```ruby
26
+ client = Rack::Client.new do
27
+ use EY::ApiHMAC::ApiAuth::Client, auth_id_arg, auth_key_arg
28
+ run Rack::Client::Handler::NetHTTP
29
+ end
30
+ ```
31
+
32
+ this will add the correct Authorization header to all requests made with this rack-client.
data/ey_api_hmac.gemspec CHANGED
@@ -19,5 +19,6 @@ Gem::Specification.new do |s|
19
19
  s.require_paths = ["lib"]
20
20
 
21
21
  s.add_dependency 'rack-client'
22
+ s.add_dependency 'json'
22
23
  s.add_development_dependency "rspec"
23
24
  end
@@ -0,0 +1,27 @@
1
+ module EY
2
+ module ApiHMAC
3
+ module SSO
4
+
5
+ def self.sign(url, parameters, auth_id, auth_key)
6
+ uri = URI.parse(url)
7
+ raise ArgumentError, "use parameters argument, got query: '#{uri.query}'" if uri.query
8
+ uri.query = parameters.sort.map {|e| e.map{|str| CGI.escape(str.to_s)}.join '='}.join '&'
9
+ signature = CGI.escape(signature_param(uri.to_s, auth_id, auth_key))
10
+ uri.query += "&signature=#{signature}"
11
+ uri.to_s
12
+ end
13
+
14
+ def self.authenticated?(url, auth_id, auth_key)
15
+ uri = URI.parse(url)
16
+ signature = CGI.unescape(uri.query.match(/&signature=(.*)$/)[1])
17
+ signed_string = uri.to_s.gsub(/&signature=(.*)$/,"")
18
+ signature_param(signed_string.to_s, auth_id, auth_key) == signature
19
+ end
20
+
21
+ def self.signature_param(signed_string, auth_id, auth_key)
22
+ ApiHMAC.auth_string(auth_id, ApiHMAC.base64digest(signed_string, auth_key))
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -1,5 +1,5 @@
1
1
  module EY
2
2
  module ApiHMAC
3
- VERSION = "0.0.1"
3
+ VERSION = "0.0.2"
4
4
  end
5
5
  end
data/lib/ey_api_hmac.rb CHANGED
@@ -1,28 +1,13 @@
1
1
  require 'ey_api_hmac/base_connection'
2
2
  require 'ey_api_hmac/api_auth'
3
+ require 'ey_api_hmac/sso'
3
4
 
4
5
  module EY
5
6
  module ApiHMAC
6
7
  require 'openssl'
7
8
 
8
- def self.sign_for_sso(url, parameters, auth_id, auth_key)
9
- uri = URI.parse(url)
10
- raise ArgumentError, "use parameters argument, got query: '#{uri.query}'" if uri.query
11
- uri.query = parameters.sort.map {|e| e.map{|str| CGI.escape(str.to_s)}.join '='}.join '&'
12
- signature = CGI.escape(base64digest(uri.query.to_s, auth_key))
13
- uri.query += "&signature=#{signature}"
14
- uri.to_s
15
- end
16
-
17
- def self.verify_for_sso(url, auth_id, auth_key)
18
- uri = URI.parse(url)
19
- signature = CGI.unescape(uri.query.match(/&signature=(.*)$/)[1])
20
- signed_string = uri.query.gsub(/&signature=(.*)$/,"")
21
- base64digest(signed_string.to_s, auth_key) == signature
22
- end
23
-
24
9
  def self.sign!(env, key_id, secret, strict = false)
25
- env["HTTP_AUTHORIZATION"] = "AuthHMAC #{key_id}:#{signature(env, secret, strict)}"
10
+ env["HTTP_AUTHORIZATION"] = auth_string(key_id, signature(env, secret, strict))
26
11
  end
27
12
 
28
13
  def self.canonical_string(env, strict = false)
@@ -45,6 +30,10 @@ module EY
45
30
  parts.join("\n")
46
31
  end
47
32
 
33
+ def self.auth_string(key_id, signature)
34
+ "AuthHMAC #{key_id}:#{signature}"
35
+ end
36
+
48
37
  def self.signature(env, secret, strict = false)
49
38
  base64digest(canonical_string(env, strict), secret)
50
39
  end
data/spec/sso_spec.rb CHANGED
@@ -17,7 +17,7 @@ describe EY::ApiHMAC do
17
17
  end
18
18
 
19
19
  it "can sign sso calls" do
20
- signed_url = EY::ApiHMAC.sign_for_sso(@url, @parameters, @auth_id, @auth_key)
20
+ signed_url = EY::ApiHMAC::SSO.sign(@url, @parameters, @auth_id, @auth_key)
21
21
  uri = URI.parse(signed_url)
22
22
 
23
23
  uri.scheme.should eq 'http'
@@ -25,13 +25,28 @@ describe EY::ApiHMAC do
25
25
  uri.path.should eq '/sign_test'
26
26
 
27
27
  parameters = CGI::parse(uri.query)
28
- parameters["signature"].first.should eq EY::ApiHMAC.base64digest("foo=bar&xargs=5&zarg=boot", @auth_key)
28
+ parameters["signature"].first.should eq EY::ApiHMAC::SSO.signature_param(
29
+ "http://example.com/sign_test?foo=bar&xargs=5&zarg=boot", @auth_id, @auth_key)
29
30
  end
30
31
 
31
32
  it "can verify signed requests" do
32
- signed_url = EY::ApiHMAC.sign_for_sso(@url, @parameters, @auth_id, @auth_key)
33
- EY::ApiHMAC.verify_for_sso(signed_url, @auth_id, @auth_key).should be_true
34
- EY::ApiHMAC.verify_for_sso(signed_url + 'a', @auth_id, @auth_key).should be_false
33
+ signed_url = EY::ApiHMAC::SSO.sign(@url, @parameters, @auth_id, @auth_key)
34
+ EY::ApiHMAC::SSO.authenticated?(signed_url, @auth_id, @auth_key).should be_true
35
+ EY::ApiHMAC::SSO.authenticated?(signed_url + 'a', @auth_id, @auth_key).should be_false
36
+ end
37
+
38
+ it "catches changes to the url" do
39
+ signed_url = EY::ApiHMAC::SSO.sign(@url, @parameters, @auth_id, @auth_key)
40
+ EY::ApiHMAC::SSO.authenticated?(signed_url, @auth_id, @auth_key).should be_true
41
+ tampered_url = signed_url.gsub("sign_test", "admin")
42
+ EY::ApiHMAC::SSO.authenticated?(tampered_url, @auth_id, @auth_key).should be_false
43
+ end
44
+
45
+ it "catches changes to the parameters" do
46
+ signed_url = EY::ApiHMAC::SSO.sign(@url, @parameters, @auth_id, @auth_key)
47
+ EY::ApiHMAC::SSO.authenticated?(signed_url, @auth_id, @auth_key).should be_true
48
+ tampered_url = signed_url.gsub("foo", "fool")
49
+ EY::ApiHMAC::SSO.authenticated?(tampered_url, @auth_id, @auth_key).should be_false
35
50
  end
36
51
 
37
52
  #TODO: write a test that fails if we skip the CGI.unescape
@@ -40,13 +55,9 @@ describe EY::ApiHMAC do
40
55
 
41
56
  #TODO: test that you get an error when you try to sign a url with any of the "Reserved" parameters (signature or timestamp)
42
57
 
43
- #TODO: send the auth_id in the params too
44
-
45
58
  #TODO: Rename "signature" to "ey_api_sso_hmac_signature"
46
59
 
47
- #TODO: provide a time
48
-
49
- #TODO: maybe an expiry time would be better
60
+ #TODO: provide a timestamp? maybe an expiry time would be better
50
61
 
51
62
  #TODO: should the other params be part of the gem?
52
63
  # ey_user_id – the unique identifier for the user.
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ey_api_hmac
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 27
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 1
10
- version: 0.0.1
9
+ - 2
10
+ version: 0.0.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - "Jacob Burkhart & Thorben Schr\xC3\xB6der & David Calavera & others"
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-08-15 00:00:00 -07:00
18
+ date: 2011-08-16 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -33,7 +33,7 @@ dependencies:
33
33
  type: :runtime
34
34
  version_requirements: *id001
35
35
  - !ruby/object:Gem::Dependency
36
- name: rspec
36
+ name: json
37
37
  prerelease: false
38
38
  requirement: &id002 !ruby/object:Gem::Requirement
39
39
  none: false
@@ -44,8 +44,22 @@ dependencies:
44
44
  segments:
45
45
  - 0
46
46
  version: "0"
47
- type: :development
47
+ type: :runtime
48
48
  version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: rspec
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :development
62
+ version_requirements: *id003
49
63
  description: basic wrapper for rack-client + middlewares for HMAC auth + helpers for SSO auth
50
64
  email:
51
65
  - jacob@engineyard.com
@@ -59,11 +73,13 @@ files:
59
73
  - Gemfile
60
74
  - Gemfile.lock
61
75
  - LICENSE
76
+ - README.md
62
77
  - Rakefile
63
78
  - ey_api_hmac.gemspec
64
79
  - lib/ey_api_hmac.rb
65
80
  - lib/ey_api_hmac/api_auth.rb
66
81
  - lib/ey_api_hmac/base_connection.rb
82
+ - lib/ey_api_hmac/sso.rb
67
83
  - lib/ey_api_hmac/version.rb
68
84
  - spec/api_auth_spec.rb
69
85
  - spec/sso_spec.rb