class Authlete::AuthenticationServer
Authlete::AuthenticationServer
class¶ ↑
This class is a base class for an authentication server based on Rack. Some method must/should be overridden by subclasses.
-
authenticate_api_call
-
authenticate_user
-
collect_claims
-
authentication_callback_endpoint_path
Public Class Methods
# File lib/authlete/authentication-server.rb, line 32 def initialize(app = nil) # Accept 'app' so that this class can work as a Rack middleware # as well as a Rack application. @app = app end
Public Instance Methods
# File lib/authlete/authentication-server.rb, line 38 def call(env) # Request request = Rack::Request.new(env) # If the request is not an authentication callback request. if match_authentication_callback_request(request) == false # If this class is used as a Rack middleware. if @app && @app.respond_to?(:call) # Call chain to the next Rack middleware. return @app.call(env) else # 404 Not Found return generate_not_found(request) end end # Basic Authentication for the API call. authenticated = do_authenticate_api_call(env) if authenticated == false # 401 Unauthorized return generate_api_call_authentication_failure() end begin # Parse the request body as AuthenticationCallbackRequest. req = parse_authentication_callback_request(request) rescue => e # 400 Bad Request return generate_authentication_callback_request_format_error(e) end # Prepare an empty response. res = Authlete::Model::Response::AuthenticationCallbackResponse.new # Let the subclass authenticate the end-user. # When authenticated successfully, a non-nil value is returned. subject = authenticate_user(req) if subject.nil? # End-user authentication failed. # Return {"authenticated": false} to Authlete. res.authenticated = false return res.to_rack_response end # The end-user has been authenticated successfully. res.authenticated = true res.subject = subject if req.claims.nil? == false && req.claims.length != 0 # Make the subclass collect values of the requested claims. res.claims = collect_claims(req, subject) end # Return {"authenticated": true, ...} to Authlete. return res.to_rack_response end
Protected Instance Methods
Authenticate the API call to the authentication callback endpoint from Authlete
. Subclasses must override this method. This default implementation returns false, meaning 'unauthorized API call'.
The argument of this method is the API key and the API secret that the caller has presented. When the pair of the API credentials is valid, return true. Otherwise, return false.
# File lib/authlete/authentication-server.rb, line 178 def authenticate_api_call(api_key, api_secret) # Unauthorized API call. false end
Authenticate the end-user. Subclasses must override this method. This default implementation returns nil, meaning 'invalid end-user'.
The argument of this method is an instance of Authlete::Model::Request::AuthenticationCallbackRequest
. When the end-user is successfully authenticated, this method must return a unique identifier (= subject) of the end-user. Otherwise, nil must be returned to indicate authentication failure.
# File lib/authlete/authentication-server.rb, line 191 def authenticate_user(req) # Invalid end-user. nil end
Get the path of the authentication callback endpoint. This default implementation returns '/authentication'. Subclasses may override this method to change the path.
# File lib/authlete/authentication-server.rb, line 226 def authentication_callback_endpoint_path '/authentication' end
Collect claim values of the end-user. Subclasses should override this method. This default implementation returns nil, meaning 'no claim values'.
The argument of this method is an instance of Authlete::Model::Request::AuthenticationCallbackRequest
and the subject which has been returned from the preceding call of authenticate_user
method.
'Claim' is a piece of information about an end-user. A subclass should collect values of requested claims (req.claims
) as many as possible and format them in JSON format like below.
{ "name": "Takahiko Kawasaki", "gender": "male" }
Collected claim values are used to generate an {ID token} [openid.net/specs/openid-connect-core-1_0.html#IDToken].
If no claim values are available, or if you don't want to provide any claim value, return nil.
# File lib/authlete/authentication-server.rb, line 218 def collect_claims(req, subject) # No claim values. nil end
Private Instance Methods
# File lib/authlete/authentication-server.rb, line 103 def do_authenticate_api_call(env) # API key and secret for the API call to the authentication endpoint. api_key, api_secret = nil, nil # Basic Authentication for the API call. auth = Rack::Auth::Basic::Request.new(env) if auth.provided? && auth.basic? api_key, api_secret = *auth.credentials end # Let the subclass authenticate the API call. authenticate_api_call(api_key, api_secret) end
401 Unauthorized
# File lib/authlete/authentication-server.rb, line 132 def generate_api_call_authentication_failure [ 401, { 'Content-Type' => 'text/plain', 'WWW-Authenticate' => 'Basic realm="Authentication Callback Endpoint"' }, [ 'Authentication of the API call to the authentication callback endpoint failed.' ] ] end
400 Bad Request
# File lib/authlete/authentication-server.rb, line 146 def generate_authentication_callback_request_format_error(exception) [ 400, { 'Content-Type' => 'text/plain', }, [ "The format of the authentication callback request was wrong: #{exception.to_s}" ] ] end
404 Not Found
# File lib/authlete/authentication-server.rb, line 119 def generate_not_found(request) [ 404, { 'Content-Type' => 'text/plain' }, [ "Not Found: #{request.request_method} #{request.path_info} (#{request.content_type})" ] ] end
# File lib/authlete/authentication-server.rb, line 97 def match_authentication_callback_request(request) request.post? && request.path_info == authentication_callback_endpoint_path() && %r{^application/json}i === request.content_type end
# File lib/authlete/authentication-server.rb, line 158 def parse_authentication_callback_request(request) # In case someone has already read it. request.body.rewind # JSON json = request.body.read # Parse the authentication callback request. Authlete::Model::Request::AuthenticationCallbackRequest.parse(json) end