From ced7ebd97fe6f319a6744ca82c201a8b7bf160b5 Mon Sep 17 00:00:00 2001 From: kolaente Date: Sat, 11 Apr 2026 21:00:16 +0200 Subject: [PATCH] fix(auth): tolerate string booleans in oidc provider config (#2599) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The four boolean OIDC provider fields (emailfallback, usernamefallback, forceuserinfo, requireavailability) were parsed with a strict .(bool) type assertion. That works for YAML/JSON config where leaves are native bools, but fails for every other input path: env vars always arrive as strings, and GetConfigValueFromFile (used by the *.file Docker secret convention) also always returns strings. The assertion would silently zero the field for emailfallback and usernamefallback, and log an error and zero the field for forceuserinfo and requireavailability, which is what #2599 reports. Extract a small parseBoolField helper that accepts both native bools and strings (via strconv.ParseBool) and logs a parse error from each call site. This also fixes the previously-silent drop of stringified emailfallback / usernamefallback values — those now log an error if the input is garbage, matching the behaviour of the other two fields. Fixes #2599 --- pkg/modules/auth/openid/providers.go | 68 ++++++++++++++-------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/pkg/modules/auth/openid/providers.go b/pkg/modules/auth/openid/providers.go index aaafab82f..30f534ad9 100644 --- a/pkg/modules/auth/openid/providers.go +++ b/pkg/modules/auth/openid/providers.go @@ -180,6 +180,28 @@ func GetProvider(key string) (provider *Provider, err error) { return } +// parseBoolField reads a boolean-valued config field from a provider map, +// tolerating both native bools (from YAML/JSON) and strings (from env vars or +// the GetConfigValueFromFile path, which always return strings). Missing or +// empty values default to false with no error. +func parseBoolField(pi map[string]interface{}, key string) (val bool, err error) { + raw, exists := pi[key] + if !exists { + return false, nil + } + switch v := raw.(type) { + case bool: + return v, nil + case string: + if v == "" { + return false, nil + } + return strconv.ParseBool(v) + default: + return false, fmt.Errorf("expected bool, got %T", raw) + } +} + func getProviderFromMap(pi map[string]interface{}, key string) (provider *Provider, err error) { requiredKeys := []string{ @@ -236,43 +258,21 @@ func getProviderFromMap(pi map[string]interface{}, key string) (provider *Provid scope = "openid profile email" } - var emailFallback = false - emailFallbackValue, exists := pi["emailfallback"] - if exists { - emailFallbackTypedValue, ok := emailFallbackValue.(bool) - if ok { - emailFallback = emailFallbackTypedValue - } + emailFallback, err := parseBoolField(pi, "emailfallback") + if err != nil { + log.Errorf("emailfallback is not a boolean for provider %s: %s", key, err) } - var usernameFallback = false - usernameFallbackValue, exists := pi["usernamefallback"] - if exists { - usernameFallbackTypedValue, ok := usernameFallbackValue.(bool) - if ok { - usernameFallback = usernameFallbackTypedValue - } + usernameFallback, err := parseBoolField(pi, "usernamefallback") + if err != nil { + log.Errorf("usernamefallback is not a boolean for provider %s: %s", key, err) } - - var forceUserInfo = false - forceUserInfoValue, exists := pi["forceuserinfo"] - if exists { - forceUserInfoTypedValue, ok := forceUserInfoValue.(bool) - if ok { - forceUserInfo = forceUserInfoTypedValue - } else { - log.Errorf("forceuserinfo is not a boolean for provider %s, value: %v", key, forceUserInfoValue) - } + forceUserInfo, err := parseBoolField(pi, "forceuserinfo") + if err != nil { + log.Errorf("forceuserinfo is not a boolean for provider %s: %s", key, err) } - - var requireAvailability = false - requireAvailabilityValue, exists := pi["requireavailability"] - if exists { - requireAvailabilityTypedValue, ok := requireAvailabilityValue.(bool) - if ok { - requireAvailability = requireAvailabilityTypedValue - } else { - log.Errorf("requireavailability is not a boolean for provider %s, value: %v", key, requireAvailabilityValue) - } + requireAvailability, err := parseBoolField(pi, "requireavailability") + if err != nil { + log.Errorf("requireavailability is not a boolean for provider %s: %s", key, err) } provider = &Provider{