lockbox_middleware 1.5.1 → 1.6.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.
@@ -0,0 +1,145 @@
1
+ require 'rubygems'
2
+ gem 'dnclabs-auth-hmac'
3
+ require 'auth-hmac'
4
+ require 'digest/md5'
5
+
6
+ class HmacRequest
7
+ attr_accessor :request, :env, :body, :hmac_id, :hmac_hash
8
+ undef :method
9
+
10
+ @@valid_date_window = 600 # seconds
11
+
12
+ HTTP_HEADER_TO_ENV_MAP = { 'Content-Type' => 'CONTENT_TYPE',
13
+ 'Content-MD5' => 'CONTENT_MD5',
14
+ 'Date' => 'HTTP_DATE',
15
+ 'Method' => 'REQUEST_METHOD',
16
+ 'Authorization' => 'HTTP_AUTHORIZATION' }
17
+
18
+ def self.new_from_rack_env(env)
19
+ r = self.new(env)
20
+ return r
21
+ end
22
+
23
+ def self.new_from_rails_request(request)
24
+ r = self.new(request.headers)
25
+ #pull stuff out of X-Referer, which is where the middleware sticks it
26
+ HTTP_HEADER_TO_ENV_MAP.each_pair do |h,e|
27
+ r.env[e] = r.env["X-Referer-#{h}"] unless r.env["X-Referer-#{h}"].blank?
28
+ end
29
+
30
+ return r
31
+ end
32
+
33
+ def initialize(env)
34
+ @request = Rack::Request.new(env)
35
+ @env = @request.env
36
+ @body = @request.body if has_body?(@env['REQUEST_METHOD'])
37
+ end
38
+
39
+ def [](key)
40
+ @request[key]
41
+ end
42
+
43
+ def path
44
+ #use Referer if it's there, which it will be when this gets called while hitting the AuthenticationController
45
+ if @env['Referer'].to_s =~ /^(?:http:\/\/)?[^\/]*(\/.*)$/
46
+ return $1
47
+ end
48
+ #if we're in the middleware, it won't be there but we can use the request's path to the same effect
49
+ return @request.path
50
+ end
51
+
52
+ def has_body?(method)
53
+ ["PUT","POST"].include?(method)
54
+ end
55
+
56
+ def hmac_id
57
+ get_hmac_vals if @hmac_id.nil?
58
+ @hmac_id
59
+ end
60
+
61
+ def hmac_hash
62
+ get_hmac_vals if @hmac_hash.nil?
63
+ @hmac_hash
64
+ end
65
+
66
+ def get_hmac_vals
67
+ @env['HTTP_AUTHORIZATION'].to_s =~ /^AuthHMAC ([^:]+):(.*)$/
68
+ @hmac_id = $1
69
+ @hmac_hash = $2
70
+ end
71
+
72
+
73
+ def hmac_auth(credential_store)
74
+ authhmac = AuthHMAC.new(credential_store)
75
+ if authhmac.authenticated?(self) && (@env['HTTP_DATE'].blank? || self.date_is_recent? )
76
+ credential_store[self.hmac_id]
77
+ else
78
+ log_auth_error(credential_store[self.hmac_id])
79
+ return false
80
+ end
81
+ end
82
+
83
+ def date_is_recent?()
84
+ req_date = nil
85
+
86
+ begin
87
+ req_date = Time.httpdate(@env['HTTP_DATE'])
88
+ rescue Exception => ex
89
+ if ex.message =~ /not RFC 2616 compliant/
90
+ # try rfc2822
91
+ req_date = Time.rfc2822(@env['HTTP_DATE'])
92
+ else
93
+ raise ex
94
+ end
95
+ end
96
+
97
+ if Time.now.to_i - req_date.to_i >= @@valid_date_window
98
+ log "Request date #{req_date} is more than #{@@valid_date_window} seconds old"
99
+ return false
100
+ else
101
+ return true
102
+ end
103
+ end
104
+
105
+ #these are the X-Referer-Headers that get passed along to lockbox from the middleware for authentication
106
+ def get_xreferer_auth_headers()
107
+ headers = {}
108
+ headers['Referer'] = "#{@env['rack.url_scheme']}://#{@env['SERVER_NAME']}#{@env['PATH_INFO']}"
109
+ headers['Referer'] << "?#{@env['QUERY_STRING']}" unless @env['QUERY_STRING'].blank?
110
+ HTTP_HEADER_TO_ENV_MAP.each_pair do |h,e|
111
+ headers["X-Referer-#{h}"] = @env[e] unless @env[e].blank?
112
+ end
113
+ headers['X-Referer-Content-MD5'] = Digest::MD5.hexdigest(@request.body.read) if @env['CONTENT_TYPE']
114
+ headers["X-Referer-Date"] = @env['HTTP_X_AUTHHMAC_REQUEST_DATE'] unless @env['HTTP_X_AUTHHMAC_REQUEST_DATE'].blank?
115
+ headers
116
+ end
117
+
118
+ def log_auth_error(key)
119
+ log "Logging Lockbox HMAC authorization error:"
120
+ log "Path: #{self.path}"
121
+
122
+ HTTP_HEADER_TO_ENV_MAP.values.each do |header|
123
+ log "#{header}: #{@env[header]}"
124
+ end
125
+
126
+ log "HMAC Canonical String: #{ AuthHMAC::CanonicalString.new(self).inspect}"
127
+
128
+ if self.hmac_id.nil?
129
+ log("HMAC failed because request is not signed")
130
+ elsif key
131
+ log("HMAC failed - expected #{AuthHMAC.signature(self,key)} but was #{self.hmac_hash}")
132
+ end
133
+ end
134
+
135
+
136
+ def log(msg)
137
+ logger = nil
138
+ if defined?(Rails.logger)
139
+ Rails.logger.error msg
140
+ else
141
+ $stdout.puts msg
142
+ end
143
+ end
144
+
145
+ end
@@ -3,22 +3,8 @@ require 'forwardable'
3
3
  module LockBoxCache
