nulogy_sso 2.6.0 → 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 +0 -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/db/test.sqlite3 +0 -0
- data/spec/dummy/log/test.log +2766 -325
- data/spec/dummy/tmp/local_secret.txt +1 -1
- 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 +32 -23
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/log/development.log +0 -12
- data/spec/feature_spec_helper.rb +0 -44
- data/spec/features/nulogy_sso/sso_login_spec.rb +0 -94
|
@@ -1 +1 @@
|
|
|
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] |
|
|
14
|
-
./spec/unit/services/nulogy_sso/authenticator_spec.rb[1:1:2:2] |
|
|
15
|
-
./spec/unit/services/nulogy_sso/authenticator_spec.rb[1:1:3:1] |
|
|
16
|
-
./spec/unit/services/nulogy_sso/authenticator_spec.rb[1:2:1] |
|
|
17
|
-
./spec/unit/services/nulogy_sso/authenticator_spec.rb[1:2:2] |
|
|
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] |
|
|
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: 2025-
|
|
11
|
+
date: 2025-12-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: auth0
|
|
@@ -31,39 +31,53 @@ 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: '7.
|
|
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: '7.
|
|
77
|
+
version: '7.2'
|
|
64
78
|
- - "<"
|
|
65
79
|
- !ruby/object:Gem::Version
|
|
66
|
-
version: '8.
|
|
80
|
+
version: '8.2'
|
|
67
81
|
- !ruby/object:Gem::Dependency
|
|
68
82
|
name: appraisal
|
|
69
83
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -163,19 +177,19 @@ dependencies:
|
|
|
163
177
|
- !ruby/object:Gem::Version
|
|
164
178
|
version: '3.24'
|
|
165
179
|
- !ruby/object:Gem::Dependency
|
|
166
|
-
name:
|
|
180
|
+
name: puma
|
|
167
181
|
requirement: !ruby/object:Gem::Requirement
|
|
168
182
|
requirements:
|
|
169
183
|
- - "~>"
|
|
170
184
|
- !ruby/object:Gem::Version
|
|
171
|
-
version: '
|
|
185
|
+
version: '7.0'
|
|
172
186
|
type: :development
|
|
173
187
|
prerelease: false
|
|
174
188
|
version_requirements: !ruby/object:Gem::Requirement
|
|
175
189
|
requirements:
|
|
176
190
|
- - "~>"
|
|
177
191
|
- !ruby/object:Gem::Version
|
|
178
|
-
version: '
|
|
192
|
+
version: '7.0'
|
|
179
193
|
description:
|
|
180
194
|
email:
|
|
181
195
|
- engineering@nulogy.com
|
|
@@ -241,11 +255,9 @@ files:
|
|
|
241
255
|
- spec/dummy/config/spring.rb
|
|
242
256
|
- spec/dummy/config/sso.yml
|
|
243
257
|
- spec/dummy/config/storage.yml
|
|
244
|
-
- spec/dummy/db/development.sqlite3
|
|
245
258
|
- spec/dummy/db/migrate/20190912211120_create_users.rb
|
|
246
259
|
- spec/dummy/db/schema.rb
|
|
247
260
|
- spec/dummy/db/test.sqlite3
|
|
248
|
-
- spec/dummy/log/development.log
|
|
249
261
|
- spec/dummy/log/test.log
|
|
250
262
|
- spec/dummy/package.json
|
|
251
263
|
- spec/dummy/public/404.html
|
|
@@ -257,16 +269,16 @@ files:
|
|
|
257
269
|
- spec/dummy/public/robots.txt
|
|
258
270
|
- spec/dummy/tmp/local_secret.txt
|
|
259
271
|
- spec/examples.txt
|
|
260
|
-
- spec/feature_spec_helper.rb
|
|
261
|
-
- spec/features/nulogy_sso/sso_login_spec.rb
|
|
262
272
|
- spec/rails_helper.rb
|
|
263
273
|
- spec/spec_helper.rb
|
|
264
274
|
- spec/support/mock_auth0_verifier.rb
|
|
275
|
+
- spec/system/nulogy_sso/sso_login_spec.rb
|
|
265
276
|
- spec/unit/services/nulogy_sso/authenticator_spec.rb
|
|
266
277
|
- spec/unit/services/nulogy_sso/cookie_token_store_spec.rb
|
|
267
278
|
- spec/unit/services/nulogy_sso/origin_redirector_spec.rb
|
|
268
279
|
homepage: https://nulogy.com
|
|
269
|
-
licenses:
|
|
280
|
+
licenses:
|
|
281
|
+
- MIT
|
|
270
282
|
metadata: {}
|
|
271
283
|
post_install_message:
|
|
272
284
|
rdoc_options: []
|
|
@@ -276,14 +288,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
276
288
|
requirements:
|
|
277
289
|
- - ">="
|
|
278
290
|
- !ruby/object:Gem::Version
|
|
279
|
-
version: '
|
|
291
|
+
version: '3.1'
|
|
280
292
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
281
293
|
requirements:
|
|
282
294
|
- - ">="
|
|
283
295
|
- !ruby/object:Gem::Version
|
|
284
296
|
version: '0'
|
|
285
297
|
requirements: []
|
|
286
|
-
rubygems_version: 3.5.
|
|
298
|
+
rubygems_version: 3.5.22
|
|
287
299
|
signing_key:
|
|
288
300
|
specification_version: 4
|
|
289
301
|
summary: Rails Engine For Nulogy's SSO Integration
|
|
@@ -330,11 +342,9 @@ test_files:
|
|
|
330
342
|
- spec/dummy/config/sso.yml
|
|
331
343
|
- spec/dummy/config/storage.yml
|
|
332
344
|
- spec/dummy/config.ru
|
|
333
|
-
- spec/dummy/db/development.sqlite3
|
|
334
345
|
- spec/dummy/db/migrate/20190912211120_create_users.rb
|
|
335
346
|
- spec/dummy/db/schema.rb
|
|
336
347
|
- spec/dummy/db/test.sqlite3
|
|
337
|
-
- spec/dummy/log/development.log
|
|
338
348
|
- spec/dummy/log/test.log
|
|
339
349
|
- spec/dummy/package.json
|
|
340
350
|
- spec/dummy/public/404.html
|
|
@@ -346,11 +356,10 @@ test_files:
|
|
|
346
356
|
- spec/dummy/public/robots.txt
|
|
347
357
|
- spec/dummy/tmp/local_secret.txt
|
|
348
358
|
- spec/examples.txt
|
|
349
|
-
- spec/feature_spec_helper.rb
|
|
350
|
-
- spec/features/nulogy_sso/sso_login_spec.rb
|
|
351
359
|
- spec/rails_helper.rb
|
|
352
360
|
- spec/spec_helper.rb
|
|
353
361
|
- spec/support/mock_auth0_verifier.rb
|
|
362
|
+
- spec/system/nulogy_sso/sso_login_spec.rb
|
|
354
363
|
- spec/unit/services/nulogy_sso/authenticator_spec.rb
|
|
355
364
|
- spec/unit/services/nulogy_sso/cookie_token_store_spec.rb
|
|
356
365
|
- spec/unit/services/nulogy_sso/origin_redirector_spec.rb
|
|
Binary file
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
[1m[35m (0.7ms)[0m [1m[35mDROP TABLE IF EXISTS "users"[0m
|
|
2
|
-
[1m[35m (0.7ms)[0m [1m[35mCREATE TABLE "users" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "email" varchar, "active" boolean DEFAULT 0 NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL)[0m
|
|
3
|
-
[1m[35m (0.3ms)[0m [1m[35mCREATE TABLE "schema_migrations" ("version" varchar NOT NULL PRIMARY KEY)[0m
|
|
4
|
-
[1m[36mActiveRecord::SchemaMigration Load (0.3ms)[0m [1m[34mSELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC[0m
|
|
5
|
-
[1m[35m (0.1ms)[0m [1m[32mINSERT INTO "schema_migrations" (version) VALUES (20190912211120)[0m
|
|
6
|
-
[1m[35m (0.2ms)[0m [1m[35mCREATE TABLE "ar_internal_metadata" ("key" varchar NOT NULL PRIMARY KEY, "value" varchar, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL)[0m
|
|
7
|
-
[1m[36mActiveRecord::InternalMetadata Load (0.1ms)[0m [1m[34mSELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1[0m [[nil, "environment"]]
|
|
8
|
-
[1m[36mActiveRecord::InternalMetadata Create (0.3ms)[0m [1m[32mINSERT INTO "ar_internal_metadata" ("key", "value", "created_at", "updated_at") VALUES ('environment', 'development', '2024-12-30 15:43:21.538370', '2024-12-30 15:43:21.538373') RETURNING "key"[0m
|
|
9
|
-
[1m[36mActiveRecord::InternalMetadata Load (0.3ms)[0m [1m[34mSELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1[0m [[nil, "environment"]]
|
|
10
|
-
[1m[36mActiveRecord::InternalMetadata Update (0.2ms)[0m [1m[33mUPDATE "ar_internal_metadata" SET "value" = 'test', "updated_at" = '2024-12-30 15:43:21.541149' WHERE "ar_internal_metadata"."key" = 'environment'[0m
|
|
11
|
-
[1m[36mActiveRecord::InternalMetadata Load (0.4ms)[0m [1m[34mSELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1[0m [[nil, "schema_sha1"]]
|
|
12
|
-
[1m[36mActiveRecord::InternalMetadata Create (0.3ms)[0m [1m[32mINSERT INTO "ar_internal_metadata" ("key", "value", "created_at", "updated_at") VALUES ('schema_sha1', '2b01fa59c4c74162736a2cb624389712cfa71fdb', '2024-12-30 15:43:21.543796', '2024-12-30 15:43:21.543798') RETURNING "key"[0m
|
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
|