Skip to content

Commit

Permalink
fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
hf committed Oct 14, 2023
1 parent 1f3f8ea commit c28cbca
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 18 deletions.
74 changes: 56 additions & 18 deletions internal/api/external_azure_test.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,56 @@
package api

import (
"context"
"crypto"
"crypto/rsa"
"encoding/base64"
"fmt"
"math/big"
"net/http"
"net/http/httptest"
"net/url"
"time"

"github.com/coreos/go-oidc/v3/oidc"
jwt "github.com/golang-jwt/jwt"
"github.com/supabase/gotrue/internal/api/provider"
)

const (
azureUser string = `{"name":"Azure Test","email":"azure@example.com","sub":"azuretestid"}`
azureUserNoEmail string = `{"name":"Azure Test","sub":"azuretestid"}`
azureUser string = `{"name":"Azure Test","email":"sdimitrovski@gmail.com","sub":"AAAAAAAAAAAAAAAAAAAAABZDnD9190_sl1q6pzveDvM"}`
azureUserNoEmail string = `{"name":"Azure Test","sub":"AAAAAAAAAAAAAAAAAAAAABZDnD9190_sl1q6pzveDvM"}`
)

const (
// #nosec
azureRealIDToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlhvdVhMWVExVGlwNW9kWWFqaUN0RlZnVmFFcyJ9.eyJ2ZXIiOiIyLjAiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vOTE4ODA0MGQtNmM2Ny00YzViLWIxMTItMzZhMzA0YjY2ZGFkL3YyLjAiLCJzdWIiOiJBQUFBQUFBQUFBQUFBQUFBQUFBQUFCWkRuRDkxOTBfc2wxcTZwenZlRHZNIiwiYXVkIjoiYTBkOGY5NzItNTRhYy00YWJmLTkxNGMtNTIyMDE0YzQwMjJhIiwiZXhwIjoxNjk3MzY0NDczLCJpYXQiOjE2OTcyNzc3NzMsIm5iZiI6MTY5NzI3Nzc3MywiZW1haWwiOiJzZGltaXRyb3Zza2lAZ21haWwuY29tIiwidGlkIjoiOTE4ODA0MGQtNmM2Ny00YzViLWIxMTItMzZhMzA0YjY2ZGFkIiwieG1zX2Vkb3YiOiIxIiwiYWlvIjoiRHBQV3lZSnRJcUl5OHpyVjROIUlIdGtFa09BMDhPS29lZ1RkYmZQUEVPYmxtYk9ESFQ0cGJVcVI1cExraENyWWZ6bUgzb3A1RzN5RGp2M0tNZ0Rad29lQ1FjKmVueldyb21iQ3BuKkR6OEpQOGMxU3pEVG1TbGp4U3U3UnVLTXNZSjRvS1lDazFBSVcqUUNUTmlMWkpUKlN3WWZQcjZBTW9IejFEZ3pBZEFkbk9uWiFHNUNFeEtQalBxcHRuVmpUZlEkJCJ9.CskICxOaeqd4SkiPdWEHJKZVdhAdgzM5SN7K7FYi0dguQH1-v6XTetDIoEsBn0GZoozXjbG2GgkFcVhhBvNA0ZrDIr4KcjfnJ5-7rwX3AtxdQ3umrHRlGu3jlmbDOtWzPWNMLLRXfR1Mm3pHEUvlzqmk3Ffh4TuAmXID-fb-Xmfuuv1k0UsZ5mlr_3ybTPVZk-Lj0bqkR1L5Zzt4HjgfpchRryJ3Y24b4dDsSjg7mgE_5JivgjhtVef5OnqYhKUF1DTy2pFysFO_eRliK6qjouYeZnQOJnWHP1MgpySAOQ3sVcwvE4P9g7V3QouxByZPv-g99N1K4GwZrtdm46gtTQ"
azureRealIDTokenIssuedAt = 1697277773
)

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(
provider.IssuerAzureMicrosoft,
&oidc.StaticKeySet{
PublicKeys: []crypto.PublicKey{publicKey},
},
config,
)
}

