add_auth 0.3.0 → 0.5.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/CHANGELOG.md +27 -0
- data/README.md +61 -9
- data/ROADMAP.md +43 -31
- data/SECURITY.md +7 -1
- data/app/controllers/add_auth/accounts_controller.rb +10 -2
- data/app/controllers/add_auth/reauthentications_controller.rb +5 -0
- data/app/controllers/add_auth/sessions_controller.rb +1 -1
- data/app/views/add_auth/accounts/_register.html.erb +1 -1
- data/app/views/add_auth/accounts/_request.html.erb +3 -0
- data/lib/add_auth/configuration.rb +2 -2
- data/lib/add_auth/core/account_lifecycle.rb +51 -7
- data/lib/add_auth/core/account_policy.rb +21 -3
- data/lib/add_auth/core/session_cursor.rb +38 -0
- data/lib/add_auth/core/session_key.rb +32 -0
- data/lib/add_auth/core/sessions.rb +19 -8
- data/lib/add_auth/rails/authentication_pages.rb +1 -1
- data/lib/add_auth/rails/doctor.rb +10 -3
- data/lib/add_auth/rails/migration/key_type.rb +3 -3
- data/lib/add_auth/rails/runtime.rb +13 -4
- data/lib/add_auth/rails/stores/account_tokens.rb +10 -2
- data/lib/add_auth/rails/stores/sessions.rb +10 -2
- data/lib/add_auth/version.rb +1 -1
- data/lib/generators/add_auth/accounts/accounts_generator.rb +7 -1
- data/lib/generators/add_auth/accounts/templates/add_add_auth_accounts.rb.tt +2 -2
- data/lib/generators/add_auth/accounts/templates/add_add_auth_provisioning.rb.tt +9 -0
- data/lib/generators/add_auth/email_link/email_link_generator.rb +4 -1
- data/lib/generators/add_auth/email_tokens/email_tokens_generator.rb +2 -0
- data/lib/generators/add_auth/email_tokens/templates/create_add_auth_sign_in_tokens.rb.tt +1 -1
- data/lib/generators/add_auth/external_identities/external_identities_generator.rb +2 -0
- data/lib/generators/add_auth/external_identities/templates/create_add_auth_external_identities.rb.tt +6 -12
- data/lib/generators/add_auth/feature_configuration.rb +21 -0
- data/lib/generators/add_auth/install/templates/initializer.rb +154 -50
- data/lib/generators/add_auth/mobile_sessions/mobile_sessions_generator.rb +2 -0
- data/lib/generators/add_auth/mobile_sessions/templates/create_add_auth_mobile_handoffs.rb.tt +4 -4
- data/lib/generators/add_auth/notifications/notifications_generator.rb +5 -4
- data/lib/generators/add_auth/notifications/templates/create_add_auth_security_events.rb.tt +1 -1
- data/lib/generators/add_auth/passkeys/passkeys_generator.rb +5 -21
- data/lib/generators/add_auth/passkeys/templates/add_add_auth_passkeys.rb.tt +2 -2
- data/lib/generators/add_auth/primary_key.rb +19 -0
- data/lib/generators/add_auth/session_upgrade/session_upgrade_generator.rb +6 -1
- data/lib/generators/add_auth/session_upgrade/templates/add_add_auth_session_cursor_index.rb.tt +5 -0
- data/lib/generators/add_auth/step_up/step_up_generator.rb +5 -5
- metadata +21 -1
|
@@ -1,52 +1,156 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# AddAuth settings. Defaults are active; alternatives are commented out.
|
|
4
|
+
# Run the relevant generator and migrations before enabling a feature.
|
|
5
|
+
# Install alone enables no features. Existing initializers are never replaced.
|
|
2
6
|
AddAuth.configure do |config|
|
|
3
|
-
#
|
|
4
|
-
|
|
5
|
-
# config.passwords_enabled =
|
|
6
|
-
|
|
7
|
-
# Ordinary
|
|
8
|
-
|
|
9
|
-
#
|
|
10
|
-
|
|
11
|
-
#
|
|
12
|
-
|
|
13
|
-
#
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
#
|
|
20
|
-
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
|
|
24
|
-
#
|
|
25
|
-
|
|
26
|
-
# config.
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
# config.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
# config.
|
|
43
|
-
#
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
# config.
|
|
51
|
-
|
|
7
|
+
# Sign-in and rendering. HTML forms work in all browser modes.
|
|
8
|
+
config.passwords_enabled = true
|
|
9
|
+
# config.passwords_enabled = false # Use only other explicitly enabled methods.
|
|
10
|
+
config.turbo_enabled = true
|
|
11
|
+
# config.turbo_enabled = false # Ordinary JS navigation, with Turbo absent.
|
|
12
|
+
|
|
13
|
+
# Host business eligibility is checked alongside Core account policy.
|
|
14
|
+
config.eligible = ->(_user) { true }
|
|
15
|
+
# config.eligible = ->(user) { user.access_state == "active" }
|
|
16
|
+
|
|
17
|
+
# Browser sessions: bin/rails generate add_auth:session_upgrade
|
|
18
|
+
config.session.enabled = false
|
|
19
|
+
config.session.lifetime = 43_200 # 12 hours, absolute expiry.
|
|
20
|
+
config.session.idle_timeout = 1800 # 30 minutes; no greater than lifetime.
|
|
21
|
+
config.session.legacy_bridge_until = nil # Reject old Rails session-ID cookies.
|
|
22
|
+
# config.session.legacy_bridge_until = Time.iso8601("2030-01-01T00:00:00Z")
|
|
23
|
+
# Choose a short, fixed cutover deadline for a reviewed legacy-cookie bridge.
|
|
24
|
+
|
|
25
|
+
# Account lifecycle: bin/rails generate add_auth:accounts
|
|
26
|
+
# Password-only host: bin/rails generate add_auth:accounts --no-email-link
|
|
27
|
+
config.lifecycle.enabled = false
|
|
28
|
+
# config.lifecycle.enabled = true # After policy review and migrations.
|
|
29
|
+
config.lifecycle.confirmation_required = true
|
|
30
|
+
# config.lifecycle.confirmation_required = false
|
|
31
|
+
# false: password signup provisions and signs in immediately, without mail.
|
|
32
|
+
# confirmed_at stays nil. Requires the add_auth_provisioned_at migration.
|
|
33
|
+
config.lifecycle.reset_unconfirmed = false
|
|
34
|
+
# config.lifecycle.reset_unconfirmed = true # Requires optional confirmation.
|
|
35
|
+
# true: the stored mailbox holder may reset an unconfirmed password account
|
|
36
|
+
# after consuming an exact-address, single-use reset proof. No automatic login
|
|
37
|
+
# or confirmation. This does not trust the address for any other recovery.
|
|
38
|
+
# false: confirm the address before password reset, or use host support.
|
|
39
|
+
# Email changes always need fresh reauthentication and proof of the new address.
|
|
40
|
+
config.lifecycle.password_policy = ->(password) { password.length >= 12 && password.bytesize <= 72 }
|
|
41
|
+
config.lifecycle.eligible = ->(_user) { true } # Additional lifecycle eligibility.
|
|
42
|
+
config.lifecycle.profile_attributes = ->(_profile) { {} } # Accept no profile fields.
|
|
43
|
+
# config.lifecycle.profile_attributes = ->(profile) { profile.slice(:name, :consent) }
|
|
44
|
+
# Also allowlist those fields in the host registration controller. Never roles.
|
|
45
|
+
config.lifecycle.provision = ->(_user) {} # Local writes in the account transaction.
|
|
46
|
+
# config.lifecycle.provision = ->(user) { user.create_personal_workspace! }
|
|
47
|
+
# Raise on failure. Use the same DB pool; remote work needs a host outbox.
|
|
48
|
+
config.lifecycle.maximum_attempts = 20 # Failed-password threshold: 1..100.
|
|
49
|
+
config.lifecycle.unlock_in = 3600 # Timed lock: 60..86400 seconds.
|
|
50
|
+
config.lifecycle.proof_lifetime = 3600 # Account links: 60..86400 seconds.
|
|
51
|
+
config.lifecycle.remember_lifetime = 1_209_600 # 14 days, absolute expiry.
|
|
52
|
+
config.lifecycle.remember_idle_timeout = 604_800 # 7 days; <= remember_lifetime.
|
|
53
|
+
config.lifecycle.deletion_allowed = ->(_user) { true } # Host authorization/retention.
|
|
54
|
+
# config.lifecycle.deletion_allowed = ->(user) { user.invoices.none? }
|
|
55
|
+
config.lifecycle.delete_account = ->(user) { user.destroy! } # Same-DB local deletion.
|
|
56
|
+
|
|
57
|
+
# Email-link sign-in: bin/rails generate add_auth:email_link
|
|
58
|
+
# Account confirmation/reset mail does not require email-link sign-in.
|
|
59
|
+
config.email_link.enabled = false
|
|
60
|
+
config.email_link.token_lifetime = 1200 # 20 minutes.
|
|
61
|
+
config.email_link.same_browser = false
|
|
62
|
+
# config.email_link.same_browser = true # Require the requesting browser.
|
|
63
|
+
|
|
64
|
+
# Fresh proof for sensitive actions: bin/rails generate add_auth:step_up
|
|
65
|
+
# Use --no-email-link for password-only reauthentication.
|
|
66
|
+
config.step_up.enabled = false
|
|
67
|
+
config.step_up.fresh_for = 600 # Ordinary proof: 10 minutes.
|
|
68
|
+
config.step_up.strong_for = 300 # Strong proof: 5 minutes.
|
|
69
|
+
config.step_up.purposes = {} # Built-in feature purposes are supplied by Core.
|
|
70
|
+
# config.step_up.purposes = {
|
|
71
|
+
# export_data: {methods: [:password], return_to: "/exports/new", label: "export your data"}
|
|
72
|
+
# }
|
|
73
|
+
# Recheck elevation and host authorization inside the actual mutation.
|
|
74
|
+
|
|
75
|
+
# Passkeys: bin/rails generate add_auth:passkeys
|
|
76
|
+
config.passkeys.enabled = false
|
|
77
|
+
config.passkeys.rp_id = nil # Required: stable deployment RP ID.
|
|
78
|
+
# config.passkeys.rp_id = "example.com"
|
|
79
|
+
config.passkeys.origins = [] # Required: exact trusted origins, never request Host.
|
|
80
|
+
# config.passkeys.origins = ["https://app.example.com"]
|
|
81
|
+
config.passkeys.name = "Your account"
|
|
82
|
+
config.passkeys.anonymous_limit = 1000 # Shared ceremony budget per five minutes.
|
|
83
|
+
config.trusted_recovery_address = ->(_user) {} # No trusted recovery by default.
|
|
84
|
+
# config.trusted_recovery_address = ->(user) { user.email_address if user.confirmed_at }
|
|
85
|
+
# Lifecycle additionally rejects unconfirmed addresses as trusted recovery.
|
|
86
|
+
config.support_url = nil # Required before strict-policy activation.
|
|
87
|
+
# config.support_url = "/support" # Document your host-owned recovery process.
|
|
88
|
+
|
|
89
|
+
# Security notices: bin/rails generate add_auth:notifications
|
|
90
|
+
config.notifications.enabled = false
|
|
91
|
+
# Mail/queue settings also serve account proofs and optional email sign-in.
|
|
92
|
+
config.base_url = nil # Required for links: fixed trusted HTTPS origin.
|
|
93
|
+
# config.base_url = "https://app.example.com"
|
|
94
|
+
config.mail_from = nil # Required for mail; configure SMTP in Rails as usual.
|
|
95
|
+
# config.mail_from = "Your app <sign-in@example.com>"
|
|
96
|
+
# Configure a durable Active Job adapter and run add_auth:deliver_pending each minute.
|
|
97
|
+
config.rate_limit_store = nil # Defaults to Rails.cache; shared atomic counters required.
|
|
98
|
+
# config.rate_limit_store = ActiveSupport::Cache::RedisCacheStore.new(url: ENV.fetch("AUTH_REDIS_URL"))
|
|
99
|
+
# Solid Cache can serve application caching, but cannot serve these counters.
|
|
100
|
+
config.maintenance.batch_size = 100 # Maximum rows per operation/model: 1..1000.
|
|
101
|
+
config.maintenance.session_retention = nil # Keep history until explicitly selected.
|
|
102
|
+
config.maintenance.email_retention = nil
|
|
103
|
+
config.maintenance.notification_retention = nil
|
|
104
|
+
config.maintenance.account_retention = nil
|
|
105
|
+
# config.maintenance.session_retention = 604_800 # 7 days, seconds.
|
|
106
|
+
# config.maintenance.email_retention = 604_800
|
|
107
|
+
# config.maintenance.notification_retention = 2_592_000 # 30 days.
|
|
108
|
+
# config.maintenance.account_retention = 604_800
|
|
109
|
+
|
|
110
|
+
# Captcha: bin/rails generate add_auth:challenge (provider-specific setup).
|
|
111
|
+
config.challenge = AddAuth::Core::Challenge::Null.new
|
|
112
|
+
config.challenge_on = [] # Available: sign_in, email_link, reauthenticate,
|
|
113
|
+
# passkey_enrollment, register, account_request, provider.
|
|
114
|
+
# config.challenge_on = [:sign_in, :register, :account_request]
|
|
115
|
+
config.challenge_when_unavailable = :closed
|
|
116
|
+
# config.challenge_when_unavailable = :open # Explicit outage bypass; emits an event.
|
|
117
|
+
# Replace challenge with a configured Turnstile or Recaptcha adapter. Keep
|
|
118
|
+
# secrets in Rails credentials/environment, and configure expected hostnames.
|
|
119
|
+
|
|
120
|
+
# Optional providers: bin/rails generate add_auth:external_identities
|
|
121
|
+
config.external_identities.enabled = false
|
|
122
|
+
# Register only reviewed Core provider configurations through
|
|
123
|
+
# config.external_identities.register(id:, label:, middleware_name:, configuration:,
|
|
124
|
+
# apple_form_post: false, reauthentication: false)
|
|
125
|
+
# or config.external_identities.register_native(configuration:).
|
|
126
|
+
# The generated add_auth_providers.rb explains provider-library middleware,
|
|
127
|
+
# verifier and credential setup. It remains commented out until reviewed.
|
|
128
|
+
|
|
129
|
+
# Native sessions: bin/rails generate add_auth:mobile_sessions
|
|
130
|
+
config.mobile.enabled = false
|
|
131
|
+
config.mobile.lifetime = nil # Required when enabled; choose finite seconds.
|
|
132
|
+
config.mobile.idle_timeout = nil # Required; <= lifetime.
|
|
133
|
+
config.mobile.clients = [] # Explicit first-party client identifiers.
|
|
134
|
+
config.mobile.callbacks = {} # Reviewed callbacks per client, when using handoffs.
|
|
135
|
+
config.mobile.apple_providers = {} # Native Apple provider IDs per client.
|
|
136
|
+
# config.mobile.lifetime = 2_592_000 # Example: 30 days.
|
|
137
|
+
# config.mobile.idle_timeout = 1_209_600 # Example: 14 days.
|
|
138
|
+
# config.mobile.clients = %w[android ios]
|
|
139
|
+
|
|
140
|
+
# Presentation: eject with bin/rails generate add_auth:views.
|
|
141
|
+
config.stylesheet = "/add_auth.css"
|
|
142
|
+
# config.stylesheet = nil # Supply your own styling.
|
|
143
|
+
config.css_classes = {}
|
|
144
|
+
# config.css_classes = {input: "form-control", button: "btn btn-primary"}
|
|
145
|
+
|
|
146
|
+
# Password migration and cryptography: retain Rails' verifier by default.
|
|
147
|
+
config.legacy_password_verifier = nil
|
|
148
|
+
config.current_password_support = AddAuth::Core::Passwords::BcryptSupport.new
|
|
149
|
+
# A custom verifier must also declare current_password_support.available?(digest:).
|
|
150
|
+
# Rails configures digest_secret from its key generator automatically. Preserve it.
|
|
151
|
+
# Outside Rails only:
|
|
152
|
+
# config.digest_secret = -> { ENV.fetch("ADD_AUTH_DIGEST_SECRET") }
|
|
153
|
+
# Optional adapter overrides must implement digest(token) and matches?(digest, token):
|
|
154
|
+
# config.session_token_digest = MySessionDigest.new
|
|
155
|
+
# config.sign_in_token_digest = MyProofDigest.new
|
|
52
156
|
end
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "rails/generators"
|
|
4
|
+
require "generators/add_auth/primary_key"
|
|
4
5
|
require "rails/generators/active_record"
|
|
5
6
|
|
|
6
7
|
module AddAuth
|
|
7
8
|
module Generators
|
|
8
9
|
class MobileSessionsGenerator < ::Rails::Generators::Base
|
|
9
10
|
include ::Rails::Generators::Migration
|
|
11
|
+
include PrimaryKey
|
|
10
12
|
|
|
11
13
|
source_root File.expand_path("templates", __dir__)
|
|
12
14
|
def self.next_migration_number(dirname) = ::ActiveRecord::Generators::Base.next_migration_number(dirname)
|
data/lib/generators/add_auth/mobile_sessions/templates/create_add_auth_mobile_handoffs.rb.tt
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
require "add_auth/rails/migration/key_type"
|
|
2
|
+
|
|
1
3
|
class CreateAddAuthMobileHandoffs < ActiveRecord::Migration[8.0]
|
|
2
4
|
def change
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
user_type = (user_key.type == :integer && user_key.limit == 8) ? :bigint : user_key.type
|
|
6
|
-
create_table :add_auth_mobile_handoffs do |t|
|
|
5
|
+
user_type = AddAuth::Rails::Migration::KeyType.for(connection, :users)
|
|
6
|
+
create_table :add_auth_mobile_handoffs, id: <%= authentication_primary_key_type %> do |t|
|
|
7
7
|
t.references :user, type: user_type, foreign_key: {on_delete: :cascade}
|
|
8
8
|
t.string :external_digest, null: false
|
|
9
9
|
t.string :digest
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "rails/generators"
|
|
4
|
+
require "generators/add_auth/primary_key"
|
|
5
|
+
require "generators/add_auth/feature_configuration"
|
|
4
6
|
require "rails/generators/active_record"
|
|
5
7
|
|
|
6
8
|
module AddAuth
|
|
7
9
|
module Generators
|
|
8
10
|
class NotificationsGenerator < ::Rails::Generators::Base
|
|
9
11
|
include ::Rails::Generators::Migration
|
|
12
|
+
include PrimaryKey
|
|
13
|
+
include FeatureConfiguration
|
|
10
14
|
|
|
11
15
|
source_root File.expand_path("templates", __dir__)
|
|
12
16
|
def self.next_migration_number(dirname) = ::ActiveRecord::Generators::Base.next_migration_number(dirname)
|
|
@@ -21,10 +25,7 @@ module AddAuth
|
|
|
21
25
|
end
|
|
22
26
|
|
|
23
27
|
def configuration
|
|
24
|
-
|
|
25
|
-
unless File.read(File.join(destination_root, path)).include?("config.notifications.enabled = true")
|
|
26
|
-
append_to_file path, "\nAddAuth.configure do |config|\n config.notifications.enabled = true\nend\n"
|
|
27
|
-
end
|
|
28
|
+
enable_feature(:notifications)
|
|
28
29
|
say "Migrate, configure mail_from and a durable queue, and schedule add_auth:deliver_pending every minute."
|
|
29
30
|
end
|
|
30
31
|
end
|
|
@@ -2,7 +2,7 @@ require "add_auth/rails/migration/key_type"
|
|
|
2
2
|
|
|
3
3
|
class CreateAddAuthSecurityEvents < ActiveRecord::Migration[8.0]
|
|
4
4
|
def change
|
|
5
|
-
create_table :add_auth_security_events do |t|
|
|
5
|
+
create_table :add_auth_security_events, id: <%= authentication_primary_key_type %> do |t|
|
|
6
6
|
t.references :user, type: AddAuth::Rails::Migration::KeyType.for(connection, :users), foreign_key: {on_delete: :nullify}
|
|
7
7
|
t.string :kind, null: false
|
|
8
8
|
t.string :digest, null: false
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "rails/generators"
|
|
4
|
+
require "generators/add_auth/primary_key"
|
|
5
|
+
require "generators/add_auth/feature_configuration"
|
|
4
6
|
require "rails/generators/active_record"
|
|
5
7
|
|
|
6
8
|
module AddAuth
|
|
7
9
|
module Generators
|
|
8
10
|
class PasskeysGenerator < ::Rails::Generators::Base
|
|
9
11
|
include ::Rails::Generators::Migration
|
|
12
|
+
include PrimaryKey
|
|
13
|
+
include FeatureConfiguration
|
|
10
14
|
|
|
11
15
|
source_root File.expand_path("templates", __dir__)
|
|
12
16
|
def self.next_migration_number(dirname) = ::ActiveRecord::Generators::Base.next_migration_number(dirname)
|
|
@@ -47,27 +51,7 @@ module AddAuth
|
|
|
47
51
|
post "recover/link", to: "add_auth/recoveries#confirm"
|
|
48
52
|
ROUTES
|
|
49
53
|
end
|
|
50
|
-
|
|
51
|
-
unless File.read(File.join(destination_root, path)).include?("config.passkeys.enabled = true")
|
|
52
|
-
append_to_file path, <<~CONFIG
|
|
53
|
-
|
|
54
|
-
AddAuth.configure do |config|
|
|
55
|
-
config.passkeys.enabled = true
|
|
56
|
-
# REQUIRED: stable RP ID and exact deployment origins, never request Host.
|
|
57
|
-
# config.passkeys.rp_id = "example.com"
|
|
58
|
-
# config.passkeys.origins = ["https://app.example.com"]
|
|
59
|
-
# config.passkeys.name = "Your app"
|
|
60
|
-
# Shared anonymous ceremony budget per five minutes; positive integer.
|
|
61
|
-
# config.passkeys.anonymous_limit = 1000
|
|
62
|
-
# Schedule add_auth:deliver_pending every minute. Production doctor
|
|
63
|
-
# requires a completed cleanup within the last two minutes.
|
|
64
|
-
# REQUIRED for email replacement: a host-verified recovery address.
|
|
65
|
-
# config.trusted_recovery_address = ->(user) { user.email_address if user.confirmed? }
|
|
66
|
-
# REQUIRED before strict activation: your documented support route.
|
|
67
|
-
# config.support_url = "/support"
|
|
68
|
-
end
|
|
69
|
-
CONFIG
|
|
70
|
-
end
|
|
54
|
+
enable_feature(:passkeys)
|
|
71
55
|
say "Review and migrate before enabling traffic. Configure RP/origins, trusted recovery and notifications; run add_auth:doctor."
|
|
72
56
|
end
|
|
73
57
|
end
|
|
@@ -14,7 +14,7 @@ class AddAddAuthPasskeys < ActiveRecord::Migration[8.0]
|
|
|
14
14
|
add_column :sessions, :authentication_policy_version, :integer, default: 0, null: false
|
|
15
15
|
add_column :sessions, :authentication_credential_id, :string
|
|
16
16
|
add_column :sessions, :authentication_uv, :boolean, default: false_default, null: false
|
|
17
|
-
create_table :add_auth_credentials do |t|
|
|
17
|
+
create_table :add_auth_credentials, id: <%= authentication_primary_key_type %> do |t|
|
|
18
18
|
t.references :user, type: user_key_type, null: false, foreign_key: {on_delete: :cascade}
|
|
19
19
|
t.string :external_id, null: false
|
|
20
20
|
t.text :public_key, null: false
|
|
@@ -29,7 +29,7 @@ class AddAddAuthPasskeys < ActiveRecord::Migration[8.0]
|
|
|
29
29
|
t.timestamps
|
|
30
30
|
end
|
|
31
31
|
add_index :add_auth_credentials, :external_id, unique: true
|
|
32
|
-
create_table :add_auth_ceremonies do |t|
|
|
32
|
+
create_table :add_auth_ceremonies, id: <%= authentication_primary_key_type %> do |t|
|
|
33
33
|
t.string :digest, null: false
|
|
34
34
|
t.string :challenge, null: false
|
|
35
35
|
t.string :kind, null: false
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AddAuth
|
|
4
|
+
module Generators
|
|
5
|
+
module PrimaryKey
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
# Freeze Rails' generator preference into the migration source. Foreign
|
|
9
|
+
# keys independently follow the actual referenced table when it runs.
|
|
10
|
+
def authentication_primary_key_type
|
|
11
|
+
type = (::Rails.application.config.generators.options.dig(:active_record, :primary_key_type) || :bigint).to_s
|
|
12
|
+
unless %w[bigint integer uuid].include?(type)
|
|
13
|
+
raise Thor::Error, "AddAuth supports Rails primary_key_type :bigint, :integer or :uuid"
|
|
14
|
+
end
|
|
15
|
+
":#{type}"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "rails/generators"
|
|
4
|
+
require "generators/add_auth/feature_configuration"
|
|
4
5
|
require "rails/generators/active_record"
|
|
5
6
|
|
|
6
7
|
module AddAuth
|
|
7
8
|
module Generators
|
|
8
9
|
class SessionUpgradeGenerator < ::Rails::Generators::Base
|
|
9
10
|
include ::Rails::Generators::Migration
|
|
11
|
+
include FeatureConfiguration
|
|
10
12
|
|
|
11
13
|
source_root File.expand_path("templates", __dir__)
|
|
12
14
|
|
|
@@ -23,6 +25,9 @@ module AddAuth
|
|
|
23
25
|
end
|
|
24
26
|
|
|
25
27
|
def migration
|
|
28
|
+
unless Dir[File.join(destination_root, "db/migrate/*_add_add_auth_session_cursor_index.rb")].any?
|
|
29
|
+
migration_template "add_add_auth_session_cursor_index.rb.tt", "db/migrate/add_add_auth_session_cursor_index.rb"
|
|
30
|
+
end
|
|
26
31
|
unless Dir[File.join(destination_root, "db/migrate/*_extend_sessions_for_add_auth.rb")].any?
|
|
27
32
|
migration_template "extend_sessions_for_add_auth.rb.tt", "db/migrate/extend_sessions_for_add_auth.rb"
|
|
28
33
|
end
|
|
@@ -62,7 +67,7 @@ module AddAuth
|
|
|
62
67
|
unless File.read(File.join(destination_root, path)).include?('require "add_auth/rails/authentication"')
|
|
63
68
|
prepend_to_file path, %(require "add_auth/rails/authentication"\nrequire "add_auth/rails/user_lifecycle"\n)
|
|
64
69
|
end
|
|
65
|
-
|
|
70
|
+
enable_feature(:session)
|
|
66
71
|
routes = File.join(destination_root, "config/routes.rb")
|
|
67
72
|
source = File.read(routes)
|
|
68
73
|
unless source.include?("# AddAuth session management")
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "rails/generators"
|
|
4
|
+
require "generators/add_auth/feature_configuration"
|
|
4
5
|
require "rails/generators/active_record"
|
|
5
6
|
|
|
6
7
|
module AddAuth
|
|
7
8
|
module Generators
|
|
8
9
|
class StepUpGenerator < ::Rails::Generators::Base
|
|
9
10
|
include ::Rails::Generators::Migration
|
|
11
|
+
include FeatureConfiguration
|
|
10
12
|
|
|
11
13
|
source_root File.expand_path("templates", __dir__)
|
|
14
|
+
class_option :email_link, type: :boolean, default: true, desc: "Enable email sign-in alongside reauthentication"
|
|
12
15
|
def self.next_migration_number(dirname) = ::ActiveRecord::Generators::Base.next_migration_number(dirname)
|
|
13
16
|
|
|
14
17
|
def dependencies
|
|
15
|
-
invoke "add_auth:email_link"
|
|
18
|
+
invoke "add_auth:email_link", [], enable: options[:email_link]
|
|
16
19
|
end
|
|
17
20
|
|
|
18
21
|
def persistence
|
|
@@ -33,10 +36,7 @@ module AddAuth
|
|
|
33
36
|
post "reauthenticate/link", to: "add_auth/reauthentications#confirm"
|
|
34
37
|
ROUTES
|
|
35
38
|
end
|
|
36
|
-
|
|
37
|
-
unless File.read(File.join(destination_root, initializer)).include?("config.step_up.enabled = true")
|
|
38
|
-
append_to_file initializer, "\nAddAuth.configure do |config|\n config.step_up.enabled = true\n # Declare purpose methods and a fixed safe GET return_to before use.\nend\n"
|
|
39
|
-
end
|
|
39
|
+
enable_feature(:step_up)
|
|
40
40
|
say "Migrate and declare config.step_up.purposes. Use with_elevated_session around sensitive database mutations."
|
|
41
41
|
end
|
|
42
42
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: add_auth
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Taimoor Qureshi
|
|
@@ -23,6 +23,20 @@ dependencies:
|
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '8.0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: json
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "<"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '3.0'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "<"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '3.0'
|
|
26
40
|
- !ruby/object:Gem::Dependency
|
|
27
41
|
name: webauthn
|
|
28
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -315,6 +329,8 @@ files:
|
|
|
315
329
|
- lib/add_auth/core/rate_limit.rb
|
|
316
330
|
- lib/add_auth/core/remaining_factors.rb
|
|
317
331
|
- lib/add_auth/core/security_events.rb
|
|
332
|
+
- lib/add_auth/core/session_cursor.rb
|
|
333
|
+
- lib/add_auth/core/session_key.rb
|
|
318
334
|
- lib/add_auth/core/sessions.rb
|
|
319
335
|
- lib/add_auth/core/step_up.rb
|
|
320
336
|
- lib/add_auth/core/strategies/email_link.rb
|
|
@@ -364,6 +380,7 @@ files:
|
|
|
364
380
|
- lib/add_auth/version.rb
|
|
365
381
|
- lib/generators/add_auth/accounts/accounts_generator.rb
|
|
366
382
|
- lib/generators/add_auth/accounts/templates/add_add_auth_accounts.rb.tt
|
|
383
|
+
- lib/generators/add_auth/accounts/templates/add_add_auth_provisioning.rb.tt
|
|
367
384
|
- lib/generators/add_auth/accounts/templates/add_auth_account_token.rb
|
|
368
385
|
- lib/generators/add_auth/accounts/templates/add_auth_address_claim.rb
|
|
369
386
|
- lib/generators/add_auth/challenge/challenge_generator.rb
|
|
@@ -388,6 +405,7 @@ files:
|
|
|
388
405
|
- lib/generators/add_auth/external_identities/templates/add_auth_external_transaction.rb
|
|
389
406
|
- lib/generators/add_auth/external_identities/templates/create_add_auth_external_identities.rb.tt
|
|
390
407
|
- lib/generators/add_auth/external_identities/templates/providers.rb
|
|
408
|
+
- lib/generators/add_auth/feature_configuration.rb
|
|
391
409
|
- lib/generators/add_auth/install/install_generator.rb
|
|
392
410
|
- lib/generators/add_auth/install/templates/initializer.rb
|
|
393
411
|
- lib/generators/add_auth/javascript/javascript_generator.rb
|
|
@@ -407,8 +425,10 @@ files:
|
|
|
407
425
|
- lib/generators/add_auth/passkeys/templates/add_add_auth_passkeys.rb.tt
|
|
408
426
|
- lib/generators/add_auth/passkeys/templates/add_auth_ceremony.rb
|
|
409
427
|
- lib/generators/add_auth/passkeys/templates/add_auth_credential.rb
|
|
428
|
+
- lib/generators/add_auth/primary_key.rb
|
|
410
429
|
- lib/generators/add_auth/session_upgrade/session_upgrade_generator.rb
|
|
411
430
|
- lib/generators/add_auth/session_upgrade/templates/add_add_auth_elevation.rb.tt
|
|
431
|
+
- lib/generators/add_auth/session_upgrade/templates/add_add_auth_session_cursor_index.rb.tt
|
|
412
432
|
- lib/generators/add_auth/session_upgrade/templates/extend_sessions_for_add_auth.rb.tt
|
|
413
433
|
- lib/generators/add_auth/step_up/step_up_generator.rb
|
|
414
434
|
- lib/generators/add_auth/step_up/templates/add_add_auth_reauthentication.rb.tt
|