8000 Extract auth code helper · coder/coder@8b597a1 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8b597a1

Browse files
committed
Extract auth code helper
1 parent 7b118ac commit 8b597a1

File tree

2 files changed

+59
-27
lines changed

2 files changed

+59
-27
lines changed

coderd/coderdtest/oidctest/helper.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
package oidctest
22

33
import (
4+
"context"
45
"database/sql"
56
"encoding/json"
67
"net/http"
8+
"net/url"
79
"testing"
810
"time"
911

1012
"github.com/golang-jwt/jwt/v4"
1113
"github.com/stretchr/testify/require"
14+
"golang.org/x/xerrors"
1215

1316
"github.com/coder/coder/v2/coderd/database"
1417
"github.com/coder/coder/v2/coderd/database/dbauthz"
@@ -114,3 +117,51 @@ func (h *LoginHelper) ForceRefresh(t *testing.T, db database.Store, user *coders
114117
_, err := user.User(testutil.Context(t, testutil.WaitShort), "me")
115118
require.NoError(t, err, "user must be able to be fetched")
116119
}
120+
121+
// OAuth2GetCode emulates a user clicking "allow" on the IDP page. When doing
122+
// unit tests, it's easier to skip this step sometimes. It does make an actual
123+
// request to the IDP, so it should be equivalent to doing this "manually" with
124+
// actual requests.
125+
//
126+
// TODO: Is state param optional? Can we grab it from the authURL?
127+
func OAuth2GetCode(authURL string, state string, doRequest func(req *http.Request) (*http.Response, error)) (string, error) {
128+
// We need to store some claims, because this is also an OIDC provider, and
129+
// it expects some claims to be present.
130+
// TODO: POST or GET method?
131+
r, err := http.NewRequestWithContext(context.Background(), http.MethodGet, authURL, nil)
132+
if err != nil {
133+
return "", xerrors.Errorf("failed to create auth request: %w", err)
134+
}
135+
136+
expCode := http.StatusTemporaryRedirect
137+
resp, err := doRequest(r)
138+
if err != nil {
139+
return "", xerrors.Errorf("request: %w", err)
140+
}
141+
defer resp.Body.Close()
142+
143+
if resp.StatusCode != expCode {
144+
return "", codersdk.ReadBodyAsError(resp)
145+
}
146+
147+
to := resp.Header.Get("Location")
148+
if to == "" {
149+
return "", xerrors.Errorf("expected redirect location")
150+
}
151+
152+
toURL, err := url.Parse(to)
153+
if err != nil {
154+
return "", xerrors.Errorf("failed to parse redirect location: %w", err)
155+
}
156+
157+
code := toURL.Query().Get("code")
158+
if code == "" {
159+
return "", xerrors.Errorf("expected code in redirect location")
160+
}
161+
162+
newState := toURL.Query().Get("state")
163+
if newState != state {
164+
return "", xerrors.Errorf("expected state %q, got %q", state, newState)
165+
}
166+
return code, nil
167+
}

coderd/coderdtest/oidctest/idp.go

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -514,37 +514,18 @@ func (*FakeIDP) DeviceLogin(t testing.TB, client *codersdk.Client, externalAuthI
514514
// unit tests, it's easier to skip this step sometimes. It does make an actual
515515
// request to the IDP, so it should be equivalent to doing this "manually" with
516516
// actual requests.
517-
func (f *FakeIDP) CreateAuthCode(t testing.TB, state string, opts ...func(r *http.Request)) string {
517+
func (f *FakeIDP) CreateAuthCode(t testing.TB, state string) string {
518518
// We need to store some claims, because this is also an OIDC provider, and
519519
// it expects some claims to be present.
520520
f.stateToIDTokenClaims.Store(state, jwt.MapClaims{})
521521

522-
u := f.cfg.AuthCodeURL(state)
523-
r, err := http.NewRequestWithContext(context.Background(), http.MethodPost, u, nil)
524-
require.NoError(t, err, "failed to create auth request")
525-
526-
for _, opt := range opts {
527-
opt(r)
528-
}
529-
530-
rw := httptest.NewRecorder()
531-
f.handler.ServeHTTP(rw, r)
532-
resp := rw.Result()
533-
defer resp.Body.Close()
534-
535-
require.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode, "expected redirect")
536-
to := resp.Header.Get("Location")
537-
require.NotEmpty(t, to, "expected redirect location")
538-
539-
toURL, err := url.Parse(to)
540-
require.NoError(t, err, "failed to parse redirect location")
541-
542-
code := toURL.Query().Get("code")
543-
require.NotEmpty(t, code, "expected code in redirect location")
544-
545-
newState := toURL.Query().Get("state")
546-
require.Equal(t, state, newState, "expected state to match")
547-
522+
code, err := OAuth2GetCode(f.cfg.AuthCodeURL(state), state, func(req *http.Request) (*http.Response, error) {
523+
rw := httptest.NewRecorder()
524+
f.handler.ServeHTTP(rw, req)
525+
resp := rw.Result()
526+
return resp, nil
527+
})
528+
require.NoError(t, err, "failed to get auth code")
548529
return code
549530
}
550531

0 commit comments

Comments
 (0)
0