devise_g5_authenticatable 0.1.3 → 0.2.0

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
2
  SHA1:
3
- metadata.gz: 647e697e95fa5a4f468529c0c016c5e9a8f2a8bd
4
- data.tar.gz: 5795af637ed1ba2bce1bc36eae8fc765ea9ce88b
3
+ metadata.gz: 7b68a3deae4616dbf188a936d77e442d39dd761d
4
+ data.tar.gz: d615bdc6cbce1fec5ba81cdcd2a3bf5454beda29
5
5
  SHA512:
6
- metadata.gz: 6a17aa3b3d6cdb0a1e3b2c93aa973df48e6b6a13d6ed923cc2da1b1be813c14e110e7dcebc4ffbdc6449c7224b099bd305234a3f1024b16efb3fe79b5ed788a1
7
- data.tar.gz: a59a344ee27a3927e89bae41de06c72a654b9a12acd62e36c7ddfc7e5a05743a07bbeb237e6cab70cf8637c6be1b6ea3bef4b2c95dcef241b72ff05bf6a140bf
6
+ metadata.gz: c3f7e0ca76d585d91942ea3f98b285e153ed6d49e2cb26369112507d28f7e7c562b742408f224c02525c44c519e6c07399bba6b51bbf251380da5831d1729c47
7
+ data.tar.gz: 43b89ca19bc3938df96be0861492767277cc1d96f2ecff341b9e2571e9a0277f8d129c1635fbbb9f0f3c116af1a436837c6a4c58aa2bac4378eb5561e51901ab
@@ -1,3 +1,8 @@
1
+ ## v0.2.0 (2015-01-08)
2
+
3
+ * Add support for strict token validation, disabled by default
4
+ ([#17](https://github.com/G5/devise_g5_authenticatable/pull/17))
5
+
1
6
  ## v0.1.3 (2014-12-19)
2
7
 
3
8
  * Fix sign out when there isn't a locally authenticated user
data/README.md CHANGED
@@ -10,7 +10,7 @@ G5 users.
10
10
 
11
11
  ## Current Version
12
12
 
13
- 0.1.3
13
+ 0.2.0
14
14
 
15
15
  ## Requirements
16
16
 
@@ -66,7 +66,7 @@ environment variables for your client application:
66
66
 
67
67
  ### Configuration
68
68
 
69
- In `config/initializers/devise.rb`, add the following:
69
+ In `config/initializers/devise.rb`, add the following to enable authentication:
70
70
 
71
71
  ```ruby
72
72
  Devise.setup do |config|
@@ -182,6 +182,29 @@ will need to insert the following in your `config/initializers/devise.rb`:
182
182
  require 'devise_g5_authenticatable/models/protected_attributes'
183
183
  ```
184
184
 
185
+ ### Token validation
186
+
187
+ After a user authenticates, their access token will be stored on the G5
188
+ Authenticatable model. By default, this token will not be validated against
189
+ the auth server again until the local session is destroyed, either because
190
+ it times out, or because the user explicitly logs out of the local application.
191
+
192
+ In order to implement single sign-out, you can enable strict token validation.
193
+ This will validate the token against the auth server on every request, and
194
+ automatically destroy the local session if the token is no longer valid.
195
+
196
+ In your `config/initializers/devise.rb':
197
+
198
+ ```ruby
199
+ Devise.setup do |config|
200
+ # ...
201
+ config.g5_strict_token_validation = true
202
+ end
203
+ ```
204
+
205
+ Note that strict token validation incurs a non-trivial amount of performance
206
+ overhead, which is why it is disabled by default.
207
+
185
208
  ## Examples
186
209
 
187
210
  Currently, the best source of example code is in the [test Rails
@@ -9,6 +9,14 @@ require 'devise_g5_authenticatable/controllers/url_helpers'
9
9
 
10
10
  require 'devise_g5_authenticatable/engine'
11
11
 
12
+ module Devise
13
+ # Should devise_g5_authenticatable validate the user's access token
14
+ # against the auth server for every request? Default is false
15
+ @@g5_strict_token_validation = false
16
+
17
+ mattr_accessor :g5_strict_token_validation
18
+ end
19
+
12
20
  Devise.add_module(:g5_authenticatable,
13
21
  strategy: false,
14
22
  route: {session: [nil, :new, :destroy]},
@@ -0,0 +1,16 @@
1
+ Warden::Manager.after_set_user only: :fetch do |record, warden, options|
2
+ if Devise.g5_strict_token_validation
3
+ scope = options[:scope]
4
+
5
+ auth_client = G5AuthenticationClient::Client.new(allow_password_credentials: 'false',
6
+ access_token: record.g5_access_token)
7
+ begin
8
+ auth_client.token_info
9
+ rescue StandardError => error
10
+ proxy = Devise::Hooks::Proxy.new(warden)
11
+ proxy.sign_out(record)
12
+ record.revoke_g5_credentials!
13
+ throw :warden, scope: scope
14
+ end
15
+ end
16
+ end
@@ -1,4 +1,5 @@
1
1
  require 'devise_g5_authenticatable/g5'
2
+ require 'devise_g5_authenticatable/hooks/g5_authenticatable'
2
3
 
3
4
  module Devise
4
5
  module Models
@@ -1,3 +1,3 @@
1
1
  module DeviseG5Authenticatable
2
- VERSION = '0.1.3'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Token validation per request' do
4
+ let(:user) { create(:user) }
5
+ let(:protected_path) { edit_user_registration_path }
6
+ let(:token_info_url) { 'http://auth.g5search.com/oauth/token/info' }
7
+
8
+ before do
9
+ stub_request(:get, token_info_url).
10
+ with(headers: {'Authorization'=>"Bearer #{user.g5_access_token}"}).
11
+ to_return(status: 200, body: '', headers: {})
12
+ end
13
+
14
+ before do
15
+ visit_path_and_login_with(protected_path, user)
16
+
17
+ # Now that we're logged in, any subsequent attempts to
18
+ # authenticate with the auth server will trigger an omniauth
19
+ # failure, which is a condition we can test for
20
+ stub_g5_invalid_credentials
21
+ end
22
+
23
+ context 'when token validation is disabled' do
24
+ before do
25
+ Devise.g5_strict_token_validation = false
26
+ visit protected_path
27
+ end
28
+
29
+ it 'should not valid the token against the auth server' do
30
+ expect(a_request(:get, token_info_url)).to_not have_been_made
31
+ end
32
+
33
+ it 'should allow the user to access the protected page' do
34
+ expect(current_path).to eq(protected_path)
35
+ end
36
+ end
37
+
38
+ context 'when token validation is enabled' do
39
+ before { Devise.g5_strict_token_validation = true }
40
+
41
+ context 'when the access_token is valid' do
42
+ before { visit protected_path }
43
+
44
+ it 'should validate the token against the auth server' do
45
+ expect(a_request(:get, token_info_url).
46
+ with(headers: {'Authorization' => "Bearer #{user.g5_access_token}"})).to have_been_made
47
+ end
48
+
49
+ it 'should allow the user to access the protected page' do
50
+ expect(current_path).to eq(protected_path)
51
+ end
52
+ end
53
+
54
+ context 'when the access_token has been invalidated' do
55
+ before do
56
+ stub_request(:get, token_info_url).
57
+ with(headers: {'Authorization'=>"Bearer #{user.g5_access_token}"}).
58
+ to_return(status: 401,
59
+ headers: {'Content-Type' => 'application/json; charset=utf-8',
60
+ 'Cache-Control' => 'no-cache'},
61
+ body: {'error' => 'invalid_token',
62
+ 'error_description' => 'The access token expired'}.to_json)
63
+ visit protected_path
64
+ end
65
+
66
+ it 'should force the user to re-authenticate' do
67
+ expect(page).to have_content('Invalid credentials')
68
+ end
69
+ end
70
+
71
+ context 'when there is some other error from the auth server' do
72
+ before do
73
+ stub_request(:get, token_info_url).to_raise(StandardError)
74
+ visit protected_path
75
+ end
76
+
77
+ it 'should force the user to re-authenticate' do
78
+ expect(page).to have_content('Invalid credentials')
79
+ end
80
+ end
81
+ end
82
+ end
@@ -1,3 +1,4 @@
1
1
  RSpec.configure do |config|
2
+ config.before(:each) { Devise.g5_strict_token_validation = false }
2
3
  config.include Devise::TestHelpers, type: :controller
3
4
  end
@@ -19,7 +19,10 @@ module UserFeatureMethods
19
19
  end
20
20
 
21
21
  RSpec.configure do |config|
22
- config.before(:each) { OmniAuth.config.test_mode = true }
22
+ config.before(:each) do
23
+ OmniAuth.config.test_mode = true
24
+ OmniAuth.config.mock_auth[:g5] = nil
25
+ end
23
26
  config.after(:each) { OmniAuth.config.test_mode = false }
24
27
 
25
28
  config.include UserFeatureMethods, type: :feature
@@ -6,20 +6,30 @@ describe 'g5:export_users' do
6
6
  let(:user_exporter) { double(:user_exporter, export: nil) }
7
7
  before { allow(G5::UserExporter).to receive(:new).and_return(user_exporter) }
8
8
 
9
- before { ENV['G5_AUTH_CLIENT_ID'] = default_client_id }
9
+ let!(:old_client_id) { ENV['G5_AUTH_CLIENT_ID'] }
10
10
  let(:default_client_id) { 'default_client_id' }
11
+ before { ENV['G5_AUTH_CLIENT_ID'] = default_client_id }
12
+ after { ENV['G5_AUTH_CLIENT_ID'] = old_client_id }
11
13
 
12
- before { ENV['G5_AUTH_CLIENT_SECRET'] = default_client_secret }
14
+ let!(:old_client_secret) { ENV['G5_AUTH_CLIENT_SECRET'] }
13
15
  let(:default_client_secret) { 'default_client_secret' }
16
+ before { ENV['G5_AUTH_CLIENT_SECRET'] = default_client_secret }
17
+ after { ENV['G5_AUTH_CLIENT_SECRET'] = old_client_secret }
14
18
 
15
- before { ENV['G5_AUTH_REDIRECT_URI'] = default_redirect_uri }
19
+ let!(:old_redirect_uri) { ENV['G5_AUTH_REDIRECT_URI'] }
16
20
  let(:default_redirect_uri) { 'http://test.host/default' }
21
+ before { ENV['G5_AUTH_REDIRECT_URI'] = default_redirect_uri }
22
+ after { ENV['G5_AUTH_REDIRECT_URI'] = old_redirect_uri }
17
23
 
18
- before { ENV['G5_AUTH_ENDPOINT'] = default_endpoint }
24
+ let!(:old_endpoint) { ENV['G5_AUTH_ENDPOINT'] }
19
25
  let(:default_endpoint) { 'https://my.g5auth.host' }
26
+ before { ENV['G5_AUTH_ENDPOINT'] = default_endpoint }
27
+ after { ENV['G5_AUTH_ENDPOINT'] = old_endpoint }
20
28
 
21
- before { ENV['G5_AUTH_AUTHORIZATION_CODE'] = default_auth_code }
29
+ let!(:old_auth_code) { ENV['G5_AUTH_AUTHORIZATION_CODE'] }
22
30
  let(:default_auth_code) { 'default_auth_code' }
31
+ before { ENV['G5_AUTH_AUTHORIZATION_CODE'] = default_auth_code }
32
+ after { ENV['G5_AUTH_AUTHORIZATION_CODE'] = old_auth_code }
23
33
 
24
34
  def expect_init_user_exporter_with(option_name, expected_value)
25
35
  expect(G5::UserExporter).to receive(:new) do |args|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devise_g5_authenticatable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maeve Revels
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-19 00:00:00.000000000 Z
11
+ date: 2015-01-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: devise
@@ -82,6 +82,7 @@ files:
82
82
  - lib/devise_g5_authenticatable/g5/auth_user_creator.rb
83
83
  - lib/devise_g5_authenticatable/g5/auth_user_updater.rb
84
84
  - lib/devise_g5_authenticatable/g5/user_exporter.rb
85
+ - lib/devise_g5_authenticatable/hooks/g5_authenticatable.rb
85
86
  - lib/devise_g5_authenticatable/models/g5_authenticatable.rb
86
87
  - lib/devise_g5_authenticatable/models/protected_attributes.rb
87
88
  - lib/devise_g5_authenticatable/omniauth.rb
@@ -160,6 +161,7 @@ files:
160
161
  - spec/features/registration_spec.rb
161
162
  - spec/features/sign_in_spec.rb
162
163
  - spec/features/sign_out_spec.rb
164
+ - spec/features/token_validation_spec.rb
163
165
  - spec/g5/auth_password_validator_spec.rb
164
166
  - spec/g5/auth_user_creator_spec.rb
165
167
  - spec/g5/auth_user_updater_spec.rb
@@ -273,6 +275,7 @@ test_files:
273
275
  - spec/features/registration_spec.rb
274
276
  - spec/features/sign_in_spec.rb
275
277
  - spec/features/sign_out_spec.rb
278
+ - spec/features/token_validation_spec.rb
276
279
  - spec/g5/auth_password_validator_spec.rb
277
280
  - spec/g5/auth_user_creator_spec.rb
278
281
  - spec/g5/auth_user_updater_spec.rb