api-auth 2.0.0 → 2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a0fd8e9563fd57370a49c2c3b909432df2047bca
4
- data.tar.gz: 4e3ca050145a2e8271e904f852ac43ad608dd5e9
3
+ metadata.gz: 92c46c40ca59ec931c02893f62155ea3efdfba48
4
+ data.tar.gz: ac4c5514140b61f5df1b81408898413aef553cf7
5
5
  SHA512:
6
- metadata.gz: 717a5e94e609715659eb3355c062436962ba93fb0352d05041fe85604fb4cd7bbd3d4c460595c944c7a14fba2705960637026b2d66d8b5d63a328c845c96e9b8
7
- data.tar.gz: 8edeaa5acf7c890900531441ea137bbf59264ec99862896bd2f168232899b9451d34930813a21bfbe50d761ad1e41f84eb431ead00d5620fc56e1aaffa042632
6
+ metadata.gz: 38370d16d830ae325f862f972b20d267da8135750e923520df5902662cae46b4244a79d1520ec15b9ca4722f76018f88bfbb874bc4b64fd44f70b36f8402d018
7
+ data.tar.gz: c3a16015aa11cd3da2b296d5729b3c7f0fccdea1e5a8005a98a4b7465e95944a951afdb9a474f182e1ff3df996d5d36e369f37f2cc60ed9e9eaf6c9e82c04985
@@ -4,8 +4,9 @@ cache: bundler
4
4
  rvm:
5
5
  - 1.8.7-p374
6
6
  - 1.9.3
7
- - 2.1.5
8
- - 2.2.1
7
+ - 2.1.9
8
+ - 2.2.5
9
+ - 2.3.1
9
10
  gemfile:
10
11
  - gemfiles/rails_23.gemfile
11
12
  - gemfiles/rails_30.gemfile
@@ -14,6 +15,13 @@ gemfile:
14
15
  - gemfiles/rails_4.gemfile
15
16
  - gemfiles/rails_41.gemfile
16
17
  - gemfiles/rails_42.gemfile
18
+ - gemfiles/rails_5.gemfile
19
+ env:
20
+ - TEST_SUITE=rake
21
+
22
+ script:
23
+ - bundle exec $TEST_SUITE
24
+
17
25
  matrix:
18
26
  exclude:
19
27
  - rvm: 1.8.7-p374
@@ -22,20 +30,38 @@ matrix:
22
30
  gemfile: gemfiles/rails_41.gemfile
23
31
  - rvm: 1.8.7-p374
24
32
  gemfile: gemfiles/rails_42.gemfile
25
- - rvm: 2.1.5
33
+ - rvm: 1.8.7-p374
34
+ gemfile: gemfiles/rails_5.gemfile
35
+ - rvm: 1.9.3
36
+ gemfile: gemfiles/rails_5.gemfile
37
+ - rvm: 2.1.9
26
38
  gemfile: gemfiles/rails_23.gemfile
27
- - rvm: 2.1.5
39
+ - rvm: 2.1.9
28
40
  gemfile: gemfiles/rails_30.gemfile
29
- - rvm: 2.1.5
41
+ - rvm: 2.1.9
30
42
  gemfile: gemfiles/rails_31.gemfile
31
- - rvm: 2.2.1
43
+ - rvm: 2.1.9
44
+ gemfile: gemfiles/rails_5.gemfile
45
+ - rvm: 2.2.5
46
+ gemfile: gemfiles/rails_23.gemfile
47
+ - rvm: 2.2.5
48
+ gemfile: gemfiles/rails_30.gemfile
49
+ - rvm: 2.2.5
50
+ gemfile: gemfiles/rails_31.gemfile
51
+ - rvm: 2.2.5
52
+ gemfile: gemfiles/rails_32.gemfile
53
+ - rvm: 2.3.1
32
54
  gemfile: gemfiles/rails_23.gemfile
33
- - rvm: 2.2.1
55
+ - rvm: 2.3.1
34
56
  gemfile: gemfiles/rails_30.gemfile
35
- - rvm: 2.2.1
57
+ - rvm: 2.3.1
36
58
  gemfile: gemfiles/rails_31.gemfile
37
- - rvm: 2.2.1
59
+ - rvm: 2.3.1
38
60
  gemfile: gemfiles/rails_32.gemfile
