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:
Kristoffer Dalby 2024-12-16 11:26:32 +01:00 committed by GitHub
parent ec8729b772
commit 5345f19693
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 114 additions and 6 deletions

View file

@ -3,6 +3,8 @@ package types
import (
"cmp"
"database/sql"
"encoding/json"
"fmt"
"net/mail"
"strconv"
@ -119,18 +121,49 @@ 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 {
// Sub is the user's unique identifier at the provider.
Sub string `json:"sub"`
Iss string `json:"iss"`
// Name is the user's full name.
Name string `json:"name,omitempty"`
Groups []string `json:"groups,omitempty"`
Email string `json:"email,omitempty"`
EmailVerified bool `json:"email_verified,omitempty"`
ProfilePictureURL string `json:"picture,omitempty"`
Username string `json:"preferred_username,omitempty"`
Name string `json:"name,omitempty"`
Groups []string `json:"groups,omitempty"`
Email string `json:"email,omitempty"`
EmailVerified FlexibleBoolean `json:"email_verified,omitempty"`
ProfilePictureURL string `json:"picture,omitempty"`
Username string `json:"preferred_username,omitempty"`
}
func (c *OIDCClaims) Identifier() string {