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,275 @@
|
|
|
1
|
+
# Generated by authnz_eleven <%= AuthnzEleven::VERSION %> with:
|
|
2
|
+
#
|
|
3
|
+
<%- generation_command_lines.each do |line| -%>
|
|
4
|
+
# <%= line %>
|
|
5
|
+
<%- end -%>
|
|
6
|
+
#
|
|
7
|
+
# Configuration for your generated auth system. Adjust them to suit
|
|
8
|
+
# your needs.
|
|
9
|
+
#
|
|
10
|
+
# <%= identity.config_constant %> is an alias for <%= identity.config_storage %>.
|
|
11
|
+
# Both refer to the same config, so you can use either. The generated code uses
|
|
12
|
+
# <%= identity.config_constant %>.
|
|
13
|
+
<%= identity.config_storage %> = ActiveSupport::OrderedOptions.new
|
|
14
|
+
<%= identity.config_constant %> = <%= identity.config_storage %>
|
|
15
|
+
|
|
16
|
+
<%= identity.config_constant %>.tap do |config|
|
|
17
|
+
# Shown as the issuer in authenticator apps and used in mailer subjects.
|
|
18
|
+
config.app_name = Rails.application.class.module_parent_name
|
|
19
|
+
|
|
20
|
+
# How often to save a session's last activity to the database. No need to
|
|
21
|
+
# write it on every request.
|
|
22
|
+
config.session = ActiveSupport::OrderedOptions.new
|
|
23
|
+
config.session.activity_write_interval = 15.minutes
|
|
24
|
+
<%- if timeoutable? -%>
|
|
25
|
+
# Sign out sessions after they are inactive for this long. They are deleted on the user's
|
|
26
|
+
# next request. For users who never come back, run the included cleanup task:
|
|
27
|
+
# `authnz_eleven:delete_timed_out_sessions`.
|
|
28
|
+
config.session.idle_timeout = 7.days
|
|
29
|
+
<%- end -%>
|
|
30
|
+
<%- if rememberable? -%>
|
|
31
|
+
# How long the "remember me" cookie lasts. Without "remember me", the cookie
|
|
32
|
+
# lasts only until the browser closes.
|
|
33
|
+
config.session.remember_for = 2.weeks
|
|
34
|
+
<%- end -%>
|
|
35
|
+
<%- if max_sessionable? -%>
|
|
36
|
+
# How many devices a <%= identity.singular %> can be signed in on at once.
|
|
37
|
+
# "Remember me" sessions count too. If a new sign-in would exceed the limit,
|
|
38
|
+
<%- if max_sessions_prompt? -%>
|
|
39
|
+
# the user is held at the session list until they sign one out
|
|
40
|
+
# (--max-sessionable=prompt). Set to nil to allow any number of sessions.
|
|
41
|
+
<%- else -%>
|
|
42
|
+
# the least-recently-active session is signed out to make room
|
|
43
|
+
# (--max-sessionable=evict). Set to nil to allow any number of sessions.
|
|
44
|
+
<%- end -%>
|
|
45
|
+
config.session.concurrent_limit = 3
|
|
46
|
+
<%- end -%>
|
|
47
|
+
<%- if guestable? -%>
|
|
48
|
+
|
|
49
|
+
# How long to keep a guest <%= identity.singular %>. This is measured from creation, not last activity.
|
|
50
|
+
# Guests are not authenticated, so we don't "sign them out" due to inactivity.
|
|
51
|
+
<%- if timeoutable? -%>
|
|
52
|
+
# session.idle_timeout does not apply to guests.
|
|
53
|
+
<%- end -%>
|
|
54
|
+
# The guest cookie lives for this long too, including across browser restarts.
|
|
55
|
+
# Run `authnz_eleven:delete_expired_guests` to delete expired guests.
|
|
56
|
+
config.guest = ActiveSupport::OrderedOptions.new
|
|
57
|
+
config.guest.ttl = 30.days
|
|
58
|
+
<%- end -%>
|
|
59
|
+
<%- if impersonatable? -%>
|
|
60
|
+
|
|
61
|
+
# How long an admin can impersonate another <%= identity.singular %>. Activity does
|
|
62
|
+
# not extend this. Once it expires, the next request returns the admin to the
|
|
63
|
+
# admin area as themselves, and that request is not carried out, since it was made
|
|
64
|
+
# as someone else.
|
|
65
|
+
config.impersonation = ActiveSupport::OrderedOptions.new
|
|
66
|
+
config.impersonation.duration = 1.hour
|
|
67
|
+
<%- end -%>
|
|
68
|
+
|
|
69
|
+
<%- if principals.username -%>
|
|
70
|
+
# Usernames nobody may register, like "admin" or "support". Edit
|
|
71
|
+
# config/forbidden_usernames.txt to add or remove names, or replace this with
|
|
72
|
+
# your own list. It must be a Set of downcased strings. Blank lines and "#"
|
|
73
|
+
# comments in the file are ignored.
|
|
74
|
+
#
|
|
75
|
+
# To change the format or the 3–20 character limit, edit the model's `format:`
|
|
76
|
+
# validation. When sign-in accepts multiple identifiers, it checks for "@"
|
|
77
|
+
# first (email), then a letter (username), otherwise it tries a phone number.
|
|
78
|
+
# Keep usernames free of "@" and require at least one letter so they cannot
|
|
79
|
+
# be mistaken for either.
|
|
80
|
+
config.username = ActiveSupport::OrderedOptions.new
|
|
81
|
+
config.username.forbidden = File.readlines(Rails.root.join("config/forbidden_usernames.txt"), chomp: true)
|
|
82
|
+
.map { |line| line.strip.downcase }
|
|
83
|
+
.reject { |line| line.empty? || line.start_with?("#") }
|
|
84
|
+
.to_set
|
|
85
|
+
|
|
86
|
+
<%- end -%>
|
|
87
|
+
<%- if principals.phone -%>
|
|
88
|
+
# Interpret numbers without "+" using this country:
|
|
89
|
+
# "US": (415) 826-4001 → +14158264001
|
|
90
|
+
# "GB": 020 7183 8750 → +442071838750
|
|
91
|
+
# An array, like %w[US GB], tries countries in order.
|
|
92
|
+
# Numbers with "+" already specify their country and ignore this default.
|
|
93
|
+
# This controls parsing, not which countries are allowed.
|
|
94
|
+
# Keep a default to avoid guessing from leading digits. Without one, a
|
|
95
|
+
# number from Gainesville, Florida (Go Gators! 🐊), (352) 555-0166, is parsed
|
|
96
|
+
# as +352 5550166 (Luxembourg).
|
|
97
|
+
config.phone = ActiveSupport::OrderedOptions.new
|
|
98
|
+
config.phone.default_country = %w[US CA]
|
|
99
|
+
|
|
100
|
+
# Accepted phone-number countries. nil allows all countries.
|
|
101
|
+
config.phone.allowed_countries = nil
|
|
102
|
+
# config.phone.allowed_countries = %w[US CA]
|
|
103
|
+
|
|
104
|
+
<%- end -%>
|
|
105
|
+
<%- if password? -%>
|
|
106
|
+
# Password rules.
|
|
107
|
+
config.password = ActiveSupport::OrderedOptions.new
|
|
108
|
+
config.password.minimum_length = 10
|
|
109
|
+
<%- if password_rotatable? -%>
|
|
110
|
+
# Require a new password after this long. On their next request, the user is
|
|
111
|
+
# held at the change-password page until they change it. Set to nil to stop
|
|
112
|
+
# expiring passwords.
|
|
113
|
+
#
|
|
114
|
+
# I do not recommend scheduled rotation unless your compliance policy requires
|
|
115
|
+
# it. NIST SP 800-63B advises against it because it encourages predictable
|
|
116
|
+
# passwords. Prefer longer passwords and breach-checking (--pwned).
|
|
117
|
+
config.password.maximum_age = 90.days
|
|
118
|
+
<%- end -%>
|
|
119
|
+
<%- if password_historical? -%>
|
|
120
|
+
# How many previous passwords to check when refusing password reuse. The
|
|
121
|
+
# current password is also checked. Stored digests are small, so you can raise
|
|
122
|
+
# this if your policy requires a longer history. Set to nil to keep archiving
|
|
123
|
+
# passwords without rejecting reuse.
|
|
124
|
+
config.password.history_depth = 5
|
|
125
|
+
<%- end -%>
|
|
126
|
+
<%- if strong_passwords? -%>
|
|
127
|
+
# Minimum zxcvbn strength score (0–4). 3 is "safely unguessable", and 4 is the
|
|
128
|
+
# strictest. Passwords scoring below this are rejected by the Authenticatable
|
|
129
|
+
# concern.
|
|
130
|
+
config.password.minimum_strength = 3
|
|
131
|
+
<%- end -%>
|
|
132
|
+
<%- if pwned? -%>
|
|
133
|
+
|
|
134
|
+
# Check new passwords against Have I Been Pwned. Enabled only in production
|
|
135
|
+
# because it makes an HTTP request and would reject the test fixture passwords.
|
|
136
|
+
config.password.check_breaches = Rails.env.production?
|
|
137
|
+
<%- end -%>
|
|
138
|
+
|
|
139
|
+
<%- end -%>
|
|
140
|
+
# How long links, codes, and challenges remain valid.
|
|
141
|
+
config.tokens = ActiveSupport::OrderedOptions.new
|
|
142
|
+
<%- if email_gated_registration? -%>
|
|
143
|
+
config.tokens.registration_email_verification = 2.days
|
|
144
|
+
<%- end -%>
|
|
145
|
+
<%- if email_change_verification? -%>
|
|
146
|
+
config.tokens.email_change_verification = 2.days
|
|
147
|
+
<%- end -%>
|
|
148
|
+
<%- if recoverable? -%>
|
|
149
|
+
config.tokens.password_reset = 20.minutes
|
|
150
|
+
<%- end -%>
|
|
151
|
+
<%- if magic_link? -%>
|
|
152
|
+
config.tokens.magic_link = 20.minutes
|
|
153
|
+
<%- end -%>
|
|
154
|
+
<%- if second_factor? -%>
|
|
155
|
+
config.tokens.mfa_challenge = 20.minutes
|
|
156
|
+
<%- end -%>
|
|
157
|
+
<%- if invitable? -%>
|
|
158
|
+
config.tokens.invitation = 7.days
|
|
159
|
+
<%- end -%>
|
|
160
|
+
<%- if sms? -%>
|
|
161
|
+
config.tokens.sms_code = 10.minutes
|
|
162
|
+
<%- end -%>
|
|
163
|
+
<%- if pending_registration? -%>
|
|
164
|
+
# How long an unfinished sign-up can sit before cleanup deletes it. Each step,
|
|
165
|
+
# and each link or code sent, restarts the clock. Keep this longer than the
|
|
166
|
+
# registration links above so cleanup doesn't delete a sign-up whose link is
|
|
167
|
+
# still valid.
|
|
168
|
+
config.tokens.pending_registration = 3.days
|
|
169
|
+
<%- end -%>
|
|
170
|
+
<%- if second_factor? -%>
|
|
171
|
+
|
|
172
|
+
# Second-factor authentication.
|
|
173
|
+
config.second_factor = ActiveSupport::OrderedOptions.new
|
|
174
|
+
<%- if totp? -%>
|
|
175
|
+
config.second_factor.totp_drift_behind = 10
|
|
176
|
+
<%- end -%>
|
|
177
|
+
config.second_factor.recovery_code_count = 10
|
|
178
|
+
config.second_factor.recovery_code_length = 10
|
|
179
|
+
|
|
180
|
+
# Which sign-in methods require a second factor, if the user has enrolled one.
|
|
181
|
+
# Methods not listed are accepted on their own. Passkey sign-in is not listed
|
|
182
|
+
# by default because it is already phishing-resistant.
|
|
183
|
+
#
|
|
184
|
+
# Adjust this to suit your security/convenience trade-off. For example, add
|
|
185
|
+
# :magic_link if access to the user's inbox is not enough for your app.
|
|
186
|
+
#
|
|
187
|
+
<%- if omniauth? -%>
|
|
188
|
+
# For social login, use the provider name, not :omniauth. For example, :google
|
|
189
|
+
# for google_oauth2. Add providers if you don't want to rely on their own MFA.
|
|
190
|
+
# :omniauth itself matches nothing.
|
|
191
|
+
#
|
|
192
|
+
<%- end -%>
|
|
193
|
+
# Do not add :second_factor. It is used after a successful second-factor
|
|
194
|
+
# challenge, so requiring another would cause a redirect loop. :registration
|
|
195
|
+
# is also unnecessary: a newly created account has no second factor yet.
|
|
196
|
+
config.second_factor.needed_after = %i[<%= default_needed_after.join(" ") %>]
|
|
197
|
+
<%- end -%>
|
|
198
|
+
|
|
199
|
+
<%- if deadboltable? -%>
|
|
200
|
+
# How many consecutive failed password sign-ins deadbolt the password door,
|
|
201
|
+
# and how long it stays shut. Once the duration passes, it unlocks and the
|
|
202
|
+
# count starts over. A completed password reset unlocks it early, or you can
|
|
203
|
+
# call `user.undeadbolt!` yourself.
|
|
204
|
+
#
|
|
205
|
+
# Other sign-in methods still work. An attacker guessing at someone's password
|
|
206
|
+
# should not also lock them out of their passkey or magic link.
|
|
207
|
+
#
|
|
208
|
+
# Set maximum_attempts to nil to count failures without locking password
|
|
209
|
+
# sign-in.
|
|
210
|
+
config.deadbolt = ActiveSupport::OrderedOptions.new
|
|
211
|
+
config.deadbolt.maximum_attempts = 10
|
|
212
|
+
config.deadbolt.duration = 1.day
|
|
213
|
+
|
|
214
|
+
<%- end -%>
|
|
215
|
+
<%- if sms? -%>
|
|
216
|
+
# Wrong guesses allowed per texted code. This is separate from the rate limits,
|
|
217
|
+
# which limit how often codes can be sent.
|
|
218
|
+
config.sms = ActiveSupport::OrderedOptions.new
|
|
219
|
+
config.sms.max_attempts = 3
|
|
220
|
+
|
|
221
|
+
<%- end -%>
|
|
222
|
+
# Request limits, written as { to: number_of_requests, within: duration }.
|
|
223
|
+
# Limits sends, not guesses.
|
|
224
|
+
config.rate_limits = ActiveSupport::OrderedOptions.new
|
|
225
|
+
<%- if password? -%>
|
|
226
|
+
config.rate_limits.sign_in = { to: 10, within: 10.minutes }
|
|
227
|
+
<%- end -%>
|
|
228
|
+
<%- if recoverable? -%>
|
|
229
|
+
config.rate_limits.password_reset = { to: 3, within: 1.hour }
|
|
230
|
+
<%- end -%>
|
|
231
|
+
<%- if second_factor? -%>
|
|
232
|
+
<%- if totp? -%>
|
|
233
|
+
config.rate_limits.totp_challenge = { to: 10, within: 5.minutes }
|
|
234
|
+
<%- end -%>
|
|
235
|
+
<%- if sms_second_factor? -%>
|
|
236
|
+
config.rate_limits.sms_second_factor = { to: 5, within: 1.hour }
|
|
237
|
+
<%- end -%>
|
|
238
|
+
config.rate_limits.recovery_code_challenge = { to: 10, within: 1.hour }
|
|
239
|
+
<%- end -%>
|
|
240
|
+
<%- if magic_link? -%>
|
|
241
|
+
config.rate_limits.magic_link = { to: 10, within: 1.hour }
|
|
242
|
+
<%- end -%>
|
|
243
|
+
<%- if email_verifiable? -%>
|
|
244
|
+
# Requests and resends for email confirmation.
|
|
245
|
+
config.rate_limits.email_verification = { to: 5, within: 1.hour }
|
|
246
|
+
<%- end -%>
|
|
247
|
+
<%- if invitable? -%>
|
|
248
|
+
config.rate_limits.invitation = { to: 5, within: 1.hour }
|
|
249
|
+
<%- end -%>
|
|
250
|
+
<%- if phone_verifiable? -%>
|
|
251
|
+
# Requests and resends for phone confirmation. Every text costs money.
|
|
252
|
+
config.rate_limits.phone_verification = { to: 5, within: 1.hour }
|
|
253
|
+
<%- end -%>
|
|
254
|
+
<%- if sms_code? -%>
|
|
255
|
+
# Texted sign-in codes. These typically cost more than emails.
|
|
256
|
+
config.rate_limits.sms_sign_in = { to: 5, within: 1.hour }
|
|
257
|
+
<%- end -%>
|
|
258
|
+
<%- if sudoable? -%>
|
|
259
|
+
# Failed sudo challenges per session. Successful confirmation resets the count.
|
|
260
|
+
config.rate_limits.sudo = { to: 10, within: 10.minutes }
|
|
261
|
+
<%- end -%>
|
|
262
|
+
<%- if sudoable? -%>
|
|
263
|
+
|
|
264
|
+
# How long a sudo confirmation keeps protected pages unlocked.
|
|
265
|
+
config.sudo = ActiveSupport::OrderedOptions.new
|
|
266
|
+
config.sudo.window = 15.minutes
|
|
267
|
+
<%- end -%>
|
|
268
|
+
<%- if password? -%>
|
|
269
|
+
# Submission limits for settings forms that require the current password.
|
|
270
|
+
config.rate_limits.password_challenge = { to: 5, within: 10.minutes }
|
|
271
|
+
<%- end -%>
|
|
272
|
+
<%- if typed_registration? -%>
|
|
273
|
+
config.rate_limits.sign_up = { to: 5, within: 1.hour }
|
|
274
|
+
<%- end -%>
|
|
275
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
OmniAuth.config.request_validation_phase = OmniAuth::AuthenticityTokenProtection.new(key: :_csrf_token)
|
|
2
|
+
|
|
3
|
+
# Replace :developer with your real provider(s), e.g.
|
|
4
|
+
# provider :google_oauth2, ENV["GOOGLE_CLIENT_ID"], ENV["GOOGLE_CLIENT_SECRET"], scope: "email,profile"
|
|
5
|
+
# provider :github, ENV["GITHUB_ID"], ENV["GITHUB_SECRET"], scope: "user:email"
|
|
6
|
+
Rails.application.config.middleware.use OmniAuth::Builder do
|
|
7
|
+
options path_prefix: "<%= omniauth_path_prefix %>"
|
|
8
|
+
provider :developer unless Rails.env.production?
|
|
9
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module TeamSlug
|
|
2
|
+
PREFIX = %r{\A/(\d+)(?=/|\z)}
|
|
3
|
+
|
|
4
|
+
class Extractor
|
|
5
|
+
def initialize(app)
|
|
6
|
+
@app = app
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def call(env)
|
|
10
|
+
request = ActionDispatch::Request.new(env)
|
|
11
|
+
|
|
12
|
+
if (match = PREFIX.match(request.path_info)) && (team = Team.find_by(id: match[1]))
|
|
13
|
+
request.script_name = "#{request.script_name}/#{match[1]}"
|
|
14
|
+
request.path_info = match.post_match.presence || "/"
|
|
15
|
+
|
|
16
|
+
Current.team = team
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
@app.call(request.env)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
Rails.application.config.middleware.insert_after Rack::TempfileReaper, TeamSlug::Extractor
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
WebAuthn.configure do |config|
|
|
2
|
+
# The fully-qualified origin(s) of your app. Set per environment (use your
|
|
3
|
+
# real https origin(s) in production)
|
|
4
|
+
config.allowed_origins = ENV.fetch("WEBAUTHN_ORIGIN", "http://localhost:3000").split(",")
|
|
5
|
+
|
|
6
|
+
# The domain WebAuthn credentials are scoped to (no scheme, port, or path).
|
|
7
|
+
# Set WEBAUTHN_RP_ID in production. Every allowed origin's host must equal
|
|
8
|
+
# this value or be its subdomain; for example, app.example.com and
|
|
9
|
+
# admin.example.com can share an RP ID of example.com.
|
|
10
|
+
config.rp_id = ENV.fetch("WEBAUTHN_RP_ID", "localhost")
|
|
11
|
+
|
|
12
|
+
# Relying-party display name, shown by some authenticators.
|
|
13
|
+
config.rp_name = Rails.application.class.module_parent_name
|
|
14
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
en:
|
|
2
|
+
activerecord:
|
|
3
|
+
attributes:
|
|
4
|
+
<%= identity.singular %>:
|
|
5
|
+
pending_email: "Email"
|
|
6
|
+
pending_phone: "Phone"
|
|
7
|
+
password_challenge: "Current password"
|
|
8
|
+
<%- if invitable? -%>
|
|
9
|
+
<%= identity.invitation_file %>:
|
|
10
|
+
sent_to: "<%= invitation_recipient_label %>"
|
|
11
|
+
<%- end -%>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
class <%= identity.nested_module("ActiveTeamsController") %> < <%= identity.controller_superclass %>
|
|
2
|
+
def create
|
|
3
|
+
set_session_team!(<%= identity.current_class %>.user.teams.find(params[:team_id]))
|
|
4
|
+
redirect_to <%= identity.nested_helper("root_path") %>, notice: "Switched team."
|
|
5
|
+
end
|
|
6
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
class <%= admin_module %>::SessionsController < <%= admin_controller %>
|
|
2
|
+
def index
|
|
3
|
+
sessions = <%= identity.session_class %>.includes(:<%= identity.singular %><%= session_carries_team? ? ", :team" : "" %>).order(created_at: :desc)
|
|
4
|
+
|
|
5
|
+
if params[:user_id].present?
|
|
6
|
+
sessions = sessions.where(<%= identity.foreign_key %>: params[:user_id])
|
|
7
|
+
@filtered_user = <%= identity.class_name %>.find(params[:user_id])
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
@sessions = sessions.limit(100)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def destroy
|
|
14
|
+
<%= identity.session_class %>.find(params[:id]).destroy!
|
|
15
|
+
redirect_to <%= admin_helper("sessions_path") %>, notice: "Session ended.", status: :see_other
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
class <%= admin_module %>::UsersController < <%= admin_controller %>
|
|
2
|
+
before_action :set_user, only: %i[show destroy destroy_all_sessions<%= " reset_second_factor" if second_factor? %><%= " undeadbolt" if deadboltable? %><%= " ban unban" if bannable? %><%= " impersonate" if impersonatable? %>]
|
|
3
|
+
before_action :refuse_admin_target, only: %i[destroy<%= " reset_second_factor" if second_factor? %><%= " ban" if bannable? %><%= " impersonate" if impersonatable? %>]
|
|
4
|
+
|
|
5
|
+
def index
|
|
6
|
+
@users = <%= identity.class_name %>.order(:<%= principals.display.column %>)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def show
|
|
10
|
+
@sessions = @user.sessions.order(created_at: :desc)
|
|
11
|
+
<%- if trackable? -%>
|
|
12
|
+
@events = @user.events.recent_first.limit(100)
|
|
13
|
+
<%- end -%>
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def destroy
|
|
17
|
+
<%- if security_notifications? -%>
|
|
18
|
+
email = @user.email
|
|
19
|
+
<%- end -%>
|
|
20
|
+
@user.destroy!
|
|
21
|
+
<%- if security_notifications? -%>
|
|
22
|
+
<%= identity.mailer_class %>.send_security_notification(:account_deleted, to: email)
|
|
23
|
+
<%- end -%>
|
|
24
|
+
redirect_to <%= admin_helper("users_path") %>, notice: "User deleted.", status: :see_other
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def destroy_all_sessions
|
|
28
|
+
count = @user.sessions.count
|
|
29
|
+
@user.sessions.destroy_all
|
|
30
|
+
<%- if security_notifications? -%>
|
|
31
|
+
<%= identity.mailer_class %>.send_security_notification(:sessions_revoked_by_admin, to: @user.email)
|
|
32
|
+
<%- end -%>
|
|
33
|
+
redirect_to <%= admin_helper("user_path") %>(@user), notice: "Ended #{count} session(s) for #{@user.<%= principals.display.column %>}.",
|
|
34
|
+
status: :see_other
|
|
35
|
+
end
|
|
36
|
+
<%- if second_factor? -%>
|
|
37
|
+
|
|
38
|
+
def reset_second_factor
|
|
39
|
+
@user.reset_second_factor!
|
|
40
|
+
<%- if security_notifications? -%>
|
|
41
|
+
<%= identity.mailer_class %>.send_security_notification(:second_factor_reset_by_admin, to: @user.email)
|
|
42
|
+
<%- end -%>
|
|
43
|
+
redirect_to <%= admin_helper("user_path") %>(@user), notice: "Cleared every second factor on #{@user.<%= principals.display.column %>}'s account."
|
|
44
|
+
end
|
|
45
|
+
<%- end -%>
|
|
46
|
+
<%- if deadboltable? -%>
|
|
47
|
+
|
|
48
|
+
def undeadbolt
|
|
49
|
+
@user.undeadbolt!
|
|
50
|
+
<%- if security_notifications? -%>
|
|
51
|
+
<%= identity.mailer_class %>.send_security_notification(:deadbolt_cleared_by_admin, to: @user.email)
|
|
52
|
+
<%- end -%>
|
|
53
|
+
redirect_to <%= admin_helper("user_path") %>(@user), notice: "Cleared the sign-in deadbolt on #{@user.<%= principals.display.column %>}."
|
|
54
|
+
end
|
|
55
|
+
<%- end -%>
|
|
56
|
+
<%- if bannable? -%>
|
|
57
|
+
|
|
58
|
+
def ban
|
|
59
|
+
@user.ban!
|
|
60
|
+
<%- if security_notifications? -%>
|
|
61
|
+
<%= identity.mailer_class %>.send_security_notification(:account_suspended, to: @user.email)
|
|
62
|
+
<%- end -%>
|
|
63
|
+
redirect_to <%= admin_helper("user_path") %>(@user), notice: "Suspended #{@user.<%= principals.display.column %>} and ended their sessions."
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def unban
|
|
67
|
+
@user.unban!
|
|
68
|
+
<%- if security_notifications? -%>
|
|
69
|
+
<%= identity.mailer_class %>.send_security_notification(:account_restored, to: @user.email)
|
|
70
|
+
<%- end -%>
|
|
71
|
+
redirect_to <%= admin_helper("user_path") %>(@user), notice: "Lifted the suspension on #{@user.<%= principals.display.column %>}."
|
|
72
|
+
end
|
|
73
|
+
<%- end -%>
|
|
74
|
+
<%- if impersonatable? -%>
|
|
75
|
+
|
|
76
|
+
def impersonate
|
|
77
|
+
impersonate_user(@user)
|
|
78
|
+
redirect_to <%= identity.nested_helper("root_path") %>
|
|
79
|
+
end
|
|
80
|
+
<%- end -%>
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
def set_user
|
|
85
|
+
@user = <%= identity.class_name %>.find(params[:id])
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def refuse_admin_target
|
|
89
|
+
redirect_to <%= admin_helper("users_path") %>, alert: "That isn't available for an admin account.", status: :see_other if @user.admin?
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class <%= identity.base_controller %> < ActionController::Base
|
|
2
|
+
include <%= identity.authentication_concern %>
|
|
3
|
+
<%- if authorization? -%>
|
|
4
|
+
include <%= identity.authorization_concern %>
|
|
5
|
+
<%- end -%>
|
|
6
|
+
<%- if captchable? -%>
|
|
7
|
+
include Captchable
|
|
8
|
+
<%- end -%>
|
|
9
|
+
|
|
10
|
+
layout "<%= identity.controller_module %>"
|
|
11
|
+
end
|
data/lib/generators/authnz_eleven/templates/controllers/concerns/api_token_authentication.rb.tt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module <%= identity.nested_module("ApiTokenAuthentication") %>
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
included do
|
|
5
|
+
include ActionController::HttpAuthentication::Token::ControllerMethods
|
|
6
|
+
before_action :authenticate_api_token
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
attr_reader :current_api_token
|
|
12
|
+
|
|
13
|
+
def current_api_user
|
|
14
|
+
current_api_token.user
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def authenticate_api_token
|
|
18
|
+
@current_api_token = authenticate_with_http_token { |secret, _| <%= identity.api_token_class %>.authenticate(secret) }
|
|
19
|
+
render json: { error: "Unauthorized" }, status: :unauthorized unless @current_api_token
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/generators/authnz_eleven/templates/controllers/concerns/authentication/easy_dev_login.rb.tt
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module <%= identity.authentication_concern %>::EasyDevLogin
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
<%- if second_factor? -%>
|
|
4
|
+
|
|
5
|
+
def self.mfa_required?
|
|
6
|
+
ENV["REQUIRE_DEV_MFA"].present?
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.passwords_required?
|
|
10
|
+
ENV["REQUIRE_DEV_PASSWORD"].present? || mfa_required?
|
|
11
|
+
end
|
|
12
|
+
<%- else -%>
|
|
13
|
+
|
|
14
|
+
def self.passwords_required?
|
|
15
|
+
ENV["REQUIRE_DEV_PASSWORD"].present?
|
|
16
|
+
end
|
|
17
|
+
<%- end -%>
|
|
18
|
+
|
|
19
|
+
included do
|
|
20
|
+
raise "Authentication::EasyDevLogin must never load outside development" unless Rails.env.development?
|
|
21
|
+
|
|
22
|
+
prepend_before_action :easy_dev_login!
|
|
23
|
+
<%- if admin_mfa_gate? -%>
|
|
24
|
+
|
|
25
|
+
skip_before_action :require_admin_mfa unless Authentication::EasyDevLogin.mfa_required?
|
|
26
|
+
<%- end -%>
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def easy_dev_login!
|
|
32
|
+
return if Authentication::EasyDevLogin.passwords_required?
|
|
33
|
+
return if find_session_by_cookie.present?
|
|
34
|
+
|
|
35
|
+
email = params[:<%= sign_in_field %>]
|
|
36
|
+
return if email.blank?
|
|
37
|
+
|
|
38
|
+
user = <%= find_by_login_expr("email") %>
|
|
39
|
+
unless user
|
|
40
|
+
Rails.logger.warn("[EASY_DEV_LOGIN] no user found for #{email.inspect}; skipping bypass")
|
|
41
|
+
return
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
Rails.logger.warn("[EASY_DEV_LOGIN] signing in as #{user.<%= principals.display.column %>} (id=#{user.id}). Password bypass is active.")
|
|
45
|
+
<%= sign_in_call("user", via: :easy_dev_login, may_challenge: false) %>
|
|
46
|
+
end
|
|
47
|
+
end
|
data/lib/generators/authnz_eleven/templates/controllers/concerns/authentication/registering.rb.tt
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module <%= identity.authentication_concern %>::Registering
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
private
|
|
5
|
+
|
|
6
|
+
<%= advance_body %>
|
|
7
|
+
|
|
8
|
+
def finish_registration(result)
|
|
9
|
+
case result.status
|
|
10
|
+
when :created
|
|
11
|
+
session.delete(:<%= pending_registration_session_key %>)
|
|
12
|
+
<%= sign_in_call("result.user", via: "result.via", may_challenge: false) %>
|
|
13
|
+
redirect_to after_authentication_url, status: :see_other
|
|
14
|
+
when :taken
|
|
15
|
+
session.delete(:<%= pending_registration_session_key %>)
|
|
16
|
+
redirect_to <%= identity.route_scope %>_sign_in_path, alert: "You already have an account. Sign in to continue."
|
|
17
|
+
when :invalid
|
|
18
|
+
render_invalid_registration
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def render_invalid_registration
|
|
23
|
+
render :new, status: :unprocessable_entity
|
|
24
|
+
end
|
|
25
|
+
end
|