61
+ include:
62
+ - rvm: 2.3.1
63
+ gemfile: gemfiles/rails_5.gemfile
64
+ env: TEST_SUITE="rubocop lib/ spec/"
39
65
 
40
66
  notifications:
41
67
  email: false
@@ -1,3 +1,10 @@
1
+ # 2.0.1 (2016-07-25)
2
+ - Support of `api_auth_options` in ActiveResource integration (#102 fwininger)
3
+ - Replace use of `#blank?` with `#nil?` to not depend on ActiveSupport (#114 packrat386)
4
+ - Fix Auth header matching to not match invalid SHA algorithms (#115 packrat386)
5
+ - Replace `alias_method_chain` with `alias_method` in the railtie since
6
+ alias_method_chain is deprecated in Rails 5 (#118 mlarraz)
7
+
1
8
  # 2.0.0 (2016-05-11)
2
9
  - IMPORTANT: 2.0.0 is backwards incompatible with the default settings of v1.x
3
10
  v2.0.0 always includes the http method in the canonical string.
data/Gemfile CHANGED
@@ -1,5 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
  gemspec
3
3
 
4
- gem "rake", "< 11.0", :platforms => :ruby_18
5
- gem "tins", "< 1.7", :platforms => :ruby_19 # amatch dependency
4
+ gem 'rake', '< 11.0', :platforms => :ruby_18
5
+ gem 'tins', '< 1.7', :platforms => :ruby_19 # amatch dependency
6
+
7
+ gem 'rubocop', :platforms => [:ruby_19, :ruby_20, :ruby_21, :ruby_22, :ruby_23]
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.0.0
1
+ 2.0.1
@@ -0,0 +1,11 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "actionpack", "~> 5.0.0"
6
+ gem "activeresource", "~> 5.0.0", git: 'https://github.com/rails/activeresource.git'
7
+ gem "activesupport", "~> 5.0.0"
8
+
9
+ gem "rubocop"
10
+
11
+ gemspec :path => "../"
@@ -69,7 +69,7 @@ module ApiAuth
69
69
 
70
70
  private
71
71
 
72
- AUTH_HEADER_PATTERN = /APIAuth(?:-HMAC-(MD[245]|SHA(?:1|224|256|384|512)*))? ([^:]+):(.+)$/
72
+ AUTH_HEADER_PATTERN = /APIAuth(?:-HMAC-(MD[245]|SHA(?:1|224|256|384|512)?))? ([^:]+):(.+)$/
73
73
 
74
74
  def request_too_old?(headers)
75
75
  # 900 seconds is 15 minutes
@@ -83,7 +83,7 @@ module ApiAuth
83
83
  match_data = parse_auth_header(headers.authorization_header)
84
84
  return false unless match_data
85
85
 
86
- digest = match_data[1].blank? ? 'SHA1' : match_data[1].upcase
86
+ digest = match_data[1].nil? ? 'SHA1' : match_data[1].upcase
87
87
  raise InvalidRequestDigest if !options[:digest].nil? && !options[:digest].casecmp(digest).zero?
88
88
 
89
89
  options = { :digest => digest }.merge(options)
@@ -58,8 +58,7 @@ module ApiAuth
58
58
  @request.content_type,
59
59
  @request.content_md5,
60
60
  parse_uri(@request.request_uri),
61
- @request.timestamp
62
- ].join(',')
61
+ @request.timestamp].join(',')
63
62
  end
64
63
 
65
64
  # Returns the authorization header from the request's headers
@@ -27,10 +27,12 @@ module ApiAuth
27
27
  base.class_attribute :hmac_access_id
28
28
  base.class_attribute :hmac_secret_key
29
29
  base.class_attribute :use_hmac
30
+ base.class_attribute :api_auth_options
30
31
  else
31
32
  base.class_inheritable_accessor :hmac_access_id
32
33
  base.class_inheritable_accessor :hmac_secret_key
33
34
  base.class_inheritable_accessor :use_hmac
35
+ base.class_inheritable_accessor :api_auth_options
34
36
  end
35
37
  end
36
38
 
@@ -39,9 +41,11 @@ module ApiAuth
39
41
  self.hmac_access_id = access_id
40
42
  self.hmac_secret_key = secret_key
41
43
  self.use_hmac = true
44
+ self.api_auth_options = options
42
45
 
43
46
  class << self
44
- alias_method_chain :connection, :auth
47
+ alias_method :connection_without_auth, :connection
48
+ alias_method :connection, :connection_with_auth
45
49
  end
46
50
  end
47
51
 
@@ -50,6 +54,7 @@ module ApiAuth
50
54
  c.hmac_access_id = hmac_access_id
51
55
  c.hmac_secret_key = hmac_secret_key
52
56
  c.use_hmac = use_hmac
57
+ c.api_auth_options = api_auth_options
53
58
  c
54
59
  end
55
60
  end # class methods
@@ -60,9 +65,11 @@ module ApiAuth
60
65
 
61
66
  module Connection
62
67
  def self.included(base)
63
- base.send :alias_method_chain, :request, :auth
68
+ base.send :alias_method, :request_without_auth, :request
69
+ base.send :alias_method, :request, :request_with_auth
70
+
64
71
  base.class_eval do
65
- attr_accessor :hmac_secret_key, :hmac_access_id, :use_hmac
72
+ attr_accessor :hmac_secret_key, :hmac_access_id, :use_hmac, :api_auth_options
66
73
  end
67
74
  end
68
75
 
@@ -71,7 +78,7 @@ module ApiAuth
71
78
  h = arguments.last
72
79
  tmp = "Net::HTTP::#{method.to_s.capitalize}".constantize.new(path, h)
73
80
  tmp.body = arguments[0] if arguments.length > 1
74
- ApiAuth.sign!(tmp, hmac_access_id, hmac_secret_key)
81
+ ApiAuth.sign!(tmp, hmac_access_id, hmac_secret_key, api_auth_options)
75
82
  arguments.last['Content-MD5'] = tmp['Content-MD5'] if tmp['Content-MD5']
76
83
  arguments.last['DATE'] = tmp['DATE']
77
84
  arguments.last['Authorization'] = tmp['Authorization']
@@ -21,10 +21,9 @@ module ApiAuth
21
21
  end
22
22
 
23
23
  def populate_content_md5
24
- if @request.put? || @request.post?
25
- @request.env['Content-MD5'] = calculated_md5
26
- fetch_headers
27
- end
24
+ return unless @request.put? || @request.post?
25
+ @request.env['Content-MD5'] = calculated_md5
26
+ fetch_headers
28
27
  end
29
28
 
30
29
  def md5_mismatch?
@@ -21,10 +21,9 @@ module ApiAuth
21
21
  end
22
22
 
23
23
  def populate_content_md5
24
- if %w(POST PUT).include?(@request.method.to_s.upcase)
25
- @request.headers['Content-MD5'] = calculated_md5
26
- fetch_headers
27
- end
24
+ return unless %w(POST PUT).include?(@request.method.to_s.upcase)
25
+ @request.headers['Content-MD5'] = calculated_md5
26
+ fetch_headers
28
27
  end
29
28
 
30
29
  def md5_mismatch?
@@ -20,10 +20,9 @@ module ApiAuth
20
20
  end
21
21
 
22
22
  def populate_content_md5
23
- if @request.body
24
- @request.headers['Content-MD5'] = calculated_md5
25
- fetch_headers
26
- end
23
+ return unless @request.body
24
+ @request.headers['Content-MD5'] = calculated_md5
25
+ fetch_headers
27
26
  end
28
27
 
29
28
  def md5_mismatch?
@@ -27,9 +27,8 @@ module ApiAuth
27
27
  end
28
28
 
29
29
  def populate_content_md5
30
- if @request.class::REQUEST_HAS_BODY
31
- @request['Content-MD5'] = calculated_md5
32
- end
30
+ return unless @request.class::REQUEST_HAS_BODY
31
+ @request['Content-MD5'] = calculated_md5
33
32
  end
34
33
 
35
34
  def md5_mismatch?
@@ -26,10 +26,9 @@ module ApiAuth
26
26
  end
27
27
 
28
28
  def populate_content_md5
29
- if %w(POST PUT).include?(@request.request_method)
30
- @request.env['Content-MD5'] = calculated_md5
31
- fetch_headers
32
- end
29
+ return unless %w(POST PUT).include?(@request.request_method)
30
+ @request.env['Content-MD5'] = calculated_md5
31
+ fetch_headers
33
32
  end
34
33
 
35
34
  def md5_mismatch?
@@ -29,10 +29,9 @@ module ApiAuth
29
29
  end
30
30
 
31
31
  def populate_content_md5
32
- if [:post, :put].include?(@request.method)
33
- @request.headers['Content-MD5'] = calculated_md5
34
- save_headers
35
- end
32
+ return unless [:post, :put].include?(@request.method)
33
+ @request.headers['Content-MD5'] = calculated_md5
34
+ save_headers
36
35
  end
37
36
 
38
37
  def md5_mismatch?
@@ -60,8 +60,7 @@ describe 'ApiAuth' do
60
60
  Net::HTTP::Put.new('/resource.xml?foo=bar&bar=foo',
61
61
  'content-type' => 'text/plain',
62
62
  'content-md5' => '1B2M2Y8AsgTpgAmY7PhCfg==',
63
- 'date' => Time.now.utc.httpdate
64
- )
63
+ 'date' => Time.now.utc.httpdate)
65
64
  end
66
65
 
67
66
  let(:canonical_string) { ApiAuth::Headers.new(request).canonical_string }
@@ -79,8 +78,7 @@ describe 'ApiAuth' do
79
78
  new_request = Net::HTTP::Put.new('/resource.xml?foo=bar&bar=foo',
80
79
  'content-type' => 'text/plain',
81
80
  'content-md5' => '1B2M2Y8AsgTpgAmY7PhCfg==',
82
- 'date' => Time.now.utc.httpdate
83
- )
81
+ 'date' => Time.now.utc.httpdate)
84
82
 
