Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions proxy/proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"log"
"log/slog"
"net/http"
"net/url"
"os"
"os/user"
"strconv"
Expand Down Expand Up @@ -200,3 +201,132 @@ func TestProxyServerBasicHTTPS(t *testing.T) {
err = server.Stop()
require.NoError(t, err)
}

// TestProxyServerCONNECT tests HTTP CONNECT method for HTTPS tunneling
func TestProxyServerCONNECT(t *testing.T) {
// Create test logger
logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
Level: slog.LevelError,
}))

// Create test rules (allow all for testing)
testRules, err := rules.ParseAllowSpecs([]string{"*"})
if err != nil {
t.Fatalf("Failed to parse test rules: %v", err)
}

// Create rule engine
ruleEngine := rules.NewRuleEngine(testRules, logger)

// Create mock auditor
auditor := &mockAuditor{}

// Get current user for TLS setup
currentUser, err := user.Current()
if err != nil {
log.Fatal(err)
}

uid, _ := strconv.Atoi(currentUser.Uid)
gid, _ := strconv.Atoi(currentUser.Gid)

// Create TLS certificate manager
certManager, err := boundary_tls.NewCertificateManager(boundary_tls.Config{
Logger: logger,
ConfigDir: "/tmp/boundary_connect_test",
Uid: uid,
Gid: gid,
})
require.NoError(t, err)

// Setup TLS to get cert path for proxy
tlsConfig, caCertPath, configDir, err := certManager.SetupTLSAndWriteCACert()
require.NoError(t, err)
_, _ = caCertPath, configDir

// Create proxy server
server := NewProxyServer(Config{
HTTPPort: 8080,

RuleEngine: ruleEngine,
Auditor: auditor,
Logger: logger,
TLSConfig: tlsConfig,
})

// Start server
err = server.Start()
require.NoError(t, err)

// Give server time to start
time.Sleep(100 * time.Millisecond)

// Test HTTPS request through proxy transport (automatic CONNECT)
t.Run("HTTPSRequestThroughProxyTransport", func(t *testing.T) {
// Create proxy URL
proxyURL, err := url.Parse("http://localhost:8080")
require.NoError(t, err)

// Create HTTP client with proxy transport
client := &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyURL(proxyURL),
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true, // Skip cert verification for testing
},
},
Timeout: 10 * time.Second,
}

// Because this is HTTPS, Go will issue CONNECT localhost:8080 → dev.coder.com:443
resp, err := client.Get("https://dev.coder.com/api/v2")
require.NoError(t, err)

// Read response
body, err := io.ReadAll(resp.Body)
require.NoError(t, err)
require.NoError(t, resp.Body.Close())

// Verify response contains expected content
expectedResponse := `{"message":"👋"}
`
require.Equal(t, expectedResponse, string(body))
})

// Test HTTP request through proxy transport
t.Run("HTTPRequestThroughProxyTransport", func(t *testing.T) {
// Create proxy URL
proxyURL, err := url.Parse("http://localhost:8080")
require.NoError(t, err)

// Create HTTP client with proxy transport
client := &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyURL(proxyURL),
},
Timeout: 10 * time.Second,
}

// For HTTP requests, Go will send the request directly to the proxy
// The proxy will forward it to the target server
resp, err := client.Get("http://jsonplaceholder.typicode.com/todos/1")
require.NoError(t, err)

// Read response
body, err := io.ReadAll(resp.Body)
require.NoError(t, err)
require.NoError(t, resp.Body.Close())

// Verify response contains expected content
expectedResponse := `{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}`
require.Equal(t, expectedResponse, string(body))
})

err = server.Stop()
require.NoError(t, err)
}
Loading