4
4
  class Cache
5
5
  extend Forwardable
6
- def_delegators :@cache, :write, :read, :delete
6
+ def_delegators :@cache, :write, :read, :delete, :clear
7
7
 
8
- class RailsCache
9
- def write(key, value)
10
- Rails.cache.write(key, value)
11
- end
12
-
13
- def read(key)
14
- Rails.cache.read(key)
15
- end
16
-
17
- def delete(key)
18
- Rails.cache.delete(key)
19
- end
20
- end
21
-
22
8
  class HashCache
23
9
  def initialize
24
10
  @store = Hash.new
@@ -35,14 +21,18 @@ module LockBoxCache
35
21
  def delete(key)
36
22
  @store.delete(key)
37
23
  end
24
+
25
+ def clear
26
+ @store = {}
27
+ end
38
28
  end
39
29
 
40
30
  def initialize(use_rails_cache=true)
41
31
  if use_rails_cache && defined?(Rails)
42
- @cache = RailsCache.new
32
+ @cache = Rails.cache
43
33
  else
44
34
  @cache = HashCache.new
45
35
  end
46
36
  end
47
37
  end
48
- end
38
+ end
@@ -1,36 +1,35 @@
1
1
  require 'rubygems'
2
- gem 'dnclabs-httparty'
3
- require 'httparty'
2
+ require 'httpotato'
4
3
  require 'lockbox_cache'
5
- require 'digest/md5'
4
+ require 'hmac_request'
6
5
 
7
6
  class LockBox
8
- include HTTParty
7
+ include HTTPotato
9
8
  include LockBoxCache
9
+
10
+ attr_accessor :cache
11
+
10
12
  @@config = nil
13
+ @@protected_paths = nil
11
14
 
12
15
  def self.config
13
16
  return @@config if @@config
14
- if defined?(Rails)
15
- root_dir = Rails.root
17
+ #use rails config if it's there
18
+ if defined?(Rails) && Rails.root
19
+ config_file = Rails.root.join('config','lockbox.yml')
20
+ @@config = YAML.load_file(config_file)[Rails.env]
16
21
  else
17
- root_dir = '.'
18
- end
19
- yaml_config = YAML.load_file(File.join(root_dir,'config','lockbox.yml'))
20
- return_config = {}
21
- environment = Rails.env if defined? Rails
22
- environment ||= ENV['RACK_ENV']
23
- environment ||= 'test'
24
- if !environment.nil?
25
- if !yaml_config['all'].nil?
22
+ env = ENV['RACK_ENV'] || "test"
23
+ config_file = File.join(Dir.pwd, 'config','lockbox.yml')
24
+ all_configs = YAML.load_file(config_file)
25
+ if !all_configs['all'].nil?
26
26
  $stderr.puts "The 'all' environment is deprecated in lockbox.yml; use built-in yaml convention instead."
27
- return_config = yaml_config['all']
28
- return_config.merge!(yaml_config[environment])
27
+ @@config = all_configs['all'].merge!(all_configs[env])
29
28
  else
