fridge 0.3.1 → 0.4.4
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 +5 -5
- data/.github/CODEOWNERS +1 -0
- data/.travis.yml +3 -2
- data/Gemfile +3 -0
- data/README.md +1 -3
- data/fridge.gemspec +6 -5
- data/lib/fridge.rb +4 -1
- data/lib/fridge/access_token.rb +23 -14
- data/lib/fridge/expired_token.rb +4 -0
- data/lib/fridge/rails_helpers.rb +21 -8
- data/lib/fridge/version.rb +1 -1
- data/spec/fixtures/app.rb +2 -5
- data/spec/fridge/access_token_spec.rb +31 -6
- data/spec/fridge/rails_helpers_spec.rb +180 -159
- data/spec/spec_helper.rb +11 -3
- metadata +29 -30
- data/spec/fixtures/controller.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f2d340550f97b33c430967cef5b8de4a59b73acfdd5a1ce62ad3ee7d17a6f8c9
|
4
|
+
data.tar.gz: 06a758734a6b6e668043c3bffe2cf350495325dfdab4f73948e2788f97d5c89d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d8b53167a69aaf39d60b4abbe6ad347968efddc1b2333dc12136b730600d65ab0c72fc8c7416d190b33fc55ce3571d8b98cbf1322c7a0eddd46c46517114cc0c
|
7
|
+
data.tar.gz: 0632f0de72e4654663256000e201568745697a05170e49191d31598a9a5bd2f6158871379253bee1302d3b10ebf76c5a6b84d2baae803cf8fd935bb4324a47b3
|
data/.github/CODEOWNERS
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
* @dawenster
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -80,6 +80,4 @@ store_session_cookie(access_token)
|
|
80
80
|
|
81
81
|
MIT License, see [LICENSE](LICENSE.md) for details.
|
82
82
|
|
83
|
-
Copyright (c)
|
84
|
-
|
85
|
-
[<img src="https://s.gravatar.com/avatar/f7790b867ae619ae0496460aa28c5861?s=60" style="border-radius: 50%;" alt="@fancyremarker" />](https://github.com/fancyremarker)
|
83
|
+
Copyright (c) 2019 [Aptible](https://www.aptible.com) and contributors.
|
data/fridge.gemspec
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
|
2
3
|
lib = File.expand_path('../lib', __FILE__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
|
@@ -20,13 +21,13 @@ Gem::Specification.new do |spec|
|
|
20
21
|
spec.require_paths = ['lib']
|
21
22
|
|
22
23
|
spec.add_dependency 'gem_config'
|
23
|
-
spec.add_dependency 'jwt', '~>
|
24
|
+
spec.add_dependency 'jwt', '~> 1.5.6'
|
24
25
|
|
25
|
-
spec.add_development_dependency 'bundler', '~> 1.5'
|
26
26
|
spec.add_development_dependency 'aptible-tasks'
|
27
|
-
spec.add_development_dependency '
|
27
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
28
|
+
spec.add_development_dependency 'pry'
|
28
29
|
spec.add_development_dependency 'rails'
|
29
|
-
spec.add_development_dependency '
|
30
|
+
spec.add_development_dependency 'rake'
|
31
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
30
32
|
spec.add_development_dependency 'rspec-rails'
|
31
|
-
spec.add_development_dependency 'pry'
|
32
33
|
end
|
data/lib/fridge.rb
CHANGED
@@ -4,6 +4,7 @@ require 'fridge/version'
|
|
4
4
|
require 'fridge/access_token'
|
5
5
|
require 'fridge/serialization_error'
|
6
6
|
require 'fridge/invalid_token'
|
7
|
+
require 'fridge/expired_token'
|
7
8
|
|
8
9
|
require 'fridge/railtie' if defined?(Rails)
|
9
10
|
|
@@ -14,7 +15,9 @@ module Fridge
|
|
14
15
|
has :private_key, classes: [String]
|
15
16
|
has :public_key, classes: [String]
|
16
17
|
|
17
|
-
|
18
|
+
# rubocop:disable Style/PercentLiteralDelimiters
|
19
|
+
has :signing_algorithm, values: %w[RS512 RS256], default: 'RS512'
|
20
|
+
# rubocop:enable Style/PercentLiteralDelimiters
|
18
21
|
|
19
22
|
# A validator must raise an exception or return a false value for an
|
20
23
|
# invalid token
|
data/lib/fridge/access_token.rb
CHANGED
@@ -5,7 +5,6 @@ module Fridge
|
|
5
5
|
attr_accessor :id, :issuer, :subject, :scope, :expires_at, :actor,
|
6
6
|
:jwt, :attributes
|
7
7
|
|
8
|
-
# rubocop:disable MethodLength
|
9
8
|
def initialize(jwt_or_options = nil)
|
10
9
|
options = case jwt_or_options
|
11
10
|
when String
|
@@ -21,7 +20,6 @@ module Fridge
|
|
21
20
|
end
|
22
21
|
self.attributes = options
|
23
22
|
end
|
24
|
-
# rubocop:enable MethodLength
|
25
23
|
|
26
24
|
def to_s
|
27
25
|
serialize
|
@@ -29,6 +27,7 @@ module Fridge
|
|
29
27
|
|
30
28
|
def serialize
|
31
29
|
return jwt if jwt
|
30
|
+
|
32
31
|
validate_parameters!
|
33
32
|
validate_private_key!
|
34
33
|
encode_and_sign
|
@@ -42,18 +41,18 @@ module Fridge
|
|
42
41
|
h.merge!(attributes)
|
43
42
|
h = encode_for_jwt(h)
|
44
43
|
JWT.encode(h, private_key, algorithm)
|
45
|
-
rescue
|
44
|
+
rescue StandardError
|
46
45
|
raise SerializationError, 'Invalid private key or signing algorithm'
|
47
46
|
end
|
48
47
|
|
49
|
-
# rubocop:disable MethodLength
|
50
48
|
def decode_and_verify(jwt)
|
51
|
-
|
52
|
-
decode_from_jwt(
|
53
|
-
rescue JWT::
|
54
|
-
raise
|
49
|
+
payload, _header = JWT.decode(jwt, public_key, true, algorithm: algorithm)
|
50
|
+
decode_from_jwt(payload)
|
51
|
+
rescue JWT::ExpiredSignature => e
|
52
|
+
raise ExpiredToken, e.message
|
53
|
+
rescue JWT::DecodeError => e
|
54
|
+
raise InvalidToken, e.message
|
55
55
|
end
|
56
|
-
# rubocop:enable MethodLength
|
57
56
|
|
58
57
|
def downgrade
|
59
58
|
self.scope = 'read'
|
@@ -69,8 +68,9 @@ module Fridge
|
|
69
68
|
|
70
69
|
def private_key
|
71
70
|
return unless config.private_key
|
71
|
+
|
72
72
|
@private_key ||= OpenSSL::PKey::RSA.new(config.private_key)
|
73
|
-
rescue
|
73
|
+
rescue StandardError
|
74
74
|
nil
|
75
75
|
end
|
76
76
|
|
@@ -80,7 +80,7 @@ module Fridge
|
|
80
80
|
elsif config.public_key
|
81
81
|
@public_key ||= OpenSSL::PKey::RSA.new(config.public_key)
|
82
82
|
end
|
83
|
-
rescue
|
83
|
+
rescue StandardError
|
84
84
|
nil
|
85
85
|
end
|
86
86
|
|
@@ -102,19 +102,24 @@ module Fridge
|
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
105
|
+
def respond_to_missing?(method, include_private = false)
|
106
|
+
attributes.key?(method) || super
|
107
|
+
end
|
108
|
+
|
105
109
|
def validate_parameters!
|
106
110
|
[:subject, :expires_at].each do |attribute|
|
107
111
|
next if send(attribute)
|
108
|
-
|
112
|
+
|
113
|
+
raise SerializationError, "Missing attribute: #{attribute}"
|
109
114
|
end
|
110
115
|
end
|
111
116
|
|
112
117
|
def validate_private_key!
|
113
|
-
|
118
|
+
raise SerializationError, 'No private key configured' unless private_key
|
114
119
|
end
|
115
120
|
|
116
121
|
def validate_public_key!
|
117
|
-
|
122
|
+
raise SerializationError, 'No public key configured' unless public_key
|
118
123
|
end
|
119
124
|
|
120
125
|
# Internally, we use "subject" to refer to "sub", and so on. We also
|
@@ -122,6 +127,8 @@ module Fridge
|
|
122
127
|
# mapping from Fridge to JWT and vice-versa.
|
123
128
|
|
124
129
|
def encode_for_jwt(hash)
|
130
|
+
hash = hash.dup
|
131
|
+
|
125
132
|
out = {
|
126
133
|
id: hash.delete(:id),
|
127
134
|
iss: hash.delete(:issuer),
|
@@ -143,6 +150,8 @@ module Fridge
|
|
143
150
|
end
|
144
151
|
|
145
152
|
def decode_from_jwt(hash)
|
153
|
+
hash = hash.dup
|
154
|
+
|
146
155
|
out = {
|
147
156
|
id: hash.delete('id'),
|
148
157
|
issuer: hash.delete('iss'),
|
data/lib/fridge/rails_helpers.rb
CHANGED
@@ -21,6 +21,7 @@ module Fridge
|
|
21
21
|
|
22
22
|
def current_token
|
23
23
|
return unless bearer_token
|
24
|
+
|
24
25
|
@current_token ||= AccessToken.new(bearer_token).tap do |token|
|
25
26
|
validate_token!(token)
|
26
27
|
end
|
@@ -41,10 +42,11 @@ module Fridge
|
|
41
42
|
|
42
43
|
def session_token
|
43
44
|
return unless session_cookie
|
45
|
+
|
44
46
|
@session_token ||= AccessToken.new(session_cookie).tap do |token|
|
45
47
|
validate_token!(token).downgrade
|
46
48
|
end
|
47
|
-
rescue
|
49
|
+
rescue StandardError
|
48
50
|
clear_session_cookie
|
49
51
|
end
|
50
52
|
|
@@ -52,7 +54,7 @@ module Fridge
|
|
52
54
|
def validate_token(access_token)
|
53
55
|
validator = Fridge.configuration.validator
|
54
56
|
validator.call(access_token) && access_token
|
55
|
-
rescue
|
57
|
+
rescue StandardError
|
56
58
|
false
|
57
59
|
end
|
58
60
|
|
@@ -62,7 +64,7 @@ module Fridge
|
|
62
64
|
if validator.call(access_token)
|
63
65
|
access_token
|
64
66
|
else
|
65
|
-
|
67
|
+
raise InvalidToken, 'Rejected by validator'
|
66
68
|
end
|
67
69
|
end
|
68
70
|
|
@@ -86,12 +88,12 @@ module Fridge
|
|
86
88
|
end
|
87
89
|
|
88
90
|
def clear_session_cookie
|
89
|
-
cookies.delete fridge_cookie_name, domain:
|
91
|
+
cookies.delete fridge_cookie_name, domain: auth_domain
|
90
92
|
nil
|
91
93
|
end
|
92
94
|
|
93
95
|
def write_shared_cookie(name, value, options = {})
|
94
|
-
|
96
|
+
raise 'Can only write string cookie values' unless value.is_a?(String)
|
95
97
|
|
96
98
|
cookies[name] = {
|
97
99
|
value: value,
|
@@ -103,9 +105,10 @@ module Fridge
|
|
103
105
|
cookies[name]
|
104
106
|
end
|
105
107
|
|
106
|
-
def fetch_shared_cookie(name
|
108
|
+
def fetch_shared_cookie(name)
|
107
109
|
return read_shared_cookie(name) if read_shared_cookie(name)
|
108
|
-
|
110
|
+
|
111
|
+
write_shared_cookie(yield)
|
109
112
|
end
|
110
113
|
|
111
114
|
def delete_shared_cookie(name)
|
@@ -118,8 +121,18 @@ module Fridge
|
|
118
121
|
|
119
122
|
def fridge_cookie_options
|
120
123
|
secure = !Rails.env.development?
|
121
|
-
options = { domain:
|
124
|
+
options = { domain: auth_domain, secure: secure, httponly: true }
|
122
125
|
options.merge(Fridge.configuration.cookie_options)
|
123
126
|
end
|
127
|
+
|
128
|
+
def auth_domain
|
129
|
+
domain = URI.parse(Aptible::Auth.configuration.root_url).host
|
130
|
+
|
131
|
+
# On localhost we fall back to the default setting b/c browsers won't set
|
132
|
+
# cookies if localhost is named
|
133
|
+
domain == 'localhost' ? :all : domain
|
134
|
+
rescue StandardError
|
135
|
+
'auth.aptible.com'
|
136
|
+
end
|
124
137
|
end
|
125
138
|
end
|
data/lib/fridge/version.rb
CHANGED
data/spec/fixtures/app.rb
CHANGED
@@ -1,7 +1,3 @@
|
|
1
|
-
require 'active_support/all'
|
2
|
-
require 'action_controller'
|
3
|
-
require 'action_dispatch'
|
4
|
-
|
5
1
|
module Rails
|
6
2
|
class App
|
7
3
|
def env_config
|
@@ -10,6 +6,7 @@ module Rails
|
|
10
6
|
|
11
7
|
def routes
|
12
8
|
return @routes if defined?(@routes)
|
9
|
+
|
13
10
|
@routes = ActionDispatch::Routing::RouteSet.new
|
14
11
|
@routes.draw do
|
15
12
|
resources :posts
|
@@ -19,6 +16,6 @@ module Rails
|
|
19
16
|
end
|
20
17
|
|
21
18
|
def self.application
|
22
|
-
@
|
19
|
+
@application ||= App.new
|
23
20
|
end
|
24
21
|
end
|
@@ -14,13 +14,17 @@ describe Fridge::AccessToken do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'should accept a JWT' do
|
17
|
-
jwt = JWT.encode(
|
17
|
+
jwt = JWT.encode(
|
18
|
+
{ id: 'foobar', exp: Time.now.to_i + 10 },
|
19
|
+
private_key, 'RS512'
|
20
|
+
)
|
18
21
|
access_token = described_class.new(jwt)
|
19
22
|
expect(access_token.id).to eq 'foobar'
|
20
23
|
end
|
21
24
|
|
22
25
|
it 'should raise an error on an invalid JWT' do
|
23
|
-
expect { described_class.new('foobar') }
|
26
|
+
expect { described_class.new('foobar') }
|
27
|
+
.to raise_error Fridge::InvalidToken
|
24
28
|
end
|
25
29
|
|
26
30
|
it 'should raise an error on an incorrectly signed JWT' do
|
@@ -28,11 +32,19 @@ describe Fridge::AccessToken do
|
|
28
32
|
expect { described_class.new(jwt) }.to raise_error Fridge::InvalidToken
|
29
33
|
end
|
30
34
|
|
35
|
+
it 'should raise an error on an expired JWT' do
|
36
|
+
jwt = JWT.encode(
|
37
|
+
{ id: 'foobar', exp: Time.now.to_i - 10 },
|
38
|
+
private_key, 'RS512'
|
39
|
+
)
|
40
|
+
expect { described_class.new(jwt) }.to raise_error(Fridge::ExpiredToken)
|
41
|
+
end
|
42
|
+
|
31
43
|
# http://bit.ly/jwt-none-vulnerability
|
32
44
|
it 'should raise an error with { "alg": "none" }' do
|
33
45
|
jwt = "#{Base64.encode64({ typ: 'JWT', alg: 'none' }.to_json).chomp}." \
|
34
46
|
"#{Base64.encode64({ id: 'foobar' }.to_json).chomp}"
|
35
|
-
expect(JWT.decode(jwt, nil, false)).to eq('id' => 'foobar')
|
47
|
+
expect(JWT.decode(jwt, nil, false)[0]).to eq('id' => 'foobar')
|
36
48
|
expect { described_class.new(jwt) }.to raise_error Fridge::InvalidToken
|
37
49
|
end
|
38
50
|
end
|
@@ -81,8 +93,8 @@ describe Fridge::AccessToken do
|
|
81
93
|
end
|
82
94
|
|
83
95
|
it 'should represent :exp in seconds since the epoch' do
|
84
|
-
hash = JWT.decode(subject.serialize, public_key)
|
85
|
-
expect(hash['exp']).to be_a
|
96
|
+
hash, = JWT.decode(subject.serialize, public_key)
|
97
|
+
expect(hash['exp']).to be_a Integer
|
86
98
|
end
|
87
99
|
|
88
100
|
it 'should be deterministic' do
|
@@ -102,6 +114,8 @@ describe Fridge::AccessToken do
|
|
102
114
|
|
103
115
|
expect(copy.attributes[:foo]).to eq 'bar'
|
104
116
|
expect(copy.foo).to eq 'bar'
|
117
|
+
expect(copy.respond_to?(:foo)).to be_truthy
|
118
|
+
expect(copy.respond_to?(:bar)).to be_falsey
|
105
119
|
end
|
106
120
|
|
107
121
|
it 'should raise an error if required attributes are missing' do
|
@@ -119,13 +133,24 @@ describe Fridge::AccessToken do
|
|
119
133
|
# test that, although eventually we'll want to see symbols back.
|
120
134
|
actor_s = { 'sub' => 'foo', 'username' => 'test',
|
121
135
|
'act' => { 'sub' => 'bar' } }
|
122
|
-
hash = JWT.decode(subject.serialize, public_key)
|
136
|
+
hash, = JWT.decode(subject.serialize, public_key)
|
123
137
|
expect(hash['act']).to eq(actor_s)
|
124
138
|
|
125
139
|
# Now, check that we properly get symbols back
|
126
140
|
new = described_class.new(subject.serialize)
|
127
141
|
expect(new.actor).to eq(actor)
|
128
142
|
end
|
143
|
+
|
144
|
+
it 'should be idempotent' do
|
145
|
+
subject = described_class.new(options)
|
146
|
+
expect(subject.serialize).to eq(subject.serialize)
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'should be idempotent with an actor' do
|
150
|
+
actor = { subject: 'foo', username: 'test', actor: { subject: 'bar' } }
|
151
|
+
subject = described_class.new(options.merge(actor: actor))
|
152
|
+
expect(subject.serialize).to eq(subject.serialize)
|
153
|
+
end
|
129
154
|
end
|
130
155
|
|
131
156
|
describe '#expired?' do
|
@@ -1,218 +1,239 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'fixtures/app'
|
3
|
-
require 'fixtures/controller'
|
4
|
-
require 'rspec/rails'
|
5
3
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
4
|
+
describe Fridge::RailsHelpers do
|
5
|
+
include RSpec::Rails::ControllerExampleGroup
|
6
|
+
|
7
|
+
controller(ActionController::Base) { include Fridge::RailsHelpers }
|
8
|
+
|
9
|
+
let(:organization_url) do
|
10
|
+
"https://auth.aptible.com/users/#{SecureRandom.uuid}"
|
11
|
+
end
|
12
|
+
let(:private_key) { OpenSSL::PKey::RSA.new(1024) }
|
13
|
+
let(:public_key) { OpenSSL::PKey::RSA.new(private_key.public_key) }
|
14
|
+
|
15
|
+
let(:options) do
|
16
|
+
{
|
17
|
+
subject: "https://auth.aptible.com/users/#{SecureRandom.uuid}",
|
18
|
+
expires_at: Time.now + 3600
|
19
|
+
}
|
20
|
+
end
|
21
|
+
let(:access_token) { Fridge::AccessToken.new(options) }
|
22
|
+
|
23
|
+
let(:cookies) { controller.send(:cookies) }
|
24
|
+
|
25
|
+
before { Fridge.configuration.private_key = private_key.to_s }
|
26
|
+
before { Fridge.configuration.public_key = public_key.to_s }
|
27
|
+
|
28
|
+
describe '#bearer_token' do
|
29
|
+
it 'returns the bearer token from the Authorization: header' do
|
30
|
+
request.env['HTTP_AUTHORIZATION'] = 'Bearer foobar'
|
31
|
+
expect(controller.bearer_token).to eq 'foobar'
|
11
32
|
end
|
12
|
-
let(:private_key) { OpenSSL::PKey::RSA.new(1024) }
|
13
|
-
let(:public_key) { OpenSSL::PKey::RSA.new(private_key.public_key) }
|
14
33
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
expires_at: Time.now + 3600
|
19
|
-
}
|
34
|
+
it 'returns nil in the absence of an Authorization: header' do
|
35
|
+
request.env['HTTP_AUTHORIZATION'] = nil
|
36
|
+
expect(controller.bearer_token).to be_nil
|
20
37
|
end
|
21
|
-
|
38
|
+
end
|
22
39
|
|
23
|
-
|
40
|
+
describe '#token_subject' do
|
41
|
+
it 'returns the subject encoded in the token' do
|
42
|
+
controller.stub(:current_token) { access_token }
|
43
|
+
expect(controller.token_subject).to eq access_token.subject
|
44
|
+
end
|
24
45
|
|
25
|
-
|
26
|
-
|
46
|
+
it 'returns nil if no token is present' do
|
47
|
+
controller.stub(:current_token) { nil }
|
48
|
+
expect(controller.token_subject).to be_nil
|
49
|
+
end
|
50
|
+
end
|
27
51
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
52
|
+
describe '#token_scope' do
|
53
|
+
it 'returns the scope encoded in the token' do
|
54
|
+
controller.stub(:current_token) { access_token }
|
55
|
+
expect(controller.token_scope).to eq access_token.scope
|
56
|
+
end
|
33
57
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
58
|
+
it 'returns nil if no token is present' do
|
59
|
+
controller.stub(:current_token) { nil }
|
60
|
+
expect(controller.token_scope).to be_nil
|
38
61
|
end
|
62
|
+
end
|
39
63
|
|
40
|
-
|
41
|
-
|
42
|
-
controller.stub(:current_token) { access_token }
|
43
|
-
expect(controller.token_subject).to eq access_token.subject
|
44
|
-
end
|
64
|
+
describe '#current_token' do
|
65
|
+
before { controller.stub(:bearer_token) { access_token.serialize } }
|
45
66
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
67
|
+
it 'should raise an error if the token is not a valid JWT' do
|
68
|
+
controller.stub(:bearer_token) { 'foobar' }
|
69
|
+
expect { controller.current_token }.to raise_error Fridge::InvalidToken
|
50
70
|
end
|
51
71
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
expect(controller.token_scope).to eq access_token.scope
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'returns nil if no token is present' do
|
59
|
-
controller.stub(:current_token) { nil }
|
60
|
-
expect(controller.token_scope).to be_nil
|
61
|
-
end
|
72
|
+
it 'should raise an error if the token has expired' do
|
73
|
+
access_token.expires_at = Time.now - 3600
|
74
|
+
expect { controller.current_token }.to raise_error Fridge::InvalidToken
|
62
75
|
end
|
63
76
|
|
64
|
-
|
65
|
-
|
77
|
+
it 'should raise an error if custom validation fails' do
|
78
|
+
Fridge.configuration.validator = ->(_) { false }
|
79
|
+
expect { controller.current_token }.to raise_error Fridge::InvalidToken
|
80
|
+
end
|
66
81
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
end
|
82
|
+
it 'should not raise an error if a valid token is passed' do
|
83
|
+
expect { controller.current_token }.not_to raise_error
|
84
|
+
end
|
71
85
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
86
|
+
it 'should return the token if a valid token is passed' do
|
87
|
+
expect(controller.current_token.id).to eq access_token.id
|
88
|
+
end
|
89
|
+
end
|
76
90
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
91
|
+
describe '#session_subject' do
|
92
|
+
it 'returns the subject encoded in the session' do
|
93
|
+
controller.stub(:session_token) { access_token }
|
94
|
+
expect(controller.session_subject).to eq access_token.subject
|
95
|
+
end
|
81
96
|
|
82
|
-
|
83
|
-
|
84
|
-
|
97
|
+
it 'returns nil if no session is present' do
|
98
|
+
controller.stub(:session_token) { nil }
|
99
|
+
expect(controller.session_subject).to be_nil
|
100
|
+
end
|
101
|
+
end
|
85
102
|
|
86
|
-
|
87
|
-
|
88
|
-
|
103
|
+
describe '#session_token' do
|
104
|
+
it 'should delete all cookies on error' do
|
105
|
+
cookies[:fridge_session] = 'foobar'
|
106
|
+
controller.session_token
|
107
|
+
expect(cookies.deleted?(:fridge_session, domain: 'auth.aptible.com'))
|
108
|
+
.to be true
|
89
109
|
end
|
90
110
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
end
|
111
|
+
it 'should return nil on error' do
|
112
|
+
cookies[:fridge_session] = 'foobar'
|
113
|
+
expect(controller.session_token).to be_nil
|
114
|
+
end
|
96
115
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
end
|
116
|
+
it 'should return the token stored in :fridge_session' do
|
117
|
+
cookies[:fridge_session] = access_token.serialize
|
118
|
+
expect(controller.session_token.id).to eq access_token.id
|
101
119
|
end
|
102
120
|
|
103
|
-
|
104
|
-
|
105
|
-
cookies[:fridge_session] = 'foobar'
|
106
|
-
controller.session_token
|
107
|
-
expect(cookies.deleted?(:fridge_session, domain: :all)).to be true
|
108
|
-
end
|
121
|
+
context 'with a non-:read scope' do
|
122
|
+
before { options.merge!(scope: 'manage') }
|
109
123
|
|
110
|
-
it 'should
|
111
|
-
cookies[:fridge_session] =
|
112
|
-
expect(controller.session_token).to
|
124
|
+
it 'should downgrade the token' do
|
125
|
+
cookies[:fridge_session] = access_token.serialize
|
126
|
+
expect(controller.session_token.scope).to eq 'read'
|
113
127
|
end
|
114
128
|
|
115
|
-
it 'should
|
129
|
+
it 'should not change the validity of a token' do
|
116
130
|
cookies[:fridge_session] = access_token.serialize
|
117
|
-
expect(controller.session_token
|
131
|
+
expect(controller.session_token).to be_valid
|
118
132
|
end
|
133
|
+
end
|
134
|
+
end
|
119
135
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
expect(controller.session_token.scope).to eq 'read'
|
126
|
-
end
|
136
|
+
describe '#validate_token' do
|
137
|
+
it 'should return false if the token is invalid' do
|
138
|
+
Fridge.configuration.validator = ->(_) { false }
|
139
|
+
expect(controller.validate_token(access_token)).to be false
|
140
|
+
end
|
127
141
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
end
|
132
|
-
end
|
142
|
+
it 'should return false if the token validator fails' do
|
143
|
+
Fridge.configuration.validator = ->(_) { raise 'Foobar' }
|
144
|
+
expect(controller.validate_token(access_token)).to be false
|
133
145
|
end
|
134
146
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
147
|
+
it 'should return the token if valid' do
|
148
|
+
Fridge.configuration.validator = ->(_) { true }
|
149
|
+
expect(controller.validate_token(access_token)).to eq access_token
|
150
|
+
end
|
151
|
+
end
|
140
152
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
153
|
+
describe '#validate_token' do
|
154
|
+
it 'should raise an exception if the token is invalid' do
|
155
|
+
Fridge.configuration.validator = ->(_) { false }
|
156
|
+
expect { controller.validate_token!(access_token) }
|
157
|
+
.to raise_error Fridge::InvalidToken
|
158
|
+
end
|
145
159
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
end
|
160
|
+
it 'should return the token if valid' do
|
161
|
+
Fridge.configuration.validator = ->(_) { true }
|
162
|
+
expect(controller.validate_token!(access_token)).to eq access_token
|
150
163
|
end
|
164
|
+
end
|
151
165
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
166
|
+
describe '#sessionize_token' do
|
167
|
+
it 'should set a session cookie' do
|
168
|
+
Rails.stub_chain(:env, :development?) { false }
|
169
|
+
controller.sessionize_token(access_token)
|
170
|
+
expect(cookies[:fridge_session]).to eq access_token.serialize
|
171
|
+
end
|
172
|
+
end
|
157
173
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
174
|
+
describe '#fridge_cookie_name' do
|
175
|
+
it 'is configurable' do
|
176
|
+
Fridge.configuration.cookie_name = 'foobar'
|
177
|
+
expect(controller.fridge_cookie_name).to eq 'foobar'
|
162
178
|
end
|
179
|
+
end
|
163
180
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
181
|
+
describe '#write_shared_cookie' do
|
182
|
+
before { Rails.stub_chain(:env, :development?) { false } }
|
183
|
+
|
184
|
+
it 'should save cookie' do
|
185
|
+
controller.write_shared_cookie(:organization_url, organization_url)
|
186
|
+
expect(cookies[:organization_url]).to eq organization_url
|
170
187
|
end
|
188
|
+
end
|
171
189
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
190
|
+
describe '#read_shared_cookie' do
|
191
|
+
it 'should read cookie' do
|
192
|
+
cookies[:organization_url] = { value: organization_url }
|
193
|
+
expect(controller.read_shared_cookie(:organization_url)).to(
|
194
|
+
eq organization_url
|
195
|
+
)
|
177
196
|
end
|
197
|
+
end
|
178
198
|
|
179
|
-
|
180
|
-
|
199
|
+
describe '#delete_shared_cookie' do
|
200
|
+
before { Rails.stub_chain(:env, :development?) { false } }
|
181
201
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
202
|
+
it 'should delete cookie' do
|
203
|
+
controller.write_shared_cookie(:organization_url, organization_url)
|
204
|
+
controller.delete_shared_cookie(:organization_url)
|
205
|
+
expect(cookies[:organization_url]).to be_nil
|
186
206
|
end
|
207
|
+
end
|
187
208
|
|
188
|
-
|
189
|
-
|
190
|
-
cookies[:organization_url] = { value: organization_url }
|
191
|
-
expect(controller.read_shared_cookie(:organization_url)).to(
|
192
|
-
eq organization_url
|
193
|
-
)
|
194
|
-
end
|
195
|
-
end
|
209
|
+
describe '#fridge_cookie_options' do
|
210
|
+
before { Rails.stub_chain(:env, :development?) { false } }
|
196
211
|
|
197
|
-
|
198
|
-
|
212
|
+
it 'are configurable' do
|
213
|
+
Fridge.configuration.cookie_options = { foobar: true }
|
214
|
+
options = controller.fridge_cookie_options
|
215
|
+
expect(options[:domain]).to eq 'auth.aptible.com'
|
216
|
+
expect(options[:foobar]).to eq true
|
217
|
+
end
|
199
218
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
219
|
+
it 'restricts cookies to the specific subdomain' do
|
220
|
+
auth = class_double('Aptible::Auth').as_stubbed_const
|
221
|
+
allow(auth).to receive_message_chain(:configuration, :root_url) do
|
222
|
+
'https://auth-bob.aptible-sandbox.com'
|
204
223
|
end
|
205
|
-
end
|
206
224
|
|
207
|
-
|
208
|
-
|
225
|
+
options = controller.fridge_cookie_options
|
226
|
+
expect(options[:domain]).to eq 'auth-bob.aptible-sandbox.com'
|
227
|
+
end
|
209
228
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
expect(options[:foobar]).to eq true
|
229
|
+
it 'handles local development using defaults' do
|
230
|
+
auth = class_double('Aptible::Auth').as_stubbed_const
|
231
|
+
allow(auth).to receive_message_chain(:configuration, :root_url) do
|
232
|
+
'https://localhost:4000'
|
215
233
|
end
|
234
|
+
|
235
|
+
options = controller.fridge_cookie_options
|
236
|
+
expect(options[:domain]).to eq :all
|
216
237
|
end
|
217
238
|
end
|
218
239
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,14 +1,22 @@
|
|
1
1
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
2
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
3
|
|
4
|
+
require 'active_support/all'
|
5
|
+
require 'action_controller'
|
6
|
+
require 'action_dispatch'
|
7
|
+
require 'action_view'
|
8
|
+
|
9
|
+
require 'fridge'
|
10
|
+
require 'fridge/rails_helpers'
|
11
|
+
|
12
|
+
require 'rspec'
|
13
|
+
require 'rspec/rails'
|
14
|
+
|
4
15
|
# Load shared spec files
|
5
16
|
Dir["#{File.dirname(__FILE__)}/shared/**/*.rb"].each do |file|
|
6
17
|
require file
|
7
18
|
end
|
8
19
|
|
9
|
-
# Require library up front
|
10
|
-
require 'fridge'
|
11
|
-
|
12
20
|
RSpec.configure do |config|
|
13
21
|
config.before { Fridge.configuration.reset }
|
14
22
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fridge
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Frank Macreery
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: gem_config
|
@@ -30,14 +30,28 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 1.5.6
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 1.5.6
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: aptible-tasks
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: bundler
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -53,7 +67,7 @@ dependencies:
|
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: '1.5'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
70
|
+
name: pry
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
58
72
|
requirements:
|
59
73
|
- - ">="
|
@@ -67,7 +81,7 @@ dependencies:
|
|
67
81
|
- !ruby/object:Gem::Version
|
68
82
|
version: '0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
84
|
+
name: rails
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
72
86
|
requirements:
|
73
87
|
- - ">="
|
@@ -81,7 +95,7 @@ dependencies:
|
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: '0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
98
|
+
name: rake
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
86
100
|
requirements:
|
87
101
|
- - ">="
|
@@ -100,14 +114,14 @@ dependencies:
|
|
100
114
|
requirements:
|
101
115
|
- - "~>"
|
102
116
|
- !ruby/object:Gem::Version
|
103
|
-
version: '
|
117
|
+
version: '3.0'
|
104
118
|
type: :development
|
105
119
|
prerelease: false
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
107
121
|
requirements:
|
108
122
|
- - "~>"
|
109
123
|
- !ruby/object:Gem::Version
|
110
|
-
version: '
|
124
|
+
version: '3.0'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: rspec-rails
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -122,20 +136,6 @@ dependencies:
|
|
122
136
|
- - ">="
|
123
137
|
- !ruby/object:Gem::Version
|
124
138
|
version: '0'
|
125
|
-
- !ruby/object:Gem::Dependency
|
126
|
-
name: pry
|
127
|
-
requirement: !ruby/object:Gem::Requirement
|
128
|
-
requirements:
|
129
|
-
- - ">="
|
130
|
-
- !ruby/object:Gem::Version
|
131
|
-
version: '0'
|
132
|
-
type: :development
|
133
|
-
prerelease: false
|
134
|
-
version_requirements: !ruby/object:Gem::Requirement
|
135
|
-
requirements:
|
136
|
-
- - ">="
|
137
|
-
- !ruby/object:Gem::Version
|
138
|
-
version: '0'
|
139
139
|
description: Token validation for distributed resource servers
|
140
140
|
email:
|
141
141
|
- frank@macreery.com
|
@@ -143,6 +143,7 @@ executables: []
|
|
143
143
|
extensions: []
|
144
144
|
extra_rdoc_files: []
|
145
145
|
files:
|
146
|
+
- ".github/CODEOWNERS"
|
146
147
|
- ".gitignore"
|
147
148
|
- ".rspec"
|
148
149
|
- ".travis.yml"
|
@@ -153,13 +154,13 @@ files:
|
|
153
154
|
- fridge.gemspec
|
154
155
|
- lib/fridge.rb
|
155
156
|
- lib/fridge/access_token.rb
|
157
|
+
- lib/fridge/expired_token.rb
|
156
158
|
- lib/fridge/invalid_token.rb
|
157
159
|
- lib/fridge/rails_helpers.rb
|
158
160
|
- lib/fridge/railtie.rb
|
159
161
|
- lib/fridge/serialization_error.rb
|
160
162
|
- lib/fridge/version.rb
|
161
163
|
- spec/fixtures/app.rb
|
162
|
-
- spec/fixtures/controller.rb
|
163
164
|
- spec/fridge/access_token_spec.rb
|
164
165
|
- spec/fridge/rails_helpers_spec.rb
|
165
166
|
- spec/spec_helper.rb
|
@@ -167,7 +168,7 @@ homepage: https://github.com/aptible/fridge
|
|
167
168
|
licenses:
|
168
169
|
- MIT
|
169
170
|
metadata: {}
|
170
|
-
post_install_message:
|
171
|
+
post_install_message:
|
171
172
|
rdoc_options: []
|
172
173
|
require_paths:
|
173
174
|
- lib
|
@@ -182,14 +183,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
182
183
|
- !ruby/object:Gem::Version
|
183
184
|
version: '0'
|
184
185
|
requirements: []
|
185
|
-
|
186
|
-
|
187
|
-
signing_key:
|
186
|
+
rubygems_version: 3.0.3
|
187
|
+
signing_key:
|
188
188
|
specification_version: 4
|
189
189
|
summary: Token validation for distributed resource servers
|
190
190
|
test_files:
|
191
191
|
- spec/fixtures/app.rb
|
192
|
-
- spec/fixtures/controller.rb
|
193
192
|
- spec/fridge/access_token_spec.rb
|
194
193
|
- spec/fridge/rails_helpers_spec.rb
|
195
194
|
- spec/spec_helper.rb
|