85
83
  signature = hmac('123', new_request)
86
84
  new_request['Authorization'] = "APIAuth 1044:#{signature}"
@@ -106,11 +104,10 @@ describe 'ApiAuth' do
106
104
  end
107
105
 
108
106
  it 'fails to validate if the date is invalid' do
109
- request['date'] = "٢٠١٤-٠٩-٠٨ ١٦:٣١:١٤ +٠٣٠٠"
107
+ request['date'] = '٢٠١٤-٠٩-٠٨ ١٦:٣١:١٤ +٠٣٠٠'
110
108
  expect(ApiAuth.authentic?(request, '123')).to eq false
111
109
  end
112
110
 
113
-
114
111
  it 'fails to validate if the request method differs' do
115
112
  canonical_string = ApiAuth::Headers.new(request).canonical_string('POST')
116
113
  signature = hmac('123', request, canonical_string)
@@ -123,20 +120,35 @@ describe 'ApiAuth' do
123
120
  new_request = Net::HTTP::Put.new('/resource.xml?foo=bar&bar=foo',
124
121
  'content-type' => 'text/plain',
125
122
  'content-md5' => '1B2M2Y8AsgTpgAmY7PhCfg==',
126
- 'date' => Time.now.utc.httpdate
127
- )
123
+ 'date' => Time.now.utc.httpdate)
128
124
  canonical_string = ApiAuth::Headers.new(new_request).canonical_string
