mirror of
https://github.com/juanfont/headscale.git
synced 2024-12-19 06:27:35 +00:00
fix issue where some oidc claim bools are sent as string (#2297)
Jumpcloud send invalid json, so we need to handle it. Fixes #2293 Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
This commit is contained in:
parent
ec8729b772
commit
5345f19693
@ -3,6 +3,8 @@ package types
|
|||||||
import (
|
import (
|
||||||
"cmp"
|
"cmp"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@ -119,6 +121,37 @@ func (u *User) Proto() *v1.User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JumpCloud returns a JSON where email_verified is returned as a
|
||||||
|
// string "true" or "false" instead of a boolean.
|
||||||
|
// This maps bool to a specific type with a custom unmarshaler to
|
||||||
|
// ensure we can decode it from a string.
|
||||||
|
// https://github.com/juanfont/headscale/issues/2293
|
||||||
|
type FlexibleBoolean bool
|
||||||
|
|
||||||
|
func (bit *FlexibleBoolean) UnmarshalJSON(data []byte) error {
|
||||||
|
var val interface{}
|
||||||
|
err := json.Unmarshal(data, &val)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not unmarshal data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := val.(type) {
|
||||||
|
case bool:
|
||||||
|
*bit = FlexibleBoolean(v)
|
||||||
|
case string:
|
||||||
|
pv, err := strconv.ParseBool(v)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not parse %s as boolean: %w", v, err)
|
||||||
|
}
|
||||||
|
*bit = FlexibleBoolean(pv)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("could not parse %v as boolean", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type OIDCClaims struct {
|
type OIDCClaims struct {
|
||||||
// Sub is the user's unique identifier at the provider.
|
// Sub is the user's unique identifier at the provider.
|
||||||
Sub string `json:"sub"`
|
Sub string `json:"sub"`
|
||||||
@ -128,7 +161,7 @@ type OIDCClaims struct {
|
|||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Groups []string `json:"groups,omitempty"`
|
Groups []string `json:"groups,omitempty"`
|
||||||
Email string `json:"email,omitempty"`
|
Email string `json:"email,omitempty"`
|
||||||
EmailVerified bool `json:"email_verified,omitempty"`
|
EmailVerified FlexibleBoolean `json:"email_verified,omitempty"`
|
||||||
ProfilePictureURL string `json:"picture,omitempty"`
|
ProfilePictureURL string `json:"picture,omitempty"`
|
||||||
Username string `json:"preferred_username,omitempty"`
|
Username string `json:"preferred_username,omitempty"`
|
||||||
}
|
}
|
||||||
|
75
hscontrol/types/users_test.go
Normal file
75
hscontrol/types/users_test.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUnmarshallOIDCClaims(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
jsonstr string
|
||||||
|
want OIDCClaims
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "normal-bool",
|
||||||
|
jsonstr: `
|
||||||
|
{
|
||||||
|
"sub": "test",
|
||||||
|
"email": "test@test.no",
|
||||||
|
"email_verified": true
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
want: OIDCClaims{
|
||||||
|
Sub: "test",
|
||||||
|
Email: "test@test.no",
|
||||||
|
EmailVerified: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "string-bool-true",
|
||||||
|
jsonstr: `
|
||||||
|
{
|
||||||
|
"sub": "test2",
|
||||||
|
"email": "test2@test.no",
|
||||||
|
"email_verified": "true"
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
want: OIDCClaims{
|
||||||
|
Sub: "test2",
|
||||||
|
Email: "test2@test.no",
|
||||||
|
EmailVerified: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "string-bool-false",
|
||||||
|
jsonstr: `
|
||||||
|
{
|
||||||
|
"sub": "test3",
|
||||||
|
"email": "test3@test.no",
|
||||||
|
"email_verified": "false"
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
want: OIDCClaims{
|
||||||
|
Sub: "test3",
|
||||||
|
Email: "test3@test.no",
|
||||||
|
EmailVerified: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
var got OIDCClaims
|
||||||
|
if err := json.Unmarshal([]byte(tt.jsonstr), &got); err != nil {
|
||||||
|
t.Errorf("UnmarshallOIDCClaims() error = %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(got, tt.want); diff != "" {
|
||||||
|
t.Errorf("UnmarshallOIDCClaims() mismatch (-want +got):\n%s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user