RubyAuthTagger
Inherits FrameworkTagger < FileHelper < Tagger < Reference < Object
Constants
Pundit / CanCanCan authorization in action body. \b: not the
doorkeeper_authorize! / authorize_if_got_token! an API calls.
return if <no credential> / return unless <credential>.
A condition that reads the app's configuration rather than the request:
a call on a constant (Settings::UserExperience.public,
Rails.configuration.x.private_mode, Flipper.enabled?(:x)) or ENV.
A deny that waits on one is a guard an operator can switch off.
Current.user (CurrentAttributes) is the caller, not a setting.
A call with no receiver: require_login, not cookies.delete.
Rails before_action authentication patterns — verify who the caller is.
(?<!skip_): skip_before_action :doorkeeper_authorize! removes the
callback; it must never read as registering it.
Rails before_action authorization — verify what the caller may do.
Union kept for the CONTROLLER_AUTH_ANY gate and the shared walk.
Lines that end the request: a 401/403, a redirect, a raise, the
authenticate_or_request_with_* / request_http_* helpers that answer
401 themselves, or a bang auth call.
user = authentication_check_only: a bare call of an app method whose
own body looks up the caller from where a request carries its
credential (User.lookup(id: session[:user_id]), warden, HTTP auth),
so the local holds the caller. current_cart reading
Cart.find_by(id: session[:cart_id]) holds a cart, not the caller.
A policy's reference to the caller it was built with.
if arg = self.class.requires_login_arg: a class setting the routed
controller turns on by calling the class macro that assigns it
(requires_login, a def self.requires_login storing
@requires_login_arg); settings are the macros it calls for this
action (see RailsCallbackChain::Resolution#settings). Such a part is
dropped when the setting holds the way the deny needs; nil when it does
not, so the deny never fires. A setting no macro is found for stays a
plain condition.
Cheap gate for check_controller_auth's backward walk, which runs to the
enclosing class — or, in a Sinatra/Grape/Roda file that has none, to line
0 — for every endpoint in the file. Mechanically the union of the three
pattern sets it guards, so a line it rejects cannot match any of them; it
replaces 13 regex evaluations per line with one.
Per-line flags for check_controller_auth, computed once per file.
The walk runs from each action back to its enclosing class, so a
controller with N actions re-examined the same lines N times — a regex
and an lstrip allocation per line per action. Neither depends on the
action, so classify each line once:
CONTROLLER_AUTH_LINE — matches CONTROLLER_AUTH_ANY; the walk runs the
full pattern checks on it
CLASS_LINE — any other line that opens a class; the walk stops
An if whose condition only asks whether a credential was sent: the
rejection under it never fires for a request that carries none.
doorkeeper_authorize!(*scopes) if doorkeeper_token: a statement whose
trailing if is only a credential being present.
Where a request carries its credential.
The words a request credential is spelled with.
An explicit 401/403 answer.
Doorkeeper's authenticators run a block from the app's
config/initializers/doorkeeper.rb; current_user || redirect_to(...)
rejects, User.find_by(id: session[:user_id]) alone lets anyone in.
return false if errors.blank? where errors = [] is touched only
under credential-present branches (if session[:user_id],
authenticate_with_http_basic do): a caller who sent no credential
leaves it empty and takes the exit, so what follows is not a login gate.
Any other use of the local above the exit (errors += [..] unless x,
require_credential(errors)) may fill it for an anonymous caller.
An anti-forgery check: raise InvalidCSRFToken after return true if valid_authenticity_token?(session, params[:authenticity_token])
(zammad's verify_csrf_token). Every visitor, anonymous or not, is
handed that token, so refusing a request without it is not a login gate.
A deny whose own condition, or a block around it, also waits on a real
credential (head :unauthorized unless current_user below a forgery
exit, redirect_to x(csrf_failed: true) unless current_user) still is
one; a credential word in an exit above (return if %w[token_auth].include?(@_auth_type)) lets callers out, so it is not.
Grape patterns (before blocks, http_basic, helpers)
Hanami patterns
A query body line that lets a nil user pass.
A request value read off params.
Pundit authorize @status, :show? asks StatusPolicy#show?;
authorize Article asks the action's own query (index? for index).
The verdict reads the query's definition (and the policy's
initializer, up its parent policies): :refuses when a nil user gets
false (or an error), :admits when one passes (true, return true unless user, user.nil? || ...),
:unknown when the policy or query cannot be found.
ponytail: the policy is the call's policy_class:, else found by
convention (@status / Status / :status →
policies/status_policy.rb); a record held in a method is unknown.
The namespaced form, authorize [:admin, @status], :review?.
A Pundit authorize call: it raises NotAuthorizedError when the
policy query answers false.
Roda / Rodauth authentication patterns
A role or permission check on the caller: current_user.admin?, can?(:x).
The other side of a comparison that makes a request value a credential whatever its key: a secret, the app's credentials, ENV or a config read.
The marker denies_anonymous? leaves on a guard an app setting decides.
Sinatra/Rack patterns
skip_before_action :a, :b, only: [...]: the callbacks it removes.
skip_before_action marks public overrides
A redirect, a raise (an app's rescue_from answers it, Discourse's
raise Discourse::NotLoggedIn), or a 4xx answer other than 401/403,
from a callback.