enhancement
major
minor
defect
critical
major
minor
major
#30177
Der Entwicklungsserver ignoriert X-Forwarded-*-Header, sodass eine relative Callback-URL hinter einem Proxy den falschen Ursprung angibt.
Problem
Der Entwicklungsserver einer Anwendung (com.top_logic.ide.jetty.Bootstrap) erstellt seine HttpConfiguration ohne einen ForwardedRequestCustomizer. Hinter einem Reverse-Proxy entsprechen das Schema, der Servername und der Port einer Anfrage daher denen der Verbindung des Proxys zum Server (z. B. 127.0.0.1:<veröffentlichter Port>) und nicht denen der vom Browser verwendeten Quelle.
Alles, was eine absolute URL aus der Anfrage ableitet, funktioniert hinter einem Proxy nicht mehr. Ein Beispiel ist die pac4j-Anmeldung: Der `DefaultOidcClientConfigurator` ergänzt den relativen Callback `/servlet/callback` aus der Anfrage (DefaultUrlResolver). Der OpenID-Anbieter leitet den Browser dann zu einer Quelle weiter, die dieser nie verwendet hat. Die Sitzung der Anwendung, die den pac4j-Zustand enthält, wird nicht dorthin gesendet, und die Anmeldung schlägt fehl.
Die Konfiguration eines absoluten Callbacks über `tl_host` ist keine Lösung, wenn derselbe Server sowohl über den Proxy als auch direkt (z. B. von einem Browser auf `localhost`) erreicht wird. Dies behebt zwar einen Fall, führt aber im anderen zu Fehlern.
Entdeckt von der Steuerungsanwendung tl-factory. Ihre Vorschau-Route leitet an den Entwicklungsserver einer Anwendung in einem Container mit den Headern „X-Forwarded-Host“, „X-Forwarded-Proto“ und „X-Forwarded-For“ weiter, während der Browser des Agenten in diesem Container die Anwendung unter „localhost“ erreicht (Gitea-Issue TopLogic/tl-factory#47).
Entwurf
- Bootstrap fügt Jettys „ForwardedRequestCustomizer“ zu seiner „HttpConfiguration“ hinzu. Schema, Host, Port und Remote-Adresse einer Anfrage folgen dann den X-Forwarded-* / Forwarded-Headern, sofern vorhanden, andernfalls den eigenen Werten der Anfrage.
- Dies ist auf den Entwicklungsserver beschränkt. Eine bereitgestellte Anwendung konfiguriert die Vertrauenswürdigkeit weitergeleiteter Header in ihrem eigenen Container.
Akzeptanz
- Eine Anfrage mit „X-Forwarded-Host: factory.example:8443“ und „X-Forwarded-Proto: https“ erkennt „https“, „factory.example“ und „8443“ als Schema, Servernamen und Port.
- Eine Anfrage ohne diese Header bleibt unverändert.
- Eine pac4j-Anmeldung mit dem standardmäßigen relativen Callback hinter einem solchen Proxy leitet zum weitergeleiteten Ursprung weiter, und eine direkte Anmeldung auf „localhost“ führt zu „localhost“.
Lösung
- Entwicklungsserver: Bootstrap fügt den „ForwardedRequestCustomizer“ zu seiner „HttpConfiguration“ hinzu.
- Die TL-Script-Funktionen requestScheme(), requestServerName(), requestServerPort(), requestRemoteAddr() und requestUrl() (RequestFunctions, Modul tl-model-search) beschreiben die aktuell verarbeitete HTTP-Anfrage aus Sicht des Servers, d. h. nach Anwendung der Weiterleitungs-Header. Außerhalb einer HTTP-Anfrage (Scheduler-Task, Startvorgang) geben sie null zurück.
- OpenAPI-Server: OpenApiServlet erbt nun von NoContextServlet. Ein REST-Aufruf wird in einer Interaktion verarbeitet, die die HTTP-Anfrage enthält (mit einer eigenen Untersitzung, der Locale aus „Accept-Language“, ohne HTTP-Sitzung), sodass die TL-Script-Implementierung einer Operation die Anfrage sieht, z. B. über die oben genannten Funktionen. Zuvor lief das Skript in einer synthetischen Interaktion ohne Anfrage. Die Authentifizierung und die Identität des Skripts (System oder authentifizierte Person) bleiben unverändert.
- Demo: tl-demo-react enthält den OpenAPI-Server mit der öffentlichen Operation GET /api/request-info, die das Schema, den Servernamen, den Serverport, die Client-Adresse und die URL der Anfrage als JSON zurückgibt. Sie zeigt, ob die Weiterleitungs-Header eines Proxys wirksam sind:
curl -H 'X-Forwarded-Host: factory.example:8443' -H 'X-Forwarded-Proto: https' -H 'X-Forwarded-For: 203.0.113.7' http://localhost:<port>/tl-demo-react/api/request-info
{"scheme":"https","serverName":"factory.example","serverPort":8443,"remoteAddr":"203.0.113.7","url":"https://factory.example:8443/tl-demo-react/api/request-info"}
Migration
- OpenApiServlet erbt nun von NoContextServlet statt von AbstractTopLogicServlet; die Methode serviceWithLogMark(HttpServletRequest, HttpServletResponse) entfällt. Eine eigene Unterklasse von OpenApiServlet überschreibt stattdessen doService(HttpServletRequest, HttpServletResponse).