prx_auth 1.2.1 → 1.6.0

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
  SHA256:
3
- metadata.gz: 1a851973aab51bd36533ff3959ab4d494886d0c6803fa1be1359ee1a5e0a68c0
4
- data.tar.gz: 9033b3e43be7f508ec7956df7be578e4b860f3285169ac1de6c5ee80b1e21c89
3
+ metadata.gz: f7d2d71dd1671a97f1ce4f9181852e8cc7e0a651e91370aca09300c468dfbf86
4
+ data.tar.gz: f4fcef9ecc2977321ae3ec193a8be62c0735d08f0a564787ff581d3e65bc869a
5
5
  SHA512:
6
- metadata.gz: 92e74203143a4920470336dd93bedfe07fe03235bbcafc20229f4076bdfabe5240e5908b0765b035c9471c0a8bfbc001435e08e61830dd954f64e65f0d0f2e26
7
- data.tar.gz: 139726fa863102b0e179c63e29df3d42f4fa03082e1208668cc6f9d32062bcab1995921677f22138718449a5b6a1cb67694003e141b829f585f0b6cc141e5dc9
6
+ metadata.gz: 482f861b69e7e05eb6d9b2308b2c0dfc402ac8a8bd01f200e14e04cafd24897adea376de29a6ad1fb6a52eeb08647303c10c344e097a45c1dea6730ace2a4bdf
7
+ data.tar.gz: 10ada294eda678f2d70c4780db32f33063a869d3caf25c481949cd5350f326bbeb6c5a60d96fa797ef3d1f2548c552edde731a28fd9667ee20a7d336ad936656
@@ -37,6 +37,14 @@ module PrxAuth
37
37
  end
38
38
  end
39
39
 
40
+ def [](key)
41
+ super(key.to_s)
42
+ end
43
+
44
+ def []=(key, value)
45
+ super(key.to_s, value)
46
+ end
47
+
40
48
  def condense
41
49
  condensed_wildcard = @wildcard.condense
