Skip to content

Commit

Permalink
enhance(oidc): add more claims
Browse files Browse the repository at this point in the history
  • Loading branch information
JordanSussman committed Aug 26, 2024
1 parent 0f28017 commit 170eae0
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 15 deletions.
3 changes: 3 additions & 0 deletions api/oi_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func GetOpenIDConfig(c *gin.Context) {
"iat",
"iss",
"aud",
"branch",
"build_number",
"build_id",
"repo",
Expand All @@ -54,6 +55,8 @@ func GetOpenIDConfig(c *gin.Context) {
"actor_scm_id",
"commands",
"image",
"image_name",
"image_tag",
"request",
"event",
"sha",
Expand Down
16 changes: 10 additions & 6 deletions api/types/oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,22 @@ 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"`
Fork bool `json:"fork,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
}

Expand Down
2 changes: 1 addition & 1 deletion internal/token/compose_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,6 @@ func TestToken_Compose(t *testing.T) {
}

if !strings.EqualFold(got, want) {
t.Errorf("Compose is %v, want %v", got, want)
t.Errorf("Compose is %v, wantName %v", got, want)
}
}
26 changes: 23 additions & 3 deletions internal/token/mint.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"context"
"errors"
"fmt"
"strings"
"time"

"github.com/golang-jwt/jwt/v5"
Expand Down Expand Up @@ -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)
Expand All @@ -133,6 +134,7 @@ func (tm *Manager) MintToken(mto *MintTokenOpts) (string, error) {
func (tm *Manager) MintIDToken(ctx context.Context, mto *MintTokenOpts, db database.Interface) (string, error) {
// initialize claims struct
var claims = new(api.OpenIDClaims)
var err error

Check failure on line 137 in internal/token/mint.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] internal/token/mint.go#L137

declarations should never be cuddled (wsl)
Raw output
internal/token/mint.go:137:2: declarations should never be cuddled (wsl)
	var err error
	^

// validate provided claims
if len(mto.Repo) == 0 {
Expand All @@ -154,6 +156,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
Expand All @@ -164,6 +167,7 @@ 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)

Check failure on line 170 in internal/token/mint.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] internal/token/mint.go#L170

ineffectual assignment to err (ineffassign)
Raw output
internal/token/mint.go:170:37: ineffectual assignment to err (ineffassign)
	claims.ImageName, claims.ImageTag, err = imageParse(mto.Image)
	                                   ^
claims.Request = mto.Request
claims.Commands = mto.Commands

Expand All @@ -175,7 +179,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)
Expand All @@ -191,7 +195,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)
Expand All @@ -201,3 +205,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)
}
}
59 changes: 59 additions & 0 deletions internal/token/mint_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package token

Check failure on line 1 in internal/token/mint_test.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] internal/token/mint_test.go#L1

Missed header for check (goheader)
Raw output
internal/token/mint_test.go:1: Missed header for check (goheader)

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)
}
})
}
}
10 changes: 5 additions & 5 deletions internal/token/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func TestTokenManager_ParseToken(t *testing.T) {
}

if !reflect.DeepEqual(got, tt.Want) {
t.Errorf("Parse is %v, want %v", got, tt.Want)
t.Errorf("Parse is %v, wantName %v", got, tt.Want)
}
})
}
Expand All @@ -138,7 +138,7 @@ func TestTokenManager_ParseToken_Error_NoParse(t *testing.T) {
}

if got != nil {
t.Errorf("Parse is %v, want nil", got)
t.Errorf("Parse is %v, wantName nil", got)
}
}

Expand Down Expand Up @@ -208,7 +208,7 @@ func TestTokenManager_ParseToken_NoSubject(t *testing.T) {
}

if got != nil {
t.Errorf("Parse is %v, want nil", got)
t.Errorf("Parse is %v, wantName nil", got)
}
}

Expand Down Expand Up @@ -248,7 +248,7 @@ func TestTokenManager_ParseToken_Error_InvalidSignature(t *testing.T) {
}

if got != nil {
t.Errorf("Parse is %v, want nil", got)
t.Errorf("Parse is %v, wantName nil", got)
}
}

Expand Down Expand Up @@ -285,6 +285,6 @@ func TestToken_Parse_AccessToken_NoExpiration(t *testing.T) {
}

if got != nil {
t.Errorf("Parse is %v, want nil", got)
t.Errorf("Parse is %v, wantName nil", got)
}
}
3 changes: 3 additions & 0 deletions mock/server/authentication.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const (
"iat",
"iss",
"aud",
"branch",
"build_number",
"build_id",
"repo",
Expand All @@ -40,6 +41,8 @@ const (
"actor_scm_id",
"commands",
"image",
"image_name",
"image_tag",
"request"
],
"id_token_signing_alg_values_supported": [
Expand Down

0 comments on commit 170eae0

Please sign in to comment.