fix: configure cookie Secure flag based on TLS configuration (#3482)

Make the Secure flag for session cookies configurable based on Zot's
TLS settings. This allows cookies to work properly when Zot is
accessed over HTTP (without TLS).

Changes:
- Add SecureSession field to AuthConfig to allow explicit control
- Add UseSecureSession() method that returns true when TLS is
  configured, or uses SecureSession setting if provided
- Update saveUserLoggedSession() to accept and use secure parameter
- Add tests for UseSecureSession() in config_test.go
- Enhance authn tests to verify cookie Secure flag behavior
- Fix TestAuthnSessionErrors by creating new client without cookies

The logic is:
- If TLS is configured, cookies always have Secure=true
- If TLS is not configured but SecureSession is explicitly set,
  use that value
- Otherwise, default to Secure=false for HTTP-only deployments

Signed-off-by: Andrei Aaron <andreifdaaron@gmail.com>
This commit is contained in:
Andrei Aaron
2025-10-27 17:21:21 +02:00
committed by GitHub
parent 22cfd9430b
commit 029f6f0a29
5 changed files with 318 additions and 16 deletions
+27
View File
@@ -80,6 +80,7 @@ type AuthConfig struct {
SessionHashKey []byte `json:"-"`
SessionEncryptKey []byte `json:"-"`
SessionDriver map[string]any `mapstructure:",omitempty"`
SecureSession *bool `json:"secureSession,omitempty" mapstructure:"secureSession,omitempty"`
}
// IsLdapAuthEnabled checks if LDAP authentication is enabled in this auth config.
@@ -670,6 +671,7 @@ func (c *Config) UpdateReloadableConfig(newConfig *Config) {
c.HTTP.Auth.LDAP = newConfig.HTTP.Auth.LDAP
c.HTTP.Auth.APIKey = newConfig.HTTP.Auth.APIKey
c.HTTP.Auth.OpenID = newConfig.HTTP.Auth.OpenID
c.HTTP.Auth.SecureSession = newConfig.HTTP.Auth.SecureSession
}
// Initialize and update AccessControlConfig
@@ -1016,6 +1018,31 @@ func (c *Config) IsCompatEnabled() bool {
return len(c.HTTP.Compat) > 0
}
// UseSecureSession returns whether cookies should have the Secure flag set.
// If TLS is configured, always returns true. Otherwise, returns the value
// of SecureSession if set, or false by default.
func (c *Config) UseSecureSession() bool {
if c == nil {
return false
}
c.mu.RLock()
defer c.mu.RUnlock()
// If TLS is configured, cookies should be secure
if c.HTTP.TLS != nil {
return true
}
// If TLS is not configured, check if SecureSession is explicitly set in auth config
if c.HTTP.Auth != nil && c.HTTP.Auth.SecureSession != nil {
return *c.HTTP.Auth.SecureSession
}
// Default to false if TLS is not configured and no explicit setting
return false
}
// IsOpenIDSupported checks if the provider supports OpenID.
func IsOpenIDSupported(provider string) bool {
for _, supportedProvider := range openIDSupportedProviders {
+77
View File
@@ -1989,6 +1989,83 @@ func TestConfig(t *testing.T) {
So(cfg.IsMTLSAuthEnabled(), ShouldBeTrue) // No basic auth, so mTLS enabled
})
Convey("Test UseSecureSession()", func() {
// Test with nil Config
var cfg *config.Config = nil
So(cfg.UseSecureSession(), ShouldBeFalse)
// Test with Config but no TLS and no Auth
cfg = &config.Config{
HTTP: config.HTTPConfig{
TLS: nil,
Auth: nil,
},
}
So(cfg.UseSecureSession(), ShouldBeFalse)
// Test with TLS configured (should return true)
cfg = &config.Config{
HTTP: config.HTTPConfig{
TLS: &config.TLSConfig{
Cert: "/path/to/cert.pem",
Key: "/path/to/key.pem",
},
},
}
So(cfg.UseSecureSession(), ShouldBeTrue)
// Test with no TLS but SecureSession explicitly set to true
secureTrue := true
cfg = &config.Config{
HTTP: config.HTTPConfig{
TLS: nil,
Auth: &config.AuthConfig{
SecureSession: &secureTrue,
},
},
}
So(cfg.UseSecureSession(), ShouldBeTrue)
// Test with no TLS but SecureSession explicitly set to false
secureFalse := false
cfg = &config.Config{
HTTP: config.HTTPConfig{
TLS: nil,
Auth: &config.AuthConfig{
SecureSession: &secureFalse,
},
},
}
So(cfg.UseSecureSession(), ShouldBeFalse)
// Test with no TLS and Auth but SecureSession not set
cfg = &config.Config{
HTTP: config.HTTPConfig{
TLS: nil,
Auth: &config.AuthConfig{
APIKey: true,
},
},
}
So(cfg.UseSecureSession(), ShouldBeFalse)
// Test with TLS configured and SecureSession set (TLS should take precedence)
secureTrue = true
cfg = &config.Config{
HTTP: config.HTTPConfig{
TLS: &config.TLSConfig{
Cert: "/path/to/cert.pem",
Key: "/path/to/key.pem",
},
Auth: &config.AuthConfig{
SecureSession: &secureTrue,
},
},
}
So(cfg.UseSecureSession(), ShouldBeTrue) // TLS takes precedence
})
Convey("Test IsCompatEnabled()", func() {
// Test with nil Config
var cfg *config.Config = nil