Class: Basecamp::Oauth::Resource
- Inherits:
-
Object
- Object
- Basecamp::Oauth::Resource
- Defined in:
- lib/basecamp/oauth/resource.rb
Overview
Fetches RFC 9728 protected-resource metadata (hop 1 of resource-first
discovery) and binds the returned resource to the requested origin.
Instance Method Summary collapse
-
#discover(resource_origin) ⇒ ProtectedResourceMetadata
Discovers protected-resource metadata from {resource_origin}/.well-known/oauth-protected-resource.
-
#initialize(http_client: nil, timeout: 10, max_body_bytes: Fetcher::DEFAULT_MAX_BODY_BYTES) ⇒ Resource
constructor
A new instance of Resource.
Constructor Details
#initialize(http_client: nil, timeout: 10, max_body_bytes: Fetcher::DEFAULT_MAX_BODY_BYTES) ⇒ Resource
Returns a new instance of Resource.
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/basecamp/oauth/resource.rb', line 11 def initialize(http_client: nil, timeout: 10, max_body_bytes: Fetcher::DEFAULT_MAX_BODY_BYTES) Fetcher.ensure_redirects_suppressed!(http_client) if http_client # Normalize before building the client and before the fetch computes its # wall-clock deadline: a non-finite/non-positive timeout must not disable # either bound (see Fetcher.normalize_timeout). @timeout = Fetcher.normalize_timeout(timeout) @http_client = http_client || Fetcher.build_client(@timeout) # Normalize the public cap to a finite non-negative Integer: a nil, float, # or Float::INFINITY would otherwise disable the streaming memory bound # (an infinite/undefined cap never trips), reintroducing an SSRF/OOM risk. @max_body_bytes = if max_body_bytes.is_a?(Integer) && max_body_bytes >= 0 max_body_bytes else Fetcher::DEFAULT_MAX_BODY_BYTES end end |
Instance Method Details
#discover(resource_origin) ⇒ ProtectedResourceMetadata
Discovers protected-resource metadata from
{resource_origin}/.well-known/oauth-protected-resource.
resource is required and must equal the requested origin by code-point;
authorization_servers is preserved distinctly as absent (+nil+) vs
present-empty (+[]+).
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 |
# File 'lib/basecamp/oauth/resource.rb', line 39 def discover(resource_origin) origin = Basecamp::Security.require_origin_root!(resource_origin, "resource origin") url = "#{origin}/.well-known/oauth-protected-resource" data = Fetcher.fetch_json(@http_client, url, timeout: @timeout, max_body_bytes: @max_body_bytes) resource = data["resource"] # Type-check, don't just probe truthiness: a wrong-typed resource (number, # object, array) is malformed metadata, and calling +.empty?+ on it would # raise a NoMethodError rather than a clean api_error. if !resource.is_a?(String) || resource.empty? raise OauthError.new("api_error", "Invalid resource metadata: missing required field: resource") end # Bind the resource identifier to the requested identifier (the raw caller # origin), code-point exact, NO normalization (RFC 9728 §3.3, SPEC.md §16): # the well-known URL is built from the normalized +origin+, but the metadata # +resource+ must be identical to what the caller supplied. unless resource == resource_origin raise OauthError.new( "api_error", "Resource identifier mismatch: metadata resource #{resource.inspect} does not equal #{resource_origin.inspect}" ) end ProtectedResourceMetadata.new( resource: resource, authorization_servers: (data) ) end |