30
- return_config = yaml_config[environment]
29
+ @@config = all_configs[env]
31
30
  end
32
31
  end
33
- @@config = return_config
32
+ return @@config
34
33
  end
35
34
 
36
35
  base_uri config['base_uri']
@@ -43,64 +42,65 @@ class LockBox
43
42
  def call(env)
44
43
  dup.call!(env)
45
44
  end
46
-
45
+
46
+ def cache_string_for_key(api_key)
47
+ "lockbox_key_#{api_key}"
48
+ end
49
+
50
+ def cache_string_for_hmac(hmac_id)
51
+ "lockbox_hmac_#{hmac_id.gsub(/[^a-z0-9]/i,'_')}"
52
+ end
53
+
47
54
  def protected_paths
48
- self.class.config['protect_paths'].map do |path|
49
- Regexp.new(path)
50
- end
55
+ @@protect_paths ||= self.class.config['protect_paths'].map{ |path| Regexp.new(path) }
51
56
  end
52
57
 
53
58
  def call!(env)
54
- #attempt to authenticate any requests to /api
55
- request = Rack::Request.new(env)
56
- path_protected = false
57
- protected_paths.each do |path|
58
- if env['PATH_INFO'] =~ path
59
- path_protected = true
60
- authorized = false
61
- key = request['key']
62
- if key.blank?
63
- key = 'hmac'
59
+ protected_path = protected_paths.detect{|path| env['PATH_INFO'] =~ path}
60
+ #if the requested path is protected, it needs to be authenticated
61
+ if protected_path
62
+ request = HmacRequest.new_from_rack_env(env)
63
+ if !request['key'].nil?
64
+ auth = auth_via_key(request['key'], request)
65
+ else
66
+ auth = auth_via_hmac(request)
64
67
  end
65
-
66
- auth = auth_response(key,env)
67
- authorized = auth[:authorized]
68
- auth_headers = auth[:headers]
69
-
70
- if authorized
68
+
69
+ if auth[:authorized]
71
70
  app_response = @app.call(env)
72
- app_headers = app_response[1]
73
- response_headers = app_headers.merge(auth_headers)
74
- return [app_response[0], response_headers, app_response[2]]
71
+ return [app_response[0], app_response[1].merge(auth[:headers]), app_response[2]]
75
72
  else
76
73
  message = "Access Denied"
77
74
  return [401, {'Content-Type' => 'text/plain', 'Content-Length' => "#{message.length}"}, [message]]
78
75
  end
79
- end
80
- end
81
- unless path_protected
76
+ else
82
77
  #pass everything else straight through to app
83
78
  return @app.call(env)
84
79
  end
85
80
  end
86
81
 
87
- def auth_response(api_key, env={})
88
- if api_key != 'hmac'
89
- cached_auth = auth_cache(api_key)
90
- if !cached_auth.nil?
91
- # currently we don't cache forward headers
92
- return {:authorized => cached_auth, :headers => {}}
93
- end
94
- end
95
- auth_response = self.class.get("/authentication/#{api_key}", {:headers => auth_headers(env), :request => {:application_name => LockBox.config['application_name']}})
82
+ def auth_via_key(api_key, request)
83
+ cached_auth = check_key_cache(api_key)
84
+ # currently we don't cache forward headers
85
+ return {:authorized => cached_auth, :headers => {}} if cached_auth
86
+ auth_response = self.class.get("/authentication/#{api_key}", {:headers => request.get_xreferer_auth_headers, :request => {:application_name => LockBox.config['application_name']}})
87
+ authorized = (auth_response.code == 200)
88
+ cache_key_response_if_allowed(api_key, auth_response) if authorized
89
+ {:authorized => authorized, :headers => response_headers(auth_response)}
90
+ end
91
+
92
+ def auth_via_hmac(hmac_request)
93
+ cached_auth = check_hmac_cache(hmac_request)
94
+ return {:authorized => cached_auth, :headers => {}} if cached_auth
95
+ auth_response = self.class.get("/authentication/hmac", {:headers => hmac_request.get_xreferer_auth_headers, :request => {:application_name => LockBox.config['application_name']}})
96
96
  authorized = (auth_response.code == 200)
97
- cache_response_if_allowed(api_key, auth_response) if authorized
97
+ cache_hmac_response_if_allowed(hmac_request, auth_response) if authorized
98
98
  {:authorized => authorized, :headers => response_headers(auth_response)}
99
99
  end
100
-
100
+
101
101
  private
