summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-05-23 16:08:15 -0600
committermo khan <mo@mokhan.ca>2025-05-23 16:08:15 -0600
commit15b1699b0ad27c9fc3aa4498d4085b7338bec95a (patch)
treefd20c6e39a8340b6c7dd41b5dd5b7a8bcbfe706a /pkg
parent86ad4fe8bf4bfde9bbe31a63431a508f81032527 (diff)
feat: parse the body of the id token
Diffstat (limited to 'pkg')
-rw-r--r--pkg/authz/check_service.go28
-rw-r--r--pkg/authz/id_token.go40
-rw-r--r--pkg/authz/id_token_test.go30
-rw-r--r--pkg/authz/server_test.go13
4 files changed, 105 insertions, 6 deletions
diff --git a/pkg/authz/check_service.go b/pkg/authz/check_service.go
index ff4e92a..3c4426a 100644
--- a/pkg/authz/check_service.go
+++ b/pkg/authz/check_service.go
@@ -2,6 +2,7 @@ package authz
import (
"context"
+ "net/http"
"strings"
core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
@@ -9,6 +10,7 @@ import (
types "github.com/envoyproxy/go-control-plane/envoy/type/v3"
"github.com/xlgmokha/x/pkg/log"
"github.com/xlgmokha/x/pkg/x"
+ "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/pls"
status "google.golang.org/genproto/googleapis/rpc/status"
"google.golang.org/grpc/codes"
)
@@ -66,7 +68,31 @@ func (svc *CheckService) validRequest(ctx context.Context, r *auth.CheckRequest)
// TODO:: Replace this naive implementation
func (svc *CheckService) isLoggedIn(ctx context.Context, r *auth.CheckRequest) bool {
- return x.IsPresent(r.Attributes.Request.Http.Headers["cookie"])
+ rawCookie := r.Attributes.Request.Http.Headers["cookie"]
+ if x.IsPresent(rawCookie) {
+ cookies, err := http.ParseCookie(rawCookie)
+ if err != nil {
+ pls.LogError(ctx, err)
+ return false
+ }
+ idTokenCookie := x.Find(cookies, func(cookie *http.Cookie) bool {
+ return cookie.Name == "id_token"
+ })
+ if x.IsZero(idTokenCookie) {
+ return false
+ }
+ segments := strings.SplitN(idTokenCookie.Value, ".", 3)
+ if len(segments) != 3 {
+ return false
+ }
+ idToken, err := NewIDToken(idTokenCookie.Value)
+ if err != nil {
+ pls.LogError(ctx, err)
+ return false
+ }
+ return x.IsPresent(idToken)
+ }
+ return false
}
func (svc *CheckService) OK(ctx context.Context) *auth.CheckResponse {
diff --git a/pkg/authz/id_token.go b/pkg/authz/id_token.go
new file mode 100644
index 0000000..b647161
--- /dev/null
+++ b/pkg/authz/id_token.go
@@ -0,0 +1,40 @@
+package authz
+
+import (
+ "encoding/base64"
+ "encoding/json"
+ "errors"
+ "strings"
+ "time"
+)
+
+type IDToken struct {
+ Audience []string `json:"aud"`
+ Email string `json:"email"`
+ EmailVerified bool `json:"email_verified"`
+ ExpiredAt int64 `json:"exp"`
+ IssuedAt int64 `json:"iat"`
+ Issuer string `json:"iss"`
+ Name string `json:"name"`
+ Nickname string `json:"nickname"`
+ Picture string `json:"picture"`
+ Subject string `json:"sub"`
+ UpdatedAt time.Time `json:"updated_at"`
+}
+
+func NewIDToken(raw string) (*IDToken, error) {
+ sections := strings.SplitN(raw, ".", 3)
+ if len(sections) != 3 {
+ return nil, errors.New("Invalid token")
+ }
+ bytes, err := base64.RawURLEncoding.DecodeString(sections[1])
+ if err != nil {
+ return nil, err
+ }
+
+ token := &IDToken{}
+ if err := json.Unmarshal(bytes, token); err != nil {
+ return nil, err
+ }
+ return token, nil
+}
diff --git a/pkg/authz/id_token_test.go b/pkg/authz/id_token_test.go
new file mode 100644
index 0000000..22aabc4
--- /dev/null
+++ b/pkg/authz/id_token_test.go
@@ -0,0 +1,30 @@
+package authz
+
+import (
+ "testing"
+
+ "github.com/oauth2-proxy/mockoidc"
+ "github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/web"
+)
+
+func TestIDToken(t *testing.T) {
+ idp := web.NewOIDCServer(t)
+ defer idp.Close()
+
+ t.Run("when the token is valid", func(t *testing.T) {
+ user := mockoidc.DefaultUser()
+ _, rawIDToken := idp.CreateTokensFor(user)
+ token, err := NewIDToken(rawIDToken)
+
+ require.NoError(t, err)
+ require.NotNil(t, token)
+ })
+
+ t.Run("when the token is invalid", func(t *testing.T) {
+ token, err := NewIDToken("invalid")
+
+ require.Error(t, err)
+ require.Nil(t, token)
+ })
+}
diff --git a/pkg/authz/server_test.go b/pkg/authz/server_test.go
index c612146..e8f179e 100644
--- a/pkg/authz/server_test.go
+++ b/pkg/authz/server_test.go
@@ -47,13 +47,15 @@ func TestServer(t *testing.T) {
user := mockoidc.DefaultUser()
_, rawIDToken := idp.CreateTokensFor(user)
- cookies := []string{
- "bearer_token=" + pls.GenerateRandomHex(32) + ";",
- "id_token=" + rawIDToken + ";",
- "refresh_token=" + pls.GenerateRandomHex(32),
+ loggedInHeaders := map[string]string{
+ "cookie": strings.Join([]string{
+ "bearer_token=" + pls.GenerateRandomHex(32),
+ "id_token=" + rawIDToken,
+ "refresh_token=" + pls.GenerateRandomHex(32),
+ }, "; "),
}
- loggedInHeaders := map[string]string{"cookie": strings.Join(cookies, "; ")}
+ invalidHeaders := map[string]string{"cookie": strings.Join([]string{"id_token=invalid"}, "; ")}
t.Run("CheckRequest", func(t *testing.T) {
tt := []struct {
@@ -75,6 +77,7 @@ func TestServer(t *testing.T) {
{status: codes.OK, http: &HTTPRequest{Method: "POST", Path: "/sparkles", Headers: loggedInHeaders}},
{status: codes.OK, http: &HTTPRequest{Method: "POST", Path: "/sparkles/restore"}},
{status: codes.PermissionDenied, http: &HTTPRequest{Method: "GET", Path: "/dashboard"}},
+ {status: codes.PermissionDenied, http: &HTTPRequest{Method: "GET", Path: "/dashboard", Headers: invalidHeaders}},
{status: codes.PermissionDenied, http: &HTTPRequest{Method: "POST", Path: "/sparkles"}},
}