@@ -2,24 +2,17 @@ package proxy
2
2
3
3
import (
4
4
"crypto/tls"
5
- "crypto/x509"
6
5
"fmt"
7
6
"log"
8
- "math/big"
9
7
"net"
10
8
"net/http"
11
9
"net/http/httputil"
12
- "path"
13
10
"testing"
14
-
15
- "github.com/argoproj-labs/argocd-agent/test/fake/testcerts"
16
11
)
17
12
18
- // Start a reverse proxy that downgrades the incoming HTTP/2 requests to HTTP/1.1
19
- func StartHTTP2DowngradingProxy (t * testing.T , addr string , target string ) * http.Server {
20
- tempDir := t .TempDir ()
21
- basePath := path .Join (tempDir , "certs" )
22
- testcerts .WriteSelfSignedCert (t , "rsa" , basePath , x509.Certificate {SerialNumber : big .NewInt (1 )})
13
+ // StartHTTP2DowngradingProxy starts a proxy that downgrades HTTP/2.0 to HTTP/1.1
14
+ // This simulates a real HTTP/1.1-only proxy environment.
15
+ func StartHTTP2DowngradingProxy (t * testing.T , addr string , target string , agentClientCert , principalServerCert tls.Certificate ) * http.Server {
23
16
24
17
lis , err := net .Listen ("tcp" , addr )
25
18
if err != nil {
@@ -28,58 +21,79 @@ func StartHTTP2DowngradingProxy(t *testing.T, addr string, target string) *http.
28
21
29
22
server := & http.Server {
30
23
TLSConfig : & tls.Config {
31
- InsecureSkipVerify : true ,
24
+ // Use principal's server certificate for incoming connections
25
+ // This makes the agent think it's connecting to the real principal
26
+ Certificates : []tls.Certificate {principalServerCert },
27
+ NextProtos : []string {"h2" , "http/1.1" },
32
28
},
33
- Handler : downgradeToHTTP1Handler (target ),
29
+ Handler : downgradeToHTTP1Handler (target , agentClientCert ),
34
30
Addr : lis .Addr ().String (),
35
31
}
36
32
37
33
//nolint:errcheck
38
- go server .ServeTLS (lis , basePath + ".crt" , basePath + ".key" )
34
+ go func () {
35
+ tlsListener := tls .NewListener (lis , server .TLSConfig )
36
+ if err := server .Serve (tlsListener ); err != nil {
37
+ log .Printf ("Proxy server error: %v" , err )
38
+ }
39
+ }()
39
40
40
41
return server
41
42
}
42
43
43
- func downgradeToHTTP1Handler (target string ) http.Handler {
44
- printHeaders := func (header http.Header ) {
45
- for name , values := range header {
46
- for _ , value := range values {
47
- fmt .Printf ("%s: %s\n " , name , value )
48
- }
49
- }
50
- }
51
- return & httputil.ReverseProxy {
52
- Director : func (req * http.Request ) {
53
- fmt .Println ("Intercepting a request" )
54
- req .URL .Host = target
55
- if req .URL .Scheme == "" {
56
- req .URL .Scheme = "https"
57
- }
44
+ func downgradeToHTTP1Handler (target string , agentCert tls.Certificate ) http.Handler {
45
+ return http .HandlerFunc (func (w http.ResponseWriter , req * http.Request ) {
46
+ fmt .Printf ("Intercepting a %s request to %s\n " , req .Method , req .URL )
47
+
48
+ // Check if this is a gRPC request
49
+ isGRPC := req .Header .Get ("Content-Type" ) == "application/grpc"
50
+ fmt .Printf ("Is gRPC request: %t, Protocol: %s\n " , isGRPC , req .Proto )
58
51
59
- // Request is downgraded to HTTP/1.1
52
+ // Downgrade all requests to HTTP/1.1
53
+ if req .Proto == "HTTP/2.0" {
54
+ fmt .Println ("Downgrading request from HTTP/2.0 to HTTP/1.1" )
60
55
req .ProtoMajor , req .ProtoMinor , req .Proto = 1 , 1 , "HTTP/1.1"
56
+ }
61
57
62
- // Log headers for debugging
63
- fmt .Println ("Request Headers:" )
64
- printHeaders (req .Header )
65
- },
66
- Transport : & http.Transport {
67
- TLSClientConfig : & tls.Config {
68
- InsecureSkipVerify : true ,
69
- },
70
- ForceAttemptHTTP2 : false ,
71
- },
72
- ModifyResponse : func (res * http.Response ) error {
73
- // Ensure the response is sent as HTTP/1.1
74
- res .ProtoMajor = 1
75
- res .ProtoMinor = 1
76
- res .Proto = "HTTP/1.1"
58
+ // For WebSocket upgrade requests, allow them through
59
+ if req .Header .Get ("Upgrade" ) == "websocket" {
60
+ fmt .Println ("Allowing WebSocket upgrade request" )
61
+ } else if isGRPC && req .Proto == "HTTP/1.1" {
62
+ fmt .Println ("Forwarding downgraded gRPC request over HTTP/1.1" )
63
+ }
77
64
78
- // Log response headers for debugging
79
- fmt .Println ("Response Headers:" )
80
- printHeaders (res .Header )
65
+ // Use reverse proxy with HTTP/1.1 enforcement
66
+ proxy := & httputil.ReverseProxy {
67
+ Director : func (req * http.Request ) {
68
+ req .URL .Host = target
69
+ if req .URL .Scheme == "" {
70
+ req .URL .Scheme = "https"
71
+ }
81
72
82
- return nil
83
- },
84
- }
73
+ // Ensure the request is downgraded to HTTP/1.1
74
+ req .ProtoMajor , req .ProtoMinor , req .Proto = 1 , 1 , "HTTP/1.1"
75
+
76
+ fmt .Printf ("Proxying %s request to %s (downgraded to %s)\n " , req .Method , req .URL , req .Proto )
77
+ },
78
+ Transport : & http.Transport {
79
+ TLSClientConfig : & tls.Config {
80
+ InsecureSkipVerify : true ,
81
+ // Use agent's certificate for outgoing connections
82
+ // This makes the principal think it's connecting to the real agent
83
+ Certificates : []tls.Certificate {agentCert },
84
+ },
85
+ ForceAttemptHTTP2 : false ,
86
+ },
87
+ ModifyResponse : func (res * http.Response ) error {
88
+ if res != nil {
89
+ // Ensure response is also HTTP/1.1
90
+ res .ProtoMajor , res .ProtoMinor , res .Proto = 1 , 1 , "HTTP/1.1"
91
+ fmt .Printf ("Response: %s (proto: %s)\n " , res .Status , res .Proto )
92
+ }
93
+ return nil
94
+ },
95
+ }
96
+
97
+ proxy .ServeHTTP (w , req )
98
+ })
85
99
}
0 commit comments