mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix(codersdk): use header auth for non-browser websocket dials (#22461)
## Context This commit is part of the fix for a downstream provider outage observed during `coderd_template` updates. Observed downstream symptoms (terraform-provider-coderd): - Template-version websocket log stream requests returned `401`: `GET /api/v2/templateversions/<id>/logs`. - In older provider code (`waitForJob`), stream-init errors could produce `(nil, nil, err)` and then trigger a nil dereference when `closer.Close()` was deferred before checking `err`. - Net effect: template update path crashed instead of returning a controlled provisioning error. That provider panic is being hardened in the provider repo separately (https://github.com/coder/terraform-provider-coderd/pull/308). This commit addresses the upstream SDK auth mismatch that caused the websocket `401` side of the chain. ## Root cause On deployments with host-prefixed cookie handling (dev.coder.com) enabled (`--host-prefix-cookie` / `EnableHostPrefix=true`), middleware rewrites cookie state to enforce prefixed auth cookies. For non-browser websocket clients that still sent unprefixed `coder_session_token` via cookie jars, this created an auth mismatch: - cookie-based credential expected by the client path, - but cookie normalization/stripping applied server-side, - resulting in no usable token at auth extraction time. ## Fix in this commit Apply the #22226 non-browser auth principle to remaining websocket callsites in `codersdk` by replacing cookie-jar session auth with header-token auth. _Generated with mux but reviewed by a human_
This commit is contained in:
@@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/netip"
|
||||
"os"
|
||||
"strconv"
|
||||
@@ -363,26 +362,23 @@ func (c *Client) AgentReconnectingPTY(ctx context.Context, opts WorkspaceAgentRe
|
||||
}
|
||||
serverURL.RawQuery = q.Encode()
|
||||
|
||||
// If we're not using a signed token, we need to set the session token as a
|
||||
// cookie.
|
||||
httpClient := c.client.HTTPClient
|
||||
// Shallow-clone the HTTP client so we never inherit a caller-provided
|
||||
// cookie jar. Non-browser websocket auth uses the Coder-Session-Token
|
||||
// header or a signed-token query param — never cookies. A stale jar
|
||||
// cookie would take precedence on the server (cookies are checked
|
||||
// before headers) and cause spurious 401s.
|
||||
wsHTTPClient := *c.client.HTTPClient
|
||||
wsHTTPClient.Jar = nil
|
||||
|
||||
headers := http.Header{}
|
||||
// If we're not using a signed token, set the session token header.
|
||||
if opts.SignedToken == "" {
|
||||
jar, err := cookiejar.New(nil)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("create cookie jar: %w", err)
|
||||
}
|
||||
jar.SetCookies(serverURL, []*http.Cookie{{
|
||||
Name: codersdk.SessionTokenCookie,
|
||||
Value: c.client.SessionToken(),
|
||||
}})
|
||||
httpClient = &http.Client{
|
||||
Jar: jar,
|
||||
Transport: c.client.HTTPClient.Transport,
|
||||
}
|
||||
headers.Set(codersdk.SessionTokenHeader, c.client.SessionToken())
|
||||
}
|
||||
//nolint:bodyclose
|
||||
conn, res, err := websocket.Dial(ctx, serverURL.String(), &websocket.DialOptions{
|
||||
HTTPClient: httpClient,
|
||||
HTTPClient: &wsHTTPClient,
|
||||
HTTPHeader: headers,
|
||||
})
|
||||
if err != nil {
|
||||
if res == nil {
|
||||
|
||||
Reference in New Issue
Block a user