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 +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +25 -2
- data/lib/devise_g5_authenticatable.rb +8 -0
- data/lib/devise_g5_authenticatable/hooks/g5_authenticatable.rb +16 -0
- data/lib/devise_g5_authenticatable/models/g5_authenticatable.rb +1 -0
- data/lib/devise_g5_authenticatable/version.rb +1 -1
- data/spec/features/token_validation_spec.rb +82 -0
- data/spec/support/devise.rb +1 -0
- data/spec/support/user_feature_methods.rb +4 -1
- data/spec/tasks/export_users_spec.rb +15 -5
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7b68a3deae4616dbf188a936d77e442d39dd761d
|
4
|
+
data.tar.gz: d615bdc6cbce1fec5ba81cdcd2a3bf5454beda29
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c3f7e0ca76d585d91942ea3f98b285e153ed6d49e2cb26369112507d28f7e7c562b742408f224c02525c44c519e6c07399bba6b51bbf251380da5831d1729c47
|
7
|
+
data.tar.gz: 43b89ca19bc3938df96be0861492767277cc1d96f2ecff341b9e2571e9a0277f8d129c1635fbbb9f0f3c116af1a436837c6a4c58aa2bac4378eb5561e51901ab
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -10,7 +10,7 @@ G5 users.
|
|
10
10
|
|
11
11
|
## Current Version
|
12
12
|
|
13
|
-
0.
|
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
|
@@ -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
|
data/spec/support/devise.rb
CHANGED
@@ -19,7 +19,10 @@ module UserFeatureMethods
|
|
19
19
|
end
|
20
20
|
|
21
21
|
RSpec.configure do |config|
|
22
|
-
config.before(:each)
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
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:
|
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
|