WarpEngine: let the host say who a browser is
The access policy asks who the caller is, and until now only a bearer token
could answer. That is what a desktop client carries — but a person clicking a
download link on the site carries a session instead, and the engine has no idea
what a session is. So a host that gated its catalog found its own signed-in
visitors refused at /api/download, which is a regression the shadowed route used
to hide.
c.subject_resolver is a callable taking the Rack request and returning the
host's subject: `->(request) { request.env["warden"]&.user }` for a Devise app.
Unset — every deployment today — a non-bearer request stays anonymous, exactly
as before. A resolver that raises is logged and treated as anonymous, because a
broken one turning every read into a 500 is worse than an anonymous request.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -20,10 +20,20 @@ module WarpEngine
|
||||
@current_access_token = resolve_access_token
|
||||
end
|
||||
|
||||
# Whoever that token belongs to — the host's own object. nil when the request is
|
||||
# anonymous, when the token is unknown, or when no subject class is configured.
|
||||
# Whoever the request is on behalf of — the host's own object, or nil.
|
||||
#
|
||||
# Two ways to be somebody, tried in that order. A bearer token is what a client
|
||||
# carries. A *browser* carries a session instead, and the engine has no idea what a
|
||||
# session is here — so a host that wants its signed-in visitors recognised on these
|
||||
# endpoints supplies a resolver:
|
||||
#
|
||||
# c.subject_resolver = ->(request) { request.env["warden"]&.user }
|
||||
#
|
||||
# Without one, a browser is simply anonymous, which is what it always was.
|
||||
def current_subject
|
||||
current_access_token&.owner
|
||||
return @current_subject if defined?(@current_subject)
|
||||
|
||||
@current_subject = current_access_token&.owner || resolve_host_subject
|
||||
end
|
||||
|
||||
def resolve_access_token
|
||||
@@ -41,6 +51,19 @@ module WarpEngine
|
||||
record
|
||||
end
|
||||
|
||||
# A resolver that raises must not take the request with it: it runs on every read
|
||||
# endpoint, and a broken one would turn the whole API into 500s rather than into
|
||||
# anonymous requests, which is the honest fallback.
|
||||
def resolve_host_subject
|
||||
resolver = WarpEngine.config.subject_resolver
|
||||
return nil if resolver.nil?
|
||||
|
||||
resolver.call(request)
|
||||
rescue StandardError => e
|
||||
Rails.logger.error("[WarpEngine::SubjectAuthentication] subject_resolver #{e.class}: #{e.message}")
|
||||
nil
|
||||
end
|
||||
|
||||
def bearer_token
|
||||
header = request.headers["Authorization"].to_s
|
||||
return nil unless header.start_with?("Bearer ")
|
||||
|
||||
Reference in New Issue
Block a user