From 763d3334e7a866e76c9f2d8c944fd34a6cf21e6c Mon Sep 17 00:00:00 2001 From: Witold Konior Date: Tue, 2 Nov 2021 09:14:33 +0100 Subject: [PATCH] feat: Enable parsing email_verified from string. (#139) * Enable parsing email_verified from string. AWS Cognito will return email_verified from /userinfo endpoint as string. This fix will accept proper boolean values as well as string values. Links for reference: https://forums.aws.amazon.com/thread.jspa?messageID=949441󧳁 https://discuss.elastic.co/t/openid-error-after-authenticating-against-aws-cognito/206018/11 * feat: Enable parsing email_verified from string. --- pkg/oidc/introspection.go | 4 +-- pkg/oidc/userinfo.go | 23 ++++++++++++--- pkg/oidc/userinfo_test.go | 59 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 79 insertions(+), 7 deletions(-) diff --git a/pkg/oidc/introspection.go b/pkg/oidc/introspection.go index 9b2bad7..8dd1987 100644 --- a/pkg/oidc/introspection.go +++ b/pkg/oidc/introspection.go @@ -115,7 +115,7 @@ func (u *introspectionResponse) GetEmail() string { } func (u *introspectionResponse) IsEmailVerified() bool { - return u.EmailVerified + return bool(u.EmailVerified) } func (u *introspectionResponse) GetPhoneNumber() string { @@ -200,7 +200,7 @@ func (u *introspectionResponse) SetPreferredUsername(name string) { func (u *introspectionResponse) SetEmail(email string, verified bool) { u.Email = email - u.EmailVerified = verified + u.EmailVerified = boolString(verified) } func (u *introspectionResponse) SetPhone(phone string, verified bool) { diff --git a/pkg/oidc/userinfo.go b/pkg/oidc/userinfo.go index 2ae2acb..2272421 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 (i *userinfo) MarshalJSON() ([]byte, error) { type Alias userinfo a := &struct { diff --git a/pkg/oidc/userinfo_test.go b/pkg/oidc/userinfo_test.go index c3c8b7b..f42ff3d 100644 --- a/pkg/oidc/userinfo_test.go +++ b/pkg/oidc/userinfo_test.go @@ -2,8 +2,9 @@ package oidc import ( "encoding/json" - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestUserInfoMarshal(t *testing.T) { @@ -24,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) + }) +}