102
-
103
- def cache_response_if_allowed(api_key, auth_response)
102
+
103
+ def cache_key_response_if_allowed(api_key, auth_response)
104
104
  cache_control = auth_response.headers['Cache-Control'].split(/,\s*/)
105
105
  cache_max_age = 0
106
106
  cache_public = false
@@ -113,52 +113,63 @@ class LockBox
113
113
  end
114
114
  caching_allowed = (cache_max_age > 0 && cache_public)
115
115
  expiration = Time.at(Time.now.to_i + cache_max_age)
116
- cache_auth(api_key,expiration) if caching_allowed
116
+ @cache.write(cache_string_for_key(api_key), expiration.to_i) if caching_allowed
117
117
  end
118
118
 
119
- def response_headers(auth_response)
120
- headers = {}
121
- auth_response.headers.each_pair do |h,v|
122
- if h =~ /^X-RateLimit-/
123
- headers[h] = v
124
- elsif h =~ /^X-LockBox-/
125
- headers[h] = v
119
+ def cache_hmac_response_if_allowed(hmac_request, auth_response)
120
+ cache_control = auth_response.headers['Cache-Control'].split(/,\s*/)
121
+ cache_max_age = 0
122
+ cache_public = false
123
+ cache_control.each do |c|
124
+ if c =~ /^max-age=\s*(\d+)$/
125
+ cache_max_age = $1.to_i
126
+ elsif c == 'public'
127
+ cache_public = true
126
128
  end
127
129
  end
128
- headers
130
+ caching_allowed = (cache_max_age > 0 && cache_public)
131
+ expiration = Time.at(Time.now.to_i + cache_max_age)
132
+ if caching_allowed
133
+ api_key = auth_response.headers['X-LockBox-API-Key']
134
+ @cache.write(cache_string_for_hmac(hmac_request.hmac_id), [api_key, expiration.to_i])
135
+ end
129
136
  end
130
137
 
131
- def auth_headers(env)
138
+ def response_headers(auth_response)
132
139
  headers = {}
133
- headers['Referer'] = "#{env['rack.url_scheme']}://#{env['SERVER_NAME']}#{env['PATH_INFO']}"
134
- headers['Referer'] << "?#{env['QUERY_STRING']}" unless env['QUERY_STRING'].blank?
135
- headers['X-Referer-Content-MD5'] = Digest::MD5.hexdigest(Rack::Request.new(env).body.read) if env['CONTENT_TYPE']
136
- {'Content-Type' => 'CONTENT_TYPE', 'Date' => 'HTTP_DATE', 'Method' => 'REQUEST_METHOD',
137
- 'Authorization' => 'HTTP_AUTHORIZATION'}.each_pair do |h,e|
138
- headers["X-Referer-#{h}"] = env[e] unless env[e].blank?
140
+ auth_response.headers.each_pair do |h,v|
141
+ headers[h] = v if h =~ /^X-RateLimit-|^X-LockBox-/
139
142
  end
140
- headers["X-Referer-Date"] = env['HTTP_X_AUTHHMAC_REQUEST_DATE'] unless env['HTTP_X_AUTHHMAC_REQUEST_DATE'].blank?
141
143
  headers
142
144
  end
143
-
144
- def cache_key(api_key)
145
- "lockbox_#{api_key}"
146
- end
147
145
 
148
- def auth_cache(api_key)
149
- expiration = @cache.read(cache_key(api_key))
146
+ def check_key_cache(api_key)
147
+ expiration = @cache.read(cache_string_for_key(api_key))
150
148
  return nil if expiration.nil?
151
149
  expiration = Time.at(expiration)
152
150
  if expiration <= Time.now
153
- @cache.delete(cache_key(api_key))
151
+ @cache.delete(cache_string_for_key(api_key))
154
152
  nil
155
- elsif expiration > Time.now
153
+ else
156
154
  true
157
155
  end
158
156
  end
159
157
 
160
- def cache_auth(api_key,expiration)
161
- @cache.write(cache_key(api_key),expiration.to_i)
158
+ def check_hmac_cache(hmac_request)
159
+ hmac_id, hmac_hash = hmac_request.hmac_id, hmac_request.hmac_hash
160
+ return nil if hmac_id.nil? || hmac_hash.nil?
161
+ cached_val = @cache.read(cache_string_for_hmac(hmac_id))
162
+ return nil if cached_val.nil?
163
+ key, expiration = cached_val
164
+ expiration = Time.at(expiration)
165
+ if expiration <= Time.now
166
+ @cache.delete(cache_string_for_hmac(hmac_id))
167
+ nil
168
+ else
169
+ #as long as the request is signed correctly, no need to contact the lockbox server to verify
170
+ #just see if the request is signed properly and let it through if it is
171
+ return true if hmac_request.hmac_auth({hmac_id => key}) == key
172
+ return nil
173
+ end
162
174
  end
