nulogy_sso 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -6
- data/app/controllers/nulogy_sso/authentication_controller.rb +18 -18
- data/app/services/nulogy_sso/authenticator.rb +4 -4
- data/lib/nulogy_sso/controller_helper.rb +1 -1
- data/lib/nulogy_sso/engine.rb +2 -2
- data/lib/nulogy_sso/test_utilities/jwt_test_helper.rb +2 -2
- data/lib/nulogy_sso/version.rb +1 -1
- data/lib/nulogy_sso.rb +11 -11
- data/spec/dummy/config/application.rb +1 -1
- data/spec/dummy/config/{auth_sso.yml → sso.yml} +0 -0
- data/spec/features/nulogy_sso/sso_login_spec.rb +1 -1
- data/spec/integration/services/nulogy_sso/authenticator_spec.rb +3 -3
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c4d1f9f535ed99d1575c31fded6cc2712f9bc22f4e19809236ec478a57715792
|
4
|
+
data.tar.gz: 779c7dcb20b58215370b4bae528862c12ce8e528d5f1da9830fafb5f27699c3c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8b8b7bb65b92718bb6a699e085a00161a1e7895c76b1f339fb0bf4e7962d5708bde3657b24ee5073c8afe1a6adf3dac5eb90eb7f32aedce209c88c7fde3d8af1
|
7
|
+
data.tar.gz: 0676e085475f7915b3f7fff3e6197d27d87856c0aa4853f7fc5c5417dea8e6b7655c88ceccb878a263e4eae64ee59d32d96254be5c1d27467b2e018f1db09670
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# NulogySSO
|
2
2
|
|
3
|
-
![Gem](https://img.shields.io/gem/v/nulogy_sso?label=nulogy_sso)
|
3
|
+
[![Gem](https://img.shields.io/gem/v/nulogy_sso?label=nulogy_sso)](https://rubygems.org/gems/nulogy_sso "View this project in Rubygems")
|
4
4
|
|
5
5
|
**This repo is still under heavy initial development and is not ready to be used by any other product besides CPI. This status will be changed very shortly.**
|
6
6
|
|
@@ -32,12 +32,12 @@ get "logout", to: redirect("sso/logout")
|
|
32
32
|
|
33
33
|
The engine now needs to be configured. First create a YAML config file, perhaps named `config/auth_sso.yml`, to configure your app's Auth0 settings. This assumes that the necessary Auth0 applications have been created in the correct Auth0 tenants. The [CPI auth_sso.yml file](https://github.com/nulogy/Common-Platform-Interface/blob/master/config/auth_sso.yml) is a good starting place.
|
34
34
|
|
35
|
-
With that available, you can configure the engine with an initializer file. This is where _NulogySSO_ can be customized according to your application's needs. Put the below code into `config/initializers/nulogy_sso.rb`, with the appropriate modifications implemented. For `
|
35
|
+
With that available, you can configure the engine with an initializer file. This is where _NulogySSO_ can be customized according to your application's needs. Put the below code into `config/initializers/nulogy_sso.rb`, with the appropriate modifications implemented. For `sso_config`, refer to [nulogy_sso.rb](lib/nulogy_sso.rb) for a list of required keys and [sso_config.yml](spec/dummy/config/sso_config.yml) for an example config file.
|
36
36
|
|
37
37
|
```ruby
|
38
38
|
# Compiles config/auth_sso.yml into a Ruby object. An error is thrown if required keys are missing.
|
39
39
|
# See lib/nulogy_sso.rb for required keys.
|
40
|
-
NulogySSO.
|
40
|
+
NulogySSO.sso_config = Rails::Application.config_for(:sso)
|
41
41
|
|
42
42
|
# Return the user matching the provided email, or nil if not found.
|
43
43
|
NulogySSO.find_user_by_email = ->(email) { nil }
|
@@ -48,7 +48,7 @@ NulogySSO.find_user_by_email = ->(email) { nil }
|
|
48
48
|
NulogySSO.handle_sso_error = ->(controller) { }
|
49
49
|
```
|
50
50
|
|
51
|
-
The app is now ready to authenticate a user with Auth0! With
|
51
|
+
The app is now ready to authenticate a user with Auth0! With NulogySSO and Auth0, the user's identity is maintained across requests (and apps!) via a [JWT](https://auth0.com/docs/jwt) stored as a browser cookie. Add this code to the `ApplicationController`:
|
52
52
|
|
53
53
|
```ruby
|
54
54
|
class ApplicationController < ActionController::Base
|
@@ -79,9 +79,9 @@ docker-compose up -d
|
|
79
79
|
|
80
80
|
### Testing
|
81
81
|
|
82
|
-
There are multiple helpers made available via the `
|
82
|
+
There are multiple helpers made available via the `NulogySSO::TestUtilities` module. These are helpful for doing things such as grabbing test JWT values and interacting with a [Mockserver](https://github.com/jamesdbloom/mockserver) mock of the Auth0 API.
|
83
83
|
|
84
|
-
It is a common use case for a Rails app to switch from Devise-powered authentication to Auth0. Here's a pattern that could be applied around a feature flag (e.g. environment variable) to switch between Devise user authentication test helpers and
|
84
|
+
It is a common use case for a Rails app to switch from Devise-powered authentication to Auth0. Here's a pattern that could be applied around a feature flag (e.g. environment variable) to switch between Devise user authentication test helpers and NulogySSO test helpers: _(TODO: insert link to CPI `ControllerIntegrationSpecMacros`)_
|
85
85
|
|
86
86
|
### Contributing
|
87
87
|
|
@@ -11,17 +11,17 @@ module NulogySSO
|
|
11
11
|
|
12
12
|
def initialize
|
13
13
|
# These instance variables have to be set in order for the HTTPProxy mixin to work.
|
14
|
-
@base_uri =
|
14
|
+
@base_uri = sso_config.base_uri
|
15
15
|
@headers = { content_type: "application/json" }
|
16
16
|
end
|
17
17
|
|
18
18
|
def login
|
19
|
-
raw_access_token = cookies[NulogySSO.
|
19
|
+
raw_access_token = cookies[NulogySSO.sso_cookie_key]
|
20
20
|
|
21
21
|
authenticator.validate_token(
|
22
22
|
raw_access_token,
|
23
23
|
on_success: method(:on_authentication_success),
|
24
|
-
on_invalid_token: -> { redirect_to
|
24
|
+
on_invalid_token: -> { redirect_to auth0_authorize_path }
|
25
25
|
)
|
26
26
|
end
|
27
27
|
|
@@ -41,18 +41,18 @@ module NulogySSO
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def logout
|
44
|
-
cookies.delete(NulogySSO.
|
44
|
+
cookies.delete(NulogySSO.sso_cookie_key, domain: :all)
|
45
45
|
|
46
46
|
query_params = {
|
47
|
-
returnTo:
|
48
|
-
client_id:
|
47
|
+
returnTo: sso_config.redirect_uri, # Yes, this must be camelCased
|
48
|
+
client_id: sso_config.client_id
|
49
49
|
}
|
50
|
-
redirect_to "#{
|
50
|
+
redirect_to "#{sso_config.base_uri}/v2/logout?#{query_params.to_query}"
|
51
51
|
end
|
52
52
|
|
53
53
|
private
|
54
54
|
|
55
|
-
delegate :
|
55
|
+
delegate :sso_config, to: :NulogySSO
|
56
56
|
|
57
57
|
def sso_error
|
58
58
|
NulogySSO.handle_sso_error.call(self)
|
@@ -65,20 +65,20 @@ module NulogySSO
|
|
65
65
|
def on_authentication_success(access_token)
|
66
66
|
respond_with_cookies(access_token)
|
67
67
|
|
68
|
-
redirect_to params["origin"].presence ||
|
68
|
+
redirect_to params["origin"].presence || sso_config.redirect_uri
|
69
69
|
end
|
70
70
|
|
71
71
|
def token_response(code)
|
72
72
|
exchange_auth_code_for_tokens(
|
73
73
|
code,
|
74
|
-
redirect_uri:
|
75
|
-
client_id:
|
76
|
-
client_secret:
|
74
|
+
redirect_uri: sso_config.login_uri,
|
75
|
+
client_id: sso_config.client_id,
|
76
|
+
client_secret: sso_config.client_secret
|
77
77
|
)
|
78
78
|
end
|
79
79
|
|
80
80
|
def respond_with_cookies(access_token_value)
|
81
|
-
cookies[NulogySSO.
|
81
|
+
cookies[NulogySSO.sso_cookie_key] = {
|
82
82
|
value: access_token_value,
|
83
83
|
domain: :all,
|
84
84
|
expires: 36_000.seconds, # TODO: Fetch this value from the JWT
|
@@ -87,16 +87,16 @@ module NulogySSO
|
|
87
87
|
}
|
88
88
|
end
|
89
89
|
|
90
|
-
def
|
90
|
+
def auth0_authorize_path
|
91
91
|
query_params = {
|
92
|
-
audience:
|
93
|
-
client_id:
|
92
|
+
audience: sso_config.audience,
|
93
|
+
client_id: sso_config.client_id,
|
94
94
|
response_type: "code",
|
95
95
|
scope: "openid email",
|
96
|
-
redirect_uri: "#{
|
96
|
+
redirect_uri: "#{sso_config.login_uri}?origin=#{session[:previous_request_url]}"
|
97
97
|
}
|
98
98
|
|
99
|
-
"#{
|
99
|
+
"#{sso_config.base_uri}/authorize?#{query_params.to_query}"
|
100
100
|
end
|
101
101
|
end
|
102
102
|
end
|
@@ -5,9 +5,9 @@ require "auth0_rs256_jwt_verifier"
|
|
5
5
|
module NulogySSO
|
6
6
|
class Authenticator
|
7
7
|
ACCESS_TOKEN_VERIFIER = Auth0RS256JWTVerifier.new(
|
8
|
-
issuer: "#{NulogySSO.
|
9
|
-
audience: NulogySSO.
|
10
|
-
jwks_url: "#{NulogySSO.
|
8
|
+
issuer: "#{NulogySSO.sso_config.base_uri}/", # Auth0 requires a backslash on the Issuer
|
9
|
+
audience: NulogySSO.sso_config.audience,
|
10
|
+
jwks_url: "#{NulogySSO.sso_config.base_uri}/.well-known/jwks.json"
|
11
11
|
)
|
12
12
|
|
13
13
|
def initialize(verifier: ACCESS_TOKEN_VERIFIER, find_user_by_email: NulogySSO.find_user_by_email)
|
@@ -15,7 +15,7 @@ module NulogySSO
|
|
15
15
|
@find_user_by_email = find_user_by_email
|
16
16
|
end
|
17
17
|
|
18
|
-
#
|
18
|
+
# Validated the provided JWT, ensuring that an authenticated Auth0 user can be associated to the token and matches an existing app user
|
19
19
|
def validate_token(raw_access_token, on_success:, on_invalid_token:)
|
20
20
|
access_token = decoded_validated_access_token(raw_access_token)
|
21
21
|
|
@@ -16,7 +16,7 @@ module NulogySSO
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def authenticate_sso_user
|
19
|
-
raw_token = cookies[NulogySSO.
|
19
|
+
raw_token = cookies[NulogySSO.sso_cookie_key]
|
20
20
|
return redirect_to nulogy_sso.login_path if raw_token.blank?
|
21
21
|
|
22
22
|
@current_user = Authenticator.new.authenticated_user(raw_token)
|
data/lib/nulogy_sso/engine.rb
CHANGED
@@ -13,8 +13,8 @@ module NulogySSO
|
|
13
13
|
Bundler.require(*Rails.groups)
|
14
14
|
|
15
15
|
config.after_initialize do
|
16
|
-
if NulogySSO.
|
17
|
-
raise "Missing
|
16
|
+
if NulogySSO.sso_config.blank?
|
17
|
+
raise "Missing sso_config config object. Consider using config_for() to load a YAML config file."
|
18
18
|
end
|
19
19
|
|
20
20
|
if NulogySSO.find_user_by_email.blank?
|
@@ -20,9 +20,9 @@ module NulogySSO
|
|
20
20
|
def jwt(email, overrides = {})
|
21
21
|
claim = {
|
22
22
|
NulogySSO::JWT_EMAIL_KEY => email,
|
23
|
-
"iss" => "#{NulogySSO.
|
23
|
+
"iss" => "#{NulogySSO.sso_config.base_uri}/",
|
24
24
|
"sub" => "MOCK",
|
25
|
-
"aud" => [NulogySSO.
|
25
|
+
"aud" => [NulogySSO.sso_config.audience],
|
26
26
|
"exp" => (Time.now + 1.day).to_i
|
27
27
|
}.merge(overrides)
|
28
28
|
|
data/lib/nulogy_sso/version.rb
CHANGED
data/lib/nulogy_sso.rb
CHANGED
@@ -5,23 +5,23 @@ require "immutable-struct"
|
|
5
5
|
|
6
6
|
module NulogySSO
|
7
7
|
# Config variables for the engine
|
8
|
-
mattr_accessor :
|
8
|
+
mattr_accessor :sso_config, :find_user_by_email, :handle_sso_error
|
9
9
|
|
10
10
|
# Public Constants
|
11
11
|
JWT_EMAIL_KEY = "https://nulogy.net/email"
|
12
12
|
|
13
|
-
def self.
|
14
|
-
raise "
|
13
|
+
def self.sso_config=(sso_config_hash)
|
14
|
+
raise "sso_config must be a Hash" unless sso_config_hash.is_a? Hash
|
15
15
|
|
16
|
-
missing_keys =
|
16
|
+
missing_keys = REQUIRED_SSO_CONFIG_KEYS - sso_config_hash.symbolize_keys.keys
|
17
17
|
if missing_keys.present?
|
18
|
-
raise "Missing required
|
18
|
+
raise "Missing required sso_config keys ['#{missing_keys.join("', '")}']"
|
19
19
|
end
|
20
20
|
|
21
|
-
@@
|
21
|
+
@@sso_config = SSOConfig.new(**sso_config_hash.symbolize_keys)
|
22
22
|
end
|
23
23
|
|
24
|
-
|
24
|
+
REQUIRED_SSO_CONFIG_KEYS = %i[
|
25
25
|
audience
|
26
26
|
base_uri
|
27
27
|
client_id
|
@@ -30,11 +30,11 @@ module NulogySSO
|
|
30
30
|
login_uri
|
31
31
|
redirect_uri
|
32
32
|
]
|
33
|
-
private_constant :
|
33
|
+
private_constant :REQUIRED_SSO_CONFIG_KEYS
|
34
34
|
|
35
|
-
|
35
|
+
SSOConfig = ImmutableStruct.new(*REQUIRED_SSO_CONFIG_KEYS)
|
36
36
|
|
37
|
-
def self.
|
38
|
-
"#{
|
37
|
+
def self.sso_cookie_key
|
38
|
+
"#{sso_config.cookie_prefix}_access_token"
|
39
39
|
end
|
40
40
|
end
|
@@ -33,7 +33,7 @@ module Dummy
|
|
33
33
|
|
34
34
|
# Load required NulogySSO config so that the dummy can boot up without error.
|
35
35
|
# These functions are mostly used for testing.
|
36
|
-
NulogySSO.
|
36
|
+
NulogySSO.sso_config = config_for(:sso)
|
37
37
|
NulogySSO.find_user_by_email = ->(email) { User.find_by(email: email) }
|
38
38
|
NulogySSO.handle_sso_error = ->(controller) { controller.render plain: "An SSO error has occurred :(" }
|
39
39
|
end
|
File without changes
|
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
module NulogySSO
|
4
4
|
RSpec.describe Authenticator do
|
5
|
-
let(:
|
5
|
+
let(:sso_config) { NulogySSO.sso_config }
|
6
6
|
let(:verifier) do
|
7
7
|
MockAuth0Verifier.new(
|
8
|
-
issuer: "#{
|
9
|
-
audience:
|
8
|
+
issuer: "#{sso_config.base_uri}/",
|
9
|
+
audience: sso_config.audience,
|
10
10
|
jwks: jwt_test_helper.jwks_json
|
11
11
|
)
|
12
12
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nulogy_sso
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nulogy Corporation
|
@@ -197,7 +197,6 @@ files:
|
|
197
197
|
- spec/dummy/bin/yarn
|
198
198
|
- spec/dummy/config.ru
|
199
199
|
- spec/dummy/config/application.rb
|
200
|
-
- spec/dummy/config/auth_sso.yml
|
201
200
|
- spec/dummy/config/boot.rb
|
202
201
|
- spec/dummy/config/cable.yml
|
203
202
|
- spec/dummy/config/database.yml
|
@@ -217,6 +216,7 @@ files:
|
|
217
216
|
- spec/dummy/config/puma.rb
|
218
217
|
- spec/dummy/config/routes.rb
|
219
218
|
- spec/dummy/config/spring.rb
|
219
|
+
- spec/dummy/config/sso.yml
|
220
220
|
- spec/dummy/config/storage.yml
|
221
221
|
- spec/dummy/db/migrate/20190912211120_create_users.rb
|
222
222
|
- spec/dummy/db/schema.rb
|
@@ -372,9 +372,9 @@ test_files:
|
|
372
372
|
- spec/dummy/bin/yarn
|
373
373
|
- spec/dummy/bin/rails
|
374
374
|
- spec/dummy/config/routes.rb
|
375
|
-
- spec/dummy/config/auth_sso.yml
|
376
375
|
- spec/dummy/config/locales/en.yml
|
377
376
|
- spec/dummy/config/cable.yml
|
377
|
+
- spec/dummy/config/sso.yml
|
378
378
|
- spec/dummy/config/environments/production.rb
|
379
379
|
- spec/dummy/config/environments/development.rb
|
380
380
|
- spec/dummy/config/environments/test.rb
|