annotate libervia/server/proxy.py @ 1435:396d5606477f

server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
author Goffi <goffi@goffi.org>
date Mon, 14 Jun 2021 15:27:33 +0200
parents 822bd0139769
children fc91b78b71db
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1360
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
1 #!/usr/bin/env python3
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
2
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
3 # Libervia: a Salut à Toi frontend
1396
822bd0139769 date update
Goffi <goffi@goffi.org>
parents: 1360
diff changeset
4 # Copyright (C) 2011-2021 Jérôme Poisson <goffi@goffi.org>
1360
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
5
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
6 # This program is free software: you can redistribute it and/or modify
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
7 # it under the terms of the GNU Affero General Public License as published by
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
8 # the Free Software Foundation, either version 3 of the License, or
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
9 # (at your option) any later version.
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
10
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
11 # This program is distributed in the hope that it will be useful,
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
14 # GNU Affero General Public License for more details.
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
15
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
16 # You should have received a copy of the GNU Affero General Public License
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
18 from twisted.web import proxy
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
19 from twisted.python.compat import urlquote
1435
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
20 from twisted.internet import address
1360
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
21 from sat.core.log import getLogger
1435
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
22 from libervia.server.constants import Const as C
1360
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
23
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
24 log = getLogger(__name__)
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
25
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
26
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
27
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
28 class SatProxyClient(proxy.ProxyClient):
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
29
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
30 def handleHeader(self, key, value):
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
31 if key.lower() == b"x-frame-options":
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
32 value = b"sameorigin"
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
33 elif key.lower() == b"content-security-policy":
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
34 value = value.replace(b"frame-ancestors 'none'", b"frame-ancestors 'self'")
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
35
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
36 super().handleHeader(key, value)
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
37
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
38
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
39 class SatProxyClientFactory(proxy.ProxyClientFactory):
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
40 protocol = SatProxyClient
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
41
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
42
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
43 class SatReverseProxyResource(proxy.ReverseProxyResource):
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
44 """Resource Proxy rewritting headers to allow embedding in iframe on same domain"""
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
45 proxyClientFactoryClass = SatProxyClientFactory
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
46
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
47 def getChild(self, path, request):
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
48 return SatReverseProxyResource(
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
49 self.host, self.port,
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
50 self.path + b'/' + urlquote(path, safe=b"").encode('utf-8'),
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
51 self.reactor
389a83eefe62 server: SàT applications integration:
Goffi <goffi@goffi.org>
parents:
diff changeset
52 )
1435
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
53
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
54 def render(self, request):
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
55 # Forwarded and X-Forwarded-xxx headers can be set if we have behin an other proxy
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
56 if ((not request.getHeader(C.H_FORWARDED)
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
57 and not request.getHeader(C.H_X_FORWARDED_HOST))):
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
58 forwarded_data = []
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
59 addr = request.getClientAddress()
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
60 if ((isinstance(addr, address.IPv4Address)
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
61 or isinstance(addr, address.IPv6Address))):
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
62 request.requestHeaders.setRawHeaders(C.H_X_FORWARDED_FOR, [addr.host])
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
63 forwarded_data.append(f"for={addr.host}")
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
64 host = request.getHeader("host")
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
65 if host is None:
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
66 port = request.getHost().port
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
67 hostname = request.getRequestHostname()
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
68 host = hostname if port in (80, 443) else f"{hostname}:{port}"
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
69 request.requestHeaders.setRawHeaders(C.H_X_FORWARDED_HOST, [host])
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
70 forwarded_data.append(f"host={host}")
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
71 proto = "https" if request.isSecure() else "http"
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
72 request.requestHeaders.setRawHeaders(C.H_X_FORWARDED_PROTO, [proto])
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
73 forwarded_data.append(f"proto={proto}")
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
74 request.requestHeaders.setRawHeaders(
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
75 C.H_FORWARDED, [";".join(forwarded_data)]
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
76 )
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
77
396d5606477f server (proxy): add "Forwarded" and "X-Forwarded-xxx" headers to reverse proxy
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
78 return super().render(request)