ey_api_hmac 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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