rails_base 0.51.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/MIT-LICENSE +20 -0
- data/README.md +32 -0
- data/Rakefile +32 -0
- data/app/assets/config/rails_base/manifest.js +3 -0
- data/app/assets/images/rails_base/favicon.ico +0 -0
- data/app/assets/javascripts/rails_base/admin.js +2 -0
- data/app/assets/javascripts/rails_base/application.js +22 -0
- data/app/assets/javascripts/rails_base/cable.js +13 -0
- data/app/assets/javascripts/rails_base/mfa_auth.coffee +3 -0
- data/app/assets/javascripts/rails_base/secondary_authentication.coffee +3 -0
- data/app/assets/javascripts/rails_base/sessions.js +152 -0
- data/app/assets/javascripts/rails_base/user_settings.coffee +3 -0
- data/app/assets/stylesheets/rails_base/admin.css +4 -0
- data/app/assets/stylesheets/rails_base/application.scss +15 -0
- data/app/assets/stylesheets/rails_base/mfa_auth.scss +3 -0
- data/app/assets/stylesheets/rails_base/scaffolds.scss +84 -0
- data/app/assets/stylesheets/rails_base/secondary_authentication.scss +3 -0
- data/app/assets/stylesheets/rails_base/user_settings.scss +3 -0
- data/app/controllers/rails_base/admin_controller.rb +315 -0
- data/app/controllers/rails_base/application_controller.rb +153 -0
- data/app/controllers/rails_base/errors_controller.rb +29 -0
- data/app/controllers/rails_base/mfa_auth_controller.rb +50 -0
- data/app/controllers/rails_base/secondary_authentication_controller.rb +224 -0
- data/app/controllers/rails_base/switch_user_controller.rb +29 -0
- data/app/controllers/rails_base/user_settings_controller.rb +81 -0
- data/app/controllers/rails_base/users/passwords_controller.rb +19 -0
- data/app/controllers/rails_base/users/registrations_controller.rb +80 -0
- data/app/controllers/rails_base/users/sessions_controller.rb +108 -0
- data/app/helpers/rails_base/admin_helper.rb +107 -0
- data/app/helpers/rails_base/appearance_helper.rb +58 -0
- data/app/helpers/rails_base/application_helper.rb +26 -0
- data/app/helpers/rails_base/capture_reference_helper.rb +57 -0
- data/app/helpers/rails_base/mfa_auth_helper.rb +2 -0
- data/app/helpers/rails_base/secondary_authentication_helper.rb +2 -0
- data/app/helpers/rails_base/user_field_validators.rb +108 -0
- data/app/helpers/rails_base/user_settings_helper.rb +22 -0
- data/app/jobs/rails_base/application_job.rb +10 -0
- data/app/jobs/twilio_job.rb +9 -0
- data/app/mailers/rails_base/application_mailer.rb +9 -0
- data/app/mailers/rails_base/email_verification_mailer.rb +22 -0
- data/app/mailers/rails_base/event_mailer.rb +16 -0
- data/app/models/admin_action.rb +119 -0
- data/app/models/rails_base/application_record.rb +22 -0
- data/app/models/rails_base/user_constants.rb +28 -0
- data/app/models/secret.rb +37 -0
- data/app/models/short_lived_data.rb +132 -0
- data/app/models/user.rb +143 -0
- data/app/services/rails_base/admin_risky_mfa_send.rb +80 -0
- data/app/services/rails_base/admin_update_attribute.rb +100 -0
- data/app/services/rails_base/authentication/authenticate_user.rb +28 -0
- data/app/services/rails_base/authentication/constants.rb +60 -0
- data/app/services/rails_base/authentication/decision_twofa_type.rb +76 -0
- data/app/services/rails_base/authentication/destroy_user.rb +45 -0
- data/app/services/rails_base/authentication/mfa_set_encrypt_token.rb +32 -0
- data/app/services/rails_base/authentication/mfa_validator.rb +88 -0
- data/app/services/rails_base/authentication/modify_password.rb +67 -0
- data/app/services/rails_base/authentication/send_forgot_password.rb +26 -0
- data/app/services/rails_base/authentication/send_login_mfa_to_user.rb +77 -0
- data/app/services/rails_base/authentication/send_verification_email.rb +103 -0
- data/app/services/rails_base/authentication/session_token_verifier.rb +31 -0
- data/app/services/rails_base/authentication/single_sign_on_create.rb +44 -0
- data/app/services/rails_base/authentication/single_sign_on_send.rb +101 -0
- data/app/services/rails_base/authentication/single_sign_on_verify.rb +42 -0
- data/app/services/rails_base/authentication/sso_verify_email.rb +43 -0
- data/app/services/rails_base/authentication/update_phone_send_verification.rb +46 -0
- data/app/services/rails_base/authentication/verify_forgot_password.rb +46 -0
- data/app/services/rails_base/email_change.rb +20 -0
- data/app/services/rails_base/encryption.rb +87 -0
- data/app/services/rails_base/name_change.rb +71 -0
- data/app/services/rails_base/service_base.rb +65 -0
- data/app/services/rails_base/service_logging.rb +23 -0
- data/app/views/layouts/rails_base/application.html.erb +185 -0
- data/app/views/layouts/rails_base/mailer.html.erb +13 -0
- data/app/views/layouts/rails_base/mailer.text.erb +1 -0
- data/app/views/new.html.erb +4 -0
- data/app/views/rails_base/admin/history.html.erb +26 -0
- data/app/views/rails_base/admin/index.html.erb +149 -0
- data/app/views/rails_base/admin/show_config.html.erb +18 -0
- data/app/views/rails_base/devise/confirmations/new.html.erb +16 -0
- data/app/views/rails_base/devise/mailer/confirmation_instructions.html.erb +5 -0
- data/app/views/rails_base/devise/mailer/email_changed.html.erb +7 -0
- data/app/views/rails_base/devise/mailer/password_change.html.erb +3 -0
- data/app/views/rails_base/devise/mailer/reset_password_instructions.html.erb +8 -0
- data/app/views/rails_base/devise/mailer/unlock_instructions.html.erb +7 -0
- data/app/views/rails_base/devise/passwords/edit.html.erb +25 -0
- data/app/views/rails_base/devise/passwords/new.html.erb +27 -0
- data/app/views/rails_base/devise/registrations/edit.html.erb +43 -0
- data/app/views/rails_base/devise/registrations/new.html.erb +123 -0
- data/app/views/rails_base/devise/sessions/new.html.erb +4 -0
- data/app/views/rails_base/devise/shared/_error_messages.html.erb +15 -0
- data/app/views/rails_base/devise/shared/_links.html.erb +25 -0
- data/app/views/rails_base/devise/unlocks/new.html.erb +16 -0
- data/app/views/rails_base/email_verification_mailer/email_verification.html.erb +25 -0
- data/app/views/rails_base/email_verification_mailer/event.html.erb +20 -0
- data/app/views/rails_base/email_verification_mailer/forgot_password.html.erb +22 -0
- data/app/views/rails_base/errors/internal_error.html.erb +1 -0
- data/app/views/rails_base/errors/not_found.html.erb +1 -0
- data/app/views/rails_base/errors/unacceptable.html.erb +1 -0
- data/app/views/rails_base/event_mailer/event.html.erb +10 -0
- data/app/views/rails_base/mfa_auth/mfa_code.html.erb +10 -0
- data/app/views/rails_base/secondary_authentication/after_email_login_session_new.html.erb +3 -0
- data/app/views/rails_base/secondary_authentication/forgot_password.html.erb +9 -0
- data/app/views/rails_base/secondary_authentication/remove_me.html.erb +1 -0
- data/app/views/rails_base/secondary_authentication/static.html.erb +5 -0
- data/app/views/rails_base/shared/_admin_actions_modal.html.erb +65 -0
- data/app/views/rails_base/shared/_admin_config_class.html.erb +52 -0
- data/app/views/rails_base/shared/_admin_history.html.erb +86 -0
- data/app/views/rails_base/shared/_admin_modify_email.html.erb +78 -0
- data/app/views/rails_base/shared/_admin_modify_name.html.erb +107 -0
- data/app/views/rails_base/shared/_admin_modify_phone.html.erb +87 -0
- data/app/views/rails_base/shared/_admin_modify_text.html.erb +35 -0
- data/app/views/rails_base/shared/_admin_risky_change.html.erb +57 -0
- data/app/views/rails_base/shared/_admin_risky_mfa.html.erb +74 -0
- data/app/views/rails_base/shared/_admin_selector_dropdown.html.erb +70 -0
- data/app/views/rails_base/shared/_admin_toggle_button.html.erb +72 -0
- data/app/views/rails_base/shared/_admin_warning_alert.html.erb +7 -0
- data/app/views/rails_base/shared/_appearance_mode_selector.html.erb +183 -0
- data/app/views/rails_base/shared/_custom_form_validation_javascript.html.erb +129 -0
- data/app/views/rails_base/shared/_enable_mfa_auth_modal.html.erb +105 -0
- data/app/views/rails_base/shared/_error_pages.html.erb +123 -0
- data/app/views/rails_base/shared/_logged_in_header.html.erb +123 -0
- data/app/views/rails_base/shared/_logged_out_header.html.erb +14 -0
- data/app/views/rails_base/shared/_mfa_input_layout.html.erb +5 -0
- data/app/views/rails_base/shared/_mfa_input_layout_default.html.erb +97 -0
- data/app/views/rails_base/shared/_mfa_input_layout_fallback.html.erb +55 -0
- data/app/views/rails_base/shared/_modify_mfa_auth_modal.html.erb +20 -0
- data/app/views/rails_base/shared/_password_confirm_javascript.html.erb +71 -0
- data/app/views/rails_base/shared/_reset_password_form.html.erb +111 -0
- data/app/views/rails_base/shared/_session_create_form.html.erb +32 -0
- data/app/views/rails_base/shared/_session_timeout_modal.html.erb +76 -0
- data/app/views/rails_base/switch_user/_widget.html.erb +5 -0
- data/app/views/rails_base/user_settings/_confirm_destroy_user.html.erb +42 -0
- data/app/views/rails_base/user_settings/_destroy_user.html.erb +106 -0
- data/app/views/rails_base/user_settings/_modify_name.html.erb +71 -0
- data/app/views/rails_base/user_settings/_modify_password.html.erb +101 -0
- data/app/views/rails_base/user_settings/_modify_password_update_password.html.erb +2 -0
- data/app/views/rails_base/user_settings/index.html.erb +54 -0
- data/config/initializers/01_rails_config.rb +19 -0
- data/config/initializers/admin_action_helper.rb +88 -0
- data/config/initializers/browser.rb +4 -0
- data/config/initializers/default_logged_in_headers.rb +23 -0
- data/config/initializers/devise.rb +314 -0
- data/config/initializers/encryption.rb +2 -0
- data/config/initializers/switch_user.rb +58 -0
- data/config/initializers/switch_user_helper.rb +29 -0
- data/config/locales/devise.en.yml +65 -0
- data/config/locales/en.yml +58 -0
- data/config/routes.rb +114 -0
- data/db/migrate/20210212175453_devise_create_rails_base_users.rb +56 -0
- data/db/migrate/20210212190537_create_rails_base_short_lived_data.rb +19 -0
- data/db/migrate/20210212192645_create_rails_base_secrets.rb +11 -0
- data/db/migrate/20210406015744_create_rails_base_admin_actions.rb +17 -0
- data/db/seeds.rb +23 -0
- data/lib/link_decision_helper.rb +71 -0
- data/lib/rails_base.rb +50 -0
- data/lib/rails_base/admin/action_cache.rb +99 -0
- data/lib/rails_base/admin/action_helper.rb +134 -0
- data/lib/rails_base/admin/default_index_tile.rb +176 -0
- data/lib/rails_base/admin/index_tile.rb +186 -0
- data/lib/rails_base/config.rb +52 -0
- data/lib/rails_base/configuration/active_job.rb +38 -0
- data/lib/rails_base/configuration/admin.rb +231 -0
- data/lib/rails_base/configuration/app.rb +52 -0
- data/lib/rails_base/configuration/appearance.rb +131 -0
- data/lib/rails_base/configuration/authentication.rb +37 -0
- data/lib/rails_base/configuration/base.rb +209 -0
- data/lib/rails_base/configuration/display/background_color.rb +25 -0
- data/lib/rails_base/configuration/display/btn_danger.rb +25 -0
- data/lib/rails_base/configuration/display/btn_dark.rb +25 -0
- data/lib/rails_base/configuration/display/btn_info.rb +25 -0
- data/lib/rails_base/configuration/display/btn_light.rb +25 -0
- data/lib/rails_base/configuration/display/btn_primary.rb +25 -0
- data/lib/rails_base/configuration/display/btn_secondary.rb +25 -0
- data/lib/rails_base/configuration/display/btn_success.rb +25 -0
- data/lib/rails_base/configuration/display/btn_warning.rb +25 -0
- data/lib/rails_base/configuration/display/footer.rb +54 -0
- data/lib/rails_base/configuration/display/navbar.rb +25 -0
- data/lib/rails_base/configuration/display/table_body.rb +25 -0
- data/lib/rails_base/configuration/display/table_header.rb +25 -0
- data/lib/rails_base/configuration/display/text.rb +26 -0
- data/lib/rails_base/configuration/exceptions_app.rb +25 -0
- data/lib/rails_base/configuration/login_behavior.rb +17 -0
- data/lib/rails_base/configuration/mailer.rb +116 -0
- data/lib/rails_base/configuration/mfa.rb +84 -0
- data/lib/rails_base/configuration/owner.rb +17 -0
- data/lib/rails_base/configuration/redis.rb +29 -0
- data/lib/rails_base/configuration/user.rb +43 -0
- data/lib/rails_base/engine.rb +51 -0
- data/lib/rails_base/version.rb +10 -0
- data/lib/tasks/rails_base_tasks.rake +4 -0
- data/lib/twilio_helper.rb +26 -0
- data/lib/velocity_limiter.rb +91 -0
- metadata +619 -0
@@ -0,0 +1,153 @@
|
|
1
|
+
module RailsBase
|
2
|
+
class ApplicationController < ActionController::Base
|
3
|
+
before_action :configure_permitted_parameters, if: :devise_controller?
|
4
|
+
before_action :set_time_zone
|
5
|
+
before_action :is_timeout_error?
|
6
|
+
before_action :admin_reset_impersonation_session!
|
7
|
+
before_action :footer_mode_case
|
8
|
+
|
9
|
+
before_action :populate_admin_actions, if: -> { RailsBase.config.admin.enable_actions? }
|
10
|
+
after_action :capture_admin_action
|
11
|
+
|
12
|
+
include ApplicationHelper
|
13
|
+
include AppearanceHelper
|
14
|
+
include CaptureReferenceHelper
|
15
|
+
|
16
|
+
def set_time_zone
|
17
|
+
return unless RailsBase.config.user.tz_user_defined?
|
18
|
+
return if current_user.nil?
|
19
|
+
|
20
|
+
# esape this since this is not signed
|
21
|
+
offset = cookies[TIMEZONE_OFFSET_COOKIE].to_i
|
22
|
+
|
23
|
+
cookie_tz = ActiveSupport::TimeZone[((offset * -1) / 60.0)]
|
24
|
+
|
25
|
+
if session_tz = session[TIMEZONE_SESSION_NAME]
|
26
|
+
# if session exists
|
27
|
+
if cookie_tz && session_tz != cookie_tz.name
|
28
|
+
# if cookie exists and cookie_tz does not match, update db and session
|
29
|
+
current_user.update_tz(tz_name: cookie_tz.name)
|
30
|
+
session[TIMEZONE_SESSION_NAME] = cookie_tz.name
|
31
|
+
end
|
32
|
+
else
|
33
|
+
# if session timezone does not exist, attempt to push to DB and set to session
|
34
|
+
current_user.update_tz(tz_name: cookie_tz.name)
|
35
|
+
session[TIMEZONE_SESSION_NAME] = cookie_tz.name
|
36
|
+
end
|
37
|
+
Thread.current[TIMEZONE_THREAD_NAME] = session[TIMEZONE_SESSION_NAME]
|
38
|
+
end
|
39
|
+
|
40
|
+
def is_timeout_error?
|
41
|
+
return if current_user || !params.keys.include?('timeout')
|
42
|
+
|
43
|
+
flash[:notice] = nil
|
44
|
+
flash[:alert] = 'Your session expired. Please sign in again to continue.'
|
45
|
+
end
|
46
|
+
|
47
|
+
def admin_impersonation_session?
|
48
|
+
return false if current_user.nil?
|
49
|
+
return false unless encrypted_val = session[RailsBase::Authentication::Constants::ADMIN_REMEMBER_REASON].presence
|
50
|
+
|
51
|
+
token = admin_get_token(encrypted_val: encrypted_val)
|
52
|
+
if token.failure?
|
53
|
+
logger.warn "Failed to parse encrypted token. Either expired or was not present"
|
54
|
+
flash[:alert] = 'Failed to retrieve Session token. Retry action'
|
55
|
+
redirect_to RailsBase.url_routes.admin_base_path
|
56
|
+
return false
|
57
|
+
else
|
58
|
+
logger.info "Found original_admin_user_id"
|
59
|
+
@original_admin_user_id = token.user_id
|
60
|
+
end
|
61
|
+
true
|
62
|
+
end
|
63
|
+
|
64
|
+
def admin_reset_impersonation_session!
|
65
|
+
return unless admin_impersonation_session?
|
66
|
+
|
67
|
+
# at this point we know there is an impersonation
|
68
|
+
admin_user = User.find @original_admin_user_id
|
69
|
+
admin_set_token_on_session(admin_user: admin_user, other_user: current_user)
|
70
|
+
end
|
71
|
+
|
72
|
+
def admin_user?
|
73
|
+
return if RailsBase.config.admin.view_admin_page?(current_user)
|
74
|
+
|
75
|
+
session.clear
|
76
|
+
sign_out(current_user)
|
77
|
+
|
78
|
+
flash[:alert] = 'Unauthorized action. You have been signed out'
|
79
|
+
redirect_to RailsBase.url_routes.unauthenticated_root_path
|
80
|
+
end
|
81
|
+
|
82
|
+
def populate_admin_actions
|
83
|
+
return if session[RailsBase::Authentication::Constants::ADMIN_REMEMBER_REASON].present?
|
84
|
+
return if current_user.nil?
|
85
|
+
return unless request.fullpath == RailsBase.url_routes.authenticated_root_path
|
86
|
+
|
87
|
+
@__admin_actions_array = AdminAction.get_cache_items(user: current_user, alltime: true)
|
88
|
+
end
|
89
|
+
|
90
|
+
def capture_admin_action
|
91
|
+
# ToDo: Turn this into a service
|
92
|
+
# ToDo: All admin actions come there here: Allow this to be confirugable on or off
|
93
|
+
_controller = ActiveSupport::Inflector.camelize("#{params[:controller]}_controller")
|
94
|
+
admin_user =
|
95
|
+
if _controller == RailsBase::AdminController.to_s
|
96
|
+
current_user
|
97
|
+
else
|
98
|
+
@original_admin_user_id ? User.find(@original_admin_user_id) : nil
|
99
|
+
end
|
100
|
+
|
101
|
+
# Means we are not in the admin controller or we are not impersonating
|
102
|
+
return if admin_user.nil? || @_admin_action_struct == false
|
103
|
+
|
104
|
+
# Admin action for all routes
|
105
|
+
(RailsBase::Admin::ActionHelper.actions.dig(RailsBase::Admin::ActionHelper::ACTIONS_KEY) || []).each do |helper|
|
106
|
+
Rails.logger.warn("Admin Action for every action")
|
107
|
+
helper.call(req: request, params: params, admin_user: admin_user, user: current_user, struct: @_admin_action_struct)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Admin action for all controller routes
|
111
|
+
object = RailsBase::Admin::ActionHelper.actions.dig(_controller, RailsBase::Admin::ActionHelper::CONTROLLER_ACTIONS_KEY) || []
|
112
|
+
object.each do |helper|
|
113
|
+
Rails.logger.warn("Admin Action for #{_controller}")
|
114
|
+
helper.call(req: request, params: params, admin_user: admin_user, user: current_user, struct: @_admin_action_struct)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Admin action for all controller action specific routes
|
118
|
+
(RailsBase::Admin::ActionHelper.actions.dig(_controller, params[:action].to_s) || []).each do |helper|
|
119
|
+
Rails.logger.warn("Admin Action for #{_controller}##{params[:action]}")
|
120
|
+
helper.call(req: request, params: params, admin_user: admin_user, user: current_user, struct: @_admin_action_struct)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
protected
|
125
|
+
|
126
|
+
def admin_get_token(encrypted_val:)
|
127
|
+
params = {
|
128
|
+
mfa_randomized_token: encrypted_val,
|
129
|
+
purpose: RailsBase::Authentication::Constants::ADMIN_REMEMBER_REASON,
|
130
|
+
}
|
131
|
+
RailsBase::Authentication::SessionTokenVerifier.call(params)
|
132
|
+
end
|
133
|
+
|
134
|
+
def admin_set_token_on_session(admin_user:, other_user:)
|
135
|
+
if admin_user.id != other_user.id #dont do this if you are yourself
|
136
|
+
logger.warn { "Admin user [#{admin_user.id}] is impersonating user #{other_user.id}" }
|
137
|
+
params = {
|
138
|
+
user: admin_user,
|
139
|
+
purpose: RailsBase::Authentication::Constants::ADMIN_REMEMBER_REASON,
|
140
|
+
expires_at: RailsBase::Authentication::Constants::ADMIN_MAX_IDLE_TIME.from_now
|
141
|
+
}
|
142
|
+
encrpytion = RailsBase::Authentication::MfaSetEncryptToken.call(params)
|
143
|
+
session[RailsBase::Authentication::Constants::ADMIN_REMEMBER_REASON] = encrpytion.encrypted_val
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def configure_permitted_parameters
|
148
|
+
added_attrs = [:phone_number, :email, :password, :password_confirmation, :remember_me]
|
149
|
+
devise_parameter_sanitizer.permit :sign_up, keys: added_attrs
|
150
|
+
devise_parameter_sanitizer.permit :account_update, keys: added_attrs
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module RailsBase
|
2
|
+
class ErrorsController < ApplicationController
|
3
|
+
before_action :set_variable
|
4
|
+
|
5
|
+
def not_found
|
6
|
+
@status = 404
|
7
|
+
@message = "The Page can't be found"
|
8
|
+
render template: 'rails_base/errors/not_found'
|
9
|
+
end
|
10
|
+
|
11
|
+
def unacceptable
|
12
|
+
@status = 422
|
13
|
+
@message = "Client Error. Please retry"
|
14
|
+
render template: 'rails_base/errors/unacceptable'
|
15
|
+
end
|
16
|
+
|
17
|
+
def internal_error
|
18
|
+
@status = 500
|
19
|
+
@message = "An Internal Error has occured"
|
20
|
+
render template: 'rails_base/errors/internal_error'
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def set_variable
|
26
|
+
@error_page = true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module RailsBase
|
2
|
+
class MfaAuthController < ApplicationController
|
3
|
+
before_action :validate_token, only: [:mfa_code, :mfa_code_verify, :resend_mfa]
|
4
|
+
|
5
|
+
# GET /mfa_verify
|
6
|
+
def mfa_code
|
7
|
+
@masked_phone = User.find(@token_verifier.user_id).masked_phone
|
8
|
+
end
|
9
|
+
|
10
|
+
# POST /mfa_verify
|
11
|
+
def mfa_code_verify
|
12
|
+
mfa_validity = RailsBase::Authentication::MfaValidator.call(params: params, session_mfa_user_id: @token_verifier.user_id)
|
13
|
+
if mfa_validity.failure?
|
14
|
+
redirect_to(mfa_validity.redirect_url, alert: mfa_validity.message)
|
15
|
+
return
|
16
|
+
end
|
17
|
+
|
18
|
+
mfa_validity.user.set_last_mfa_login!
|
19
|
+
|
20
|
+
sign_in(mfa_validity.user)
|
21
|
+
redirect_to RailsBase.url_routes.authenticated_root_path, notice: "Welcome #{mfa_validity.user.full_name}"
|
22
|
+
end
|
23
|
+
|
24
|
+
# POST /mfa_verify
|
25
|
+
def resend_mfa
|
26
|
+
user = User.find(@token_verifier.user_id)
|
27
|
+
mfa_token = RailsBase::Authentication::SendLoginMfaToUser.call(user: user)
|
28
|
+
if mfa_token.failure?
|
29
|
+
flash[:error] = mfa_token.message
|
30
|
+
session[:mfa_randomized_token] = nil
|
31
|
+
redirect_to RailsBase.url_routes.new_user_session_path, email: params.dig(:user,:email), alert: mfa_token.message
|
32
|
+
return
|
33
|
+
end
|
34
|
+
expired_at = Time.zone.parse(@token_verifier.expires_at)
|
35
|
+
session[:mfa_randomized_token] =
|
36
|
+
RailsBase::Authentication::MfaSetEncryptToken.call(user: user, expires_at: expired_at).encrypted_val
|
37
|
+
|
38
|
+
redirect_to RailsBase.url_routes.mfa_code_path, notice: "MFA has been sent via SMS to number on file"
|
39
|
+
end
|
40
|
+
|
41
|
+
def validate_token
|
42
|
+
@token_verifier =
|
43
|
+
RailsBase::Authentication::SessionTokenVerifier.call(mfa_randomized_token: session[:mfa_randomized_token])
|
44
|
+
return if @token_verifier.success?
|
45
|
+
|
46
|
+
redirect_to RailsBase.url_routes.new_user_session_path, alert: @token_verifier.message
|
47
|
+
return false
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,224 @@
|
|
1
|
+
module RailsBase
|
2
|
+
class SecondaryAuthenticationController < ApplicationController
|
3
|
+
before_action :authenticate_user!, only: [:remove_phone_mfa, :confirm_phone_registration]
|
4
|
+
|
5
|
+
before_action :validate_token!, only: [:resend_email, :wait, :confirm_phone_registration]
|
6
|
+
|
7
|
+
before_action :json_validate_current_user!, only: [:phone_registration]
|
8
|
+
|
9
|
+
# GET auth/wait
|
10
|
+
def static
|
11
|
+
return unless validate_token!(purpose: Authentication::Constants::SSOVE_PURPOSE)
|
12
|
+
|
13
|
+
if flash[:notice].nil? && flash[:alert].nil?
|
14
|
+
flash[:notice] = Authentication::Constants::STATIC_WAIT_FLASH
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def remove_me
|
19
|
+
end
|
20
|
+
|
21
|
+
def testing_route
|
22
|
+
Rails.logger.error("This will cause an error to be thrown")
|
23
|
+
raise ArgumentError, 'Boo'
|
24
|
+
end
|
25
|
+
|
26
|
+
# POST auth/resend_email
|
27
|
+
def resend_email
|
28
|
+
user = User.find @token_verifier.user_id
|
29
|
+
email_verification = Authentication::SendVerificationEmail.call(user: user, reason: Authentication::Constants::SVE_LOGIN_REASON)
|
30
|
+
params =
|
31
|
+
if email_verification.failure?
|
32
|
+
{ alert: email_verification.message }
|
33
|
+
else
|
34
|
+
{ notice: I18n.t('authentication.resend_email', email: user.email) }
|
35
|
+
end
|
36
|
+
redirect_to RailsBase.url_routes.auth_static_path, params
|
37
|
+
end
|
38
|
+
|
39
|
+
# GET auth/email/:data
|
40
|
+
def email_verification
|
41
|
+
verify = Authentication::SsoVerifyEmail.call(verification: params[:data])
|
42
|
+
|
43
|
+
if verify.failure?
|
44
|
+
redirect_to(verify.redirect_url, alert: verify.message)
|
45
|
+
return
|
46
|
+
end
|
47
|
+
|
48
|
+
session[:mfa_randomized_token] = verify.encrypted_val
|
49
|
+
redirect_to RailsBase.url_routes.login_after_email_path
|
50
|
+
end
|
51
|
+
|
52
|
+
# GET auth/login
|
53
|
+
def after_email_login_session_new
|
54
|
+
return unless validate_token!(purpose: Authentication::Constants::SSOVE_PURPOSE)
|
55
|
+
|
56
|
+
@user = User.new
|
57
|
+
if flash[:alert].nil? && flash[:notice].nil?
|
58
|
+
flash[:notice] = I18n.t('authentication.after_email_login_session_new')
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# POST auth/login
|
63
|
+
def after_email_login_session_create
|
64
|
+
return unless validate_token!(purpose: Authentication::Constants::SSOVE_PURPOSE)
|
65
|
+
|
66
|
+
flash[:notice] = nil
|
67
|
+
flash[:alert] = nil
|
68
|
+
authenticate = Authentication::AuthenticateUser.call(email: params[:user][:email], password: params[:user][:password])
|
69
|
+
if authenticate.failure?
|
70
|
+
flash[:alert] = authenticate.message
|
71
|
+
@user = User.new(email: params[:user][:email])
|
72
|
+
render :after_email_login_session_new
|
73
|
+
return
|
74
|
+
end
|
75
|
+
|
76
|
+
sign_in(authenticate.user)
|
77
|
+
flash[:notice] = I18n.t('authentication.after_email_login_session_create')
|
78
|
+
redirect_to RailsBase.url_routes.authenticated_root_path
|
79
|
+
end
|
80
|
+
|
81
|
+
# POST auth/phone
|
82
|
+
def phone_registration
|
83
|
+
result = Authentication::UpdatePhoneSendVerification.call(user: current_user, phone_number: params[:phone_number])
|
84
|
+
if result.failure?
|
85
|
+
render :json => { error: I18n.t('request_response.teapot.fail'), msg: result.message }.to_json, :status => 418
|
86
|
+
return
|
87
|
+
end
|
88
|
+
session[:mfa_randomized_token] = result.mfa_randomized_token
|
89
|
+
|
90
|
+
render :json => { status: :success, message: I18n.t('request_response.teapot.valid') }
|
91
|
+
end
|
92
|
+
|
93
|
+
# POST auth/phone/mfa
|
94
|
+
def confirm_phone_registration
|
95
|
+
mfa_validity = Authentication::MfaValidator.call(current_user: current_user, params: params, session_mfa_user_id: @token_verifier.user_id)
|
96
|
+
if mfa_validity.failure?
|
97
|
+
redirect_to RailsBase.url_routes.authenticated_root_path, alert: I18n.t('authentication.confirm_phone_registration.fail', message: mfa_validity.message)
|
98
|
+
return
|
99
|
+
end
|
100
|
+
|
101
|
+
current_user.update!(mfa_enabled: true)
|
102
|
+
|
103
|
+
redirect_to RailsBase.url_routes.authenticated_root_path, notice: I18n.t('authentication.confirm_phone_registration.valid')
|
104
|
+
end
|
105
|
+
|
106
|
+
# DELETE auth/phone/disable
|
107
|
+
def remove_phone_mfa
|
108
|
+
current_user.update!(mfa_enabled: false, last_mfa_login: nil)
|
109
|
+
redirect_to RailsBase.url_routes.authenticated_root_path, notice: I18n.t('authentication.remove_phone_mfa')
|
110
|
+
end
|
111
|
+
|
112
|
+
# GET auth/email/forgot/:data
|
113
|
+
def forgot_password
|
114
|
+
result = Authentication::VerifyForgotPassword.call(data: params[:data])
|
115
|
+
|
116
|
+
if result.failure?
|
117
|
+
redirect_to result.redirect_url, alert: result.message
|
118
|
+
return
|
119
|
+
end
|
120
|
+
session[:mfa_randomized_token] = result.encrypted_val
|
121
|
+
flash[:notice] =
|
122
|
+
if @mfa_flow = result.mfa_flow
|
123
|
+
I18n.t('authentication.forgot_password.2fa')
|
124
|
+
else
|
125
|
+
I18n.t('authentication.forgot_password.base')
|
126
|
+
end
|
127
|
+
@user = result.user
|
128
|
+
@data = params[:data]
|
129
|
+
end
|
130
|
+
|
131
|
+
# POST auth/email/forgot/:data
|
132
|
+
def forgot_password_with_mfa
|
133
|
+
return unless validate_token!(purpose: Authentication::Constants::VFP_PURPOSE)
|
134
|
+
|
135
|
+
# datum is expired because it was used with #forgot_password method
|
136
|
+
# we dont care, we just want to ensure the correct user (multiple verification ways)
|
137
|
+
# -- validate user by datum
|
138
|
+
# -- validate user by short lived token
|
139
|
+
# -- validate user by mfa_token
|
140
|
+
# -- When all match by user and within the lifetime of the short lived token... we b gucci uber super secure/over engineered
|
141
|
+
expired_datum = ShortLivedData.get_by_data(data: params[:data], reason: Authentication::Constants::VFP_REASON)
|
142
|
+
|
143
|
+
unless expired_datum
|
144
|
+
redirect_to(RailsBase.url_routes.new_user_password_path, alert: I18n.t('authentication.forgot_password_with_mfa.expired_datum'))
|
145
|
+
return
|
146
|
+
end
|
147
|
+
|
148
|
+
result = Authentication::MfaValidator.call(params: params, session_mfa_user_id: @token_verifier.user_id, current_user: expired_datum.user)
|
149
|
+
if result.failure?
|
150
|
+
redirect_to(RailsBase.url_routes.new_user_password_path, alert: result.message)
|
151
|
+
return
|
152
|
+
end
|
153
|
+
|
154
|
+
@mfa_flow = false
|
155
|
+
@data = params[:data]
|
156
|
+
@user = result.user
|
157
|
+
flash[:notice] = I18n.t('authentication.forgot_password_with_mfa.valid_mfa')
|
158
|
+
render :forgot_password
|
159
|
+
end
|
160
|
+
|
161
|
+
# POST auth/email/reset/:data
|
162
|
+
def reset_password
|
163
|
+
return unless validate_token!(purpose: Authentication::Constants::VFP_PURPOSE)
|
164
|
+
|
165
|
+
result = Authentication::ModifyPassword.call(password: params[:user][:password], password_confirmation: params[:user][:password_confirmation], data: params[:data], user_id: @token_verifier.user_id, flow: :forgot_password)
|
166
|
+
if result.failure?
|
167
|
+
redirect_to RailsBase.url_routes.new_user_password_path, alert: result.message
|
168
|
+
return
|
169
|
+
end
|
170
|
+
|
171
|
+
redirect_to RailsBase.url_routes.authenticated_root_path, notice: I18n.t('authentication.reset_password')
|
172
|
+
end
|
173
|
+
|
174
|
+
# GET auth/validate/:data
|
175
|
+
def sso_login
|
176
|
+
input_params = {
|
177
|
+
data: params[:data],
|
178
|
+
reason: RailsBase::Authentication::Constants::SSO_LOGIN_REASON
|
179
|
+
}
|
180
|
+
sso_decision = RailsBase::Authentication::SingleSignOnVerify.call(input_params)
|
181
|
+
if sso_decision.failure?
|
182
|
+
if current_user.nil?
|
183
|
+
flash[:alert] = I18n.t('authentication.sso_login.fail') + sso_decision.message
|
184
|
+
redirect_to RailsBase.url_routes.unauthenticated_root_path
|
185
|
+
return
|
186
|
+
else
|
187
|
+
logger.info('User is logged in but failed the SSO login')
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
|
192
|
+
sign_in(sso_decision.user) if current_user.nil?
|
193
|
+
|
194
|
+
url =
|
195
|
+
if RailsBase.route_exist?(sso_decision.url_redirect)
|
196
|
+
sso_decision.url_redirect
|
197
|
+
else
|
198
|
+
logger.debug("Failed to find #{sso_decision.url_redirect}. Redirecing to root")
|
199
|
+
RailsBase.url_routes.authenticated_root_path
|
200
|
+
end
|
201
|
+
|
202
|
+
flash[:notice] = I18n.t('authentication.sso_login.valid')
|
203
|
+
redirect_to url
|
204
|
+
end
|
205
|
+
|
206
|
+
private
|
207
|
+
|
208
|
+
def json_validate_current_user!
|
209
|
+
return if current_user
|
210
|
+
|
211
|
+
render json: { error: "Unauthorized" }.to_json, :status => 401
|
212
|
+
return false
|
213
|
+
end
|
214
|
+
|
215
|
+
def validate_token!(purpose: Authentication::Constants::MSET_PURPOSE)
|
216
|
+
@token_verifier =
|
217
|
+
Authentication::SessionTokenVerifier.call(purpose: purpose, mfa_randomized_token: session[:mfa_randomized_token])
|
218
|
+
return true if @token_verifier.success?
|
219
|
+
|
220
|
+
redirect_to RailsBase.url_routes.new_user_session_path, alert: @token_verifier.message
|
221
|
+
return false
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|