prx_auth 1.3.0 → 1.7.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 +4 -4
- data/lib/prx_auth/scope_list.rb +1 -1
- data/lib/prx_auth/version.rb +1 -1
- data/lib/rack/prx_auth.rb +12 -24
- data/lib/rack/prx_auth/auth_validator.rb +58 -0
- data/lib/rack/prx_auth/certificate.rb +1 -0
- data/lib/rack/prx_auth/token_data.rb +5 -1
- data/prx_auth.gemspec +2 -2
- data/test/prx_auth/scope_list_test.rb +10 -0
- data/test/rack/prx_auth/auth_validator_test.rb +141 -0
- data/test/rack/prx_auth_test.rb +19 -33
- metadata +10 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e89ea4feff47dadbac479d38e5a35fa04be2e148cb10ebe4b41d800e2df48c3
|
4
|
+
data.tar.gz: b3ae9ed7381ff2765abc01c4126c3b7ede3db2f06a73cbd9da6918c9ac3a41ab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 17ffcb56a69a9c5d674f418967a56405a9f44dac40a0359d9bac42bd93421e7273af08632b311718ca10844ac3a37347d1b8753f1cac7f661b62d75752d25875
|
7
|
+
data.tar.gz: bb3d2a19cabf47a5f6d3d62edebf9bdb0ac368521b6c6128c1dc73edb00f2a2d353c8e0a17a46c52334e651a3c2926cfaf9215053d4f260d258a75793ee13d14
|
data/lib/prx_auth/scope_list.rb
CHANGED
data/lib/prx_auth/version.rb
CHANGED
data/lib/rack/prx_auth.rb
CHANGED
@@ -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
|
-
|
33
|
+
auth_validator = build_auth_validator(token)
|
34
|
+
|
35
|
+
return @app.call(env) unless should_validate_token?(auth_validator)
|
30
36
|
|
31
|
-
if valid?
|
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
|
42
|
-
|
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,58 @@
|
|
1
|
+
require 'json/jwt'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
class PrxAuth
|
5
|
+
class AuthValidator
|
6
|
+
|
7
|
+
attr_reader :issuer, :token
|
8
|
+
|
9
|
+
def initialize(token, certificate = nil, issuer = nil)
|
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
|
+
(time_to_live + 30) <= 0 # 30 second clock jitter allowance
|
39
|
+
end
|
40
|
+
|
41
|
+
def time_to_live
|
42
|
+
now = Time.now.to_i
|
43
|
+
if claims['exp'].nil?
|
44
|
+
0
|
45
|
+
elsif claims['iat'].nil? || claims['iat'] <= claims['exp']
|
46
|
+
claims['exp'] - now
|
47
|
+
else
|
48
|
+
# malformed - exp is a num-seconds offset from issued-at-time
|
49
|
+
(claims['iat'] + claims['exp']) - now
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def token_issuer_matches?
|
54
|
+
claims['iss'] == @issuer
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
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)
|
data/prx_auth.gemspec
CHANGED
@@ -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', '~>
|
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.
|
31
|
+
spec.add_dependency 'json-jwt', '~> 1.12.0'
|
32
32
|
end
|
@@ -104,6 +104,16 @@ 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
|
107
117
|
end
|
108
118
|
|
109
119
|
describe '==' do
|
@@ -0,0 +1,141 @@
|
|
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) { 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 '#time_to_live' do
|
93
|
+
def time_to_live(claims)
|
94
|
+
auth_validator.stub(:claims, claims) do
|
95
|
+
auth_validator.time_to_live
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'returns the ttl without any clock jitter correction' do
|
100
|
+
claims['exp'] = Time.now.to_i + 999
|
101
|
+
assert_equal time_to_live(claims), 999
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'handles missing exp' do
|
105
|
+
claims['exp'] = nil
|
106
|
+
assert_equal time_to_live(claims), 0
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'handles missing iat' do
|
110
|
+
claims['iat'] = nil
|
111
|
+
claims['exp'] = Time.now.to_i + 999
|
112
|
+
assert_equal time_to_live(claims), 999
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'handles malformed exp' do
|
116
|
+
claims['iat'] = Time.now.to_i
|
117
|
+
claims['exp'] = 999
|
118
|
+
assert_equal time_to_live(claims), 999
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe '#decode_token' do
|
123
|
+
it 'should return an empty result for a nil token' do
|
124
|
+
auth_validator.stub(:token, nil) do
|
125
|
+
assert auth_validator.decode_token == {}
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should return an empty result for an empty token' do
|
130
|
+
auth_validator.stub(:token, '') do
|
131
|
+
assert auth_validator.decode_token == {}
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'should return an empty result for a malformed token' do
|
136
|
+
auth_validator.stub(:token, token) do
|
137
|
+
assert auth_validator.decode_token == {}
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
data/test/rack/prx_auth_test.rb
CHANGED
@@ -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(:
|
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(:
|
37
|
-
|
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(:
|
45
|
-
|
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.
|
52
|
-
|
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,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prx_auth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eve Asher
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2021-03-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:
|
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:
|
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.
|
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.
|
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
|
@@ -172,7 +174,7 @@ 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.
|
177
|
+
rubygems_version: 3.0.3
|
176
178
|
signing_key:
|
177
179
|
specification_version: 4
|
178
180
|
summary: Utilites for parsing PRX JWTs and Rack middleware that verifies and attaches
|
@@ -180,6 +182,7 @@ summary: Utilites for parsing PRX JWTs and Rack middleware that verifies and att
|
|
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
|