fridge 0.2.4 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: baa2d0014ae145e09c68dc53c816938ad272aa3d
4
- data.tar.gz: 7f34e028cb347f9da11e1d52d6f7443dc7f470bb
2
+ SHA256:
3
+ metadata.gz: 769896062879cb0dc6c7c69f095a5cedab11beaa0c30cb3e302dfc15eb842343
4
+ data.tar.gz: 657ca035209d5be3fcb78aaa74cc418bf764726622ccc3d90e0cab900ad4cf13
5
5
  SHA512:
6
- metadata.gz: 586f9c3edb3356d64068ca3b9c43741411238423b6cdb0d6a63041fed790b13e47c3d1d43c7ea6ef1c4e290b04f03cf253e4a6da40a2d0d9a89b01d72cb866fa
7
- data.tar.gz: 7d3dff29fffe39c8f656180e091639f4b2139a513fa024e2d0d189f5436cb4d39f2dacab4867987e57e781380359a3281e3d61fee5db8fe5a8fff723bc68ed91
6
+ metadata.gz: 1500d9599ef57f700c52c2362086a3c9e0ac1853c2182e72e1f24ffe0583ccdc38bcaca4d7c9e53b792d93b164ae7ac1510af721e7b1359e2e07998da44388b2
7
+ data.tar.gz: e18539fb6ae2d73dac73005348bc78015dc2a708e6d4e3f10b7b430ed8368f16f73d58d876ca6afdfb3dcf41d41b165d4291eac3ef6cb11c03c61ff87574fc72
@@ -0,0 +1 @@
1
+ * @dawenster
@@ -1,3 +1,5 @@
1
+ sudo: false
1
2
  rvm:
2
- - 2.0.0
3
- - jruby
3
+ - 2.2
4
+ - 2.5
5
+ - 2.6
data/Gemfile CHANGED
@@ -1,4 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ gem 'activesupport', '~> 4.0'
4
+ gem 'nokogiri', '~> 1.9.1'
5
+
3
6
  # Specify your gem's dependencies in fridge.gemspec
4
7
  gemspec
data/README.md CHANGED
@@ -80,4 +80,4 @@ store_session_cookie(access_token)
80
80
 
81
81
  MIT License, see [LICENSE](LICENSE.md) for details.
82
82
 