163
-
164
175
  end
@@ -99,7 +99,7 @@ describe 'LockBox' do
99
99
  end
100
100
  end
101
101
 
102
- context "hitting API actions" do
102
+ context "hitting API actions with key-based authentication" do
103
103
  before :each do
104
104
  @max_age = 3600
105
105
  successful_response = mock("MockResponse")
@@ -214,9 +214,7 @@ describe 'LockBox' do
214
214
  @path = "/api/some_controller/some_action"
215
215
 
216
216
  hmac_request = Net::HTTP::Get.new(@path, {'Date' => Time.now.httpdate})
217
- store = mock("MockStore")
218
- store.stubs(:[]).with('key-id').returns("123456")
219
- authhmac = AuthHMAC.new(store)
217
+ authhmac = AuthHMAC.new({"key-id" => "123456"})
220
218
  authhmac.sign!(hmac_request, 'key-id')
221
219
  @hmac_headers = hmac_request.to_hash
222
220
  end
@@ -228,7 +226,7 @@ describe 'LockBox' do
228
226
  get @path
229
227
  last_response.status.should == 200
230
228
  end
231
-
229
+
232
230
  it "should return 200 for a valid HMAC request from a .NET client" do
233
231
  # first test w/ a Date header too, then test w/o a separate Date header
234
232
  @hmac_headers['X-AuthHMAC-Request-Date'] = @hmac_headers['Date']
@@ -238,7 +236,7 @@ describe 'LockBox' do
238
236
  get @path
239
237
  last_response.status.should == 200
240
238
  end
241
-
239
+
242
240
  it "should return 200 for a valid HMAC request from a .NET client with no Date header" do
243
241
  @hmac_headers['X-AuthHMAC-Request-Date'] = @hmac_headers.delete('Date')
244
242
  @hmac_headers.each_pair do |key,value|
@@ -256,8 +254,9 @@ describe 'LockBox' do
256
254
  get @path
257
255
  last_response.status.should == 401
258
256
  end
257
+
259
258
  end
260
-
259
+
261
260
  context "hitting API actions via POST requests with HMAC auth" do
262
261
  before :each do
263
262
  @content = "" # TODO: Rack::Test sucks at some stuff, like setting the request body when making a POST
@@ -280,9 +279,7 @@ describe 'LockBox' do
280
279
 
281
280
  hmac_request = Net::HTTP::Post.new(@path, {'Date' => Time.now.httpdate})
282
281
  hmac_request.body = @content
283
- store = mock("MockStore")
284
- store.stubs(:[]).with('key-id').returns("123456")
285
- authhmac = AuthHMAC.new(store)
282
+ authhmac = AuthHMAC.new({"key-id" => "123456"})
286
283
  authhmac.sign!(hmac_request, 'key-id')
287
284
  @hmac_headers = hmac_request.to_hash
288
285
  end
@@ -303,8 +300,9 @@ describe 'LockBox' do
303
300
  post @path, @content
304
301
  last_response.status.should == 401
305
302
  end
303
+
306
304
  end
307
-
305
+
308
306
  context "hitting actions without API" do
309
307
 
310
308
  it "should not try to authenticate a request that doesn't start with /api" do
@@ -314,5 +312,67 @@ describe 'LockBox' do
314
312
  end
315
313
 
316
314
  end
