diff options
| author | mo khan <mo@mokhan.ca> | 2025-04-28 16:23:19 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-04-28 16:23:19 -0600 |
| commit | 62fdf88cbdec6dbf248bea13611521667112f5e1 (patch) | |
| tree | 2632236a73a674aa86f8efe46f3553f8d81e5328 | |
| parent | 3b942be3d49830b80689a5c7b9f0fda4b3deb44b (diff) | |
feat: generate a nonce to validate the OAuth callback
| -rw-r--r-- | app/controllers/sessions/controller.go | 7 | ||||
| -rw-r--r-- | app/controllers/sessions/controller_test.go | 20 | ||||
| -rw-r--r-- | pkg/pls/nonce.go | 11 |
3 files changed, 31 insertions, 7 deletions
diff --git a/app/controllers/sessions/controller.go b/app/controllers/sessions/controller.go index 7e706e7..7549dc7 100644 --- a/app/controllers/sessions/controller.go +++ b/app/controllers/sessions/controller.go @@ -3,9 +3,11 @@ package sessions import ( "context" "net/http" + "time" "github.com/xlgmokha/x/pkg/log" "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/oidc" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/pls" "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/web/cookie" "golang.org/x/oauth2" ) @@ -29,8 +31,9 @@ func (c *Controller) MountTo(mux *http.ServeMux) { } func (c *Controller) New(w http.ResponseWriter, r *http.Request) { - // TODO:: Generate and store nonce and use as state param to compare as a CSRF token - url := c.cfg.Config.AuthCodeURL("todo-csrf-token", oauth2.SetAuthURLParam("audience", "todo")) + nonce := pls.GenerateNonce(32) + url := c.cfg.Config.AuthCodeURL(nonce, oauth2.SetAuthURLParam("audience", c.cfg.Config.ClientID)) + http.SetCookie(w, cookie.New("oauth_state", nonce, time.Now().Add(10*time.Minute))) http.Redirect(w, r, url, http.StatusFound) } diff --git a/app/controllers/sessions/controller_test.go b/app/controllers/sessions/controller_test.go index e325afc..64c9fc1 100644 --- a/app/controllers/sessions/controller_test.go +++ b/app/controllers/sessions/controller_test.go @@ -37,11 +37,11 @@ func TestSessions(t *testing.T) { t.Run("GET /session/new", func(t *testing.T) { t.Run("without an authenticated session", func(t *testing.T) { - t.Run("redirect to the OIDC Provider", func(t *testing.T) { - r, w := test.RequestResponse("GET", "/session/new") + r, w := test.RequestResponse("GET", "/session/new") - mux.ServeHTTP(w, r) + mux.ServeHTTP(w, r) + t.Run("redirect to the OIDC Provider", func(t *testing.T) { require.Equal(t, http.StatusFound, w.Code) require.NotEmpty(t, w.Header().Get("Location")) redirectURL, err := url.Parse(w.Header().Get("Location")) @@ -50,12 +50,22 @@ func TestSessions(t *testing.T) { assert.NotEmpty(t, redirectURL.Query().Get("state")) assert.Equal(t, srv.MockOIDC.Config().ClientID, redirectURL.Query().Get("client_id")) assert.Equal(t, "openid profile email", redirectURL.Query().Get("scope")) - assert.Equal(t, "todo", redirectURL.Query().Get("audience")) + assert.Equal(t, cfg.Config.ClientID, redirectURL.Query().Get("audience")) assert.Equal(t, cfg.Config.RedirectURL, redirectURL.Query().Get("redirect_uri")) assert.Equal(t, "code", redirectURL.Query().Get("response_type")) }) - t.Run("generates a CSRF token", func(t *testing.T) {}) + t.Run("generates a CSRF token", func(t *testing.T) { + cookieHeader := w.Header().Get("Set-Cookie") + require.NotEmpty(t, cookieHeader) + + cookies, err := http.ParseCookie(cookieHeader) + require.NoError(t, err) + cookie := x.Find(cookies, func(item *http.Cookie) bool { + return item.Name == "oauth_state" + }) + require.NotZero(t, cookie) + }) }) t.Run("with an active authenicated session", func(t *testing.T) {}) diff --git a/pkg/pls/nonce.go b/pkg/pls/nonce.go new file mode 100644 index 0000000..aeab640 --- /dev/null +++ b/pkg/pls/nonce.go @@ -0,0 +1,11 @@ +package pls + +import ( + "crypto/rand" +) + +func GenerateNonce(size int) string { + nonceBytes := make([]byte, size) + rand.Read(nonceBytes) + return string(nonceBytes) +} |
