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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 65c090bfda1540bd6e0462e5799cd1214e0c8cdc62d76065870c0d621fef29b9
|
|
4
|
+
data.tar.gz: 421729a511e2e15ea2755da6aceb9c704a4eadcdbf14e56b4b500f12b5f1d4f8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9db89629c700a273ab58e966a6043d1b828eb7eff1d26ce2b4a4d66d97b88d9ff1832309eb6a0c5496f2794cf6284b8add09925362384cd8d1e185a38ec9bd96
|
|
7
|
+
data.tar.gz: c829baf9974ec356a75933bf99e4cc544443188d15cdfe1460c834ce5c1023b63b32141d5d558fd11fc164e59ca897b142c624b77a681f41da9650cbf92cb80b
|
data/Rakefile
CHANGED
|
@@ -20,7 +20,7 @@ module NulogySSO
|
|
|
20
20
|
|
|
21
21
|
authenticator.validate_token(
|
|
22
22
|
raw_access_token,
|
|
23
|
-
on_success:
|
|
23
|
+
on_success: ->(_decoded_token) { on_authentication_success(raw_access_token) },
|
|
24
24
|
on_invalid_token: ->(_e) { redirect_to auth0_authorize_path, allow_other_host: true }
|
|
25
25
|
)
|
|
26
26
|
end
|
|
@@ -35,7 +35,7 @@ module NulogySSO
|
|
|
35
35
|
|
|
36
36
|
authenticator.validate_token(
|
|
37
37
|
raw_access_token,
|
|
38
|
-
on_success:
|
|
38
|
+
on_success: ->(_decoded_token) { on_authentication_success(raw_access_token) },
|
|
39
39
|
on_invalid_token: ->(e) { sso_error(e) }
|
|
40
40
|
)
|
|
41
41
|
end
|
|
@@ -66,8 +66,8 @@ module NulogySSO
|
|
|
66
66
|
@token_store ||= CookieTokenStore.new(request, response)
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
-
def on_authentication_success(
|
|
70
|
-
token_store.store!(
|
|
69
|
+
def on_authentication_success(raw_access_token)
|
|
70
|
+
token_store.store!(raw_access_token)
|
|
71
71
|
|
|
72
72
|
redirect_to(params["origin"].presence || sso_config.redirect_uri, allow_other_host: true)
|
|
73
73
|
end
|
|
@@ -1,10 +1,54 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "
|
|
3
|
+
require "jwt"
|
|
4
|
+
require "net/http"
|
|
5
|
+
require "json"
|
|
4
6
|
|
|
5
7
|
module NulogySSO
|
|
6
8
|
class Authenticator
|
|
7
|
-
|
|
9
|
+
# Verifier class that uses ruby-jwt for JWT verification with JWKS support
|
|
10
|
+
class JWTVerifier
|
|
11
|
+
VerificationResult = Struct.new(:valid?, :payload) do
|
|
12
|
+
alias_method :valid?, :valid?
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def initialize(issuer:, audience:, jwks_url:)
|
|
16
|
+
@issuer = issuer
|
|
17
|
+
@audience = audience
|
|
18
|
+
@jwks_url = jwks_url
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def verify(token)
|
|
22
|
+
begin
|
|
23
|
+
jwks = fetch_jwks
|
|
24
|
+
payload, = JWT.decode(
|
|
25
|
+
token,
|
|
26
|
+
nil,
|
|
27
|
+
true,
|
|
28
|
+
{
|
|
29
|
+
jwks: jwks,
|
|
30
|
+
algorithms: ["RS256"],
|
|
31
|
+
iss: @issuer,
|
|
32
|
+
verify_iss: true,
|
|
33
|
+
aud: @audience,
|
|
34
|
+
verify_aud: true
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
VerificationResult.new(true, payload)
|
|
38
|
+
rescue JWT::DecodeError, JWT::InvalidIssuerError, JWT::InvalidAudienceError, JWT::ExpiredSignature, JWT::JWKError
|
|
39
|
+
VerificationResult.new(false, nil)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def fetch_jwks
|
|
46
|
+
jwks_hash = JSON.parse(Net::HTTP.get(URI(@jwks_url)))
|
|
47
|
+
JWT::JWK::Set.new(jwks_hash)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
ACCESS_TOKEN_VERIFIER = JWTVerifier.new(
|
|
8
52
|
issuer: "#{NulogySSO.sso_config.base_uri}/", # Auth0 requires a backslash on the Issuer
|
|
9
53
|
audience: NulogySSO.sso_config.audience,
|
|
10
54
|
jwks_url: "#{NulogySSO.sso_config.base_uri}/.well-known/jwks.json"
|
|
@@ -47,11 +91,12 @@ module NulogySSO
|
|
|
47
91
|
attr_reader :verifier, :find_user_by_email
|
|
48
92
|
|
|
49
93
|
def decoded_validated_access_token(raw_access_token)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
94
|
+
return nil unless raw_access_token.present?
|
|
95
|
+
|
|
96
|
+
verification_result = verifier.verify(raw_access_token)
|
|
97
|
+
return nil unless verification_result.valid?
|
|
53
98
|
|
|
54
|
-
|
|
99
|
+
verification_result.payload
|
|
55
100
|
end
|
|
56
101
|
|
|
57
102
|
def fetch_user(access_token)
|
|
@@ -9,8 +9,8 @@ module NulogySSO
|
|
|
9
9
|
class Auth0Mock
|
|
10
10
|
def initialize(
|
|
11
11
|
engine_path: "/nulogy_sso",
|
|
12
|
-
mockserver_host: ENV.fetch("NULOGY_SSO_MOCKSERVER_HOST"),
|
|
13
|
-
mockserver_port: ENV.fetch("NULOGY_SSO_MOCKSERVER_PORT")
|
|
12
|
+
mockserver_host: ENV.fetch("NULOGY_SSO_MOCKSERVER_HOST", "localhost"),
|
|
13
|
+
mockserver_port: ENV.fetch("NULOGY_SSO_MOCKSERVER_PORT", "1080").to_i
|
|
14
14
|
)
|
|
15
15
|
@jwt_test_helper = NulogySSO::TestUtilities::JwtTestHelper.new
|
|
16
16
|
@engine_path = engine_path
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "
|
|
3
|
+
require "jwt"
|
|
4
|
+
require "base64"
|
|
4
5
|
|
|
5
6
|
module NulogySSO
|
|
6
7
|
module TestUtilities
|
|
7
8
|
|
|
8
9
|
# Test utilities that revolve around the JWT (JSON Web Token) protocool.
|
|
9
|
-
# This class
|
|
10
|
+
# This class uses ruby-jwt (https://github.com/jwt/ruby-jwt) for JWT operations
|
|
10
11
|
class JwtTestHelper
|
|
11
12
|
def initialize
|
|
12
13
|
@private_key = OpenSSL::PKey::RSA.new(
|
|
@@ -26,26 +27,39 @@ module NulogySSO
|
|
|
26
27
|
"exp" => (Time.now + 1.day).to_i
|
|
27
28
|
}.merge(overrides)
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
# Get the kid from the JWK
|
|
31
|
+
jwk_hash = jwk.export
|
|
32
|
+
kid = jwk_hash[:kid] || jwk_hash["kid"]
|
|
33
|
+
|
|
34
|
+
JWT.encode(claim, private_key, "RS256", { kid: kid })
|
|
33
35
|
end
|
|
34
36
|
|
|
35
37
|
def jwk
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
# Create JWK from public key
|
|
39
|
+
base_jwk = JWT::JWK.new(public_key)
|
|
40
|
+
base_jwk_hash = base_jwk.export
|
|
41
|
+
kid = base_jwk_hash[:kid] || base_jwk_hash["kid"]
|
|
42
|
+
|
|
43
|
+
# Create JWK with additional parameters for Auth0 compatibility
|
|
44
|
+
JWT::JWK.new(
|
|
45
|
+
public_key,
|
|
46
|
+
{
|
|
47
|
+
kid: kid,
|
|
40
48
|
alg: "RS256",
|
|
41
49
|
use: "sig",
|
|
50
|
+
x5t: kid,
|
|
42
51
|
x5c: [certificate_der]
|
|
43
|
-
|
|
52
|
+
}
|
|
44
53
|
)
|
|
45
54
|
end
|
|
46
55
|
|
|
47
56
|
def jwks_json
|
|
48
|
-
|
|
57
|
+
# Export the single JWK and wrap it in a keys array for JWKS format
|
|
58
|
+
jwk_hash = jwk.export
|
|
59
|
+
# Convert symbol keys to strings for JSON serialization if needed
|
|
60
|
+
jwk_hash = jwk_hash.transform_keys(&:to_s) if jwk_hash.is_a?(Hash) && jwk_hash.keys.first.is_a?(Symbol)
|
|
61
|
+
|
|
62
|
+
{ keys: [jwk_hash] }.to_json
|
|
49
63
|
end
|
|
50
64
|
|
|
51
65
|
private
|
data/lib/nulogy_sso/version.rb
CHANGED
data/spec/dummy/db/test.sqlite3
CHANGED
|
Binary file
|