315
+
316
+ context "hitting API actions with HMAC auth caching" do
317
+ before :each do
318
+ Time.stubs(:now).returns(Time.parse("2010-05-10 16:30:00 EDT"))
319
+ @response_with_caching = mock("MockResponse")
320
+ @response_with_caching.stubs(:code).returns(200)
321
+ @response_with_caching.stubs(:headers).returns({'Cache-Control' => "public,max-age=3600,must-revalidate", "X-LockBox-API-Key" => "123456"})
322
+
323
+ @response_without_caching = mock("MockResponse")
324
+ @response_without_caching.stubs(:code).returns(200)
325
+ @response_without_caching.stubs(:headers).returns({'Cache-Control' => 'public, no-cache', "X-LockBox-API-Key" => "123456"})
326
+
327
+ @bad_response = mock("MockResponse")
328
+ @bad_response.stubs(:code).returns(401)
329
+ @bad_response.stubs(:headers).returns({'Cache-Control' => 'public, no-cache'})
330
+
331
+ @path = "/api/some_controller/some_action"
332
+
333
+ hmac_request = Net::HTTP::Get.new(@path, {'Date' => Time.now.httpdate, 'Referer' =>'http://example.org/api/some_controller/some_action' })
334
+ authhmac = AuthHMAC.new({'key-id' => '123456'})
335
+ authhmac.sign!(hmac_request, 'key-id')
336
+ @hmac_headers = hmac_request.to_hash
337
+ @hmac_headers.each_pair do |key,value|
338
+ header key, value
339
+ end
340
+
341
+ end
342
+
343
+ after :each do
344
+ app.cache.clear
345
+ end
346
+
347
+
348
+ it "should cache lockbox responses for max-age when Cache-Control allows it" do
349
+ LockBox.stubs(:get).returns(@response_with_caching)
350
+ get @path
351
+ last_response.status.should == 200
352
+ LockBox.stubs(:get).returns(@bad_response)
353
+ get @path
354
+ last_response.status.should == 200
355
+ end
356
+
357
+ it "should expire cached lockbox responses when max-age seconds have passed" do
358
+ LockBox.stubs(:get).returns(@response_with_caching)
359
+ get @path
360
+ last_response.status.should == 200
361
+ expired_time = Time.at(Time.now.to_i + 3600)
362
+ Time.stubs(:now).returns(expired_time)
363
+ LockBox.stubs(:get).returns(@bad_response)
364
+ get @path
365
+ last_response.status.should == 401
366
+ end
367
+
368
+ it "should not cache lockbox responses when Cache-Control does not allow it" do
369
+ LockBox.stubs(:get).returns(@response_without_caching)
370
+ get @path
371
+ last_response.status.should == 200
372
+ LockBox.stubs(:get).returns(@bad_response)
373
+ get @path
374
+ last_response.status.should == 401
375
+ end
376
+ end
317
377
 
318
378
  end
@@ -10,6 +10,6 @@ module Mocha
10
10
  end
11
11
  def teardown_mocks_for_rspec
12
12
  mocha_teardown
13
- end
13
+ end
14
14
  end
15
15
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lockbox_middleware
3
3
  version: !ruby/object:Gem::Version
4
- hash: 1
5
- prerelease: false
4
+ hash: 11
5
+ prerelease:
6
6
  segments:
7
7
  - 1
8
- - 5
9
- - 1
10
- version: 1.5.1
8
+ - 6
9
+ - 2
10
+ version: 1.6.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Chris Gill
@@ -19,7 +19,7 @@ autorequire:
19
19
  bindir: bin
20
20
  cert_chain: []
21
21
 
22
- date: 2010-12-28 00:00:00 -06:00
22
+ date: 2011-03-02 00:00:00 -05:00
23
23
  default_executable:
24
24
  dependencies:
25
25
  - !ruby/object:Gem::Dependency
@@ -37,7 +37,7 @@ dependencies:
37
37
  type: :runtime
38
38
  version_requirements: *id001
39
39
  - !ruby/object:Gem::Dependency
40
- name: dnclabs-httparty
40
+ name: httpotato
41
41
  prerelease: false
42
42
  requirement: &id002 !ruby/object:Gem::Requirement
43
43
  none: false
@@ -50,6 +50,20 @@ dependencies:
50
50
  version: "0"
51
51
  type: :runtime
52
52
  version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: dnclabs-auth-hmac
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 3
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ type: :runtime
66
+ version_requirements: *id003
53
67
  description: Rack middleware for the LockBox centralized API authorization service. Brought to you by the DNC Innovation Lab.
54
68
  email: innovationlab@dnc.org
55
69
  executables: []
@@ -62,6 +76,7 @@ extra_rdoc_files:
62
76
  files:
63
77
  - lib/lockbox_cache.rb
64
78
  - lib/lockbox_middleware.rb
79
+ - lib/hmac_request.rb
65
80
  - LICENSE
66
81
  - README.rdoc
67
82
  - spec/lib/lockbox_cache_spec.rb
@@ -100,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
115
  requirements: []
101
116
 
102
117
  rubyforge_project:
103
- rubygems_version: 1.3.7
118
+ rubygems_version: 1.6.0
104
119
  signing_key:
105
120
  specification_version: 3
106
121
  summary: Rack middleware for the LockBox centralized API authorization service.