diff --git a/go.mod b/go.mod index 655aaf81ab54..610936b402b9 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,8 @@ go 1.23 toolchain go1.23.2 replace ( + github.com/coreos/go-oidc/v3 => github.com/ory/go-oidc/v3 v3.0.0-20241127113405-e5362711266b + github.com/go-swagger/go-swagger => github.com/aeneasr/go-swagger v0.19.1-0.20241013070044-bccef3a12e26 // See https://github.com/go-swagger/go-swagger/issues/3131 // github.com/go-swagger/go-swagger => ../../go-swagger/go-swagger // https://github.com/gobuffalo/pop/pull/833 @@ -95,10 +97,10 @@ require ( go.opentelemetry.io/otel v1.32.0 go.opentelemetry.io/otel/sdk v1.32.0 go.opentelemetry.io/otel/trace v1.32.0 - golang.org/x/crypto v0.28.0 + golang.org/x/crypto v0.29.0 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 - golang.org/x/net v0.30.0 - golang.org/x/oauth2 v0.23.0 + golang.org/x/net v0.31.0 + golang.org/x/oauth2 v0.24.0 golang.org/x/sync v0.9.0 golang.org/x/text v0.20.0 google.golang.org/grpc v1.67.1 @@ -113,9 +115,10 @@ require ( github.com/bmatcuk/doublestar v1.3.4 // indirect github.com/cortesi/moddwatch v0.1.0 // indirect github.com/cortesi/termlog v0.0.0-20210222042314-a1eec763abec // indirect + github.com/dgraph-io/ristretto/v2 v2.0.0 // indirect github.com/jackc/pgx/v5 v5.6.0 // indirect github.com/rjeczalik/notify v0.9.3 // indirect - golang.org/x/term v0.25.0 // indirect + golang.org/x/term v0.26.0 // indirect gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect mvdan.cc/sh/v3 v3.6.0 // indirect ) @@ -152,7 +155,7 @@ require ( github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/go-crypt/x v0.2.18 // indirect github.com/go-jose/go-jose/v3 v3.0.3 // indirect - github.com/go-jose/go-jose/v4 v4.0.2 // indirect + github.com/go-jose/go-jose/v4 v4.0.4 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.23.0 // indirect diff --git a/go.sum b/go.sum index cc07fbbdba0c..2c39e978d87a 100644 --- a/go.sum +++ b/go.sum @@ -108,8 +108,6 @@ github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7b github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= -github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI= -github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0= github.com/cortesi/modd v0.8.1 h1:0s8e10CJ6pxc6NQHYFrmUZOLP0X6v63ry+3na6Gq2Ow= github.com/cortesi/modd v0.8.1/go.mod h1:GDJFkhHnnW+SD1C+wHBlKe5Yh2IqiOb6Lu5t2/fjnS4= github.com/cortesi/moddwatch v0.1.0 h1:+TSMuplhKlKEPKsdUXNHd67aCqew+et15dJvRCxMd1M= @@ -132,6 +130,8 @@ github.com/dghubble/oauth1 v0.7.3 h1:EkEM/zMDMp3zOsX2DC/ZQ2vnEX3ELK0/l9kb+vs4ptE github.com/dghubble/oauth1 v0.7.3/go.mod h1:oxTe+az9NSMIucDPDCCtzJGsPhciJV33xocHfcR2sVY= github.com/dgraph-io/ristretto v1.0.0 h1:SYG07bONKMlFDUYu5pEu3DGAh8c2OFNzKm6G9J4Si84= github.com/dgraph-io/ristretto v1.0.0/go.mod h1:jTi2FiYEhQ1NsMmA7DeBykizjOuY88NhKBkepyu1jPc= +github.com/dgraph-io/ristretto/v2 v2.0.0 h1:l0yiSOtlJvc0otkqyMaDNysg8E9/F/TYZwMbxscNOAQ= +github.com/dgraph-io/ristretto/v2 v2.0.0/go.mod h1:FVFokF2dRqXyPyeMnK1YDy8Fc6aTe0IKgbcd03CYeEk= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= @@ -185,8 +185,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= -github.com/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk= -github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= +github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= +github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= @@ -621,6 +621,8 @@ github.com/ory/dockertest/v3 v3.11.0 h1:OiHcxKAvSDUwsEVh2BjxQQc/5EHz9n0va9awCtNG github.com/ory/dockertest/v3 v3.11.0/go.mod h1:VIPxS1gwT9NpPOrfD3rACs8Y9Z7yhzO4SB194iUDnUI= github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe h1:rvu4obdvqR0fkSIJ8IfgzKOWwZ5kOT2UNfLq81Qk7rc= github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe/go.mod h1:z4n3u6as84LbV4YmgjHhnwtccQqzf4cZlSk9f1FhygI= +github.com/ory/go-oidc/v3 v3.0.0-20241127113405-e5362711266b h1:PHfiybEhBiabSpPAD5Vq8BotzBrvCUgZN3OrAy3w5u8= +github.com/ory/go-oidc/v3 v3.0.0-20241127113405-e5362711266b/go.mod h1:Jxfv2TPRvdJuLfmkvokss8dkguhMmer2UvARU6SWy0Y= github.com/ory/graceful v0.1.4-0.20230301144740-e222150c51d0 h1:VMUeLRfQD14fOMvhpYZIIT4vtAqxYh+f3KnSqCeJ13o= github.com/ory/graceful v0.1.4-0.20230301144740-e222150c51d0/go.mod h1:hg2iCy+LCWOXahBZ+NQa4dk8J2govyQD79rrqrgMyY8= github.com/ory/herodot v0.10.3-0.20230626083119-d7e5192f0d88 h1:J0CIFKdpUeqKbVMw7pQ1qLtUnflRM1JWAcOEq7Hp4yg= @@ -864,8 +866,8 @@ golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4 golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -952,8 +954,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= -golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -962,8 +964,8 @@ golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= -golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= +golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1058,8 +1060,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= -golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= +golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= +golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/selfservice/strategy/oidc/provider.go b/selfservice/strategy/oidc/provider.go index 2241cb93d193..8d2e5edad189 100644 --- a/selfservice/strategy/oidc/provider.go +++ b/selfservice/strategy/oidc/provider.go @@ -20,24 +20,24 @@ import ( "github.com/ory/kratos/x" ) -type Provider interface { - Config() *Configuration -} - -type OAuth2Provider interface { - Provider - AuthCodeURLOptions(r ider) []oauth2.AuthCodeOption - OAuth2(ctx context.Context) (*oauth2.Config, error) - Claims(ctx context.Context, exchange *oauth2.Token, query url.Values) (*Claims, error) -} - -type OAuth1Provider interface { - Provider - OAuth1(ctx context.Context) *oauth1.Config - AuthURL(ctx context.Context, state string) (string, error) - Claims(ctx context.Context, token *oauth1.Token) (*Claims, error) - ExchangeToken(ctx context.Context, req *http.Request) (*oauth1.Token, error) -} +type ( + Provider interface { + Config() *Configuration + } + OAuth2Provider interface { + Provider + AuthCodeURLOptions(r ider) []oauth2.AuthCodeOption + OAuth2(ctx context.Context) (*oauth2.Config, error) + Claims(ctx context.Context, exchange *oauth2.Token, query url.Values) (*Claims, error) + } + OAuth1Provider interface { + Provider + OAuth1(ctx context.Context) *oauth1.Config + AuthURL(ctx context.Context, state string) (string, error) + Claims(ctx context.Context, token *oauth1.Token) (*Claims, error) + ExchangeToken(ctx context.Context, req *http.Request) (*oauth1.Token, error) + } +) type OAuth2TokenExchanger interface { Exchange(ctx context.Context, code string, opts ...oauth2.AuthCodeOption) (*oauth2.Token, error) @@ -51,22 +51,22 @@ type NonceValidationSkipper interface { CanSkipNonce(*Claims) bool } -// ConvertibleBoolean is used as Apple casually sends the email_verified field as a string. type Claims struct { - Issuer string `json:"iss,omitempty"` - Subject string `json:"sub,omitempty"` - Object string `json:"oid,omitempty"` - Name string `json:"name,omitempty"` - GivenName string `json:"given_name,omitempty"` - FamilyName string `json:"family_name,omitempty"` - LastName string `json:"last_name,omitempty"` - MiddleName string `json:"middle_name,omitempty"` - Nickname string `json:"nickname,omitempty"` - PreferredUsername string `json:"preferred_username,omitempty"` - Profile string `json:"profile,omitempty"` - Picture string `json:"picture,omitempty"` - Website string `json:"website,omitempty"` - Email string `json:"email,omitempty"` + Issuer string `json:"iss,omitempty"` + Subject string `json:"sub,omitempty"` + Object string `json:"oid,omitempty"` + Name string `json:"name,omitempty"` + GivenName string `json:"given_name,omitempty"` + FamilyName string `json:"family_name,omitempty"` + LastName string `json:"last_name,omitempty"` + MiddleName string `json:"middle_name,omitempty"` + Nickname string `json:"nickname,omitempty"` + PreferredUsername string `json:"preferred_username,omitempty"` + Profile string `json:"profile,omitempty"` + Picture string `json:"picture,omitempty"` + Website string `json:"website,omitempty"` + Email string `json:"email,omitempty"` + // ConvertibleBoolean is used as Apple casually sends the email_verified field as a string. EmailVerified x.ConvertibleBoolean `json:"email_verified,omitempty"` Gender string `json:"gender,omitempty"` Birthdate string `json:"birthdate,omitempty"` diff --git a/selfservice/strategy/oidc/provider_apple.go b/selfservice/strategy/oidc/provider_apple.go index 706a7150c5e4..7706eda9d9af 100644 --- a/selfservice/strategy/oidc/provider_apple.go +++ b/selfservice/strategy/oidc/provider_apple.go @@ -25,6 +25,8 @@ type ProviderApple struct { JWKSUrl string } +var _ OAuth2Provider = (*ProviderApple)(nil) + func NewProviderApple( config *Configuration, reg Dependencies, diff --git a/selfservice/strategy/oidc/provider_auth0.go b/selfservice/strategy/oidc/provider_auth0.go index a4c9ee46e1ab..50f4c03fc45b 100644 --- a/selfservice/strategy/oidc/provider_auth0.go +++ b/selfservice/strategy/oidc/provider_auth0.go @@ -29,6 +29,8 @@ type ProviderAuth0 struct { *ProviderGenericOIDC } +var _ OAuth2Provider = (*ProviderAuth0)(nil) + func NewProviderAuth0( config *Configuration, reg Dependencies, diff --git a/selfservice/strategy/oidc/provider_config.go b/selfservice/strategy/oidc/provider_config.go index 7e2b0b19dbfb..7b580f9bc10b 100644 --- a/selfservice/strategy/oidc/provider_config.go +++ b/selfservice/strategy/oidc/provider_config.go @@ -12,7 +12,6 @@ import ( "golang.org/x/exp/maps" "github.com/ory/herodot" - "github.com/ory/x/urlx" ) @@ -181,8 +180,7 @@ var supportedProviders = map[string]func(config *Configuration, reg Dependencies } func (c ConfigurationCollection) Provider(id string, reg Dependencies) (Provider, error) { - for k := range c.Providers { - p := c.Providers[k] + for _, p := range c.Providers { if p.ID == id { if f, ok := supportedProviders[p.Provider]; ok { return f(&p, reg), nil diff --git a/selfservice/strategy/oidc/provider_dingtalk.go b/selfservice/strategy/oidc/provider_dingtalk.go index 12abffe85942..466c7d76406d 100644 --- a/selfservice/strategy/oidc/provider_dingtalk.go +++ b/selfservice/strategy/oidc/provider_dingtalk.go @@ -25,6 +25,8 @@ type ProviderDingTalk struct { reg Dependencies } +var _ OAuth2Provider = (*ProviderDingTalk)(nil) + func NewProviderDingTalk( config *Configuration, reg Dependencies, diff --git a/selfservice/strategy/oidc/provider_discord.go b/selfservice/strategy/oidc/provider_discord.go index 99bea24d5770..97c64a4b414e 100644 --- a/selfservice/strategy/oidc/provider_discord.go +++ b/selfservice/strategy/oidc/provider_discord.go @@ -19,6 +19,8 @@ import ( "github.com/ory/x/stringsx" ) +var _ OAuth2Provider = (*ProviderDiscord)(nil) + type ProviderDiscord struct { config *Configuration reg Dependencies diff --git a/selfservice/strategy/oidc/provider_facebook.go b/selfservice/strategy/oidc/provider_facebook.go index 2f7a0a58aff0..a7d2ec689eaf 100644 --- a/selfservice/strategy/oidc/provider_facebook.go +++ b/selfservice/strategy/oidc/provider_facebook.go @@ -24,6 +24,8 @@ import ( "github.com/ory/herodot" ) +var _ OAuth2Provider = (*ProviderFacebook)(nil) + type ProviderFacebook struct { *ProviderGenericOIDC } diff --git a/selfservice/strategy/oidc/provider_generic_oidc.go b/selfservice/strategy/oidc/provider_generic_oidc.go index 146505165807..3bdb8d24ec31 100644 --- a/selfservice/strategy/oidc/provider_generic_oidc.go +++ b/selfservice/strategy/oidc/provider_generic_oidc.go @@ -6,17 +6,16 @@ package oidc import ( "context" "net/url" + "slices" + gooidc "github.com/coreos/go-oidc/v3/oidc" "github.com/pkg/errors" "golang.org/x/oauth2" - gooidc "github.com/coreos/go-oidc/v3/oidc" - "github.com/ory/herodot" - "github.com/ory/x/stringslice" ) -var _ Provider = new(ProviderGenericOIDC) +var _ OAuth2Provider = (*ProviderGenericOIDC)(nil) type ProviderGenericOIDC struct { p *gooidc.Provider @@ -60,7 +59,7 @@ func (g *ProviderGenericOIDC) provider(ctx context.Context) (*gooidc.Provider, e func (g *ProviderGenericOIDC) oauth2ConfigFromEndpoint(ctx context.Context, endpoint oauth2.Endpoint) *oauth2.Config { scope := g.config.Scope - if !stringslice.Has(scope, gooidc.ScopeOpenID) { + if !slices.Contains(scope, gooidc.ScopeOpenID) { scope = append(scope, gooidc.ScopeOpenID) } diff --git a/selfservice/strategy/oidc/provider_github.go b/selfservice/strategy/oidc/provider_github.go index fe1d2bc371d1..650778cd1506 100644 --- a/selfservice/strategy/oidc/provider_github.go +++ b/selfservice/strategy/oidc/provider_github.go @@ -23,6 +23,8 @@ import ( "github.com/ory/herodot" ) +var _ OAuth2Provider = (*ProviderGitHub)(nil) + type ProviderGitHub struct { config *Configuration reg Dependencies diff --git a/selfservice/strategy/oidc/provider_gitlab.go b/selfservice/strategy/oidc/provider_gitlab.go index 9ef55b4beef7..a0cf7508c944 100644 --- a/selfservice/strategy/oidc/provider_gitlab.go +++ b/selfservice/strategy/oidc/provider_gitlab.go @@ -25,6 +25,8 @@ const ( defaultEndpoint = "https://gitlab.com" ) +var _ OAuth2Provider = (*ProviderGitLab)(nil) + type ProviderGitLab struct { *ProviderGenericOIDC } diff --git a/selfservice/strategy/oidc/provider_google.go b/selfservice/strategy/oidc/provider_google.go index e27832692faa..4e009b318380 100644 --- a/selfservice/strategy/oidc/provider_google.go +++ b/selfservice/strategy/oidc/provider_google.go @@ -12,6 +12,8 @@ import ( "github.com/ory/x/stringslice" ) +var _ OAuth2Provider = (*ProviderGoogle)(nil) + type ProviderGoogle struct { *ProviderGenericOIDC JWKSUrl string diff --git a/selfservice/strategy/oidc/provider_lark.go b/selfservice/strategy/oidc/provider_lark.go index 52902dc20e8c..d66d5c0b2230 100644 --- a/selfservice/strategy/oidc/provider_lark.go +++ b/selfservice/strategy/oidc/provider_lark.go @@ -16,6 +16,8 @@ import ( "github.com/ory/x/httpx" ) +var _ OAuth2Provider = (*ProviderLark)(nil) + type ProviderLark struct { *ProviderGenericOIDC } diff --git a/selfservice/strategy/oidc/provider_linkedin.go b/selfservice/strategy/oidc/provider_linkedin.go index 03a3db3e490d..475dd738b29f 100644 --- a/selfservice/strategy/oidc/provider_linkedin.go +++ b/selfservice/strategy/oidc/provider_linkedin.go @@ -63,6 +63,8 @@ const ( IntrospectionURL string = "https://www.linkedin.com/oauth/v2/introspectToken" ) +var _ OAuth2Provider = (*ProviderLinkedIn)(nil) + type ProviderLinkedIn struct { config *Configuration reg Dependencies diff --git a/selfservice/strategy/oidc/provider_microsoft.go b/selfservice/strategy/oidc/provider_microsoft.go index ec634ce75e3e..408a11096573 100644 --- a/selfservice/strategy/oidc/provider_microsoft.go +++ b/selfservice/strategy/oidc/provider_microsoft.go @@ -9,20 +9,19 @@ import ( "net/url" "strings" - "github.com/hashicorp/go-retryablehttp" - - "github.com/ory/x/httpx" - + gooidc "github.com/coreos/go-oidc/v3/oidc" "github.com/gofrs/uuid" "github.com/golang-jwt/jwt/v4" - - gooidc "github.com/coreos/go-oidc/v3/oidc" + "github.com/hashicorp/go-retryablehttp" "github.com/pkg/errors" "golang.org/x/oauth2" "github.com/ory/herodot" + "github.com/ory/x/httpx" ) +var _ OAuth2Provider = (*ProviderMicrosoft)(nil) + type ProviderMicrosoft struct { *ProviderGenericOIDC } @@ -40,7 +39,7 @@ func NewProviderMicrosoft( } func (m *ProviderMicrosoft) OAuth2(ctx context.Context) (*oauth2.Config, error) { - if len(strings.TrimSpace(m.config.Tenant)) == 0 { + if strings.TrimSpace(m.config.Tenant) == "" { return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("No Tenant specified for the `microsoft` oidc provider %s", m.config.ID)) } @@ -53,7 +52,7 @@ func (m *ProviderMicrosoft) OAuth2(ctx context.Context) (*oauth2.Config, error) return m.oauth2ConfigFromEndpoint(ctx, endpoint), nil } -func (m *ProviderMicrosoft) Claims(ctx context.Context, exchange *oauth2.Token, query url.Values) (*Claims, error) { +func (m *ProviderMicrosoft) Claims(ctx context.Context, exchange *oauth2.Token, _ url.Values) (*Claims, error) { raw, ok := exchange.Extra("id_token").(string) if !ok || len(raw) == 0 { return nil, errors.WithStack(ErrIDTokenMissing) diff --git a/selfservice/strategy/oidc/provider_netid.go b/selfservice/strategy/oidc/provider_netid.go index dfe83c958433..d936bf1b361c 100644 --- a/selfservice/strategy/oidc/provider_netid.go +++ b/selfservice/strategy/oidc/provider_netid.go @@ -8,11 +8,10 @@ import ( "encoding/json" "fmt" "net/url" + "slices" gooidc "github.com/coreos/go-oidc/v3/oidc" - "github.com/ory/x/stringslice" - "github.com/hashicorp/go-retryablehttp" "github.com/pkg/errors" "golang.org/x/oauth2" @@ -28,6 +27,8 @@ const ( defaultBrokerHost = "broker.netid.de" ) +var _ OAuth2Provider = (*ProviderNetID)(nil) + type ProviderNetID struct { *ProviderGenericOIDC } @@ -37,7 +38,7 @@ func NewProviderNetID( reg Dependencies, ) Provider { config.IssuerURL = fmt.Sprintf("%s://%s/", defaultBrokerScheme, defaultBrokerHost) - if !stringslice.Has(config.Scope, gooidc.ScopeOpenID) { + if !slices.Contains(config.Scope, gooidc.ScopeOpenID) { config.Scope = append(config.Scope, gooidc.ScopeOpenID) } diff --git a/selfservice/strategy/oidc/provider_patreon.go b/selfservice/strategy/oidc/provider_patreon.go index 745dc8fcc199..d89e1e2a3ebc 100644 --- a/selfservice/strategy/oidc/provider_patreon.go +++ b/selfservice/strategy/oidc/provider_patreon.go @@ -18,6 +18,8 @@ import ( "github.com/ory/herodot" ) +var _ OAuth2Provider = (*ProviderPatreon)(nil) + type ProviderPatreon struct { config *Configuration reg Dependencies diff --git a/selfservice/strategy/oidc/provider_salesforce.go b/selfservice/strategy/oidc/provider_salesforce.go index 1d028a1a8de7..04d514ccdf22 100644 --- a/selfservice/strategy/oidc/provider_salesforce.go +++ b/selfservice/strategy/oidc/provider_salesforce.go @@ -25,6 +25,8 @@ import ( "github.com/ory/herodot" ) +var _ OAuth2Provider = (*ProviderSalesforce)(nil) + type ProviderSalesforce struct { *ProviderGenericOIDC } diff --git a/selfservice/strategy/oidc/provider_slack.go b/selfservice/strategy/oidc/provider_slack.go index 7c7e26c99da4..0faed2220ae5 100644 --- a/selfservice/strategy/oidc/provider_slack.go +++ b/selfservice/strategy/oidc/provider_slack.go @@ -19,6 +19,8 @@ import ( "github.com/slack-go/slack" ) +var _ OAuth2Provider = (*ProviderSlack)(nil) + type ProviderSlack struct { config *Configuration reg Dependencies diff --git a/selfservice/strategy/oidc/provider_spotify.go b/selfservice/strategy/oidc/provider_spotify.go index 366105c94d0e..2c01d0764b3c 100644 --- a/selfservice/strategy/oidc/provider_spotify.go +++ b/selfservice/strategy/oidc/provider_spotify.go @@ -23,6 +23,8 @@ import ( "github.com/ory/herodot" ) +var _ OAuth2Provider = (*ProviderSpotify)(nil) + type ProviderSpotify struct { config *Configuration reg Dependencies diff --git a/selfservice/strategy/oidc/provider_userinfo_test.go b/selfservice/strategy/oidc/provider_userinfo_test.go index dde2507af319..9eb27914541e 100644 --- a/selfservice/strategy/oidc/provider_userinfo_test.go +++ b/selfservice/strategy/oidc/provider_userinfo_test.go @@ -349,14 +349,13 @@ func TestProviderClaimsRespectsErrorCodes(t *testing.T) { } httpmock.RegisterResponder("GET", tc.userInfoEndpoint, func(req *http.Request) (*http.Response, error) { - resp, err := httpmock.NewJsonResponse(455, map[string]interface{}{}) - return resp, err + return httpmock.NewJsonResponse(455, map[string]interface{}{}) }) _, err := tc.provider.(oidc.OAuth2Provider).Claims(ctx, token, url.Values{}) var he *herodot.DefaultError require.ErrorAs(t, err, &he) - assert.Equal(t, "OpenID Connect provider returned a 455 status code but 200 is expected.", he.Reason()) + assert.Equal(t, "OpenID Connect provider returned a 455 status code but 200 is expected.", he.Reason(), "%+v", err) }) t.Run("call is successful", func(t *testing.T) { diff --git a/selfservice/strategy/oidc/provider_vk.go b/selfservice/strategy/oidc/provider_vk.go index 2a3513b6e050..c60711504fd3 100644 --- a/selfservice/strategy/oidc/provider_vk.go +++ b/selfservice/strategy/oidc/provider_vk.go @@ -19,6 +19,8 @@ import ( "github.com/ory/herodot" ) +var _ OAuth2Provider = (*ProviderVK)(nil) + type ProviderVK struct { config *Configuration reg Dependencies diff --git a/selfservice/strategy/oidc/provider_x.go b/selfservice/strategy/oidc/provider_x.go index f58dbd48182f..ca2acb6c5e25 100644 --- a/selfservice/strategy/oidc/provider_x.go +++ b/selfservice/strategy/oidc/provider_x.go @@ -18,7 +18,6 @@ import ( "github.com/ory/herodot" ) -var _ Provider = (*ProviderX)(nil) var _ OAuth1Provider = (*ProviderX)(nil) const xUserInfoBase = "https://api.twitter.com/1.1/account/verify_credentials.json" diff --git a/selfservice/strategy/oidc/provider_yandex.go b/selfservice/strategy/oidc/provider_yandex.go index 07b30caee52b..9b11b8fbcf5e 100644 --- a/selfservice/strategy/oidc/provider_yandex.go +++ b/selfservice/strategy/oidc/provider_yandex.go @@ -17,6 +17,8 @@ import ( "github.com/ory/herodot" ) +var _ OAuth2Provider = (*ProviderYandex)(nil) + type ProviderYandex struct { config *Configuration reg Dependencies diff --git a/selfservice/strategy/oidc/strategy.go b/selfservice/strategy/oidc/strategy.go index f2837e769b73..d799c9190dcd 100644 --- a/selfservice/strategy/oidc/strategy.go +++ b/selfservice/strategy/oidc/strategy.go @@ -14,39 +14,20 @@ import ( "strings" "time" - "github.com/ory/x/sqlxx" - - "golang.org/x/exp/maps" - - "github.com/ory/x/urlx" - - "go.opentelemetry.io/otel/attribute" - "golang.org/x/oauth2" - - "github.com/ory/kratos/cipher" - oidcv1 "github.com/ory/kratos/gen/oidc/v1" - "github.com/ory/kratos/selfservice/sessiontokenexchange" - "github.com/ory/x/jsonnetsecure" - "github.com/ory/x/otelx" - - "github.com/ory/kratos/text" - - "github.com/ory/kratos/ui/container" - "github.com/ory/x/decoderx" - "github.com/ory/x/stringsx" - - "github.com/ory/kratos/ui/node" - "github.com/gofrs/uuid" "github.com/julienschmidt/httprouter" "github.com/pkg/errors" "github.com/tidwall/gjson" - - "github.com/ory/x/jsonx" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" + "golang.org/x/exp/maps" + "golang.org/x/oauth2" "github.com/ory/herodot" + "github.com/ory/kratos/cipher" "github.com/ory/kratos/continuity" "github.com/ory/kratos/driver/config" + oidcv1 "github.com/ory/kratos/gen/oidc/v1" "github.com/ory/kratos/identity" "github.com/ory/kratos/schema" "github.com/ory/kratos/selfservice/errorx" @@ -54,10 +35,20 @@ import ( "github.com/ory/kratos/selfservice/flow/login" "github.com/ory/kratos/selfservice/flow/registration" "github.com/ory/kratos/selfservice/flow/settings" - + "github.com/ory/kratos/selfservice/sessiontokenexchange" "github.com/ory/kratos/selfservice/strategy" "github.com/ory/kratos/session" + "github.com/ory/kratos/text" + "github.com/ory/kratos/ui/container" + "github.com/ory/kratos/ui/node" "github.com/ory/kratos/x" + "github.com/ory/x/decoderx" + "github.com/ory/x/jsonnetsecure" + "github.com/ory/x/jsonx" + "github.com/ory/x/otelx" + "github.com/ory/x/sqlxx" + "github.com/ory/x/stringsx" + "github.com/ory/x/urlx" ) const ( @@ -375,7 +366,7 @@ func (s *Strategy) HandleCallback(w http.ResponseWriter, r *http.Request, ps htt ) ctx := context.WithValue(r.Context(), httprouter.ParamsKey, ps) - ctx, span := s.d.Tracer(ctx).Tracer().Start(ctx, "strategy.oidc.ExchangeCode") + ctx, span := s.d.Tracer(ctx).Tracer().Start(ctx, "strategy.oidc.HandleCallback") defer otelx.End(span, &err) r = r.WithContext(ctx) @@ -405,7 +396,7 @@ func (s *Strategy) HandleCallback(w http.ResponseWriter, r *http.Request, ps htt var et *identity.CredentialsOIDCEncryptedTokens switch p := provider.(type) { case OAuth2Provider: - token, err := s.ExchangeCode(ctx, provider, code, PKCEVerifier(state)) + token, err := s.exchangeCode(ctx, p, code, PKCEVerifier(state)) if err != nil { s.forwardError(ctx, w, r, req, s.handleError(ctx, w, r, req, state.ProviderId, nil, err)) return @@ -489,29 +480,24 @@ func (s *Strategy) HandleCallback(w http.ResponseWriter, r *http.Request, ps htt } } -func (s *Strategy) ExchangeCode(ctx context.Context, provider Provider, code string, opts []oauth2.AuthCodeOption) (token *oauth2.Token, err error) { - ctx, span := s.d.Tracer(ctx).Tracer().Start(ctx, "strategy.oidc.ExchangeCode") +func (s *Strategy) exchangeCode(ctx context.Context, provider OAuth2Provider, code string, opts []oauth2.AuthCodeOption) (token *oauth2.Token, err error) { + ctx, span := s.d.Tracer(ctx).Tracer().Start(ctx, "strategy.oidc.exchangeCode", trace.WithAttributes( + attribute.String("provider_id", provider.Config().ID), + attribute.String("provider_label", provider.Config().Label))) defer otelx.End(span, &err) - span.SetAttributes(attribute.String("provider_id", provider.Config().ID)) - span.SetAttributes(attribute.String("provider_label", provider.Config().Label)) - switch p := provider.(type) { - case OAuth2Provider: - te, ok := provider.(OAuth2TokenExchanger) - if !ok { - te, err = p.OAuth2(ctx) - if err != nil { - return nil, err - } + te, ok := provider.(OAuth2TokenExchanger) + if !ok { + te, err = provider.OAuth2(ctx) + if err != nil { + return nil, err } - - client := s.d.HTTPClient(ctx) - ctx = context.WithValue(ctx, oauth2.HTTPClient, client.HTTPClient) - token, err = te.Exchange(ctx, code, opts...) - return token, err - default: - return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("The chosen provider is not capable of exchanging an OAuth 2.0 code for an access token.")) } + + client := s.d.HTTPClient(ctx) + ctx = context.WithValue(ctx, oauth2.HTTPClient, client.HTTPClient) + token, err = te.Exchange(ctx, code, opts...) + return token, err } func (s *Strategy) populateMethod(r *http.Request, f flow.Flow, message func(provider string, providerId string) *text.Message) error {