clerk-sdk-ruby 4.0.0.beta3 → 4.0.0.beta5
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/.env.example +3 -0
- data/.github/workflows/main.yml +24 -14
- data/.gitignore +7 -1
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +22 -0
- data/Gemfile +26 -3
- data/Gemfile.lock +269 -13
- data/Guardfile +14 -0
- data/README.md +71 -11
- data/Rakefile +50 -6
- data/apps/rack/app.rb +67 -0
- data/apps/rack/config.ru +17 -0
- data/apps/rack/middleware/disable_paths.rb +13 -0
- data/apps/rails-api/.dockerignore +41 -0
- data/apps/rails-api/.gitattributes +9 -0
- data/apps/rails-api/.gitignore +32 -0
- data/apps/rails-api/.kamal/hooks/docker-setup.sample +3 -0
- data/apps/rails-api/.kamal/hooks/post-deploy.sample +14 -0
- data/apps/rails-api/.kamal/hooks/post-proxy-reboot.sample +3 -0
- data/apps/rails-api/.kamal/hooks/pre-build.sample +51 -0
- data/apps/rails-api/.kamal/hooks/pre-connect.sample +47 -0
- data/apps/rails-api/.kamal/hooks/pre-deploy.sample +109 -0
- data/apps/rails-api/.kamal/hooks/pre-proxy-reboot.sample +3 -0
- data/apps/rails-api/.kamal/secrets +17 -0
- data/apps/rails-api/.rubocop.yml +8 -0
- data/apps/rails-api/.ruby-version +1 -0
- data/apps/rails-api/Dockerfile +69 -0
- data/apps/rails-api/Gemfile +54 -0
- data/apps/rails-api/Gemfile.lock +374 -0
- data/apps/rails-api/README.md +24 -0
- data/apps/rails-api/Rakefile +6 -0
- data/apps/rails-api/app/controllers/application_controller.rb +3 -0
- data/apps/rails-api/app/controllers/home_controller.rb +5 -0
- data/apps/rails-api/app/jobs/application_job.rb +7 -0
- data/apps/rails-api/app/mailers/application_mailer.rb +4 -0
- data/apps/rails-api/app/models/application_record.rb +3 -0
- data/apps/rails-api/app/views/layouts/mailer.html.erb +13 -0
- data/apps/rails-api/app/views/layouts/mailer.text.erb +1 -0
- data/apps/rails-api/bin/brakeman +7 -0
- data/apps/rails-api/bin/bundle +109 -0
- data/apps/rails-api/bin/dev +2 -0
- data/apps/rails-api/bin/docker-entrypoint +14 -0
- data/apps/rails-api/bin/jobs +6 -0
- data/apps/rails-api/bin/kamal +27 -0
- data/apps/rails-api/bin/rails +4 -0
- data/apps/rails-api/bin/rake +4 -0
- data/apps/rails-api/bin/rubocop +8 -0
- data/apps/rails-api/bin/setup +34 -0
- data/apps/rails-api/bin/thrust +5 -0
- data/apps/rails-api/config/application.rb +36 -0
- data/apps/rails-api/config/boot.rb +4 -0
- data/apps/rails-api/config/cable.yml +17 -0
- data/apps/rails-api/config/cache.yml +16 -0
- data/apps/rails-api/config/credentials.yml.enc +1 -0
- data/apps/rails-api/config/database.yml +41 -0
- data/apps/rails-api/config/deploy.yml +116 -0
- data/apps/rails-api/config/environment.rb +5 -0
- data/apps/rails-api/config/environments/development.rb +70 -0
- data/apps/rails-api/config/environments/production.rb +88 -0
- data/apps/rails-api/config/environments/test.rb +53 -0
- data/apps/rails-api/config/initializers/cors.rb +16 -0
- data/apps/rails-api/config/initializers/filter_parameter_logging.rb +8 -0
- data/apps/rails-api/config/initializers/inflections.rb +16 -0
- data/apps/rails-api/config/locales/en.yml +31 -0
- data/apps/rails-api/config/puma.rb +41 -0
- data/apps/rails-api/config/queue.yml +18 -0
- data/apps/rails-api/config/recurring.yml +10 -0
- data/apps/rails-api/config/routes.rb +10 -0
- data/apps/rails-api/config/storage.yml +34 -0
- data/apps/rails-api/config.ru +6 -0
- data/apps/rails-api/db/cable_schema.rb +11 -0
- data/apps/rails-api/db/cache_schema.rb +14 -0
- data/apps/rails-api/db/queue_schema.rb +129 -0
- data/apps/rails-api/db/seeds.rb +9 -0
- data/apps/rails-api/public/robots.txt +1 -0
- data/apps/rails-api/test/controllers/home_controller_test.rb +7 -0
- data/apps/rails-api/test/test_helper.rb +15 -0
- data/apps/rails-full/.dockerignore +47 -0
- data/apps/rails-full/.gitattributes +9 -0
- data/apps/rails-full/.gitignore +34 -0
- data/apps/rails-full/.kamal/hooks/docker-setup.sample +3 -0
- data/apps/rails-full/.kamal/hooks/post-deploy.sample +14 -0
- data/apps/rails-full/.kamal/hooks/post-proxy-reboot.sample +3 -0
- data/apps/rails-full/.kamal/hooks/pre-build.sample +51 -0
- data/apps/rails-full/.kamal/hooks/pre-connect.sample +47 -0
- data/apps/rails-full/.kamal/hooks/pre-deploy.sample +109 -0
- data/apps/rails-full/.kamal/hooks/pre-proxy-reboot.sample +3 -0
- data/apps/rails-full/.kamal/secrets +17 -0
- data/apps/rails-full/.rubocop.yml +8 -0
- data/apps/rails-full/.ruby-version +1 -0
- data/apps/rails-full/Dockerfile +72 -0
- data/apps/rails-full/Gemfile +70 -0
- data/apps/rails-full/Gemfile.lock +429 -0
- data/apps/rails-full/README.md +24 -0
- data/apps/rails-full/Rakefile +6 -0
- data/apps/rails-full/app/assets/stylesheets/application.css +10 -0
- data/apps/rails-full/app/controllers/application_controller.rb +6 -0
- data/apps/rails-full/app/controllers/home_controller.rb +11 -0
- data/apps/rails-full/app/helpers/application_helper.rb +2 -0
- data/apps/rails-full/app/helpers/home_helper.rb +2 -0
- data/apps/rails-full/app/javascript/application.js +3 -0
- data/apps/rails-full/app/javascript/controllers/application.js +9 -0
- data/apps/rails-full/app/javascript/controllers/hello_controller.js +7 -0
- data/apps/rails-full/app/javascript/controllers/index.js +4 -0
- data/apps/rails-full/app/jobs/application_job.rb +7 -0
- data/apps/rails-full/app/mailers/application_mailer.rb +4 -0
- data/apps/rails-full/app/models/application_record.rb +3 -0
- data/apps/rails-full/app/views/home/index.html.erb +7 -0
- data/apps/rails-full/app/views/layouts/application.html.erb +60 -0
- data/apps/rails-full/app/views/layouts/mailer.html.erb +13 -0
- data/apps/rails-full/app/views/layouts/mailer.text.erb +1 -0
- data/apps/rails-full/app/views/pwa/manifest.json.erb +22 -0
- data/apps/rails-full/app/views/pwa/service-worker.js +26 -0
- data/apps/rails-full/bin/brakeman +7 -0
- data/apps/rails-full/bin/bundle +109 -0
- data/apps/rails-full/bin/dev +2 -0
- data/apps/rails-full/bin/docker-entrypoint +14 -0
- data/apps/rails-full/bin/importmap +4 -0
- data/apps/rails-full/bin/jobs +6 -0
- data/apps/rails-full/bin/kamal +27 -0
- data/apps/rails-full/bin/rails +4 -0
- data/apps/rails-full/bin/rake +4 -0
- data/apps/rails-full/bin/rubocop +8 -0
- data/apps/rails-full/bin/setup +34 -0
- data/apps/rails-full/bin/thrust +5 -0
- data/apps/rails-full/config/application.rb +31 -0
- data/apps/rails-full/config/boot.rb +4 -0
- data/apps/rails-full/config/cable.yml +17 -0
- data/apps/rails-full/config/cache.yml +16 -0
- data/apps/rails-full/config/credentials.yml.enc +1 -0
- data/apps/rails-full/config/database.yml +41 -0
- data/apps/rails-full/config/deploy.yml +116 -0
- data/apps/rails-full/config/environment.rb +5 -0
- data/apps/rails-full/config/environments/development.rb +72 -0
- data/apps/rails-full/config/environments/production.rb +91 -0
- data/apps/rails-full/config/environments/test.rb +53 -0
- data/apps/rails-full/config/importmap.rb +7 -0
- data/apps/rails-full/config/initializers/assets.rb +7 -0
- data/apps/rails-full/config/initializers/clerk.rb +4 -0
- data/apps/rails-full/config/initializers/content_security_policy.rb +25 -0
- data/apps/rails-full/config/initializers/filter_parameter_logging.rb +8 -0
- data/apps/rails-full/config/initializers/inflections.rb +16 -0
- data/apps/rails-full/config/locales/en.yml +31 -0
- data/apps/rails-full/config/puma.rb +41 -0
- data/apps/rails-full/config/queue.yml +18 -0
- data/apps/rails-full/config/recurring.yml +10 -0
- data/apps/rails-full/config/routes.rb +15 -0
- data/apps/rails-full/config/storage.yml +34 -0
- data/apps/rails-full/config.ru +6 -0
- data/apps/rails-full/db/cable_schema.rb +11 -0
- data/apps/rails-full/db/cache_schema.rb +14 -0
- data/apps/rails-full/db/queue_schema.rb +129 -0
- data/apps/rails-full/db/seeds.rb +9 -0
- data/apps/rails-full/public/400.html +114 -0
- data/apps/rails-full/public/404.html +114 -0
- data/apps/rails-full/public/406-unsupported-browser.html +114 -0
- data/apps/rails-full/public/422.html +114 -0
- data/apps/rails-full/public/500.html +114 -0
- data/apps/rails-full/public/icon.png +0 -0
- data/apps/rails-full/public/icon.svg +3 -0
- data/apps/rails-full/public/robots.txt +1 -0
- data/apps/rails-full/test/application_system_test_case.rb +5 -0
- data/apps/rails-full/test/controllers/home_controller_test.rb +7 -0
- data/apps/rails-full/test/test_helper.rb +15 -0
- data/apps/sinatra/app.rb +29 -0
- data/apps/sinatra/config.ru +2 -0
- data/apps/sinatra/views/index.erb +44 -0
- data/clerk-sdk-ruby.gemspec +2 -1
- data/lib/clerk/authenticatable.rb +14 -79
- data/lib/clerk/authenticate_context.rb +164 -181
- data/lib/clerk/authenticate_request.rb +238 -230
- data/lib/clerk/configuration.rb +78 -0
- data/lib/clerk/constants.rb +68 -46
- data/lib/clerk/error.rb +17 -0
- data/lib/clerk/jwks_cache.rb +27 -22
- data/lib/clerk/proxy.rb +135 -0
- data/lib/clerk/rack.rb +2 -0
- data/lib/clerk/rack_middleware.rb +88 -73
- data/lib/clerk/rails.rb +3 -0
- data/lib/clerk/railtie.rb +7 -6
- data/lib/clerk/sdk.rb +17 -156
- data/lib/clerk/sinatra.rb +52 -0
- data/lib/clerk/utils.rb +46 -6
- data/lib/clerk/version.rb +1 -1
- data/lib/clerk.rb +15 -51
- metadata +187 -25
- data/CODEOWNERS +0 -1
- data/lib/clerk/errors.rb +0 -22
- data/lib/clerk/rack_middleware_v2.rb +0 -167
- data/lib/clerk/resources/allowlist.rb +0 -16
- data/lib/clerk/resources/allowlist_identifiers.rb +0 -16
- data/lib/clerk/resources/clients.rb +0 -23
- data/lib/clerk/resources/email_addresses.rb +0 -17
- data/lib/clerk/resources/emails.rb +0 -16
- data/lib/clerk/resources/jwks.rb +0 -18
- data/lib/clerk/resources/organizations.rb +0 -73
- data/lib/clerk/resources/phone_numbers.rb +0 -17
- data/lib/clerk/resources/plural_resource.rb +0 -38
- data/lib/clerk/resources/sessions.rb +0 -26
- data/lib/clerk/resources/singular_resource.rb +0 -14
- data/lib/clerk/resources/users.rb +0 -37
- data/lib/clerk/resources.rb +0 -10
data/lib/clerk/constants.rb
CHANGED
@@ -1,50 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Clerk
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
4
|
+
SESSION_COOKIE = "__session"
|
5
|
+
CLIENT_UAT_COOKIE = "__client_uat"
|
6
|
+
|
7
|
+
# Dev Browser
|
8
|
+
DEV_BROWSER_COOKIE = "__clerk_db_jwt"
|
9
|
+
|
10
|
+
# Handshake
|
11
|
+
HANDSHAKE_COOKIE = "__clerk_handshake"
|
12
|
+
HANDSHAKE_COOKIE_DIRECTIVES_KEY = "handshake"
|
13
|
+
|
14
|
+
# auth debug response headers
|
15
|
+
AUTH_STATUS_HEADER = "X-Clerk-Auth-Status"
|
16
|
+
AUTH_REASON_HEADER = "X-Clerk-Auth-Reason"
|
17
|
+
AUTH_MESSAGE_HEADER = "X-Clerk-Auth-Message"
|
18
|
+
|
19
|
+
CONTENT_TYPE_HEADER = "Content-Type"
|
20
|
+
SEC_FETCH_DEST_HEADER = "HTTP_SEC_FETCH_DEST"
|
21
|
+
|
22
|
+
# headers used in response - should be lowered case and without http prefix
|
23
|
+
LOCATION_HEADER = "Location"
|
24
|
+
SET_COOKIE_HEADER = "set-cookie"
|
25
|
+
|
26
|
+
# clerk url related headers
|
27
|
+
AUTHORIZATION_HEADER = "HTTP_AUTHORIZATION"
|
28
|
+
ACCEPT_HEADER = "HTTP_ACCEPT"
|
29
|
+
USER_AGENT_HEADER = "HTTP_USER_AGENT"
|
30
|
+
ORIGIN_HEADER = "HTTP_ORIGIN"
|
31
|
+
|
32
|
+
module TokenVerificationErrorReason
|
33
|
+
TOKEN_INVALID = "token-invalid"
|
34
|
+
TOKEN_EXPIRED = "token-expired"
|
35
|
+
TOKEN_NOT_ACTIVE_YET = "token-not-active-yet"
|
36
|
+
JWK_FAILED_TO_RESOLVE = "jwk-failed-to-resolve"
|
37
|
+
end
|
38
|
+
|
39
|
+
module AuthErrorReason
|
40
|
+
CLIENT_UAT_WITHOUT_SESSION_TOKEN = "client-uat-but-no-session-token"
|
41
|
+
DEV_BROWSER_SYNC = "dev-browser-sync"
|
42
|
+
DEV_BROWSER_MISSING = "dev-browser-missing"
|
43
|
+
PRIMARY_RESPONDS_TO_SYNCING = "primary-responds-to-syncing"
|
44
|
+
SATELLITE_COOKIE_NEEDS_SYNCING = "satellite-needs-syncing"
|
45
|
+
SESSION_TOKEN_AND_UAT_MISSING = "session-token-and-uat-missing"
|
46
|
+
SESSION_TOKEN_MISSING = "session-token-missing"
|
47
|
+
SESSION_TOKEN_OUTDATED = "session-token-outdated"
|
48
|
+
SESSION_TOKEN_WITHOUT_CLIENT_UAT = "session-token-but-no-client-uat"
|
49
|
+
UNEXPECTED_ERROR = "unexpected-error"
|
50
|
+
end
|
51
|
+
|
52
|
+
module StepUp
|
53
|
+
module Preset
|
54
|
+
STRICT_MFA = {after_minutes: 10, level: :multi_factor}
|
55
|
+
STRICT = {after_minutes: 10, level: :second_factor}
|
56
|
+
MODERATE = {after_minutes: 60, level: :second_factor}
|
57
|
+
LAX = {after_minutes: 1440, level: :second_factor}
|
37
58
|
end
|
38
59
|
|
39
|
-
module
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
60
|
+
module Reverification
|
61
|
+
def self.error_payload(missing_config)
|
62
|
+
{
|
63
|
+
clerk_error: {
|
64
|
+
type: "forbidden",
|
65
|
+
reason: "reverification-error",
|
66
|
+
metadata: {reverification: missing_config}
|
67
|
+
}
|
68
|
+
}
|
69
|
+
end
|
49
70
|
end
|
50
|
-
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/clerk/error.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Clerk
|
2
|
+
class Error < StandardError
|
3
|
+
attr_reader :status
|
4
|
+
|
5
|
+
def initialize(msg, status:)
|
6
|
+
@errors = msg["errors"]
|
7
|
+
@status = status
|
8
|
+
super(msg.merge(status: status))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class AuthenticationError < Error; end
|
13
|
+
|
14
|
+
class ConfigurationError < StandardError; end
|
15
|
+
|
16
|
+
class FatalError < Error; end
|
17
|
+
end
|
data/lib/clerk/jwks_cache.rb
CHANGED
@@ -1,32 +1,37 @@
|
|
1
|
-
|
2
|
-
def initialize(lifetime)
|
3
|
-
@lifetime = lifetime
|
4
|
-
@jwks = nil
|
5
|
-
@last_update = nil
|
6
|
-
@lock = Concurrent::ReadWriteLock.new
|
7
|
-
end
|
1
|
+
require "concurrent"
|
8
2
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
3
|
+
module Clerk
|
4
|
+
class JWKSCache
|
5
|
+
def initialize(lifetime)
|
6
|
+
@lifetime = lifetime
|
7
|
+
@jwks = nil
|
8
|
+
@last_update = nil
|
9
|
+
@lock = Concurrent::ReadWriteLock.new
|
14
10
|
end
|
15
11
|
|
16
|
-
|
17
|
-
@lock.
|
18
|
-
|
12
|
+
def fetch(sdk, force_refresh: false, kid_not_found: false)
|
13
|
+
should_refresh = @lock.with_read_lock do
|
14
|
+
now = Time.now.to_i
|
15
|
+
|
16
|
+
@jwks.nil? || @last_update.nil? || force_refresh ||
|
17
|
+
(now - @last_update > @lifetime) ||
|
18
|
+
(kid_not_found && now - @last_update > 300)
|
19
|
+
end
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
if should_refresh
|
22
|
+
@lock.with_write_lock do
|
23
|
+
@last_update = Time.now.to_i
|
24
|
+
@jwks = begin
|
25
|
+
sdk.jwks.get_jwks.keys.map(&:to_hash)
|
26
|
+
rescue Clerk::Error, ClerkHttpClient::ApiError
|
27
|
+
nil
|
28
|
+
end
|
24
29
|
end
|
25
30
|
end
|
26
|
-
end
|
27
31
|
|
28
|
-
|
29
|
-
|
32
|
+
@lock.with_read_lock do
|
33
|
+
@jwks
|
34
|
+
end
|
30
35
|
end
|
31
36
|
end
|
32
37
|
end
|
data/lib/clerk/proxy.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
require "clerk"
|
2
|
+
require "clerk/authenticate_context"
|
3
|
+
require "clerk/authenticate_request"
|
4
|
+
|
5
|
+
module Clerk
|
6
|
+
class Proxy
|
7
|
+
CACHE_TTL = 60 # seconds
|
8
|
+
|
9
|
+
attr_reader :session_claims, :session_token
|
10
|
+
|
11
|
+
def initialize(session_claims: nil, session_token: nil)
|
12
|
+
@session_claims = session_claims
|
13
|
+
@session_token = session_token
|
14
|
+
end
|
15
|
+
|
16
|
+
def user?
|
17
|
+
!@session_claims.nil?
|
18
|
+
end
|
19
|
+
|
20
|
+
def user
|
21
|
+
return nil unless user?
|
22
|
+
|
23
|
+
@user ||= fetch_user(user_id)
|
24
|
+
end
|
25
|
+
|
26
|
+
def user_id
|
27
|
+
return nil unless user?
|
28
|
+
|
29
|
+
@session_claims["sub"]
|
30
|
+
end
|
31
|
+
|
32
|
+
def organization?
|
33
|
+
!organization_id.nil?
|
34
|
+
end
|
35
|
+
|
36
|
+
def organization
|
37
|
+
return nil unless organization?
|
38
|
+
|
39
|
+
@org ||= fetch_org(organization_id)
|
40
|
+
end
|
41
|
+
|
42
|
+
def organization_id
|
43
|
+
return nil unless user?
|
44
|
+
|
45
|
+
@session_claims["org_id"]
|
46
|
+
end
|
47
|
+
|
48
|
+
def organization_role
|
49
|
+
return nil if @session_claims.nil?
|
50
|
+
|
51
|
+
@session_claims["org_role"]
|
52
|
+
end
|
53
|
+
|
54
|
+
def organization_permissions
|
55
|
+
return nil if @session_claims.nil?
|
56
|
+
|
57
|
+
@session_claims["org_permissions"]
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns true if the session needs to perform step up verification
|
61
|
+
def user_reverified?(params)
|
62
|
+
return false unless user?
|
63
|
+
|
64
|
+
fva = session_claims["fva"]
|
65
|
+
|
66
|
+
# the feature is disabled
|
67
|
+
return true if fva.nil?
|
68
|
+
|
69
|
+
level = params[:level]
|
70
|
+
after_minutes = params[:after_minutes].to_i
|
71
|
+
|
72
|
+
return false if after_minutes.nil? || level.nil?
|
73
|
+
|
74
|
+
factor1_age, factor2_age = fva
|
75
|
+
is_valid_factor1 = factor1_age != -1 && after_minutes > factor1_age
|
76
|
+
is_valid_factor2 = factor2_age != -1 && after_minutes > factor2_age
|
77
|
+
|
78
|
+
case level
|
79
|
+
when :first_factor
|
80
|
+
is_valid_factor1
|
81
|
+
when :second_factor
|
82
|
+
(factor2_age == -1) ? is_valid_factor1 : is_valid_factor2
|
83
|
+
when :multi_factor
|
84
|
+
(factor2_age == -1) ? is_valid_factor1 : is_valid_factor1 && is_valid_factor2
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def user_needs_reverification?(preset = StepUp::Preset::STRICT)
|
89
|
+
!user_reverified?(preset)
|
90
|
+
end
|
91
|
+
|
92
|
+
def user_require_reverification!(preset = StepUp::Preset::STRICT, &block)
|
93
|
+
return unless user_needs_reverification?(preset)
|
94
|
+
yield(preset) if block_given?
|
95
|
+
end
|
96
|
+
|
97
|
+
def user_reverification_rack_response(config = nil)
|
98
|
+
raise ArgumentError, "Missing config, please pass a preset a la `Clerk::StepUp::Preset::*`" if config.nil?
|
99
|
+
|
100
|
+
[
|
101
|
+
403,
|
102
|
+
{"Content-Type" => "application/json"},
|
103
|
+
[StepUp::Reverification.error_payload(config).to_json]
|
104
|
+
]
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
def fetch_user(user_id)
|
110
|
+
cached_fetch("clerk:user:#{user_id}") do
|
111
|
+
sdk.users.get_user(user_id)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def fetch_org(org_id)
|
116
|
+
cached_fetch("clerk:org:#{org_id}") do
|
117
|
+
sdk.organizations.get_organization(org_id)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def cached_fetch(key, &block)
|
122
|
+
store = Clerk.configuration.cache_store
|
123
|
+
|
124
|
+
if store
|
125
|
+
store.fetch(key, expires_in: CACHE_TTL, &block)
|
126
|
+
else
|
127
|
+
yield
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def sdk
|
132
|
+
@sdk ||= Clerk::SDK.new
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
data/lib/clerk/rack.rb
ADDED
@@ -1,97 +1,112 @@
|
|
1
|
-
|
1
|
+
require "clerk"
|
2
|
+
require "clerk/authenticate_context"
|
3
|
+
require "clerk/authenticate_request"
|
4
|
+
require "clerk/proxy"
|
5
|
+
require "clerk/utils"
|
2
6
|
|
3
7
|
module Clerk
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
+
module Rack
|
9
|
+
class Middleware
|
10
|
+
def initialize(app, options = {})
|
11
|
+
@app = app
|
8
12
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
@app.call(env)
|
13
|
-
end
|
14
|
-
end
|
13
|
+
Clerk.configuration.update(options) if options
|
14
|
+
@excluded_routes, @excluded_routes_wildcards = Clerk::Utils.filter_routes(Clerk.configuration.excluded_routes)
|
15
|
+
end
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
def initialize(env)
|
19
|
-
req = Rack::Request.new(env)
|
20
|
-
@token = req.cookies[SESSION_COOKIE]
|
21
|
-
@session_id = req.params["_clerk_session_id"]
|
22
|
-
@session = nil
|
23
|
-
@user_id = nil
|
24
|
-
@user = nil
|
25
|
-
end
|
17
|
+
def call(env)
|
18
|
+
env["clerk.initialized"] = true
|
26
19
|
|
27
|
-
|
28
|
-
return nil if @token.nil?
|
29
|
-
return @session if @session
|
20
|
+
req = ::Rack::Request.new(env)
|
30
21
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
36
|
-
@session
|
37
|
-
end
|
22
|
+
if @excluded_routes[req.path]
|
23
|
+
env["clerk.excluded_route"] = true
|
24
|
+
return @app.call(env)
|
25
|
+
end
|
38
26
|
|
39
|
-
|
40
|
-
|
41
|
-
|
27
|
+
@excluded_routes_wildcards.each do |route|
|
28
|
+
if req.path.start_with?(route)
|
29
|
+
env["clerk.excluded_route"] = true
|
30
|
+
return @app.call(env)
|
31
|
+
end
|
32
|
+
end
|
42
33
|
|
43
|
-
|
44
|
-
return nil if session.nil?
|
45
|
-
@user ||= fetch_user(user_id)
|
46
|
-
end
|
34
|
+
env["clerk"] = Clerk::Proxy.new
|
47
35
|
|
48
|
-
|
49
|
-
|
50
|
-
[ivar.to_s, instance_variable_get(ivar)]
|
51
|
-
end.to_h
|
52
|
-
end
|
36
|
+
auth_context = AuthenticateContext.new(req, Clerk.configuration)
|
37
|
+
auth_request = AuthenticateRequest.new(auth_context)
|
53
38
|
|
54
|
-
|
55
|
-
def sdk
|
56
|
-
@sdk ||= SDK.new
|
57
|
-
end
|
39
|
+
status, auth_request_headers, body = auth_request.resolve(env)
|
58
40
|
|
59
|
-
|
60
|
-
|
61
|
-
|
41
|
+
return [status, auth_request_headers, body] if status
|
42
|
+
|
43
|
+
status, headers, body = @app.call(env)
|
62
44
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
45
|
+
unless auth_request_headers.empty?
|
46
|
+
# Remove them to avoid overriding existing cookies set in headers by other middlewares
|
47
|
+
auth_request_cookies = auth_request_headers.delete(SET_COOKIE_HEADER.downcase)
|
48
|
+
# merge non-cookie related headers into response headers
|
49
|
+
headers.merge!(auth_request_headers)
|
50
|
+
|
51
|
+
set_cookie_headers!(headers, auth_request_cookies) if auth_request_cookies
|
67
52
|
end
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
53
|
+
|
54
|
+
[status, headers, body]
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def parse_cookie_key(cookie_header)
|
60
|
+
cookie_header.split(";")[0].split("=")[0]
|
61
|
+
end
|
62
|
+
|
63
|
+
def set_cookie_headers!(headers, cookie_headers)
|
64
|
+
cookie_headers.each do |cookie_header|
|
65
|
+
cookie_key = parse_cookie_key(cookie_header)
|
66
|
+
cookie = ::Rack::Utils.parse_cookies_header(cookie_header)
|
67
|
+
cookie_params = convert_http_cookie_to_cookie_setter_params(cookie_key, cookie)
|
68
|
+
::Rack::Utils.set_cookie_header!(headers, cookie_key, cookie_params)
|
75
69
|
end
|
76
70
|
end
|
77
|
-
end
|
78
71
|
|
79
|
-
|
80
|
-
|
81
|
-
|
72
|
+
def convert_http_cookie_to_cookie_setter_params(cookie_key, cookie)
|
73
|
+
# convert cookie to to match cookie setter method params (lowercase symbolized keys with `:value` key)
|
74
|
+
cookie_params = cookie.transform_keys { |k| k.downcase.to_sym }
|
75
|
+
# drop the current cookie name key to avoid polluting the expected cookie params
|
76
|
+
cookie_params[:value] = cookie_params.delete(cookie_key.to_sym)
|
77
|
+
|
78
|
+
# Ensure secure and httponly are set to true if present
|
79
|
+
cookie_params[:secure] = cookie_params.has_key?(:secure)
|
80
|
+
cookie_params[:httponly] = cookie_params.has_key?(:httponly)
|
81
|
+
|
82
|
+
# fix issue with cookie expiration expected to be Date type
|
83
|
+
cookie_params[:expires] = Date.parse(cookie_params[:expires]) if cookie_params[:expires]
|
84
|
+
|
85
|
+
cookie_params
|
82
86
|
end
|
83
87
|
end
|
84
88
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
89
|
+
class Reverification
|
90
|
+
def initialize(app, routes: ["/*"], preset: Clerk::StepUp::Preset::STRICT)
|
91
|
+
@app = app
|
92
|
+
@preset = preset
|
93
|
+
|
94
|
+
@included_routes, @included_routes_wildcards = Clerk::Utils.filter_routes(routes)
|
90
95
|
end
|
91
|
-
end
|
92
96
|
|
93
|
-
|
94
|
-
|
97
|
+
def call(env)
|
98
|
+
raise Clerk::ConfigurationError, "`Clerk::Rack::Reverification` must be initialized after `Clerk::Rack::Middleware`" unless env["clerk.initialized"]
|
99
|
+
return @app.call(env) if env["clerk.excluded_route"]
|
100
|
+
|
101
|
+
req = ::Rack::Request.new(env)
|
102
|
+
valid_route = @included_routes[req.path] || @included_routes_wildcards.any? { |route| req.path.start_with?(route) }
|
103
|
+
|
104
|
+
if valid_route && env["clerk"].user_needs_reverification?(@preset)
|
105
|
+
return env["clerk"].user_reverification_rack_response(@preset)
|
106
|
+
end
|
107
|
+
|
108
|
+
@app.call(env)
|
109
|
+
end
|
95
110
|
end
|
96
111
|
end
|
97
112
|
end
|
data/lib/clerk/rails.rb
ADDED
data/lib/clerk/railtie.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
|
4
|
-
require_relative "rack_middleware_v2"
|
2
|
+
|
3
|
+
require "clerk/rack_middleware"
|
5
4
|
|
6
5
|
module Clerk
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
module Rails
|
7
|
+
class Railtie < ::Rails::Railtie
|
8
|
+
initializer "clerk.configure_rails_initialization" do |app|
|
9
|
+
app.middleware.use Clerk::Rack::Middleware
|
10
|
+
end
|
10
11
|
end
|
11
12
|
end
|
12
13
|
end
|