186 lines
7.5 KiB
Go
186 lines
7.5 KiB
Go
package provider
|
|
|
|
import (
|
|
"context"
|
|
"crypto"
|
|
"crypto/rsa"
|
|
"encoding/base64"
|
|
"math/big"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/coreos/go-oidc/v3/oidc"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
type realIDToken struct {
|
|
AccessToken string
|
|
IDToken string
|
|
Time time.Time
|
|
Email string
|
|
Verifier func(context.Context, *oidc.Config) *oidc.IDTokenVerifier
|
|
}
|
|
|
|
func googleIDTokenVerifier(ctx context.Context, config *oidc.Config) *oidc.IDTokenVerifier {
|
|
keyBytes, err := base64.RawURLEncoding.DecodeString("pP-rCe4jkKX6mq8yP1GcBZcxJzmxKWicHHor1S3Q49u6Oe-bQsk5NsK5mdR7Y7liGV9n0ikXSM42dYKQdxbhKA-7--fFon5isJoHr4fIwL2CCwVm5QWlK37q6PiH2_F1M0hRorHfkCb4nI56ZvfygvuOH4LIS82OzIgmsYbeEfwDRpeMSxWKwlpa3pX3GZ6jG7FgzJGBvmBkagpgsa2JZdyU4gEGMOkHdSzi5Ii-6RGfFLhhI1OMxC9P2JaU5yjMN2pikfFIq_dbpm75yNUGpWJNVywtrlNvvJfA74UMN_lVCAaSR0A03BUMg6ljB65gFllpKF224uWBA8tpjngwKQ")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
n := big.NewInt(0)
|
|
n.SetBytes(keyBytes)
|
|
|
|
publicKey := &rsa.PublicKey{
|
|
N: n,
|
|
E: 65537,
|
|
}
|
|
|
|
return oidc.NewVerifier(
|
|
"https://accounts.google.com",
|
|
&oidc.StaticKeySet{
|
|
PublicKeys: []crypto.PublicKey{publicKey},
|
|
},
|
|
config,
|
|
)
|
|
}
|
|
|
|
func azureIDTokenVerifier(ctx context.Context, config *oidc.Config) *oidc.IDTokenVerifier {
|
|
keyBytes, err := base64.RawURLEncoding.DecodeString("1djHqyNclRpJWtHCnkP5QWvDxozCTG_ZDnkEmudpcxjnYrVL4RVIwdNCBLAStg8Dob5OUyAlHcRFMCqGTW4HA6kHgIxyfiFsYCBDMHWd2-61N1cAS6S9SdXlWXkBQgU0Qj6q_yFYTRS7J-zI_jMLRQAlpowfDFM1vSTBIci7kqynV6pPOz4jMaDQevmSscEs-jz7e8YXAiiVpN588oBQ0jzQaTTx90WjgRP23mn8mPyabj8gcR3gLwKLsBUhlp1oZj7FopGp8z8LHuueJB_q_LOUa_gAozZ0lfoJxFimXgpgEK7GNVdMRsMH3mIl0A5oYN8f29RFwbG0rNO5ZQ1YWQ")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
n := big.NewInt(0)
|
|
n.SetBytes(keyBytes)
|
|
|
|
publicKey := &rsa.PublicKey{
|
|
N: n,
|
|
E: 65537,
|
|
}
|
|
|
|
return oidc.NewVerifier(
|
|
IssuerAzureMicrosoft,
|
|
&oidc.StaticKeySet{
|
|
PublicKeys: []crypto.PublicKey{publicKey},
|
|
},
|
|
config,
|
|
)
|
|
}
|
|
|
|
var realIDTokens map[string]realIDToken = map[string]realIDToken{
|
|
IssuerGoogle: {
|
|
AccessToken: "ya29.a0AWY7CklOn4TehiT4kA6osNP6e-pHErOY8X53T2oUe7Oqqwc3-uIJpoEgoZCUogewBuNWr-JFT2FK9s0E0oRSFtAfu0-uIDckBj5ca1pxnk0-zPkPZouqoIyl0AlIpQjIUEuyuQTYUay99kRajbHcFCR1VMbNcQaCgYKAQESARESFQG1tDrp1joUHupV5Rn8-nWDpKkmMw0165",
|
|
IDToken: "eyJhbGciOiJSUzI1NiIsImtpZCI6Ijg1YmE5MzEzZmQ3YTdkNGFmYTg0ODg0YWJjYzg0MDMwMDQzNjMxODAiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiI5MTQ2NjY0MjA3NS03OWNwaWs4aWNxYzU4NjY5bjdtaXY5NjZsYmFwOTNhMi5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImF1ZCI6IjkxNDY2NjQyMDc1LTc5Y3BpazhpY3FjNTg2NjluN21pdjk2NmxiYXA5M2EyLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwic3ViIjoiMTAzNzgzMTkwMTI2NDM5NzUxMjY5IiwiaGQiOiJzdXBhYmFzZS5pbyIsImVtYWlsIjoic3RvamFuQHN1cGFiYXNlLmlvIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImF0X2hhc2giOiJlcGVWV244VmxWa28zd195Unk3UDZRIiwibmFtZSI6IlN0b2phbiBEaW1pdHJvdnNraSIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS9BQWNIVHRka0dhWjVlcGtqT1dxSEF1UUV4N2cwRlBCeXJiQ2ZNUjVNTk5kYz1zOTYtYyIsImdpdmVuX25hbWUiOiJTdG9qYW4iLCJmYW1pbHlfbmFtZSI6IkRpbWl0cm92c2tpIiwibG9jYWxlIjoiZW4tR0IiLCJpYXQiOjE2ODY2NTk5MzIsImV4cCI6MTY4NjY2MzUzMn0.nKAN9BFSxvavXYfWX4fZHREYY_3O4uOFRFq1KU1NNrBOMq_CPpM8c8PV7ZhKQvGCjBthSjtxGWbcqT0ByA7RdpNW6kj5UpFxEPdhenZ-eO1FwiEVIC8uZpiX6J3Nr7fAqi1P0DVeB3Zr_GrtkS9MDhZNb3hE5NDkvjCulwP4gRBC-5Pn_aRJRESxYkr_naKiSSmVilkmNVjZO4orq6KuYlvWHKHZIRiUI1akt0gVr5GxsEpd_duzUU30yVSPiq8l6fgxvJn2hT0MHa77wo3hvlP0NyAoSE7Nh4tRSowB0Qq7_byDMUmNWfXh-Qqa2M6ywuJ-_3LTLNUJH-cwdm2tNQ",
|
|
Time: time.Unix(1686659933, 0), // 1 sec after iat
|
|
Verifier: googleIDTokenVerifier,
|
|
},
|
|
IssuerAzureMicrosoft: {
|
|
AccessToken: "access-token",
|
|
Time: time.Unix(1697277774, 0), // 1 sec after iat
|
|
IDToken: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlhvdVhMWVExVGlwNW9kWWFqaUN0RlZnVmFFcyJ9.eyJ2ZXIiOiIyLjAiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vOTE4ODA0MGQtNmM2Ny00YzViLWIxMTItMzZhMzA0YjY2ZGFkL3YyLjAiLCJzdWIiOiJBQUFBQUFBQUFBQUFBQUFBQUFBQUFCWkRuRDkxOTBfc2wxcTZwenZlRHZNIiwiYXVkIjoiYTBkOGY5NzItNTRhYy00YWJmLTkxNGMtNTIyMDE0YzQwMjJhIiwiZXhwIjoxNjk3MzY0NDczLCJpYXQiOjE2OTcyNzc3NzMsIm5iZiI6MTY5NzI3Nzc3MywiZW1haWwiOiJzZGltaXRyb3Zza2lAZ21haWwuY29tIiwidGlkIjoiOTE4ODA0MGQtNmM2Ny00YzViLWIxMTItMzZhMzA0YjY2ZGFkIiwieG1zX2Vkb3YiOiIxIiwiYWlvIjoiRHBQV3lZSnRJcUl5OHpyVjROIUlIdGtFa09BMDhPS29lZ1RkYmZQUEVPYmxtYk9ESFQ0cGJVcVI1cExraENyWWZ6bUgzb3A1RzN5RGp2M0tNZ0Rad29lQ1FjKmVueldyb21iQ3BuKkR6OEpQOGMxU3pEVG1TbGp4U3U3UnVLTXNZSjRvS1lDazFBSVcqUUNUTmlMWkpUKlN3WWZQcjZBTW9IejFEZ3pBZEFkbk9uWiFHNUNFeEtQalBxcHRuVmpUZlEkJCJ9.CskICxOaeqd4SkiPdWEHJKZVdhAdgzM5SN7K7FYi0dguQH1-v6XTetDIoEsBn0GZoozXjbG2GgkFcVhhBvNA0ZrDIr4KcjfnJ5-7rwX3AtxdQ3umrHRlGu3jlmbDOtWzPWNMLLRXfR1Mm3pHEUvlzqmk3Ffh4TuAmXID-fb-Xmfuuv1k0UsZ5mlr_3ybTPVZk-Lj0bqkR1L5Zzt4HjgfpchRryJ3Y24b4dDsSjg7mgE_5JivgjhtVef5OnqYhKUF1DTy2pFysFO_eRliK6qjouYeZnQOJnWHP1MgpySAOQ3sVcwvE4P9g7V3QouxByZPv-g99N1K4GwZrtdm46gtTQ",
|
|
Verifier: azureIDTokenVerifier,
|
|
},
|
|
}
|
|
|
|
func TestParseIDToken(t *testing.T) {
|
|
defer func() {
|
|
OverrideVerifiers = make(map[string]func(context.Context, *oidc.Config) *oidc.IDTokenVerifier)
|
|
OverrideClock = nil
|
|
}()
|
|
|
|
// note that this test can fail if/when the issuers rotate their
|
|
// signing keys (which happens rarely if ever)
|
|
// then you should obtain new ID tokens and update this test
|
|
for issuer, token := range realIDTokens {
|
|
oidcProvider, err := oidc.NewProvider(context.Background(), issuer)
|
|
require.NoError(t, err)
|
|
|
|
OverrideVerifiers[oidcProvider.Endpoint().AuthURL] = token.Verifier
|
|
|
|
_, user, err := ParseIDToken(context.Background(), oidcProvider, &oidc.Config{
|
|
SkipClientIDCheck: true,
|
|
Now: func() time.Time {
|
|
return token.Time
|
|
},
|
|
}, token.IDToken, ParseIDTokenOptions{
|
|
AccessToken: token.AccessToken,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
require.NotEmpty(t, user.Emails[0].Email)
|
|
require.Equal(t, user.Emails[0].Verified, true)
|
|
}
|
|
}
|
|
|
|
func TestAzureIDTokenClaimsIsEmailVerified(t *testing.T) {
|
|
positiveExamples := []AzureIDTokenClaims{
|
|
{
|
|
Email: "test@example.com",
|
|
XMicrosoftEmailDomainOwnerVerified: nil,
|
|
},
|
|
{
|
|
Email: "test@example.com",
|
|
XMicrosoftEmailDomainOwnerVerified: true,
|
|
},
|
|
{
|
|
Email: "test@example.com",
|
|
XMicrosoftEmailDomainOwnerVerified: "1",
|
|
},
|
|
{
|
|
Email: "test@example.com",
|
|
XMicrosoftEmailDomainOwnerVerified: "true",
|
|
},
|
|
}
|
|
|
|
negativeExamples := []AzureIDTokenClaims{
|
|
{
|
|
Email: "",
|
|
XMicrosoftEmailDomainOwnerVerified: true,
|
|
},
|
|
{
|
|
Email: "test@example.com",
|
|
XMicrosoftEmailDomainOwnerVerified: false,
|
|
},
|
|
{
|
|
Email: "test@example.com",
|
|
XMicrosoftEmailDomainOwnerVerified: "0",
|
|
},
|
|
{
|
|
Email: "test@example.com",
|
|
XMicrosoftEmailDomainOwnerVerified: "false",
|
|
},
|
|
{
|
|
Email: "test@example.com",
|
|
XMicrosoftEmailDomainOwnerVerified: float32(0),
|
|
},
|
|
{
|
|
Email: "test@example.com",
|
|
XMicrosoftEmailDomainOwnerVerified: float64(0),
|
|
},
|
|
{
|
|
Email: "test@example.com",
|
|
XMicrosoftEmailDomainOwnerVerified: int(0),
|
|
},
|
|
{
|
|
Email: "test@example.com",
|
|
XMicrosoftEmailDomainOwnerVerified: int32(0),
|
|
},
|
|
{
|
|
Email: "test@example.com",
|
|
XMicrosoftEmailDomainOwnerVerified: int64(0),
|
|
},
|
|
}
|
|
|
|
for i, example := range positiveExamples {
|
|
if !example.IsEmailVerified() {
|
|
t.Errorf("positive example %v reports negative result", i)
|
|
}
|
|
}
|
|
|
|
for i, example := range negativeExamples {
|
|
if example.IsEmailVerified() {
|
|
t.Errorf("negative example %v reports positive result", i)
|
|
}
|
|
}
|
|
}
|