Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
109 lines
5.0 KiB
Go
109 lines
5.0 KiB
Go
// Copyright © 2023 Ory Corp
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package oidc_test
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"golang.org/x/oauth2"
|
|
|
|
"github.com/ory/kratos/driver/config"
|
|
"github.com/ory/kratos/pkg"
|
|
"github.com/ory/kratos/selfservice/strategy/oidc"
|
|
"github.com/ory/x/configx"
|
|
)
|
|
|
|
const (
|
|
wellknownJWKs = "https://raw.githubusercontent.com/aeneasr/private-oidc/master/jwks"
|
|
fakeJWTJWKS = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjk5OTk5OTk5OTksImF1ZCI6ImFiY2QiLCJpc3MiOiJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vYWVuZWFzci9wcml2YXRlLW9pZGMvbWFzdGVyL2p3a3MifQ.RLR3dSRGGIjbRqyOMGMYFGTzcVHi7hPuFs_IKYywVWJ_XMyzWozTW4M8uuvBUPiVoNDNs7osm-AkRl7cBfw0by1XEcnEKZStCjdEh7Q0IGGb4hgq8rRqm1d3uJwNIGU5h7-s7tMnDED2ZTZhp304U99YWz7Ozl_TA9tqolBLLZEmIfXSY_RR3rMoDwtHZvWhI0OZtPdcBh86vWS9zG6QPHM5qGtRMMIs-ljXrrgS8LulUI5CAVEeHlQLXroBIe9v89IkKi07A7YRrk1SxFxlojcZ2v0z-0iTI3WL8mUoocF-RYy1RgJTK_dPYkSJebaN0R5MmBax5MXLKy4baNHKsg"
|
|
)
|
|
|
|
func TestProviderPrivateIP(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
t.Error("the request should not have reached the test server")
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
t.Cleanup(ts.Close)
|
|
|
|
_, reg := pkg.NewFastRegistryWithMocks(t,
|
|
configx.WithValue(config.ViperKeyClientHTTPNoPrivateIPRanges, true))
|
|
|
|
generic := func(c *oidc.Configuration) oidc.Provider {
|
|
return oidc.NewProviderGenericOIDC(c, reg)
|
|
}
|
|
auth0 := func(c *oidc.Configuration) oidc.Provider {
|
|
return oidc.NewProviderAuth0(c, reg)
|
|
}
|
|
gitlab := func(c *oidc.Configuration) oidc.Provider {
|
|
return oidc.NewProviderGitLab(c, reg)
|
|
}
|
|
|
|
// We do not test the Auth URL as the Auth URL is not vulnerable to SSRF attacks.
|
|
// The AuthURL is only given to the user's browser, thus it is not possible to cause SSRF.
|
|
// We only care about Token URLs and Issuer URLs.
|
|
for k, tc := range []struct {
|
|
c *oidc.Configuration
|
|
e string
|
|
p func(c *oidc.Configuration) oidc.Provider
|
|
id string
|
|
}{
|
|
// Apple uses a fixed token URL and does not use the issuer.
|
|
|
|
{p: auth0, c: &oidc.Configuration{IssuerURL: ts.URL}, e: "no route to host"},
|
|
// The TokenURL is fixed in Auth0 to {issuer_url}/token. Since the issuer is called first, any local token fails also.
|
|
|
|
// If the issuer URL is local, we fail
|
|
{p: generic, c: &oidc.Configuration{IssuerURL: ts.URL}, e: "no route to host", id: fakeJWTJWKS},
|
|
{p: generic, c: &oidc.Configuration{IssuerURL: ts.URL, ClaimsSource: "userinfo"}, e: "no route to host", id: fakeJWTJWKS},
|
|
{p: generic, c: &oidc.Configuration{IssuerURL: ts.URL, ClaimsSource: "invalid"}, e: "Unknown claims source: \"invalid\"", id: fakeJWTJWKS},
|
|
|
|
// If the issuer URL has a local JWKs URL, we fail
|
|
{p: generic, c: &oidc.Configuration{ClientID: "abcd", IssuerURL: wellknownJWKs}, e: "no route to host", id: fakeJWTJWKS},
|
|
{p: generic, c: &oidc.Configuration{ClientID: "abcd", IssuerURL: wellknownJWKs, ClaimsSource: "userinfo"}, e: "no route to host", id: fakeJWTJWKS},
|
|
|
|
// The next call does not fail because the provider uses only the ID JSON Web Token to verify this call and does
|
|
// not use the TokenURL at all!
|
|
// {p: generic, c: &oidc.Configuration{ClientID: "abcd", IssuerURL: wellknownToken, TokenURL: "http://127.0.0.3/"}, e: "127.0.0.3 is not a public IP address", id: fakeJWTToken},
|
|
|
|
// Discord uses a fixed token URL and does not use the issuer.
|
|
// Facebook uses a fixed token URL and does not use the issuer.
|
|
// GitHub uses a fixed token URL and does not use the issuer.
|
|
// GitHub App uses a fixed token URL and does not use the issuer.
|
|
// GitHub App uses a fixed token URL and does not use the issuer.
|
|
// LinkedInV2 uses a fixed token URL and does not use the issuer.
|
|
|
|
{p: gitlab, c: &oidc.Configuration{IssuerURL: ts.URL}, e: "no route to host"},
|
|
// The TokenURL is fixed in GitLab to {issuer_url}/token. Since the issuer is called first, any local token fails also.
|
|
|
|
// Google uses a fixed token URL and does not use the issuer.
|
|
// Microsoft uses a fixed token URL and does not use the issuer.
|
|
// Slack uses a fixed token URL and does not use the issuer.
|
|
// Spotify uses a fixed token URL and does not use the issuer.
|
|
// VK uses a fixed token URL and does not use the issuer.
|
|
// Yandex uses a fixed token URL and does not use the issuer.
|
|
// NetID uses a fixed token URL and does not use the issuer.
|
|
// X uses a fixed token URL and userinfoRL and does not use the issuer value.
|
|
// Line v2.1 uses a fixed token URL and does not use the issuer.
|
|
// UAE PASS uses fixed token URL and userinfo URL and does not use the issuer value.
|
|
} {
|
|
t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) {
|
|
p := tc.p(tc.c)
|
|
_, err := p.(oidc.OAuth2Provider).Claims(t.Context(), (&oauth2.Token{RefreshToken: "foo", Expiry: time.Now().Add(-time.Hour)}).WithExtra(map[string]interface{}{
|
|
"id_token": tc.id,
|
|
}), url.Values{})
|
|
require.Error(t, err)
|
|
assert.Contains(t, fmt.Sprintf("%+v", err), tc.e)
|
|
})
|
|
}
|
|
}
|