129
125
  signature = hmac('123', new_request, canonical_string, 'sha256')
130
- new_request['Authorization'] = "APIAuth-HMAC-SHA256 1044:#{signature}"
126
+ new_request['Authorization'] = "APIAuth-HMAC-#{digest} 1044:#{signature}"
131
127
  new_request
132
128
  end
133
129
 
134
- it 'validates for sha256 digest' do
135
- expect(ApiAuth.authentic?(request, '123', :digest => 'sha256')).to eq true
130
+ context 'valid request digest' do
131
+ let(:digest) { 'SHA256' }
132
+
133
+ context 'matching client digest' do
134
+ it 'validates matching digest' do
135
+ expect(ApiAuth.authentic?(request, '123', :digest => 'sha256')).to eq true
136
+ end
137
+ end
138
+
139
+ context 'different client digest' do
140
+ it 'raises an exception' do
141
+ expect { ApiAuth.authentic?(request, '123', :digest => 'sha512') }.to raise_error(ApiAuth::InvalidRequestDigest)
142
+ end
143
+ end
136
144
  end
137
145
 
138
- it 'validates exception with wrong client digest' do
139
- expect { ApiAuth.authentic?(request, '123', :digest => 'sha512') }.to raise_error(ApiAuth::InvalidRequestDigest)
146
+ context 'invalid request digest' do
147
+ let(:digest) { 'SHA111' }
148
+
149
+ it 'fails validation' do
150
+ expect(ApiAuth.authentic?(request, '123', :digest => 'sha111')).to eq false
151
+ end
140
152
  end
