From 30ef4087fa85270d8ddcbfc3c2baa01cc3add3f1 Mon Sep 17 00:00:00 2001 From: Braden-OBrien Date: Sun, 21 Jun 2026 15:23:33 -0600 Subject: [PATCH] chore: add client_secret and client_authentication env variables implementing quick fixes for #2345 --- changelog/unreleased/add-oidc-web-env-vars.md | 8 ++ services/web/pkg/config/config.go | 4 +- .../web/pkg/config/defaults/defaultconfig.go | 13 ++-- services/web/pkg/config/oidc_config_test.go | 73 +++++++++++++++++++ 4 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 changelog/unreleased/add-oidc-web-env-vars.md create mode 100644 services/web/pkg/config/oidc_config_test.go diff --git a/changelog/unreleased/add-oidc-web-env-vars.md b/changelog/unreleased/add-oidc-web-env-vars.md new file mode 100644 index 0000000000..763408f169 --- /dev/null +++ b/changelog/unreleased/add-oidc-web-env-vars.md @@ -0,0 +1,8 @@ +Enhancement: Add OIDC env vars to expand external IDP compatibility + +Added two new environment variables, OC_OIDC_CLIENT_SECRET / +WEB_OIDC_CLIENT_SECRET and WEB_OIDC_CLIENT_AUTHENTICATION to +control additional functionality of the frontend's OAuth code exchanges. +Both are passed to the frontend to control oidc-client-ts. + +https://github.com/opencloud-eu/opencloud/issues/2345 diff --git a/services/web/pkg/config/config.go b/services/web/pkg/config/config.go index b7279759a5..ba2492b544 100644 --- a/services/web/pkg/config/config.go +++ b/services/web/pkg/config/config.go @@ -67,11 +67,13 @@ type WebConfig struct { // OIDC defines the available oidc configuration type OIDC struct { - MetadataURL string `json:"metadata_url,omitempty" yaml:"metadata_url" env:"WEB_OIDC_METADATA_URL" desc:"URL for the OIDC well-known configuration endpoint. Defaults to the OpenCloud API URL + '/.well-known/openid-configuration'." introductionVersion:"1.0.0"` Authority string `json:"authority,omitempty" yaml:"authority" env:"OC_URL;OC_OIDC_ISSUER;WEB_OIDC_AUTHORITY" desc:"URL of the OIDC issuer. It defaults to URL of the builtin IDP." introductionVersion:"1.0.0"` + MetadataURL string `json:"metadata_url,omitempty" yaml:"metadata_url" env:"WEB_OIDC_METADATA_URL" desc:"URL for the OIDC well-known configuration endpoint. Defaults to the OpenCloud API URL + '/.well-known/openid-configuration'." introductionVersion:"1.0.0"` ClientID string `json:"client_id,omitempty" yaml:"client_id" env:"OC_OIDC_CLIENT_ID;WEB_OIDC_CLIENT_ID" desc:"The OIDC client ID which OpenCloud Web uses. This client needs to be set up in your IDP. Note that this setting has no effect when using the builtin IDP." introductionVersion:"1.0.0"` + ClientSecret string `json:"client_secret,omitempty" yaml:"client_secret" env:"OC_OIDC_CLIENT_SECRET;WEB_OIDC_CLIENT_SECRET" desc:"The OIDC client secret which OpenCloud Web uses. Useful when some external IDPs require a client secret be sent despite PKCE. This client needs to be set up in your IDP. Note that this setting has no effect when using the builtin IDP." introductionVersion:"%%NEXT%%"` ResponseType string `json:"response_type,omitempty" yaml:"response_type" env:"WEB_OIDC_RESPONSE_TYPE" desc:"The OIDC response type to use for authentication." introductionVersion:"1.0.0"` Scope string `json:"scope,omitempty" yaml:"scope" env:"WEB_OIDC_SCOPE" desc:"OIDC scopes to request during authentication to authorize access to user details. Defaults to 'openid profile email'. Values are separated by blank. More example values but not limited to are 'address' or 'phone' etc." introductionVersion:"1.0.0"` + ClientAuthentication string `json:"client_authentication,omitempty" yaml:"client_authentication" env:"WEB_OIDC_CLIENT_AUTHENTICATION" desc:"Client authentication method that is used to authenticate when using the token endpoint (default 'client_secret_post'). 'client_secret_basic' using the HTTP Basic authentication scheme, 'client_secret_post' including the client credentials in the request body, 'client_secret_jwt' using a JWT signed with the client secret." introductionVersion:"%%NEXT%%"` PostLogoutRedirectURI string `json:"post_logout_redirect_uri,omitempty" yaml:"post_logout_redirect_uri" env:"WEB_OIDC_POST_LOGOUT_REDIRECT_URI" desc:"This value needs to point to a valid and reachable web page. The web client will trigger a redirect to that page directly after the logout action. The default value is empty and redirects to the login page." introductionVersion:"1.0.0"` } diff --git a/services/web/pkg/config/defaults/defaultconfig.go b/services/web/pkg/config/defaults/defaultconfig.go index 4c18aae0bd..cf8aebc957 100644 --- a/services/web/pkg/config/defaults/defaultconfig.go +++ b/services/web/pkg/config/defaults/defaultconfig.go @@ -92,11 +92,14 @@ func DefaultConfig() *config.Config { Server: "https://localhost:9200", Theme: "", OpenIDConnect: config.OIDC{ - MetadataURL: "", - Authority: "https://localhost:9200", - ClientID: "web", - ResponseType: "code", - Scope: "openid profile email", + MetadataURL: "", + Authority: "https://localhost:9200", + ClientID: "web", + ClientSecret: "", + ResponseType: "code", + Scope: "openid profile email", + ClientAuthentication: "client_secret_post", + PostLogoutRedirectURI: "", }, Apps: []string{"files", "search", "text-editor", "pdf-viewer", "external", "admin-settings", "epub-reader", "preview", "app-store"}, Options: config.Options{ diff --git a/services/web/pkg/config/oidc_config_test.go b/services/web/pkg/config/oidc_config_test.go new file mode 100644 index 0000000000..75689be4d2 --- /dev/null +++ b/services/web/pkg/config/oidc_config_test.go @@ -0,0 +1,73 @@ +package config_test + +import ( + "os" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/opencloud-eu/opencloud/services/web/pkg/config" + "github.com/opencloud-eu/opencloud/services/web/pkg/config/parser" +) + +func TestOIDCWebConfiguration(t *testing.T) { + Describe("OIDC Configuration Environment Decoding", func() { + var ( + testEnvVars map[string]string + savedEnv map[string]string + ) + + BeforeEach(func() { + testEnvVars = map[string]string{ + "WEB_OIDC_AUTHORITY": "https://idp.example.com", + "WEB_OIDC_METADATA_URL": "https://idp.example.com/.well-known/openid-configuration", + "WEB_OIDC_CLIENT_ID": "web", + "WEB_OIDC_CLIENT_SECRET": "secret", + "WEB_OIDC_RESPONSE_TYPE": "code", + "WEB_OIDC_SCOPE": "openid profile email", + "WEB_OIDC_CLIENT_AUTHENTICATION": "client_secret_post", + "WEB_OIDC_POST_LOGOUT_REDIRECT_URI": "https://app.example.com/login", + } + + // pretend env are callee saved + // not sure what the standards for env vars between tests are + savedEnv = make(map[string]string) + for k := range testEnvVars { + if val, exists := os.LookupEnv(k); exists { + savedEnv[k] = val + } + } + + for k, v := range testEnvVars { + err := os.Setenv(k, v) + Expect(err).To(BeNil()) + } + }) + + AfterEach(func() { + // restore + for k := range testEnvVars { + err := os.Unsetenv(k) + Expect(err).To(BeNil()) + } + }) + + It("successfully decodes OIDC environment variables into the struct", func() { + var cfg config.Config + + err := parser.ParseConfig(&cfg) + Expect(err).To(BeNil()) + + oidcCfg := &cfg.Web.Config.OpenIDConnect + + Expect(oidcCfg.Authority).To(Equal("https://idp.example.com")) + Expect(oidcCfg.MetadataURL).To(Equal("https://idp.example.com/.well-known/openid-configuration")) + Expect(oidcCfg.ClientID).To(Equal("web")) + Expect(oidcCfg.ClientSecret).To(Equal("secret")) + Expect(oidcCfg.ResponseType).To(Equal("code")) + Expect(oidcCfg.Scope).To(Equal("openid profile email")) + Expect(oidcCfg.ClientAuthentication).To(Equal("client_secret_post")) + Expect(oidcCfg.PostLogoutRedirectURI).To(Equal("https://app.example.com/login")) + }) + }) +}