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 75942643..adb638ed 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 e4e5c6c8..42596741 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 b017023a..127db97a 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 0d9874e9..8dcfc7e9 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 cb513a09..167f8b78 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 2721e0b7..64f07f16 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 2abef362..78c0f797 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 e63e0e51..6b6945a1 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 7e1afbd5..acac5711 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 6e5ee321..07af903f 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 e36eac7a..590c4a03 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 58568a78..6dfc993d 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 127db97a..776e7586 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 8dcfc7e9..7377a843 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 bd498948..60cf8a47 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 5e9fb3df..dd9f5ad7 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 776e7586..5283eb59 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 7377a843..ef1e77f8 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 faab4e38..a574366d 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 a89d75ee..462ea447 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 b850053d..b8b99604 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 acac5711..a4c4f46d 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 b3120988..1f9fc459 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 af4724a8..9da44a7d 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 73b67cae..a397f141 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 6b6945a1..5c5cf20f 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 86718205..362443de 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 9da44a7d..04f8c0c7 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 04f8c0c7..32a3dd1f 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 1f9fc459..c2646055 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 7a9701bd..2bba4e7e 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 adb638ed..09c1f69b 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 42596741..e8e5db78 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 09c1f69b..f4e77f69 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 e8e5db78..8d3f108b 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 56044839..1dc8bd17 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 04c06f27..f7691ca6 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 69ba1024..cf94c3fd 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 ba3570bd..3e6377ff 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 ecb753ec..fc5262a0 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 9eda973e..f6a407bf 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 e19a7202..40e1bee9 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 a934f7d5..a220dc5c 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 ede74538..71270208 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 f4e77f69..5f96c729 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 8d3f108b..df4d60cd 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 78c0f797..7483b2f7 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