Skip to content

Commit

Permalink
Merge pull request rails#44505 from jonathanhefner/apidocs-improve-ht…
Browse files Browse the repository at this point in the history
…tp-authentication-doc

Improve HTTP authentication API docs [ci-skip]
  • Loading branch information
jonathanhefner committed Feb 23, 2022
2 parents 19f8d03 + eb7a0fc commit 8e080d0
Showing 1 changed file with 48 additions and 23 deletions.
71 changes: 48 additions & 23 deletions actionpack/lib/action_controller/metal/http_authentication.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
module ActionController
# HTTP Basic, Digest, and Token authentication.
module HttpAuthentication
# HTTP \Basic authentication.
# = HTTP \Basic authentication
#
# === Simple \Basic example
#
Expand Down Expand Up @@ -70,6 +70,9 @@ module ControllerMethods
extend ActiveSupport::Concern

module ClassMethods
# Enables HTTP \Basic authentication.
#
# See ActionController::HttpAuthentication::Basic for example usage.
def http_basic_authenticate_with(name:, password:, realm: nil, **options)
before_action(options) { http_basic_authenticate_or_request_with name: name, password: password, realm: realm }
end
Expand Down Expand Up @@ -135,7 +138,7 @@ def authentication_request(controller, realm, message)
end
end

# HTTP \Digest authentication.
# = HTTP \Digest authentication
#
# === Simple \Digest example
#
Expand Down Expand Up @@ -181,16 +184,22 @@ module Digest
extend self

module ControllerMethods
# Authenticate using an HTTP \Digest, or otherwise render an HTTP header
# requesting the client to send a \Digest.
#
# See ActionController::HttpAuthentication::Digest for example usage.
def authenticate_or_request_with_http_digest(realm = "Application", message = nil, &password_procedure)
authenticate_with_http_digest(realm, &password_procedure) || request_http_digest_authentication(realm, message)
end

# Authenticate with HTTP \Digest. Returns true or false.
# Authenticate using an HTTP \Digest. Returns true if authentication is
# successful, false otherwise.
def authenticate_with_http_digest(realm = "Application", &password_procedure)
HttpAuthentication::Digest.authenticate(request, realm, &password_procedure)
end

# Render output including the HTTP \Digest authentication header.
# Render an HTTP header requesting the client to send a \Digest for
# authentication.
def request_http_digest_authentication(realm = "Application", message = nil)
HttpAuthentication::Digest.authentication_request(self, realm, message)
end
Expand Down Expand Up @@ -331,9 +340,9 @@ def opaque(secret_key)
end
end

# HTTP Token authentication.
# = HTTP \Token authentication
#
# Simple Token example:
# === Simple \Token example
#
# class PostsController < ApplicationController
# TOKEN = "secret"
Expand Down Expand Up @@ -412,14 +421,22 @@ module Token
extend self

module ControllerMethods
# Authenticate using an HTTP Bearer token, or otherwise render an HTTP
# header requesting the client to send a Bearer token.
#
# See ActionController::HttpAuthentication::Token for example usage.
def authenticate_or_request_with_http_token(realm = "Application", message = nil, &login_procedure)
authenticate_with_http_token(&login_procedure) || request_http_token_authentication(realm, message)
end

# Authenticate using an HTTP Bearer token. Returns true if
# authentication is successful, false otherwise.
def authenticate_with_http_token(&login_procedure)
Token.authenticate(self, &login_procedure)
end

# Render an HTTP header requesting the client to send a Bearer token for
# authentication.
def request_http_token_authentication(realm = "Application", message = nil)
Token.authentication_request(self, realm, message)
end
Expand All @@ -428,17 +445,17 @@ def request_http_token_authentication(realm = "Application", message = nil)
# If token Authorization header is present, call the login
# procedure with the present token and options.
#
# [controller]
# ActionController::Base instance for the current request.
# Returns the return value of <tt>login_procedure</tt> if a
# token is found. Returns <tt>nil</tt> if no token is found.
#
# ==== Parameters
#
# [login_procedure]
# Proc to call if a token is present. The Proc should take two arguments:
# * +controller+ - ActionController::Base instance for the current request.
# * +login_procedure+ - Proc to call if a token is present. The Proc
# should take two arguments:
#
# authenticate(controller) { |token, options| ... }
#
# Returns the return value of <tt>login_procedure</tt> if a
# token is found. Returns <tt>nil</tt> if no token is found.

def authenticate(controller, &login_procedure)
token, options = token_and_options(controller.request)
unless token.blank?
Expand All @@ -449,14 +466,18 @@ def authenticate(controller, &login_procedure)
# Parses the token and options out of the token Authorization header.
# The value for the Authorization header is expected to have the prefix
# <tt>"Token"</tt> or <tt>"Bearer"</tt>. If the header looks like this:
#
# Authorization: Token token="abc", nonce="def"
# Then the returned token is <tt>"abc"</tt>, and the options are
# <tt>{nonce: "def"}</tt>
#
# request - ActionDispatch::Request instance with the current headers.
# Then the returned token is <tt>"abc"</tt>, and the options are
# <tt>{nonce: "def"}</tt>.
#
# Returns an +Array+ of <tt>[String, Hash]</tt> if a token is present.
# Returns +nil+ if no token is found.
#
# ==== Parameters
#
# * +request+ - ActionDispatch::Request instance with the current headers.
def token_and_options(request)
authorization_request = request.authorization.to_s
if authorization_request[TOKEN_REGEX]
Expand All @@ -469,7 +490,7 @@ def token_params_from(auth)
rewrite_param_values params_array_from raw_params auth
end

# Takes raw_params and turns it into an array of parameters.
# Takes +raw_params+ and turns it into an array of parameters.
def params_array_from(raw_params)
raw_params.map { |param| param.split %r/=(.+)?/ }
end
Expand All @@ -494,10 +515,12 @@ def raw_params(auth)

# Encodes the given token and options into an Authorization header value.
#
# token - String token.
# options - optional Hash of the options.
#
# Returns String.
#
# ==== Parameters
#
# * +token+ - String token.
# * +options+ - Optional Hash of the options.
def encode_credentials(token, options = {})
values = ["#{TOKEN_KEY}#{token.to_s.inspect}"] + options.map do |key, value|
"#{key}=#{value.to_s.inspect}"
Expand All @@ -507,10 +530,12 @@ def encode_credentials(token, options = {})

# Sets a WWW-Authenticate header to let the client know a token is desired.
#
# controller - ActionController::Base instance for the outgoing response.
# realm - String realm to use in the header.
#
# Returns nothing.
#
# ==== Parameters
#
# * +controller+ - ActionController::Base instance for the outgoing response.
# * +realm+ - String realm to use in the header.
def authentication_request(controller, realm, message = nil)
message ||= "HTTP Token: Access denied.\n"
controller.headers["WWW-Authenticate"] = %(Token realm="#{realm.tr('"', "")}")
Expand Down

0 comments on commit 8e080d0

Please sign in to comment.