Class: CommandTower::ApplicationController
- Inherits:
-
ActionController::API
- Object
- ActionController::API
- CommandTower::ApplicationController
- Includes:
- Execution::HttpBoundary
- Defined in:
- app/controllers/command_tower/application_controller.rb
Direct Known Subclasses
CommandTower::Admin::ApplicationController, CommandTower::Auth::Email::AvailabilityController, CommandTower::Auth::EmailVerification::SendController, CommandTower::Auth::EmailVerification::VerifyController, CommandTower::Auth::IdentityPolicyController, CommandTower::Auth::ImpersonationSessionController, CommandTower::Auth::LogoutController, CommandTower::Auth::PasswordRecoverySession::CreateController, CommandTower::Auth::PasswordReset::ResetController, CommandTower::Auth::PasswordReset::SendController, CommandTower::Auth::PasswordReset::ValidateController, CommandTower::Auth::PlainText::LoginController, CommandTower::Auth::PrincipalCapabilitiesController, CommandTower::Auth::RegisterController, CommandTower::Auth::SessionController, CommandTower::Auth::SignupSession::CreateController, CommandTower::Auth::Username::AvailabilityController, Me::AccountController, Me::AuditEventsController, Me::InboxController, Me::NameController, Me::PasswordController, Me::PhoneController, Me::PhoneVerification::VerificationsController, Me::PhoneVerification::VerifyController, Me::PreferencesController, Me::Pushover::VerificationsController, Me::PushoverController, MeController, ProfileController
Constant Summary collapse
- AUTHENTICATION_HEADER =
CommandTower::Jwt::AuthorizationHelper::AUTHENTICATION_HEADER
- AUTHENTICATION_EXPIRE_HEADER =
CommandTower::Jwt::AuthorizationHelper::AUTHENTICATION_EXPIRE_HEADER
- AUTHENTICATION_WITH_RESET =
CommandTower::Jwt::AuthorizationHelper::AUTHENTICATION_WITH_RESET
Instance Method Summary collapse
-
#authenticate_user!(bypass_email_validation: false) ⇒ Object
Authenticate user via the passed in header or cookie AUTHENTICATION_HEADER="Bearer value" or cookie (if enabled).
-
#authenticate_user_without_email_verification! ⇒ Object
Authenticate user via the passed in header without validating email.
-
#authorize_user! ⇒ Object
After Authenticating user, see if the user needs authorization on the route.
- #current_user ⇒ Object
- #safe_boolean(value:) ⇒ Object
Instance Method Details
#authenticate_user!(bypass_email_validation: false) ⇒ Object
Authenticate user via the passed in header or cookie AUTHENTICATION_HEADER="Bearer value" or cookie (if enabled)
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'app/controllers/command_tower/application_controller.rb', line 20 def authenticate_user!(bypass_email_validation: false) # Extract and validate token (from header or cookie fallback) token_data = CommandTower::Jwt::AuthorizationHelper.extract_token(request) if token_data[:error] status = 401 schema = CommandTower::Schema::Error::Base.new(status:, message: token_data[:message]) render(json: schema.to_h, status:) return false end token = token_data[:token] token_source = token_data[:source] # CSRF validation for cookie-authenticated unsafe requests # Enforcement is centralized here because token_source is only reliably known in this shared filter if csrf_required?(request, token_source) csrf_validation = CommandTower::Jwt::CsrfHelper.validate(request) unless csrf_validation[:valid] status = 403 schema = CommandTower::Schema::Error::Base.new( status: status.to_s, message: csrf_validation[:message] # Stable error code: "csrf_missing" or "csrf_mismatch" ) render(json: schema.to_h, status: status) return false end end with_reset = CommandTower::Jwt::AuthorizationHelper.get_with_reset_flag(request) result = CommandTower::Jwt::AuthenticateUser.(token:, bypass_email_validation:, with_reset:) if result.success? established = CommandTower::Impersonation::EstablishIdentity.call( actor: result.user, impersonation_session_id: result.impersonation_session_id ) if established.expired? status = 401 schema = CommandTower::Schema::Error::Base.new( status:, message: CommandTower::Errors::Auth::ImpersonationSessionExpiredError.new. ) render(json: schema.to_h, status:) return false end @current_user = established.user if with_reset # Use helper to set both headers and cookie (if enabled) CommandTower::Jwt::AuthorizationHelper.set_token( response, result.generated_token, expires_at: result.expires_at ) # Handle CSRF cookie issuance/rotation for token reset path # CSRF cookie issuance rules: # - rotate_on_reset = true → force rotate (generate new token) # - rotate_on_reset = false → ensure exists only (create if missing, keep if exists) if CommandTower::Jwt::CsrfHelper.csrf_enabled? if CommandTower.config.jwt..csrf.rotate_on_reset CommandTower::Jwt::CsrfHelper.(request, response, should_rotate: true) else # Ensure cookie exists (rotate-or-ensure model) CommandTower::Jwt::CsrfHelper.(request, response, should_rotate: false) end end else # Only set expire header when not resetting response.set_header(AUTHENTICATION_EXPIRE_HEADER, result.expires_at) end true else # Check if this is an email validation failure (status 412) if result.status == 412 status = 412 schema = CommandTower::Schema::Error::EmailValidationRequired.new( status:, message: result.msg, meta: { email_validated: false } ) # Do NOT clear cookie for 412 status - user needs to keep cookie to verify email else # If authentication failed and token came from cookie, clear the invalid cookie # Exception: Do not clear cookie for 412 status (email validation required) if token_source == :cookie CommandTower::Jwt::AuthorizationHelper.(response) end status = result.status || 401 schema = CommandTower::Schema::Error::Base.new(status:, message: result.msg) end render(json: schema.to_h, status:) # Must return false so callbacks know to halt propagation false end end |
#authenticate_user_without_email_verification! ⇒ Object
Authenticate user via the passed in header without validating email
118 119 120 |
# File 'app/controllers/command_tower/application_controller.rb', line 118 def authenticate_user_without_email_verification! authenticate_user!(bypass_email_validation: true) end |
#authorize_user! ⇒ Object
After Authenticating user, see if the user needs authorization on the route
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'app/controllers/command_tower/application_controller.rb', line 124 def if current_user.nil? Rails.logger.error { "Current User is not defined. This means that authenticate_user! was not called" } status = 401 schema = CommandTower::Schema::Error::Base.new(status:, message: "Bearer token missing") render(json: schema.to_h, status:) return false end result = CommandTower::Authorize::Validate.(user: current_user, controller: self.class, method: params[:action]) if result.success? @current_user = result.user true else # Current user is not authorized for the current Controller#action status = 403 schema = CommandTower::Schema::Error::Base.new(status:, message: result.msg) render(json: schema.to_h, status:) # Must return false so callbacks know to halt propagation false end end |
#current_user ⇒ Object
147 148 149 |
# File 'app/controllers/command_tower/application_controller.rb', line 147 def current_user @current_user ||= nil end |
#safe_boolean(value:) ⇒ Object
11 12 13 14 15 |
# File 'app/controllers/command_tower/application_controller.rb', line 11 def safe_boolean(value:) return nil unless [true, false, "true", "false", "0", "1", 0, 1].include?(value) ActiveModel::Type::Boolean.new.cast(value) end |