diff --git a/api/oi_config.go b/api/oi_config.go index 1fe4d28ec..acd082951 100644 --- a/api/oi_config.go +++ b/api/oi_config.go @@ -44,6 +44,7 @@ func GetOpenIDConfig(c *gin.Context) { "iat", "iss", "aud", + "branch", "build_number", "build_id", "repo", @@ -52,6 +53,8 @@ func GetOpenIDConfig(c *gin.Context) { "actor_scm_id", "commands", "image", + "image_name", + "image_tag", "request", "event", "sha", diff --git a/api/types/oidc.go b/api/types/oidc.go index 359178244..c6ba560e7 100644 --- a/api/types/oidc.go +++ b/api/types/oidc.go @@ -21,18 +21,21 @@ type OpenIDConfig struct { // OpenIDClaims struct is an extension of the JWT standard claims. It // includes information relevant to OIDC services. type OpenIDClaims struct { - BuildNumber int `json:"build_number,omitempty"` - BuildID int64 `json:"build_id,omitempty"` Actor string `json:"actor,omitempty"` ActorSCMID string `json:"actor_scm_id,omitempty"` - Repo string `json:"repo,omitempty"` - TokenType string `json:"token_type,omitempty"` - Image string `json:"image,omitempty"` - Request string `json:"request,omitempty"` + Branch string `json:"branch,omitempty"` + BuildID int64 `json:"build_id,omitempty"` + BuildNumber int `json:"build_number,omitempty"` Commands bool `json:"commands,omitempty"` Event string `json:"event,omitempty"` + Image string `json:"image,omitempty"` + ImageName string `json:"image_name,omitempty"` + ImageTag string `json:"image_tag,omitempty"` Ref string `json:"ref,omitempty"` + Repo string `json:"repo,omitempty"` + Request string `json:"request,omitempty"` SHA string `json:"sha,omitempty"` + TokenType string `json:"token_type,omitempty"` jwt.RegisteredClaims } diff --git a/internal/token/mint.go b/internal/token/mint.go index c86757b07..4ab6ed4f7 100644 --- a/internal/token/mint.go +++ b/internal/token/mint.go @@ -6,6 +6,7 @@ import ( "context" "errors" "fmt" + "strings" "time" "github.com/golang-jwt/jwt/v5" @@ -120,7 +121,7 @@ func (tm *Manager) MintToken(mto *MintTokenOpts) (string, error) { tk := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - //sign token with configured private signing key + // sign token with configured private signing key token, err := tk.SignedString([]byte(tm.PrivateKeyHMAC)) if err != nil { return "", fmt.Errorf("unable to sign token: %w", err) @@ -134,6 +135,8 @@ func (tm *Manager) MintIDToken(ctx context.Context, mto *MintTokenOpts, db datab // initialize claims struct var claims = new(api.OpenIDClaims) + var err error + // validate provided claims if len(mto.Repo) == 0 { return "", errors.New("missing repo for ID token") @@ -154,6 +157,7 @@ func (tm *Manager) MintIDToken(ctx context.Context, mto *MintTokenOpts, db datab // set claims based on input claims.Actor = mto.Build.GetSender() claims.ActorSCMID = mto.Build.GetSenderSCMID() + claims.Branch = mto.Build.GetBranch() claims.BuildNumber = mto.Build.GetNumber() claims.BuildID = mto.Build.GetID() claims.Repo = mto.Repo @@ -164,6 +168,12 @@ func (tm *Manager) MintIDToken(ctx context.Context, mto *MintTokenOpts, db datab claims.Audience = mto.Audience claims.TokenType = mto.TokenType claims.Image = mto.Image + + claims.ImageName, claims.ImageTag, err = imageParse(mto.Image) + if err != nil { + return "", err + } + claims.Request = mto.Request claims.Commands = mto.Commands @@ -175,7 +185,7 @@ func (tm *Manager) MintIDToken(ctx context.Context, mto *MintTokenOpts, db datab tk := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) // verify key is active in the database before signing - _, err := db.GetActiveJWK(ctx, tm.RSAKeySet.KID) + _, err = db.GetActiveJWK(ctx, tm.RSAKeySet.KID) if err != nil { if !errors.Is(err, gorm.ErrRecordNotFound) { return "", fmt.Errorf("unable to get active public key: %w", err) @@ -191,7 +201,7 @@ func (tm *Manager) MintIDToken(ctx context.Context, mto *MintTokenOpts, db datab // set KID header tk.Header["kid"] = tm.RSAKeySet.KID - //sign token with configured private signing key + // sign token with configured private signing key token, err := tk.SignedString(tm.RSAKeySet.PrivateKey) if err != nil { return "", fmt.Errorf("unable to sign token: %w", err) @@ -201,3 +211,19 @@ func (tm *Manager) MintIDToken(ctx context.Context, mto *MintTokenOpts, db datab return token, nil } + +// imageParse parses the given image string and returns the image name and tag. +// If no tag is provided in the image string, "latest" is used as the tag. +// If the image string is invalid, an error is returned. +func imageParse(image string) (string, string, error) { + parts := strings.Split(image, ":") + + switch len(parts) { + case 1: + return image, "latest", nil + case 2: + return parts[0], parts[1], nil + default: + return "", "", fmt.Errorf("invalid image format: %s", image) + } +} diff --git a/internal/token/mint_test.go b/internal/token/mint_test.go new file mode 100644 index 000000000..7ec01bc34 --- /dev/null +++ b/internal/token/mint_test.go @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: Apache-2.0 + +package token + +import "testing" + +func Test_imageParse(t *testing.T) { + type args struct { + image string + } + tests := []struct { + name string + args args + wantName string + wantTag string + wantErr bool + }{ + { + name: "image with tag", + args: args{ + image: "alpine:1.20", + }, + wantName: "alpine", + wantTag: "1.20", + wantErr: false, + }, + { + name: "image without latest tag", + args: args{ + image: "alpine:latest", + }, + wantName: "alpine", + wantTag: "latest", + wantErr: false, + }, + { + name: "image without tag", + args: args{ + image: "alpine", + }, + wantName: "alpine", + wantTag: "latest", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, got1, err := imageParse(tt.args.image) + if (err != nil) != tt.wantErr { + t.Errorf("imageParse() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.wantName { + t.Errorf("imageParse() got = %v, wantName %v", got, tt.wantName) + } + if got1 != tt.wantTag { + t.Errorf("imageParse() got1 = %v, wantName %v", got1, tt.wantTag) + } + }) + } +} diff --git a/mock/server/authentication.go b/mock/server/authentication.go index b1903eeb9..1d8ed2147 100644 --- a/mock/server/authentication.go +++ b/mock/server/authentication.go @@ -32,6 +32,7 @@ const ( "iat", "iss", "aud", + "branch", "build_number", "build_id", "repo", @@ -40,6 +41,8 @@ const ( "actor_scm_id", "commands", "image", + "image_name", + "image_tag", "request" ], "id_token_signing_alg_values_supported": [