From 777eeafabc3467dc8398069e3695d26fe2fa4f89 Mon Sep 17 00:00:00 2001 From: Eric Chiang Date: Wed, 8 Mar 2017 10:33:19 -0800 Subject: [PATCH 1/2] *: update go-oidc and use standard library's context package --- cmd/dex/serve.go | 2 +- cmd/example-app/main.go | 4 ++-- connector/connector.go | 3 +-- connector/github/github.go | 2 +- connector/gitlab/gitlab.go | 2 +- connector/ldap/ldap.go | 2 +- connector/mock/connectortest.go | 3 +-- connector/oidc/oidc.go | 6 +++--- glide.yaml | 3 +-- server/api.go | 3 +++ server/handlers_test.go | 3 +-- server/rotation.go | 2 +- server/server.go | 2 +- server/server_test.go | 19 ++++++++++++------- storage/kubernetes/client.go | 2 +- storage/kubernetes/storage.go | 4 ++-- 16 files changed, 33 insertions(+), 29 deletions(-) diff --git a/cmd/dex/serve.go b/cmd/dex/serve.go index 6c708c4e..08d9fdb0 100644 --- a/cmd/dex/serve.go +++ b/cmd/dex/serve.go @@ -1,6 +1,7 @@ package main import ( + "context" "crypto/tls" "crypto/x509" "errors" @@ -15,7 +16,6 @@ import ( "github.com/Sirupsen/logrus" "github.com/ghodss/yaml" "github.com/spf13/cobra" - "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/credentials" diff --git a/cmd/example-app/main.go b/cmd/example-app/main.go index 3ec34e38..4da34b9a 100644 --- a/cmd/example-app/main.go +++ b/cmd/example-app/main.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "context" "crypto/tls" "crypto/x509" "encoding/json" @@ -19,7 +20,6 @@ import ( "github.com/coreos/go-oidc" "github.com/spf13/cobra" - "golang.org/x/net/context" "golang.org/x/oauth2" ) @@ -175,7 +175,7 @@ func cmd() *cobra.Command { } a.provider = provider - a.verifier = provider.Verifier(oidc.VerifyAudience(a.clientID)) + a.verifier = provider.Verifier(&oidc.Config{ClientID: a.clientID}) http.HandleFunc("/", a.handleIndex) http.HandleFunc("/login", a.handleLogin) diff --git a/connector/connector.go b/connector/connector.go index c92d7589..fde38a24 100644 --- a/connector/connector.go +++ b/connector/connector.go @@ -2,9 +2,8 @@ package connector import ( + "context" "net/http" - - "golang.org/x/net/context" ) // Connector is a mechanism for federating login to a remote identity service. diff --git a/connector/github/github.go b/connector/github/github.go index f6dbdfee..49dc3bb3 100644 --- a/connector/github/github.go +++ b/connector/github/github.go @@ -2,6 +2,7 @@ package github import ( + "context" "encoding/json" "errors" "fmt" @@ -10,7 +11,6 @@ import ( "regexp" "strconv" - "golang.org/x/net/context" "golang.org/x/oauth2" "golang.org/x/oauth2/github" diff --git a/connector/gitlab/gitlab.go b/connector/gitlab/gitlab.go index 0fcc3d26..b0f10cf1 100644 --- a/connector/gitlab/gitlab.go +++ b/connector/gitlab/gitlab.go @@ -2,6 +2,7 @@ package gitlab import ( + "context" "encoding/json" "errors" "fmt" @@ -12,7 +13,6 @@ import ( "github.com/Sirupsen/logrus" "github.com/coreos/dex/connector" - "golang.org/x/net/context" "golang.org/x/oauth2" ) diff --git a/connector/ldap/ldap.go b/connector/ldap/ldap.go index c5e45d37..df3d4c9d 100644 --- a/connector/ldap/ldap.go +++ b/connector/ldap/ldap.go @@ -2,6 +2,7 @@ package ldap import ( + "context" "crypto/tls" "crypto/x509" "encoding/json" @@ -9,7 +10,6 @@ import ( "io/ioutil" "net" - "golang.org/x/net/context" "gopkg.in/ldap.v2" "github.com/Sirupsen/logrus" diff --git a/connector/mock/connectortest.go b/connector/mock/connectortest.go index b754705b..ef7749f7 100644 --- a/connector/mock/connectortest.go +++ b/connector/mock/connectortest.go @@ -2,13 +2,12 @@ package mock import ( + "context" "errors" "fmt" "net/http" "net/url" - "golang.org/x/net/context" - "github.com/Sirupsen/logrus" "github.com/coreos/dex/connector" ) diff --git a/connector/oidc/oidc.go b/connector/oidc/oidc.go index 6a8b6f98..728bdf6a 100644 --- a/connector/oidc/oidc.go +++ b/connector/oidc/oidc.go @@ -2,13 +2,13 @@ package oidc import ( + "context" "errors" "fmt" "net/http" "github.com/Sirupsen/logrus" "github.com/coreos/go-oidc" - "golang.org/x/net/context" "golang.org/x/oauth2" "github.com/coreos/dex/connector" @@ -53,10 +53,10 @@ func (c *Config) Open(logger logrus.FieldLogger) (conn connector.Connector, err RedirectURL: c.RedirectURI, }, verifier: provider.Verifier( - oidc.VerifyExpiry(), - oidc.VerifyAudience(clientID), + &oidc.Config{ClientID: clientID}, ), logger: logger, + cancel: cancel, }, nil } diff --git a/glide.yaml b/glide.yaml index c6d1991f..07337a1d 100644 --- a/glide.yaml +++ b/glide.yaml @@ -35,7 +35,6 @@ import: version: 6a513affb38dc9788b449d59ffed099b8de18fa0 subpackages: - context - - context/ctxhttp - http2 - http2/hpack - internal/timeseries @@ -68,7 +67,7 @@ import: # Used for server integration tests and OpenID Connect connector. - package: github.com/coreos/go-oidc - version: 2b5d73091ea4b7ddb15e3ac00077f153120b5b61 + version: be73733bb8cc830d0205609b95d125215f8e9c70 - package: github.com/pquerna/cachecontrol version: c97913dcbd76de40b051a9b4cd827f7eaeb7a868 - package: golang.org/x/oauth2 diff --git a/server/api.go b/server/api.go index 25655d68..0e7c5b2f 100644 --- a/server/api.go +++ b/server/api.go @@ -5,6 +5,9 @@ import ( "fmt" "golang.org/x/crypto/bcrypt" + + // go-grpc doesn't use the standard library's context. + // https://github.com/grpc/grpc-go/issues/711 "golang.org/x/net/context" "github.com/Sirupsen/logrus" diff --git a/server/handlers_test.go b/server/handlers_test.go index 233af279..4c410b8e 100644 --- a/server/handlers_test.go +++ b/server/handlers_test.go @@ -1,11 +1,10 @@ package server import ( + "context" "net/http" "net/http/httptest" "testing" - - "golang.org/x/net/context" ) func TestHandleHealth(t *testing.T) { diff --git a/server/rotation.go b/server/rotation.go index fb790c62..5619b3a7 100644 --- a/server/rotation.go +++ b/server/rotation.go @@ -1,6 +1,7 @@ package server import ( + "context" "crypto/rand" "crypto/rsa" "encoding/hex" @@ -9,7 +10,6 @@ import ( "io" "time" - "golang.org/x/net/context" "gopkg.in/square/go-jose.v2" "github.com/Sirupsen/logrus" diff --git a/server/server.go b/server/server.go index 012802f2..68fe0915 100644 --- a/server/server.go +++ b/server/server.go @@ -1,6 +1,7 @@ package server import ( + "context" "errors" "fmt" "net/http" @@ -10,7 +11,6 @@ import ( "time" "golang.org/x/crypto/bcrypt" - "golang.org/x/net/context" "github.com/Sirupsen/logrus" "github.com/gorilla/handlers" diff --git a/server/server_test.go b/server/server_test.go index 688c606e..2fd0229b 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -1,6 +1,7 @@ package server import ( + "context" "crypto/rsa" "crypto/x509" "encoding/json" @@ -24,7 +25,6 @@ import ( oidc "github.com/coreos/go-oidc" "github.com/kylelemons/godebug/pretty" "golang.org/x/crypto/bcrypt" - "golang.org/x/net/context" "golang.org/x/oauth2" jose "gopkg.in/square/go-jose.v2" @@ -175,6 +175,8 @@ func TestOAuth2CodeFlow(t *testing.T) { // Connector used by the tests. var conn *mock.Callback + oidcConfig := &oidc.Config{SkipClientIDCheck: true} + tests := []struct { name string // If specified these set of scopes will be used during the test case. @@ -189,7 +191,7 @@ func TestOAuth2CodeFlow(t *testing.T) { if !ok { return fmt.Errorf("no id token found") } - if _, err := p.Verifier().Verify(ctx, idToken); err != nil { + if _, err := p.Verifier(oidcConfig).Verify(ctx, idToken); err != nil { return fmt.Errorf("failed to verify id token: %v", err) } return nil @@ -212,7 +214,7 @@ func TestOAuth2CodeFlow(t *testing.T) { if !ok { return fmt.Errorf("no id token found") } - idToken, err := p.Verifier().Verify(ctx, rawIDToken) + idToken, err := p.Verifier(oidcConfig).Verify(ctx, rawIDToken) if err != nil { return fmt.Errorf("failed to verify id token: %v", err) } @@ -229,7 +231,7 @@ func TestOAuth2CodeFlow(t *testing.T) { if !ok { return fmt.Errorf("no id token found") } - idToken, err := p.Verifier().Verify(ctx, rawIDToken) + idToken, err := p.Verifier(oidcConfig).Verify(ctx, rawIDToken) if err != nil { return fmt.Errorf("failed to verify id token: %v", err) } @@ -391,7 +393,7 @@ func TestOAuth2CodeFlow(t *testing.T) { if !ok { return fmt.Errorf("no id_token in refreshed token") } - idToken, err := p.Verifier().Verify(ctx, rawIDToken) + idToken, err := p.Verifier(oidcConfig).Verify(ctx, rawIDToken) if err != nil { return fmt.Errorf("failed to verify id token: %v", err) } @@ -632,7 +634,10 @@ func TestOAuth2ImplicitFlow(t *testing.T) { src := &nonceSource{nonce: nonce} - idTokenVerifier := p.Verifier(oidc.VerifyAudience(client.ID), oidc.VerifyNonce(src)) + idTokenVerifier := p.Verifier(&oidc.Config{ + ClientID: client.ID, + ClaimNonce: src.ClaimNonce, + }) oauth2Config = &oauth2.Config{ ClientID: client.ID, @@ -749,7 +754,7 @@ func TestCrossClientScopes(t *testing.T) { t.Errorf("no id token found: %v", err) return } - idToken, err := p.Verifier().Verify(ctx, rawIDToken) + idToken, err := p.Verifier(&oidc.Config{ClientID: testClientID}).Verify(ctx, rawIDToken) if err != nil { t.Errorf("failed to parse ID Token: %v", err) return diff --git a/storage/kubernetes/client.go b/storage/kubernetes/client.go index 1f562165..f61c37db 100644 --- a/storage/kubernetes/client.go +++ b/storage/kubernetes/client.go @@ -2,6 +2,7 @@ package kubernetes import ( "bytes" + "context" "crypto/tls" "crypto/x509" "encoding/base32" @@ -24,7 +25,6 @@ import ( "github.com/Sirupsen/logrus" "github.com/ghodss/yaml" "github.com/gtank/cryptopasta" - "golang.org/x/net/context" "golang.org/x/net/http2" "github.com/coreos/dex/storage" diff --git a/storage/kubernetes/storage.go b/storage/kubernetes/storage.go index 788d08b1..5b8721f3 100644 --- a/storage/kubernetes/storage.go +++ b/storage/kubernetes/storage.go @@ -1,13 +1,12 @@ package kubernetes import ( + "context" "errors" "fmt" "strings" "time" - "golang.org/x/net/context" - "github.com/Sirupsen/logrus" "github.com/coreos/dex/storage" "github.com/coreos/dex/storage/kubernetes/k8sapi" @@ -85,6 +84,7 @@ func (c *Config) open(logger logrus.FieldLogger, errOnTPRs bool) (*client, error if !cli.createThirdPartyResources() { if errOnTPRs { + cancel() return nil, fmt.Errorf("failed creating third party resources") } From e5f60fe9ddc52c954fbb4c2722af450e7ff72b2a Mon Sep 17 00:00:00 2001 From: Eric Chiang Date: Wed, 8 Mar 2017 10:33:36 -0800 Subject: [PATCH 2/2] vendor: revendor --- glide.lock | 7 +- vendor/github.com/coreos/go-oidc/jwks.go | 5 +- vendor/github.com/coreos/go-oidc/oidc.go | 46 +++-- vendor/github.com/coreos/go-oidc/verify.go | 192 ++++++++---------- .../x/net/context/ctxhttp/ctxhttp.go | 74 ------- .../x/net/context/ctxhttp/ctxhttp_pre17.go | 147 -------------- 6 files changed, 120 insertions(+), 351 deletions(-) delete mode 100644 vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go delete mode 100644 vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go diff --git a/glide.lock b/glide.lock index 3edb6fb3..97eb92d5 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 1207c251a7dab3b824746d66219beabc40f0b1d3c08ed90ac50f5bbdb8872631 -updated: 2017-01-25T20:32:43.599648533+01:00 +hash: fbef1f81a0f86f519714bbe568692a92709c446ef487a3fa9875e58f86e14430 +updated: 2017-03-08T10:31:06.364335442-08:00 imports: - name: github.com/beevik/etree version: 4cd0dd976db869f817248477718071a28e978df0 @@ -8,7 +8,7 @@ imports: subpackages: - crdb - name: github.com/coreos/go-oidc - version: 2b5d73091ea4b7ddb15e3ac00077f153120b5b61 + version: be73733bb8cc830d0205609b95d125215f8e9c70 - name: github.com/ghodss/yaml version: bea76d6a4713e18b7f5321a2b020738552def3ea - name: github.com/go-sql-driver/mysql @@ -62,7 +62,6 @@ imports: version: 6a513affb38dc9788b449d59ffed099b8de18fa0 subpackages: - context - - context/ctxhttp - http2 - http2/hpack - internal/timeseries diff --git a/vendor/github.com/coreos/go-oidc/jwks.go b/vendor/github.com/coreos/go-oidc/jwks.go index 413f392f..0f3cf0c9 100644 --- a/vendor/github.com/coreos/go-oidc/jwks.go +++ b/vendor/github.com/coreos/go-oidc/jwks.go @@ -1,6 +1,7 @@ package oidc import ( + "context" "encoding/json" "fmt" "io/ioutil" @@ -9,8 +10,6 @@ import ( "time" "github.com/pquerna/cachecontrol" - "golang.org/x/net/context" - "golang.org/x/net/context/ctxhttp" jose "gopkg.in/square/go-jose.v2" ) @@ -163,7 +162,7 @@ func (r *remoteKeySet) updateKeys(ctx context.Context) error { return fmt.Errorf("oidc: can't create request: %v", err) } - resp, err := ctxhttp.Do(ctx, clientFromContext(ctx), req) + resp, err := doRequest(ctx, req) if err != nil { return fmt.Errorf("oidc: get keys failed %v", err) } diff --git a/vendor/github.com/coreos/go-oidc/oidc.go b/vendor/github.com/coreos/go-oidc/oidc.go index 62be15d3..a14dca0c 100644 --- a/vendor/github.com/coreos/go-oidc/oidc.go +++ b/vendor/github.com/coreos/go-oidc/oidc.go @@ -2,6 +2,7 @@ package oidc import ( + "context" "encoding/json" "errors" "fmt" @@ -10,8 +11,6 @@ import ( "strings" "time" - "golang.org/x/net/context" - "golang.org/x/net/context/ctxhttp" "golang.org/x/oauth2" jose "gopkg.in/square/go-jose.v2" ) @@ -46,11 +45,12 @@ func ClientContext(ctx context.Context, client *http.Client) context.Context { return context.WithValue(ctx, oauth2.HTTPClient, client) } -func clientFromContext(ctx context.Context) *http.Client { - if client, ok := ctx.Value(oauth2.HTTPClient).(*http.Client); ok { - return client +func doRequest(ctx context.Context, req *http.Request) (*http.Response, error) { + client := http.DefaultClient + if c, ok := ctx.Value(oauth2.HTTPClient).(*http.Client); ok { + client = c } - return http.DefaultClient + return client.Do(req.WithContext(ctx)) } // Provider represents an OpenID Connect server's configuration. @@ -85,7 +85,11 @@ type providerJSON struct { // or "https://login.salesforce.com". func NewProvider(ctx context.Context, issuer string) (*Provider, error) { wellKnown := strings.TrimSuffix(issuer, "/") + "/.well-known/openid-configuration" - resp, err := ctxhttp.Get(ctx, clientFromContext(ctx), wellKnown) + req, err := http.NewRequest("GET", wellKnown, nil) + if err != nil { + return nil, err + } + resp, err := doRequest(ctx, req) if err != nil { return nil, err } @@ -174,7 +178,7 @@ func (p *Provider) UserInfo(ctx context.Context, tokenSource oauth2.TokenSource) } token.SetAuthHeader(req) - resp, err := ctxhttp.Do(ctx, clientFromContext(ctx), req) + resp, err := doRequest(ctx, req) if err != nil { return nil, err } @@ -201,19 +205,35 @@ func (p *Provider) UserInfo(ctx context.Context, tokenSource oauth2.TokenSource) // The ID Token only holds fields OpenID Connect requires. To access additional // claims returned by the server, use the Claims method. type IDToken struct { - // The URL of the server which issued this token. This will always be the same - // as the URL used for initial discovery. + // The URL of the server which issued this token. OpenID Connect + // requires this value always be identical to the URL used for + // initial discovery. + // + // Note: Because of a known issue with Google Accounts' implementation + // this value may differ when using Google. + // + // See: https://developers.google.com/identity/protocols/OpenIDConnect#obtainuserinfo Issuer string - // The client, or set of clients, that this token is issued for. + // The client ID, or set of client IDs, that this token is issued for. For + // common uses, this is the client that initialized the auth flow. + // + // This package ensures the audience contains an expected value. Audience []string // A unique string which identifies the end user. Subject string + // Expiry of the token. Ths package will not process tokens that have + // expired unless that validation is explicitly turned off. + Expiry time.Time + // When the token was issued by the provider. IssuedAt time.Time - Expiry time.Time - Nonce string + + // Initial nonce provided during the authentication redirect. + // + // If present, this package ensures this is a valid nonce. + Nonce string // Raw payload of the id_token. claims []byte diff --git a/vendor/github.com/coreos/go-oidc/verify.go b/vendor/github.com/coreos/go-oidc/verify.go index 67185a26..2b67aa9c 100644 --- a/vendor/github.com/coreos/go-oidc/verify.go +++ b/vendor/github.com/coreos/go-oidc/verify.go @@ -2,6 +2,7 @@ package oidc import ( "bytes" + "context" "encoding/base64" "encoding/json" "errors" @@ -9,61 +10,71 @@ import ( "strings" "time" - "golang.org/x/net/context" "golang.org/x/oauth2" jose "gopkg.in/square/go-jose.v2" ) +const ( + issuerGoogleAccounts = "https://accounts.google.com" + issuerGoogleAccountsNoScheme = "accounts.google.com" +) + // IDTokenVerifier provides verification for ID Tokens. type IDTokenVerifier struct { keySet *remoteKeySet - config *verificationConfig -} - -// verificationConfig is the unexported configuration for an IDTokenVerifier. -// -// Users interact with this struct using a VerificationOption. -type verificationConfig struct { + config *Config issuer string - // If provided, this value must be in the ID Token audiences. - audience string - // If not nil, check the expiry of the id token. - checkExpiry func() time.Time - // If specified, only these sets of algorithms may be used to sign the JWT. - requiredAlgs []string - // If not nil, don't verify nonce. - nonceSource NonceSource } -// VerificationOption provides additional checks on ID Tokens. -type VerificationOption interface { - // Unexport this method so other packages can't implement this interface. - updateConfig(c *verificationConfig) +// Config is the configuration for an IDTokenVerifier. +type Config struct { + // Expected audience of the token. For a majority of the cases this is expected to be + // the ID of the client that initialized the login flow. It may occasionally differ if + // the provider supports the authorizing party (azp) claim. + // + // If not provided, users must explicitly set SkipClientIDCheck. + ClientID string + // Method to verify the ID Token nonce. If a nonce is present and this method + // is nil, users must explicitly set SkipNonceCheck. + // + // If the ID Token nonce is empty, for example if the client didn't provide a nonce in + // the initial redirect, this may be nil. + ClaimNonce func(nonce string) error + // If specified, only this set of algorithms may be used to sign the JWT. + // + // Since many providers only support RS256, SupportedSigningAlgs defaults to this value. + SupportedSigningAlgs []string + + // If true, no ClientID check performed. Must be true if ClientID field is empty. + SkipClientIDCheck bool + // If true, token expiry is not checked. + SkipExpiryCheck bool + // If true, nonce claim is not checked. Must be true if ClaimNonce field is empty. + SkipNonceCheck bool + + // Time function to check Token expiry. Defaults to time.Now + Now func() time.Time } // Verifier returns an IDTokenVerifier that uses the provider's key set to verify JWTs. // // The returned IDTokenVerifier is tied to the Provider's context and its behavior is // undefined once the Provider's context is canceled. -func (p *Provider) Verifier(options ...VerificationOption) *IDTokenVerifier { - config := &verificationConfig{issuer: p.issuer} - for _, option := range options { - option.updateConfig(config) - } +func (p *Provider) Verifier(config *Config) *IDTokenVerifier { - return newVerifier(p.remoteKeySet, config) + return newVerifier(p.remoteKeySet, config, p.issuer) } -func newVerifier(keySet *remoteKeySet, config *verificationConfig) *IDTokenVerifier { - // As discussed in the godocs for VerifrySigningAlg, because almost all providers - // only support RS256, default to only allowing it. - if len(config.requiredAlgs) == 0 { - config.requiredAlgs = []string{RS256} +func newVerifier(keySet *remoteKeySet, config *Config, issuer string) *IDTokenVerifier { + // If SupportedSigningAlgs is empty defaults to only support RS256. + if len(config.SupportedSigningAlgs) == 0 { + config.SupportedSigningAlgs = []string{RS256} } return &IDTokenVerifier{ keySet: keySet, config: config, + issuer: issuer, } } @@ -89,7 +100,7 @@ func contains(sli []string, ele string) bool { } // Verify parses a raw ID Token, verifies it's been signed by the provider, preforms -// any additional checks passed as VerifictionOptions, and returns the payload. +// any additional checks depending on the Config, and returns the payload. // // See: https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation // @@ -134,20 +145,38 @@ func (v *IDTokenVerifier) Verify(ctx context.Context, rawIDToken string) (*IDTok } // Check issuer. - if t.Issuer != v.config.issuer { - return nil, fmt.Errorf("oidc: id token issued by a different provider, expected %q got %q", v.config.issuer, t.Issuer) - } - - // If a client ID has been provided, make sure it's part of the audience. - if v.config.audience != "" { - if !contains(t.Audience, v.config.audience) { - return nil, fmt.Errorf("oidc: expected audience %q got %q", v.config.audience, t.Audience) + if t.Issuer != v.issuer { + // Google sometimes returns "accounts.google.com" as the issuer claim instead of + // the required "https://accounts.google.com". Detect this case and allow it only + // for Google. + // + // We will not add hooks to let other providers go off spec like this. + if !(v.issuer == issuerGoogleAccounts && t.Issuer == issuerGoogleAccountsNoScheme) { + return nil, fmt.Errorf("oidc: id token issued by a different provider, expected %q got %q", v.issuer, t.Issuer) } } - // If a checkExpiry is specified, make sure token is not expired. - if v.config.checkExpiry != nil { - if t.Expiry.Before(v.config.checkExpiry()) { + // If a client ID has been provided, make sure it's part of the audience. SkipClientIDCheck must be true if ClientID is empty. + // + // This check DOES NOT ensure that the ClientID is the party to which the ID Token was issued (i.e. Authorized party). + if !v.config.SkipClientIDCheck { + if v.config.ClientID != "" { + if !contains(t.Audience, v.config.ClientID) { + return nil, fmt.Errorf("oidc: expected audience %q got %q", v.config.ClientID, t.Audience) + } + } else { + return nil, fmt.Errorf("oidc: Invalid configuration. ClientID must be provided or SkipClientIDCheck must be set.") + } + } + + // If a SkipExpiryCheck is false, make sure token is not expired. + if !v.config.SkipExpiryCheck { + now := time.Now + if v.config.Now != nil { + now = v.config.Now + } + + if t.Expiry.Before(now()) { return nil, fmt.Errorf("oidc: token is expired (Token Expiry: %v)", t.Expiry) } } @@ -155,14 +184,14 @@ func (v *IDTokenVerifier) Verify(ctx context.Context, rawIDToken string) (*IDTok // If a set of required algorithms has been provided, ensure that the signatures use those. var keyIDs, gotAlgs []string for _, sig := range jws.Signatures { - if len(v.config.requiredAlgs) == 0 || contains(v.config.requiredAlgs, sig.Header.Algorithm) { + if len(v.config.SupportedSigningAlgs) == 0 || contains(v.config.SupportedSigningAlgs, sig.Header.Algorithm) { keyIDs = append(keyIDs, sig.Header.KeyID) } else { gotAlgs = append(gotAlgs, sig.Header.Algorithm) } } if len(keyIDs) == 0 { - return nil, fmt.Errorf("oidc: no signatures use a require algorithm, expected %q got %q", v.config.requiredAlgs, gotAlgs) + return nil, fmt.Errorf("oidc: no signatures use a supported algorithm, expected %q got %q", v.config.SupportedSigningAlgs, gotAlgs) } // Get keys from the remote key set. This may trigger a re-sync. @@ -192,79 +221,22 @@ func (v *IDTokenVerifier) Verify(ctx context.Context, rawIDToken string) (*IDTok // Check the nonce after we've verified the token. We don't want to allow unverified // payloads to trigger a nonce lookup. - if v.config.nonceSource != nil { - if err := v.config.nonceSource.ClaimNonce(t.Nonce); err != nil { - return nil, err + // If SkipNonceCheck is not set ClaimNonce cannot be Nil. + if !v.config.SkipNonceCheck && t.Nonce != "" { + if v.config.ClaimNonce != nil { + if err := v.config.ClaimNonce(t.Nonce); err != nil { + return nil, err + } + } else { + return nil, fmt.Errorf("oidc: Invalid configuration. ClaimNonce must be provided or SkipNonceCheck must be set.") } } return t, nil } -// VerifyAudience ensures that an ID Token was issued for the specific client. -// -// Note that a verified token may be valid for other clients, as OpenID Connect allows a token to have -// multiple audiences. -func VerifyAudience(clientID string) VerificationOption { - return clientVerifier{clientID} -} - -type clientVerifier struct { - clientID string -} - -func (v clientVerifier) updateConfig(c *verificationConfig) { - c.audience = v.clientID -} - -// VerifyExpiry ensures that an ID Token has not expired. -func VerifyExpiry() VerificationOption { - return expiryVerifier{} -} - -type expiryVerifier struct{} - -func (v expiryVerifier) updateConfig(c *verificationConfig) { - c.checkExpiry = time.Now -} - -// VerifySigningAlg enforces that an ID Token is signed by a specific signing algorithm. -// -// Because so many providers only support RS256, if this verifiction option isn't used, -// the IDTokenVerifier defaults to only allowing RS256. -func VerifySigningAlg(allowedAlgs ...string) VerificationOption { - return algVerifier{allowedAlgs} -} - -type algVerifier struct { - algs []string -} - -func (v algVerifier) updateConfig(c *verificationConfig) { - c.requiredAlgs = v.algs -} - // Nonce returns an auth code option which requires the ID Token created by the // OpenID Connect provider to contain the specified nonce. func Nonce(nonce string) oauth2.AuthCodeOption { return oauth2.SetAuthURLParam("nonce", nonce) } - -// NonceSource represents a source which can verify a nonce is valid and has not -// been claimed before. -type NonceSource interface { - ClaimNonce(nonce string) error -} - -// VerifyNonce ensures that the ID Token contains a nonce which can be claimed by the nonce source. -func VerifyNonce(source NonceSource) VerificationOption { - return nonceVerifier{source} -} - -type nonceVerifier struct { - nonceSource NonceSource -} - -func (n nonceVerifier) updateConfig(c *verificationConfig) { - c.nonceSource = n.nonceSource -} diff --git a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go b/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go deleted file mode 100644 index 606cf1f9..00000000 --- a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build go1.7 - -// Package ctxhttp provides helper functions for performing context-aware HTTP requests. -package ctxhttp // import "golang.org/x/net/context/ctxhttp" - -import ( - "io" - "net/http" - "net/url" - "strings" - - "golang.org/x/net/context" -) - -// Do sends an HTTP request with the provided http.Client and returns -// an HTTP response. -// -// If the client is nil, http.DefaultClient is used. -// -// The provided ctx must be non-nil. If it is canceled or times out, -// ctx.Err() will be returned. -func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) { - if client == nil { - client = http.DefaultClient - } - resp, err := client.Do(req.WithContext(ctx)) - // If we got an error, and the context has been canceled, - // the context's error is probably more useful. - if err != nil { - select { - case <-ctx.Done(): - err = ctx.Err() - default: - } - } - return resp, err -} - -// Get issues a GET request via the Do function. -func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) { - req, err := http.NewRequest("GET", url, nil) - if err != nil { - return nil, err - } - return Do(ctx, client, req) -} - -// Head issues a HEAD request via the Do function. -func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) { - req, err := http.NewRequest("HEAD", url, nil) - if err != nil { - return nil, err - } - return Do(ctx, client, req) -} - -// Post issues a POST request via the Do function. -func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) { - req, err := http.NewRequest("POST", url, body) - if err != nil { - return nil, err - } - req.Header.Set("Content-Type", bodyType) - return Do(ctx, client, req) -} - -// PostForm issues a POST request via the Do function. -func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) { - return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) -} diff --git a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go b/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go deleted file mode 100644 index 926870cc..00000000 --- a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !go1.7 - -package ctxhttp // import "golang.org/x/net/context/ctxhttp" - -import ( - "io" - "net/http" - "net/url" - "strings" - - "golang.org/x/net/context" -) - -func nop() {} - -var ( - testHookContextDoneBeforeHeaders = nop - testHookDoReturned = nop - testHookDidBodyClose = nop -) - -// Do sends an HTTP request with the provided http.Client and returns an HTTP response. -// If the client is nil, http.DefaultClient is used. -// If the context is canceled or times out, ctx.Err() will be returned. -func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) { - if client == nil { - client = http.DefaultClient - } - - // TODO(djd): Respect any existing value of req.Cancel. - cancel := make(chan struct{}) - req.Cancel = cancel - - type responseAndError struct { - resp *http.Response - err error - } - result := make(chan responseAndError, 1) - - // Make local copies of test hooks closed over by goroutines below. - // Prevents data races in tests. - testHookDoReturned := testHookDoReturned - testHookDidBodyClose := testHookDidBodyClose - - go func() { - resp, err := client.Do(req) - testHookDoReturned() - result <- responseAndError{resp, err} - }() - - var resp *http.Response - - select { - case <-ctx.Done(): - testHookContextDoneBeforeHeaders() - close(cancel) - // Clean up after the goroutine calling client.Do: - go func() { - if r := <-result; r.resp != nil { - testHookDidBodyClose() - r.resp.Body.Close() - } - }() - return nil, ctx.Err() - case r := <-result: - var err error - resp, err = r.resp, r.err - if err != nil { - return resp, err - } - } - - c := make(chan struct{}) - go func() { - select { - case <-ctx.Done(): - close(cancel) - case <-c: - // The response's Body is closed. - } - }() - resp.Body = ¬ifyingReader{resp.Body, c} - - return resp, nil -} - -// Get issues a GET request via the Do function. -func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) { - req, err := http.NewRequest("GET", url, nil) - if err != nil { - return nil, err - } - return Do(ctx, client, req) -} - -// Head issues a HEAD request via the Do function. -func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) { - req, err := http.NewRequest("HEAD", url, nil) - if err != nil { - return nil, err - } - return Do(ctx, client, req) -} - -// Post issues a POST request via the Do function. -func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) { - req, err := http.NewRequest("POST", url, body) - if err != nil { - return nil, err - } - req.Header.Set("Content-Type", bodyType) - return Do(ctx, client, req) -} - -// PostForm issues a POST request via the Do function. -func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) { - return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) -} - -// notifyingReader is an io.ReadCloser that closes the notify channel after -// Close is called or a Read fails on the underlying ReadCloser. -type notifyingReader struct { - io.ReadCloser - notify chan<- struct{} -} - -func (r *notifyingReader) Read(p []byte) (int, error) { - n, err := r.ReadCloser.Read(p) - if err != nil && r.notify != nil { - close(r.notify) - r.notify = nil - } - return n, err -} - -func (r *notifyingReader) Close() error { - err := r.ReadCloser.Close() - if r.notify != nil { - close(r.notify) - r.notify = nil - } - return err -}