83
- Copyright (c) 2014 [Aptible](https://www.aptible.com), Frank Macreery, and contributors.
83
+ Copyright (c) 2019 [Aptible](https://www.aptible.com) and contributors.
@@ -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
 
@@ -16,17 +17,17 @@ Gem::Specification.new do |spec|
16
17
  spec.license = 'MIT'
17
18
 
18
19
  spec.files = `git ls-files`.split($RS)
19
- spec.test_files = spec.files.grep(/^spec\//)
20
+ spec.test_files = spec.files.grep(%r{^spec/})
20
21
  spec.require_paths = ['lib']
21
22
 
22
23
  spec.add_dependency 'gem_config'
23
- spec.add_dependency 'jwt', '~> 0.1.13'
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 'rake'
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 'rspec', '~> 2.0'
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
@@ -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
- has :signing_algorithm, values: %w(RS512 RS256), default: 'RS512'
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
@@ -2,10 +2,9 @@ require 'jwt'
2
2
 
3
3
  module Fridge
4
4
  class AccessToken
5
- attr_accessor :id, :issuer, :subject, :scope, :expires_at,
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
@@ -15,13 +14,12 @@ module Fridge
15
14
  when Hash then jwt_or_options
16
15
  else {}
17
16
  end
18
- [:id, :issuer, :subject, :scope, :expires_at].each do |key|
17
+
18
+ [:id, :issuer, :subject, :scope, :expires_at, :actor].each do |key|
19
19
  send "#{key}=", options.delete(key)
20
20
  end
21
- self.attributes = options.reject { |_, v| v.nil? }
22
- self.attributes = Hash[attributes.map { |k, v| [k.to_sym, v] }]
21
+ self.attributes = options
23
22
  end
24
- # rubocop:enable MethodLength
25
23
 
26
24
  def to_s
27
25
  serialize
@@ -29,38 +27,36 @@ 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
35
34
  end
36
35
 
37
36
  def encode_and_sign
38
- JWT.encode({
39
- id: id,
40
- iss: issuer,
41
- sub: subject,
42
- scope: scope,
43
- exp: expires_at.to_i
44
- }.merge(attributes), private_key, algorithm)
45
- rescue
37
+ h = {}
38
+ [:id, :issuer, :subject, :scope, :expires_at, :actor].each do |key|
39
+ h[key] = send(key)
40
+ end
41
+ h.merge!(attributes)
42
+ h = encode_for_jwt(h)
43
+ JWT.encode(h, private_key, algorithm)
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
- hash = JWT.decode(jwt, public_key)
52
- base = {
53
- id: hash.delete('id'),
54
- issuer: hash.delete('iss'),
55
- subject: hash.delete('sub'),
56
- scope: hash.delete('scope'),
57
- expires_at: Time.at(hash.delete('exp'))
58
- }
59
- base.merge(hash)
60
- rescue JWT::DecodeError
61
- raise InvalidToken, 'Invalid access token'
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
+ end
56
+
57
+ def downgrade
58
+ self.scope = 'read'
62
59
  end
63
- # rubocop:enable MethodLength
64
60
 
65
61
  def valid?
66
62
  !expired?
@@ -72,8 +68,9 @@ module Fridge
72
68
 
73
69
  def private_key
74
70
  return unless config.private_key
71
+
75
72
  @private_key ||= OpenSSL::PKey::RSA.new(config.private_key)
76
- rescue
73
+ rescue StandardError
77
74
  nil
78
75
  end
79
76
 
@@ -83,7 +80,7 @@ module Fridge
83
80
  elsif config.public_key
84
81
  @public_key ||= OpenSSL::PKey::RSA.new(config.public_key)
85
82
  end
86
- rescue
83
+ rescue StandardError
87
84
  nil
88
85
  end
89
86
 
@@ -105,19 +102,72 @@ module Fridge
105
102
  end
106
103
  end
107
104
 
105
+ def respond_to_missing?(method, include_private = false)
106
+ attributes.key?(method) || super
107
+ end
108
+
108
109
  def validate_parameters!
109
110
  [:subject, :expires_at].each do |attribute|
110
111
  next if send(attribute)
111
- fail SerializationError, "Missing attribute: #{attribute}"
112
+
113
+ raise SerializationError, "Missing attribute: #{attribute}"
112
114
  end
113
115
  end
114
116
 
115
117
  def validate_private_key!
116
- fail SerializationError, 'No private key configured' unless private_key
118
+ raise SerializationError, 'No private key configured' unless private_key
117
119
  end
118
120
 
119
121
  def validate_public_key!
120
- fail SerializationError, 'No public key configured' unless public_key
122
+ raise SerializationError, 'No public key configured' unless public_key
123
+ end
124
+
125
+ # Internally, we use "subject" to refer to "sub", and so on. We also
126
+ # represent some objects (expiry) differently. These functions do the
127
+ # mapping from Fridge to JWT and vice-versa.
128
+
129
+ def encode_for_jwt(hash)
130
+ hash = hash.dup
131
+
132
+ out = {
133
+ id: hash.delete(:id),
134
+ iss: hash.delete(:issuer),
135
+ sub: hash.delete(:subject),
136
+ scope: hash.delete(:scope)
137
+ }.delete_if { |_, v| v.nil? }
138
+
139
+ # Unfortunately, nil.to_i returns 0, which means we can't
140
+ # easily clean out exp if we include it although it wasn't passed
141
+ # in like we do for other keys. So, we only include it if it's
142
+ # actually passed in and non-nil. Either way, we delete the keys.
143
+ hash.delete(:expires_at).tap { |e| out[:exp] = e.to_i if e }
144
+ hash.delete(:actor).tap { |a| out[:act] = encode_for_jwt(a) if a }
145
+
146
+ # Extra attributes passed through as-is
147
+ out.merge!(hash)
148
+
149
+ out
150
+ end
151
+
152
+ def decode_from_jwt(hash)
153
+ hash = hash.dup
154
+
155
+ out = {
156
+ id: hash.delete('id'),
157
+ issuer: hash.delete('iss'),
158
+ subject: hash.delete('sub'),
159
+ scope: hash.delete('scope')
160
+ }.delete_if { |_, v| v.nil? }
161
+
162
+ hash.delete('exp').tap { |e| out[:expires_at] = Time.at(e) if e }
163
+ hash.delete('act').tap { |a| out[:actor] = decode_from_jwt(a) if a }
164
+
165
+ # Extra attributes
166
+ hash.delete_if { |_, v| v.nil? }
167
+ hash = Hash[hash.map { |k, v| [k.to_sym, v] }]
168
+ out.merge!(hash)
169
+
170
+ out
121
171
  end
122
172
  end
123
173
  end
@@ -0,0 +1,4 @@
1
+ module Fridge
2
+ class ExpiredToken < InvalidToken
3
+ end
4
+ end
@@ -15,8 +15,13 @@ module Fridge
15
15
  current_token.subject if current_token
16
16
  end
17
17
 
18
+ def token_actor
19
+ current_token.actor if current_token
20
+ end
21
+
18
22
  def current_token
19
23
  return unless bearer_token
24
+
20
25
  @current_token ||= AccessToken.new(bearer_token).tap do |token|
21
26
  validate_token!(token)
22
27
  end
@@ -31,12 +36,17 @@ module Fridge
31
36
  session_token.subject if session_token
32
37
  end
33
38
 
39
+ def session_actor
40
+ session_token.actor if session_token
41
+ end
42
+
34
43
  def session_token
35
44
  return unless session_cookie
45
+
36
46
  @session_token ||= AccessToken.new(session_cookie).tap do |token|
37
- validate_token!(token)
47
+ validate_token!(token).downgrade
38
48
  end
39
- rescue
49
+ rescue StandardError
40
50
  clear_session_cookie
41
51
  end
42
52
 
@@ -44,7 +54,7 @@ module Fridge
44
54
  def validate_token(access_token)
45
55
  validator = Fridge.configuration.validator
46
56
  validator.call(access_token) && access_token
47
- rescue
57
+ rescue StandardError
48
58
  false
49
59
  end
50
60
 
@@ -54,7 +64,7 @@ module Fridge
54
64
  if validator.call(access_token)
55
65
  access_token
56
66
  else
57
- fail InvalidToken
67
+ raise InvalidToken, 'Rejected by validator'
58
68
  end
59
69
  end
60
70
 
@@ -83,7 +93,7 @@ module Fridge
83
93
  end
84
94
 
85
95
  def write_shared_cookie(name, value, options = {})
86
- fail 'Can only write string cookie values' unless value.is_a?(String)
96
+ raise 'Can only write string cookie values' unless value.is_a?(String)
87
97
 
88
98
  cookies[name] = {
89
99
  value: value,
@@ -95,9 +105,10 @@ module Fridge
95
105
  cookies[name]
96
106
  end
97
107
 
98
- def fetch_shared_cookie(name, &block)
108
+ def fetch_shared_cookie(name)
99
109
  return read_shared_cookie(name) if read_shared_cookie(name)
100
- write_shared_cookie(block.call)
110
+
111
+ write_shared_cookie(yield)
101
112
  end
102
113
 
103
114
  def delete_shared_cookie(name)
@@ -1,3 +1,3 @@
1
1
  module Fridge
2
- VERSION = '0.2.4'
2
+ VERSION = '0.4.2'.freeze
3
3
  end
@@ -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
- @app ||= App.new
19
+ @application ||= App.new
23
20
  end
24
21
  end
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'json'
2
3
 
3
4
  describe Fridge::AccessToken do
4
5
  describe '#initialize' do
@@ -13,19 +14,39 @@ describe Fridge::AccessToken do
13
14
  end
14
15
 
15
16
  it 'should accept a JWT' do
16
- jwt = JWT.encode({ id: 'foobar', exp: 0 }, private_key, 'RS512')
17
+ jwt = JWT.encode(
18
+ { id: 'foobar', exp: Time.now.to_i + 10 },
19
+ private_key, 'RS512'
20
+ )
17
21
  access_token = described_class.new(jwt)
18
22
  expect(access_token.id).to eq 'foobar'
19
23
  end
20
24
 
21
25
  it 'should raise an error on an invalid JWT' do
22
- expect { described_class.new('foobar') }.to raise_error
26
+ expect { described_class.new('foobar') }
27
+ .to raise_error Fridge::InvalidToken
23
28
  end
24
29
 
25
30
  it 'should raise an error on an incorrectly signed JWT' do
26
31
  jwt = JWT.encode({ id: 'foobar' }, OpenSSL::PKey::RSA.new(1024), 'RS512')
27
32
  expect { described_class.new(jwt) }.to raise_error Fridge::InvalidToken
28
33
  end
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
+
43
+ # http://bit.ly/jwt-none-vulnerability
44
+ it 'should raise an error with { "alg": "none" }' do
45
+ jwt = "#{Base64.encode64({ typ: 'JWT', alg: 'none' }.to_json).chomp}." \
46
+ "#{Base64.encode64({ id: 'foobar' }.to_json).chomp}"
47
+ expect(JWT.decode(jwt, nil, false)[0]).to eq('id' => 'foobar')
48
+ expect { described_class.new(jwt) }.to raise_error Fridge::InvalidToken
49
+ end
29
50
  end
30
51
 
31
52
  describe '#serialize' do
@@ -72,8 +93,8 @@ describe Fridge::AccessToken do
72
93
  end
73
94
 
74
95
  it 'should represent :exp in seconds since the epoch' do
75
- hash = JWT.decode(subject.serialize, public_key)
76
- expect(hash['exp']).to be_a Fixnum
96
+ hash, = JWT.decode(subject.serialize, public_key)
97
+ expect(hash['exp']).to be_a Integer
77
98
  end
78
99
 
79
100
  it 'should be deterministic' do
@@ -93,12 +114,43 @@ describe Fridge::AccessToken do
93
114
 
94
115
  expect(copy.attributes[:foo]).to eq 'bar'
95
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
96
119
  end
97
120
 
98
121
  it 'should raise an error if required attributes are missing' do
99
122
  subject.subject = nil
100
123
  expect { subject.serialize }.to raise_error Fridge::SerializationError
101
124
  end
125
+
126
+ it 'should encode and decode :actor as :act' do
127
+ # The `act` field can recursively encode additional
128
+ # claims, so we check those too.
129
+ actor = { subject: 'foo', username: 'test', actor: { subject: 'bar' } }
130
+ subject = described_class.new(options.merge(actor: actor))
131
+
132
+ # The JWT lib will return everything as strings, so we'll
133
+ # test that, although eventually we'll want to see symbols back.
134
+ actor_s = { 'sub' => 'foo', 'username' => 'test',
135
+ 'act' => { 'sub' => 'bar' } }
136
+ hash, = JWT.decode(subject.serialize, public_key)
137
+ expect(hash['act']).to eq(actor_s)
138
+
139
+ # Now, check that we properly get symbols back
140
+ new = described_class.new(subject.serialize)
141
+ expect(new.actor).to eq(actor)
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
102
154
  end
103
155
 
104
156
  describe '#expired?' do
@@ -117,4 +169,10 @@ describe Fridge::AccessToken do
117
169
  expect(subject).not_to be_expired
118
170
  end
119
171
  end
172
+
173
+ describe '#downgrade' do
174
+ it 'sets the token scope to :read' do
175
+ expect { subject.downgrade }.to change(subject, :scope).to('read')
176
+ end
177
+ end
120
178
  end
@@ -1,204 +1,218 @@
1
1
  require 'spec_helper'
2
2
  require 'fixtures/app'
3
- require 'fixtures/controller'
4
- require 'rspec/rails'
5
3
 
6
- # http://say26.com/rspec-testing-controllers-outside-of-a-rails-application
7
- describe Controller, type: :controller do
8
- context Fridge::RailsHelpers do
9
- let(:organization_url) do
10
- "https://auth.aptible.com/users/#{SecureRandom.uuid}"
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
- let(:options) do
16
- {
17
- subject: "https://auth.aptible.com/users/#{SecureRandom.uuid}",
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
- let(:access_token) { Fridge::AccessToken.new(options) }
38
+ end
22
39
 
23
- let(:cookies) { controller.send(:cookies) }
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
- before { Fridge.configuration.private_key = private_key.to_s }
26
- before { Fridge.configuration.public_key = public_key.to_s }
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
- 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'
32
- end
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
- 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
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
- 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
64
+ describe '#current_token' do
65
+ before { controller.stub(:bearer_token) { access_token.serialize } }
45
66
 
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
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
- 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
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
- describe '#current_token' do
65
- before { controller.stub(:bearer_token) { access_token.serialize } }
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
- 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
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
- 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
75
- end
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
- 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
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
- it 'should not raise an error if a valid token is passed' do
83
- expect { controller.current_token }.not_to raise_error
84
- end
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
- 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
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: :all)).to be true
89
108
  end
90
109
 
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
110
+ it 'should return nil on error' do
111
+ cookies[:fridge_session] = 'foobar'
112
+ expect(controller.session_token).to be_nil
113
+ end
96
114
 
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
115
+ it 'should return the token stored in :fridge_session' do
116
+ cookies[:fridge_session] = access_token.serialize
117
+ expect(controller.session_token.id).to eq access_token.id
101
118
  end
102
119
 
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: :all)).to be_true
108
- end
120
+ context 'with a non-:read scope' do
121
+ before { options.merge!(scope: 'manage') }
109
122
 
110
- it 'should return nil on error' do
111
- cookies[:fridge_session] = 'foobar'
112
- expect(controller.session_token).to be_nil
123
+ it 'should downgrade the token' do
124
+ cookies[:fridge_session] = access_token.serialize
125
+ expect(controller.session_token.scope).to eq 'read'
113
126
  end
114
127
 
115
- it 'should return the token stored in :fridge_session' do
128
+ it 'should not change the validity of a token' do
116
129
  cookies[:fridge_session] = access_token.serialize
117
- expect(controller.session_token.id).to eq access_token.id
130
+ expect(controller.session_token).to be_valid
118
131
  end
119
132
  end
133
+ end
120
134
 
121
- describe '#validate_token' do
122
- it 'should return false if the token is invalid' do
123
- Fridge.configuration.validator = ->(_) { false }
124
- expect(controller.validate_token(access_token)).to be_false
125
- end
135
+ describe '#validate_token' do
136
+ it 'should return false if the token is invalid' do
137
+ Fridge.configuration.validator = ->(_) { false }
138
+ expect(controller.validate_token(access_token)).to be false
139
+ end
126
140
 
127
- it 'should return false if the token validator fails' do
128
- Fridge.configuration.validator = ->(_) { fail 'Foobar' }
129
- expect(controller.validate_token(access_token)).to be_false
130
- end
141
+ it 'should return false if the token validator fails' do
142
+ Fridge.configuration.validator = ->(_) { raise 'Foobar' }
143
+ expect(controller.validate_token(access_token)).to be false
144
+ end
131
145
 
132
- it 'should return the token if valid' do
133
- Fridge.configuration.validator = ->(_) { true }
134
- expect(controller.validate_token(access_token)).to eq access_token
135
- end
146
+ it 'should return the token if valid' do
147
+ Fridge.configuration.validator = ->(_) { true }
148
+ expect(controller.validate_token(access_token)).to eq access_token
136
149
  end
150
+ end
137
151
 
138
- describe '#validate_token' do
139
- it 'should raise an exception if the token is invalid' do
140
- Fridge.configuration.validator = ->(_) { false }
141
- expect { controller.validate_token!(access_token) }.to raise_error
142
- end
152
+ describe '#validate_token' do
153
+ it 'should raise an exception if the token is invalid' do
154
+ Fridge.configuration.validator = ->(_) { false }
155
+ expect { controller.validate_token!(access_token) }
156
+ .to raise_error Fridge::InvalidToken
157
+ end
143
158
 
144
- it 'should return the token if valid' do
145
- Fridge.configuration.validator = ->(_) { true }
146
- expect(controller.validate_token!(access_token)).to eq access_token
147
- end
159
+ it 'should return the token if valid' do
160
+ Fridge.configuration.validator = ->(_) { true }
161
+ expect(controller.validate_token!(access_token)).to eq access_token
148
162
  end
163
+ end
149
164
 
150
- describe '#sessionize_token' do
151
- it 'should set a session cookie' do
152
- Rails.stub_chain(:env, :development?) { false }
153
- controller.sessionize_token(access_token)
154
- expect(cookies[:fridge_session]).to eq access_token.serialize
155
- end
165
+ describe '#sessionize_token' do
166
+ it 'should set a session cookie' do
167
+ Rails.stub_chain(:env, :development?) { false }
168
+ controller.sessionize_token(access_token)
169
+ expect(cookies[:fridge_session]).to eq access_token.serialize
156
170
  end
171
+ end
157
172
 
158
- describe '#fridge_cookie_name' do
159
- it 'is configurable' do
160
- Fridge.configuration.cookie_name = 'foobar'
161
- expect(controller.fridge_cookie_name).to eq 'foobar'
162
- end
173
+ describe '#fridge_cookie_name' do
174
+ it 'is configurable' do
175
+ Fridge.configuration.cookie_name = 'foobar'
176
+ expect(controller.fridge_cookie_name).to eq 'foobar'
163
177
  end
178
+ end
164
179
 
165
- describe '#write_shared_cookie' do
166
- before { Rails.stub_chain(:env, :development?) { false } }
180
+ describe '#write_shared_cookie' do
181
+ before { Rails.stub_chain(:env, :development?) { false } }
167
182
 
168
- it 'should save cookie' do
169
- controller.write_shared_cookie(:organization_url, organization_url)
170
- expect(cookies[:organization_url]).to eq organization_url
171
- end
183
+ it 'should save cookie' do
184
+ controller.write_shared_cookie(:organization_url, organization_url)
185
+ expect(cookies[:organization_url]).to eq organization_url
172
186
  end
187
+ end
173
188
 
174
- describe '#read_shared_cookie' do
175
- it 'should read cookie' do
176
- cookies[:organization_url] = { value: organization_url }
177
- expect(controller.read_shared_cookie(:organization_url)).to(
178
- eq organization_url
179
- )
180
- end
189
+ describe '#read_shared_cookie' do
190
+ it 'should read cookie' do
191
+ cookies[:organization_url] = { value: organization_url }
192
+ expect(controller.read_shared_cookie(:organization_url)).to(
193
+ eq organization_url
194
+ )
181
195
  end
196
+ end
182
197
 
183
- describe '#delete_shared_cookie' do
184
- before { Rails.stub_chain(:env, :development?) { false } }
198
+ describe '#delete_shared_cookie' do
199
+ before { Rails.stub_chain(:env, :development?) { false } }
185
200
 
186
- it 'should delete cookie' do
187
- controller.write_shared_cookie(:organization_url, organization_url)
188
- controller.delete_shared_cookie(:organization_url)
189
- expect(cookies[:organization_url]).to be_nil
190
- end
201
+ it 'should delete cookie' do
202
+ controller.write_shared_cookie(:organization_url, organization_url)
203
+ controller.delete_shared_cookie(:organization_url)
204
+ expect(cookies[:organization_url]).to be_nil
191
205
  end
206
+ end
192
207
 
193
- describe '#fridge_cookie_options' do
194
- before { Rails.stub_chain(:env, :development?) { false } }
208
+ describe '#fridge_cookie_options' do
209
+ before { Rails.stub_chain(:env, :development?) { false } }
195
210
 
196
- it 'are configurable' do
197
- Fridge.configuration.cookie_options = { foobar: true }
198
- options = controller.fridge_cookie_options
199
- expect(options[:domain]).to eq :all
200
- expect(options[:foobar]).to eq true
201
- end
211
+ it 'are configurable' do
212
+ Fridge.configuration.cookie_options = { foobar: true }
213
+ options = controller.fridge_cookie_options
214
+ expect(options[:domain]).to eq :all
215
+ expect(options[:foobar]).to eq true
202
216
  end
203
217
  end
204
218
  end
@@ -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,139 +1,139 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fridge
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.4.2
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: 2014-09-30 00:00:00.000000000 Z
11
+ date: 2020-07-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gem_config
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: jwt
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.1.13
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: 0.1.13
40
+ version: 1.5.6
41
41
  - !ruby/object:Gem::Dependency
42
- name: bundler
42
+ name: aptible-tasks
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '1.5'
47
+ version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '1.5'
54
+ version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: aptible-tasks
56
+ name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: '1.5'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: '1.5'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rake
70
+ name: pry
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '>='
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rails
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - '>='
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - '>='
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: rspec
98
+ name: rake
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ~>
101
+ - - ">="
102
102
  - !ruby/object:Gem::Version
103
- version: '2.0'
103
+ version: '0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ~>
108
+ - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: '2.0'
110
+ version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: rspec-rails
112
+ name: rspec
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - '>='
115
+ - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '0'
117
+ version: '3.0'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - '>='
122
+ - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: '0'
124
+ version: '3.0'
125
125
  - !ruby/object:Gem::Dependency
126
- name: pry
126
+ name: rspec-rails
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - '>='
129
+ - - ">="
130
130
  - !ruby/object:Gem::Version
131
131
  version: '0'
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - '>='
136
+ - - ">="
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
139
  description: Token validation for distributed resource servers
@@ -143,9 +143,10 @@ executables: []
143
143
  extensions: []
144
144
  extra_rdoc_files: []
145
145
  files:
146
- - .gitignore
147
- - .rspec
148
- - .travis.yml
146
+ - ".github/CODEOWNERS"
147
+ - ".gitignore"
148
+ - ".rspec"
149
+ - ".travis.yml"
149
150
  - Gemfile
150
151
  - LICENSE.md
151
152
  - README.md
@@ -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,29 +168,27 @@ 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
174
175
  required_ruby_version: !ruby/object:Gem::Requirement
175
176
  requirements:
176
- - - '>='
177
+ - - ">="
177
178
  - !ruby/object:Gem::Version
178
179
  version: '0'
179
180
  required_rubygems_version: !ruby/object:Gem::Requirement
180
181
  requirements:
181
- - - '>='
182
+ - - ">="
182
183
  - !ruby/object:Gem::Version
183
184
  version: '0'
184
185
  requirements: []
185
- rubyforge_project:
186
- rubygems_version: 2.2.2
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
@@ -1,5 +0,0 @@
1
- require 'fridge/rails_helpers'
2
-
3
- class Controller < ActionController::Base
4
- include Fridge::RailsHelpers
5
- end