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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 810c9823ed0e49c273e814699a784e5280d4a52e48c4ccd82dd424cf38ad8912
4
- data.tar.gz: c911aaac0f3755c392214ac800210fe65f60841f37a8b13cc9c851206f572fff
3
+ metadata.gz: 65c090bfda1540bd6e0462e5799cd1214e0c8cdc62d76065870c0d621fef29b9
4
+ data.tar.gz: 421729a511e2e15ea2755da6aceb9c704a4eadcdbf14e56b4b500f12b5f1d4f8
5
5
  SHA512:
6
- metadata.gz: e75ece84b7f7b661467c2dd697f8a80ad51efc81f55272c854d8bb934694fe85dc3da3de45d8b7e02dfca0111820af456b907f9eb0409df2da131b080caa6f43
7
- data.tar.gz: 44ad58428c6962ff6378e34ea3dc1179427dbd4cb77ce761288624dc5385a7fad1553c25327411619cca9f1d3f68b27b0aa9bee8525635065b67f1a193e0bd00
6
+ metadata.gz: 9db89629c700a273ab58e966a6043d1b828eb7eff1d26ce2b4a4d66d97b88d9ff1832309eb6a0c5496f2794cf6284b8add09925362384cd8d1e185a38ec9bd96
7
+ data.tar.gz: c829baf9974ec356a75933bf99e4cc544443188d15cdfe1460c834ce5c1023b63b32141d5d558fd11fc164e59ca897b142c624b77a681f41da9650cbf92cb80b
data/Rakefile CHANGED
@@ -16,9 +16,6 @@ end
16
16
 
17
17
  APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
18
18
  load "rails/tasks/engine.rake"
19
-
20
- load "rails/tasks/statistics.rake"
21
-
22
19
  require "bundler/gem_tasks"
23
20
 
24
21
  require 'rspec/core/rake_task'
@@ -20,7 +20,7 @@ module NulogySSO
20
20
 
21
21
  authenticator.validate_token(
22
22
  raw_access_token,
23
- on_success: method(:on_authentication_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: method(:on_authentication_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(access_token)
70
- token_store.store!(access_token)
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 "auth0_rs256_jwt_verifier"
3
+ require "jwt"
4
+ require "net/http"
5
+ require "json"
4
6
 
5
7
  module NulogySSO
6
8
  class Authenticator
7
- ACCESS_TOKEN_VERIFIER = Auth0RS256JWTVerifier.new(
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
- if raw_access_token.present? && verifier.verify(raw_access_token).valid?
51
- return JSON::JWT.decode(raw_access_token, :skip_verification)
52
- end
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
- nil
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 "json/jwt"
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 is mostly a helpful wrapper around this gem: https://github.com/nov/json-jwt
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
- jwt = JSON::JWT.new(claim)
30
- jwt.header[:kid] = jwk["kid"]
31
- jwt = jwt.sign(private_key, :RS256)
32
- jwt.to_s
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
- base_jwk_params = public_key.to_jwk.to_h
37
- JSON::JWK.new(
38
- base_jwk_params.merge(
39
- x5t: base_jwk_params["kid"],
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
- JSON::JWK::Set.new(jwk).to_json
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
@@ -1,3 +1,3 @@
1
1
  module NulogySSO
2
- VERSION = "2.6.0"
2
+ VERSION = "3.0.0"
3
3
  end
Binary file