diff --git a/pkg/oidc/introspection.go b/pkg/oidc/introspection.go index 4d4b1f3..6ac2986 100644 --- a/pkg/oidc/introspection.go +++ b/pkg/oidc/introspection.go @@ -115,7 +115,7 @@ func (i *introspectionResponse) GetEmail() string { } func (i *introspectionResponse) IsEmailVerified() bool { - return i.EmailVerified + return bool(i.EmailVerified) } func (i *introspectionResponse) GetPhoneNumber() string { @@ -200,7 +200,7 @@ func (i *introspectionResponse) SetPreferredUsername(name string) { func (i *introspectionResponse) SetEmail(email string, verified bool) { i.Email = email - i.EmailVerified = verified + i.EmailVerified = boolString(verified) } func (i *introspectionResponse) SetPhone(phone string, verified bool) { diff --git a/pkg/oidc/userinfo.go b/pkg/oidc/userinfo.go index b4894fa..afc2ad0 100644 --- a/pkg/oidc/userinfo.go +++ b/pkg/oidc/userinfo.go @@ -154,7 +154,7 @@ func (u *userinfo) GetEmail() string { } func (u *userinfo) IsEmailVerified() bool { - return u.EmailVerified + return bool(u.EmailVerified) } func (u *userinfo) GetPhoneNumber() string { @@ -235,7 +235,7 @@ func (u *userinfo) SetPreferredUsername(name string) { func (u *userinfo) SetEmail(email string, verified bool) { u.Email = email - u.EmailVerified = verified + u.EmailVerified = boolString(verified) } func (u *userinfo) SetPhone(phone string, verified bool) { @@ -296,8 +296,22 @@ type userInfoProfile struct { } type userInfoEmail struct { - Email string `json:"email,omitempty"` - EmailVerified bool `json:"email_verified,omitempty"` + Email string `json:"email,omitempty"` + + // Handle providers that return email_verified as a string + // https://forums.aws.amazon.com/thread.jspa?messageID=949441󧳁 + // https://discuss.elastic.co/t/openid-error-after-authenticating-against-aws-cognito/206018/11 + EmailVerified boolString `json:"email_verified,omitempty"` +} + +type boolString bool + +func (bs *boolString) UnmarshalJSON(data []byte) error { + if string(data) == "true" || string(data) == `"true"` { + *bs = true + } + + return nil } type userInfoPhone struct { @@ -324,6 +338,7 @@ func NewUserInfoAddress(streetAddress, locality, region, postalCode, country, fo Formatted: formatted, } } + func (u *userinfo) MarshalJSON() ([]byte, error) { type Alias userinfo a := &struct { diff --git a/pkg/oidc/userinfo_test.go b/pkg/oidc/userinfo_test.go index 114fe2d..f42ff3d 100644 --- a/pkg/oidc/userinfo_test.go +++ b/pkg/oidc/userinfo_test.go @@ -25,3 +25,59 @@ func TestUserInfoMarshal(t *testing.T) { assert.NoError(t, err) assert.Equal(t, expected, marshal) } + +func TestUserInfoEmailVerifiedUnmarshal(t *testing.T) { + t.Parallel() + + t.Run("unmarsha email_verified from json bool true", func(t *testing.T) { + jsonBool := []byte(`{"email": "my@email.com", "email_verified": true}`) + + var uie userInfoEmail + + err := json.Unmarshal(jsonBool, &uie) + assert.NoError(t, err) + assert.Equal(t, userInfoEmail{ + Email: "my@email.com", + EmailVerified: true, + }, uie) + }) + + t.Run("unmarsha email_verified from json string true", func(t *testing.T) { + jsonBool := []byte(`{"email": "my@email.com", "email_verified": "true"}`) + + var uie userInfoEmail + + err := json.Unmarshal(jsonBool, &uie) + assert.NoError(t, err) + assert.Equal(t, userInfoEmail{ + Email: "my@email.com", + EmailVerified: true, + }, uie) + }) + + t.Run("unmarsha email_verified from json bool false", func(t *testing.T) { + jsonBool := []byte(`{"email": "my@email.com", "email_verified": false}`) + + var uie userInfoEmail + + err := json.Unmarshal(jsonBool, &uie) + assert.NoError(t, err) + assert.Equal(t, userInfoEmail{ + Email: "my@email.com", + EmailVerified: false, + }, uie) + }) + + t.Run("unmarsha email_verified from json string false", func(t *testing.T) { + jsonBool := []byte(`{"email": "my@email.com", "email_verified": "false"}`) + + var uie userInfoEmail + + err := json.Unmarshal(jsonBool, &uie) + assert.NoError(t, err) + assert.Equal(t, userInfoEmail{ + Email: "my@email.com", + EmailVerified: false, + }, uie) + }) +}