42
50
  condensed_map = Hash[map do |resource, list|
@@ -126,7 +126,11 @@ module PrxAuth
126
126
  def &(other_list)
127
127
  return ScopeList.new('') if other_list.nil?
128
128
 
129
- self - (self - other_list)
129
+ self - (self - other_list) + (other_list - (other_list - self))
130
+ end
131
+
132
+ def ==(other)
133
+ condense.sort_by(&:to_s) == other.condense.sort_by(&:to_s)
130
134
  end
131
135
 
132
136
  private
@@ -1,3 +1,3 @@
1
1
  module PrxAuth
2
- VERSION = "1.2.1"
2
+ VERSION = "1.6.0"
3
3
  end
@@ -1,6 +1,7 @@
1
1
  require 'json/jwt'
2
2
  require 'rack/prx_auth/certificate'
3
3
  require 'rack/prx_auth/token_data'
4
+ require 'rack/prx_auth/auth_validator'
4
5
  require 'prx_auth'
5
6
 
6
7
  module Rack
@@ -20,16 +21,21 @@ module Rack
20
21
  @issuer = options[:issuer] || DEFAULT_ISS
21
22
  end
22
23
 
24
+ def build_auth_validator(token)
25
+ AuthValidator.new(token, @certificate, @issuer)
26
+ end
27
+
23
28
  def call(env)
24
29
  return @app.call(env) unless env['HTTP_AUTHORIZATION']
25
30
 
26
31
  token = env['HTTP_AUTHORIZATION'].split[1]
27
- claims = decode_token(token)
28
32
 
29
- return @app.call(env) unless should_validate_token?(claims)
33
+ auth_validator = build_auth_validator(token)
34
+
35
+ return @app.call(env) unless should_validate_token?(auth_validator)
30
36
 
31
- if valid?(claims, token)
32
- env['prx.auth'] = TokenData.new(claims)
37
+ if auth_validator.valid?
38
+ env['prx.auth'] = TokenData.new(auth_validator.claims)
33
39
  @app.call(env)
34
40
  else
35
41
  INVALID_TOKEN
@@ -38,26 +44,8 @@ module Rack
38
44
 
39
45
  private
40
46
 
41
- def valid?(claims, token)
42
- !expired?(claims) && @certificate.valid?(token)
43
- end
44
-
45
- def decode_token(token)
46
- return {} if token.nil?
47
-
48
- begin
49
- JSON::JWT.decode(token, :skip_verification)
50
- rescue JSON::JWT::InvalidFormat
51
- {}
52
- end
53
- end
54
-
55
- def expired?(claims)
56
- Time.now.to_i > (claims['iat'] + claims['exp'])
57
- end
58
-
59
- def should_validate_token?(claims)
60
- claims['iss'] == @issuer
47
+ def should_validate_token?(auth_validator)
48
+ auth_validator.token_issuer_matches?
61
49
  end
62
50
  end
63
51
  end
@@ -0,0 +1,51 @@
1
+ require 'json/jwt'
2
+
3
+ module Rack
4
+ class PrxAuth
5
+ class AuthValidator
6
+
7
+ attr_reader :issuer, :claims, :token
8
+
9
+ def initialize(token, certificate, issuer)
10
+ @token = token
11
+ @certificate = certificate
12
+ @issuer = issuer
13
+ end
14
+
15
+ def valid?
16
+ valid_token_format? && !expired? && @certificate.valid?(token)
17
+ end
18
+
19
+ def claims
20
+ @claims ||= decode_token
21
+ end
22
+
23
+ def valid_token_format?
24
+ decode_token.present?
25
+ end
26
+
27
+ def decode_token
28
+ return {} if token.nil?
29
+
30
+ begin
31
+ JSON::JWT.decode(token, :skip_verification)
32
+ rescue JSON::JWT::InvalidFormat
33
+ {}
34
+ end
35
+ end
36
+
37
+ def expired?
38
+ now = Time.now.to_i - 30 # 30 second clock jitter allowance
39
+ if claims['iat'] <= claims['exp']
40
+ now > claims['exp']
41
+ else
42
+ now > (claims['iat'] + claims['exp'])
43
+ end
44
+ end
45
+
46
+ def token_issuer_matches?
47
+ claims['iss'] == @issuer
48
+ end
49
+ end
50
+ end
51
+ end
@@ -32,7 +32,11 @@ module Rack
32
32
  def globally_authorized?(namespace, scope=nil)
33
33
  authorized?(::PrxAuth::ResourceMap::WILDCARD_KEY, namespace, scope)
34
34
  end
35
-
35
+
36
+ def authorized_account_ids(scope)
37
+ resources(::PrxAuth::Rails.configuration.namespace, scope).map(&:to_i)
38
+ end
39
+
36
40
  private
37
41
 
38
42
  def unpack_aur(aur)
@@ -21,12 +21,12 @@ Gem::Specification.new do |spec|
21
21
  spec.required_ruby_version = '>= 2.3'
22
22
 
23
23
  spec.add_development_dependency 'bundler', '~> 2.0'
24
- spec.add_development_dependency 'rake', '~> 10.0'
24
+ spec.add_development_dependency 'rake', '~> 12.3.3'
25
25
  spec.add_development_dependency 'coveralls', '~> 0'
26
26
  spec.add_development_dependency 'guard'
27
27
  spec.add_development_dependency 'guard-minitest'
28
28
 
29
29
  spec.add_dependency 'rack', '>= 1.5.2'
30
30
  spec.add_dependency 'json', '>= 1.8.1'
31
- spec.add_dependency 'json-jwt', '~> 1.9.4'
31
+ spec.add_dependency 'json-jwt', '~> 1.12.0'
32
32
  end
@@ -169,4 +169,17 @@ describe PrxAuth::ResourceMap do
169
169
  assert map.as_json.has_key?('*')
170
170
  end
171
171
  end
172
+
173
+ describe '#[]' do
174
+ it 'automatically stringifies' do
175
+ refute_nil map[123]
176
+ end
177
+ end
178
+
179
+ describe '#[]=' do
180
+ it 'automatically stringifies' do
181
+ map[789] = PrxAuth::ScopeList.new("")
182
+ refute_nil map["789"]
183
+ end
184
+ end
172
185
  end
@@ -104,5 +104,26 @@ describe PrxAuth::ScopeList do
104
104
  sl = new_list('one') & nil
105
105
  assert !sl.contains?(:one)
106
106
  end
107
+
108
+ it 'works when either side has non-namespaced values correctly' do
109
+ sl = PrxAuth::ScopeList.new('foo:bar') & PrxAuth::ScopeList.new('bar')
110
+ assert sl.contains?(:foo, :bar)
111
+ refute sl.contains?(:bar)
112
+
113
+ sl = PrxAuth::ScopeList.new('bar') & PrxAuth::ScopeList.new('foo:bar')
114
+ assert sl.contains?(:foo, :bar)
115
+ refute sl.contains?(:bar)
116
+ end
117
+ end
118
+
119
+ describe '==' do
120
+
121
+ it 'is equal when they are functionally equal' do
122
+ assert_equal PrxAuth::ScopeList.new("foo ns:foo bar ns2:baz"), PrxAuth::ScopeList.new("ns2:baz bar foo")
123
+ end
124
+
125
+ it 'is not equal when they are not functionally equal' do
126
+ refute_equal PrxAuth::ScopeList.new("foo bar"), PrxAuth::ScopeList.new("foo:bar bar:foo")
127
+ end
107
128
  end
108
129
  end
@@ -0,0 +1,111 @@
1
+ require 'test_helper'
2
+
3
+ describe Rack::PrxAuth::AuthValidator do
4
+ let(:app) { Proc.new {|env| env } }
5
+ let(:auth_validator) { Rack::PrxAuth::AuthValidator.new(token, certificate, 'id.local.test') }
6
+
7
+ let(:token) { 'some.token.foo' }
8
+
9
+ let(:iat) { Time.now.to_i }
10
+ let(:exp) { 3600 }
11
+ let(:claims) { {'sub'=>3, 'exp'=>exp, 'iat'=>iat, 'token_type'=>'bearer', 'scope'=>nil, 'iss'=>'id.prx.org'} }
12
+ let(:certificate) { cert = Rack::PrxAuth::Certificate.new }
13
+
14
+ describe '#token_issuer_matches' do
15
+ it 'false if the token is from another issuer' do
16
+ auth_validator.stub(:claims, claims) do
17
+ refute auth_validator.token_issuer_matches?
18
+ end
19
+ end
20
+
21
+ it 'is false if the issuer in the validator does not match' do
22
+ auth_validator.stub(:issuer, 'id.foo.com') do
23
+ refute auth_validator.token_issuer_matches?
24
+ end
25
+ end
26
+ end
27
+
28
+ describe '#valid?' do
29
+ it 'is false if token is invalid' do
30
+ auth_validator.stub(:claims, claims) do
31
+ refute auth_validator.valid?
32
+ end
33
+ end
34
+
35
+ it 'is false if the token is nil' do
36
+ certificate.stub(:valid?, true) do
37
+ auth_validator.stub(:token, nil) do
38
+ refute auth_validator.valid?
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ describe '#expired?' do
45
+
46
+ def expired?(claims)
47
+ auth_validator.stub(:claims, claims) do
48
+ auth_validator.expired?
49
+ end
50
+ end
51
+
52
+ describe 'with a malformed exp' do
53
+ let(:iat) { Time.now.to_i }
54
+ let(:exp) { 3600 }
55
+
56
+ it 'is expired if iat + exp are in the past' do
57
+ claims['iat'] -= 3631
58
+
59
+ assert expired?(claims)
60
+ end
61
+
62
+ it 'is not expired if iat + exp are in the future' do
63
+ claims['iat'] = Time.now.to_i - 3599
64
+
65
+ refute expired?(claims)
66
+ end
67
+
68
+ it 'allows a 30s clock jitter' do
69
+ claims['iat'] = Time.now.to_i - 3629
70
+
71
+ refute expired?(claims)
72
+ end
73
+ end
74
+
75
+ describe 'with a corrected exp' do
76
+ let(:iat) { Time.now.to_i - 3600 }
77
+ let(:exp) { Time.now.to_i + 1 }
78
+
79
+ it 'is not expired if exp is in the future' do
80
+ refute expired?(claims)
81
+ end
82
+
83
+ it 'is expired if exp is in the past (with 30s jitter grace)' do
84
+ claims['exp'] = Time.now.to_i - 31
85
+ assert expired?(claims)
86
+ claims['exp'] = Time.now.to_i - 29
87
+ refute expired?(claims)
88
+ end
89
+ end
90
+ end
91
+
92
+ describe '#decode_token' do
93
+ it 'should return an empty result for a nil token' do
94
+ auth_validator.stub(:token, nil) do
95
+ assert auth_validator.decode_token == {}
96
+ end
97
+ end
98
+
99
+ it 'should return an empty result for an empty token' do
100
+ auth_validator.stub(:token, '') do
101
+ assert auth_validator.decode_token == {}
102
+ end
103
+ end
104
+
105
+ it 'should return an empty result for a malformed token' do
106
+ auth_validator.stub(:token, token) do
107
+ assert auth_validator.decode_token == {}
108
+ end
109
+ end
110
+ end
111
+ end
@@ -5,7 +5,9 @@ describe Rack::PrxAuth do
5
5
  let(:prxauth) { Rack::PrxAuth.new(app) }
6
6
  let(:fake_token) { 'afawefawefawefawegstgnsrtiohnlijblublwjnvrtoign'}
7
7
  let(:env) { {'HTTP_AUTHORIZATION' => 'Bearer ' + fake_token } }
8
- let(:claims) { {'sub'=>3, 'exp'=>3600, 'iat'=>Time.now.to_i, 'token_type'=>'bearer', 'scope'=>nil, 'iss'=>'id.prx.org'} }
8
+ let(:iat) { Time.now.to_i }
9
+ let(:exp) { 3600 }
10
+ let(:claims) { {'sub'=>3, 'exp'=>exp, 'iat'=>iat, 'token_type'=>'bearer', 'scope'=>nil, 'iss'=>'id.prx.org'} }
9
11
 
10
12
  describe '#call' do
11
13
  it 'does nothing if there is no authorization header' do
@@ -32,24 +34,34 @@ describe Rack::PrxAuth do
32
34
  end
33
35
 
34
36
  it 'returns 401 if verification fails' do
37
+ auth_validator = prxauth.build_auth_validator('sometoken')
38
+
35
39
  JSON::JWT.stub(:decode, claims) do
36
- prxauth.stub(:valid?, false) do
37
- assert prxauth.call(env) == Rack::PrxAuth::INVALID_TOKEN
40
+ prxauth.stub(:build_auth_validator, auth_validator) do
41
+ auth_validator.stub(:valid?, false) do
42
+ assert prxauth.call(env) == Rack::PrxAuth::INVALID_TOKEN
43
+ end
38
44
  end
39
45
  end
40
46
  end
41
47
 
42
48
  it 'returns 401 if access token has expired' do
49
+ auth_validator = prxauth.build_auth_validator('sometoken')
50
+
43
51
  JSON::JWT.stub(:decode, claims) do
44
- prxauth.stub(:expired?, true) do
45
- assert prxauth.call(env) == Rack::PrxAuth::INVALID_TOKEN
52
+ prxauth.stub(:build_auth_validator, auth_validator) do
53
+ auth_validator.stub(:expired?, true) do
54
+ assert prxauth.call(env) == Rack::PrxAuth::INVALID_TOKEN
55
+ end
46
56
  end
47
57
  end
48
58
  end
49
59
 
50
60
  it 'attaches claims to request params if verification passes' do
51
- prxauth.stub(:decode_token, claims) do
52
- prxauth.stub(:valid?, true) do
61
+ auth_validator = prxauth.build_auth_validator('sometoken')
62
+
63
+ JSON::JWT.stub(:decode, claims) do
64
+ prxauth.stub(:build_auth_validator, auth_validator) do
53
65
  prxauth.call(env)['prx.auth'].tap do |token|
54
66
  assert token.instance_of? Rack::PrxAuth::TokenData
55
67
  assert token.user_id == claims['sub']
@@ -59,18 +71,6 @@ describe Rack::PrxAuth do
59
71
  end
60
72
  end
61
73
 
62
- describe '#token_expired?' do
63
- it 'returns true if token is expired' do
64
- claims['iat'] = Time.now.to_i - 4000
65
-
66
- assert prxauth.send(:expired?, claims) == true
67
- end
68
-
69
- it 'returns false if it is valid' do
70
- assert prxauth.send(:expired?, claims) == false
71
- end
72
- end
73
-
74
74
  describe 'initialize' do
75
75
  it 'takes a certificate location as an option' do
76
76
  loc = nil
@@ -80,18 +80,4 @@ describe Rack::PrxAuth do
80
80
  end
81
81
  end
82
82
  end
83
-
84
- describe '#decode_token' do
85
- it 'should return an empty result for a nil token' do
86
- assert prxauth.send(:decode_token, nil) == {}
87
- end
88
-
89
- it 'should return an empty result for an empty token' do
90
- assert prxauth.send(:decode_token, {}) == {}
91
- end
92
-
93
- it 'should return an empty result for a malformed token' do
94
- assert prxauth.send(:decode_token, 'asdfsadfsad') == {}
95
- end
96
- end
97
83
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prx_auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eve Asher
8
8
  - Chris Rhoden
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-08-11 00:00:00.000000000 Z
12
+ date: 2021-01-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -31,14 +31,14 @@ dependencies:
31
31
  requirements:
32
32
  - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: '10.0'
34
+ version: 12.3.3
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - "~>"
40
40
  - !ruby/object:Gem::Version
41
- version: '10.0'
41
+ version: 12.3.3
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: coveralls
44
44
  requirement: !ruby/object:Gem::Requirement
@@ -115,14 +115,14 @@ dependencies:
115
115
  requirements:
116
116
  - - "~>"
117
117
  - !ruby/object:Gem::Version
118
- version: 1.9.4
118
+ version: 1.12.0
119
119
  type: :runtime
120
120
  prerelease: false
121
121
  version_requirements: !ruby/object:Gem::Requirement
122
122
  requirements:
123
123
  - - "~>"
124
124
  - !ruby/object:Gem::Version
125
- version: 1.9.4
125
+ version: 1.12.0
126
126
  description: Specific to PRX. Will ignore tokens that were not issued by PRX.
127
127
  email:
128
128
  - eve@prx.org
@@ -144,11 +144,13 @@ files:
144
144
  - lib/prx_auth/scope_list.rb
145
145
  - lib/prx_auth/version.rb
146
146
  - lib/rack/prx_auth.rb
147
+ - lib/rack/prx_auth/auth_validator.rb
147
148
  - lib/rack/prx_auth/certificate.rb
148
149
  - lib/rack/prx_auth/token_data.rb
149
150
  - prx_auth.gemspec
150
151
  - test/prx_auth/resource_map_test.rb
151
152
  - test/prx_auth/scope_list_test.rb
153
+ - test/rack/prx_auth/auth_validator_test.rb
152
154
  - test/rack/prx_auth/certificate_test.rb
153
155
  - test/rack/prx_auth/token_data_test.rb
154
156
  - test/rack/prx_auth_test.rb
@@ -157,7 +159,7 @@ homepage: https://github.com/PRX/prx_auth
157
159
  licenses:
158
160
  - MIT
159
161
  metadata: {}
160
- post_install_message:
162
+ post_install_message:
161
163
  rdoc_options: []
162
164
  require_paths:
163
165
  - lib
@@ -172,14 +174,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
172
174
  - !ruby/object:Gem::Version
173
175
  version: '0'
174
176
  requirements: []
175
- rubygems_version: 3.0.1
176
- signing_key:
177
+ rubygems_version: 3.0.3
178
+ signing_key:
177
179
  specification_version: 4
178
180
  summary: Utilites for parsing PRX JWTs and Rack middleware that verifies and attaches
179
181
  the token's claims to env.
180
182
  test_files:
181
183
  - test/prx_auth/resource_map_test.rb
182
184
  - test/prx_auth/scope_list_test.rb
185
+ - test/rack/prx_auth/auth_validator_test.rb
183
186
  - test/rack/prx_auth/certificate_test.rb
184
187
  - test/rack/prx_auth/token_data_test.rb
185
188
  - test/rack/prx_auth_test.rb