From bb392314d835b5dacb705cc0a3e6e8f20e92fc13 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Mar 2023 13:02:07 +0000 Subject: [PATCH 01/21] chore(deps): bump google.golang.org/protobuf from 1.29.0 to 1.29.1 Bumps [google.golang.org/protobuf](https://github.com/protocolbuffers/protobuf-go) from 1.29.0 to 1.29.1. - [Release notes](https://github.com/protocolbuffers/protobuf-go/releases) - [Changelog](https://github.com/protocolbuffers/protobuf-go/blob/master/release.bash) - [Commits](https://github.com/protocolbuffers/protobuf-go/compare/v1.29.0...v1.29.1) --- updated-dependencies: - dependency-name: google.golang.org/protobuf dependency-type: indirect ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 15 ++------------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index 7594264..adb638e 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( golang.org/x/net v0.8.0 // indirect golang.org/x/sys v0.6.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.29.0 // indirect + google.golang.org/protobuf v1.29.1 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index e4e5c6c..4259674 100644 --- a/go.sum +++ b/go.sum @@ -34,8 +34,6 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/muhlemmer/gu v0.3.1 h1:7EAqmFrW7n3hETvuAdmFmn4hS8W+z3LgKtrnow+YzNM= github.com/muhlemmer/gu v0.3.1/go.mod h1:YHtHR+gxM+bKEIIs7Hmi9sPT3ZDUvTN/i88wQpZkrdM= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo= @@ -50,9 +48,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -84,12 +79,6 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -104,8 +93,8 @@ google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6 google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.29.0 h1:44S3JjaKmLEE4YIkjzexaP+NzZsudE3Zin5Njn/pYX0= -google.golang.org/protobuf v1.29.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.29.1 h1:7QBf+IK2gx70Ap/hDsOmam3GE0v9HicjfEdAxE62UoM= +google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= From 890a7f3ed4cf4e258159dbe500cd8be82c56afba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20M=C3=B6hlmann?= Date: Mon, 20 Mar 2023 11:06:32 +0200 Subject: [PATCH 02/21] feat: GetUserinfo helper method for IDTokenClaims (#337) --- pkg/oidc/token.go | 11 +++++++++++ pkg/oidc/token_test.go | 13 +++++++++++++ 2 files changed, 24 insertions(+) diff --git a/pkg/oidc/token.go b/pkg/oidc/token.go index b017023..127db97 100644 --- a/pkg/oidc/token.go +++ b/pkg/oidc/token.go @@ -159,6 +159,17 @@ func (t *IDTokenClaims) SetUserInfo(i *UserInfo) { t.Address = i.Address } +func (t *IDTokenClaims) GetUserInfo() *UserInfo { + return &UserInfo{ + Subject: t.Subject, + UserInfoProfile: t.UserInfoProfile, + UserInfoEmail: t.UserInfoEmail, + UserInfoPhone: t.UserInfoPhone, + Address: t.Address, + Claims: t.Claims, + } +} + func NewIDTokenClaims(issuer, subject string, audience []string, expiration, authTime time.Time, nonce string, acr string, amr []string, clientID string, skew time.Duration) *IDTokenClaims { audience = AppendClientIDToAudience(clientID, audience) return &IDTokenClaims{ diff --git a/pkg/oidc/token_test.go b/pkg/oidc/token_test.go index 0d9874e..8dcfc7e 100644 --- a/pkg/oidc/token_test.go +++ b/pkg/oidc/token_test.go @@ -225,3 +225,16 @@ func TestNewIDTokenClaims(t *testing.T) { assert.Equal(t, want, got) } + +func TestIDTokenClaims_GetUserInfo(t *testing.T) { + want := &UserInfo{ + Subject: idTokenData.Subject, + UserInfoProfile: idTokenData.UserInfoProfile, + UserInfoEmail: idTokenData.UserInfoEmail, + UserInfoPhone: idTokenData.UserInfoPhone, + Address: idTokenData.Address, + Claims: idTokenData.Claims, + } + got := idTokenData.GetUserInfo() + assert.Equal(t, want, got) +} From 115813ee38b74322d6a974163ff2e93a56aaa686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20M=C3=B6hlmann?= Date: Mon, 20 Mar 2023 14:56:06 +0200 Subject: [PATCH 03/21] fix: handle the zero cases for oidc.Time --- pkg/oidc/types.go | 6 +++++ pkg/oidc/types_test.go | 51 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/pkg/oidc/types.go b/pkg/oidc/types.go index cb513a0..167f8b7 100644 --- a/pkg/oidc/types.go +++ b/pkg/oidc/types.go @@ -173,10 +173,16 @@ func NewEncoder() *schema.Encoder { type Time int64 func (ts Time) AsTime() time.Time { + if ts == 0 { + return time.Time{} + } return time.Unix(int64(ts), 0) } func FromTime(tt time.Time) Time { + if tt.IsZero() { + return 0 + } return Time(tt.Unix()) } diff --git a/pkg/oidc/types_test.go b/pkg/oidc/types_test.go index 2721e0b..64f07f1 100644 --- a/pkg/oidc/types_test.go +++ b/pkg/oidc/types_test.go @@ -7,6 +7,7 @@ import ( "strconv" "strings" "testing" + "time" "github.com/gorilla/schema" "github.com/stretchr/testify/assert" @@ -467,6 +468,56 @@ func TestNewEncoder(t *testing.T) { assert.Equal(t, a, b) } +func TestTime_AsTime(t *testing.T) { + tests := []struct { + name string + ts Time + want time.Time + }{ + { + name: "unset", + ts: 0, + want: time.Time{}, + }, + { + name: "set", + ts: 1, + want: time.Unix(1, 0), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.ts.AsTime() + assert.Equal(t, tt.want, got) + }) + } +} + +func TestTime_FromTime(t *testing.T) { + tests := []struct { + name string + tt time.Time + want Time + }{ + { + name: "zero", + tt: time.Time{}, + want: 0, + }, + { + name: "set", + tt: time.Unix(1, 0), + want: 1, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := FromTime(tt.tt) + assert.Equal(t, tt.want, got) + }) + } +} + func TestTime_UnmarshalJSON(t *testing.T) { type dst struct { UpdatedAt Time `json:"updated_at"` From 3c1e81e6a673a41ee32d11314064ffde6d2c532b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 19:59:14 +0000 Subject: [PATCH 04/21] chore(deps): bump actions/setup-go from 3 to 4 Bumps [actions/setup-go](https://github.com/actions/setup-go) from 3 to 4. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-go dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2abef36..78c0f79 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Setup go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: ${{ matrix.go }} - run: go test -race -v -coverprofile=profile.cov -coverpkg=./pkg/... ./pkg/... From a08ce5009112da5ee4c8db01dcd51a871c0b934e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20M=C3=B6hlmann?= Date: Tue, 21 Mar 2023 11:43:38 +0200 Subject: [PATCH 05/21] fix: correct returned field for JWTTokenRequest JWTTokenRequest.GetIssuedAt() was returning the ExpiresAt field. This change corrects that by returning IssuedAt instead. This bug was introduced in #283 --- pkg/oidc/token_request.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/oidc/token_request.go b/pkg/oidc/token_request.go index e63e0e5..6b6945a 100644 --- a/pkg/oidc/token_request.go +++ b/pkg/oidc/token_request.go @@ -192,7 +192,7 @@ func (j *JWTTokenRequest) GetExpiration() time.Time { // GetIssuedAt implements the Claims interface func (j *JWTTokenRequest) GetIssuedAt() time.Time { - return j.ExpiresAt.AsTime() + return j.IssuedAt.AsTime() } // GetNonce implements the Claims interface From c9555c7f1bb238b4ea48f5cbfa2332c5ef517d08 Mon Sep 17 00:00:00 2001 From: David Sharnoff Date: Fri, 24 Mar 2023 09:55:41 -0700 Subject: [PATCH 06/21] feat: add CanSetUserinfoFromRequest interface (#347) --- example/server/storage/storage.go | 13 ++++++++++--- example/server/storage/storage_dynamic.go | 15 +++++++++++++-- pkg/op/storage.go | 9 +++++++++ pkg/op/token.go | 6 ++++++ 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/example/server/storage/storage.go b/example/server/storage/storage.go index 7e1afbd..acac571 100644 --- a/example/server/storage/storage.go +++ b/example/server/storage/storage.go @@ -438,10 +438,17 @@ func (s *Storage) AuthorizeClientIDSecret(ctx context.Context, clientID, clientS return nil } -// SetUserinfoFromScopes implements the op.Storage interface -// it will be called for the creation of an id_token, so we'll just pass it to the private function without any further check +// SetUserinfoFromScopes implements the op.Storage interface. +// Provide an empty implementation and use SetUserinfoFromRequest instead. func (s *Storage) SetUserinfoFromScopes(ctx context.Context, userinfo *oidc.UserInfo, userID, clientID string, scopes []string) error { - return s.setUserinfo(ctx, userinfo, userID, clientID, scopes) + return nil +} + +// SetUserinfoFromRequests implements the op.CanSetUserinfoFromRequest interface. In the +// next major release, it will be required for op.Storage. +// It will be called for the creation of an id_token, so we'll just pass it to the private function without any further check +func (s *Storage) SetUserinfoFromRequest(ctx context.Context, userinfo *oidc.UserInfo, token op.IDTokenRequest, scopes []string) error { + return s.setUserinfo(ctx, userinfo, token.GetSubject(), token.GetClientID(), scopes) } // SetUserinfoFromToken implements the op.Storage interface diff --git a/example/server/storage/storage_dynamic.go b/example/server/storage/storage_dynamic.go index 6e5ee32..07af903 100644 --- a/example/server/storage/storage_dynamic.go +++ b/example/server/storage/storage_dynamic.go @@ -196,8 +196,8 @@ func (s *multiStorage) AuthorizeClientIDSecret(ctx context.Context, clientID, cl return storage.AuthorizeClientIDSecret(ctx, clientID, clientSecret) } -// SetUserinfoFromScopes implements the op.Storage interface -// it will be called for the creation of an id_token, so we'll just pass it to the private function without any further check +// SetUserinfoFromScopes implements the op.Storage interface. +// Provide an empty implementation and use SetUserinfoFromRequest instead. func (s *multiStorage) SetUserinfoFromScopes(ctx context.Context, userinfo *oidc.UserInfo, userID, clientID string, scopes []string) error { storage, err := s.storageFromContext(ctx) if err != nil { @@ -206,6 +206,17 @@ func (s *multiStorage) SetUserinfoFromScopes(ctx context.Context, userinfo *oidc return storage.SetUserinfoFromScopes(ctx, userinfo, userID, clientID, scopes) } +// SetUserinfoFromRequests implements the op.CanSetUserinfoFromRequest interface. In the +// next major release, it will be required for op.Storage. +// It will be called for the creation of an id_token, so we'll just pass it to the private function without any further check +func (s *multiStorage) SetUserinfoFromRequest(ctx context.Context, userinfo *oidc.UserInfo, token op.IDTokenRequest, scopes []string) error { + storage, err := s.storageFromContext(ctx) + if err != nil { + return err + } + return storage.SetUserinfoFromRequest(ctx, userinfo, token, scopes) +} + // SetUserinfoFromToken implements the op.Storage interface // it will be called for the userinfo endpoint, so we read the token and pass the information from that to the private function func (s *multiStorage) SetUserinfoFromToken(ctx context.Context, userinfo *oidc.UserInfo, tokenID, subject, origin string) error { diff --git a/pkg/op/storage.go b/pkg/op/storage.go index e36eac7..590c4a0 100644 --- a/pkg/op/storage.go +++ b/pkg/op/storage.go @@ -113,6 +113,8 @@ type OPStorage interface { // handle the current request. GetClientByClientID(ctx context.Context, clientID string) (Client, error) AuthorizeClientIDSecret(ctx context.Context, clientID, clientSecret string) error + // SetUserinfoFromScopes is deprecated and should have an empty implementation for now. + // Implement SetUserinfoFromRequest instead. SetUserinfoFromScopes(ctx context.Context, userinfo *oidc.UserInfo, userID, clientID string, scopes []string) error SetUserinfoFromToken(ctx context.Context, userinfo *oidc.UserInfo, tokenID, subject, origin string) error SetIntrospectionFromToken(ctx context.Context, userinfo *oidc.IntrospectionResponse, tokenID, subject, clientID string) error @@ -127,6 +129,13 @@ type JWTProfileTokenStorage interface { JWTProfileTokenType(ctx context.Context, request TokenRequest) (AccessTokenType, error) } +// CanSetUserinfoFromRequest is an optional additional interface that may be implemented by +// implementors of Storage. It allows additional data to be set in id_tokens based on the +// request. +type CanSetUserinfoFromRequest interface { + SetUserinfoFromRequest(ctx context.Context, userinfo *oidc.UserInfo, request IDTokenRequest, scopes []string) error +} + // Storage is a required parameter for NewOpenIDProvider(). In addition to the // embedded interfaces below, if the passed Storage implements ClientCredentialsStorage // then the grant type "client_credentials" will be supported. In that case, the access diff --git a/pkg/op/token.go b/pkg/op/token.go index 58568a7..6dfc993 100644 --- a/pkg/op/token.go +++ b/pkg/op/token.go @@ -190,6 +190,12 @@ func CreateIDToken(ctx context.Context, issuer string, request IDTokenRequest, v if err != nil { return "", err } + if fromRequest, ok := storage.(CanSetUserinfoFromRequest); ok { + err := fromRequest.SetUserinfoFromRequest(ctx, userInfo, request, scopes) + if err != nil { + return "", err + } + } claims.SetUserInfo(userInfo) } if code != "" { From be3cc13c27aad3a778bb46258b84293836b70e90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20M=C3=B6hlmann?= Date: Mon, 27 Mar 2023 16:41:09 +0300 Subject: [PATCH 07/21] fix: merge user info claims into id token claims (#349) oidc IDTokenClaims.SetUserInfo did not set the claims map from user info. This fix merges the claims map into the IDToken Claims map. --- pkg/oidc/token.go | 8 +++++++- pkg/oidc/token_test.go | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/pkg/oidc/token.go b/pkg/oidc/token.go index 127db97..776e758 100644 --- a/pkg/oidc/token.go +++ b/pkg/oidc/token.go @@ -8,6 +8,7 @@ import ( "golang.org/x/oauth2" "gopkg.in/square/go-jose.v2" + "github.com/muhlemmer/gu" "github.com/zitadel/oidc/v2/pkg/crypto" ) @@ -157,6 +158,11 @@ func (t *IDTokenClaims) SetUserInfo(i *UserInfo) { t.UserInfoEmail = i.UserInfoEmail t.UserInfoPhone = i.UserInfoPhone t.Address = i.Address + + if t.Claims == nil { + t.Claims = make(map[string]any, len(t.Claims)) + } + gu.MapMerge(i.Claims, t.Claims) } func (t *IDTokenClaims) GetUserInfo() *UserInfo { @@ -166,7 +172,7 @@ func (t *IDTokenClaims) GetUserInfo() *UserInfo { UserInfoEmail: t.UserInfoEmail, UserInfoPhone: t.UserInfoPhone, Address: t.Address, - Claims: t.Claims, + Claims: gu.MapCopy(t.Claims), } } diff --git a/pkg/oidc/token_test.go b/pkg/oidc/token_test.go index 8dcfc7e..7377a84 100644 --- a/pkg/oidc/token_test.go +++ b/pkg/oidc/token_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + "github.com/muhlemmer/gu" "github.com/stretchr/testify/assert" "golang.org/x/text/language" "gopkg.in/square/go-jose.v2" @@ -181,6 +182,7 @@ func TestIDTokenClaims_SetUserInfo(t *testing.T) { UserInfoEmail: userInfoData.UserInfoEmail, UserInfoPhone: userInfoData.UserInfoPhone, Address: userInfoData.Address, + Claims: gu.MapCopy(userInfoData.Claims), } var got IDTokenClaims From e1d50faf9b58798a0b4e397fea37a93a464ac5ba Mon Sep 17 00:00:00 2001 From: David Sharnoff Date: Mon, 27 Mar 2023 13:40:10 -0700 Subject: [PATCH 08/21] fix: do not modify userInfo when marshaling --- pkg/oidc/introspection_test.go | 3 ++- pkg/oidc/regression_assert_test.go | 7 +++++-- pkg/oidc/token.go | 1 - pkg/oidc/token_test.go | 5 +++-- pkg/oidc/userinfo_test.go | 5 ++++- pkg/oidc/util.go | 13 +++++++++---- 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/pkg/oidc/introspection_test.go b/pkg/oidc/introspection_test.go index bd49894..60cf8a4 100644 --- a/pkg/oidc/introspection_test.go +++ b/pkg/oidc/introspection_test.go @@ -4,6 +4,7 @@ import ( "encoding/json" "testing" + "github.com/muhlemmer/gu" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -25,7 +26,7 @@ func TestIntrospectionResponse_SetUserInfo(t *testing.T) { UserInfoProfile: userInfoData.UserInfoProfile, UserInfoEmail: userInfoData.UserInfoEmail, UserInfoPhone: userInfoData.UserInfoPhone, - Claims: userInfoData.Claims, + Claims: gu.MapCopy(userInfoData.Claims), }, }, { diff --git a/pkg/oidc/regression_assert_test.go b/pkg/oidc/regression_assert_test.go index 5e9fb3d..dd9f5ad 100644 --- a/pkg/oidc/regression_assert_test.go +++ b/pkg/oidc/regression_assert_test.go @@ -6,6 +6,7 @@ import ( "encoding/json" "io" "os" + "reflect" "strings" "testing" @@ -38,10 +39,12 @@ func Test_assert_regression(t *testing.T) { assert.JSONEq(t, want, first) + target := reflect.New(reflect.TypeOf(obj).Elem()).Interface() + require.NoError(t, - json.Unmarshal([]byte(first), obj), + json.Unmarshal([]byte(first), target), ) - second, err := json.Marshal(obj) + second, err := json.Marshal(target) require.NoError(t, err) assert.JSONEq(t, want, string(second)) diff --git a/pkg/oidc/token.go b/pkg/oidc/token.go index 776e758..5283eb5 100644 --- a/pkg/oidc/token.go +++ b/pkg/oidc/token.go @@ -158,7 +158,6 @@ func (t *IDTokenClaims) SetUserInfo(i *UserInfo) { t.UserInfoEmail = i.UserInfoEmail t.UserInfoPhone = i.UserInfoPhone t.Address = i.Address - if t.Claims == nil { t.Claims = make(map[string]any, len(t.Claims)) } diff --git a/pkg/oidc/token_test.go b/pkg/oidc/token_test.go index 7377a84..ef1e77f 100644 --- a/pkg/oidc/token_test.go +++ b/pkg/oidc/token_test.go @@ -4,7 +4,6 @@ import ( "testing" "time" - "github.com/muhlemmer/gu" "github.com/stretchr/testify/assert" "golang.org/x/text/language" "gopkg.in/square/go-jose.v2" @@ -182,7 +181,9 @@ func TestIDTokenClaims_SetUserInfo(t *testing.T) { UserInfoEmail: userInfoData.UserInfoEmail, UserInfoPhone: userInfoData.UserInfoPhone, Address: userInfoData.Address, - Claims: gu.MapCopy(userInfoData.Claims), + Claims: map[string]interface{}{ + "foo": "bar", + }, } var got IDTokenClaims diff --git a/pkg/oidc/userinfo_test.go b/pkg/oidc/userinfo_test.go index faab4e3..a574366 100644 --- a/pkg/oidc/userinfo_test.go +++ b/pkg/oidc/userinfo_test.go @@ -52,11 +52,14 @@ func TestUserInfoMarshal(t *testing.T) { out := new(UserInfo) assert.NoError(t, json.Unmarshal(marshal, out)) - assert.Equal(t, userinfo, out) expected, err := json.Marshal(out) assert.NoError(t, err) assert.Equal(t, expected, marshal) + + out2 := new(UserInfo) + assert.NoError(t, json.Unmarshal(expected, out2)) + assert.Equal(t, out, out2) } func TestUserInfoEmailVerifiedUnmarshal(t *testing.T) { diff --git a/pkg/oidc/util.go b/pkg/oidc/util.go index a89d75e..462ea44 100644 --- a/pkg/oidc/util.go +++ b/pkg/oidc/util.go @@ -9,7 +9,7 @@ import ( // mergeAndMarshalClaims merges registered and the custom // claims map into a single JSON object. // Registered fields overwrite custom claims. -func mergeAndMarshalClaims(registered any, claims map[string]any) ([]byte, error) { +func mergeAndMarshalClaims(registered any, extraClaims map[string]any) ([]byte, error) { // Use a buffer for memory re-use, instead off letting // json allocate a new []byte for every step. buf := new(bytes.Buffer) @@ -19,16 +19,21 @@ func mergeAndMarshalClaims(registered any, claims map[string]any) ([]byte, error return nil, fmt.Errorf("oidc registered claims: %w", err) } - if len(claims) > 0 { + if len(extraClaims) > 0 { + merged := make(map[string]any) + for k, v := range extraClaims { + merged[k] = v + } + // Merge JSON data into custom claims. // The full-read action by the decoder resets the buffer // to zero len, while retaining underlaying cap. - if err := json.NewDecoder(buf).Decode(&claims); err != nil { + if err := json.NewDecoder(buf).Decode(&merged); err != nil { return nil, fmt.Errorf("oidc registered claims: %w", err) } // Marshal the final result. - if err := json.NewEncoder(buf).Encode(claims); err != nil { + if err := json.NewEncoder(buf).Encode(merged); err != nil { return nil, fmt.Errorf("oidc custom claims: %w", err) } } From b7d18bfd0284b42a7dfc86dfcbf283cab19fbbd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20M=C3=B6hlmann?= Date: Tue, 28 Mar 2023 14:58:57 +0300 Subject: [PATCH 09/21] chore: document non-standard glob client (#328) * op: correct typo rename checkURIAginstRedirects to checkURIAgainstRedirects * chore: document standard deviation when using globs add example on how to toggle the underlying client implementation based on DevMode. --------- Co-authored-by: David Sharnoff --- example/server/storage/client.go | 35 ++++++++++++++++++++++--------- example/server/storage/storage.go | 2 +- pkg/op/auth_request.go | 10 ++++----- pkg/op/client.go | 6 ++++++ 4 files changed, 37 insertions(+), 16 deletions(-) diff --git a/example/server/storage/client.go b/example/server/storage/client.go index b850053..b8b9960 100644 --- a/example/server/storage/client.go +++ b/example/server/storage/client.go @@ -32,6 +32,8 @@ type Client struct { devMode bool idTokenUserinfoClaimsAssertion bool clockSkew time.Duration + postLogoutRedirectURIGlobs []string + redirectURIGlobs []string } // GetID must return the client_id @@ -44,21 +46,11 @@ func (c *Client) RedirectURIs() []string { return c.redirectURIs } -// RedirectURIGlobs provide wildcarding for additional valid redirects -func (c *Client) RedirectURIGlobs() []string { - return nil -} - // PostLogoutRedirectURIs must return the registered post_logout_redirect_uris for sign-outs func (c *Client) PostLogoutRedirectURIs() []string { return []string{} } -// PostLogoutRedirectURIGlobs provide extra wildcarding for additional valid redirects -func (c *Client) PostLogoutRedirectURIGlobs() []string { - return nil -} - // ApplicationType must return the type of the client (app, native, user agent) func (c *Client) ApplicationType() op.ApplicationType { return c.applicationType @@ -200,3 +192,26 @@ func WebClient(id, secret string, redirectURIs ...string) *Client { clockSkew: 0, } } + +type hasRedirectGlobs struct { + *Client +} + +// RedirectURIGlobs provide wildcarding for additional valid redirects +func (c hasRedirectGlobs) RedirectURIGlobs() []string { + return c.redirectURIGlobs +} + +// PostLogoutRedirectURIGlobs provide extra wildcarding for additional valid redirects +func (c hasRedirectGlobs) PostLogoutRedirectURIGlobs() []string { + return c.postLogoutRedirectURIGlobs +} + +// RedirectGlobsClient wraps the client in a op.HasRedirectGlobs +// only if DevMode is enabled. +func RedirectGlobsClient(client *Client) op.Client { + if client.devMode { + return hasRedirectGlobs{client} + } + return client +} diff --git a/example/server/storage/storage.go b/example/server/storage/storage.go index acac571..a4c4f46 100644 --- a/example/server/storage/storage.go +++ b/example/server/storage/storage.go @@ -418,7 +418,7 @@ func (s *Storage) GetClientByClientID(ctx context.Context, clientID string) (op. if !ok { return nil, fmt.Errorf("client not found") } - return client, nil + return RedirectGlobsClient(client), nil } // AuthorizeClientIDSecret implements the op.Storage interface diff --git a/pkg/op/auth_request.go b/pkg/op/auth_request.go index b312098..1f9fc45 100644 --- a/pkg/op/auth_request.go +++ b/pkg/op/auth_request.go @@ -274,9 +274,9 @@ func ValidateAuthReqScopes(client Client, scopes []string) ([]string, error) { return scopes, nil } -// checkURIAginstRedirects just checks aginst the valid redirect URIs and ignores +// checkURIAgainstRedirects just checks aginst the valid redirect URIs and ignores // other factors. -func checkURIAginstRedirects(client Client, uri string) error { +func checkURIAgainstRedirects(client Client, uri string) error { if str.Contains(client.RedirectURIs(), uri) { return nil } @@ -303,12 +303,12 @@ func ValidateAuthReqRedirectURI(client Client, uri string, responseType oidc.Res "Please ensure it is added to the request. If you have any questions, you may contact the administrator of the application.") } if strings.HasPrefix(uri, "https://") { - return checkURIAginstRedirects(client, uri) + return checkURIAgainstRedirects(client, uri) } if client.ApplicationType() == ApplicationTypeNative { return validateAuthReqRedirectURINative(client, uri, responseType) } - if err := checkURIAginstRedirects(client, uri); err != nil { + if err := checkURIAgainstRedirects(client, uri); err != nil { return err } if strings.HasPrefix(uri, "http://") { @@ -329,7 +329,7 @@ func ValidateAuthReqRedirectURI(client Client, uri string, responseType oidc.Res func validateAuthReqRedirectURINative(client Client, uri string, responseType oidc.ResponseType) error { parsedURL, isLoopback := HTTPLoopbackOrLocalhost(uri) isCustomSchema := !strings.HasPrefix(uri, "http://") - if err := checkURIAginstRedirects(client, uri); err == nil { + if err := checkURIAgainstRedirects(client, uri); err == nil { if client.DevMode() { return nil } diff --git a/pkg/op/client.go b/pkg/op/client.go index af4724a..9da44a7 100644 --- a/pkg/op/client.go +++ b/pkg/op/client.go @@ -56,6 +56,12 @@ type Client interface { // interpretation. Redirect URIs that match either the non-glob version or the // glob version will be accepted. Glob URIs are only partially supported for native // clients: "http://" is not allowed except for loopback or in dev mode. +// +// Note that globbing / wildcards are not permitted by the OIDC +// standard and implementing this interface can have security implications. +// It is advised to only return a client of this type in rare cases, +// such as DevMode for the client being enabled. +// https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest type HasRedirectGlobs interface { RedirectURIGlobs() []string PostLogoutRedirectURIGlobs() []string From 1a2db3683f135ced14022705373d21789d6ec9f2 Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Wed, 29 Mar 2023 09:51:10 +0200 Subject: [PATCH 10/21] fix: Only set GrantType once (#353) This fixes an issue where, when using the device authorization flow, the grant type would be set twice. Some OPs don't accept this, and fail when polling. With this fix the grant type is only set once, which will make some OPs happy again. Fixes #352 --- pkg/client/rp/device.go | 1 - pkg/oidc/token_request.go | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/client/rp/device.go b/pkg/client/rp/device.go index 73b67ca..a397f14 100644 --- a/pkg/client/rp/device.go +++ b/pkg/client/rp/device.go @@ -12,7 +12,6 @@ import ( func newDeviceClientCredentialsRequest(scopes []string, rp RelyingParty) (*oidc.ClientCredentialsRequest, error) { confg := rp.OAuthConfig() req := &oidc.ClientCredentialsRequest{ - GrantType: oidc.GrantTypeDeviceCode, Scope: scopes, ClientID: confg.ClientID, ClientSecret: confg.ClientSecret, diff --git a/pkg/oidc/token_request.go b/pkg/oidc/token_request.go index 6b6945a..5c5cf20 100644 --- a/pkg/oidc/token_request.go +++ b/pkg/oidc/token_request.go @@ -241,7 +241,7 @@ type TokenExchangeRequest struct { } type ClientCredentialsRequest struct { - GrantType GrantType `schema:"grant_type"` + GrantType GrantType `schema:"grant_type,omitempty"` Scope SpaceDelimitedArray `schema:"scope"` ClientID string `schema:"client_id"` ClientSecret string `schema:"client_secret"` From 211b17589ee25ede48a30cba51ff3ad3b10149ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Apr 2023 07:36:29 +0200 Subject: [PATCH 11/21] chore(deps): bump actions/add-to-project from 0.4.1 to 0.5.0 (#357) Bumps [actions/add-to-project](https://github.com/actions/add-to-project) from 0.4.1 to 0.5.0. - [Release notes](https://github.com/actions/add-to-project/releases) - [Commits](https://github.com/actions/add-to-project/compare/v0.4.1...v0.5.0) --- updated-dependencies: - dependency-name: actions/add-to-project dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/issue.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/issue.yml b/.github/workflows/issue.yml index 8671820..362443d 100644 --- a/.github/workflows/issue.yml +++ b/.github/workflows/issue.yml @@ -10,7 +10,7 @@ jobs: name: Add issue to project runs-on: ubuntu-latest steps: - - uses: actions/add-to-project@v0.4.1 + - uses: actions/add-to-project@v0.5.0 with: # You can target a repository in a different organization # to the issue From dc2bdc6202866510a1e2caaaaa2200ba156e258a Mon Sep 17 00:00:00 2001 From: Livio Spring Date: Tue, 4 Apr 2023 12:48:18 +0200 Subject: [PATCH 12/21] fix: improve error handling when getting ClientIDFromRequest (#359) --- pkg/op/client.go | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/pkg/op/client.go b/pkg/op/client.go index 9da44a7..04f8c0c 100644 --- a/pkg/op/client.go +++ b/pkg/op/client.go @@ -156,16 +156,25 @@ func ClientIDFromRequest(r *http.Request, p ClientProvider) (clientID string, au } JWTProfile, ok := p.(ClientJWTProfile) - if ok { + if ok && data.ClientAssertion != "" { + // if JWTProfile is supported and client sent an assertion, check it and use it as response + // regardless if it succeeded or failed clientID, err = ClientJWTAuth(r.Context(), data.ClientAssertionParams, JWTProfile) + return clientID, err == nil, err } - if !ok || errors.Is(err, ErrNoClientCredentials) { - clientID, err = ClientBasicAuth(r, p.Storage()) - } + // try basic auth + clientID, err = ClientBasicAuth(r, p.Storage()) + // if that succeeded, use it if err == nil { return clientID, true, nil } + // if the client did not send a Basic Auth Header, ignore the `ErrNoClientCredentials` + // but return other errors immediately + if err != nil && !errors.Is(err, ErrNoClientCredentials) { + return "", false, err + } + // if the client did not authenticate (public clients) it must at least send a client_id if data.ClientID == "" { return "", false, oidc.ErrInvalidClient().WithParent(ErrMissingClientID) } From c72aa8f9a1e799e3165de2ba10e8cd3ca5b9d113 Mon Sep 17 00:00:00 2001 From: Livio Spring Date: Tue, 4 Apr 2023 13:45:30 +0200 Subject: [PATCH 13/21] fix: use Form instead of PostForm in ClientIDFromRequest (#360) --- pkg/op/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/op/client.go b/pkg/op/client.go index 04f8c0c..32a3dd1 100644 --- a/pkg/op/client.go +++ b/pkg/op/client.go @@ -151,7 +151,7 @@ func ClientIDFromRequest(r *http.Request, p ClientProvider) (clientID string, au } data := new(clientData) - if err = p.Decoder().Decode(data, r.PostForm); err != nil { + if err = p.Decoder().Decode(data, r.Form); err != nil { return "", false, err } From 057538d55546bb7aa95dcb5fb2d7b2d51cc321ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20M=C3=B6hlmann?= Date: Wed, 5 Apr 2023 10:02:37 +0200 Subject: [PATCH 14/21] fix: resolve nil pointer panic in Authorize (#358) When ParseAuthorizeRequest received an invalid URL, for example containing a semi-colon `;`, AuthRequestError used to panic. This was because a typed nil was passed as a interface argument. The nil check inside AuthRequestError always resulted in false, allowing access through the nil pointer. Fixes #315 --- pkg/op/auth_request.go | 2 +- pkg/op/auth_request_test.go | 83 +++++++++++++------------------------ 2 files changed, 30 insertions(+), 55 deletions(-) diff --git a/pkg/op/auth_request.go b/pkg/op/auth_request.go index 1f9fc45..c264605 100644 --- a/pkg/op/auth_request.go +++ b/pkg/op/auth_request.go @@ -68,7 +68,7 @@ func authorizeCallbackHandler(authorizer Authorizer) func(http.ResponseWriter, * func Authorize(w http.ResponseWriter, r *http.Request, authorizer Authorizer) { authReq, err := ParseAuthorizeRequest(r, authorizer.Decoder()) if err != nil { - AuthRequestError(w, r, authReq, err, authorizer.Encoder()) + AuthRequestError(w, r, nil, err, authorizer.Encoder()) return } ctx := r.Context() diff --git a/pkg/op/auth_request_test.go b/pkg/op/auth_request_test.go index 7a9701b..2bba4e7 100644 --- a/pkg/op/auth_request_test.go +++ b/pkg/op/auth_request_test.go @@ -9,6 +9,7 @@ import ( "reflect" "testing" + "github.com/golang/mock/gomock" "github.com/gorilla/schema" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -19,60 +20,34 @@ import ( "github.com/zitadel/oidc/v2/pkg/op/mock" ) -// -// TOOD: tests will be implemented in branch for service accounts -// func TestAuthorize(t *testing.T) { -// // testCallback := func(t *testing.T, clienID string) callbackHandler { -// // return func(authReq *oidc.AuthRequest, client oidc.Client, w http.ResponseWriter, r *http.Request) { -// // // require.Equal(t, clientID, client.) -// // } -// // } -// // testErr := func(t *testing.T, expected error) errorHandler { -// // return func(w http.ResponseWriter, r *http.Request, authReq *oidc.AuthRequest, err error) { -// // require.Equal(t, expected, err) -// // } -// // } -// type args struct { -// w http.ResponseWriter -// r *http.Request -// authorizer op.Authorizer -// } -// tests := []struct { -// name string -// args args -// }{ -// { -// "parsing fails", -// args{ -// httptest.NewRecorder(), -// &http.Request{Method: "POST", Body: nil}, -// mock.NewAuthorizerExpectValid(t, true), -// // testCallback(t, ""), -// // testErr(t, ErrInvalidRequest("cannot parse form")), -// }, -// }, -// { -// "decoding fails", -// args{ -// httptest.NewRecorder(), -// func() *http.Request { -// r := httptest.NewRequest("POST", "/authorize", strings.NewReader("client_id=foo")) -// r.Header.Set("Content-Type", "application/x-www-form-urlencoded") -// return r -// }(), -// mock.NewAuthorizerExpectValid(t, true), -// // testCallback(t, ""), -// // testErr(t, ErrInvalidRequest("cannot parse auth request")), -// }, -// }, -// // {"decoding fails", args{httptest.NewRecorder(), &http.Request{}, mock.NewAuthorizerExpectValid(t), nil, testErr(t, nil)}}, -// } -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// op.Authorize(tt.args.w, tt.args.r, tt.args.authorizer) -// }) -// } -//} +func TestAuthorize(t *testing.T) { + tests := []struct { + name string + req *http.Request + expect func(a *mock.MockAuthorizerMockRecorder) + }{ + { + name: "parse error", // used to panic, see issue #315 + req: httptest.NewRequest(http.MethodPost, "/?;", nil), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + w := httptest.NewRecorder() + authorizer := mock.NewMockAuthorizer(gomock.NewController(t)) + + expect := authorizer.EXPECT() + expect.Decoder().Return(schema.NewDecoder()) + expect.Encoder().Return(schema.NewEncoder()) + + if tt.expect != nil { + tt.expect(expect) + } + + op.Authorize(w, tt.req, authorizer) + }) + } +} func TestParseAuthorizeRequest(t *testing.T) { type args struct { From 54c87ada6f61f9a4fa7d07b7274cc6e9d3c3fdae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Apr 2023 10:35:15 +0300 Subject: [PATCH 15/21] chore(deps): bump golang.org/x/text from 0.8.0 to 0.9.0 (#361) Bumps [golang.org/x/text](https://github.com/golang/text) from 0.8.0 to 0.9.0. - [Release notes](https://github.com/golang/text/releases) - [Commits](https://github.com/golang/text/compare/v0.8.0...v0.9.0) --- updated-dependencies: - dependency-name: golang.org/x/text dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index adb638e..09c1f69 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.8.2 golang.org/x/oauth2 v0.6.0 - golang.org/x/text v0.8.0 + golang.org/x/text v0.9.0 gopkg.in/square/go-jose.v2 v2.6.0 ) diff --git a/go.sum b/go.sum index 4259674..e8e5db7 100644 --- a/go.sum +++ b/go.sum @@ -79,8 +79,8 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= From 97bc09583d7028ec1c4f75396ed77062a04f897a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Apr 2023 10:37:08 +0300 Subject: [PATCH 16/21] chore(deps): bump golang.org/x/oauth2 from 0.6.0 to 0.7.0 (#362) Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.6.0 to 0.7.0. - [Release notes](https://github.com/golang/oauth2/releases) - [Commits](https://github.com/golang/oauth2/compare/v0.6.0...v0.7.0) --- updated-dependencies: - dependency-name: golang.org/x/oauth2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 09c1f69..f4e77f6 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/rs/cors v1.8.3 github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.8.2 - golang.org/x/oauth2 v0.6.0 + golang.org/x/oauth2 v0.7.0 golang.org/x/text v0.9.0 gopkg.in/square/go-jose.v2 v2.6.0 ) @@ -26,8 +26,8 @@ require ( github.com/google/go-querystring v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/crypto v0.7.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/sys v0.6.0 // indirect + golang.org/x/net v0.9.0 // indirect + golang.org/x/sys v0.7.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.29.1 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect diff --git a/go.sum b/go.sum index e8e5db7..8d3f108 100644 --- a/go.sum +++ b/go.sum @@ -60,11 +60,11 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= +golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -73,8 +73,8 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= From 44f840357475b1923c2dd3b2ef5240da189ea345 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20M=C3=B6hlmann?= Date: Tue, 11 Apr 2023 21:29:17 +0300 Subject: [PATCH 17/21] feat: get issuer from context for device auth (#363) * feat: get issuer from context for device auth * use distinct UserFormURL and UserFormPath - Properly deprecate UserFormURL and default to old behaviour, to prevent breaking change. - Refactor unit tests to test both cases. * update example --- example/server/exampleop/op.go | 2 +- pkg/op/device.go | 27 ++++++++++++-- pkg/op/device_test.go | 64 +++++++++++++++++++++++++--------- pkg/op/op_test.go | 29 ++++++++------- 4 files changed, 90 insertions(+), 32 deletions(-) diff --git a/example/server/exampleop/op.go b/example/server/exampleop/op.go index 5604483..1dc8bd1 100644 --- a/example/server/exampleop/op.go +++ b/example/server/exampleop/op.go @@ -107,7 +107,7 @@ func newOP(storage op.Storage, issuer string, key [32]byte) (op.OpenIDProvider, DeviceAuthorization: op.DeviceAuthorizationConfig{ Lifetime: 5 * time.Minute, PollInterval: 5 * time.Second, - UserFormURL: issuer + "device", + UserFormPath: "/device", UserCode: op.UserCodeBase20, }, } diff --git a/pkg/op/device.go b/pkg/op/device.go index 04c06f2..f7691ca 100644 --- a/pkg/op/device.go +++ b/pkg/op/device.go @@ -8,6 +8,7 @@ import ( "fmt" "math/big" "net/http" + "net/url" "strings" "time" @@ -18,7 +19,14 @@ import ( type DeviceAuthorizationConfig struct { Lifetime time.Duration PollInterval time.Duration - UserFormURL string // the URL where the user must go to authorize the device + + // UserFormURL is the complete URL where the user must go to authorize the device. + // Deprecated: use UserFormPath instead. + UserFormURL string + + // UserFormPath is the path where the user must go to authorize the device. + // The hostname for the URL is taken from the request by IssuerFromContext. + UserFormPath string UserCode UserCodeConfig } @@ -82,15 +90,28 @@ func DeviceAuthorization(w http.ResponseWriter, r *http.Request, o OpenIDProvide return err } + var verification *url.URL + if config.UserFormURL != "" { + if verification, err = url.Parse(config.UserFormURL); err != nil { + return oidc.ErrServerError().WithParent(err).WithDescription("invalid URL for device user form") + } + } else { + if verification, err = url.Parse(IssuerFromContext(r.Context())); err != nil { + return oidc.ErrServerError().WithParent(err).WithDescription("invalid URL for issuer") + } + verification.Path = config.UserFormPath + } + response := &oidc.DeviceAuthorizationResponse{ DeviceCode: deviceCode, UserCode: userCode, - VerificationURI: config.UserFormURL, + VerificationURI: verification.String(), ExpiresIn: int(config.Lifetime / time.Second), Interval: int(config.PollInterval / time.Second), } - response.VerificationURIComplete = fmt.Sprintf("%s?user_code=%s", config.UserFormURL, userCode) + verification.RawQuery = "user_code=" + userCode + response.VerificationURIComplete = verification.String() httphelper.MarshalJSON(w, response) return nil diff --git a/pkg/op/device_test.go b/pkg/op/device_test.go index 69ba102..cf94c3f 100644 --- a/pkg/op/device_test.go +++ b/pkg/op/device_test.go @@ -13,6 +13,7 @@ import ( "testing" "time" + "github.com/muhlemmer/gu" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/zitadel/oidc/v2/pkg/oidc" @@ -20,29 +21,60 @@ import ( ) func Test_deviceAuthorizationHandler(t *testing.T) { - req := &oidc.DeviceAuthorizationRequest{ - Scopes: []string{"foo", "bar"}, - ClientID: "web", + type conf struct { + UserFormURL string + UserFormPath string } - values := make(url.Values) - testProvider.Encoder().Encode(req, values) - body := strings.NewReader(values.Encode()) + tests := []struct { + name string + conf conf + }{ + { + name: "UserFormURL", + conf: conf{ + UserFormURL: "https://localhost:9998/device", + }, + }, + { + name: "UserFormPath", + conf: conf{ + UserFormPath: "/device", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + conf := gu.PtrCopy(testConfig) + conf.DeviceAuthorization.UserFormURL = tt.conf.UserFormURL + conf.DeviceAuthorization.UserFormPath = tt.conf.UserFormPath + provider := newTestProvider(conf) - r := httptest.NewRequest(http.MethodPost, "/", body) - r.Header.Set("Content-Type", "application/x-www-form-urlencoded") + req := &oidc.DeviceAuthorizationRequest{ + Scopes: []string{"foo", "bar"}, + ClientID: "web", + } + values := make(url.Values) + testProvider.Encoder().Encode(req, values) + body := strings.NewReader(values.Encode()) - w := httptest.NewRecorder() + r := httptest.NewRequest(http.MethodPost, "/", body) + r.Header.Set("Content-Type", "application/x-www-form-urlencoded") + r = r.WithContext(op.ContextWithIssuer(r.Context(), testIssuer)) - runWithRandReader(mr.New(mr.NewSource(1)), func() { - op.DeviceAuthorizationHandler(testProvider)(w, r) - }) + w := httptest.NewRecorder() - result := w.Result() + runWithRandReader(mr.New(mr.NewSource(1)), func() { + op.DeviceAuthorizationHandler(provider)(w, r) + }) - assert.Less(t, result.StatusCode, 300) + result := w.Result() - got, _ := io.ReadAll(result.Body) - assert.JSONEq(t, `{"device_code":"Uv38ByGCZU8WP18PmmIdcg", "expires_in":300, "interval":5, "user_code":"JKRV-FRGK", "verification_uri":"https://localhost:9998/device", "verification_uri_complete":"https://localhost:9998/device?user_code=JKRV-FRGK"}`, string(got)) + assert.Less(t, result.StatusCode, 300) + + got, _ := io.ReadAll(result.Body) + assert.JSONEq(t, `{"device_code":"Uv38ByGCZU8WP18PmmIdcg", "expires_in":300, "interval":5, "user_code":"JKRV-FRGK", "verification_uri":"https://localhost:9998/device", "verification_uri_complete":"https://localhost:9998/device?user_code=JKRV-FRGK"}`, string(got)) + }) + } } func TestParseDeviceCodeRequest(t *testing.T) { diff --git a/pkg/op/op_test.go b/pkg/op/op_test.go index ba3570b..3e6377f 100644 --- a/pkg/op/op_test.go +++ b/pkg/op/op_test.go @@ -20,15 +20,9 @@ import ( "golang.org/x/text/language" ) -var testProvider op.OpenIDProvider - -const ( - testIssuer = "https://localhost:9998/" - pathLoggedOut = "/logged-out" -) - -func init() { - config := &op.Config{ +var ( + testProvider op.OpenIDProvider + testConfig = &op.Config{ CryptoKey: sha256.Sum256([]byte("test")), DefaultLogoutRedirectURI: pathLoggedOut, CodeMethodS256: true, @@ -40,24 +34,35 @@ func init() { DeviceAuthorization: op.DeviceAuthorizationConfig{ Lifetime: 5 * time.Minute, PollInterval: 5 * time.Second, - UserFormURL: testIssuer + "device", + UserFormPath: "/device", UserCode: op.UserCodeBase20, }, } +) +const ( + testIssuer = "https://localhost:9998/" + pathLoggedOut = "/logged-out" +) + +func init() { storage.RegisterClients( storage.NativeClient("native"), storage.WebClient("web", "secret", "https://example.com"), storage.WebClient("api", "secret"), ) - var err error - testProvider, err = op.NewOpenIDProvider(testIssuer, config, + testProvider = newTestProvider(testConfig) +} + +func newTestProvider(config *op.Config) op.OpenIDProvider { + provider, err := op.NewOpenIDProvider(testIssuer, config, storage.NewStorage(storage.NewUserStore(testIssuer)), op.WithAllowInsecure(), ) if err != nil { panic(err) } + return provider } type routesTestStorage interface { From 8730a1685e185d681392e17f5f402e60dce8b152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20M=C3=B6hlmann?= Date: Thu, 13 Apr 2023 12:25:49 +0300 Subject: [PATCH 18/21] feat: custom endpoint for device authorization (#368) --- pkg/op/op.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pkg/op/op.go b/pkg/op/op.go index ecb753e..fc5262a 100644 --- a/pkg/op/op.go +++ b/pkg/op/op.go @@ -476,6 +476,16 @@ func WithCustomKeysEndpoint(endpoint Endpoint) Option { } } +func WithCustomDeviceAuthorizationEndpoint(endpoint Endpoint) Option { + return func(o *Provider) error { + if err := endpoint.Validate(); err != nil { + return err + } + o.endpoints.DeviceAuthorization = endpoint + return nil + } +} + func WithCustomEndpoints(auth, token, userInfo, revocation, endSession, keys Endpoint) Option { return func(o *Provider) error { o.endpoints.Authorization = auth From f0d46593e0aa984bb1a63fc93cb79fc73b7ab59b Mon Sep 17 00:00:00 2001 From: David Sharnoff Date: Thu, 13 Apr 2023 06:37:50 -0700 Subject: [PATCH 19/21] feat: rp.RefreshAccessToken() now may provide an updated IDToken (#365) --- pkg/client/client.go | 10 ++++++++-- pkg/client/integration_test.go | 2 +- pkg/client/profile/jwt_profile.go | 2 +- pkg/client/rp/relying_party.go | 4 ++++ 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/pkg/client/client.go b/pkg/client/client.go index 9eda973..f6a407b 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -61,12 +61,18 @@ func callTokenEndpoint(request interface{}, authFn interface{}, caller TokenEndp if err := httphelper.HttpRequest(caller.HttpClient(), req, &tokenRes); err != nil { return nil, err } - return &oauth2.Token{ + token := &oauth2.Token{ AccessToken: tokenRes.AccessToken, TokenType: tokenRes.TokenType, RefreshToken: tokenRes.RefreshToken, Expiry: time.Now().UTC().Add(time.Duration(tokenRes.ExpiresIn) * time.Second), - }, nil + } + if tokenRes.IDToken != "" { + token = token.WithExtra(map[string]any{ + "id_token": tokenRes.IDToken, + }) + } + return token, nil } type EndSessionCaller interface { diff --git a/pkg/client/integration_test.go b/pkg/client/integration_test.go index e19a720..40e1bee 100644 --- a/pkg/client/integration_test.go +++ b/pkg/client/integration_test.go @@ -53,6 +53,7 @@ func TestRelyingPartySession(t *testing.T) { t.Logf("new token type %s", newTokens.TokenType) t.Logf("new expiry %s", newTokens.Expiry.Format(time.RFC3339)) require.NotEmpty(t, newTokens.AccessToken, "new accessToken") + assert.NotEmpty(t, newTokens.Extra("id_token"), "new idToken") t.Log("------ end session (logout) ------") @@ -141,7 +142,6 @@ func TestResourceServerTokenExchange(t *testing.T) { require.Error(t, err, "refresh token") assert.Contains(t, err.Error(), "subject_token is invalid") require.Nil(t, tokenExchangeResponse, "token exchange response") - } func RunAuthorizationCodeFlow(t *testing.T, opServer *httptest.Server, clientID, clientSecret string) (provider rp.RelyingParty, accessToken, refreshToken, idToken string) { diff --git a/pkg/client/profile/jwt_profile.go b/pkg/client/profile/jwt_profile.go index a934f7d..a220dc5 100644 --- a/pkg/client/profile/jwt_profile.go +++ b/pkg/client/profile/jwt_profile.go @@ -13,7 +13,7 @@ import ( // jwtProfileTokenSource implement the oauth2.TokenSource // it will request a token using the OAuth2 JWT Profile Grant -// therefore sending an `assertion` by singing a JWT with the provided private key +// therefore sending an `assertion` by signing a JWT with the provided private key type jwtProfileTokenSource struct { clientID string audience []string diff --git a/pkg/client/rp/relying_party.go b/pkg/client/rp/relying_party.go index ede7453..7127020 100644 --- a/pkg/client/rp/relying_party.go +++ b/pkg/client/rp/relying_party.go @@ -620,6 +620,10 @@ type RefreshTokenRequest struct { GrantType oidc.GrantType `schema:"grant_type"` } +// RefreshAccessToken performs a token refresh. If it doesn't error, it will always +// provide a new AccessToken. It may provide a new RefreshToken, and if it does, then +// the old one should be considered invalid. It may also provide a new IDToken. The +// new IDToken can be retrieved with token.Extra("id_token"). func RefreshAccessToken(rp RelyingParty, refreshToken, clientAssertion, clientAssertionType string) (*oauth2.Token, error) { request := RefreshTokenRequest{ RefreshToken: refreshToken, From 2c7ca3a30579084555028dc4c0c7f5688de454d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Apr 2023 15:32:02 +0300 Subject: [PATCH 20/21] chore(deps): bump github.com/rs/cors from 1.8.3 to 1.9.0 (#369) Bumps [github.com/rs/cors](https://github.com/rs/cors) from 1.8.3 to 1.9.0. - [Release notes](https://github.com/rs/cors/releases) - [Commits](https://github.com/rs/cors/compare/v1.8.3...v1.9.0) --- updated-dependencies: - dependency-name: github.com/rs/cors dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f4e77f6..5f96c72 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/gorilla/securecookie v1.1.1 github.com/jeremija/gosubmit v0.2.7 github.com/muhlemmer/gu v0.3.1 - github.com/rs/cors v1.8.3 + github.com/rs/cors v1.9.0 github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.8.2 golang.org/x/oauth2 v0.7.0 diff --git a/go.sum b/go.sum index 8d3f108..df4d60c 100644 --- a/go.sum +++ b/go.sum @@ -36,8 +36,8 @@ github.com/muhlemmer/gu v0.3.1 h1:7EAqmFrW7n3hETvuAdmFmn4hS8W+z3LgKtrnow+YzNM= github.com/muhlemmer/gu v0.3.1/go.mod h1:YHtHR+gxM+bKEIIs7Hmi9sPT3ZDUvTN/i88wQpZkrdM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo= -github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE= +github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= From 7aa96feb6a8454782a53b22d47d9dba3044c2aa1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Apr 2023 12:15:21 +0300 Subject: [PATCH 21/21] chore(deps): bump codecov/codecov-action from 3.1.1 to 3.1.2 (#373) Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 3.1.1 to 3.1.2. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v3.1.1...v3.1.2) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 78c0f79..7483b2f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,7 +25,7 @@ jobs: with: go-version: ${{ matrix.go }} - run: go test -race -v -coverprofile=profile.cov -coverpkg=./pkg/... ./pkg/... - - uses: codecov/codecov-action@v3.1.1 + - uses: codecov/codecov-action@v3.1.2 with: file: ./profile.cov name: codecov-go