nulogy_sso 2.5.1 → 3.0.0
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 +4 -4
- data/Rakefile +3 -3
- data/app/controllers/nulogy_sso/authentication_controller.rb +4 -4
- data/app/services/nulogy_sso/authenticator.rb +51 -6
- data/lib/nulogy_sso/test_utilities/auth0_mock.rb +2 -2
- data/lib/nulogy_sso/test_utilities/jwt_test_helper.rb +26 -12
- data/lib/nulogy_sso/version.rb +1 -1
- data/spec/dummy/config/application.rb +0 -5
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/test.log +2767 -166
- data/spec/dummy/tmp/local_secret.txt +1 -0
- data/spec/examples.txt +22 -22
- data/spec/rails_helper.rb +21 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/support/mock_auth0_verifier.rb +30 -18
- data/spec/system/nulogy_sso/sso_login_spec.rb +92 -0
- metadata +60 -33
- data/spec/dummy/tmp/development_secret.txt +0 -1
- data/spec/feature_spec_helper.rb +0 -44
- data/spec/features/nulogy_sso/sso_login_spec.rb +0 -94
|
@@ -0,0 +1 @@
|
|
|
1
|
+
fbd7ec478b18e938597866d54ece09ed83775658f0b661085699e48972ae2e1aeee86de5babcd5c94d3caa5e38d0da6a5abc2d163b78ac3d28144bfadbd938be
|
data/spec/examples.txt
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
example_id | status | run_time |
|
|
2
2
|
---------------------------------------------------------------- | ------ | --------------- |
|
|
3
|
-
./spec/
|
|
4
|
-
./spec/
|
|
5
|
-
./spec/
|
|
6
|
-
./spec/
|
|
7
|
-
./spec/
|
|
8
|
-
./spec/
|
|
9
|
-
./spec/
|
|
10
|
-
./spec/
|
|
11
|
-
./spec/
|
|
12
|
-
./spec/unit/services/nulogy_sso/authenticator_spec.rb[1:1:1] | passed | 0.
|
|
13
|
-
./spec/unit/services/nulogy_sso/authenticator_spec.rb[1:1:2:1] | passed | 0.
|
|
14
|
-
./spec/unit/services/nulogy_sso/authenticator_spec.rb[1:1:2:2] | passed | 0.
|
|
15
|
-
./spec/unit/services/nulogy_sso/authenticator_spec.rb[1:1:3:1] | passed | 0.
|
|
16
|
-
./spec/unit/services/nulogy_sso/authenticator_spec.rb[1:2:1] | passed | 0.
|
|
17
|
-
./spec/unit/services/nulogy_sso/authenticator_spec.rb[1:2:2] | passed | 0.
|
|
18
|
-
./spec/unit/services/nulogy_sso/authenticator_spec.rb[1:2:3] | passed | 0.
|
|
19
|
-
./spec/unit/services/nulogy_sso/authenticator_spec.rb[1:2:4] | passed | 0.
|
|
20
|
-
./spec/unit/services/nulogy_sso/cookie_token_store_spec.rb[1:1] | passed | 0.
|
|
21
|
-
./spec/unit/services/nulogy_sso/cookie_token_store_spec.rb[1:2] | passed | 0.
|
|
22
|
-
./spec/unit/services/nulogy_sso/cookie_token_store_spec.rb[1:3] | passed | 0.
|
|
23
|
-
./spec/unit/services/nulogy_sso/origin_redirector_spec.rb[1:1:1] | passed | 0.
|
|
24
|
-
./spec/unit/services/nulogy_sso/origin_redirector_spec.rb[1:1:2] | passed | 0.
|
|
3
|
+
./spec/system/nulogy_sso/sso_login_spec.rb[1:1:1] | passed | 0.15002 seconds |
|
|
4
|
+
./spec/system/nulogy_sso/sso_login_spec.rb[1:1:2] | passed | 2.23 seconds |
|
|
5
|
+
./spec/system/nulogy_sso/sso_login_spec.rb[1:1:3] | passed | 0.09708 seconds |
|
|
6
|
+
./spec/system/nulogy_sso/sso_login_spec.rb[1:2:1] | passed | 0.09063 seconds |
|
|
7
|
+
./spec/system/nulogy_sso/sso_login_spec.rb[1:2:2] | passed | 0.22381 seconds |
|
|
8
|
+
./spec/system/nulogy_sso/sso_login_spec.rb[1:2:3] | passed | 0.14889 seconds |
|
|
9
|
+
./spec/system/nulogy_sso/sso_login_spec.rb[1:3:1] | passed | 0.07893 seconds |
|
|
10
|
+
./spec/system/nulogy_sso/sso_login_spec.rb[1:3:2] | passed | 0.16209 seconds |
|
|
11
|
+
./spec/system/nulogy_sso/sso_login_spec.rb[1:3:3] | passed | 0.16081 seconds |
|
|
12
|
+
./spec/unit/services/nulogy_sso/authenticator_spec.rb[1:1:1] | passed | 0.0044 seconds |
|
|
13
|
+
./spec/unit/services/nulogy_sso/authenticator_spec.rb[1:1:2:1] | passed | 0.01292 seconds |
|
|
14
|
+
./spec/unit/services/nulogy_sso/authenticator_spec.rb[1:1:2:2] | passed | 0.0096 seconds |
|
|
15
|
+
./spec/unit/services/nulogy_sso/authenticator_spec.rb[1:1:3:1] | passed | 0.00551 seconds |
|
|
16
|
+
./spec/unit/services/nulogy_sso/authenticator_spec.rb[1:2:1] | passed | 0.0058 seconds |
|
|
17
|
+
./spec/unit/services/nulogy_sso/authenticator_spec.rb[1:2:2] | passed | 0.00512 seconds |
|
|
18
|
+
./spec/unit/services/nulogy_sso/authenticator_spec.rb[1:2:3] | passed | 0.00228 seconds |
|
|
19
|
+
./spec/unit/services/nulogy_sso/authenticator_spec.rb[1:2:4] | passed | 0.00549 seconds |
|
|
20
|
+
./spec/unit/services/nulogy_sso/cookie_token_store_spec.rb[1:1] | passed | 0.00522 seconds |
|
|
21
|
+
./spec/unit/services/nulogy_sso/cookie_token_store_spec.rb[1:2] | passed | 0.00052 seconds |
|
|
22
|
+
./spec/unit/services/nulogy_sso/cookie_token_store_spec.rb[1:3] | passed | 0.00046 seconds |
|
|
23
|
+
./spec/unit/services/nulogy_sso/origin_redirector_spec.rb[1:1:1] | passed | 0.00024 seconds |
|
|
24
|
+
./spec/unit/services/nulogy_sso/origin_redirector_spec.rb[1:1:2] | passed | 0.00014 seconds |
|
data/spec/rails_helper.rb
CHANGED
|
@@ -25,4 +25,25 @@ RSpec.configure do |config|
|
|
|
25
25
|
|
|
26
26
|
# Filter lines from Rails gems in backtraces.
|
|
27
27
|
config.filter_rails_from_backtrace!
|
|
28
|
+
|
|
29
|
+
# Use transactional fixtures for all tests except system tests
|
|
30
|
+
# System tests run in separate threads and need truncation
|
|
31
|
+
config.use_transactional_fixtures = true
|
|
32
|
+
|
|
33
|
+
# Configure system tests to run headless
|
|
34
|
+
config.before(:each, type: :system) do
|
|
35
|
+
driven_by :selenium_chrome_headless
|
|
36
|
+
configure_webmock
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Clean database between system tests
|
|
40
|
+
config.before(:each, type: :system) do
|
|
41
|
+
# Truncate all tables except schema_migrations
|
|
42
|
+
ActiveRecord::Base.connection_pool.with_connection do |conn|
|
|
43
|
+
conn.tables.each do |table|
|
|
44
|
+
next if table == "schema_migrations"
|
|
45
|
+
conn.execute("DELETE FROM #{table}")
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
28
49
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
require 'active_support/testing/time_helpers'
|
|
3
|
+
require 'webmock/rspec'
|
|
3
4
|
|
|
4
5
|
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
|
5
6
|
RSpec.configure do |config|
|
|
@@ -44,3 +45,11 @@ RSpec.configure do |config|
|
|
|
44
45
|
|
|
45
46
|
config.include ActiveSupport::Testing::TimeHelpers
|
|
46
47
|
end
|
|
48
|
+
|
|
49
|
+
def configure_webmock(overrides: [])
|
|
50
|
+
allowed_hosts = (overrides + [ENV["NULOGY_SSO_MOCKSERVER_HOST"]]).compact
|
|
51
|
+
WebMock.disable_net_connect!(
|
|
52
|
+
allow_localhost: true,
|
|
53
|
+
allow: allowed_hosts
|
|
54
|
+
)
|
|
55
|
+
end
|
|
@@ -1,26 +1,38 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
#
|
|
3
|
+
require "jwt"
|
|
4
|
+
require "json"
|
|
5
|
+
|
|
6
|
+
# Mock verifier for testing that uses ruby-jwt with a provided JWKS
|
|
7
7
|
class MockAuth0Verifier
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
issuer: issuer,
|
|
11
|
-
audience: audience,
|
|
12
|
-
jwks_url: "https://do.not.care",
|
|
13
|
-
http: http_stub(jwks)
|
|
14
|
-
)
|
|
8
|
+
VerificationResult = Struct.new(:valid?, :payload) do
|
|
9
|
+
alias_method :valid?, :valid?
|
|
15
10
|
end
|
|
16
11
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
def initialize(issuer:, audience:, jwks:)
|
|
13
|
+
@issuer = issuer
|
|
14
|
+
@audience = audience
|
|
15
|
+
@jwks = JWT::JWK::Set.new(JSON.parse(jwks))
|
|
16
|
+
end
|
|
20
17
|
|
|
21
|
-
def
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
def verify(token)
|
|
19
|
+
begin
|
|
20
|
+
payload, = JWT.decode(
|
|
21
|
+
token,
|
|
22
|
+
nil,
|
|
23
|
+
true,
|
|
24
|
+
{
|
|
25
|
+
jwks: @jwks,
|
|
26
|
+
algorithms: ["RS256"],
|
|
27
|
+
iss: @issuer,
|
|
28
|
+
verify_iss: true,
|
|
29
|
+
aud: @audience,
|
|
30
|
+
verify_aud: true
|
|
31
|
+
}
|
|
32
|
+
)
|
|
33
|
+
VerificationResult.new(true, payload)
|
|
34
|
+
rescue JWT::DecodeError, JWT::InvalidIssuerError, JWT::InvalidAudienceError, JWT::ExpiredSignature, JWT::JWKError
|
|
35
|
+
VerificationResult.new(false, nil)
|
|
36
|
+
end
|
|
25
37
|
end
|
|
26
38
|
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe "SSO login process", type: :system do
|
|
6
|
+
let(:email) { "test@nulogy.com" }
|
|
7
|
+
let(:auth0_mock) {
|
|
8
|
+
NulogySSO::TestUtilities::Auth0Mock.new(
|
|
9
|
+
mockserver_host: ENV.fetch("NULOGY_SSO_MOCKSERVER_HOST", "localhost"),
|
|
10
|
+
mockserver_port: ENV.fetch("NULOGY_SSO_MOCKSERVER_PORT", "1080").to_i
|
|
11
|
+
)
|
|
12
|
+
}
|
|
13
|
+
let(:jwt_test_helper) { NulogySSO::TestUtilities::JwtTestHelper.new }
|
|
14
|
+
|
|
15
|
+
describe "login flow" do
|
|
16
|
+
it "can successfully login" do
|
|
17
|
+
auth0_mock.setup(email: email, redirect_path: "/hello_world")
|
|
18
|
+
create_user
|
|
19
|
+
|
|
20
|
+
visit "/hello_world"
|
|
21
|
+
|
|
22
|
+
expect(page).to have_content("Hello World")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "shows an error page when the user can authorize with Auth0 but not exist in the app" do
|
|
26
|
+
auth0_mock.setup(email: email, redirect_path: "/hello_world")
|
|
27
|
+
|
|
28
|
+
visit "/hello_world"
|
|
29
|
+
|
|
30
|
+
expect(page).to have_content("An SSO error has occurred :(")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "shows an error page when Auth0 throws an error" do
|
|
34
|
+
auth0_mock.setup(email: email, redirect_path: "/hello_world", status_code: 403)
|
|
35
|
+
create_user
|
|
36
|
+
|
|
37
|
+
visit "/hello_world"
|
|
38
|
+
|
|
39
|
+
expect(page).to have_content("An SSO error has occurred :(")
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
shared_examples "JWT authentication" do |endpoint:|
|
|
44
|
+
let!(:user) { create_user }
|
|
45
|
+
|
|
46
|
+
before do
|
|
47
|
+
auth0_mock.mockserver_reset
|
|
48
|
+
auth0_mock.setup_jwks
|
|
49
|
+
|
|
50
|
+
# have to visit an unauthenticated endpoint in order for capybara to have something to have a tab to set the cookie on
|
|
51
|
+
visit "/robots.txt"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "allows a user with a valid JWT to visit a secured endpoint" do
|
|
55
|
+
set_access_token_cookie(jwt_test_helper.jwt(email))
|
|
56
|
+
|
|
57
|
+
visit endpoint
|
|
58
|
+
|
|
59
|
+
expect(page).to have_content("Hello World")
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "prevents sessions with invalid JWTs from accessing secured endpoints" do
|
|
63
|
+
set_access_token_cookie(jwt_test_helper.jwt(email, "exp" => (Time.now - 1.day).to_i))
|
|
64
|
+
|
|
65
|
+
visit endpoint
|
|
66
|
+
|
|
67
|
+
expect(current_path).to eq("/authorize")
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "prevents sessions with no JWT from accessing secured endpoints" do
|
|
71
|
+
visit endpoint
|
|
72
|
+
|
|
73
|
+
expect(current_path).to eq("/authorize")
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def set_access_token_cookie(token)
|
|
77
|
+
page.driver.browser.manage.add_cookie(name: NulogySSO.sso_cookie_key, value: token)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
describe "web app authentication" do
|
|
82
|
+
include_examples "JWT authentication", endpoint: "/hello_world"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
describe "API authentication" do
|
|
86
|
+
include_examples "JWT authentication", endpoint: "/api_endpoint"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def create_user
|
|
90
|
+
User.create!(email: email)
|
|
91
|
+
end
|
|
92
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: nulogy_sso
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 3.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nulogy Corporation
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2025-12-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: auth0
|
|
@@ -31,137 +31,165 @@ dependencies:
|
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
32
|
version: '5.5'
|
|
33
33
|
- !ruby/object:Gem::Dependency
|
|
34
|
-
name:
|
|
34
|
+
name: base64
|
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: 0.0
|
|
39
|
+
version: 0.3.0
|
|
40
40
|
type: :runtime
|
|
41
41
|
prerelease: false
|
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
|
43
43
|
requirements:
|
|
44
44
|
- - "~>"
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
|
-
version: 0.0
|
|
46
|
+
version: 0.3.0
|
|
47
|
+
- !ruby/object:Gem::Dependency
|
|
48
|
+
name: jwt
|
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '2.10'
|
|
54
|
+
type: :runtime
|
|
55
|
+
prerelease: false
|
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '2.10'
|
|
47
61
|
- !ruby/object:Gem::Dependency
|
|
48
62
|
name: rails
|
|
49
63
|
requirement: !ruby/object:Gem::Requirement
|
|
50
64
|
requirements:
|
|
51
65
|
- - ">="
|
|
52
66
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: '
|
|
67
|
+
version: '7.2'
|
|
54
68
|
- - "<"
|
|
55
69
|
- !ruby/object:Gem::Version
|
|
56
|
-
version: '8.
|
|
70
|
+
version: '8.2'
|
|
57
71
|
type: :runtime
|
|
58
72
|
prerelease: false
|
|
59
73
|
version_requirements: !ruby/object:Gem::Requirement
|
|
60
74
|
requirements:
|
|
61
75
|
- - ">="
|
|
62
76
|
- !ruby/object:Gem::Version
|
|
63
|
-
version: '
|
|
77
|
+
version: '7.2'
|
|
64
78
|
- - "<"
|
|
65
79
|
- !ruby/object:Gem::Version
|
|
66
|
-
version: '8.
|
|
80
|
+
version: '8.2'
|
|
81
|
+
- !ruby/object:Gem::Dependency
|
|
82
|
+
name: appraisal
|
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
|
84
|
+
requirements:
|
|
85
|
+
- - "~>"
|
|
86
|
+
- !ruby/object:Gem::Version
|
|
87
|
+
version: '2.5'
|
|
88
|
+
type: :development
|
|
89
|
+
prerelease: false
|
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
91
|
+
requirements:
|
|
92
|
+
- - "~>"
|
|
93
|
+
- !ruby/object:Gem::Version
|
|
94
|
+
version: '2.5'
|
|
67
95
|
- !ruby/object:Gem::Dependency
|
|
68
96
|
name: capybara
|
|
69
97
|
requirement: !ruby/object:Gem::Requirement
|
|
70
98
|
requirements:
|
|
71
99
|
- - "~>"
|
|
72
100
|
- !ruby/object:Gem::Version
|
|
73
|
-
version: '3.
|
|
101
|
+
version: '3.40'
|
|
74
102
|
type: :development
|
|
75
103
|
prerelease: false
|
|
76
104
|
version_requirements: !ruby/object:Gem::Requirement
|
|
77
105
|
requirements:
|
|
78
106
|
- - "~>"
|
|
79
107
|
- !ruby/object:Gem::Version
|
|
80
|
-
version: '3.
|
|
108
|
+
version: '3.40'
|
|
81
109
|
- !ruby/object:Gem::Dependency
|
|
82
110
|
name: dotenv-rails
|
|
83
111
|
requirement: !ruby/object:Gem::Requirement
|
|
84
112
|
requirements:
|
|
85
113
|
- - "~>"
|
|
86
114
|
- !ruby/object:Gem::Version
|
|
87
|
-
version: '
|
|
115
|
+
version: '3.1'
|
|
88
116
|
type: :development
|
|
89
117
|
prerelease: false
|
|
90
118
|
version_requirements: !ruby/object:Gem::Requirement
|
|
91
119
|
requirements:
|
|
92
120
|
- - "~>"
|
|
93
121
|
- !ruby/object:Gem::Version
|
|
94
|
-
version: '
|
|
122
|
+
version: '3.1'
|
|
95
123
|
- !ruby/object:Gem::Dependency
|
|
96
124
|
name: rspec-rails
|
|
97
125
|
requirement: !ruby/object:Gem::Requirement
|
|
98
126
|
requirements:
|
|
99
127
|
- - "~>"
|
|
100
128
|
- !ruby/object:Gem::Version
|
|
101
|
-
version: '
|
|
129
|
+
version: '7.1'
|
|
102
130
|
type: :development
|
|
103
131
|
prerelease: false
|
|
104
132
|
version_requirements: !ruby/object:Gem::Requirement
|
|
105
133
|
requirements:
|
|
106
134
|
- - "~>"
|
|
107
135
|
- !ruby/object:Gem::Version
|
|
108
|
-
version: '
|
|
136
|
+
version: '7.1'
|
|
109
137
|
- !ruby/object:Gem::Dependency
|
|
110
138
|
name: selenium-webdriver
|
|
111
139
|
requirement: !ruby/object:Gem::Requirement
|
|
112
140
|
requirements:
|
|
113
141
|
- - "~>"
|
|
114
142
|
- !ruby/object:Gem::Version
|
|
115
|
-
version: '
|
|
143
|
+
version: '4.27'
|
|
116
144
|
type: :development
|
|
117
145
|
prerelease: false
|
|
118
146
|
version_requirements: !ruby/object:Gem::Requirement
|
|
119
147
|
requirements:
|
|
120
148
|
- - "~>"
|
|
121
149
|
- !ruby/object:Gem::Version
|
|
122
|
-
version: '
|
|
150
|
+
version: '4.27'
|
|
123
151
|
- !ruby/object:Gem::Dependency
|
|
124
152
|
name: sqlite3
|
|
125
153
|
requirement: !ruby/object:Gem::Requirement
|
|
126
154
|
requirements:
|
|
127
155
|
- - "~>"
|
|
128
156
|
- !ruby/object:Gem::Version
|
|
129
|
-
version: '
|
|
157
|
+
version: '2.5'
|
|
130
158
|
type: :development
|
|
131
159
|
prerelease: false
|
|
132
160
|
version_requirements: !ruby/object:Gem::Requirement
|
|
133
161
|
requirements:
|
|
134
162
|
- - "~>"
|
|
135
163
|
- !ruby/object:Gem::Version
|
|
136
|
-
version: '
|
|
164
|
+
version: '2.5'
|
|
137
165
|
- !ruby/object:Gem::Dependency
|
|
138
166
|
name: webmock
|
|
139
167
|
requirement: !ruby/object:Gem::Requirement
|
|
140
168
|
requirements:
|
|
141
169
|
- - "~>"
|
|
142
170
|
- !ruby/object:Gem::Version
|
|
143
|
-
version: '3.
|
|
171
|
+
version: '3.24'
|
|
144
172
|
type: :development
|
|
145
173
|
prerelease: false
|
|
146
174
|
version_requirements: !ruby/object:Gem::Requirement
|
|
147
175
|
requirements:
|
|
148
176
|
- - "~>"
|
|
149
177
|
- !ruby/object:Gem::Version
|
|
150
|
-
version: '3.
|
|
178
|
+
version: '3.24'
|
|
151
179
|
- !ruby/object:Gem::Dependency
|
|
152
|
-
name:
|
|
180
|
+
name: puma
|
|
153
181
|
requirement: !ruby/object:Gem::Requirement
|
|
154
182
|
requirements:
|
|
155
183
|
- - "~>"
|
|
156
184
|
- !ruby/object:Gem::Version
|
|
157
|
-
version: '
|
|
185
|
+
version: '7.0'
|
|
158
186
|
type: :development
|
|
159
187
|
prerelease: false
|
|
160
188
|
version_requirements: !ruby/object:Gem::Requirement
|
|
161
189
|
requirements:
|
|
162
190
|
- - "~>"
|
|
163
191
|
- !ruby/object:Gem::Version
|
|
164
|
-
version: '
|
|
192
|
+
version: '7.0'
|
|
165
193
|
description:
|
|
166
194
|
email:
|
|
167
195
|
- engineering@nulogy.com
|
|
@@ -239,18 +267,18 @@ files:
|
|
|
239
267
|
- spec/dummy/public/apple-touch-icon.png
|
|
240
268
|
- spec/dummy/public/favicon.ico
|
|
241
269
|
- spec/dummy/public/robots.txt
|
|
242
|
-
- spec/dummy/tmp/
|
|
270
|
+
- spec/dummy/tmp/local_secret.txt
|
|
243
271
|
- spec/examples.txt
|
|
244
|
-
- spec/feature_spec_helper.rb
|
|
245
|
-
- spec/features/nulogy_sso/sso_login_spec.rb
|
|
246
272
|
- spec/rails_helper.rb
|
|
247
273
|
- spec/spec_helper.rb
|
|
248
274
|
- spec/support/mock_auth0_verifier.rb
|
|
275
|
+
- spec/system/nulogy_sso/sso_login_spec.rb
|
|
249
276
|
- spec/unit/services/nulogy_sso/authenticator_spec.rb
|
|
250
277
|
- spec/unit/services/nulogy_sso/cookie_token_store_spec.rb
|
|
251
278
|
- spec/unit/services/nulogy_sso/origin_redirector_spec.rb
|
|
252
279
|
homepage: https://nulogy.com
|
|
253
|
-
licenses:
|
|
280
|
+
licenses:
|
|
281
|
+
- MIT
|
|
254
282
|
metadata: {}
|
|
255
283
|
post_install_message:
|
|
256
284
|
rdoc_options: []
|
|
@@ -260,14 +288,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
260
288
|
requirements:
|
|
261
289
|
- - ">="
|
|
262
290
|
- !ruby/object:Gem::Version
|
|
263
|
-
version: '
|
|
291
|
+
version: '3.1'
|
|
264
292
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
265
293
|
requirements:
|
|
266
294
|
- - ">="
|
|
267
295
|
- !ruby/object:Gem::Version
|
|
268
296
|
version: '0'
|
|
269
297
|
requirements: []
|
|
270
|
-
rubygems_version: 3.
|
|
298
|
+
rubygems_version: 3.5.22
|
|
271
299
|
signing_key:
|
|
272
300
|
specification_version: 4
|
|
273
301
|
summary: Rails Engine For Nulogy's SSO Integration
|
|
@@ -326,13 +354,12 @@ test_files:
|
|
|
326
354
|
- spec/dummy/public/apple-touch-icon.png
|
|
327
355
|
- spec/dummy/public/favicon.ico
|
|
328
356
|
- spec/dummy/public/robots.txt
|
|
329
|
-
- spec/dummy/tmp/
|
|
357
|
+
- spec/dummy/tmp/local_secret.txt
|
|
330
358
|
- spec/examples.txt
|
|
331
|
-
- spec/feature_spec_helper.rb
|
|
332
|
-
- spec/features/nulogy_sso/sso_login_spec.rb
|
|
333
359
|
- spec/rails_helper.rb
|
|
334
360
|
- spec/spec_helper.rb
|
|
335
361
|
- spec/support/mock_auth0_verifier.rb
|
|
362
|
+
- spec/system/nulogy_sso/sso_login_spec.rb
|
|
336
363
|
- spec/unit/services/nulogy_sso/authenticator_spec.rb
|
|
337
364
|
- spec/unit/services/nulogy_sso/cookie_token_store_spec.rb
|
|
338
365
|
- spec/unit/services/nulogy_sso/origin_redirector_spec.rb
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
ab92fd0ece8b30044343553f055464ba07c174e3aff5891025f0160b9e6134b1c77cc8e2acff77f8e6b50969505afb86b5795ea6cfedae93b0700ee7eacc5f39
|
data/spec/feature_spec_helper.rb
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "rails_helper"
|
|
4
|
-
require "capybara/rspec"
|
|
5
|
-
require "webmock/rspec"
|
|
6
|
-
require "resolv"
|
|
7
|
-
require "socket"
|
|
8
|
-
|
|
9
|
-
def configure_webmock(overrides: [])
|
|
10
|
-
allowed_hosts = (overrides + [ENV["NULOGY_SSO_MOCKSERVER_HOST"]]).compact
|
|
11
|
-
WebMock.disable_net_connect!(
|
|
12
|
-
allow_localhost: true,
|
|
13
|
-
allow: allowed_hosts
|
|
14
|
-
)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
Capybara.server = :webrick
|
|
18
|
-
|
|
19
|
-
if ENV["REMOTE_SELENIUM_HOST"].present?
|
|
20
|
-
ip = Socket.ip_address_list.detect(&:ipv4_private?)
|
|
21
|
-
rails_server_host = ip.ip_address
|
|
22
|
-
remote_selenium_host = Resolv.getaddress(ENV.fetch("REMOTE_SELENIUM_HOST"))
|
|
23
|
-
remote_selenium_port = ENV.fetch("REMOTE_SELENIUM_PORT")
|
|
24
|
-
|
|
25
|
-
Capybara.register_driver :remote do |app|
|
|
26
|
-
Capybara.server_host = rails_server_host
|
|
27
|
-
Capybara::Selenium::Driver.new(
|
|
28
|
-
app,
|
|
29
|
-
browser: :remote,
|
|
30
|
-
url: "http://#{remote_selenium_host}:#{remote_selenium_port}/wd/hub",
|
|
31
|
-
desired_capabilities: :chrome
|
|
32
|
-
)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
Capybara.javascript_driver = :remote
|
|
36
|
-
configure_webmock(overrides: [rails_server_host, remote_selenium_host])
|
|
37
|
-
else
|
|
38
|
-
Capybara.javascript_driver = :selenium_chrome
|
|
39
|
-
configure_webmock
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
RSpec.configure do |config|
|
|
43
|
-
config.use_transactional_fixtures = true
|
|
44
|
-
end
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "feature_spec_helper"
|
|
4
|
-
|
|
5
|
-
module NulogySSO
|
|
6
|
-
RSpec.describe "the SSO login process", type: :feature, js: true do
|
|
7
|
-
let(:email) { "test@nulogy.com" }
|
|
8
|
-
let(:auth0_mock) {
|
|
9
|
-
TestUtilities::Auth0Mock.new(
|
|
10
|
-
mockserver_host: ENV.fetch("NULOGY_SSO_MOCKSERVER_HOST", "localhost"),
|
|
11
|
-
mockserver_port: ENV.fetch("NULOGY_SSO_MOCKSERVER_PORT", 1080)
|
|
12
|
-
)
|
|
13
|
-
}
|
|
14
|
-
let(:jwt_test_helper) { TestUtilities::JwtTestHelper.new }
|
|
15
|
-
|
|
16
|
-
describe "login flow" do
|
|
17
|
-
it "can successfully login" do
|
|
18
|
-
auth0_mock.setup(email: email, redirect_path: "/hello_world")
|
|
19
|
-
create_user
|
|
20
|
-
|
|
21
|
-
visit "/hello_world"
|
|
22
|
-
|
|
23
|
-
expect(page).to have_content("Hello World")
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
it "shows an error page when the user can authorize with Auth0 but not exist in the app" do
|
|
27
|
-
auth0_mock.setup(email: email, redirect_path: "/hello_world")
|
|
28
|
-
|
|
29
|
-
visit "/hello_world"
|
|
30
|
-
|
|
31
|
-
expect(page).to have_content("An SSO error has occurred :(")
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
it "shows an error page when Auth0 throws an error" do
|
|
35
|
-
auth0_mock.setup(email: email, redirect_path: "/hello_world", status_code: 403)
|
|
36
|
-
create_user
|
|
37
|
-
|
|
38
|
-
visit "/hello_world"
|
|
39
|
-
|
|
40
|
-
expect(page).to have_content("An SSO error has occurred :(")
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
shared_examples "JWT authentication" do |endpoint:|
|
|
45
|
-
let!(:user) { create_user }
|
|
46
|
-
|
|
47
|
-
before do
|
|
48
|
-
auth0_mock.mockserver_reset
|
|
49
|
-
auth0_mock.setup_jwks
|
|
50
|
-
|
|
51
|
-
# have to visit an unauthenticated endpoint in order for capybara to have something to have a tab to set the cookie on
|
|
52
|
-
visit "/robots.txt"
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
it "allows a user with a valid JWT to visit a secured endpoint" do
|
|
56
|
-
set_access_token_cookie(jwt_test_helper.jwt(email))
|
|
57
|
-
|
|
58
|
-
visit endpoint
|
|
59
|
-
|
|
60
|
-
expect(page).to have_content("Hello World")
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
it "prevents sessions with invalid JWTs from accessing secured endpoints" do
|
|
64
|
-
set_access_token_cookie(jwt_test_helper.jwt(email, "exp" => (Time.now - 1.day).to_i))
|
|
65
|
-
|
|
66
|
-
visit endpoint
|
|
67
|
-
|
|
68
|
-
expect(current_path).to eq("/authorize")
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
it "prevents sessions with no JWT from accessing secured endpoints" do
|
|
72
|
-
visit endpoint
|
|
73
|
-
|
|
74
|
-
expect(current_path).to eq("/authorize")
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def set_access_token_cookie(token)
|
|
78
|
-
page.driver.browser.manage.add_cookie(name: NulogySSO.sso_cookie_key, value: token)
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
describe "web app authentication" do
|
|
83
|
-
include_examples "JWT authentication", endpoint: "/hello_world"
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
describe "API authentication" do
|
|
87
|
-
include_examples "JWT authentication", endpoint: "/api_endpoint"
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def create_user
|
|
91
|
-
User.create!(email: email)
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
end
|