authnz_eleven 0.1.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 +7 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +384 -0
- data/lib/authnz_eleven/identity.rb +210 -0
- data/lib/authnz_eleven/principal.rb +201 -0
- data/lib/authnz_eleven/principals.rb +111 -0
- data/lib/authnz_eleven/version.rb +5 -0
- data/lib/authnz_eleven/wizard.rb +570 -0
- data/lib/authnz_eleven.rb +15 -0
- data/lib/generators/authnz_eleven/USAGE +26 -0
- data/lib/generators/authnz_eleven/authnz_eleven_generator.rb +3040 -0
- data/lib/generators/authnz_eleven/templates/config/forbidden_usernames.LICENSE +22 -0
- data/lib/generators/authnz_eleven/templates/config/forbidden_usernames.txt +558 -0
- data/lib/generators/authnz_eleven/templates/config/initializers/authentication.rb.tt +275 -0
- data/lib/generators/authnz_eleven/templates/config/initializers/omniauth.rb.tt +9 -0
- data/lib/generators/authnz_eleven/templates/config/initializers/team_slug.rb.tt +24 -0
- data/lib/generators/authnz_eleven/templates/config/initializers/webauthn.rb.tt +14 -0
- data/lib/generators/authnz_eleven/templates/config/locales/authentication.en.yml.tt +11 -0
- data/lib/generators/authnz_eleven/templates/controllers/active_teams_controller.rb.tt +6 -0
- data/lib/generators/authnz_eleven/templates/controllers/admin/dashboard_controller.rb.tt +4 -0
- data/lib/generators/authnz_eleven/templates/controllers/admin/sessions_controller.rb.tt +17 -0
- data/lib/generators/authnz_eleven/templates/controllers/admin/users_controller.rb.tt +91 -0
- data/lib/generators/authnz_eleven/templates/controllers/admin_controller.rb.tt +6 -0
- data/lib/generators/authnz_eleven/templates/controllers/base_controller.rb.tt +11 -0
- data/lib/generators/authnz_eleven/templates/controllers/concerns/api_token_authentication.rb.tt +21 -0
- data/lib/generators/authnz_eleven/templates/controllers/concerns/authentication/easy_dev_login.rb.tt +47 -0
- data/lib/generators/authnz_eleven/templates/controllers/concerns/authentication/registering.rb.tt +25 -0
- data/lib/generators/authnz_eleven/templates/controllers/concerns/authentication/sudoable.rb.tt +117 -0
- data/lib/generators/authnz_eleven/templates/controllers/concerns/authentication/webauthn_ceremony.rb.tt +51 -0
- data/lib/generators/authnz_eleven/templates/controllers/concerns/authentication.rb.tt +421 -0
- data/lib/generators/authnz_eleven/templates/controllers/concerns/authorization.rb.tt +48 -0
- data/lib/generators/authnz_eleven/templates/controllers/concerns/captchable.rb.tt +11 -0
- data/lib/generators/authnz_eleven/templates/controllers/impersonations_controller.rb.tt +8 -0
- data/lib/generators/authnz_eleven/templates/controllers/invitations_controller.rb.tt +65 -0
- data/lib/generators/authnz_eleven/templates/controllers/settings/api_tokens_controller.rb.tt +54 -0
- data/lib/generators/authnz_eleven/templates/controllers/settings/authentications/events_controller.rb.tt +5 -0
- data/lib/generators/authnz_eleven/templates/controllers/settings/dashboard_controller.rb.tt +4 -0
- data/lib/generators/authnz_eleven/templates/controllers/settings/email_verifications_controller.rb.tt +15 -0
- data/lib/generators/authnz_eleven/templates/controllers/settings/emails_controller.rb.tt +93 -0
- data/lib/generators/authnz_eleven/templates/controllers/settings/invitations_controller.rb.tt +61 -0
- data/lib/generators/authnz_eleven/templates/controllers/settings/multi_factor_authentication/authenticators_controller.rb.tt +87 -0
- data/lib/generators/authnz_eleven/templates/controllers/settings/multi_factor_authentication/recovery_codes_controller.rb.tt +27 -0
- data/lib/generators/authnz_eleven/templates/controllers/settings/multi_factor_authentication/security_keys_controller.rb.tt +86 -0
- data/lib/generators/authnz_eleven/templates/controllers/settings/multi_factor_authentication/sms_controller.rb.tt +84 -0
- data/lib/generators/authnz_eleven/templates/controllers/settings/omniauth_identities_controller.rb.tt +27 -0
- data/lib/generators/authnz_eleven/templates/controllers/settings/passkeys_controller.rb.tt +70 -0
- data/lib/generators/authnz_eleven/templates/controllers/settings/passwords_controller.rb.tt +74 -0
- data/lib/generators/authnz_eleven/templates/controllers/settings/phone_verifications_controller.rb.tt +39 -0
- data/lib/generators/authnz_eleven/templates/controllers/settings/phones_controller.rb.tt +88 -0
- data/lib/generators/authnz_eleven/templates/controllers/settings/sessions_controller.rb.tt +29 -0
- data/lib/generators/authnz_eleven/templates/controllers/settings/users_controller.rb.tt +42 -0
- data/lib/generators/authnz_eleven/templates/controllers/settings_controller.rb.tt +5 -0
- data/lib/generators/authnz_eleven/templates/controllers/teams_controller.rb.tt +38 -0
- data/lib/generators/authnz_eleven/templates/controllers/users/credential_enrollments/passkeys_controller.rb.tt +36 -0
- data/lib/generators/authnz_eleven/templates/controllers/users/credential_enrollments/passwords_controller.rb.tt +28 -0
- data/lib/generators/authnz_eleven/templates/controllers/users/credential_enrollments_controller.rb.tt +14 -0
- data/lib/generators/authnz_eleven/templates/controllers/users/easy_dev_logins_controller.rb.tt +19 -0
- data/lib/generators/authnz_eleven/templates/controllers/users/email_verifications_controller.rb.tt +36 -0
- data/lib/generators/authnz_eleven/templates/controllers/users/magic_link_controller.rb.tt +53 -0
- data/lib/generators/authnz_eleven/templates/controllers/users/multi_factor_authentication/challenge/recovery_codes_controller.rb.tt +30 -0
- data/lib/generators/authnz_eleven/templates/controllers/users/multi_factor_authentication/challenge/security_keys_controller.rb.tt +34 -0
- data/lib/generators/authnz_eleven/templates/controllers/users/multi_factor_authentication/challenge/sms_controller.rb.tt +45 -0
- data/lib/generators/authnz_eleven/templates/controllers/users/multi_factor_authentication/challenge/totps_controller.rb.tt +42 -0
- data/lib/generators/authnz_eleven/templates/controllers/users/omniauth/registrations_controller.rb.tt +26 -0
- data/lib/generators/authnz_eleven/templates/controllers/users/omniauth_controller.rb.tt +139 -0
- data/lib/generators/authnz_eleven/templates/controllers/users/passkeys/sessions_controller.rb.tt +18 -0
- data/lib/generators/authnz_eleven/templates/controllers/users/password_resets_controller.rb.tt +64 -0
- data/lib/generators/authnz_eleven/templates/controllers/users/registrations/email_verifications_controller.rb.tt +53 -0
- data/lib/generators/authnz_eleven/templates/controllers/users/registrations/phone_verifications_controller.rb.tt +37 -0
- data/lib/generators/authnz_eleven/templates/controllers/users/registrations_controller.rb.tt +112 -0
- data/lib/generators/authnz_eleven/templates/controllers/users/sessions_controller.rb.tt +52 -0
- data/lib/generators/authnz_eleven/templates/controllers/users/sms_sessions_controller.rb.tt +53 -0
- data/lib/generators/authnz_eleven/templates/controllers/users/sudos_controller.rb.tt +42 -0
- data/lib/generators/authnz_eleven/templates/erb/admin/dashboard/index.html.erb.tt +9 -0
- data/lib/generators/authnz_eleven/templates/erb/admin/sessions/index.html.erb.tt +27 -0
- data/lib/generators/authnz_eleven/templates/erb/admin/users/index.html.erb.tt +32 -0
- data/lib/generators/authnz_eleven/templates/erb/admin/users/show.html.erb.tt +70 -0
- data/lib/generators/authnz_eleven/templates/erb/invitations/show.html.erb.tt +9 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/api_tokens/create.html.erb.tt +7 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/api_tokens/index.html.erb.tt +29 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/authentications/events/index.html.erb.tt +18 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/dashboard/index.html.erb.tt +75 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/emails/edit.html.erb.tt +68 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/invitations/new.html.erb.tt +31 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/multi_factor_authentication/authenticators/new.html.erb.tt +57 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/multi_factor_authentication/recovery_codes/create.html.erb.tt +14 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/multi_factor_authentication/recovery_codes/index.html.erb.tt +13 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/multi_factor_authentication/security_keys/edit.html.erb.tt +14 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/multi_factor_authentication/security_keys/index.html.erb.tt +20 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/multi_factor_authentication/security_keys/new.html.erb.tt +17 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/multi_factor_authentication/sms/new.html.erb.tt +35 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/omniauth_identities/index.html.erb.tt +28 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/passkeys/edit.html.erb.tt +14 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/passkeys/index.html.erb.tt +21 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/passkeys/new.html.erb.tt +13 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/passwords/edit.html.erb.tt +68 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/phone_verifications/new.html.erb.tt +22 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/phones/edit.html.erb.tt +58 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/sessions/index.html.erb.tt +29 -0
- data/lib/generators/authnz_eleven/templates/erb/settings/users/show.html.erb.tt +28 -0
- data/lib/generators/authnz_eleven/templates/erb/shared/_authnz_eleven_nav.html.erb.tt +24 -0
- data/lib/generators/authnz_eleven/templates/erb/shared/_authnz_eleven_sudo_challenge.html.erb.tt +43 -0
- data/lib/generators/authnz_eleven/templates/erb/shared/_captcha.html.erb.tt +8 -0
- data/lib/generators/authnz_eleven/templates/erb/teams/index.html.erb.tt +34 -0
- data/lib/generators/authnz_eleven/templates/erb/teams/new.html.erb.tt +22 -0
- data/lib/generators/authnz_eleven/templates/erb/teams/show.html.erb.tt +5 -0
- data/lib/generators/authnz_eleven/templates/erb/user_mailer/email_change_verification.html.erb.tt +7 -0
- data/lib/generators/authnz_eleven/templates/erb/user_mailer/invitation.html.erb.tt +11 -0
- data/lib/generators/authnz_eleven/templates/erb/user_mailer/magic_link.html.erb.tt +5 -0
- data/lib/generators/authnz_eleven/templates/erb/user_mailer/password_reset.html.erb.tt +6 -0
- data/lib/generators/authnz_eleven/templates/erb/user_mailer/registration_email_verification.html.erb.tt +7 -0
- data/lib/generators/authnz_eleven/templates/erb/user_mailer/security_notification.html.erb.tt +15 -0
- data/lib/generators/authnz_eleven/templates/erb/users/credential_enrollments/passkeys/new.html.erb.tt +24 -0
- data/lib/generators/authnz_eleven/templates/erb/users/credential_enrollments/passwords/new.html.erb.tt +21 -0
- data/lib/generators/authnz_eleven/templates/erb/users/credential_enrollments/show.html.erb.tt +21 -0
- data/lib/generators/authnz_eleven/templates/erb/users/email_verifications/show.html.erb.tt +9 -0
- data/lib/generators/authnz_eleven/templates/erb/users/magic_link/edit.html.erb.tt +9 -0
- data/lib/generators/authnz_eleven/templates/erb/users/magic_link/new.html.erb.tt +22 -0
- data/lib/generators/authnz_eleven/templates/erb/users/multi_factor_authentication/challenge/recovery_codes/new.html.erb.tt +20 -0
- data/lib/generators/authnz_eleven/templates/erb/users/multi_factor_authentication/challenge/security_keys/new.html.erb.tt +17 -0
- data/lib/generators/authnz_eleven/templates/erb/users/multi_factor_authentication/challenge/sms/new.html.erb.tt +25 -0
- data/lib/generators/authnz_eleven/templates/erb/users/multi_factor_authentication/challenge/totps/new.html.erb.tt +21 -0
- data/lib/generators/authnz_eleven/templates/erb/users/omniauth/registrations/new.html.erb.tt +28 -0
- data/lib/generators/authnz_eleven/templates/erb/users/password_resets/edit.html.erb.tt +26 -0
- data/lib/generators/authnz_eleven/templates/erb/users/password_resets/new.html.erb.tt +20 -0
- data/lib/generators/authnz_eleven/templates/erb/users/registrations/email_verifications/new.html.erb.tt +11 -0
- data/lib/generators/authnz_eleven/templates/erb/users/registrations/email_verifications/show.html.erb.tt +34 -0
- data/lib/generators/authnz_eleven/templates/erb/users/registrations/new.html.erb.tt +87 -0
- data/lib/generators/authnz_eleven/templates/erb/users/registrations/phone_verifications/new.html.erb.tt +46 -0
- data/lib/generators/authnz_eleven/templates/erb/users/sessions/new.html.erb.tt +88 -0
- data/lib/generators/authnz_eleven/templates/erb/users/sms_sessions/edit.html.erb.tt +30 -0
- data/lib/generators/authnz_eleven/templates/erb/users/sms_sessions/new.html.erb.tt +22 -0
- data/lib/generators/authnz_eleven/templates/erb/users/sudos/new.html.erb.tt +9 -0
- data/lib/generators/authnz_eleven/templates/javascript/controllers/webauthn_controller.js.tt +142 -0
- data/lib/generators/authnz_eleven/templates/jobs/authnz_eleven_deferred_job.rb.tt +9 -0
- data/lib/generators/authnz_eleven/templates/jobs/authnz_eleven_mail_delivery_job.rb.tt +3 -0
- data/lib/generators/authnz_eleven/templates/jobs/sms_delivery_job.rb.tt +11 -0
- data/lib/generators/authnz_eleven/templates/lib/captcha/null.rb.tt +9 -0
- data/lib/generators/authnz_eleven/templates/lib/captcha/turnstile.rb.tt +39 -0
- data/lib/generators/authnz_eleven/templates/lib/captcha.rb.tt +15 -0
- data/lib/generators/authnz_eleven/templates/lib/sms/log.rb.tt +8 -0
- data/lib/generators/authnz_eleven/templates/lib/sms/twilio.rb.tt +70 -0
- data/lib/generators/authnz_eleven/templates/lib/sms.rb.tt +15 -0
- data/lib/generators/authnz_eleven/templates/mailers/user_mailer.rb.tt +98 -0
- data/lib/generators/authnz_eleven/templates/migrations/add_guest_to_users_migration.rb.tt +6 -0
- data/lib/generators/authnz_eleven/templates/migrations/create_api_tokens_migration.rb.tt +14 -0
- data/lib/generators/authnz_eleven/templates/migrations/create_events_migration.rb.tt +26 -0
- data/lib/generators/authnz_eleven/templates/migrations/create_invitations_migration.rb.tt +20 -0
- data/lib/generators/authnz_eleven/templates/migrations/create_memberships_migration.rb.tt +12 -0
- data/lib/generators/authnz_eleven/templates/migrations/create_omniauth_identities_migration.rb.tt +16 -0
- data/lib/generators/authnz_eleven/templates/migrations/create_password_histories_migration.rb.tt +11 -0
- data/lib/generators/authnz_eleven/templates/migrations/create_pending_registrations_migration.rb.tt +31 -0
- data/lib/generators/authnz_eleven/templates/migrations/create_recovery_codes_migration.rb.tt +11 -0
- data/lib/generators/authnz_eleven/templates/migrations/create_sessions_migration.rb.tt +19 -0
- data/lib/generators/authnz_eleven/templates/migrations/create_teams_migration.rb.tt +9 -0
- data/lib/generators/authnz_eleven/templates/migrations/create_users_migration.rb.tt +70 -0
- data/lib/generators/authnz_eleven/templates/migrations/create_webauthn_credentials_migration.rb.tt +16 -0
- data/lib/generators/authnz_eleven/templates/models/api_token.rb.tt +24 -0
- data/lib/generators/authnz_eleven/templates/models/concerns/adminable.rb.tt +15 -0
- data/lib/generators/authnz_eleven/templates/models/concerns/authenticatable.rb.tt +151 -0
- data/lib/generators/authnz_eleven/templates/models/concerns/bannable.rb.tt +24 -0
- data/lib/generators/authnz_eleven/templates/models/concerns/deadboltable.rb.tt +39 -0
- data/lib/generators/authnz_eleven/templates/models/concerns/email_verifiable.rb.tt +52 -0
- data/lib/generators/authnz_eleven/templates/models/concerns/eventable.rb.tt +22 -0
- data/lib/generators/authnz_eleven/templates/models/concerns/guestable.rb.tt +30 -0
- data/lib/generators/authnz_eleven/templates/models/concerns/invitable.rb.tt +12 -0
- data/lib/generators/authnz_eleven/templates/models/concerns/magic_linkable.rb.tt +34 -0
- data/lib/generators/authnz_eleven/templates/models/concerns/password_historical.rb.tt +28 -0
- data/lib/generators/authnz_eleven/templates/models/concerns/password_policy.rb.tt +38 -0
- data/lib/generators/authnz_eleven/templates/models/concerns/password_rotatable.rb.tt +15 -0
- data/lib/generators/authnz_eleven/templates/models/concerns/phone_verifiable.rb.tt +50 -0
- data/lib/generators/authnz_eleven/templates/models/concerns/principals.rb.tt +67 -0
- data/lib/generators/authnz_eleven/templates/models/concerns/recoverable.rb.tt +19 -0
- data/lib/generators/authnz_eleven/templates/models/concerns/second_factor.rb.tt +52 -0
- data/lib/generators/authnz_eleven/templates/models/concerns/sms_challengeable.rb.tt +38 -0
- data/lib/generators/authnz_eleven/templates/models/concerns/team_member.rb.tt +20 -0
- data/lib/generators/authnz_eleven/templates/models/current.rb.tt +28 -0
- data/lib/generators/authnz_eleven/templates/models/event.rb.tt +32 -0
- data/lib/generators/authnz_eleven/templates/models/invitation.rb.tt +122 -0
- data/lib/generators/authnz_eleven/templates/models/membership.rb.tt +16 -0
- data/lib/generators/authnz_eleven/templates/models/omniauth_identity.rb.tt +12 -0
- data/lib/generators/authnz_eleven/templates/models/password_history.rb.tt +3 -0
- data/lib/generators/authnz_eleven/templates/models/pending_registration.rb.tt +216 -0
- data/lib/generators/authnz_eleven/templates/models/recovery_code.rb.tt +41 -0
- data/lib/generators/authnz_eleven/templates/models/session.rb.tt +46 -0
- data/lib/generators/authnz_eleven/templates/models/team.rb.tt +12 -0
- data/lib/generators/authnz_eleven/templates/models/user.rb.tt +59 -0
- data/lib/generators/authnz_eleven/templates/models/webauthn_credential.rb.tt +12 -0
- data/lib/generators/authnz_eleven/templates/tasks/authnz_eleven.rake.tt +41 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/account_existence_parity_test.rb.tt +158 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/admin/access_test.rb.tt +139 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/admin/multi_factor_authentication_test.rb.tt +65 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/api_token_authentication_test.rb.tt +45 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/credential_enrollment_test.rb.tt +84 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/guest_access_test.rb.tt +113 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/invitations_controller_test.rb.tt +230 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/passkey_ceremony_test.rb.tt +126 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/password_rotation_test.rb.tt +67 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/security_key_ceremony_test.rb.tt +218 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/security_notifications_test.rb.tt +39 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/session_lifecycle_test.rb.tt +102 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/settings/api_tokens_controller_test.rb.tt +61 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/settings/authentications/events_controller_test.rb.tt +17 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/settings/email_verifications_controller_test.rb.tt +39 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/settings/invitations_controller_test.rb.tt +157 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/settings/management_test.rb.tt +256 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/settings/multi_factor_authentication/management_test.rb.tt +222 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/settings/omniauth_identities_controller_test.rb.tt +57 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/settings/phone_verifications_controller_test.rb.tt +146 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/teams_controller_test.rb.tt +83 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/users/email_verifications_controller_test.rb.tt +74 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/users/magic_link_controller_test.rb.tt +90 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/users/multi_factor_authentication/challenge_test.rb.tt +143 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/users/omniauth/registrations_controller_test.rb.tt +138 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/users/omniauth_controller_test.rb.tt +97 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/users/password_resets_controller_test.rb.tt +58 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/users/registrations/email_verifications_controller_test.rb.tt +102 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/users/registrations/phone_verifications_controller_test.rb.tt +69 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/users/registrations_controller_test.rb.tt +180 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/users/sessions_controller_test.rb.tt +124 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/users/sms_sessions_controller_test.rb.tt +111 -0
- data/lib/generators/authnz_eleven/templates/test_unit/controllers/users/sudos_controller_test.rb.tt +110 -0
- data/lib/generators/authnz_eleven/templates/test_unit/fixtures/memberships.yml.tt +13 -0
- data/lib/generators/authnz_eleven/templates/test_unit/fixtures/teams.yml.tt +2 -0
- data/lib/generators/authnz_eleven/templates/test_unit/fixtures/users.yml.tt +68 -0
- data/lib/generators/authnz_eleven/templates/test_unit/mailers/user_mailer_test.rb.tt +88 -0
- data/lib/generators/authnz_eleven/templates/test_unit/models/api_token_test.rb.tt +38 -0
- data/lib/generators/authnz_eleven/templates/test_unit/models/password_history_test.rb.tt +51 -0
- data/lib/generators/authnz_eleven/templates/test_unit/models/session_test.rb.tt +16 -0
- data/lib/generators/authnz_eleven/templates/test_unit/models/sms_challengeable_test.rb.tt +108 -0
- data/lib/generators/authnz_eleven/templates/test_unit/models/user/guestable_test.rb.tt +78 -0
- data/lib/generators/authnz_eleven/templates/test_unit/models/user/recovery_codes_test.rb.tt +32 -0
- data/lib/generators/authnz_eleven/templates/test_unit/models/user/sign_in_methods_test.rb.tt +56 -0
- data/lib/generators/authnz_eleven/templates/test_unit/models/user_test.rb.tt +145 -0
- data/lib/generators/authnz_eleven/wizard_generator.rb +52 -0
- metadata +309 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
class <%= identity.module_name %>::MultiFactorAuthentication::Challenge::SmsController < <%= identity.controller_superclass %>
|
|
2
|
+
require_unauthenticated_access
|
|
3
|
+
rate_limit(**<%= identity.config_reference %>.rate_limits.sms_second_factor, only: :create,
|
|
4
|
+
with: -> { redirect_to new_<%= identity.route_scope %>_mfa_challenge_sms_path, alert: "Too many codes requested. Please try again later." })
|
|
5
|
+
before_action :set_user
|
|
6
|
+
before_action :require_sms_enrolled
|
|
7
|
+
|
|
8
|
+
def new
|
|
9
|
+
@user.issue_sms_challenge unless @user.sms_challenge?
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def create
|
|
13
|
+
@user.issue_sms_challenge
|
|
14
|
+
|
|
15
|
+
redirect_to new_<%= identity.route_scope %>_mfa_challenge_sms_path, notice: "We sent you another code."
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def update
|
|
19
|
+
unless @user.verify_sms_challenge(params[:code])
|
|
20
|
+
flash.now[:alert] = "That code is incorrect or has expired."
|
|
21
|
+
return render :new, status: :unprocessable_entity
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
<%- if rememberable? -%>
|
|
25
|
+
start_new_session_for(@user, via: :second_factor, remember: session.delete(:<%= session_key(:remember_me) %>))
|
|
26
|
+
<%- else -%>
|
|
27
|
+
start_new_session_for(@user, via: :second_factor)
|
|
28
|
+
<%- end -%>
|
|
29
|
+
redirect_to after_authentication_url, status: :see_other
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def set_user
|
|
35
|
+
@user = <%= identity.class_name %>.find_by_token_for!(:authentication_challenge, session[:<%= session_key(:challenge_token) %>])
|
|
36
|
+
rescue ActiveSupport::MessageVerifier::InvalidSignature, ActiveRecord::RecordNotFound
|
|
37
|
+
redirect_to <%= identity.route_scope %>_sign_in_path, alert: "Your sign-in challenge has expired. Please sign in again."
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def require_sms_enrolled
|
|
41
|
+
return if @user.sms_enrolled_at?
|
|
42
|
+
|
|
43
|
+
redirect_to <%= identity.route_scope %>_sign_in_path, alert: "Please sign in again."
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
class <%= identity.module_name %>::MultiFactorAuthentication::Challenge::TotpsController < <%= identity.controller_superclass %>
|
|
2
|
+
require_unauthenticated_access
|
|
3
|
+
rate_limit(**<%= identity.config_reference %>.rate_limits.totp_challenge, only: :create,
|
|
4
|
+
with: -> { redirect_to new_<%= identity.route_scope %>_mfa_challenge_totp_path, alert: "Too many attempts. Please try again later." })
|
|
5
|
+
before_action :set_user
|
|
6
|
+
before_action :require_totp_enrolled
|
|
7
|
+
|
|
8
|
+
def new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def create
|
|
12
|
+
totp = ROTP::TOTP.new(@user.totp_secret, issuer: <%= identity.config_reference %>.app_name)
|
|
13
|
+
used_at = totp.verify(params[:code], drift_behind: <%= identity.config_reference %>.second_factor.totp_drift_behind,
|
|
14
|
+
after: @user.totp_last_used_at)
|
|
15
|
+
|
|
16
|
+
if used_at
|
|
17
|
+
@user.update!(totp_last_used_at: Time.at(used_at))
|
|
18
|
+
<%- if rememberable? -%>
|
|
19
|
+
start_new_session_for(@user, via: :second_factor, remember: session.delete(:<%= session_key(:remember_me) %>))
|
|
20
|
+
<%- else -%>
|
|
21
|
+
start_new_session_for(@user, via: :second_factor)
|
|
22
|
+
<%- end -%>
|
|
23
|
+
redirect_to after_authentication_url, status: :see_other
|
|
24
|
+
else
|
|
25
|
+
redirect_to new_<%= identity.route_scope %>_mfa_challenge_totp_path, alert: "That code is incorrect."
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def set_user
|
|
32
|
+
@user = <%= identity.class_name %>.find_by_token_for!(:authentication_challenge, session[:<%= session_key(:challenge_token) %>])
|
|
33
|
+
rescue ActiveSupport::MessageVerifier::InvalidSignature, ActiveRecord::RecordNotFound
|
|
34
|
+
redirect_to <%= identity.route_scope %>_sign_in_path, alert: "Your sign-in challenge has expired. Please sign in again."
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def require_totp_enrolled
|
|
38
|
+
return if @user.totp_enrolled_at?
|
|
39
|
+
|
|
40
|
+
redirect_to <%= identity.route_scope %>_sign_in_path, alert: "Please sign in again."
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
class <%= identity.module_name %>::Omniauth::RegistrationsController < <%= identity.controller_superclass %>
|
|
2
|
+
include <%= identity.authentication_concern %>::Registering
|
|
3
|
+
|
|
4
|
+
require_unauthenticated_access
|
|
5
|
+
before_action :set_registration
|
|
6
|
+
|
|
7
|
+
def new
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def create
|
|
11
|
+
return render :new, status: :unprocessable_entity unless @registration.update(profile_params)
|
|
12
|
+
|
|
13
|
+
advance(@registration)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def set_registration
|
|
19
|
+
@registration = <%= identity.pending_registration_class %>.unexpired.find_by(id: session[:<%= pending_registration_session_key %>])
|
|
20
|
+
redirect_to <%= identity.route_scope %>_sign_in_path, alert: "That took too long. Please sign in again." unless @registration&.provider
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def profile_params
|
|
24
|
+
params.permit(<%= omniauth_registration_permits %>)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
class <%= identity.module_name %>::OmniauthController < <%= identity.controller_superclass %>
|
|
2
|
+
<%- if pending_registration_holds_provider? -%>
|
|
3
|
+
include <%= identity.authentication_concern %>::Registering
|
|
4
|
+
|
|
5
|
+
<%- end -%>
|
|
6
|
+
allow_unauthenticated_access
|
|
7
|
+
skip_before_action :verify_authenticity_token
|
|
8
|
+
|
|
9
|
+
def create
|
|
10
|
+
identity = <%= identity.omniauth_identity_class %>.find_by(provider: omniauth.provider, uid: omniauth.uid)
|
|
11
|
+
|
|
12
|
+
return link_identity(identity) if authenticated?
|
|
13
|
+
return sign_in(identity) if identity
|
|
14
|
+
<%- if pre_account_provider_enrollment? -%>
|
|
15
|
+
return complete_pending_registration if request.env.dig("omniauth.params", "registration_intent")
|
|
16
|
+
<%- end -%>
|
|
17
|
+
|
|
18
|
+
register
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def failure
|
|
22
|
+
redirect_to <%= identity.route_scope %>_sign_in_path, alert: params[:message]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def sign_in(identity)
|
|
28
|
+
user = identity.<%= identity.singular %>
|
|
29
|
+
<%= sign_in_call("user", via: "identity.via") %>
|
|
30
|
+
redirect_to after_authentication_url, status: :see_other
|
|
31
|
+
end
|
|
32
|
+
<%- if pre_account_provider_enrollment? -%>
|
|
33
|
+
|
|
34
|
+
def complete_pending_registration
|
|
35
|
+
@registration = <%= identity.pending_registration_class %>.unexpired.find_by(id: session[:<%= pending_registration_session_key %>])
|
|
36
|
+
unless @registration
|
|
37
|
+
return redirect_to <%= identity.route_scope %>_sign_up_path, alert: "That sign-up has expired. Please start again."
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
@registration.update!(provider: omniauth.provider, uid: omniauth.uid)
|
|
41
|
+
advance(@registration)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def render_invalid_registration
|
|
45
|
+
redirect_to <%= credential_enrollment_path %>, alert: @registration.errors.full_messages.to_sentence
|
|
46
|
+
end
|
|
47
|
+
<%- end -%>
|
|
48
|
+
|
|
49
|
+
def link_identity(existing)
|
|
50
|
+
if existing && existing.<%= identity.foreign_key %> != <%= identity.current_class %>.user.id
|
|
51
|
+
return redirect_to <%= identity.settings_helper_prefix %>_omniauth_identities_path,
|
|
52
|
+
alert: "That #{provider_name} account is already linked to another account."
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
if existing
|
|
56
|
+
return redirect_to <%= identity.settings_helper_prefix %>_omniauth_identities_path,
|
|
57
|
+
notice: "That account is already linked."
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
<%= identity.current_class %>.user.omniauth_identities.create!(provider: omniauth.provider, uid: omniauth.uid)
|
|
61
|
+
<%- if security_notifications? -%>
|
|
62
|
+
<%= identity.mailer_class %>.send_security_notification(:connected_account_linked)
|
|
63
|
+
<%- end -%>
|
|
64
|
+
redirect_to <%= identity.settings_helper_prefix %>_omniauth_identities_path, notice: "Linked.", status: :see_other
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
<%- if email_verifiable? -%>
|
|
68
|
+
# A provider's email address is taken as verified. Nothing reverifies it.
|
|
69
|
+
<%- end -%>
|
|
70
|
+
def register
|
|
71
|
+
<%- if principals.email&.required? -%>
|
|
72
|
+
return redirect_to <%= identity.route_scope %>_sign_in_path, alert: no_address_alert if omniauth.info.email.blank?
|
|
73
|
+
|
|
74
|
+
<%- end -%>
|
|
75
|
+
<%- if invite_only? -%>
|
|
76
|
+
unless pending_invitation_for(omniauth.info.email)
|
|
77
|
+
return redirect_to <%= identity.route_scope %>_sign_in_path, alert: "Registration is invite-only."
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
<%- end -%>
|
|
81
|
+
<%- if omniauth_registration? -%>
|
|
82
|
+
registration = <%= identity.pending_registration_class %>.new(provider: omniauth.provider, uid: omniauth.uid<%= ", email: omniauth.info.email" if principals.email %>)
|
|
83
|
+
<%- if email_verifiable? -%>
|
|
84
|
+
registration.email_verified_at = Time.current if registration.email.present?
|
|
85
|
+
<%- end -%>
|
|
86
|
+
<%- if invitable? -%>
|
|
87
|
+
registration.invitation = pending_invitation_for(omniauth.info.email)
|
|
88
|
+
<%- end -%>
|
|
89
|
+
registration.save!(validate: false)
|
|
90
|
+
session[:<%= pending_registration_session_key %>] = registration.id
|
|
91
|
+
|
|
92
|
+
advance(registration)
|
|
93
|
+
<%- else -%>
|
|
94
|
+
# Do not look up an account by the provider-reported email: it is a claim and could link an attacker to another account.
|
|
95
|
+
user = <%= identity.class_name %>.new<%= "(email: omniauth.info.email)" if principals.email %>
|
|
96
|
+
user.omniauth_identities.build(provider: omniauth.provider, uid: omniauth.uid)
|
|
97
|
+
|
|
98
|
+
case save_account(user)
|
|
99
|
+
when :ok
|
|
100
|
+
<%- if invitable? -%>
|
|
101
|
+
pending_invitation_for(omniauth.info.email)&.accept(user)
|
|
102
|
+
<%- end -%>
|
|
103
|
+
<%= sign_in_call("user", via: "provider_via") %>
|
|
104
|
+
redirect_to after_authentication_url, status: :see_other
|
|
105
|
+
when :taken
|
|
106
|
+
redirect_to <%= identity.route_scope %>_sign_in_path, alert: taken_alert
|
|
107
|
+
else
|
|
108
|
+
redirect_to <%= identity.route_scope %>_sign_in_path, alert: no_address_alert
|
|
109
|
+
end
|
|
110
|
+
<%- end -%>
|
|
111
|
+
end
|
|
112
|
+
<%- if !omniauth_registration? -%>
|
|
113
|
+
|
|
114
|
+
def save_account(user)
|
|
115
|
+
return :ok if user.save
|
|
116
|
+
|
|
117
|
+
user.errors.of_kind?(:email, :taken) ? :taken : :invalid
|
|
118
|
+
rescue ActiveRecord::RecordNotUnique
|
|
119
|
+
:taken
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def taken_alert
|
|
123
|
+
"An account already uses that email address. Sign in, then link #{provider_name} from your settings."
|
|
124
|
+
end
|
|
125
|
+
<%- end -%>
|
|
126
|
+
<%- if !omniauth_registration? || principals.email&.required? -%>
|
|
127
|
+
|
|
128
|
+
def no_address_alert
|
|
129
|
+
"That provider didn't share an email address, try signing up another way."
|
|
130
|
+
end
|
|
131
|
+
<%- end -%>
|
|
132
|
+
|
|
133
|
+
def provider_via = <%= identity.omniauth_identity_class %>.via(omniauth.provider)
|
|
134
|
+
def provider_name = provider_via.to_s.titleize
|
|
135
|
+
|
|
136
|
+
def omniauth
|
|
137
|
+
request.env["omniauth.auth"]
|
|
138
|
+
end
|
|
139
|
+
end
|
data/lib/generators/authnz_eleven/templates/controllers/users/passkeys/sessions_controller.rb.tt
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
class <%= identity.module_name %>::Passkeys::SessionsController < <%= identity.controller_superclass %>
|
|
2
|
+
require_unauthenticated_access
|
|
3
|
+
|
|
4
|
+
def new
|
|
5
|
+
# Omit an allow-list so discoverable passkeys can identify their owner; require user verification because this is passwordless sign-in.
|
|
6
|
+
issue_webauthn_challenge(WebAuthn::Credential.options_for_get(user_verification: "required"))
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def create
|
|
10
|
+
passkey = verify_webauthn_assertion(params.expect(credential: {}), from: <%= identity.webauthn_credential_class %><%= ".passkeys" if passkey_and_security_keys? %>)
|
|
11
|
+
user = passkey.<%= identity.singular %>
|
|
12
|
+
|
|
13
|
+
<%= sign_in_call("user", via: :passkey) %>
|
|
14
|
+
render json: { status: "ok", location: after_authentication_url }, status: :created
|
|
15
|
+
rescue WebAuthn::Error, ActiveRecord::RecordNotFound
|
|
16
|
+
render json: { error: "We couldn't verify that passkey. Please try again." }, status: :unprocessable_entity
|
|
17
|
+
end
|
|
18
|
+
end
|
data/lib/generators/authnz_eleven/templates/controllers/users/password_resets_controller.rb.tt
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
class <%= identity.module_name %>::PasswordResetsController < <%= identity.controller_superclass %>
|
|
2
|
+
require_unauthenticated_access
|
|
3
|
+
rate_limit(**<%= identity.config_reference %>.rate_limits.password_reset, only: :create,
|
|
4
|
+
with: -> { redirect_to root_path, alert: "Too many reset links requested. Please try again later." })
|
|
5
|
+
before_action :set_user, only: %i[edit update]
|
|
6
|
+
|
|
7
|
+
def new
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def edit
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def create
|
|
14
|
+
<%- if captchable? -%>
|
|
15
|
+
unless captcha_verified?
|
|
16
|
+
flash.now[:alert] = "Captcha verification failed. Please try again."
|
|
17
|
+
return render :new, status: :unprocessable_entity
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
<%- end -%>
|
|
21
|
+
<%- if coy? -%>
|
|
22
|
+
<%= deferred_call(identity.class_name, :request_password_reset, "params[:email].to_s") %>
|
|
23
|
+
redirect_to <%= identity.route_scope %>_sign_in_path, notice: "Check your email for password reset instructions."
|
|
24
|
+
<%- else -%>
|
|
25
|
+
if <%= identity.class_name %>.request_password_reset(params[:email])
|
|
26
|
+
redirect_to <%= identity.route_scope %>_sign_in_path, notice: "Check your email for password reset instructions."
|
|
27
|
+
else
|
|
28
|
+
redirect_to <%= identity.route_scope %>_forgot_password_path, alert: "No<%= email_verifiable? ? " verified" : "" %> account was found for that email."
|
|
29
|
+
end
|
|
30
|
+
<%- end -%>
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def update
|
|
34
|
+
if @user.update(user_params)
|
|
35
|
+
<%- if deadboltable? -%>
|
|
36
|
+
@user.undeadbolt!
|
|
37
|
+
<%- end -%>
|
|
38
|
+
<%- if security_notifications? -%>
|
|
39
|
+
<%= identity.mailer_class %>.send_security_notification(:password_reset, to: @user.email)
|
|
40
|
+
<%- end -%>
|
|
41
|
+
redirect_to <%= identity.route_scope %>_sign_in_path, notice: "Your password has been reset. Please sign in.",
|
|
42
|
+
status: :see_other
|
|
43
|
+
else
|
|
44
|
+
render :edit, status: :unprocessable_entity
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def set_user
|
|
51
|
+
@user = <%= identity.class_name %>.find_by_token_for(:password_reset, params.expect(:sid))
|
|
52
|
+
|
|
53
|
+
redirect_to_rejection unless @user
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def redirect_to_rejection
|
|
57
|
+
redirect_to <%= identity.route_scope %>_forgot_password_path, alert: "That password reset link is invalid or has expired.",
|
|
58
|
+
status: :see_other
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def user_params
|
|
62
|
+
params.permit(:password, :password_confirmation)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
class <%= identity.module_name %>::Registrations::EmailVerificationsController < <%= identity.controller_superclass %>
|
|
2
|
+
include <%= identity.authentication_concern %>::Registering
|
|
3
|
+
|
|
4
|
+
allow_unauthenticated_access
|
|
5
|
+
rate_limit(**<%= identity.config_reference %>.rate_limits.email_verification, only: :create,
|
|
6
|
+
with: -> { redirect_to <%= identity.route_scope %>_new_verify_email_path, alert: "Too many links requested. Please try again later." })
|
|
7
|
+
before_action :set_pending_registration, only: [ :new, :create ]
|
|
8
|
+
before_action :set_claimed_registration, only: [ :show, :update ]
|
|
9
|
+
|
|
10
|
+
def new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def create
|
|
14
|
+
<%= deferred_call("@registration", :request_email_verification) %>
|
|
15
|
+
redirect_to <%= identity.route_scope %>_new_verify_email_path, notice: "We sent you another link."
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def show
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def update
|
|
22
|
+
<%- if principals.username -%>
|
|
23
|
+
@registration.username = params[:username] if params[:username]
|
|
24
|
+
<%- end -%>
|
|
25
|
+
@registration.email_verified_at = Time.current
|
|
26
|
+
return render :show, status: :unprocessable_entity unless @registration.save
|
|
27
|
+
|
|
28
|
+
advance(@registration)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def set_pending_registration
|
|
34
|
+
@registration = <%= identity.pending_registration_class %>.unexpired.find_by(id: session[:<%= pending_registration_session_key %>])
|
|
35
|
+
redirect_to <%= registration_entry_path %> unless @registration
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def set_claimed_registration
|
|
39
|
+
@registration = <%= identity.pending_registration_class %>.unexpired.find_by_token_for(
|
|
40
|
+
:registration_email_verification, params.expect(:sid)
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
redirect_to_rejection unless @registration && session[:<%= pending_registration_session_key %>] == @registration.id
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def render_invalid_registration
|
|
47
|
+
render :show, status: :unprocessable_entity
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def redirect_to_rejection
|
|
51
|
+
redirect_to <%= registration_entry_path %>, alert: "That confirmation link is invalid or has expired."
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
class <%= identity.module_name %>::Registrations::PhoneVerificationsController < <%= identity.controller_superclass %>
|
|
2
|
+
include <%= identity.authentication_concern %>::Registering
|
|
3
|
+
|
|
4
|
+
allow_unauthenticated_access
|
|
5
|
+
rate_limit(**<%= identity.config_reference %>.rate_limits.phone_verification, only: :create,
|
|
6
|
+
with: -> { redirect_to <%= identity.route_scope %>_verify_phone_path, alert: "Too many codes requested. Please try again later." })
|
|
7
|
+
before_action :set_pending_registration
|
|
8
|
+
|
|
9
|
+
def new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def create
|
|
13
|
+
<%= deferred_call("@registration", :request_phone_verification) %>
|
|
14
|
+
redirect_to <%= identity.route_scope %>_verify_phone_path, notice: "We sent you another code."
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def update
|
|
18
|
+
<%- if principals.username -%>
|
|
19
|
+
@registration.username = params[:username] if params[:username]
|
|
20
|
+
return render :new, status: :unprocessable_entity unless @registration.valid?
|
|
21
|
+
<%- end -%>
|
|
22
|
+
unless @registration.verify_sms_challenge(params[:code])
|
|
23
|
+
flash.now[:alert] = "That code is incorrect or has expired."
|
|
24
|
+
return render :new, status: :unprocessable_entity
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
@registration.update!(phone_verified_at: Time.current)
|
|
28
|
+
advance(@registration)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def set_pending_registration
|
|
34
|
+
@registration = <%= identity.pending_registration_class %>.unexpired.find_by(id: session[:<%= pending_registration_session_key %>])
|
|
35
|
+
redirect_to <%= registration_entry_path %> unless @registration
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
class <%= identity.module_name %>::RegistrationsController < <%= identity.controller_superclass %>
|
|
2
|
+
<%- if typed_staged_registration? -%>
|
|
3
|
+
include <%= identity.authentication_concern %>::Registering
|
|
4
|
+
|
|
5
|
+
<%- end -%>
|
|
6
|
+
require_unauthenticated_access
|
|
7
|
+
rate_limit(**<%= identity.config_reference %>.rate_limits.sign_up, only: :create,
|
|
8
|
+
with: -> { redirect_to <%= identity.route_scope %>_sign_up_path, alert: "Too many sign-up attempts. Please try again later." })
|
|
9
|
+
<%- if invite_only? -%>
|
|
10
|
+
before_action :require_invitation_to_register
|
|
11
|
+
<%- end -%>
|
|
12
|
+
|
|
13
|
+
def new
|
|
14
|
+
<%- if invitable? -%>
|
|
15
|
+
@pending_invitation = pending_invitation
|
|
16
|
+
<%- end -%>
|
|
17
|
+
<%- if typed_staged_registration? -%>
|
|
18
|
+
@registration = <%= identity.pending_registration_class %>.new
|
|
19
|
+
<%- else -%>
|
|
20
|
+
@user = <%= identity.class_name %>.new
|
|
21
|
+
<%- end -%>
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
<%- if typed_staged_registration? -%>
|
|
25
|
+
def create
|
|
26
|
+
@registration = <%= identity.pending_registration_class %>.new(registration_params)
|
|
27
|
+
<%- if captchable? -%>
|
|
28
|
+
@registration.validate
|
|
29
|
+
@registration.errors.add(:base, "Captcha verification failed. Please try again.") unless captcha_verified?
|
|
30
|
+
return render :new, status: :unprocessable_entity if @registration.errors.any?
|
|
31
|
+
<%- else -%>
|
|
32
|
+
return render :new, status: :unprocessable_entity unless @registration.valid?
|
|
33
|
+
<%- end -%>
|
|
34
|
+
<%- if !coy? -%>
|
|
35
|
+
|
|
36
|
+
if (taken = taken_identifier)
|
|
37
|
+
@registration.errors.add(taken, "has already been taken")
|
|
38
|
+
return render :new, status: :unprocessable_entity
|
|
39
|
+
end
|
|
40
|
+
<%- end -%>
|
|
41
|
+
|
|
42
|
+
@registration.save!
|
|
43
|
+
session[:<%= pending_registration_session_key %>] = @registration.id
|
|
44
|
+
|
|
45
|
+
advance(@registration)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
<%- if !coy? -%>
|
|
50
|
+
|
|
51
|
+
def taken_identifier
|
|
52
|
+
<%- if principals.email -%>
|
|
53
|
+
return :email if @registration.email.present? && <%= identity.class_name %>.exists?(email: @registration.email)
|
|
54
|
+
<%- end -%>
|
|
55
|
+
<%- if principals.phone -%>
|
|
56
|
+
return :phone if @registration.phone.present? && <%= identity.class_name %>.exists?(phone: @registration.phone)
|
|
57
|
+
<%- end -%>
|
|
58
|
+
|
|
59
|
+
nil
|
|
60
|
+
end
|
|
61
|
+
<%- end -%>
|
|
62
|
+
|
|
63
|
+
def registration_params
|
|
64
|
+
<%= sign_up_params_expression %>
|
|
65
|
+
end
|
|
66
|
+
<%- else -%>
|
|
67
|
+
def create
|
|
68
|
+
@user = <%= identity.class_name %>.new(user_params)
|
|
69
|
+
<%- if captchable? -%>
|
|
70
|
+
@user.validate
|
|
71
|
+
@user.errors.add(:base, "Captcha verification failed. Please try again.") unless captcha_verified?
|
|
72
|
+
return render :new, status: :unprocessable_entity if @user.errors.any?
|
|
73
|
+
<%- else -%>
|
|
74
|
+
return render :new, status: :unprocessable_entity unless @user.valid?
|
|
75
|
+
<%- end -%>
|
|
76
|
+
|
|
77
|
+
if @user.save
|
|
78
|
+
<%- if invitable? -%>
|
|
79
|
+
pending_invitation&.accept(@user)
|
|
80
|
+
<%- end -%>
|
|
81
|
+
<%= sign_in_call("@user", via: :registration, may_challenge: false) %>
|
|
82
|
+
redirect_to after_authentication_url, status: :see_other
|
|
83
|
+
else
|
|
84
|
+
render :new, status: :unprocessable_entity
|
|
85
|
+
end
|
|
86
|
+
rescue ActiveRecord::RecordNotUnique
|
|
87
|
+
<%- if principals.email -%>
|
|
88
|
+
@user.errors.add(:email, "has already been taken")
|
|
89
|
+
<%- elsif principals.phone -%>
|
|
90
|
+
@user.errors.add(:phone, "has already been taken")
|
|
91
|
+
<%- else -%>
|
|
92
|
+
@user.errors.add(:base, "That account already exists")
|
|
93
|
+
<%- end -%>
|
|
94
|
+
render :new, status: :unprocessable_entity
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
private
|
|
98
|
+
|
|
99
|
+
def user_params
|
|
100
|
+
<%= sign_up_params_expression %>
|
|
101
|
+
end
|
|
102
|
+
<%- end -%>
|
|
103
|
+
<%- if invitable? -%>
|
|
104
|
+
|
|
105
|
+
def with_invitation(permitted)
|
|
106
|
+
invitation = pending_invitation
|
|
107
|
+
return permitted unless invitation
|
|
108
|
+
|
|
109
|
+
permitted.merge(<%= invitation_channel_pair %><%= ", invitation:" if typed_staged_registration? %>)
|
|
110
|
+
end
|
|
111
|
+
<%- end -%>
|
|
112
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
class <%= identity.module_name %>::SessionsController < <%= identity.controller_superclass %>
|
|
2
|
+
require_unauthenticated_access except: [ :destroy ]
|
|
3
|
+
<%- if impeded? -%>
|
|
4
|
+
skip_impediments only: :destroy
|
|
5
|
+
<%- end -%>
|
|
6
|
+
<%- if password? -%>
|
|
7
|
+
rate_limit(**<%= identity.config_reference %>.rate_limits.sign_in, only: :create,
|
|
8
|
+
with: -> { redirect_to <%= identity.route_scope %>_sign_in_path, alert: "Too many sign-in attempts. Please try again later." })
|
|
9
|
+
<%- end -%>
|
|
10
|
+
|
|
11
|
+
def new
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
<%- if password? -%>
|
|
15
|
+
def create
|
|
16
|
+
<%- if multi_login? -%>
|
|
17
|
+
identifier = params[:login].to_s.strip
|
|
18
|
+
|
|
19
|
+
<%- end -%>
|
|
20
|
+
<%- if captchable? -%>
|
|
21
|
+
unless captcha_verified?
|
|
22
|
+
return redirect_to <%= identity.route_scope %>_sign_in_path(<%= login_hint_param %>: <%= login_identifier_expr %>),
|
|
23
|
+
alert: "Captcha verification failed. Please try again."
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
<%- end -%>
|
|
27
|
+
user = <%= identity.class_name %>.authenticate_with_password(<%= login_identifier_expr %>, params[:password])
|
|
28
|
+
|
|
29
|
+
unless user
|
|
30
|
+
<%- if deadboltable? -%>
|
|
31
|
+
<%= failed_sign_in_lookup %>
|
|
32
|
+
return redirect_to <%= identity.route_scope %>_sign_in_path(<%= login_hint_param %>: <%= login_identifier_expr %>),
|
|
33
|
+
alert: <%= failed_sign_in_alert %>
|
|
34
|
+
<%- else -%>
|
|
35
|
+
return redirect_to <%= identity.route_scope %>_sign_in_path(<%= login_hint_param %>: <%= login_identifier_expr %>), alert: "<%= incorrect_login_message %>."
|
|
36
|
+
<%- end -%>
|
|
37
|
+
end
|
|
38
|
+
<%- if deadboltable? -%>
|
|
39
|
+
|
|
40
|
+
user.reset_failed_attempts!
|
|
41
|
+
<%- end -%>
|
|
42
|
+
|
|
43
|
+
<%= sign_in_call("user", via: :password, remember_expr: 'params[:remember_me] == "1"') %>
|
|
44
|
+
redirect_to after_authentication_url, status: :see_other
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
<%- end -%>
|
|
48
|
+
def destroy
|
|
49
|
+
terminate_current_session
|
|
50
|
+
redirect_to root_url, notice: "Signed out.", status: :see_other
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
class <%= identity.module_name %>::SmsSessionsController < <%= identity.controller_superclass %>
|
|
2
|
+
allow_unauthenticated_access
|
|
3
|
+
rate_limit(**<%= identity.config_reference %>.rate_limits.sms_sign_in, only: :create,
|
|
4
|
+
with: -> { redirect_to <%= identity.route_scope %>_sms_sign_in_path, alert: "Too many codes requested. Please try again later." })
|
|
5
|
+
before_action :set_pending_user, only: [ :edit, :update ]
|
|
6
|
+
|
|
7
|
+
SESSION_KEY = :pending_sms_sign_in
|
|
8
|
+
|
|
9
|
+
def new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def create
|
|
13
|
+
<%- if captchable? -%>
|
|
14
|
+
unless captcha_verified?
|
|
15
|
+
flash.now[:alert] = "Captcha verification failed. Please try again."
|
|
16
|
+
return render :new, status: :unprocessable_entity
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
<%- end -%>
|
|
20
|
+
<%- if coy? -%>
|
|
21
|
+
<%= deferred_call(identity.class_name, :issue_sms_sign_in_code, "params[:phone].to_s") %>
|
|
22
|
+
session[SESSION_KEY] = params[:phone].to_s
|
|
23
|
+
redirect_to <%= identity.route_scope %>_sms_sign_in_code_path, notice: "We sent a code if that number has an account."
|
|
24
|
+
<%- else -%>
|
|
25
|
+
unless <%= identity.class_name %>.issue_sms_sign_in_code(params[:phone])
|
|
26
|
+
return redirect_to <%= identity.route_scope %>_sms_sign_in_path, alert: "No account was found for that number."
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
session[SESSION_KEY] = params[:phone].to_s
|
|
30
|
+
redirect_to <%= identity.route_scope %>_sms_sign_in_code_path, notice: "We sent a code to that number."
|
|
31
|
+
<%- end -%>
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def edit
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def update
|
|
38
|
+
unless (@user || <%= identity.class_name %>.new).verify_sms_challenge(params[:code])
|
|
39
|
+
flash.now[:alert] = "That code is incorrect or has expired."
|
|
40
|
+
return render :edit, status: :unprocessable_entity
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
session.delete(SESSION_KEY)
|
|
44
|
+
<%= sign_in_call("@user", via: :sms_code) %>
|
|
45
|
+
redirect_to after_authentication_url, status: :see_other
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def set_pending_user
|
|
51
|
+
@user = <%= identity.class_name %>.find_by(phone: session[SESSION_KEY])
|
|
52
|
+
end
|
|
53
|
+
end
|