func (ts *ExternalTestSuite) TestSignupExternalAzure() {
req := httptest.NewRequest(http.MethodGet, "http://localhost/authorize?provider=azure", nil)
w := httptest.NewRecorder()
Expand All @@ -38,7 +75,12 @@ func (ts *ExternalTestSuite) TestSignupExternalAzure() {
ts.Equal(ts.Config.SiteURL, claims.SiteURL)
}

func AzureTestSignupSetup(ts *ExternalTestSuite, tokenCount *int, userCount *int, code string, user string) *httptest.Server {
func AzureTestSignupSetup(ts *ExternalTestSuite, tokenCount *int, userCount *int, code string) *httptest.Server {
provider.OverrideVerifiers[provider.IssuerAzureMicrosoft] = azureIDTokenVerifier
provider.OverrideClock = func() time.Time {
return time.Unix(azureRealIDTokenIssuedAt+1, 0) // 1 sec after iat
}

server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/oauth2/v2.0/token":
Expand All @@ -48,11 +90,7 @@ func AzureTestSignupSetup(ts *ExternalTestSuite, tokenCount *int, userCount *int
ts.Equal(ts.Config.External.Azure.RedirectURI, r.FormValue("redirect_uri"))

w.Header().Add("Content-Type", "application/json")
fmt.Fprint(w, `{"access_token":"azure_token","expires_in":100000}`)
case "/oidc/userinfo":
*userCount++
w.Header().Add("Content-Type", "application/json")
fmt.Fprint(w, user)
fmt.Fprintf(w, `{"access_token":"azure_token","expires_in":100000,"id_token":%q}`, azureRealIDToken)
default:
w.WriteHeader(500)
ts.Fail("unknown azure oauth call %s", r.URL.Path)
Expand All @@ -69,12 +107,12 @@ func (ts *ExternalTestSuite) TestSignupExternalAzure_AuthorizationCode() {
ts.Config.DisableSignup = false
tokenCount, userCount := 0, 0
code := "authcode"
server := AzureTestSignupSetup(ts, &tokenCount, &userCount, code, azureUser)
server := AzureTestSignupSetup(ts, &tokenCount, &userCount, code)
defer server.Close()

u := performAuthorization(ts, "azure", code, "")

assertAuthorizationSuccess(ts, u, tokenCount, userCount, "azure@example.com", "Azure Test", "azuretestid", "")
assertAuthorizationSuccess(ts, u, tokenCount, userCount, "sdimitrovski@gmail.com", "Azure Test", "AAAAAAAAAAAAAAAAAAAAABZDnD9190_sl1q6pzveDvM", "")
}

func (ts *ExternalTestSuite) TestSignupExternalAzureDisableSignupErrorWhenNoUser() {
Expand All @@ -86,7 +124,7 @@ func (ts *ExternalTestSuite) TestSignupExternalAzureDisableSignupErrorWhenNoUser

u := performAuthorization(ts, "azure", code, "")

assertAuthorizationFailure(ts, u, "Signups not allowed for this instance", "access_denied", "azure@example.com")
assertAuthorizationFailure(ts, u, "Signups not allowed for this instance", "access_denied", "sdimitrovski@gmail.com")
}

func (ts *ExternalTestSuite) TestSignupExternalAzureDisableSignupErrorWhenNoEmail() {
Expand All @@ -98,14 +136,14 @@ func (ts *ExternalTestSuite) TestSignupExternalAzureDisableSignupErrorWhenNoEmai

u := performAuthorization(ts, "azure", code, "")

assertAuthorizationFailure(ts, u, "Error getting user email from external provider", "server_error", "azure@example.com")
assertAuthorizationFailure(ts, u, "Error getting user email from external provider", "server_error", "sdimitrovski@gmail.com")

}

func (ts *ExternalTestSuite) TestSignupExternalAzureDisableSignupSuccessWithPrimaryEmail() {
ts.Config.DisableSignup = true

ts.createUser("azuretestid", "azure@example.com", "Azure Test", "http://example.com/avatar", "")
ts.createUser("AAAAAAAAAAAAAAAAAAAAABZDnD9190_sl1q6pzveDvM", "sdimitrovski@gmail.com", "Azure Test", "http://example.com/avatar", "")

tokenCount, userCount := 0, 0
code := "authcode"
Expand All @@ -114,12 +152,12 @@ func (ts *ExternalTestSuite) TestSignupExternalAzureDisableSignupSuccessWithPrim

u := performAuthorization(ts, "azure", code, "")

assertAuthorizationSuccess(ts, u, tokenCount, userCount, "azure@example.com", "Azure Test", "azuretestid", "http://example.com/avatar")
assertAuthorizationSuccess(ts, u, tokenCount, userCount, "sdimitrovski@gmail.com", "Azure Test", "AAAAAAAAAAAAAAAAAAAAABZDnD9190_sl1q6pzveDvM", "http://example.com/avatar")
}

func (ts *ExternalTestSuite) TestInviteTokenExternalAzureSuccessWhenMatchingToken() {
// name should be populated from Azure API
ts.createUser("azuretestid", "azure@example.com", "", "http://example.com/avatar", "invite_token")
ts.createUser("AAAAAAAAAAAAAAAAAAAAABZDnD9190_sl1q6pzveDvM", "sdimitrovski@gmail.com", "", "http://example.com/avatar", "invite_token")

tokenCount, userCount := 0, 0
code := "authcode"
Expand All @@ -128,7 +166,7 @@ func (ts *ExternalTestSuite) TestInviteTokenExternalAzureSuccessWhenMatchingToke

u := performAuthorization(ts, "azure", code, "invite_token")

assertAuthorizationSuccess(ts, u, tokenCount, userCount, "azure@example.com", "Azure Test", "azuretestid", "http://example.com/avatar")
assertAuthorizationSuccess(ts, u, tokenCount, userCount, "sdimitrovski@gmail.com", "Azure Test", "AAAAAAAAAAAAAAAAAAAAABZDnD9190_sl1q6pzveDvM", "http://example.com/avatar")
}

func (ts *ExternalTestSuite) TestInviteTokenExternalAzureErrorWhenNoMatchingToken() {
Expand All @@ -143,7 +181,7 @@ func (ts *ExternalTestSuite) TestInviteTokenExternalAzureErrorWhenNoMatchingToke
}

func (ts *ExternalTestSuite) TestInviteTokenExternalAzureErrorWhenWrongToken() {
ts.createUser("azuretestid", "azure@example.com", "", "", "invite_token")
ts.createUser("AAAAAAAAAAAAAAAAAAAAABZDnD9190_sl1q6pzveDvM", "sdimitrovski@gmail.com", "", "", "invite_token")

tokenCount, userCount := 0, 0
code := "authcode"
Expand All @@ -156,7 +194,7 @@ func (ts *ExternalTestSuite) TestInviteTokenExternalAzureErrorWhenWrongToken() {
}

func (ts *ExternalTestSuite) TestInviteTokenExternalAzureErrorWhenEmailDoesntMatch() {
ts.createUser("azuretestid", "azure@example.com", "", "", "invite_token")
ts.createUser("AAAAAAAAAAAAAAAAAAAAABZDnD9190_sl1q6pzveDvM", "sdimitrovski@gmail.com", "", "", "invite_token")

tokenCount, userCount := 0, 0
code := "authcode"
Expand Down
3 changes: 3 additions & 0 deletions internal/api/provider/azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
)

const IssuerAzure = "https://login.microsoftonline.com/common/v2.0"
const IssuerAzureMicrosoft = "https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0"

const (
defaultAzureAuthBase = "login.microsoftonline.com/common"
Expand Down Expand Up @@ -94,6 +95,8 @@ func (g azureProvider) detectIDTokenIssuer(ctx context.Context, idToken string)
func (g azureProvider) GetUserData(ctx context.Context, tok *oauth2.Token) (*UserProvidedData, error) {
idToken := tok.Extra("id_token")

fmt.Printf("AZURE ID TOKEN %v\n", idToken)

if idToken != nil {
issuer, err := g.detectIDTokenIssuer(ctx, idToken.(string))
if err != nil {
Expand Down
11 changes: 11 additions & 0 deletions internal/api/provider/oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"strconv"
"strings"
"time"

"github.com/coreos/go-oidc/v3/oidc"
"github.com/golang-jwt/jwt"
Expand All @@ -21,6 +22,10 @@ type ParseIDTokenOptions struct {
// used in tests.
var OverrideVerifiers = make(map[string]func(context.Context, *oidc.Config) *oidc.IDTokenVerifier)

// OverrideClock can be used to set a custom clock function to be used when
// parsing ID tokens. Should only be used in tests.
var OverrideClock func() time.Time

func ParseIDToken(ctx context.Context, provider *oidc.Provider, config *oidc.Config, idToken string, options ParseIDTokenOptions) (*oidc.IDToken, *UserProvidedData, error) {
if config == nil {
config = &oidc.Config{
Expand All @@ -29,6 +34,12 @@ func ParseIDToken(ctx context.Context, provider *oidc.Provider, config *oidc.Con
}
}

if OverrideClock != nil {
clonedConfig := *config
clonedConfig.Now = OverrideClock
config = &clonedConfig
}

verifier := provider.VerifierContext(ctx, config)
overrideVerifier, ok := OverrideVerifiers[provider.Endpoint().AuthURL]
if ok && overrideVerifier != nil {
Expand Down
30 changes: 30 additions & 0 deletions internal/api/provider/oidc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,48 @@ func googleIDTokenVerifier(ctx context.Context, config *oidc.Config) *oidc.IDTok
)
}

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
Expand Down

0 comments on commit c28cbca

Please sign in to comment.