141
153
  end
142
154
  end
@@ -62,7 +62,11 @@ describe 'Rails integration' do
62
62
  end
63
63
 
64
64
  it 'should permit a request with properly signed headers' do
65
- request = ActionController::TestRequest.new
65
+ request = if ActionController::TestRequest.respond_to?(:create)
66
+ ActionController::TestRequest.create
67
+ else
68
+ ActionController::TestRequest.new
69
+ end
66
70
  request.env['DATE'] = Time.now.utc.httpdate
67
71
  ApiAuth.sign!(request, '1044', API_KEY_STORE['1044'])
68
72
  response = generated_response(request, :index)
@@ -70,7 +74,11 @@ describe 'Rails integration' do
70
74
  end
71
75
 
72
76
  it 'should forbid a request with properly signed headers but timestamp > 15 minutes' do
73
- request = ActionController::TestRequest.new
77
+ request = if ActionController::TestRequest.respond_to?(:create)
78
+ ActionController::TestRequest.create
79
+ else
80
+ ActionController::TestRequest.new
81
+ end
74
82
  request.env['DATE'] = 'Mon, 23 Jan 1984 03:29:56 GMT'
75
83
  ApiAuth.sign!(request, '1044', API_KEY_STORE['1044'])
76
84
  response = generated_response(request, :index)
@@ -78,26 +86,42 @@ describe 'Rails integration' do
78
86
  end
79
87
 
80
88
  it "should insert a DATE header in the request when one hasn't been specified" do
81
- request = ActionController::TestRequest.new
89
+ request = if ActionController::TestRequest.respond_to?(:create)
90
+ ActionController::TestRequest.create
91
+ else
92
+ ActionController::TestRequest.new
93
+ end
82
94
  ApiAuth.sign!(request, '1044', API_KEY_STORE['1044'])
83
95
  expect(request.headers['DATE']).not_to be_nil
84
96
  end
85
97
 
86
98
  it 'should forbid an unsigned request to a protected controller action' do
87
- request = ActionController::TestRequest.new
99
+ request = if ActionController::TestRequest.respond_to?(:create)
100
+ ActionController::TestRequest.create
101
+ else
102
+ ActionController::TestRequest.new
103
+ end
88
104
  response = generated_response(request, :index)
89
105
  expect(response.code).to eq('401')
90
106
  end
91
107
 
92
108
  it 'should forbid a request with a bogus signature' do
93
- request = ActionController::TestRequest.new
109
+ request = if ActionController::TestRequest.respond_to?(:create)
110
+ ActionController::TestRequest.create
111
+ else
112
+ ActionController::TestRequest.new
113
+ end
94
114
  request.env['Authorization'] = 'APIAuth bogus:bogus'
95
115
  response = generated_response(request, :index)
96
116
  expect(response.code).to eq('401')
97
117
  end
98
118
 
99
119
  it 'should allow non-protected controller actions to function as before' do
100
- request = ActionController::TestRequest.new
120
+ request = if ActionController::TestRequest.respond_to?(:create)
121
+ ActionController::TestRequest.create
122
+ else
123
+ ActionController::TestRequest.new
124
+ end
101
125
  response = generated_response(request, :public)
102
126
  expect(response.code).to eq('200')
103
127
  end
@@ -122,7 +146,7 @@ describe 'Rails integration' do
122
146
  },
123
147
  { :id => '1' }.to_xml(:root => 'test_resource')
124
148
  end
125
- expect(ApiAuth).to receive(:sign!).with(anything, '1044', API_KEY_STORE['1044']).and_call_original
149
+ expect(ApiAuth).to receive(:sign!).with(anything, '1044', API_KEY_STORE['1044'], {}).and_call_original
126
150
  TestResource.find(1)
127
151
  end
128
152
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: api-auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mauricio Gomes
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-11 00:00:00.000000000 Z
11
+ date: 2016-07-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: appraisal
@@ -216,6 +216,7 @@ files:
216
216
  - gemfiles/rails_4.gemfile
217
217
  - gemfiles/rails_41.gemfile
218
218
  - gemfiles/rails_42.gemfile
219
+ - gemfiles/rails_5.gemfile
219
220
  - lib/api-auth.rb
220
221
  - lib/api_auth.rb
221
222
  - lib/api_auth/base.rb