b4c4a32205
Rather than silently ignoring bearer tokens on HTML requests (which breaks the audit console's error handling), explicitly reject them with 401. Bearer tokens on JSON requests continue to authenticate normally.
112 lines
2.9 KiB
Ruby
112 lines
2.9 KiB
Ruby
module Authentication
|
|
extend ActiveSupport::Concern
|
|
|
|
included do
|
|
before_action :require_account # Checking and setting account must happen first
|
|
before_action :require_authentication
|
|
helper_method :authenticated?
|
|
helper_method :email_address_pending_authentication
|
|
|
|
etag { Current.identity.id if authenticated? }
|
|
|
|
include Authentication::ViaMagicLink, LoginHelper
|
|
end
|
|
|
|
class_methods do
|
|
def require_unauthenticated_access(**options)
|
|
allow_unauthenticated_access **options
|
|
before_action :redirect_authenticated_user, **options
|
|
end
|
|
|
|
def allow_unauthenticated_access(**options)
|
|
skip_before_action :require_authentication, **options
|
|
before_action :resume_session, **options
|
|
allow_unauthorized_access **options
|
|
end
|
|
|
|
def disallow_account_scope(**options)
|
|
skip_before_action :require_account, **options
|
|
before_action :redirect_tenanted_request, **options
|
|
end
|
|
end
|
|
|
|
private
|
|
def authenticated?
|
|
Current.identity.present?
|
|
end
|
|
|
|
def require_account
|
|
unless Current.account.present?
|
|
redirect_to main_app.session_menu_path(script_name: nil)
|
|
end
|
|
end
|
|
|
|
def require_authentication
|
|
resume_session || authenticate_by_bearer_token || request_authentication
|
|
end
|
|
|
|
def resume_session
|
|
if session = find_session_by_cookie
|
|
set_current_session session
|
|
end
|
|
end
|
|
|
|
def find_session_by_cookie
|
|
Session.find_signed(cookies.signed[:session_token])
|
|
end
|
|
|
|
def authenticate_by_bearer_token
|
|
if request.authorization.to_s.include?("Bearer")
|
|
if request.format.json?
|
|
authenticate_or_request_with_http_token do |token|
|
|
if identity = Identity.find_by_permissable_access_token(token, method: request.method)
|
|
Current.identity = identity
|
|
end
|
|
end
|
|
else
|
|
request_http_token_authentication
|
|
end
|
|
end
|
|
end
|
|
|
|
def request_authentication
|
|
if Current.account.present?
|
|
session[:return_to_after_authenticating] = request.url
|
|
end
|
|
|
|
redirect_to_login_url
|
|
end
|
|
|
|
def after_authentication_url
|
|
session.delete(:return_to_after_authenticating) || landing_url
|
|
end
|
|
|
|
def redirect_authenticated_user
|
|
redirect_to main_app.root_url if authenticated?
|
|
end
|
|
|
|
def redirect_tenanted_request
|
|
redirect_to main_app.root_url if Current.account.present?
|
|
end
|
|
|
|
def start_new_session_for(identity)
|
|
identity.sessions.create!(user_agent: request.user_agent, ip_address: request.remote_ip).tap do |session|
|
|
set_current_session session
|
|
end
|
|
end
|
|
|
|
def set_current_session(session)
|
|
Current.session = session
|
|
cookies.signed.permanent[:session_token] = { value: session.signed_id, httponly: true, same_site: :lax }
|
|
end
|
|
|
|
def terminate_session
|
|
Current.session.destroy
|
|
cookies.delete(:session_token)
|
|
end
|
|
|
|
def session_token
|
|
cookies[:session_token]
|
|
end
|
|
end
|