Skip to content

Commit 886d87c

Browse files
committed
add test for workspaceapps
1 parent 5ee6ad5 commit 886d87c

File tree

1 file changed

+88
-2
lines changed

1 file changed

+88
-2
lines changed

coderd/workspaceapps/apptest/apptest.go

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package apptest
33
import (
44
"bufio"
55
"context"
6+
"crypto/rand"
67
"encoding/json"
78
"fmt"
89
"io"
@@ -463,7 +464,7 @@ func Run(t *testing.T, appHostIsPrimary bool, factory DeploymentFactory) {
463464
appClient.SetSessionToken("")
464465

465466
// Try to load the application without authentication.
466-
u := c.appURL
467+
u := *c.appURL
467468
u.Path = path.Join(u.Path, "/test")
468469
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
469470
require.NoError(t, err)
@@ -500,7 +501,7 @@ func Run(t *testing.T, appHostIsPrimary bool, factory DeploymentFactory) {
500501

501502
// Copy the query parameters and then check equality.
502503
u.RawQuery = gotLocation.RawQuery
503-
require.Equal(t, u, gotLocation)
504+
require.Equal(t, u, *gotLocation)
504505

505506
// Verify the API key is set.
506507
encryptedAPIKey := gotLocation.Query().Get(workspaceapps.SubdomainProxyAPIKeyParam)
@@ -580,6 +581,70 @@ func Run(t *testing.T, appHostIsPrimary bool, factory DeploymentFactory) {
580581
resp.Body.Close()
581582
require.Equal(t, http.StatusOK, resp.StatusCode)
582583
})
584+
585+
t.Run("BadJWT", func(t *testing.T) {
586+
t.Parallel()
587+
588+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
589+
defer cancel()
590+
591+
currentKeyStr := appDetails.SDKClient.SessionToken()
592+
appClient := appDetails.AppClient(t)
593+
appClient.SetSessionToken("")
594+
u := *c.appURL
595+
u.Path = path.Join(u.Path, "/test")
596+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
597+
require.NoError(t, err)
598+
599+
var resp *http.Response
600+
resp, err = doWithRetries(t, appClient, req)
601+
require.NoError(t, err)
602+
603+
if !assert.Equal(t, http.StatusSeeOther, resp.StatusCode) {
604+
dump, err := httputil.DumpResponse(resp, true)
605+
require.NoError(t, err)
606+
t.Log(string(dump))
607+
}
608+
resp.Body.Close()
609+
610+
// Check that the Location is correct.
611+
gotLocation, err := resp.Location()
612+
require.NoError(t, err)
613+
// This should always redirect to the primary access URL.
614+
require.Equal(t, appDetails.SDKClient.URL.Host, gotLocation.Host)
615+
require.Equal(t, "/api/v2/applications/auth-redirect", gotLocation.Path)
616+
require.Equal(t, u.String(), gotLocation.Query().Get("redirect_uri"))
617+
618+
// Load the application auth-redirect endpoint.
619+
resp, err = requestWithRetries(ctx, t, appDetails.SDKClient, http.MethodGet, "/api/v2/applications/auth-redirect", nil, codersdk.WithQueryParam(
620+
"redirect_uri", u.String(),
621+
))
622+
require.NoError(t, err)
623+
defer resp.Body.Close()
624+
625+
require.Equal(t, http.StatusSeeOther, resp.StatusCode)
626+
gotLocation, err = resp.Location()
627+
require.NoError(t, err)
628+
629+
badToken := generateBadJWT(t, workspaceapps.EncryptedAPIKeyPayload{
630+
APIKey: currentKeyStr,
631+
})
632+
633+
gotLocation.RawQuery = (url.Values{
634+
workspaceapps.SubdomainProxyAPIKeyParam: {badToken},
635+
}).Encode()
636+
637+
req, err = http.NewRequestWithContext(ctx, "GET", gotLocation.String(), nil)
638+
require.NoError(t, err)
639+
resp, err = appClient.HTTPClient.Do(req)
640+
require.NoError(t, err)
641+
defer resp.Body.Close()
642+
require.Equal(t, http.StatusBadRequest, resp.StatusCode)
643+
body, err := io.ReadAll(resp.Body)
644+
require.NoError(t, err)
645+
require.Contains(t, string(body), "Could not decrypt API key. Please remove the query parameter and try again.")
646+
647+
})
583648
}
584649
})
585650
})
@@ -1789,3 +1854,24 @@ func assertWorkspaceLastUsedAtNotUpdated(t testing.TB, details *Details) {
17891854
require.NoError(t, err)
17901855
require.Equal(t, before.LastUsedAt, after.LastUsedAt, "workspace LastUsedAt updated when it should not have been")
17911856
}
1857+
1858+
// generateBadJWT generates a JWT with a random key. It's intended to emulate the old-style JWT's we generated.
1859+
func generateBadJWT(t *testing.T, claims interface{}) string {
1860+
t.Helper()
1861+
1862+
var buf [64]byte
1863+
_, err := rand.Read(buf[:])
1864+
require.NoError(t, err)
1865+
signer, err := jose.NewSigner(jose.SigningKey{
1866+
Algorithm: jose.HS512,
1867+
Key: buf[:],
1868+
}, nil)
1869+
require.NoError(t, err)
1870+
payload, err := json.Marshal(claims)
1871+
require.NoError(t, err)
1872+
signed, err := signer.Sign(payload)
1873+
require.NoError(t, err)
1874+
compact, err := signed.CompactSerialize()
1875+
require.NoError(t, err)
1876+
return compact
1877+
}

0 commit comments

Comments
 (0)