summaryrefslogtreecommitdiff
path: root/app/controllers/sessions
diff options
context:
space:
mode:
Diffstat (limited to 'app/controllers/sessions')
-rw-r--r--app/controllers/sessions/controller.go32
-rw-r--r--app/controllers/sessions/controller_test.go100
2 files changed, 91 insertions, 41 deletions
diff --git a/app/controllers/sessions/controller.go b/app/controllers/sessions/controller.go
index a4ba092..70d5631 100644
--- a/app/controllers/sessions/controller.go
+++ b/app/controllers/sessions/controller.go
@@ -1,10 +1,10 @@
package sessions
import (
- "fmt"
+ "encoding/base64"
+ "encoding/json"
"net/http"
- "github.com/xlgmokha/x/pkg/serde"
"gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/oidc"
"golang.org/x/oauth2"
)
@@ -31,25 +31,23 @@ func (c *Controller) New(w http.ResponseWriter, r *http.Request) {
func (c *Controller) Create(w http.ResponseWriter, r *http.Request) {
token, err := c.cfg.Config.Exchange(r.Context(), r.URL.Query().Get("code"))
if err != nil {
- fmt.Printf("%v\n", err)
+ return
}
- err = serde.ToJSON(w, token)
- if err != nil {
- fmt.Printf("%v\n", err)
- return
+ tokens := map[string]interface{}{
+ "access_token": token.AccessToken,
+ "token_type": token.TokenType,
+ "refresh_token": token.RefreshToken,
+ "expiry": token.Expiry,
+ "expires_in": token.ExpiresIn,
}
if rawIDToken, ok := token.Extra("id_token").(string); ok {
- idToken, err := oidc.NewIDToken(rawIDToken)
- if err != nil {
- fmt.Printf("%v\n", err)
- return
- }
- err = serde.ToJSON(w, idToken)
- if err != nil {
- fmt.Printf("%v\n", err)
- return
- }
+ tokens["id_token"] = rawIDToken
}
+
+ data, err := json.Marshal(tokens)
+ encoded := base64.URLEncoding.EncodeToString(data)
+ http.SetCookie(w, &http.Cookie{Name: "session", Value: encoded})
+ http.Redirect(w, r, "/dashboard", http.StatusFound)
}
diff --git a/app/controllers/sessions/controller_test.go b/app/controllers/sessions/controller_test.go
index d90896e..1c4637d 100644
--- a/app/controllers/sessions/controller_test.go
+++ b/app/controllers/sessions/controller_test.go
@@ -1,6 +1,8 @@
package sessions
import (
+ "encoding/base64"
+ "encoding/json"
"net/http"
"net/http/httptest"
"net/url"
@@ -10,6 +12,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/xlgmokha/x/pkg/serde"
+ "github.com/xlgmokha/x/pkg/x"
"gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/oidc"
"gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/test"
)
@@ -18,27 +21,47 @@ func TestSessions(t *testing.T) {
srv := httptest.NewServer(nil)
srv.Config = &http.Server{
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- require.Equal(t, "/.well-known/openid-configuration", r.URL.Path)
- require.NoError(t, serde.ToJSON(w, &oidc.Metadata{
- AuthorizationEndpoint: srv.URL + "/oauth/authorize",
- ClaimsSupported: []string{"aud"},
- CodeChallengeMethodsSupported: []string{"plain"},
- DeviceAuthorizationEndpoint: srv.URL + "/device/authorize",
- IDTokenSigningAlgValuesSupported: []string{"RS256"},
- Issuer: srv.URL,
- JWKSURI: srv.URL + "/jwks",
- MFAChallengeEndpoint: srv.URL + "/mfa",
- RegistrationEndpoint: srv.URL + "/users/new",
- RequestURIParameterSupported: false,
- ResponseModesSupported: []string{"query"},
- ResponseTypeSupported: []string{"code"},
- RevocationEndpoint: srv.URL + "/revoke",
- ScopesSupported: []string{"oidc"},
- SubjectTypesSupported: []string{"public"},
- TokenEndpoint: srv.URL + "/token",
- TokenEndpointAuthMethodsSupported: []string{"client_secret_post"},
- UserInfoEndpoint: srv.URL + "/users/me",
- }))
+ switch r.URL.Path {
+ case "/.well-known/openid-configuration":
+ require.NoError(t, serde.ToJSON(w, &oidc.Metadata{
+ AuthorizationEndpoint: srv.URL + "/oauth/authorize",
+ ClaimsSupported: []string{"aud"},
+ CodeChallengeMethodsSupported: []string{"plain"},
+ DeviceAuthorizationEndpoint: srv.URL + "/device/authorize",
+ IDTokenSigningAlgValuesSupported: []string{"RS256"},
+ Issuer: srv.URL,
+ JWKSURI: srv.URL + "/jwks",
+ MFAChallengeEndpoint: srv.URL + "/mfa",
+ RegistrationEndpoint: srv.URL + "/users/new",
+ RequestURIParameterSupported: false,
+ ResponseModesSupported: []string{"query"},
+ ResponseTypeSupported: []string{"code"},
+ RevocationEndpoint: srv.URL + "/revoke",
+ ScopesSupported: []string{"oidc"},
+ SubjectTypesSupported: []string{"public"},
+ TokenEndpoint: srv.URL + "/token",
+ TokenEndpointAuthMethodsSupported: []string{"client_secret_post"},
+ UserInfoEndpoint: srv.URL + "/users/me",
+ }))
+ case "/token":
+ if err := r.ParseForm(); err != nil {
+ w.WriteHeader(http.StatusBadRequest)
+ return
+ }
+ if r.Form["grant_type"][0] == "authorization_code" && r.Form["code"][0] == "code" {
+ w.Header().Add("Content-Type", "application/json")
+ require.NoError(t, serde.ToJSON(w, map[string]string{
+ "access_token": "14fa6e71afaabbe5e31ef2b47ccab7ca7a3c26f8dfdb74acce3eca30099af028",
+ "token_type": "Bearer",
+ "refresh_token": "365b261d4b25ba37e7c1e14e6501902aeecfb7fffc4602c44d6ac22b4c715b0f",
+ "expiry": "2025-04-15T12:30:50.498991929-06:00",
+ "id_token": "eyJ0eXAiOiJKV1QiLCJraWQiOiJ0ZDBTbWRKUTRxUGg1cU5Lek0yNjBDWHgyVWgtd2hHLU1Eam9PS1dmdDhFIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwOi8vZ2RrLnRlc3Q6MzAwMCIsInN1YiI6IjEiLCJhdWQiOiJlMzFlMWRhMGI4ZjZiNmUzNWNhNzBjNzkwYjEzYzA0MDZlNDRhY2E2YjJiZjY3ZjU1ZGU3MzU1YTk3OWEyMjRmIiwiZXhwIjoxNzQ0NzM3NDI3LCJpYXQiOjE3NDQ3MzczMDcsImF1dGhfdGltZSI6MTc0NDczNDY0OSwic3ViX2xlZ2FjeSI6IjI0NzRjZjBiMjIxMTY4OGE1NzI5N2FjZTBlMjYwYTE1OTQ0NzU0ZDE2YjFiZDQyYzlkNjc3OWM5MDAzNjc4MDciLCJuYW1lIjoiQWRtaW5pc3RyYXRvciIsIm5pY2tuYW1lIjoicm9vdCIsInByZWZlcnJlZF91c2VybmFtZSI6InJvb3QiLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsInByb2ZpbGUiOiJodHRwOi8vZ2RrLnRlc3Q6MzAwMC9yb290IiwicGljdHVyZSI6Imh0dHBzOi8vd3d3LmdyYXZhdGFyLmNvbS9hdmF0YXIvMjU4ZDhkYzkxNmRiOGNlYTJjYWZiNmMzY2QwY2IwMjQ2ZWZlMDYxNDIxZGJkODNlYzNhMzUwNDI4Y2FiZGE0Zj9zPTgwJmQ9aWRlbnRpY29uIiwiZ3JvdXBzX2RpcmVjdCI6WyJ0b29sYm94IiwiZ2l0bGFiLW9yZyIsImdudXdnZXQiLCJDb21taXQ0NTEiLCJqYXNoa2VuYXMiLCJmbGlnaHRqcyIsInR3aXR0ZXIiLCJnaXRsYWItZXhhbXBsZXMiLCJnaXRsYWItZXhhbXBsZXMvc2VjdXJpdHkiLCI0MTI3MDgiLCJnaXRsYWItZXhhbXBsZXMvZGVtby1ncm91cCIsImN1c3RvbS1yb2xlcy1yb290LWdyb3VwIiwiNDM0MDQ0LWdyb3VwLTEiLCI0MzQwNDQtZ3JvdXAtMiIsImdpdGxhYi1vcmcxIiwiZ2l0bGFiLW9yZy9zZWN1cmUiLCJnaXRsYWItb3JnL3NlY3VyZS9tYW5hZ2VycyIsImdpdGxhYi1vcmcvc2VjdXJpdHktcHJvZHVjdHMiLCJnaXRsYWItb3JnL3NlY3VyaXR5LXByb2R1Y3RzL2FuYWx5emVycyIsImN1c3RvbS1yb2xlcy1yb290LWdyb3VwL2FhIiwiY3VzdG9tLXJvbGVzLXJvb3QtZ3JvdXAvYWEvYWFhIiwibWFzc19pbnNlcnRfZ3JvdXBfXzBfMTAwIl19.SZu_l7tQ2Kkeogq0z8cRaDWPfv52JTo-RkiExbnud_lrfrXXneS77BIzaGKX_bzq4SM_oO_Q63AzK66B1r6Gp7ACo4DjOUEIWETg7ZBKcDzEZnresB7kmI_MJ5rfIJTmnH75GOfc_pl5l8T896TbaShN6zSpaXXIVEfhyUrflSWb4hhA7Hbwy2b6laXiaDv0qpcn1udPVYMTsll8I5ni_2yzuEPSVRgrcQoQ46OwVDZIi9tlfdT2qNVjH6FxJ3mkBcxtIVjf3_JYAawFEscg2uvQYwFWj9T6LleMknAh3QFJJMrS6mPqlXJGPUE5pTQgsBInfEikfm9PXxezA-IY6g",
+ }))
+ }
+ default:
+ t.Logf("404: %v", r.URL.Path)
+ w.WriteHeader(http.StatusNotFound)
+ }
}),
}
defer srv.Close()
@@ -81,9 +104,38 @@ func TestSessions(t *testing.T) {
t.Run("with an invalid csrf token", func(t *testing.T) {})
t.Run("with an invalid authorization code grant", func(t *testing.T) {})
t.Run("with a valid authorization code grant", func(t *testing.T) {
- t.Run("stores the id token in a session cookie", func(t *testing.T) {})
- t.Run("stores the access token in a session cookie", func(t *testing.T) {})
- t.Run("redirects to the homepage", func(t *testing.T) {})
+ r, w := test.RequestResponse("GET", "/session/callback?code=code")
+
+ mux.ServeHTTP(w, r)
+
+ cookies, err := http.ParseCookie(w.Header().Get("Set-Cookie"))
+ require.NoError(t, err)
+ cookie := x.Find(cookies, func(item *http.Cookie) bool {
+ return item.Name == "session"
+ })
+ require.NotZero(t, cookie)
+ data, err := base64.URLEncoding.DecodeString(cookie.Value)
+ require.NoError(t, err)
+ tokens := map[string]interface{}{}
+ require.NoError(t, json.Unmarshal(data, &tokens))
+
+ t.Run("stores the id token in a session cookie", func(t *testing.T) {
+ assert.Equal(t, "eyJ0eXAiOiJKV1QiLCJraWQiOiJ0ZDBTbWRKUTRxUGg1cU5Lek0yNjBDWHgyVWgtd2hHLU1Eam9PS1dmdDhFIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwOi8vZ2RrLnRlc3Q6MzAwMCIsInN1YiI6IjEiLCJhdWQiOiJlMzFlMWRhMGI4ZjZiNmUzNWNhNzBjNzkwYjEzYzA0MDZlNDRhY2E2YjJiZjY3ZjU1ZGU3MzU1YTk3OWEyMjRmIiwiZXhwIjoxNzQ0NzM3NDI3LCJpYXQiOjE3NDQ3MzczMDcsImF1dGhfdGltZSI6MTc0NDczNDY0OSwic3ViX2xlZ2FjeSI6IjI0NzRjZjBiMjIxMTY4OGE1NzI5N2FjZTBlMjYwYTE1OTQ0NzU0ZDE2YjFiZDQyYzlkNjc3OWM5MDAzNjc4MDciLCJuYW1lIjoiQWRtaW5pc3RyYXRvciIsIm5pY2tuYW1lIjoicm9vdCIsInByZWZlcnJlZF91c2VybmFtZSI6InJvb3QiLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsInByb2ZpbGUiOiJodHRwOi8vZ2RrLnRlc3Q6MzAwMC9yb290IiwicGljdHVyZSI6Imh0dHBzOi8vd3d3LmdyYXZhdGFyLmNvbS9hdmF0YXIvMjU4ZDhkYzkxNmRiOGNlYTJjYWZiNmMzY2QwY2IwMjQ2ZWZlMDYxNDIxZGJkODNlYzNhMzUwNDI4Y2FiZGE0Zj9zPTgwJmQ9aWRlbnRpY29uIiwiZ3JvdXBzX2RpcmVjdCI6WyJ0b29sYm94IiwiZ2l0bGFiLW9yZyIsImdudXdnZXQiLCJDb21taXQ0NTEiLCJqYXNoa2VuYXMiLCJmbGlnaHRqcyIsInR3aXR0ZXIiLCJnaXRsYWItZXhhbXBsZXMiLCJnaXRsYWItZXhhbXBsZXMvc2VjdXJpdHkiLCI0MTI3MDgiLCJnaXRsYWItZXhhbXBsZXMvZGVtby1ncm91cCIsImN1c3RvbS1yb2xlcy1yb290LWdyb3VwIiwiNDM0MDQ0LWdyb3VwLTEiLCI0MzQwNDQtZ3JvdXAtMiIsImdpdGxhYi1vcmcxIiwiZ2l0bGFiLW9yZy9zZWN1cmUiLCJnaXRsYWItb3JnL3NlY3VyZS9tYW5hZ2VycyIsImdpdGxhYi1vcmcvc2VjdXJpdHktcHJvZHVjdHMiLCJnaXRsYWItb3JnL3NlY3VyaXR5LXByb2R1Y3RzL2FuYWx5emVycyIsImN1c3RvbS1yb2xlcy1yb290LWdyb3VwL2FhIiwiY3VzdG9tLXJvbGVzLXJvb3QtZ3JvdXAvYWEvYWFhIiwibWFzc19pbnNlcnRfZ3JvdXBfXzBfMTAwIl19.SZu_l7tQ2Kkeogq0z8cRaDWPfv52JTo-RkiExbnud_lrfrXXneS77BIzaGKX_bzq4SM_oO_Q63AzK66B1r6Gp7ACo4DjOUEIWETg7ZBKcDzEZnresB7kmI_MJ5rfIJTmnH75GOfc_pl5l8T896TbaShN6zSpaXXIVEfhyUrflSWb4hhA7Hbwy2b6laXiaDv0qpcn1udPVYMTsll8I5ni_2yzuEPSVRgrcQoQ46OwVDZIi9tlfdT2qNVjH6FxJ3mkBcxtIVjf3_JYAawFEscg2uvQYwFWj9T6LleMknAh3QFJJMrS6mPqlXJGPUE5pTQgsBInfEikfm9PXxezA-IY6g", tokens["id_token"])
+ })
+
+ t.Run("stores the access token in a session cookie", func(t *testing.T) {
+ assert.Equal(t, "14fa6e71afaabbe5e31ef2b47ccab7ca7a3c26f8dfdb74acce3eca30099af028", tokens["access_token"])
+ assert.Equal(t, "Bearer", tokens["token_type"])
+ })
+
+ t.Run("stores the refresh token in a session cookie", func(t *testing.T) {
+ assert.Equal(t, "365b261d4b25ba37e7c1e14e6501902aeecfb7fffc4602c44d6ac22b4c715b0f", tokens["refresh_token"])
+ })
+
+ t.Run("redirects to the homepage", func(t *testing.T) {
+ require.Equal(t, http.StatusFound, w.Code)
+ assert.Equal(t, "/dashboard", w.Header().Get("Location"))
+ })
})
})
}