From cb4144edda6d64cd0f3defdadfdbec57de28c27e Mon Sep 17 00:00:00 2001 From: mo khan Date: Mon, 21 Apr 2025 12:17:58 -0600 Subject: refactor: rename middleware --- pkg/web/middleware/enforce_authn.go | 1 - pkg/web/middleware/enforce_authn_test.go | 11 ---- pkg/web/middleware/id_token.go | 56 +++++++++++++++++ pkg/web/middleware/id_token_test.go | 101 +++++++++++++++++++++++++++++++ pkg/web/middleware/unpack_token.go | 56 ----------------- pkg/web/middleware/unpack_token_test.go | 101 ------------------------------- 6 files changed, 157 insertions(+), 169 deletions(-) delete mode 100644 pkg/web/middleware/enforce_authn.go delete mode 100644 pkg/web/middleware/enforce_authn_test.go create mode 100644 pkg/web/middleware/id_token.go create mode 100644 pkg/web/middleware/id_token_test.go delete mode 100644 pkg/web/middleware/unpack_token.go delete mode 100644 pkg/web/middleware/unpack_token_test.go (limited to 'pkg/web') diff --git a/pkg/web/middleware/enforce_authn.go b/pkg/web/middleware/enforce_authn.go deleted file mode 100644 index c870d7c..0000000 --- a/pkg/web/middleware/enforce_authn.go +++ /dev/null @@ -1 +0,0 @@ -package middleware diff --git a/pkg/web/middleware/enforce_authn_test.go b/pkg/web/middleware/enforce_authn_test.go deleted file mode 100644 index 285db5b..0000000 --- a/pkg/web/middleware/enforce_authn_test.go +++ /dev/null @@ -1,11 +0,0 @@ -package middleware - -import "testing" - -func TestEnforceAuthn(t *testing.T) { - t.Run("when an active session cookie is provided", func(t *testing.T) { - t.Run("attaches a user to the request context", func(t *testing.T) { - - }) - }) -} diff --git a/pkg/web/middleware/id_token.go b/pkg/web/middleware/id_token.go new file mode 100644 index 0000000..a32c77b --- /dev/null +++ b/pkg/web/middleware/id_token.go @@ -0,0 +1,56 @@ +package middleware + +import ( + "net/http" + + "github.com/xlgmokha/x/pkg/log" + "github.com/xlgmokha/x/pkg/x" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/key" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/oidc" +) + +type TokenParser func(*http.Request) oidc.RawToken + +func IDTokenFromSessionCookie(r *http.Request) oidc.RawToken { + cookies := r.CookiesNamed("session") + + if len(cookies) != 1 { + return "" + } + + tokens, err := oidc.TokensFromBase64String(cookies[0].Value) + if err != nil { + log.WithFields(r.Context(), log.Fields{"error": err}) + return "" + } + + return tokens.IDToken +} + +func IDToken(cfg *oidc.OpenID) func(http.Handler) http.Handler { + parsers := []TokenParser{IDTokenFromSessionCookie} + + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + for _, parser := range parsers { + rawIDToken := parser(r) + if !x.IsZero(rawIDToken) { + verifier := cfg.Provider.VerifierContext(r.Context(), cfg.OIDCConfig) + idToken, err := verifier.Verify(r.Context(), rawIDToken.String()) + if err != nil { + log.WithFields(r.Context(), log.Fields{"error": err}) + } else { + log.WithFields(r.Context(), log.Fields{"id_token": idToken}) + next.ServeHTTP( + w, + r.WithContext(key.IDToken.With(r.Context(), idToken)), + ) + return + } + } + } + + next.ServeHTTP(w, r) + }) + } +} diff --git a/pkg/web/middleware/id_token_test.go b/pkg/web/middleware/id_token_test.go new file mode 100644 index 0000000..4f26cdf --- /dev/null +++ b/pkg/web/middleware/id_token_test.go @@ -0,0 +1,101 @@ +package middleware + +import ( + "context" + "net/http" + "os" + "testing" + "time" + + "github.com/oauth2-proxy/mockoidc" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/xlgmokha/x/pkg/log" + "github.com/xlgmokha/x/pkg/x" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/key" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/oidc" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/test" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/web" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/web/cookie" + "golang.org/x/oauth2" +) + +func TestIDToken(t *testing.T) { + srv := test.NewOIDCServer(t) + defer srv.Close() + + client := &http.Client{Transport: &web.Transport{Logger: log.New(os.Stdout, log.Fields{})}} + cfg := srv.MockOIDC.Config() + ctx := context.WithValue(t.Context(), oauth2.HTTPClient, client) + openID, err := oidc.New( + ctx, + srv.Issuer(), + cfg.ClientID, + cfg.ClientSecret, + "https://example.com/oauth/callback", + ) + require.NoError(t, err) + + middleware := IDToken(openID) + + t.Run("when an active session cookie is provided", func(t *testing.T) { + t.Run("attaches the token to the request context", func(t *testing.T) { + user := mockoidc.DefaultUser() + + token, rawIDToken := srv.CreateTokensFor(user) + tokens := &oidc.Tokens{Token: token, IDToken: oidc.RawToken(rawIDToken)} + encoded := x.Must(tokens.ToBase64String()) + + server := middleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + token := key.IDToken.From(r.Context()) + require.NotNil(t, token) + assert.Equal(t, user.Subject, token.Subject) + + w.WriteHeader(http.StatusTeapot) + })) + + r, w := test.RequestResponse( + "GET", + "/example", + test.WithCookie(cookie.New("session", encoded, time.Now().Add(1*time.Hour))), + ) + server.ServeHTTP(w, r) + + assert.Equal(t, http.StatusTeapot, w.Code) + }) + }) + + t.Run("when an invalid session cookie is provided", func(t *testing.T) { + t.Run("forwards the request", func(t *testing.T) { + server := middleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Nil(t, key.IDToken.From(r.Context())) + + w.WriteHeader(http.StatusTeapot) + })) + + r, w := test.RequestResponse( + "GET", + "/example", + test.WithCookie(cookie.New("session", "invalid", time.Now().Add(1*time.Hour))), + ) + server.ServeHTTP(w, r) + + assert.Equal(t, http.StatusTeapot, w.Code) + }) + }) + + t.Run("when no cookies are provided", func(t *testing.T) { + t.Run("forwards the request", func(t *testing.T) { + server := middleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Nil(t, key.IDToken.From(r.Context())) + + w.WriteHeader(http.StatusTeapot) + })) + + r, w := test.RequestResponse("GET", "/example") + server.ServeHTTP(w, r) + + assert.Equal(t, http.StatusTeapot, w.Code) + }) + }) +} diff --git a/pkg/web/middleware/unpack_token.go b/pkg/web/middleware/unpack_token.go deleted file mode 100644 index 0b182a0..0000000 --- a/pkg/web/middleware/unpack_token.go +++ /dev/null @@ -1,56 +0,0 @@ -package middleware - -import ( - "net/http" - - "github.com/xlgmokha/x/pkg/log" - "github.com/xlgmokha/x/pkg/x" - "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/key" - "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/oidc" -) - -type TokenParser func(*http.Request) oidc.RawIDToken - -func FromSessionCookie(r *http.Request) oidc.RawIDToken { - cookies := r.CookiesNamed("session") - - if len(cookies) != 1 { - return "" - } - - tokens, err := oidc.TokensFromBase64String(cookies[0].Value) - if err != nil { - log.WithFields(r.Context(), log.Fields{"error": err}) - return "" - } - - return tokens.IDToken -} - -func UnpackToken(cfg *oidc.OpenID) func(http.Handler) http.Handler { - parsers := []TokenParser{FromSessionCookie} - - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - for _, parser := range parsers { - rawIDToken := parser(r) - if !x.IsZero(rawIDToken) { - verifier := cfg.Provider.VerifierContext(r.Context(), cfg.OIDCConfig) - idToken, err := verifier.Verify(r.Context(), rawIDToken.String()) - if err != nil { - log.WithFields(r.Context(), log.Fields{"error": err}) - } else { - log.WithFields(r.Context(), log.Fields{"id_token": idToken}) - next.ServeHTTP( - w, - r.WithContext(key.IDToken.With(r.Context(), idToken)), - ) - return - } - } - } - - next.ServeHTTP(w, r) - }) - } -} diff --git a/pkg/web/middleware/unpack_token_test.go b/pkg/web/middleware/unpack_token_test.go deleted file mode 100644 index 116e88f..0000000 --- a/pkg/web/middleware/unpack_token_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package middleware - -import ( - "context" - "net/http" - "os" - "testing" - "time" - - "github.com/oauth2-proxy/mockoidc" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/xlgmokha/x/pkg/log" - "github.com/xlgmokha/x/pkg/x" - "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/key" - "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/oidc" - "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/test" - "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/web" - "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/web/cookie" - "golang.org/x/oauth2" -) - -func TestUnpackToken(t *testing.T) { - srv := test.NewOIDCServer(t) - defer srv.Close() - - client := &http.Client{Transport: &web.Transport{Logger: log.New(os.Stdout, log.Fields{})}} - cfg := srv.MockOIDC.Config() - ctx := context.WithValue(t.Context(), oauth2.HTTPClient, client) - openID, err := oidc.New( - ctx, - srv.Issuer(), - cfg.ClientID, - cfg.ClientSecret, - "https://example.com/oauth/callback", - ) - require.NoError(t, err) - - middleware := UnpackToken(openID) - - t.Run("when an active session cookie is provided", func(t *testing.T) { - t.Run("attaches the token to the request context", func(t *testing.T) { - user := mockoidc.DefaultUser() - - token, rawIDToken := srv.CreateTokensFor(user) - tokens := &oidc.Tokens{Token: token, IDToken: oidc.RawIDToken(rawIDToken)} - encoded := x.Must(tokens.ToBase64String()) - - server := middleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - token := key.IDToken.From(r.Context()) - require.NotNil(t, token) - assert.Equal(t, user.Subject, token.Subject) - - w.WriteHeader(http.StatusTeapot) - })) - - r, w := test.RequestResponse( - "GET", - "/example", - test.WithCookie(cookie.New("session", encoded, time.Now().Add(1*time.Hour))), - ) - server.ServeHTTP(w, r) - - assert.Equal(t, http.StatusTeapot, w.Code) - }) - }) - - t.Run("when an invalid session cookie is provided", func(t *testing.T) { - t.Run("forwards the request", func(t *testing.T) { - server := middleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - require.Nil(t, key.IDToken.From(r.Context())) - - w.WriteHeader(http.StatusTeapot) - })) - - r, w := test.RequestResponse( - "GET", - "/example", - test.WithCookie(cookie.New("session", "invalid", time.Now().Add(1*time.Hour))), - ) - server.ServeHTTP(w, r) - - assert.Equal(t, http.StatusTeapot, w.Code) - }) - }) - - t.Run("when no cookies are provided", func(t *testing.T) { - t.Run("forwards the request", func(t *testing.T) { - server := middleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - require.Nil(t, key.IDToken.From(r.Context())) - - w.WriteHeader(http.StatusTeapot) - })) - - r, w := test.RequestResponse("GET", "/example") - server.ServeHTTP(w, r) - - assert.Equal(t, http.StatusTeapot, w.Code) - }) - }) -} -- cgit v1.2.3