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
177 lines
4.7 KiB
Go
177 lines
4.7 KiB
Go
// Copyright © 2023 Ory Corp
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package oidc
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/url"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"golang.org/x/oauth2"
|
|
)
|
|
|
|
func TestClaimsValidate(t *testing.T) {
|
|
require.Error(t, new(Claims).Validate())
|
|
require.Error(t, (&Claims{Issuer: "not-empty"}).Validate())
|
|
require.Error(t, (&Claims{Issuer: "not-empty"}).Validate())
|
|
require.Error(t, (&Claims{Subject: "not-empty"}).Validate())
|
|
require.Error(t, (&Claims{Subject: "not-empty"}).Validate())
|
|
require.NoError(t, (&Claims{Issuer: "not-empty", Subject: "not-empty"}).Validate())
|
|
}
|
|
|
|
type TestProvider struct {
|
|
*ProviderGenericOIDC
|
|
}
|
|
|
|
func NewTestProvider(c *Configuration, reg Dependencies) Provider {
|
|
return &TestProvider{
|
|
ProviderGenericOIDC: NewProviderGenericOIDC(c, reg).(*ProviderGenericOIDC),
|
|
}
|
|
}
|
|
|
|
func RegisterTestProvider(t *testing.T, id string) {
|
|
supportedProviders[id] = func(c *Configuration, reg Dependencies) Provider {
|
|
return NewTestProvider(c, reg)
|
|
}
|
|
t.Cleanup(func() {
|
|
delete(supportedProviders, id)
|
|
})
|
|
}
|
|
|
|
var _ IDTokenVerifier = new(TestProvider)
|
|
|
|
func (t *TestProvider) Verify(_ context.Context, token string) (*Claims, error) {
|
|
if token == "error" {
|
|
return nil, fmt.Errorf("stub error")
|
|
}
|
|
c := Claims{}
|
|
if err := json.Unmarshal([]byte(token), &c); err != nil {
|
|
return nil, err
|
|
}
|
|
return &c, nil
|
|
}
|
|
|
|
// SetUserInfoURL allows overriding the userinfo URL for testing purposes.
|
|
func (p *ProviderUAEPass) SetUserInfoURL(t *testing.T, url string) {
|
|
t.Helper()
|
|
p.userinfoURL = url
|
|
}
|
|
|
|
// upstreamParam reports whether the option list produced by
|
|
// UpstreamParameters contains a given upstream parameter, and its value.
|
|
// The options are applied through a real oauth2.Config.AuthCodeURL so the
|
|
// test observes exactly what is sent to the upstream provider.
|
|
func upstreamParam(t *testing.T, opts []oauth2.AuthCodeOption, key string) (string, bool) {
|
|
t.Helper()
|
|
conf := &oauth2.Config{
|
|
ClientID: "client",
|
|
Endpoint: oauth2.Endpoint{AuthURL: "https://idp.example.com/auth"},
|
|
}
|
|
authURL, err := url.Parse(conf.AuthCodeURL("state", opts...))
|
|
require.NoError(t, err)
|
|
q := authURL.Query()
|
|
if !q.Has(key) {
|
|
return "", false
|
|
}
|
|
return q.Get(key), true
|
|
}
|
|
|
|
func TestUpstreamParameters(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
upstream := map[string]string{
|
|
"login_hint": "victim@example.com",
|
|
"hd": "example.com",
|
|
"prompt": "select_account",
|
|
"auth_type": "reauthenticate",
|
|
"acr_values": "urn:example:acr",
|
|
"unknown": "dropped",
|
|
}
|
|
|
|
opts := UpstreamParameters(upstream)
|
|
|
|
t.Run("case=login_hint is never forwarded", func(t *testing.T) {
|
|
// A caller-supplied login_hint cannot be trusted and can steer
|
|
// account/tenant/client selection on some IdPs, enabling a client-swap
|
|
// attack (HackerOne #3239672, ory-corp/cloud#8955).
|
|
_, ok := upstreamParam(t, opts, "login_hint")
|
|
assert.False(t, ok, "login_hint must not be forwarded")
|
|
})
|
|
|
|
t.Run("case=other allowed parameters are forwarded", func(t *testing.T) {
|
|
for key, want := range map[string]string{
|
|
"hd": "example.com",
|
|
"prompt": "select_account",
|
|
"auth_type": "reauthenticate",
|
|
"acr_values": "urn:example:acr",
|
|
} {
|
|
got, ok := upstreamParam(t, opts, key)
|
|
assert.True(t, ok, "%s must be forwarded", key)
|
|
assert.Equal(t, want, got)
|
|
}
|
|
})
|
|
|
|
t.Run("case=unknown parameters are dropped", func(t *testing.T) {
|
|
_, ok := upstreamParam(t, opts, "unknown")
|
|
assert.False(t, ok, "unknown parameters must not be forwarded")
|
|
})
|
|
}
|
|
|
|
func TestLocale(t *testing.T) {
|
|
// test json unmarshal
|
|
for _, tc := range []struct {
|
|
name string
|
|
json string
|
|
expected string
|
|
assertErr assert.ErrorAssertionFunc
|
|
}{{
|
|
name: "empty",
|
|
json: `{}`,
|
|
expected: "",
|
|
}, {
|
|
name: "empty string locale",
|
|
json: `{"locale":""}`,
|
|
expected: "",
|
|
}, {
|
|
name: "invalid string locale",
|
|
json: `{"locale":"""}`,
|
|
assertErr: assert.Error,
|
|
}, {
|
|
name: "string locale",
|
|
json: `{"locale":"en-US"}`,
|
|
expected: "en-US",
|
|
}, {
|
|
name: "linkedin locale",
|
|
json: `{"locale":{"country":"US","language":"en","ignore":"me"}}`,
|
|
expected: "en-US",
|
|
}, {
|
|
name: "missing country linkedin locale",
|
|
json: `{"locale":{"language":"en"}}`,
|
|
expected: "en",
|
|
}, {
|
|
name: "missing language linkedin locale",
|
|
json: `{"locale":{"country":"US"}}`,
|
|
expected: "US",
|
|
}, {
|
|
name: "invalid linkedin locale",
|
|
json: `{"locale":{"invalid":"me"}}`,
|
|
expected: "",
|
|
}} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var c Claims
|
|
err := json.Unmarshal([]byte(tc.json), &c)
|
|
if tc.assertErr != nil {
|
|
tc.assertErr(t, err)
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
assert.EqualValues(t, tc.expected, c.Locale)
|
|
})
|
|
}
|
|
}
|