Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 79c666b

Browse files
fix(vpn): avoid setting session token header twice (#18524)
`coderd` currently does not handle a session token header value of the form `token1, token2`. However, it does handle multiple instances of the token header by simply taking the first. This is the default behaviour of `http.Header.Get`. So, setting the token header twice causes issues when Coder is behind a proxy that merges duplicate headers, such as [Apache](https://httpd.apache.org/docs/2.4/mod/mod_headers.html#:~:text=list%20of%20values.-,When%20a%20new%20value%20is%20merged%20onto%20an%20existing%20header,format%20specifiers%20have%20been%20processed). This PR ensures we don't set it twice by not sharing one slice between the `HTTPClient` and the `websocket.DialerOptions`. It also adds a regression test.
1 parent 288ec77 commit 79c666b

File tree

3 files changed

+12
-4
lines changed

3 files changed

+12
-4
lines changed

codersdk/client.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ func (c *Client) Dial(ctx context.Context, path string, opts *websocket.DialOpti
354354
if opts.HTTPHeader == nil {
355355
opts.HTTPHeader = http.Header{}
356356
}
357-
if opts.HTTPHeader.Get("tokenHeader") == "" {
357+
if opts.HTTPHeader.Get(tokenHeader) == "" {
358358
opts.HTTPHeader.Set(tokenHeader, c.SessionToken())
359359
}
360360

vpn/client.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ func (*client) NewConn(initCtx context.Context, serverURL *url.URL, token string
9292
sdk.SetSessionToken(token)
9393
sdk.HTTPClient.Transport = &codersdk.HeaderTransport{
9494
Transport: http.DefaultTransport,
95-
Header: headers,
95+
Header: headers.Clone(),
9696
}
9797

9898
// New context, separate from initCtx. We don't want to cancel the
@@ -129,17 +129,18 @@ func (*client) NewConn(initCtx context.Context, serverURL *url.URL, token string
129129
headers.Set(codersdk.SessionTokenHeader, token)
130130
dialer := workspacesdk.NewWebsocketDialer(options.Logger, rpcURL, &websocket.DialOptions{
131131
HTTPClient: sdk.HTTPClient,
132-
HTTPHeader: headers,
132+
HTTPHeader: headers.Clone(),
133133
CompressionMode: websocket.CompressionDisabled,
134134
}, workspacesdk.WithWorkspaceUpdates(&proto.WorkspaceUpdatesRequest{
135135
WorkspaceOwnerId: tailnet.UUIDToByteSlice(me.ID),
136136
}))
137137

138+
clonedHeaders := headers.Clone()
138139
ip := tailnet.CoderServicePrefix.RandomAddr()
139140
conn, err := tailnet.NewConn(&tailnet.Options{
140141
Addresses: []netip.Prefix{netip.PrefixFrom(ip, 128)},
141142
DERPMap: connInfo.DERPMap,
142-
DERPHeader: &headers,
143+
DERPHeader: &clonedHeaders,
143144
DERPForceWebSockets: connInfo.DERPForceWebSockets,
144145
Logger: options.Logger,
145146
BlockEndpoints: connInfo.DisableDirectConnections,

vpn/client_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ func TestClient_WorkspaceUpdates(t *testing.T) {
9090
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
9191
switch r.URL.Path {
9292
case "/api/v2/users/me":
93+
values := r.Header.Values(codersdk.SessionTokenHeader)
94+
assert.Len(t, values, 1, "expected exactly one session token header value")
9395
httpapi.Write(ctx, w, http.StatusOK, codersdk.User{
9496
ReducedUser: codersdk.ReducedUser{
9597
MinimalUser: codersdk.MinimalUser{
@@ -101,6 +103,8 @@ func TestClient_WorkspaceUpdates(t *testing.T) {
101103
user <- struct{}{}
102104

103105
case "/api/v2/workspaceagents/connection":
106+
values := r.Header.Values(codersdk.SessionTokenHeader)
107+
assert.Len(t, values, 1, "expected exactly one session token header value")
104108
httpapi.Write(ctx, w, http.StatusOK, tc.agentConnectionInfo)
105109
connInfo <- struct{}{}
106110

@@ -109,6 +113,9 @@ func TestClient_WorkspaceUpdates(t *testing.T) {
109113
cVer := r.URL.Query().Get("version")
110114
assert.Equal(t, "2.3", cVer)
111115

116+
values := r.Header.Values(codersdk.SessionTokenHeader)
117+
assert.Len(t, values, 1, "expected exactly one session token header value")
118+
112119
sws, err := websocket.Accept(w, r, nil)
113120
if !assert.NoError(t, err) {
114121
return

0 commit comments

Comments
 (0)