Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions selfservice/strategy/oidc/provider_apple_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ func TestAppleVerify(t *testing.T) {
assert.Equal(t, "acme@ory.sh", c.Email)
assert.Equal(t, "acme@ory.sh", c.Subject)
assert.Equal(t, "https://appleid.apple.com", c.Issuer)
assert.Equal(t, "acme@ory.sh", c.RawClaims["sub"])
})

t.Run("case=fails due to client_id mismatch", func(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions selfservice/strategy/oidc/provider_google_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ func TestGoogleVerify(t *testing.T) {
assert.Equal(t, "acme@ory.sh", c.Email)
assert.Equal(t, "acme@ory.sh", c.Subject)
assert.Equal(t, "https://accounts.google.com", c.Issuer)
assert.Equal(t, "acme@ory.sh", c.RawClaims["sub"])
})

t.Run("case=fails due to client_id mismatch", func(t *testing.T) {
Expand Down
85 changes: 85 additions & 0 deletions selfservice/strategy/oidc/provider_microsoft_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package oidc_test

import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"net/url"
Expand Down Expand Up @@ -76,6 +77,58 @@ func TestMicrosoftVerify(t *testing.T) {
assert.Equal(t, issuerFor(tenantA), c.Issuer)
})

t.Run("case=preserves verified raw claims for the mapper", func(t *testing.T) {
for _, tc := range []struct {
name string
value interface{}
}{
{name: "boolean true", value: true},
{name: "boolean false", value: false},
{name: "string one", value: "1"},
{name: "string zero", value: "0"},
{name: "string true", value: "true"},
{name: "string false", value: "false"},
{name: "number one", value: float64(1)},
{name: "number zero", value: float64(0)},
{name: "absent"},
} {
t.Run(tc.name, func(t *testing.T) {
cl := makeClaimsWithRawClaims(issuerFor(tenantA), tenantA, tc.value)
c, err := newProvider(t, &oidc.Configuration{
Tenant: tenantA, SubjectSource: "oid",
}).Verify(context.Background(), signIdToken(t, cl))
require.NoError(t, err)
require.NotEmpty(t, c.RawClaims)

// The mapper receives the JSON-encoded Claims object, not the JWT.
encoded, err := json.Marshal(c)
require.NoError(t, err)
var mapperClaims map[string]interface{}
require.NoError(t, json.Unmarshal(encoded, &mapperClaims))
raw := mapperClaims["raw_claims"].(map[string]interface{})
if tc.value == nil {
assert.NotContains(t, raw, "xms_edov")
} else {
assert.Equal(t, tc.value, raw["xms_edov"])
}
assert.Equal(t, cl.Object, c.Subject)
assert.Equal(t, cl.Subject, raw["sub"])
assert.Equal(t, cl.Object, raw["oid"])
assert.Equal(t, cl.Email, c.Email)
assert.Equal(t, cl.TenantID, raw["tid"])
})
}
})

t.Run("case=rejects expired tokens even with xms_edov", func(t *testing.T) {
cl := makeClaimsWithRawClaims(issuerFor(tenantA), tenantA, "1")
cl.ExpiresAt = jwt.NewNumericDate(time.Now().Add(-time.Hour))
c, err := newProvider(t, &oidc.Configuration{Tenant: tenantA}).Verify(context.Background(), signIdToken(t, cl))
require.Error(t, err)
assert.Contains(t, err.Error(), "token is expired")
assert.Nil(t, c)
})

t.Run("case=fails due to client_id mismatch", func(t *testing.T) {
_, err := newProvider(t, &oidc.Configuration{Tenant: tenantA}).Verify(context.Background(), signIdToken(t, makeClaims("com.different-example.app", tenantA)))
require.Error(t, err)
Expand Down Expand Up @@ -221,4 +274,36 @@ func TestMicrosoftClaims(t *testing.T) {
assert.Equal(t, http.StatusBadRequest, herr.StatusCode())
assert.Contains(t, herr.Reason(), "`oid` claim")
})

t.Run("case=browser and native expose the same verified claims", func(t *testing.T) {
for _, value := range []interface{}{true, false, "1", "0", float64(1), nil} {
cl := makeClaimsWithRawClaims(issuer, tenant, value)
cl.Audience = jwt.ClaimStrings{"foo"}
raw := signIdToken(t, cl)
exchange := (&oauth2.Token{AccessToken: "foo"}).WithExtra(map[string]interface{}{"id_token": raw})
browserClaims, err := provider.Claims(context.Background(), exchange, url.Values{})
require.NoError(t, err)

native := provider.(*oidc.ProviderMicrosoft)
native.JWKSUrl = issuer + "/keys"
nativeClaims, err := native.Verify(context.Background(), raw)
require.NoError(t, err)
assert.Equal(t, browserClaims, nativeClaims)
}
})
}

func makeClaimsWithRawClaims(issuer, tenant string, xmsEdov interface{}) *claims {
return &claims{
RegisteredClaims: &jwt.RegisteredClaims{
Issuer: issuer,
Subject: "pairwise-sub",
Audience: jwt.ClaimStrings{"com.example.app"},
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour)),
},
Email: "acme@ory.sh",
Object: "00000000-0000-0000-0000-00000000c0de",
TenantID: tenant,
XmsEdov: xmsEdov,
}
}
7 changes: 4 additions & 3 deletions selfservice/strategy/oidc/strategy_helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,9 +390,10 @@ var publicJWKS2 []byte

type claims struct {
*jwt.RegisteredClaims
Email string `json:"email"`
Object string `json:"oid,omitempty"`
TenantID string `json:"tid,omitempty"`
Email string `json:"email"`
Object string `json:"oid,omitempty"`
TenantID string `json:"tid,omitempty"`
XmsEdov interface{} `json:"xms_edov,omitempty"`
}

func createIdToken(t *testing.T, cl jwt.RegisteredClaims) string {
Expand Down
11 changes: 11 additions & 0 deletions selfservice/strategy/oidc/token_verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,19 @@ func verifyToken(ctx context.Context, keySet oidc.KeySet, config *Configuration,
return nil, fmt.Errorf("token audience didn't match allowed audiences: %+v %w", tokenAudiences, err)
}
claims := &Claims{}
var rawClaims map[string]any

if token == nil {
return nil, fmt.Errorf("token is nil")
}

if err := token.Claims(claims); err != nil {
return nil, err
}
if err = token.Claims(&rawClaims); err != nil {
return nil, err
}
claims.RawClaims = rawClaims

return claims, nil
}
Loading