From ea535ac02a1ab5da1b3b878254b5b27baaddbc34 Mon Sep 17 00:00:00 2001 From: olalekan odukoya Date: Mon, 16 Feb 2026 10:49:34 +0100 Subject: [PATCH] add validation for --oidc-issuer-url and --oidc-callback-url Signed-off-by: olalekan odukoya --- backend/options/oidc.go | 21 ++++++++++++++ backend/options/oidc_test.go | 56 +++++++++++++++++++++++++++++++++--- 2 files changed, 73 insertions(+), 4 deletions(-) diff --git a/backend/options/oidc.go b/backend/options/oidc.go index a86794f8d..311de002b 100644 --- a/backend/options/oidc.go +++ b/backend/options/oidc.go @@ -20,6 +20,7 @@ import ( "crypto/tls" "fmt" "net" + "net/url" "os" "strings" @@ -123,6 +124,7 @@ func (options *OIDC) Validate() error { if options.CallbackURL == "" { return fmt.Errorf("OIDC callback URL cannot be empty") } + if options.CAFile != "" && options.TLSConfig != nil { return fmt.Errorf("cannot use both CA file and embedded OIDC server") } @@ -131,6 +133,25 @@ func (options *OIDC) Validate() error { return fmt.Errorf("invalid OIDC provider type: %s", options.Type) } + issuerURL, err := url.Parse(options.IssuerURL) + if err != nil { + return fmt.Errorf("--oidc-issuer-url must be a valid URL: %w", err) + } + if issuerURL.Scheme != "http" && issuerURL.Scheme != "https" { + return fmt.Errorf("--oidc-issuer-url must use http or https scheme, got: %s", issuerURL.Scheme) + } + + callbackURL, err := url.Parse(options.CallbackURL) + if err != nil { + return fmt.Errorf("--oidc-callback-url must be a valid URL: %w", err) + } + if callbackURL.Scheme != "http" && callbackURL.Scheme != "https" { + return fmt.Errorf("--oidc-callback-url must use http or https scheme, got: %s", callbackURL.Scheme) + } + if !strings.HasSuffix(callbackURL.Path, "/api/callback") { + return fmt.Errorf("--oidc-callback-url must end with '/api/callback', got path: %s", callbackURL.Path) + } + if options.Type == string(kubebindv1alpha2.OIDCProviderTypeEmbedded) && !strings.HasSuffix(options.IssuerURL, "/oidc") { return fmt.Errorf("--oidc-issuer-url must end with '/oidc' when using embedded OIDC provider") } diff --git a/backend/options/oidc_test.go b/backend/options/oidc_test.go index 1339196ff..023f4d9bb 100644 --- a/backend/options/oidc_test.go +++ b/backend/options/oidc_test.go @@ -38,7 +38,7 @@ func TestOIDCValidate(t *testing.T) { IssuerClientID: "test-client-id", IssuerClientSecret: "test-client-secret", IssuerURL: "http://localhost:8080/oidc", - CallbackURL: "http://localhost:8080/callback", + CallbackURL: "http://localhost:8080/api/callback", }, wantErr: false, }, @@ -49,7 +49,7 @@ func TestOIDCValidate(t *testing.T) { IssuerClientID: "test-client-id", IssuerClientSecret: "test-client-secret", IssuerURL: "http://localhost:8080", - CallbackURL: "http://localhost:8080/callback", + CallbackURL: "http://localhost:8080/api/callback", }, wantErr: true, errMsg: "--oidc-issuer-url must end with '/oidc' when using embedded OIDC provider", @@ -61,7 +61,7 @@ func TestOIDCValidate(t *testing.T) { IssuerClientID: "test-client-id", IssuerClientSecret: "test-client-secret", IssuerURL: "http://localhost:8080/oidc/", - CallbackURL: "http://localhost:8080/callback", + CallbackURL: "http://localhost:8080/api/callback", }, wantErr: true, errMsg: "--oidc-issuer-url must end with '/oidc' when using embedded OIDC provider", @@ -73,11 +73,59 @@ func TestOIDCValidate(t *testing.T) { IssuerClientID: "test-client-id", IssuerClientSecret: "test-client-secret", IssuerURL: "http://localhost:8080", - CallbackURL: "http://localhost:8080/callback", + CallbackURL: "http://localhost:8080/api/callback", AllowedGroups: []string{"admins"}, }, wantErr: false, }, + { + name: "malformed issuer URL", + options: &OIDC{ + Type: string(kubebindv1alpha2.OIDCProviderTypeEmbedded), + IssuerClientID: "test-client-id", + IssuerClientSecret: "test-client-secret", + IssuerURL: "not-a-valid-url", + CallbackURL: "http://localhost:8080/api/callback", + }, + wantErr: true, + errMsg: "--oidc-issuer-url must use http or https scheme, got: ", + }, + { + name: "malformed callback URL", + options: &OIDC{ + Type: string(kubebindv1alpha2.OIDCProviderTypeEmbedded), + IssuerClientID: "test-client-id", + IssuerClientSecret: "test-client-secret", + IssuerURL: "http://localhost:8080/oidc", + CallbackURL: "not-a-valid-url", + }, + wantErr: true, + errMsg: "--oidc-callback-url must use http or https scheme, got: ", + }, + { + name: "callback URL with invalid scheme", + options: &OIDC{ + Type: string(kubebindv1alpha2.OIDCProviderTypeEmbedded), + IssuerClientID: "test-client-id", + IssuerClientSecret: "test-client-secret", + IssuerURL: "http://localhost:8080/oidc", + CallbackURL: "ftp://localhost:8080/api/callback", + }, + wantErr: true, + errMsg: "--oidc-callback-url must use http or https scheme, got: ftp", + }, + { + name: "callback URL with only /callback (missing /api prefix)", + options: &OIDC{ + Type: string(kubebindv1alpha2.OIDCProviderTypeEmbedded), + IssuerClientID: "test-client-id", + IssuerClientSecret: "test-client-secret", + IssuerURL: "http://localhost:8080/oidc", + CallbackURL: "http://localhost:8080/callback", + }, + wantErr: true, + errMsg: "--oidc-callback-url must end with '/api/callback', got path: /callback", + }, } for _, tt := range tests {